bun-sqlite-for-rxdb 1.0.1
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/.serena/project.yml +84 -0
- package/CHANGELOG.md +300 -0
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/ROADMAP.md +532 -0
- package/benchmarks/benchmark.ts +145 -0
- package/benchmarks/case-insensitive-10runs.ts +156 -0
- package/benchmarks/fts5-1m-scale.ts +126 -0
- package/benchmarks/fts5-before-after.ts +104 -0
- package/benchmarks/indexed-benchmark.ts +141 -0
- package/benchmarks/new-operators-benchmark.ts +140 -0
- package/benchmarks/query-builder-benchmark.ts +88 -0
- package/benchmarks/query-builder-consistency.ts +109 -0
- package/benchmarks/raw-better-sqlite3-10m.ts +85 -0
- package/benchmarks/raw-better-sqlite3.ts +86 -0
- package/benchmarks/raw-bun-sqlite-10m.ts +85 -0
- package/benchmarks/raw-bun-sqlite.ts +86 -0
- package/benchmarks/regex-10runs-all.ts +216 -0
- package/benchmarks/regex-comparison-benchmark.ts +161 -0
- package/benchmarks/regex-real-comparison.ts +213 -0
- package/benchmarks/run-10x.sh +19 -0
- package/benchmarks/smart-regex-benchmark.ts +148 -0
- package/benchmarks/sql-vs-mingo-benchmark.ts +210 -0
- package/benchmarks/sql-vs-mingo-comparison.ts +175 -0
- package/benchmarks/text-vs-jsonb.ts +167 -0
- package/benchmarks/wal-benchmark.ts +112 -0
- package/docs/architectural-patterns.md +1336 -0
- package/docs/id1-testsuite-journey.md +839 -0
- package/docs/official-test-suite-setup.md +393 -0
- package/nul +0 -0
- package/package.json +44 -0
- package/src/changestream.test.ts +182 -0
- package/src/cleanup.test.ts +110 -0
- package/src/collection-isolation.test.ts +74 -0
- package/src/connection-pool.test.ts +102 -0
- package/src/connection-pool.ts +38 -0
- package/src/findDocumentsById.test.ts +122 -0
- package/src/index.ts +2 -0
- package/src/instance.ts +382 -0
- package/src/multi-instance-events.test.ts +204 -0
- package/src/query/and-operator.test.ts +39 -0
- package/src/query/builder.test.ts +96 -0
- package/src/query/builder.ts +154 -0
- package/src/query/elemMatch-operator.test.ts +24 -0
- package/src/query/exists-operator.test.ts +28 -0
- package/src/query/in-operators.test.ts +54 -0
- package/src/query/mod-operator.test.ts +22 -0
- package/src/query/nested-query.test.ts +198 -0
- package/src/query/not-operators.test.ts +49 -0
- package/src/query/operators.test.ts +70 -0
- package/src/query/operators.ts +185 -0
- package/src/query/or-operator.test.ts +68 -0
- package/src/query/regex-escaping-regression.test.ts +43 -0
- package/src/query/regex-operator.test.ts +44 -0
- package/src/query/schema-mapper.ts +27 -0
- package/src/query/size-operator.test.ts +22 -0
- package/src/query/smart-regex.ts +52 -0
- package/src/query/type-operator.test.ts +37 -0
- package/src/query-cache.test.ts +286 -0
- package/src/rxdb-helpers.test.ts +348 -0
- package/src/rxdb-helpers.ts +262 -0
- package/src/schema-version-isolation.test.ts +126 -0
- package/src/statement-manager.ts +69 -0
- package/src/storage.test.ts +589 -0
- package/src/storage.ts +21 -0
- package/src/types.ts +14 -0
- package/test/rxdb-test-suite.ts +27 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
RxStorageInstance,
|
|
3
|
+
BulkWriteRow,
|
|
4
|
+
RxDocumentData,
|
|
5
|
+
RxStorageWriteError,
|
|
6
|
+
EventBulk,
|
|
7
|
+
RxStorageChangeEvent,
|
|
8
|
+
RxStorageInstanceCreationParams,
|
|
9
|
+
RxStorageDefaultCheckpoint,
|
|
10
|
+
RxAttachmentWriteData
|
|
11
|
+
} from 'rxdb';
|
|
12
|
+
|
|
13
|
+
export interface AttachmentOperation {
|
|
14
|
+
documentId: string;
|
|
15
|
+
attachmentId: string;
|
|
16
|
+
attachmentData: RxAttachmentWriteData;
|
|
17
|
+
digest: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AttachmentRemoveOperation {
|
|
21
|
+
documentId: string;
|
|
22
|
+
attachmentId: string;
|
|
23
|
+
digest: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function randomToken(length: number): string {
|
|
27
|
+
return Math.random().toString(36).substring(2, 2 + length);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function flatClone<T>(obj: T): T {
|
|
31
|
+
return Object.assign({}, obj);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getAttachmentSize(attachmentBase64String: string): number {
|
|
35
|
+
return atob(attachmentBase64String).length;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function attachmentWriteDataToNormalData(writeData: RxAttachmentWriteData): any {
|
|
39
|
+
const data = writeData.data;
|
|
40
|
+
if (!data) {
|
|
41
|
+
return writeData;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
length: getAttachmentSize(data),
|
|
45
|
+
digest: writeData.digest,
|
|
46
|
+
type: writeData.type
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function stripAttachmentsDataFromDocument<T>(doc: RxDocumentData<T>): RxDocumentData<T> {
|
|
51
|
+
if (!doc._attachments || Object.keys(doc._attachments).length === 0) {
|
|
52
|
+
return doc;
|
|
53
|
+
}
|
|
54
|
+
const useDoc = flatClone(doc);
|
|
55
|
+
useDoc._attachments = {};
|
|
56
|
+
Object.entries(doc._attachments).forEach(([attachmentId, attachmentData]) => {
|
|
57
|
+
useDoc._attachments[attachmentId] = attachmentWriteDataToNormalData(attachmentData as RxAttachmentWriteData);
|
|
58
|
+
});
|
|
59
|
+
return useDoc;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function stripAttachmentsDataFromRow<T>(writeRow: BulkWriteRow<T>): BulkWriteRow<T> {
|
|
63
|
+
return {
|
|
64
|
+
previous: writeRow.previous,
|
|
65
|
+
document: stripAttachmentsDataFromDocument(writeRow.document)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function categorizeBulkWriteRows<RxDocType>(
|
|
70
|
+
storageInstance: RxStorageInstance<RxDocType, any, any>,
|
|
71
|
+
primaryPath: string,
|
|
72
|
+
docsInDb: Map<string, RxDocumentData<RxDocType>>,
|
|
73
|
+
bulkWriteRows: BulkWriteRow<RxDocType>[],
|
|
74
|
+
context: string
|
|
75
|
+
): {
|
|
76
|
+
bulkInsertDocs: BulkWriteRow<RxDocType>[];
|
|
77
|
+
bulkUpdateDocs: BulkWriteRow<RxDocType>[];
|
|
78
|
+
errors: RxStorageWriteError<RxDocType>[];
|
|
79
|
+
eventBulk: EventBulk<RxStorageChangeEvent<RxDocumentData<RxDocType>>, RxStorageDefaultCheckpoint>;
|
|
80
|
+
newestRow?: BulkWriteRow<RxDocType>;
|
|
81
|
+
attachmentsAdd: AttachmentOperation[];
|
|
82
|
+
attachmentsRemove: AttachmentRemoveOperation[];
|
|
83
|
+
attachmentsUpdate: AttachmentOperation[];
|
|
84
|
+
} {
|
|
85
|
+
const hasAttachments = !!storageInstance.schema.attachments;
|
|
86
|
+
const bulkInsertDocs: BulkWriteRow<RxDocType>[] = [];
|
|
87
|
+
const bulkUpdateDocs: BulkWriteRow<RxDocType>[] = [];
|
|
88
|
+
const errors: RxStorageWriteError<RxDocType>[] = [];
|
|
89
|
+
const events: RxStorageChangeEvent<RxDocumentData<RxDocType>>[] = [];
|
|
90
|
+
const attachmentsAdd: AttachmentOperation[] = [];
|
|
91
|
+
const attachmentsRemove: AttachmentRemoveOperation[] = [];
|
|
92
|
+
const attachmentsUpdate: AttachmentOperation[] = [];
|
|
93
|
+
let newestRow: BulkWriteRow<RxDocType> | undefined;
|
|
94
|
+
|
|
95
|
+
for (const writeRow of bulkWriteRows) {
|
|
96
|
+
const document = writeRow.document;
|
|
97
|
+
const previous = writeRow.previous;
|
|
98
|
+
const docId = document[primaryPath as keyof RxDocumentData<RxDocType>] as string;
|
|
99
|
+
const documentInDb = docsInDb.get(docId);
|
|
100
|
+
let attachmentError: RxStorageWriteError<RxDocType> | undefined;
|
|
101
|
+
|
|
102
|
+
if (!documentInDb) {
|
|
103
|
+
if (hasAttachments && document._attachments) {
|
|
104
|
+
Object.entries(document._attachments).forEach(([attachmentId, attachmentData]) => {
|
|
105
|
+
const attData = attachmentData as RxAttachmentWriteData;
|
|
106
|
+
if (!attData.data) {
|
|
107
|
+
const error: RxStorageWriteError<RxDocType> = {
|
|
108
|
+
documentId: docId,
|
|
109
|
+
isError: true,
|
|
110
|
+
status: 510,
|
|
111
|
+
writeRow,
|
|
112
|
+
attachmentId
|
|
113
|
+
} as any;
|
|
114
|
+
attachmentError = error;
|
|
115
|
+
errors.push(error);
|
|
116
|
+
} else {
|
|
117
|
+
attachmentsAdd.push({
|
|
118
|
+
documentId: docId,
|
|
119
|
+
attachmentId,
|
|
120
|
+
attachmentData: attData,
|
|
121
|
+
digest: attData.digest
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!attachmentError) {
|
|
128
|
+
if (hasAttachments) {
|
|
129
|
+
bulkInsertDocs.push(stripAttachmentsDataFromRow(writeRow));
|
|
130
|
+
} else {
|
|
131
|
+
bulkInsertDocs.push(writeRow);
|
|
132
|
+
}
|
|
133
|
+
newestRow = writeRow;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!document._deleted) {
|
|
137
|
+
events.push({
|
|
138
|
+
documentId: docId,
|
|
139
|
+
operation: 'INSERT',
|
|
140
|
+
documentData: hasAttachments ? stripAttachmentsDataFromDocument(document) : document,
|
|
141
|
+
previousDocumentData: hasAttachments && previous ? stripAttachmentsDataFromDocument(previous) : previous
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
if (!previous || documentInDb._rev !== previous._rev) {
|
|
146
|
+
errors.push({
|
|
147
|
+
isError: true,
|
|
148
|
+
status: 409,
|
|
149
|
+
documentId: docId,
|
|
150
|
+
writeRow,
|
|
151
|
+
documentInDb
|
|
152
|
+
});
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const updatedRow = hasAttachments ? stripAttachmentsDataFromRow(writeRow) : writeRow;
|
|
157
|
+
|
|
158
|
+
if (hasAttachments) {
|
|
159
|
+
if (document._deleted) {
|
|
160
|
+
if (previous && previous._attachments) {
|
|
161
|
+
Object.keys(previous._attachments).forEach(attachmentId => {
|
|
162
|
+
attachmentsRemove.push({
|
|
163
|
+
documentId: docId,
|
|
164
|
+
attachmentId,
|
|
165
|
+
digest: previous._attachments[attachmentId].digest
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
} else if (document._attachments) {
|
|
170
|
+
Object.entries(document._attachments).forEach(([attachmentId, attachmentData]) => {
|
|
171
|
+
const attData = attachmentData as RxAttachmentWriteData;
|
|
172
|
+
const previousAttachmentData = previous && previous._attachments ? previous._attachments[attachmentId] : undefined;
|
|
173
|
+
|
|
174
|
+
if (!previousAttachmentData) {
|
|
175
|
+
if (!attData.data) {
|
|
176
|
+
const error: RxStorageWriteError<RxDocType> = {
|
|
177
|
+
documentId: docId,
|
|
178
|
+
documentInDb,
|
|
179
|
+
isError: true,
|
|
180
|
+
status: 510,
|
|
181
|
+
writeRow,
|
|
182
|
+
attachmentId
|
|
183
|
+
} as any;
|
|
184
|
+
attachmentError = error;
|
|
185
|
+
} else {
|
|
186
|
+
attachmentsAdd.push({
|
|
187
|
+
documentId: docId,
|
|
188
|
+
attachmentId,
|
|
189
|
+
attachmentData: attData,
|
|
190
|
+
digest: attData.digest
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
const newDigest = updatedRow.document._attachments[attachmentId].digest;
|
|
195
|
+
if (attData.data && previousAttachmentData.digest !== newDigest) {
|
|
196
|
+
attachmentsUpdate.push({
|
|
197
|
+
documentId: docId,
|
|
198
|
+
attachmentId,
|
|
199
|
+
attachmentData: attData,
|
|
200
|
+
digest: attData.digest
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (attachmentError) {
|
|
209
|
+
errors.push(attachmentError);
|
|
210
|
+
} else {
|
|
211
|
+
bulkUpdateDocs.push(updatedRow);
|
|
212
|
+
newestRow = updatedRow;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const previousDeleted = previous && previous._deleted;
|
|
216
|
+
const documentDeleted = document._deleted;
|
|
217
|
+
let operation: 'INSERT' | 'UPDATE' | 'DELETE';
|
|
218
|
+
|
|
219
|
+
if (previousDeleted && !documentDeleted) {
|
|
220
|
+
operation = 'INSERT';
|
|
221
|
+
} else if (!documentDeleted) {
|
|
222
|
+
operation = 'UPDATE';
|
|
223
|
+
} else {
|
|
224
|
+
operation = 'DELETE';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
events.push({
|
|
228
|
+
documentId: docId,
|
|
229
|
+
documentData: hasAttachments ? stripAttachmentsDataFromDocument(document) : document,
|
|
230
|
+
previousDocumentData: previous,
|
|
231
|
+
operation
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
bulkInsertDocs,
|
|
238
|
+
bulkUpdateDocs,
|
|
239
|
+
errors,
|
|
240
|
+
newestRow,
|
|
241
|
+
eventBulk: {
|
|
242
|
+
checkpoint: { id: '', lwt: 0 },
|
|
243
|
+
context,
|
|
244
|
+
events,
|
|
245
|
+
id: randomToken(10)
|
|
246
|
+
},
|
|
247
|
+
attachmentsAdd,
|
|
248
|
+
attachmentsRemove,
|
|
249
|
+
attachmentsUpdate
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function ensureRxStorageInstanceParamsAreCorrect(
|
|
254
|
+
params: RxStorageInstanceCreationParams<any, any>
|
|
255
|
+
): void {
|
|
256
|
+
if (params.schema.keyCompression) {
|
|
257
|
+
throw new Error('UT5: RX_SCHEMA_KEY_COMPRESSION_USED');
|
|
258
|
+
}
|
|
259
|
+
if (params.schema.encrypted && params.schema.encrypted.length > 0 && !params.password) {
|
|
260
|
+
throw new Error('UT6: RX_SCHEMA_ENCRYPTED_FIELDS_MISSING_PASSWORD');
|
|
261
|
+
}
|
|
262
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { describe, test, expect, afterEach } from 'bun:test';
|
|
2
|
+
import { BunSQLiteStorageInstance } from './instance';
|
|
3
|
+
import type { RxStorageInstanceCreationParams } from 'rxdb';
|
|
4
|
+
|
|
5
|
+
describe('Schema Version Isolation', () => {
|
|
6
|
+
const instances: BunSQLiteStorageInstance<any>[] = [];
|
|
7
|
+
|
|
8
|
+
afterEach(async () => {
|
|
9
|
+
for (const instance of instances) {
|
|
10
|
+
await instance.close();
|
|
11
|
+
}
|
|
12
|
+
instances.length = 0;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('different schema versions should use different tables', async () => {
|
|
16
|
+
const baseParams = {
|
|
17
|
+
databaseName: 'testdb',
|
|
18
|
+
collectionName: 'users',
|
|
19
|
+
databaseInstanceToken: 'test',
|
|
20
|
+
options: {},
|
|
21
|
+
devMode: false,
|
|
22
|
+
multiInstance: false
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const instanceV0 = new BunSQLiteStorageInstance({
|
|
26
|
+
...baseParams,
|
|
27
|
+
schema: {
|
|
28
|
+
version: 0,
|
|
29
|
+
primaryKey: 'id',
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: { id: { type: 'string' } }
|
|
32
|
+
},
|
|
33
|
+
internals: {}
|
|
34
|
+
} as RxStorageInstanceCreationParams<any, any>);
|
|
35
|
+
instances.push(instanceV0);
|
|
36
|
+
|
|
37
|
+
const instanceV1 = new BunSQLiteStorageInstance({
|
|
38
|
+
...baseParams,
|
|
39
|
+
schema: {
|
|
40
|
+
version: 1,
|
|
41
|
+
primaryKey: 'id',
|
|
42
|
+
type: 'object',
|
|
43
|
+
properties: { id: { type: 'string' } }
|
|
44
|
+
},
|
|
45
|
+
internals: {}
|
|
46
|
+
} as RxStorageInstanceCreationParams<any, any>);
|
|
47
|
+
instances.push(instanceV1);
|
|
48
|
+
|
|
49
|
+
const docV0 = {
|
|
50
|
+
id: 'doc1',
|
|
51
|
+
_deleted: false,
|
|
52
|
+
_attachments: {},
|
|
53
|
+
_meta: { lwt: Date.now() },
|
|
54
|
+
_rev: '1-abc'
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const docV1 = {
|
|
58
|
+
id: 'doc2',
|
|
59
|
+
_deleted: false,
|
|
60
|
+
_attachments: {},
|
|
61
|
+
_meta: { lwt: Date.now() },
|
|
62
|
+
_rev: '1-def'
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
await instanceV0.bulkWrite([{ document: docV0 }], 'test');
|
|
66
|
+
await instanceV1.bulkWrite([{ document: docV1 }], 'test');
|
|
67
|
+
|
|
68
|
+
const docsV0 = await instanceV0.findDocumentsById(['doc1', 'doc2'], false);
|
|
69
|
+
const docsV1 = await instanceV1.findDocumentsById(['doc1', 'doc2'], false);
|
|
70
|
+
|
|
71
|
+
expect(docsV0.length).toBe(1);
|
|
72
|
+
expect(docsV0[0].id).toBe('doc1');
|
|
73
|
+
|
|
74
|
+
expect(docsV1.length).toBe(1);
|
|
75
|
+
expect(docsV1[0].id).toBe('doc2');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('same schema version should share table', async () => {
|
|
79
|
+
const baseParams = {
|
|
80
|
+
databaseName: 'testdb',
|
|
81
|
+
collectionName: 'users',
|
|
82
|
+
databaseInstanceToken: 'test',
|
|
83
|
+
options: {},
|
|
84
|
+
devMode: false,
|
|
85
|
+
multiInstance: false
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const instance1 = new BunSQLiteStorageInstance({
|
|
89
|
+
...baseParams,
|
|
90
|
+
schema: {
|
|
91
|
+
version: 0,
|
|
92
|
+
primaryKey: 'id',
|
|
93
|
+
type: 'object',
|
|
94
|
+
properties: { id: { type: 'string' } }
|
|
95
|
+
},
|
|
96
|
+
internals: {}
|
|
97
|
+
} as RxStorageInstanceCreationParams<any, any>);
|
|
98
|
+
instances.push(instance1);
|
|
99
|
+
|
|
100
|
+
const instance2 = new BunSQLiteStorageInstance({
|
|
101
|
+
...baseParams,
|
|
102
|
+
schema: {
|
|
103
|
+
version: 0,
|
|
104
|
+
primaryKey: 'id',
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: { id: { type: 'string' } }
|
|
107
|
+
},
|
|
108
|
+
internals: {}
|
|
109
|
+
} as RxStorageInstanceCreationParams<any, any>);
|
|
110
|
+
instances.push(instance2);
|
|
111
|
+
|
|
112
|
+
const doc = {
|
|
113
|
+
id: 'doc1',
|
|
114
|
+
_deleted: false,
|
|
115
|
+
_attachments: {},
|
|
116
|
+
_meta: { lwt: Date.now() },
|
|
117
|
+
_rev: '1-abc'
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
await instance1.bulkWrite([{ document: doc }], 'test');
|
|
121
|
+
|
|
122
|
+
const docs = await instance2.findDocumentsById(['doc1'], false);
|
|
123
|
+
expect(docs.length).toBe(1);
|
|
124
|
+
expect(docs[0].id).toBe('doc1');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Database, Statement, Changes } from 'bun:sqlite';
|
|
2
|
+
|
|
3
|
+
export type QueryWithParams = {
|
|
4
|
+
query: string;
|
|
5
|
+
params: any[];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export class StatementManager {
|
|
9
|
+
private db: Database;
|
|
10
|
+
private staticStatements = new Map<string, Statement>();
|
|
11
|
+
|
|
12
|
+
constructor(db: Database) {
|
|
13
|
+
this.db = db;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
all(queryWithParams: QueryWithParams): any[] {
|
|
17
|
+
const { query, params } = queryWithParams;
|
|
18
|
+
|
|
19
|
+
if (this.isStaticSQL(query)) {
|
|
20
|
+
let stmt = this.staticStatements.get(query);
|
|
21
|
+
if (!stmt) {
|
|
22
|
+
stmt = this.db.query(query);
|
|
23
|
+
this.staticStatements.set(query, stmt);
|
|
24
|
+
}
|
|
25
|
+
return stmt.all(...params);
|
|
26
|
+
} else {
|
|
27
|
+
const stmt = this.db.prepare(query);
|
|
28
|
+
try {
|
|
29
|
+
return stmt.all(...params);
|
|
30
|
+
} finally {
|
|
31
|
+
stmt.finalize();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
run(queryWithParams: QueryWithParams): Changes {
|
|
37
|
+
const { query, params } = queryWithParams;
|
|
38
|
+
|
|
39
|
+
if (this.isStaticSQL(query)) {
|
|
40
|
+
let stmt = this.staticStatements.get(query);
|
|
41
|
+
if (!stmt) {
|
|
42
|
+
stmt = this.db.query(query);
|
|
43
|
+
this.staticStatements.set(query, stmt);
|
|
44
|
+
}
|
|
45
|
+
return stmt.run(...params);
|
|
46
|
+
} else {
|
|
47
|
+
const stmt = this.db.prepare(query);
|
|
48
|
+
try {
|
|
49
|
+
return stmt.run(...params);
|
|
50
|
+
} finally {
|
|
51
|
+
stmt.finalize();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
close(): void {
|
|
57
|
+
for (const stmt of this.staticStatements.values()) {
|
|
58
|
+
stmt.finalize();
|
|
59
|
+
}
|
|
60
|
+
this.staticStatements.clear();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private isStaticSQL(query: string): boolean {
|
|
64
|
+
if (query.includes('WHERE (')) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|