@syncular/dialect-expo-sqlite 0.0.1-118 → 0.0.1-120
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.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.test.ts +141 -1
- package/src/index.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -82,7 +82,7 @@ class ExpoSqliteDriver {
|
|
|
82
82
|
return new ExpoSqliteConnection(this.#db);
|
|
83
83
|
}
|
|
84
84
|
async beginTransaction(connection, _settings) {
|
|
85
|
-
await connection.executeQuery(CompiledQuery.raw('begin'));
|
|
85
|
+
await connection.executeQuery(CompiledQuery.raw('begin immediate'));
|
|
86
86
|
}
|
|
87
87
|
async commitTransaction(connection) {
|
|
88
88
|
await connection.executeQuery(CompiledQuery.raw('commit'));
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAWjD,OAAO,EACL,aAAa,EACb,MAAM,EACN,aAAa,EACb,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,QAAQ,CAAC;AAyChB;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAAI,OAA0B,EAAa;IAC3E,OAAO,IAAI,MAAM,CAAI;QACnB,OAAO,EAAE,uBAAuB,CAAC,OAAO,CAAC;QACzC,OAAO,EAAE,CAAC,IAAI,eAAe,EAAE,CAAC;KACjC,CAAC,CAAC;AAAA,CACJ;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAA0B,EACP;IACnB,OAAO,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAAA,CACvC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,GAAoB;IACvD,OAAO,IAAI,eAAe,EAAE,CAAC;AAAA,CAC9B;AAED,8EAA8E;AAC9E,gDAAgD;AAChD,8EAA8E;AAE9E,MAAM,iBAAiB;IACZ,QAAQ,CAAoB;IAErC,YAAY,OAA0B,EAAE;QACtC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAAA,CACzB;IAED,aAAa,GAAmB;QAC9B,OAAO,IAAI,aAAa,EAAE,CAAC;IAAA,CAC5B;IAED,YAAY,GAAW;QACrB,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAAA,CAC5C;IAED,mBAAmB,GAAkB;QACnC,OAAO,IAAI,mBAAmB,EAAE,CAAC;IAAA,CAClC;IAED,kBAAkB,CAAC,EAAmB,EAAwB;QAC5D,OAAO,IAAI,kBAAkB,CAAC,EAAE,CAAC,CAAC;IAAA,CACnC;CACF;AAED,MAAM,gBAAgB;IACX,QAAQ,CAAoB;IACrC,GAAG,CAAqC;IAExC,YAAY,OAA0B,EAAE;QACtC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAAA,CACzB;IAED,KAAK,CAAC,IAAI,GAAkB;QAC1B,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACnC,kEAAkE;QAClE,oEAAoE;QACpE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;QAClD,mEAAmE;QACnE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC;IAAA,CACpD;IAED,KAAK,CAAC,iBAAiB,GAAgC;QACrD,OAAO,IAAI,oBAAoB,CAAC,IAAI,CAAC,GAAI,CAAC,CAAC;IAAA,CAC5C;IAED,KAAK,CAAC,gBAAgB,CACpB,UAA8B,EAC9B,SAA8B,EACf;QACf,MAAM,UAAU,CAAC,YAAY,CAAC,aAAa,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/dialect-expo-sqlite",
|
|
3
|
-
"version": "0.0.1-
|
|
3
|
+
"version": "0.0.1-120",
|
|
4
4
|
"description": "Expo SQLite dialect for the Syncular client",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"release": "bunx syncular-publish"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@syncular/core": "0.0.1-
|
|
46
|
+
"@syncular/core": "0.0.1-120"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"expo-sqlite": "^16.0.10",
|
package/src/index.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
1
2
|
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
|
|
2
|
-
import type
|
|
3
|
+
import { type Kysely, sql } from 'kysely';
|
|
3
4
|
import type {
|
|
4
5
|
ExpoSqliteBindParams,
|
|
5
6
|
ExpoSqliteBindValue,
|
|
@@ -103,3 +104,142 @@ describe('expo sqlite dialect RETURNING behavior', () => {
|
|
|
103
104
|
await db.destroy();
|
|
104
105
|
});
|
|
105
106
|
});
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Adapter that wraps bun:sqlite Database to match ExpoSqliteDatabaseLike,
|
|
110
|
+
* so we can run real SQLite concurrency tests without expo-sqlite.
|
|
111
|
+
*/
|
|
112
|
+
class BunSqliteAdapter implements ExpoSqliteDatabaseLike {
|
|
113
|
+
readonly #db: Database;
|
|
114
|
+
|
|
115
|
+
constructor(path = ':memory:') {
|
|
116
|
+
this.#db = new Database(path);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
getAllSync<R>(sqlStr: string, params: ExpoSqliteBindParams): R[];
|
|
120
|
+
getAllSync<R>(sqlStr: string, ...params: readonly ExpoSqliteBindValue[]): R[];
|
|
121
|
+
getAllSync<R>(
|
|
122
|
+
sqlStr: string,
|
|
123
|
+
...paramsOrFirst:
|
|
124
|
+
| readonly [ExpoSqliteBindParams]
|
|
125
|
+
| readonly ExpoSqliteBindValue[]
|
|
126
|
+
): R[] {
|
|
127
|
+
const p = this.#resolveParams(paramsOrFirst);
|
|
128
|
+
return this.#db.prepare(sqlStr).all(...p) as R[];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
runSync(sqlStr: string, params: ExpoSqliteBindParams): ExpoSqliteRunResult;
|
|
132
|
+
runSync(
|
|
133
|
+
sqlStr: string,
|
|
134
|
+
...params: readonly ExpoSqliteBindValue[]
|
|
135
|
+
): ExpoSqliteRunResult;
|
|
136
|
+
runSync(
|
|
137
|
+
sqlStr: string,
|
|
138
|
+
...paramsOrFirst:
|
|
139
|
+
| readonly [ExpoSqliteBindParams]
|
|
140
|
+
| readonly ExpoSqliteBindValue[]
|
|
141
|
+
): ExpoSqliteRunResult {
|
|
142
|
+
const p = this.#resolveParams(paramsOrFirst);
|
|
143
|
+
const result = this.#db.run(sqlStr, ...p);
|
|
144
|
+
return {
|
|
145
|
+
changes: result.changes,
|
|
146
|
+
lastInsertRowId: Number(result.lastInsertRowid),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
closeSync(): void {
|
|
151
|
+
this.#db.close();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#resolveParams(
|
|
155
|
+
paramsOrFirst:
|
|
156
|
+
| readonly [ExpoSqliteBindParams]
|
|
157
|
+
| readonly ExpoSqliteBindValue[]
|
|
158
|
+
): ExpoSqliteBindValue[] {
|
|
159
|
+
if (paramsOrFirst.length === 1 && Array.isArray(paramsOrFirst[0])) {
|
|
160
|
+
return paramsOrFirst[0] as ExpoSqliteBindValue[];
|
|
161
|
+
}
|
|
162
|
+
return paramsOrFirst as ExpoSqliteBindValue[];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
interface ConcurrencyDb {
|
|
167
|
+
items: { id: number; value: string };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
describe('expo sqlite dialect concurrency (real SQLite)', () => {
|
|
171
|
+
let adapter: BunSqliteAdapter;
|
|
172
|
+
let db: Kysely<ConcurrencyDb>;
|
|
173
|
+
|
|
174
|
+
beforeEach(async () => {
|
|
175
|
+
adapter = new BunSqliteAdapter();
|
|
176
|
+
db = createExpoSqliteDb<ConcurrencyDb>({ database: adapter });
|
|
177
|
+
await sql`create table items (id integer primary key, value text)`.execute(
|
|
178
|
+
db
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
afterEach(async () => {
|
|
183
|
+
await db.destroy();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('concurrent transaction + read does not deadlock', async () => {
|
|
187
|
+
// Seed data
|
|
188
|
+
for (let i = 0; i < 100; i++) {
|
|
189
|
+
await db
|
|
190
|
+
.insertInto('items')
|
|
191
|
+
.values({ id: i, value: `v${i}` })
|
|
192
|
+
.execute();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Simulate sync engine: long-running write transaction
|
|
196
|
+
const writeTx = db.transaction().execute(async (trx) => {
|
|
197
|
+
for (let i = 100; i < 200; i++) {
|
|
198
|
+
await trx
|
|
199
|
+
.insertInto('items')
|
|
200
|
+
.values({ id: i, value: `tx-${i}` })
|
|
201
|
+
.execute();
|
|
202
|
+
}
|
|
203
|
+
// Yield to allow the concurrent read to interleave
|
|
204
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
205
|
+
for (let i = 200; i < 300; i++) {
|
|
206
|
+
await trx
|
|
207
|
+
.insertInto('items')
|
|
208
|
+
.values({ id: i, value: `tx-${i}` })
|
|
209
|
+
.execute();
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Simulate React hook: concurrent read while transaction is open
|
|
214
|
+
const readResult = db.selectFrom('items').select(['id', 'value']).execute();
|
|
215
|
+
|
|
216
|
+
// Both should complete without "database is locked"
|
|
217
|
+
const [, rows] = await Promise.all([writeTx, readResult]);
|
|
218
|
+
expect(rows.length).toBeGreaterThanOrEqual(100);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('sequential write transactions complete without error', async () => {
|
|
222
|
+
await db.transaction().execute(async (trx) => {
|
|
223
|
+
for (let i = 0; i < 50; i++) {
|
|
224
|
+
await trx
|
|
225
|
+
.insertInto('items')
|
|
226
|
+
.values({ id: i, value: `a-${i}` })
|
|
227
|
+
.execute();
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
await db.transaction().execute(async (trx) => {
|
|
232
|
+
for (let i = 1000; i < 1050; i++) {
|
|
233
|
+
await trx
|
|
234
|
+
.insertInto('items')
|
|
235
|
+
.values({ id: i, value: `b-${i}` })
|
|
236
|
+
.execute();
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
const { rows } = await sql<{
|
|
241
|
+
cnt: number;
|
|
242
|
+
}>`select count(*) as cnt from items`.execute(db);
|
|
243
|
+
expect(rows[0].cnt).toBe(100);
|
|
244
|
+
});
|
|
245
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -158,7 +158,7 @@ class ExpoSqliteDriver implements Driver {
|
|
|
158
158
|
connection: DatabaseConnection,
|
|
159
159
|
_settings: TransactionSettings
|
|
160
160
|
): Promise<void> {
|
|
161
|
-
await connection.executeQuery(CompiledQuery.raw('begin'));
|
|
161
|
+
await connection.executeQuery(CompiledQuery.raw('begin immediate'));
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
async commitTransaction(connection: DatabaseConnection): Promise<void> {
|