@peerbit/indexer-sqlite3 1.2.26 → 1.2.27-a4bcfcf
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/peerbit/sqlite3.min.js +78 -17
- package/dist/peerbit/sqlite3.worker.min.js +13 -1
- package/dist/src/engine.d.ts +4 -0
- package/dist/src/engine.d.ts.map +1 -1
- package/dist/src/engine.js +69 -17
- package/dist/src/engine.js.map +1 -1
- package/dist/src/schema.d.ts +2 -2
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +2 -2
- package/dist/src/schema.js.map +1 -1
- package/dist/src/sqlite3.browser.js +1 -1
- package/dist/src/sqlite3.browser.js.map +1 -1
- package/dist/src/sqlite3.wasm.d.ts.map +1 -1
- package/dist/src/sqlite3.wasm.js +20 -1
- package/dist/src/sqlite3.wasm.js.map +1 -1
- package/dist/src/utils.d.ts +2 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +8 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +78 -78
- package/src/engine.ts +81 -23
- package/src/schema.ts +6 -4
- package/src/sqlite3.browser.ts +1 -1
- package/src/sqlite3.wasm.ts +23 -1
- package/src/utils.ts +9 -0
package/src/engine.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
selectChildren,
|
|
31
31
|
} from "./schema.js";
|
|
32
32
|
import type { Database, Statement } from "./types.js";
|
|
33
|
+
import { isFKError } from "./utils.js";
|
|
33
34
|
|
|
34
35
|
const escapePathToSQLName = (path: string[]) => {
|
|
35
36
|
return path.map((x) => x.replace(/[^a-zA-Z0-9]/g, "_"));
|
|
@@ -40,6 +41,49 @@ const replaceStatementKey = (table: Table) => table.name + "_replicate";
|
|
|
40
41
|
const resolveChildrenStatement = (table: Table) =>
|
|
41
42
|
table.name + "_resolve_children";
|
|
42
43
|
|
|
44
|
+
type FKMode = "strict" | "race-tolerant";
|
|
45
|
+
|
|
46
|
+
async function safeReset(stmt?: Statement) {
|
|
47
|
+
if (!stmt || !stmt.reset) return;
|
|
48
|
+
try {
|
|
49
|
+
await stmt.reset();
|
|
50
|
+
} catch (e) {
|
|
51
|
+
if (isFKError(e)) return; // swallow FK-reset noise
|
|
52
|
+
throw e;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function runIgnoreFK(stmt: Statement, values: any[]) {
|
|
57
|
+
try {
|
|
58
|
+
await stmt.run(values);
|
|
59
|
+
await safeReset(stmt); // success path: reset safely
|
|
60
|
+
return;
|
|
61
|
+
} catch (e) {
|
|
62
|
+
if (isFKError(e)) {
|
|
63
|
+
await safeReset(stmt); // swallow FK + swallow reset error
|
|
64
|
+
return; // pretend no-op
|
|
65
|
+
}
|
|
66
|
+
// real error
|
|
67
|
+
await safeReset(stmt); // best effort
|
|
68
|
+
throw e;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function getIgnoreFK(stmt: Statement, values: any[]) {
|
|
73
|
+
try {
|
|
74
|
+
const out = await stmt.get(values);
|
|
75
|
+
await safeReset(stmt); // success path
|
|
76
|
+
return out;
|
|
77
|
+
} catch (e) {
|
|
78
|
+
if (isFKError(e)) {
|
|
79
|
+
await safeReset(stmt); // swallow FK + reset error
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
await safeReset(stmt);
|
|
83
|
+
throw e;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
43
87
|
export class SQLLiteIndex<T extends Record<string, any>>
|
|
44
88
|
implements Index<T, any>
|
|
45
89
|
{
|
|
@@ -61,6 +105,7 @@ export class SQLLiteIndex<T extends Record<string, any>>
|
|
|
61
105
|
|
|
62
106
|
iteratorTimeout: number;
|
|
63
107
|
closed: boolean = true;
|
|
108
|
+
private fkMode: FKMode;
|
|
64
109
|
|
|
65
110
|
id: string;
|
|
66
111
|
constructor(
|
|
@@ -71,8 +116,9 @@ export class SQLLiteIndex<T extends Record<string, any>>
|
|
|
71
116
|
start?: () => Promise<void> | void;
|
|
72
117
|
stop?: () => Promise<void> | void;
|
|
73
118
|
},
|
|
74
|
-
options?: { iteratorTimeout?: number },
|
|
119
|
+
options?: { iteratorTimeout?: number; fkMode?: FKMode },
|
|
75
120
|
) {
|
|
121
|
+
this.fkMode = options?.fkMode || "race-tolerant";
|
|
76
122
|
this.closed = true;
|
|
77
123
|
this.id = uuid();
|
|
78
124
|
this.scopeString =
|
|
@@ -347,26 +393,33 @@ export class SQLLiteIndex<T extends Record<string, any>>
|
|
|
347
393
|
return insert(
|
|
348
394
|
async (values, table) => {
|
|
349
395
|
let preId = values[table.primaryIndex];
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
396
|
+
let statement: Statement | undefined = undefined;
|
|
397
|
+
try {
|
|
398
|
+
if (preId != null) {
|
|
399
|
+
statement = this.properties.db.statements.get(
|
|
400
|
+
replaceStatementKey(table),
|
|
401
|
+
)!;
|
|
402
|
+
this.fkMode === "race-tolerant"
|
|
403
|
+
? await runIgnoreFK(statement, values)
|
|
404
|
+
: await statement.run(values);
|
|
405
|
+
return preId;
|
|
406
|
+
} else {
|
|
407
|
+
statement = this.properties.db.statements.get(
|
|
408
|
+
putStatementKey(table),
|
|
409
|
+
)!;
|
|
410
|
+
const out =
|
|
411
|
+
this.fkMode === "race-tolerant"
|
|
412
|
+
? await getIgnoreFK(statement, values)
|
|
413
|
+
: await statement.get(values);
|
|
414
|
+
|
|
415
|
+
// TODO types
|
|
416
|
+
if (out == null) {
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
return out[table.primary as string];
|
|
368
420
|
}
|
|
369
|
-
|
|
421
|
+
} finally {
|
|
422
|
+
await statement?.reset?.();
|
|
370
423
|
}
|
|
371
424
|
},
|
|
372
425
|
value,
|
|
@@ -441,8 +494,6 @@ export class SQLLiteIndex<T extends Record<string, any>>
|
|
|
441
494
|
|
|
442
495
|
once = true;
|
|
443
496
|
|
|
444
|
-
/* console.log("----------------------")
|
|
445
|
-
console.log(sqlFetch); */
|
|
446
497
|
const allResults = await planningScope.perform(async () => {
|
|
447
498
|
const allResults: Record<string, any>[] = await stmt.all([
|
|
448
499
|
...bindable,
|
|
@@ -585,7 +636,14 @@ export class SQLLiteIndex<T extends Record<string, any>>
|
|
|
585
636
|
|
|
586
637
|
// TODO types
|
|
587
638
|
for (const result of results) {
|
|
588
|
-
ret.push(
|
|
639
|
+
ret.push(
|
|
640
|
+
types.toId(
|
|
641
|
+
convertFromSQLType(
|
|
642
|
+
result[table.primary as string],
|
|
643
|
+
table.primaryField!.from!.type,
|
|
644
|
+
),
|
|
645
|
+
),
|
|
646
|
+
);
|
|
589
647
|
}
|
|
590
648
|
once = true;
|
|
591
649
|
} catch (error) {
|
package/src/schema.ts
CHANGED
|
@@ -96,7 +96,7 @@ export class MissingFieldError extends Error {
|
|
|
96
96
|
|
|
97
97
|
export const convertFromSQLType = (
|
|
98
98
|
value: boolean | bigint | string | number | Uint8Array,
|
|
99
|
-
type
|
|
99
|
+
type: FieldType | undefined,
|
|
100
100
|
) => {
|
|
101
101
|
if (type === "bool") {
|
|
102
102
|
if (
|
|
@@ -341,7 +341,7 @@ export const getSQLFields = (
|
|
|
341
341
|
? sqlFields.find((field) => field.name === primary)
|
|
342
342
|
: undefined;
|
|
343
343
|
const parentPrimaryFieldName =
|
|
344
|
-
parentPrimaryField?.
|
|
344
|
+
parentPrimaryField?.name || CHILD_TABLE_ID;
|
|
345
345
|
const parentPrimaryFieldType = parentPrimaryField
|
|
346
346
|
? parentPrimaryField.type
|
|
347
347
|
: "INTEGER";
|
|
@@ -707,7 +707,9 @@ export const insert = async (
|
|
|
707
707
|
tables: Map<string, Table>,
|
|
708
708
|
table: Table,
|
|
709
709
|
fields: Field[],
|
|
710
|
-
handleNestedCallback?: (
|
|
710
|
+
handleNestedCallback?: (
|
|
711
|
+
cb: (parentId: any) => Promise<void>,
|
|
712
|
+
) => Promise<void> | void | number,
|
|
711
713
|
parentId: any = undefined,
|
|
712
714
|
index?: number,
|
|
713
715
|
): Promise<void> => {
|
|
@@ -843,7 +845,7 @@ export const insert = async (
|
|
|
843
845
|
// we need to know the id of the parent document to insert the foreign key correctly
|
|
844
846
|
for (const nested of nestedFields) {
|
|
845
847
|
const isOptional = nested.type instanceof OptionKind;
|
|
846
|
-
handleNestedCallback!((id) => handleNested(nested, isOptional, id));
|
|
848
|
+
await handleNestedCallback!((id) => handleNested(nested, isOptional, id));
|
|
847
849
|
}
|
|
848
850
|
|
|
849
851
|
const thisId = await insertFn(bindableValues, table);
|
package/src/sqlite3.browser.ts
CHANGED
|
@@ -236,7 +236,7 @@ const init = async (): Promise<DatabaseCreator> => {
|
|
|
236
236
|
|
|
237
237
|
const resolver = resolvers[message.id];
|
|
238
238
|
if (message.type === "error") {
|
|
239
|
-
resolver.reject(message.message);
|
|
239
|
+
resolver.reject(new Error(message.message));
|
|
240
240
|
} else if (message.type === "response") {
|
|
241
241
|
resolver.resolve(message.result);
|
|
242
242
|
}
|
package/src/sqlite3.wasm.ts
CHANGED
|
@@ -66,7 +66,29 @@ class Statement implements IStatement {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
async reset() {
|
|
69
|
-
|
|
69
|
+
try {
|
|
70
|
+
await this.statement.reset(); // this returns the last rc
|
|
71
|
+
} catch (e: any) {
|
|
72
|
+
// sqlite3_reset() can surface the prior step/exec rc.
|
|
73
|
+
// The statement *is* reset; ignore benign codes.
|
|
74
|
+
const msg = e?.message || "";
|
|
75
|
+
const rc = e?.rc;
|
|
76
|
+
const code = e?.code;
|
|
77
|
+
|
|
78
|
+
const isFk =
|
|
79
|
+
code === "SQLITE_CONSTRAINT_FOREIGNKEY" ||
|
|
80
|
+
rc === 787 ||
|
|
81
|
+
msg.includes("SQLITE_CONSTRAINT_FOREIGNKEY") ||
|
|
82
|
+
msg.includes("FOREIGN KEY constraint failed");
|
|
83
|
+
|
|
84
|
+
const isBusy = code === "SQLITE_BUSY" || rc === 5; // optional
|
|
85
|
+
|
|
86
|
+
if (isFk || isBusy) {
|
|
87
|
+
return this as IStatement; // swallow; stmt is reset
|
|
88
|
+
}
|
|
89
|
+
// (keep throwing for other unexpected errors)
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
70
92
|
return this as IStatement;
|
|
71
93
|
}
|
|
72
94
|
|
package/src/utils.ts
ADDED