Skip to main content

Generic

You can integrate any SQLite database driver by adapting it to the ElectricSQL DatabaseAdapter interface:

export interface DatabaseAdapter {
// Database connection instance from your driver library.
db: AnyDatabase

// Run the provided sql statement. A statement has the
// form of `{sql: string, bindParams?: string[]}`.
run(statement: Statement): Promise<RunResult>

// Run an array of sql statements within a transaction.
runInTransaction(...statements: Statement[]): Promise<RunResult>

// Run a query statement and return the results as an
// array of rows.
query(statement: Statement): Promise<Row[]>

// Run the provided function inside a transaction.
transaction<T>(
f: (tx: Transaction, setResult: (res: T) => void) => void
): Promise<T | void>

// Get the tables potentially used by an SQL statement.
// This supports reactivity for raw SQL use via the
// `db.liveRawQuery` function.
tableNames(statement: Statement): QualifiedTablename[]
}

For convenience, we provide two generic database adapters, SerialDatabaseAdapter`` and BatchDatabaseAdapter``. These implement the parts of the interface that are common to most adapters. This allows you to implement your own driver adapters using a simpler interface.

export abstract class SerialDatabaseAdapter implements DatabaseAdapter {
// Run a single SQL statement against the DB
abstract _run(stmt: Statement): Promise<RunResult>
// Run a single SQL query against the DB
abstract _query(stmt: Statement): Promise<Row[]>
}

// Use `BatchDatabaseAdapter` if the underlying driver
// supports batch execution of SQL statements
export abstract class BatchDatabaseAdapter implements DatabaseAdapter {
// Run a single SQL statement against the DB
abstract _run(stmt: Statement): Promise<RunResult>
// Run a single SQL query against the DB
abstract _query(stmt: Statement): Promise<Row[]>
// Run several SQL statements againt the DB in a single batch
abstract execBatch(statements: Statement[]): Promise<RunResult>
}

The best guidance for this is to look at the existing driver implementations. You can then build on the base electrify function to implement your own electrify function, e.g.:

export const electrify = async <T, DB extends DbSchema<any>>(
db: T,
dbDescription: DB,
config: ElectricConfig,
opts?: ElectrifyOptions
): Promise<ElectricClient<DB>> => {
const dbName = db.name
const adapter = opts?.adapter || new MyDatabaseAdapter(db)
const socketFactory = opts?.socketFactory || new WebSocketWebFactory()

const client = await baseElectrify(
dbName,
dbDescription,
adapter,
socketFactory,
config,
opts
)

return client
}

For more help / pointers, let us know on Discord and we'll be happy to help you with the integration.