@syncular/dialect-sqlite3 0.0.1-60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +140 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
- package/src/index.ts +197 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/dialect-sqlite3 - node-sqlite3 dialect for sync
|
|
3
|
+
*
|
|
4
|
+
* Provides a Kysely dialect for the callback-based `sqlite3` npm package
|
|
5
|
+
* with SerializePlugin for automatic JSON serialization/deserialization.
|
|
6
|
+
* SQLite-compatible — use with @syncular/server-dialect-sqlite.
|
|
7
|
+
*
|
|
8
|
+
* Implements a custom Kysely Driver that wraps sqlite3's callback API
|
|
9
|
+
* into the promise-based interface Kysely expects.
|
|
10
|
+
*/
|
|
11
|
+
import { SerializePlugin } from '@syncular/core';
|
|
12
|
+
import { Kysely } from 'kysely';
|
|
13
|
+
import sqlite3 from 'sqlite3';
|
|
14
|
+
interface Sqlite3PathOptions {
|
|
15
|
+
/** Path to SQLite database file, or ':memory:' for in-memory */
|
|
16
|
+
path: string;
|
|
17
|
+
}
|
|
18
|
+
interface Sqlite3InstanceOptions {
|
|
19
|
+
/** An existing sqlite3.Database instance */
|
|
20
|
+
database: sqlite3.Database;
|
|
21
|
+
}
|
|
22
|
+
type Sqlite3Options = Sqlite3PathOptions | Sqlite3InstanceOptions;
|
|
23
|
+
/**
|
|
24
|
+
* Create a Kysely instance with node-sqlite3 dialect and SerializePlugin.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* const db = createSqlite3Db<MyDb>({ path: './data.db' });
|
|
28
|
+
* const db = createSqlite3Db<MyDb>({ path: ':memory:' });
|
|
29
|
+
*/
|
|
30
|
+
export declare function createSqlite3Db<T>(options: Sqlite3Options): Kysely<T>;
|
|
31
|
+
export declare function createSerializePlugin(): SerializePlugin;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAWjD,OAAO,EAEL,MAAM,EAIP,MAAM,QAAQ,CAAC;AAChB,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,UAAU,kBAAkB;IAC1B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,sBAAsB;IAC9B,4CAA4C;IAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC;CAC5B;AAED,KAAK,cAAc,GAAG,kBAAkB,GAAG,sBAAsB,CAAC;AAElE;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,CAKrE;AASD,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/dialect-sqlite3 - node-sqlite3 dialect for sync
|
|
3
|
+
*
|
|
4
|
+
* Provides a Kysely dialect for the callback-based `sqlite3` npm package
|
|
5
|
+
* with SerializePlugin for automatic JSON serialization/deserialization.
|
|
6
|
+
* SQLite-compatible — use with @syncular/server-dialect-sqlite.
|
|
7
|
+
*
|
|
8
|
+
* Implements a custom Kysely Driver that wraps sqlite3's callback API
|
|
9
|
+
* into the promise-based interface Kysely expects.
|
|
10
|
+
*/
|
|
11
|
+
import { SerializePlugin } from '@syncular/core';
|
|
12
|
+
import { CompiledQuery, Kysely, SqliteAdapter, SqliteIntrospector, SqliteQueryCompiler, } from 'kysely';
|
|
13
|
+
import sqlite3 from 'sqlite3';
|
|
14
|
+
/**
|
|
15
|
+
* Create a Kysely instance with node-sqlite3 dialect and SerializePlugin.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const db = createSqlite3Db<MyDb>({ path: './data.db' });
|
|
19
|
+
* const db = createSqlite3Db<MyDb>({ path: ':memory:' });
|
|
20
|
+
*/
|
|
21
|
+
export function createSqlite3Db(options) {
|
|
22
|
+
return new Kysely({
|
|
23
|
+
dialect: createSqlite3Dialect(options),
|
|
24
|
+
plugins: [new SerializePlugin()],
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create the sqlite3 dialect directly (without SerializePlugin).
|
|
29
|
+
*/
|
|
30
|
+
function createSqlite3Dialect(options) {
|
|
31
|
+
return new Sqlite3Dialect(options);
|
|
32
|
+
}
|
|
33
|
+
export function createSerializePlugin() {
|
|
34
|
+
return new SerializePlugin();
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Kysely Dialect implementation for node-sqlite3
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
class Sqlite3Dialect {
|
|
40
|
+
#options;
|
|
41
|
+
constructor(options) {
|
|
42
|
+
this.#options = options;
|
|
43
|
+
}
|
|
44
|
+
createAdapter() {
|
|
45
|
+
return new SqliteAdapter();
|
|
46
|
+
}
|
|
47
|
+
createDriver() {
|
|
48
|
+
return new Sqlite3Driver(this.#options);
|
|
49
|
+
}
|
|
50
|
+
createQueryCompiler() {
|
|
51
|
+
return new SqliteQueryCompiler();
|
|
52
|
+
}
|
|
53
|
+
createIntrospector(db) {
|
|
54
|
+
return new SqliteIntrospector(db);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
class Sqlite3Driver {
|
|
58
|
+
#options;
|
|
59
|
+
#db;
|
|
60
|
+
constructor(options) {
|
|
61
|
+
this.#options = options;
|
|
62
|
+
}
|
|
63
|
+
async init() {
|
|
64
|
+
this.#db = await this.#resolveDatabase();
|
|
65
|
+
}
|
|
66
|
+
async acquireConnection() {
|
|
67
|
+
return new Sqlite3Connection(this.#db);
|
|
68
|
+
}
|
|
69
|
+
async beginTransaction(connection, _settings) {
|
|
70
|
+
await connection.executeQuery(CompiledQuery.raw('begin'));
|
|
71
|
+
}
|
|
72
|
+
async commitTransaction(connection) {
|
|
73
|
+
await connection.executeQuery(CompiledQuery.raw('commit'));
|
|
74
|
+
}
|
|
75
|
+
async rollbackTransaction(connection) {
|
|
76
|
+
await connection.executeQuery(CompiledQuery.raw('rollback'));
|
|
77
|
+
}
|
|
78
|
+
async releaseConnection(_connection) {
|
|
79
|
+
// Single-connection model — nothing to release.
|
|
80
|
+
}
|
|
81
|
+
async destroy() {
|
|
82
|
+
if (this.#db) {
|
|
83
|
+
await new Promise((resolve, reject) => {
|
|
84
|
+
this.#db.close((err) => (err ? reject(err) : resolve()));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async #resolveDatabase() {
|
|
89
|
+
if ('database' in this.#options) {
|
|
90
|
+
return this.#options.database;
|
|
91
|
+
}
|
|
92
|
+
const path = this.#options.path;
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const db = new sqlite3.Database(path, (err) => {
|
|
95
|
+
if (err)
|
|
96
|
+
reject(err);
|
|
97
|
+
else
|
|
98
|
+
resolve(db);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
class Sqlite3Connection {
|
|
104
|
+
#db;
|
|
105
|
+
constructor(db) {
|
|
106
|
+
this.#db = db;
|
|
107
|
+
}
|
|
108
|
+
async executeQuery(compiledQuery) {
|
|
109
|
+
const { sql, parameters } = compiledQuery;
|
|
110
|
+
const params = [...parameters];
|
|
111
|
+
// Determine if this is a SELECT / RETURNING query
|
|
112
|
+
const isSelect = /^\s*(select|pragma|explain|with)\b/i.test(sql);
|
|
113
|
+
const isInsert = /^\s*(insert|replace)\b/i.test(sql);
|
|
114
|
+
if (isSelect) {
|
|
115
|
+
return new Promise((resolve, reject) => {
|
|
116
|
+
this.#db.all(sql, params, (err, rows) => {
|
|
117
|
+
if (err)
|
|
118
|
+
return reject(err);
|
|
119
|
+
resolve({ rows: rows ?? [] });
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// For INSERT, UPDATE, DELETE — use run() to get lastID and changes
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
this.#db.run(sql, params, function (err) {
|
|
126
|
+
if (err)
|
|
127
|
+
return reject(err);
|
|
128
|
+
resolve({
|
|
129
|
+
rows: [],
|
|
130
|
+
numAffectedRows: BigInt(this.changes),
|
|
131
|
+
...(isInsert ? { insertId: BigInt(this.lastID) } : {}),
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
streamQuery(_compiledQuery, _chunkSize) {
|
|
137
|
+
throw new Error('sqlite3 driver does not support streaming');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@syncular/dialect-sqlite3",
|
|
3
|
+
"version": "0.0.1-60",
|
|
4
|
+
"description": "node-sqlite3 dialect for the Syncular client",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Benjamin Kniffler",
|
|
7
|
+
"homepage": "https://syncular.dev",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/syncular/syncular.git",
|
|
11
|
+
"directory": "packages/dialect-sqlite3"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/syncular/syncular/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"sync",
|
|
18
|
+
"offline-first",
|
|
19
|
+
"realtime",
|
|
20
|
+
"database",
|
|
21
|
+
"typescript",
|
|
22
|
+
"sqlite3",
|
|
23
|
+
"node"
|
|
24
|
+
],
|
|
25
|
+
"private": false,
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"type": "module",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"bun": "./src/index.ts",
|
|
33
|
+
"import": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"default": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"tsgo": "tsgo --noEmit",
|
|
41
|
+
"build": "rm -rf dist && tsgo",
|
|
42
|
+
"release": "bun pm pack --destination . && npm publish ./*.tgz --tag latest && rm -f ./*.tgz"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@syncular/core": "0.0.1",
|
|
46
|
+
"sqlite3": "^5.1.7"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"kysely": "^0.28.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@syncular/config": "0.0.0",
|
|
53
|
+
"kysely": "*"
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"dist",
|
|
57
|
+
"src"
|
|
58
|
+
]
|
|
59
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @syncular/dialect-sqlite3 - node-sqlite3 dialect for sync
|
|
3
|
+
*
|
|
4
|
+
* Provides a Kysely dialect for the callback-based `sqlite3` npm package
|
|
5
|
+
* with SerializePlugin for automatic JSON serialization/deserialization.
|
|
6
|
+
* SQLite-compatible — use with @syncular/server-dialect-sqlite.
|
|
7
|
+
*
|
|
8
|
+
* Implements a custom Kysely Driver that wraps sqlite3's callback API
|
|
9
|
+
* into the promise-based interface Kysely expects.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { SerializePlugin } from '@syncular/core';
|
|
13
|
+
import type {
|
|
14
|
+
DatabaseConnection,
|
|
15
|
+
DatabaseIntrospector,
|
|
16
|
+
Dialect,
|
|
17
|
+
DialectAdapter,
|
|
18
|
+
Driver,
|
|
19
|
+
QueryCompiler,
|
|
20
|
+
QueryResult,
|
|
21
|
+
TransactionSettings,
|
|
22
|
+
} from 'kysely';
|
|
23
|
+
import {
|
|
24
|
+
CompiledQuery,
|
|
25
|
+
Kysely,
|
|
26
|
+
SqliteAdapter,
|
|
27
|
+
SqliteIntrospector,
|
|
28
|
+
SqliteQueryCompiler,
|
|
29
|
+
} from 'kysely';
|
|
30
|
+
import sqlite3 from 'sqlite3';
|
|
31
|
+
|
|
32
|
+
interface Sqlite3PathOptions {
|
|
33
|
+
/** Path to SQLite database file, or ':memory:' for in-memory */
|
|
34
|
+
path: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface Sqlite3InstanceOptions {
|
|
38
|
+
/** An existing sqlite3.Database instance */
|
|
39
|
+
database: sqlite3.Database;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type Sqlite3Options = Sqlite3PathOptions | Sqlite3InstanceOptions;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Create a Kysely instance with node-sqlite3 dialect and SerializePlugin.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* const db = createSqlite3Db<MyDb>({ path: './data.db' });
|
|
49
|
+
* const db = createSqlite3Db<MyDb>({ path: ':memory:' });
|
|
50
|
+
*/
|
|
51
|
+
export function createSqlite3Db<T>(options: Sqlite3Options): Kysely<T> {
|
|
52
|
+
return new Kysely<T>({
|
|
53
|
+
dialect: createSqlite3Dialect(options),
|
|
54
|
+
plugins: [new SerializePlugin()],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create the sqlite3 dialect directly (without SerializePlugin).
|
|
60
|
+
*/
|
|
61
|
+
function createSqlite3Dialect(options: Sqlite3Options): Sqlite3Dialect {
|
|
62
|
+
return new Sqlite3Dialect(options);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createSerializePlugin(): SerializePlugin {
|
|
66
|
+
return new SerializePlugin();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Kysely Dialect implementation for node-sqlite3
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
class Sqlite3Dialect implements Dialect {
|
|
74
|
+
readonly #options: Sqlite3Options;
|
|
75
|
+
|
|
76
|
+
constructor(options: Sqlite3Options) {
|
|
77
|
+
this.#options = options;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
createAdapter(): DialectAdapter {
|
|
81
|
+
return new SqliteAdapter();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
createDriver(): Driver {
|
|
85
|
+
return new Sqlite3Driver(this.#options);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
createQueryCompiler(): QueryCompiler {
|
|
89
|
+
return new SqliteQueryCompiler();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
createIntrospector(db: Kysely<any>): DatabaseIntrospector {
|
|
93
|
+
return new SqliteIntrospector(db);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
class Sqlite3Driver implements Driver {
|
|
98
|
+
readonly #options: Sqlite3Options;
|
|
99
|
+
#db: sqlite3.Database | undefined;
|
|
100
|
+
|
|
101
|
+
constructor(options: Sqlite3Options) {
|
|
102
|
+
this.#options = options;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async init(): Promise<void> {
|
|
106
|
+
this.#db = await this.#resolveDatabase();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async acquireConnection(): Promise<DatabaseConnection> {
|
|
110
|
+
return new Sqlite3Connection(this.#db!);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async beginTransaction(
|
|
114
|
+
connection: DatabaseConnection,
|
|
115
|
+
_settings: TransactionSettings
|
|
116
|
+
): Promise<void> {
|
|
117
|
+
await connection.executeQuery(CompiledQuery.raw('begin'));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async commitTransaction(connection: DatabaseConnection): Promise<void> {
|
|
121
|
+
await connection.executeQuery(CompiledQuery.raw('commit'));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async rollbackTransaction(connection: DatabaseConnection): Promise<void> {
|
|
125
|
+
await connection.executeQuery(CompiledQuery.raw('rollback'));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async releaseConnection(_connection: DatabaseConnection): Promise<void> {
|
|
129
|
+
// Single-connection model — nothing to release.
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async destroy(): Promise<void> {
|
|
133
|
+
if (this.#db) {
|
|
134
|
+
await new Promise<void>((resolve, reject) => {
|
|
135
|
+
this.#db!.close((err) => (err ? reject(err) : resolve()));
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async #resolveDatabase(): Promise<sqlite3.Database> {
|
|
141
|
+
if ('database' in this.#options) {
|
|
142
|
+
return this.#options.database;
|
|
143
|
+
}
|
|
144
|
+
const path = this.#options.path;
|
|
145
|
+
return new Promise<sqlite3.Database>((resolve, reject) => {
|
|
146
|
+
const db = new sqlite3.Database(path, (err) => {
|
|
147
|
+
if (err) reject(err);
|
|
148
|
+
else resolve(db);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
class Sqlite3Connection implements DatabaseConnection {
|
|
155
|
+
readonly #db: sqlite3.Database;
|
|
156
|
+
|
|
157
|
+
constructor(db: sqlite3.Database) {
|
|
158
|
+
this.#db = db;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async executeQuery<R>(compiledQuery: CompiledQuery): Promise<QueryResult<R>> {
|
|
162
|
+
const { sql, parameters } = compiledQuery;
|
|
163
|
+
const params = [...parameters];
|
|
164
|
+
|
|
165
|
+
// Determine if this is a SELECT / RETURNING query
|
|
166
|
+
const isSelect = /^\s*(select|pragma|explain|with)\b/i.test(sql);
|
|
167
|
+
const isInsert = /^\s*(insert|replace)\b/i.test(sql);
|
|
168
|
+
|
|
169
|
+
if (isSelect) {
|
|
170
|
+
return new Promise<QueryResult<R>>((resolve, reject) => {
|
|
171
|
+
this.#db.all(sql, params, (err: Error | null, rows: R[]) => {
|
|
172
|
+
if (err) return reject(err);
|
|
173
|
+
resolve({ rows: rows ?? [] });
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// For INSERT, UPDATE, DELETE — use run() to get lastID and changes
|
|
179
|
+
return new Promise<QueryResult<R>>((resolve, reject) => {
|
|
180
|
+
this.#db.run(sql, params, function (err: Error | null) {
|
|
181
|
+
if (err) return reject(err);
|
|
182
|
+
resolve({
|
|
183
|
+
rows: [],
|
|
184
|
+
numAffectedRows: BigInt(this.changes),
|
|
185
|
+
...(isInsert ? { insertId: BigInt(this.lastID) } : {}),
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
streamQuery<R>(
|
|
192
|
+
_compiledQuery: CompiledQuery,
|
|
193
|
+
_chunkSize?: number
|
|
194
|
+
): AsyncIterableIterator<QueryResult<R>> {
|
|
195
|
+
throw new Error('sqlite3 driver does not support streaming');
|
|
196
|
+
}
|
|
197
|
+
}
|