~ git clone https://git.cass.si/kysely-op-sqlite.git
~ git clone https://git.cass.si/kysely-op-sqlite.git
A Kysely dialect for @op-engineering/op-sqlite - a fast SQLite library for React Native.
npm install kysely-op-sqlite kysely @op-engineering/op-sqlite
# or
yarn add kysely-op-sqlite kysely @op-engineering/op-sqlite
import { KyselyOpSqliteProvider, useKysely } from 'kysely-op-sqlite'
import type { DB } from './types'
function App() {
return (
<KyselyOpSqliteProvider<DB>
database={{ name: 'myapp.db' }}
autoAffinityConversion={true}
onInit={async (db) => {
// Run migrations, seed data, etc.
await db.schema
.createTable('users')
.ifNotExists()
.addColumn('id', 'integer', (col) => col.primaryKey().autoIncrement())
.addColumn('name', 'text', (col) => col.notNull())
.execute()
}}
onError={(error) => console.error(error)}
>
<MyComponent />
</KyselyOpSqliteProvider>
)
}
function MyComponent() {
const db = useKysely<DB>()
// Use db to query...
}
import { Kysely } from 'kysely'
import { OpSqliteDialect } from 'kysely-op-sqlite'
import type { DB } from './types'
const db = new Kysely<DB>({
dialect: new OpSqliteDialect({
database: { name: 'myapp.db' },
autoAffinityConversion: true,
}),
})
const users = await db.selectFrom('users').selectAll().execute()
import { SQLiteType } from 'kysely-op-sqlite'
await db.schema
.createTable('users')
.addColumn('id', SQLiteType.Integer, (col) => col.primaryKey().autoIncrement())
.addColumn('name', SQLiteType.String, (col) => col.notNull())
.addColumn('email', SQLiteType.String)
.addColumn('created_at', SQLiteType.DateTime, (col) => col.notNull())
.addColumn('is_active', SQLiteType.Boolean, (col) => col.notNull().defaultTo('true'))
.execute()
The main dialect class for Kysely.
new OpSqliteDialect({
database: { name: 'myapp.db', location?: string, encryptionKey?: string },
// or pass an existing op-sqlite DB instance
database: existingDb,
autoAffinityConversion?: boolean, // Auto-convert types (default: false)
disableForeignKeys?: boolean, // Disable foreign keys (default: false)
disableStrictModeCreateTable?: boolean, // Disable STRICT tables (default: false)
disableMutex?: boolean, // Disable connection mutex (default: false)
debug?: boolean, // Log queries (default: false)
onError?: (message: string, error: unknown) => void,
})
React context provider for Kysely.
<KyselyOpSqliteProvider<DB>
database={{ name: 'myapp.db' }}
autoAffinityConversion={true}
onInit={async (db) => {
/* ... */
}}
onError={(error) => {
/* ... */
}}
>
{children}
</KyselyOpSqliteProvider>
useKysely<T>() - Returns the Kysely instance. Throws if not ready.useKyselyContext<T>() - Returns { db, isReady, error } for loading states.Type constants for STRICT mode compatible schemas:
SQLiteType.String - TEXTSQLiteType.Integer - INTEGERSQLiteType.Number - REALSQLiteType.Boolean - TEXT ('true'/'false')SQLiteType.DateTime - TEXT (ISO 8601)SQLiteType.Blob - BLOBThis library includes a JavaScript-level mutex that serializes all database operations. Counter-intuitively, this improves performance significantly.
Without the mutex, concurrent queries cause SQLite lock contention at the native level. SQLite handles this internally, but with expensive busy-waiting and retries. The JS mutex moves serialization to JavaScript, which is nearly free.
Without JS mutex (concurrent queries contend at SQLite level):
getActiveProgramQuer ━━━━━━━━━━━━━━━━━━━━━━━ 396ms
listRestDaysQuery ━━━━━━━━━━━━━━━━━━━━━━━ 394ms
listPreWorkoutSurvey ━━━━━━━━━━━ 195ms
listRestDaysQuery ━━━━ 68ms
listWorkoutHistoryQu ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 464ms
listWorkoutHistoryQu ━━━━━━━━━━━━━━━━━━━━━━━━━━ 445ms
getTrainingLoadQuery ━━━━━━━━━━━━━━━ 257ms
listWorkoutHistoryQu ━━━━━━━━━━━━━━━ 253ms
listWorkoutHistoryQu ━━━━━━━━━━━━━━━━━━━━━━━━━━━ 466ms
total: 862ms
With JS mutex (queries run sequentially, no contention):
getActiveProgramQuer ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 375ms
listRestDaysQuery ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 388ms
listPreWorkoutSurvey ━━━━━━━━━━━━━━━━━━━━━━━━━━ 209ms
listRestDaysQuery ━━━ 25ms
listWorkoutHistoryQu ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 399ms
listWorkoutHistoryQu ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 381ms
getTrainingLoadQuery ━━━━━━━━━━━━━━━━━━━━━━━━━━ 207ms
listWorkoutHistoryQu ━━━━━━━━━━━━━━━━━━━━━━━━━ 203ms
listWorkoutHistoryQu ━━━ 27ms
total: 402ms
Same queries, but 2x faster with the mutex because:
If you have a specific use case that benefits from concurrent SQLite access (rare), you can disable it:
<KyselyOpSqliteProvider<DB> database={{ name: 'myapp.db' }} disableMutex={true}>
{children}
</KyselyOpSqliteProvider>
Or with direct dialect usage:
new OpSqliteDialect({
database: { name: 'myapp.db' },
disableMutex: true,
})
MIT