@nymphjs/driver-sqlite3 1.0.0-beta.10 → 1.0.0-beta.101
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/CHANGELOG.md +446 -0
- package/README.md +1 -1
- package/dist/SQLite3Driver.d.ts +81 -14
- package/dist/SQLite3Driver.js +886 -349
- package/dist/SQLite3Driver.js.map +1 -1
- package/dist/SQLite3Driver.test.js +47 -15
- package/dist/SQLite3Driver.test.js.map +1 -1
- package/dist/conf/d.d.ts +58 -1
- package/dist/conf/d.js +1 -2
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +3 -4
- package/dist/conf/defaults.js.map +1 -1
- package/dist/conf/index.d.ts +2 -2
- package/dist/conf/index.js +2 -8
- package/dist/conf/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -24
- package/dist/index.js.map +1 -1
- package/jest.config.js +12 -2
- package/package.json +18 -16
- package/src/SQLite3Driver.test.ts +44 -9
- package/src/SQLite3Driver.ts +1349 -639
- package/src/conf/d.ts +26 -2
- package/src/conf/defaults.ts +3 -2
- package/src/conf/index.ts +2 -2
- package/src/index.ts +2 -2
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
package/src/SQLite3Driver.ts
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import SQLite3 from 'better-sqlite3';
|
|
2
|
+
import type {
|
|
3
|
+
SearchTerm,
|
|
4
|
+
SearchOrTerm,
|
|
5
|
+
SearchNotTerm,
|
|
6
|
+
SearchSeriesTerm,
|
|
7
|
+
} from '@sciactive/tokenizer';
|
|
2
8
|
import {
|
|
3
9
|
NymphDriver,
|
|
4
|
-
EntityConstructor,
|
|
5
|
-
EntityData,
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
type EntityConstructor,
|
|
11
|
+
type EntityData,
|
|
12
|
+
type EntityObjectType,
|
|
13
|
+
type EntityInterface,
|
|
14
|
+
type EntityInstanceType,
|
|
15
|
+
type SerializedEntityData,
|
|
16
|
+
type FormattedSelector,
|
|
17
|
+
type Options,
|
|
18
|
+
type Selector,
|
|
19
|
+
EntityUniqueConstraintError,
|
|
8
20
|
InvalidParametersError,
|
|
9
21
|
NotConfiguredError,
|
|
10
22
|
QueryFailedError,
|
|
11
23
|
UnableToConnectError,
|
|
12
|
-
FormattedSelector,
|
|
13
|
-
Options,
|
|
14
|
-
Selector,
|
|
15
24
|
xor,
|
|
16
25
|
} from '@nymphjs/nymph';
|
|
17
26
|
import { makeTableSuffix } from '@nymphjs/guid';
|
|
@@ -19,10 +28,11 @@ import { makeTableSuffix } from '@nymphjs/guid';
|
|
|
19
28
|
import {
|
|
20
29
|
SQLite3DriverConfig,
|
|
21
30
|
SQLite3DriverConfigDefaults as defaults,
|
|
22
|
-
} from './conf';
|
|
31
|
+
} from './conf/index.js';
|
|
23
32
|
|
|
24
33
|
class InternalStore {
|
|
25
34
|
public link: SQLite3.Database;
|
|
35
|
+
public linkWrite?: SQLite3.Database;
|
|
26
36
|
public connected: boolean = false;
|
|
27
37
|
public transactionsStarted = 0;
|
|
28
38
|
|
|
@@ -43,7 +53,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
43
53
|
static escape(input: string) {
|
|
44
54
|
if (input.indexOf('\x00') !== -1) {
|
|
45
55
|
throw new InvalidParametersError(
|
|
46
|
-
'SQLite3 identifiers (like entity ETYPE) cannot contain null characters.'
|
|
56
|
+
'SQLite3 identifiers (like entity ETYPE) cannot contain null characters.',
|
|
47
57
|
);
|
|
48
58
|
}
|
|
49
59
|
|
|
@@ -53,6 +63,9 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
53
63
|
constructor(config: Partial<SQLite3DriverConfig>, store?: InternalStore) {
|
|
54
64
|
super();
|
|
55
65
|
this.config = { ...defaults, ...config };
|
|
66
|
+
if (this.config.filename === ':memory:') {
|
|
67
|
+
this.config.explicitWrite = true;
|
|
68
|
+
}
|
|
56
69
|
this.prefix = this.config.prefix;
|
|
57
70
|
if (store) {
|
|
58
71
|
this.store = store;
|
|
@@ -75,57 +88,107 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
75
88
|
*
|
|
76
89
|
* @returns Whether this instance is connected to a SQLite3 database.
|
|
77
90
|
*/
|
|
78
|
-
public
|
|
79
|
-
const { filename, fileMustExist, timeout, readonly, wal, verbose } =
|
|
80
|
-
this.config;
|
|
81
|
-
|
|
91
|
+
public connect() {
|
|
82
92
|
if (this.store && this.store.connected) {
|
|
83
|
-
return true;
|
|
93
|
+
return Promise.resolve(true);
|
|
84
94
|
}
|
|
85
95
|
|
|
86
96
|
// Connecting
|
|
97
|
+
this._connect(false);
|
|
98
|
+
|
|
99
|
+
return Promise.resolve(this.store.connected);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private _connect(write: boolean) {
|
|
103
|
+
const { filename, fileMustExist, timeout, explicitWrite, wal, verbose } =
|
|
104
|
+
this.config;
|
|
105
|
+
|
|
87
106
|
try {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
107
|
+
const setOptions = (link: SQLite3.Database) => {
|
|
108
|
+
// Set database and connection options.
|
|
109
|
+
if (wal) {
|
|
110
|
+
link.pragma('journal_mode = WAL;');
|
|
111
|
+
}
|
|
112
|
+
link.pragma('encoding = "UTF-8";');
|
|
113
|
+
link.pragma('foreign_keys = 1;');
|
|
114
|
+
link.pragma('case_sensitive_like = 1;');
|
|
115
|
+
for (let pragma of this.config.pragmas) {
|
|
116
|
+
link.pragma(pragma);
|
|
117
|
+
}
|
|
118
|
+
// Create the preg_match and regexp functions.
|
|
119
|
+
link.function('regexp', { deterministic: true }, ((
|
|
120
|
+
pattern: string,
|
|
121
|
+
subject: string,
|
|
122
|
+
) => (this.posixRegexMatch(pattern, subject) ? 1 : 0)) as (
|
|
123
|
+
...params: any[]
|
|
124
|
+
) => any);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
let link: SQLite3.Database;
|
|
128
|
+
try {
|
|
129
|
+
link = new SQLite3(filename, {
|
|
130
|
+
readonly: !explicitWrite && !write,
|
|
131
|
+
fileMustExist,
|
|
132
|
+
timeout,
|
|
133
|
+
verbose,
|
|
134
|
+
});
|
|
135
|
+
} catch (e: any) {
|
|
136
|
+
if (
|
|
137
|
+
e.code === 'SQLITE_CANTOPEN' &&
|
|
138
|
+
!explicitWrite &&
|
|
139
|
+
!write &&
|
|
140
|
+
!this.config.fileMustExist
|
|
141
|
+
) {
|
|
142
|
+
// This happens when the file doesn't exist and we attempt to open it
|
|
143
|
+
// readonly.
|
|
144
|
+
// First open it in write mode.
|
|
145
|
+
const writeLink = new SQLite3(filename, {
|
|
146
|
+
readonly: false,
|
|
147
|
+
fileMustExist,
|
|
148
|
+
timeout,
|
|
149
|
+
verbose,
|
|
150
|
+
});
|
|
151
|
+
setOptions(writeLink);
|
|
152
|
+
writeLink.close();
|
|
153
|
+
// Now open in readonly.
|
|
154
|
+
link = new SQLite3(filename, {
|
|
155
|
+
readonly: true,
|
|
156
|
+
fileMustExist,
|
|
157
|
+
timeout,
|
|
158
|
+
verbose,
|
|
159
|
+
});
|
|
160
|
+
} else {
|
|
161
|
+
throw e;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
94
164
|
|
|
95
165
|
if (!this.store) {
|
|
166
|
+
if (write) {
|
|
167
|
+
throw new Error(
|
|
168
|
+
'Tried to open in write without opening in read first.',
|
|
169
|
+
);
|
|
170
|
+
}
|
|
96
171
|
this.store = new InternalStore(link);
|
|
172
|
+
} else if (write) {
|
|
173
|
+
this.store.linkWrite = link;
|
|
97
174
|
} else {
|
|
98
175
|
this.store.link = link;
|
|
99
176
|
}
|
|
100
177
|
this.store.connected = true;
|
|
101
|
-
|
|
102
|
-
if (wal) {
|
|
103
|
-
this.store.link.pragma('journal_mode = WAL;');
|
|
104
|
-
}
|
|
105
|
-
this.store.link.pragma('encoding = "UTF-8";');
|
|
106
|
-
this.store.link.pragma('foreign_keys = 1;');
|
|
107
|
-
this.store.link.pragma('case_sensitive_like = 1;');
|
|
108
|
-
// Create the preg_match and regexp functions.
|
|
109
|
-
this.store.link.function(
|
|
110
|
-
'regexp',
|
|
111
|
-
{ deterministic: true },
|
|
112
|
-
(pattern: string, subject: string) =>
|
|
113
|
-
this.posixRegexMatch(pattern, subject) ? 1 : 0
|
|
114
|
-
);
|
|
178
|
+
setOptions(link);
|
|
115
179
|
} catch (e: any) {
|
|
116
180
|
if (this.store) {
|
|
117
181
|
this.store.connected = false;
|
|
118
182
|
}
|
|
119
183
|
if (filename === ':memory:') {
|
|
120
184
|
throw new NotConfiguredError(
|
|
121
|
-
"It seems the config hasn't been set up correctly."
|
|
185
|
+
"It seems the config hasn't been set up correctly. Could not connect: " +
|
|
186
|
+
e?.message,
|
|
122
187
|
);
|
|
123
188
|
} else {
|
|
124
189
|
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
125
190
|
}
|
|
126
191
|
}
|
|
127
|
-
|
|
128
|
-
return this.store.connected;
|
|
129
192
|
}
|
|
130
193
|
|
|
131
194
|
/**
|
|
@@ -135,8 +198,16 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
135
198
|
*/
|
|
136
199
|
public async disconnect() {
|
|
137
200
|
if (this.store.connected) {
|
|
138
|
-
this.store.
|
|
201
|
+
if (this.store.linkWrite && !this.config.explicitWrite) {
|
|
202
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
203
|
+
this.store.linkWrite.close();
|
|
204
|
+
this.store.linkWrite = undefined;
|
|
205
|
+
}
|
|
206
|
+
if (this.config.explicitWrite) {
|
|
207
|
+
this.store.link.exec('PRAGMA optimize;');
|
|
208
|
+
}
|
|
139
209
|
this.store.link.close();
|
|
210
|
+
this.store.transactionsStarted = 0;
|
|
140
211
|
this.store.connected = false;
|
|
141
212
|
}
|
|
142
213
|
return this.store.connected;
|
|
@@ -155,15 +226,242 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
155
226
|
return this.store.connected;
|
|
156
227
|
}
|
|
157
228
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
229
|
+
private createEntitiesTable(etype: string) {
|
|
230
|
+
// Create the entity table.
|
|
231
|
+
this.queryRun(
|
|
232
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
233
|
+
`${this.prefix}entities_${etype}`,
|
|
234
|
+
)} ("guid" CHARACTER(24) PRIMARY KEY, "tags" TEXT, "cdate" REAL NOT NULL, "mdate" REAL NOT NULL);`,
|
|
235
|
+
);
|
|
236
|
+
this.queryRun(
|
|
237
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
238
|
+
`${this.prefix}entities_${etype}_id_cdate`,
|
|
239
|
+
)} ON ${SQLite3Driver.escape(
|
|
240
|
+
`${this.prefix}entities_${etype}`,
|
|
241
|
+
)} ("cdate");`,
|
|
242
|
+
);
|
|
243
|
+
this.queryRun(
|
|
244
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
245
|
+
`${this.prefix}entities_${etype}_id_mdate`,
|
|
246
|
+
)} ON ${SQLite3Driver.escape(
|
|
247
|
+
`${this.prefix}entities_${etype}`,
|
|
248
|
+
)} ("mdate");`,
|
|
249
|
+
);
|
|
250
|
+
this.queryRun(
|
|
251
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
252
|
+
`${this.prefix}entities_${etype}_id_tags`,
|
|
253
|
+
)} ON ${SQLite3Driver.escape(
|
|
254
|
+
`${this.prefix}entities_${etype}`,
|
|
255
|
+
)} ("tags");`,
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
private createDataTable(etype: string) {
|
|
260
|
+
// Create the data table.
|
|
261
|
+
this.queryRun(
|
|
262
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
263
|
+
`${this.prefix}data_${etype}`,
|
|
264
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
265
|
+
`${this.prefix}entities_${etype}`,
|
|
266
|
+
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "value" CHARACTER(1) NOT NULL, "json" BLOB, "string" TEXT, "number" REAL, "truthy" INTEGER, PRIMARY KEY("guid", "name"));`,
|
|
267
|
+
);
|
|
268
|
+
this.queryRun(
|
|
269
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
270
|
+
`${this.prefix}data_${etype}_id_guid`,
|
|
271
|
+
)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`,
|
|
272
|
+
);
|
|
273
|
+
this.queryRun(
|
|
274
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
275
|
+
`${this.prefix}data_${etype}_id_guid_name`,
|
|
276
|
+
)} ON ${SQLite3Driver.escape(
|
|
277
|
+
`${this.prefix}data_${etype}`,
|
|
278
|
+
)} ("guid", "name");`,
|
|
279
|
+
);
|
|
280
|
+
this.queryRun(
|
|
281
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
282
|
+
`${this.prefix}data_${etype}_id_name`,
|
|
283
|
+
)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`,
|
|
284
|
+
);
|
|
285
|
+
this.queryRun(
|
|
286
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
287
|
+
`${this.prefix}data_${etype}_id_name_string`,
|
|
288
|
+
)} ON ${SQLite3Driver.escape(
|
|
289
|
+
`${this.prefix}data_${etype}`,
|
|
290
|
+
)} ("name", "string");`,
|
|
291
|
+
);
|
|
292
|
+
this.queryRun(
|
|
293
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
294
|
+
`${this.prefix}data_${etype}_id_name_number`,
|
|
295
|
+
)} ON ${SQLite3Driver.escape(
|
|
296
|
+
`${this.prefix}data_${etype}`,
|
|
297
|
+
)} ("name", "number");`,
|
|
298
|
+
);
|
|
299
|
+
this.queryRun(
|
|
300
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
301
|
+
`${this.prefix}data_${etype}_id_guid_name_number`,
|
|
302
|
+
)} ON ${SQLite3Driver.escape(
|
|
303
|
+
`${this.prefix}data_${etype}`,
|
|
304
|
+
)} ("guid", "name", "number");`,
|
|
305
|
+
);
|
|
306
|
+
this.queryRun(
|
|
307
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
308
|
+
`${this.prefix}data_${etype}_id_name_truthy`,
|
|
309
|
+
)} ON ${SQLite3Driver.escape(
|
|
310
|
+
`${this.prefix}data_${etype}`,
|
|
311
|
+
)} ("name", "truthy");`,
|
|
312
|
+
);
|
|
313
|
+
this.queryRun(
|
|
314
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
315
|
+
`${this.prefix}data_${etype}_id_guid_name_truthy`,
|
|
316
|
+
)} ON ${SQLite3Driver.escape(
|
|
317
|
+
`${this.prefix}data_${etype}`,
|
|
318
|
+
)} ("guid", "name", "truthy");`,
|
|
319
|
+
);
|
|
320
|
+
this.queryRun(
|
|
321
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
322
|
+
`${this.prefix}data_${etype}_id_acuserread`,
|
|
323
|
+
)} ON ${SQLite3Driver.escape(
|
|
324
|
+
`${this.prefix}data_${etype}`,
|
|
325
|
+
)} ("guid") WHERE "name"=\'acUser\' AND "number" >= 1;`,
|
|
326
|
+
);
|
|
327
|
+
this.queryRun(
|
|
328
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
329
|
+
`${this.prefix}data_${etype}_id_acgroupread`,
|
|
330
|
+
)} ON ${SQLite3Driver.escape(
|
|
331
|
+
`${this.prefix}data_${etype}`,
|
|
332
|
+
)} ("guid") WHERE "name"=\'acGroup\' AND "number" >= 1;`,
|
|
333
|
+
);
|
|
334
|
+
this.queryRun(
|
|
335
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
336
|
+
`${this.prefix}data_${etype}_id_acotherread`,
|
|
337
|
+
)} ON ${SQLite3Driver.escape(
|
|
338
|
+
`${this.prefix}data_${etype}`,
|
|
339
|
+
)} ("guid") WHERE "name"=\'acOther\' AND "number" >= 1;`,
|
|
340
|
+
);
|
|
341
|
+
this.queryRun(
|
|
342
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
343
|
+
`${this.prefix}data_${etype}_id_acuser`,
|
|
344
|
+
)} ON ${SQLite3Driver.escape(
|
|
345
|
+
`${this.prefix}data_${etype}`,
|
|
346
|
+
)} ("guid") WHERE "name"=\'user\';`,
|
|
347
|
+
);
|
|
348
|
+
this.queryRun(
|
|
349
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
350
|
+
`${this.prefix}data_${etype}_id_acgroup`,
|
|
351
|
+
)} ON ${SQLite3Driver.escape(
|
|
352
|
+
`${this.prefix}data_${etype}`,
|
|
353
|
+
)} ("guid") WHERE "name"=\'group\';`,
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
private createReferencesTable(etype: string) {
|
|
358
|
+
// Create the references table.
|
|
359
|
+
this.queryRun(
|
|
360
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
361
|
+
`${this.prefix}references_${etype}`,
|
|
362
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
363
|
+
`${this.prefix}entities_${etype}`,
|
|
364
|
+
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "reference" CHARACTER(24) NOT NULL, PRIMARY KEY("guid", "name", "reference"));`,
|
|
365
|
+
);
|
|
366
|
+
this.queryRun(
|
|
367
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
368
|
+
`${this.prefix}references_${etype}_id_guid`,
|
|
369
|
+
)} ON ${SQLite3Driver.escape(
|
|
370
|
+
`${this.prefix}references_${etype}`,
|
|
371
|
+
)} ("guid");`,
|
|
372
|
+
);
|
|
373
|
+
this.queryRun(
|
|
374
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
375
|
+
`${this.prefix}references_${etype}_id_name`,
|
|
376
|
+
)} ON ${SQLite3Driver.escape(
|
|
377
|
+
`${this.prefix}references_${etype}`,
|
|
378
|
+
)} ("name");`,
|
|
379
|
+
);
|
|
380
|
+
this.queryRun(
|
|
381
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
382
|
+
`${this.prefix}references_${etype}_id_name_reference`,
|
|
383
|
+
)} ON ${SQLite3Driver.escape(
|
|
384
|
+
`${this.prefix}references_${etype}`,
|
|
385
|
+
)} ("name", "reference");`,
|
|
386
|
+
);
|
|
387
|
+
this.queryRun(
|
|
388
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
389
|
+
`${this.prefix}references_${etype}_id_reference`,
|
|
390
|
+
)} ON ${SQLite3Driver.escape(
|
|
391
|
+
`${this.prefix}references_${etype}`,
|
|
392
|
+
)} ("reference");`,
|
|
393
|
+
);
|
|
394
|
+
this.queryRun(
|
|
395
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
396
|
+
`${this.prefix}references_${etype}_id_guid_name`,
|
|
397
|
+
)} ON ${SQLite3Driver.escape(
|
|
398
|
+
`${this.prefix}references_${etype}`,
|
|
399
|
+
)} ("guid", "name");`,
|
|
400
|
+
);
|
|
401
|
+
this.queryRun(
|
|
402
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
403
|
+
`${this.prefix}references_${etype}_id_guid_name_reference`,
|
|
404
|
+
)} ON ${SQLite3Driver.escape(
|
|
405
|
+
`${this.prefix}references_${etype}`,
|
|
406
|
+
)} ("guid", "name", "reference");`,
|
|
407
|
+
);
|
|
408
|
+
this.queryRun(
|
|
409
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
410
|
+
`${this.prefix}references_${etype}_id_reference_name_guid`,
|
|
411
|
+
)} ON ${SQLite3Driver.escape(
|
|
412
|
+
`${this.prefix}references_${etype}`,
|
|
413
|
+
)} ("reference", "name", "guid");`,
|
|
414
|
+
);
|
|
415
|
+
this.queryRun(
|
|
416
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
417
|
+
`${this.prefix}references_${etype}_id_reference_guid_name`,
|
|
418
|
+
)} ON ${SQLite3Driver.escape(
|
|
419
|
+
`${this.prefix}references_${etype}`,
|
|
420
|
+
)} ("reference", "guid", "name");`,
|
|
421
|
+
);
|
|
422
|
+
this.queryRun(
|
|
423
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
424
|
+
`${this.prefix}references_${etype}_id_guid_reference_nameuser`,
|
|
425
|
+
)} ON ${SQLite3Driver.escape(
|
|
426
|
+
`${this.prefix}references_${etype}`,
|
|
427
|
+
)} ("guid", "reference") WHERE "name"=\'user\';`,
|
|
428
|
+
);
|
|
429
|
+
this.queryRun(
|
|
430
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
431
|
+
`${this.prefix}references_${etype}_id_guid_reference_namegroup`,
|
|
432
|
+
)} ON ${SQLite3Driver.escape(
|
|
433
|
+
`${this.prefix}references_${etype}`,
|
|
434
|
+
)} ("guid", "reference") WHERE "name"=\'group\';`,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private createTokensTable(etype: string) {
|
|
439
|
+
// Create the tokens table.
|
|
440
|
+
this.queryRun(
|
|
441
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
442
|
+
`${this.prefix}tokens_${etype}`,
|
|
443
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
444
|
+
`${this.prefix}entities_${etype}`,
|
|
445
|
+
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "token" INTEGER NOT NULL, "position" INTEGER NOT NULL, "stem" INTEGER NOT NULL, PRIMARY KEY("guid", "name", "token", "position"));`,
|
|
446
|
+
);
|
|
447
|
+
this.queryRun(
|
|
448
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
449
|
+
`${this.prefix}tokens_${etype}_id_name_token`,
|
|
450
|
+
)} ON ${SQLite3Driver.escape(
|
|
451
|
+
`${this.prefix}tokens_${etype}`,
|
|
452
|
+
)} ("name", "token");`,
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
private createUniquesTable(etype: string) {
|
|
457
|
+
// Create the unique strings table.
|
|
458
|
+
this.queryRun(
|
|
459
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
460
|
+
`${this.prefix}uniques_${etype}`,
|
|
461
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
462
|
+
`${this.prefix}entities_${etype}`,
|
|
463
|
+
)} ("guid") ON DELETE CASCADE, "unique" TEXT NOT NULL UNIQUE, PRIMARY KEY("guid", "unique"));`,
|
|
464
|
+
);
|
|
167
465
|
}
|
|
168
466
|
|
|
169
467
|
/**
|
|
@@ -172,160 +470,38 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
172
470
|
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
173
471
|
*/
|
|
174
472
|
private createTables(etype: string | null = null) {
|
|
175
|
-
this.checkReadOnlyMode();
|
|
176
473
|
this.startTransaction('nymph-tablecreation');
|
|
177
474
|
try {
|
|
178
475
|
if (etype != null) {
|
|
179
|
-
|
|
180
|
-
this.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
);
|
|
185
|
-
this.queryRun(
|
|
186
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
187
|
-
`${this.prefix}entities_${etype}_id_cdate`
|
|
188
|
-
)} ON ${SQLite3Driver.escape(
|
|
189
|
-
`${this.prefix}entities_${etype}`
|
|
190
|
-
)} ("cdate");`
|
|
191
|
-
);
|
|
192
|
-
this.queryRun(
|
|
193
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
194
|
-
`${this.prefix}entities_${etype}_id_mdate`
|
|
195
|
-
)} ON ${SQLite3Driver.escape(
|
|
196
|
-
`${this.prefix}entities_${etype}`
|
|
197
|
-
)} ("mdate");`
|
|
198
|
-
);
|
|
199
|
-
this.queryRun(
|
|
200
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
201
|
-
`${this.prefix}entities_${etype}_id_tags`
|
|
202
|
-
)} ON ${SQLite3Driver.escape(
|
|
203
|
-
`${this.prefix}entities_${etype}`
|
|
204
|
-
)} ("tags");`
|
|
205
|
-
);
|
|
206
|
-
// Create the data table.
|
|
207
|
-
this.queryRun(
|
|
208
|
-
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
209
|
-
`${this.prefix}data_${etype}`
|
|
210
|
-
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
211
|
-
`${this.prefix}entities_${etype}`
|
|
212
|
-
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "value" TEXT NOT NULL, PRIMARY KEY("guid", "name"));`
|
|
213
|
-
);
|
|
214
|
-
this.queryRun(
|
|
215
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
216
|
-
`${this.prefix}data_${etype}_id_guid`
|
|
217
|
-
)} ON ${SQLite3Driver.escape(
|
|
218
|
-
`${this.prefix}data_${etype}`
|
|
219
|
-
)} ("guid");`
|
|
220
|
-
);
|
|
221
|
-
this.queryRun(
|
|
222
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
223
|
-
`${this.prefix}data_${etype}_id_name`
|
|
224
|
-
)} ON ${SQLite3Driver.escape(
|
|
225
|
-
`${this.prefix}data_${etype}`
|
|
226
|
-
)} ("name");`
|
|
227
|
-
);
|
|
228
|
-
this.queryRun(
|
|
229
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
230
|
-
`${this.prefix}data_${etype}_id_value`
|
|
231
|
-
)} ON ${SQLite3Driver.escape(
|
|
232
|
-
`${this.prefix}data_${etype}`
|
|
233
|
-
)} ("value");`
|
|
234
|
-
);
|
|
235
|
-
this.queryRun(
|
|
236
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
237
|
-
`${this.prefix}data_${etype}_id_guid__name_user`
|
|
238
|
-
)} ON ${SQLite3Driver.escape(
|
|
239
|
-
`${this.prefix}data_${etype}`
|
|
240
|
-
)} ("guid") WHERE "name" = \'user\';`
|
|
241
|
-
);
|
|
242
|
-
this.queryRun(
|
|
243
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
244
|
-
`${this.prefix}data_${etype}_id_guid__name_group`
|
|
245
|
-
)} ON ${SQLite3Driver.escape(
|
|
246
|
-
`${this.prefix}data_${etype}`
|
|
247
|
-
)} ("guid") WHERE "name" = \'group\';`
|
|
248
|
-
);
|
|
249
|
-
// Create the comparisons table.
|
|
250
|
-
this.queryRun(
|
|
251
|
-
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
252
|
-
`${this.prefix}comparisons_${etype}`
|
|
253
|
-
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
254
|
-
`${this.prefix}entities_${etype}`
|
|
255
|
-
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "truthy" INTEGER, "string" TEXT, "number" REAL, PRIMARY KEY("guid", "name"));`
|
|
256
|
-
);
|
|
257
|
-
this.queryRun(
|
|
258
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
259
|
-
`${this.prefix}comparisons_${etype}_id_guid`
|
|
260
|
-
)} ON ${SQLite3Driver.escape(
|
|
261
|
-
`${this.prefix}comparisons_${etype}`
|
|
262
|
-
)} ("guid");`
|
|
263
|
-
);
|
|
264
|
-
this.queryRun(
|
|
265
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
266
|
-
`${this.prefix}comparisons_${etype}_id_name`
|
|
267
|
-
)} ON ${SQLite3Driver.escape(
|
|
268
|
-
`${this.prefix}comparisons_${etype}`
|
|
269
|
-
)} ("name");`
|
|
270
|
-
);
|
|
271
|
-
this.queryRun(
|
|
272
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
273
|
-
`${this.prefix}comparisons_${etype}_id_name__truthy`
|
|
274
|
-
)} ON ${SQLite3Driver.escape(
|
|
275
|
-
`${this.prefix}comparisons_${etype}`
|
|
276
|
-
)} ("name") WHERE "truthy" = 1;`
|
|
277
|
-
);
|
|
278
|
-
// Create the references table.
|
|
279
|
-
this.queryRun(
|
|
280
|
-
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
281
|
-
`${this.prefix}references_${etype}`
|
|
282
|
-
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
283
|
-
`${this.prefix}entities_${etype}`
|
|
284
|
-
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "reference" CHARACTER(24) NOT NULL, PRIMARY KEY("guid", "name", "reference"));`
|
|
285
|
-
);
|
|
286
|
-
this.queryRun(
|
|
287
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
288
|
-
`${this.prefix}references_${etype}_id_guid`
|
|
289
|
-
)} ON ${SQLite3Driver.escape(
|
|
290
|
-
`${this.prefix}references_${etype}`
|
|
291
|
-
)} ("guid");`
|
|
292
|
-
);
|
|
293
|
-
this.queryRun(
|
|
294
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
295
|
-
`${this.prefix}references_${etype}_id_name`
|
|
296
|
-
)} ON ${SQLite3Driver.escape(
|
|
297
|
-
`${this.prefix}references_${etype}`
|
|
298
|
-
)} ("name");`
|
|
299
|
-
);
|
|
300
|
-
this.queryRun(
|
|
301
|
-
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
302
|
-
`${this.prefix}references_${etype}_id_reference`
|
|
303
|
-
)} ON ${SQLite3Driver.escape(
|
|
304
|
-
`${this.prefix}references_${etype}`
|
|
305
|
-
)} ("reference");`
|
|
306
|
-
);
|
|
476
|
+
this.createEntitiesTable(etype);
|
|
477
|
+
this.createDataTable(etype);
|
|
478
|
+
this.createReferencesTable(etype);
|
|
479
|
+
this.createTokensTable(etype);
|
|
480
|
+
this.createUniquesTable(etype);
|
|
307
481
|
} else {
|
|
308
482
|
// Create the UID table.
|
|
309
483
|
this.queryRun(
|
|
310
484
|
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
311
|
-
`${this.prefix}uids
|
|
312
|
-
)} ("name" TEXT PRIMARY KEY NOT NULL, "cur_uid" INTEGER NOT NULL)
|
|
485
|
+
`${this.prefix}uids`,
|
|
486
|
+
)} ("name" TEXT PRIMARY KEY NOT NULL, "cur_uid" INTEGER NOT NULL);`,
|
|
313
487
|
);
|
|
314
488
|
}
|
|
315
|
-
this.commit('nymph-tablecreation');
|
|
316
|
-
return true;
|
|
317
489
|
} catch (e: any) {
|
|
318
490
|
this.rollback('nymph-tablecreation');
|
|
319
491
|
throw e;
|
|
320
492
|
}
|
|
493
|
+
|
|
494
|
+
this.commit('nymph-tablecreation');
|
|
495
|
+
return true;
|
|
321
496
|
}
|
|
322
497
|
|
|
323
498
|
private query<T extends () => any>(
|
|
324
499
|
runQuery: T,
|
|
325
500
|
query: string,
|
|
326
|
-
etypes: string[] = []
|
|
501
|
+
etypes: string[] = [],
|
|
327
502
|
): ReturnType<T> {
|
|
328
503
|
try {
|
|
504
|
+
this.nymph.config.debugInfo('sqlite3:query', query);
|
|
329
505
|
return runQuery();
|
|
330
506
|
} catch (e: any) {
|
|
331
507
|
const errorCode = e?.code;
|
|
@@ -343,29 +519,37 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
343
519
|
} catch (e2: any) {
|
|
344
520
|
throw new QueryFailedError(
|
|
345
521
|
'Query failed: ' + e2?.code + ' - ' + e2?.message,
|
|
346
|
-
query
|
|
522
|
+
query,
|
|
347
523
|
);
|
|
348
524
|
}
|
|
525
|
+
} else if (
|
|
526
|
+
errorCode === 'SQLITE_CONSTRAINT_UNIQUE' &&
|
|
527
|
+
errorMsg.match(/^UNIQUE constraint failed: /)
|
|
528
|
+
) {
|
|
529
|
+
throw new EntityUniqueConstraintError(`Unique constraint violation.`);
|
|
349
530
|
} else {
|
|
350
531
|
throw new QueryFailedError(
|
|
351
532
|
'Query failed: ' + e?.code + ' - ' + e?.message,
|
|
352
|
-
query
|
|
533
|
+
query,
|
|
353
534
|
);
|
|
354
535
|
}
|
|
355
536
|
}
|
|
356
537
|
}
|
|
357
538
|
|
|
358
|
-
private
|
|
539
|
+
private queryArray(
|
|
359
540
|
query: string,
|
|
360
541
|
{
|
|
361
542
|
etypes = [],
|
|
362
543
|
params = {},
|
|
363
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
544
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
364
545
|
) {
|
|
365
546
|
return this.query(
|
|
366
|
-
() =>
|
|
547
|
+
() =>
|
|
548
|
+
(this.store.linkWrite || this.store.link)
|
|
549
|
+
.prepare(query)
|
|
550
|
+
.iterate(params),
|
|
367
551
|
`${query} -- ${JSON.stringify(params)}`,
|
|
368
|
-
etypes
|
|
552
|
+
etypes,
|
|
369
553
|
);
|
|
370
554
|
}
|
|
371
555
|
|
|
@@ -374,12 +558,13 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
374
558
|
{
|
|
375
559
|
etypes = [],
|
|
376
560
|
params = {},
|
|
377
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
561
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
378
562
|
) {
|
|
379
563
|
return this.query(
|
|
380
|
-
() =>
|
|
564
|
+
() =>
|
|
565
|
+
(this.store.linkWrite || this.store.link).prepare(query).get(params),
|
|
381
566
|
`${query} -- ${JSON.stringify(params)}`,
|
|
382
|
-
etypes
|
|
567
|
+
etypes,
|
|
383
568
|
);
|
|
384
569
|
}
|
|
385
570
|
|
|
@@ -388,19 +573,20 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
388
573
|
{
|
|
389
574
|
etypes = [],
|
|
390
575
|
params = {},
|
|
391
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
576
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
392
577
|
) {
|
|
393
578
|
return this.query(
|
|
394
|
-
() =>
|
|
579
|
+
() =>
|
|
580
|
+
(this.store.linkWrite || this.store.link).prepare(query).run(params),
|
|
395
581
|
`${query} -- ${JSON.stringify(params)}`,
|
|
396
|
-
etypes
|
|
582
|
+
etypes,
|
|
397
583
|
);
|
|
398
584
|
}
|
|
399
585
|
|
|
400
586
|
public async commit(name: string) {
|
|
401
587
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
402
588
|
throw new InvalidParametersError(
|
|
403
|
-
'Transaction commit attempted without a name.'
|
|
589
|
+
'Transaction commit attempted without a name.',
|
|
404
590
|
);
|
|
405
591
|
}
|
|
406
592
|
if (this.store.transactionsStarted === 0) {
|
|
@@ -408,12 +594,23 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
408
594
|
}
|
|
409
595
|
this.queryRun(`RELEASE SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
410
596
|
this.store.transactionsStarted--;
|
|
597
|
+
|
|
598
|
+
if (
|
|
599
|
+
this.store.transactionsStarted === 0 &&
|
|
600
|
+
this.store.linkWrite &&
|
|
601
|
+
!this.config.explicitWrite
|
|
602
|
+
) {
|
|
603
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
604
|
+
this.store.linkWrite.close();
|
|
605
|
+
this.store.linkWrite = undefined;
|
|
606
|
+
}
|
|
607
|
+
|
|
411
608
|
return true;
|
|
412
609
|
}
|
|
413
610
|
|
|
414
611
|
public async deleteEntityByID(
|
|
415
612
|
guid: string,
|
|
416
|
-
className?: EntityConstructor | string | null
|
|
613
|
+
className?: EntityConstructor | string | null,
|
|
417
614
|
) {
|
|
418
615
|
let EntityClass: EntityConstructor;
|
|
419
616
|
if (typeof className === 'string' || className == null) {
|
|
@@ -423,133 +620,185 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
423
620
|
EntityClass = className;
|
|
424
621
|
}
|
|
425
622
|
const etype = EntityClass.ETYPE;
|
|
426
|
-
this.checkReadOnlyMode();
|
|
427
623
|
await this.startTransaction('nymph-delete');
|
|
428
624
|
try {
|
|
429
625
|
this.queryRun(
|
|
430
626
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
431
|
-
`${this.prefix}entities_${etype}
|
|
627
|
+
`${this.prefix}entities_${etype}`,
|
|
432
628
|
)} WHERE "guid"=@guid;`,
|
|
433
629
|
{
|
|
434
630
|
etypes: [etype],
|
|
435
631
|
params: {
|
|
436
632
|
guid,
|
|
437
633
|
},
|
|
438
|
-
}
|
|
634
|
+
},
|
|
439
635
|
);
|
|
440
636
|
this.queryRun(
|
|
441
637
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
442
|
-
`${this.prefix}data_${etype}
|
|
638
|
+
`${this.prefix}data_${etype}`,
|
|
443
639
|
)} WHERE "guid"=@guid;`,
|
|
444
640
|
{
|
|
445
641
|
etypes: [etype],
|
|
446
642
|
params: {
|
|
447
643
|
guid,
|
|
448
644
|
},
|
|
449
|
-
}
|
|
645
|
+
},
|
|
450
646
|
);
|
|
451
647
|
this.queryRun(
|
|
452
648
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
453
|
-
`${this.prefix}
|
|
649
|
+
`${this.prefix}references_${etype}`,
|
|
454
650
|
)} WHERE "guid"=@guid;`,
|
|
455
651
|
{
|
|
456
652
|
etypes: [etype],
|
|
457
653
|
params: {
|
|
458
654
|
guid,
|
|
459
655
|
},
|
|
460
|
-
}
|
|
656
|
+
},
|
|
461
657
|
);
|
|
462
658
|
this.queryRun(
|
|
463
659
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
464
|
-
`${this.prefix}
|
|
660
|
+
`${this.prefix}tokens_${etype}`,
|
|
465
661
|
)} WHERE "guid"=@guid;`,
|
|
466
662
|
{
|
|
467
663
|
etypes: [etype],
|
|
468
664
|
params: {
|
|
469
665
|
guid,
|
|
470
666
|
},
|
|
471
|
-
}
|
|
667
|
+
},
|
|
668
|
+
);
|
|
669
|
+
this.queryRun(
|
|
670
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
671
|
+
`${this.prefix}uniques_${etype}`,
|
|
672
|
+
)} WHERE "guid"=@guid;`,
|
|
673
|
+
{
|
|
674
|
+
etypes: [etype],
|
|
675
|
+
params: {
|
|
676
|
+
guid,
|
|
677
|
+
},
|
|
678
|
+
},
|
|
472
679
|
);
|
|
473
|
-
await this.commit('nymph-delete');
|
|
474
|
-
// Remove any cached versions of this entity.
|
|
475
|
-
if (this.nymph.config.cache) {
|
|
476
|
-
this.cleanCache(guid);
|
|
477
|
-
}
|
|
478
|
-
return true;
|
|
479
680
|
} catch (e: any) {
|
|
681
|
+
this.nymph.config.debugError('sqlite3', `Delete entity error: "${e}"`);
|
|
480
682
|
await this.rollback('nymph-delete');
|
|
481
683
|
throw e;
|
|
482
684
|
}
|
|
685
|
+
|
|
686
|
+
await this.commit('nymph-delete');
|
|
687
|
+
// Remove any cached versions of this entity.
|
|
688
|
+
if (this.nymph.config.cache) {
|
|
689
|
+
this.cleanCache(guid);
|
|
690
|
+
}
|
|
691
|
+
return true;
|
|
483
692
|
}
|
|
484
693
|
|
|
485
694
|
public async deleteUID(name: string) {
|
|
486
695
|
if (!name) {
|
|
487
696
|
throw new InvalidParametersError('Name not given for UID');
|
|
488
697
|
}
|
|
489
|
-
this.
|
|
698
|
+
await this.startTransaction('nymph-delete-uid');
|
|
490
699
|
this.queryRun(
|
|
491
700
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
492
|
-
`${this.prefix}uids
|
|
701
|
+
`${this.prefix}uids`,
|
|
493
702
|
)} WHERE "name"=@name;`,
|
|
494
703
|
{
|
|
495
704
|
params: {
|
|
496
705
|
name,
|
|
497
706
|
},
|
|
498
|
-
}
|
|
707
|
+
},
|
|
499
708
|
);
|
|
709
|
+
await this.commit('nymph-delete-uid');
|
|
500
710
|
return true;
|
|
501
711
|
}
|
|
502
712
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
713
|
+
public async getEtypes() {
|
|
714
|
+
const tables: IterableIterator<any> = this.queryArray(
|
|
715
|
+
"SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix;",
|
|
716
|
+
{
|
|
717
|
+
params: {
|
|
718
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
719
|
+
},
|
|
720
|
+
},
|
|
721
|
+
);
|
|
722
|
+
const etypes: string[] = [];
|
|
723
|
+
for (const table of tables) {
|
|
724
|
+
etypes.push(table.name.substr((this.prefix + 'entities_').length));
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return etypes;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
public async *exportDataIterator(): AsyncGenerator<
|
|
731
|
+
{ type: 'comment' | 'uid' | 'entity'; content: string },
|
|
732
|
+
void,
|
|
733
|
+
false | undefined
|
|
734
|
+
> {
|
|
735
|
+
if (
|
|
736
|
+
yield {
|
|
737
|
+
type: 'comment',
|
|
738
|
+
content: `#nex2
|
|
739
|
+
# Nymph Entity Exchange v2
|
|
740
|
+
# http://nymph.io
|
|
741
|
+
#
|
|
742
|
+
# Generation Time: ${new Date().toLocaleString()}
|
|
743
|
+
`,
|
|
744
|
+
}
|
|
745
|
+
) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
510
748
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
749
|
+
if (
|
|
750
|
+
yield {
|
|
751
|
+
type: 'comment',
|
|
752
|
+
content: `
|
|
753
|
+
|
|
754
|
+
#
|
|
755
|
+
# UIDs
|
|
756
|
+
#
|
|
757
|
+
|
|
758
|
+
`,
|
|
759
|
+
}
|
|
760
|
+
) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
515
763
|
|
|
516
764
|
// Export UIDs.
|
|
517
|
-
let uids = this.
|
|
765
|
+
let uids: IterableIterator<any> = this.queryArray(
|
|
518
766
|
`SELECT * FROM ${SQLite3Driver.escape(
|
|
519
|
-
`${this.prefix}uids
|
|
520
|
-
)} ORDER BY "name"
|
|
767
|
+
`${this.prefix}uids`,
|
|
768
|
+
)} ORDER BY "name";`,
|
|
521
769
|
);
|
|
522
770
|
for (const uid of uids) {
|
|
523
|
-
|
|
771
|
+
if (yield { type: 'uid', content: `<${uid.name}>[${uid.cur_uid}]\n` }) {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
524
774
|
}
|
|
525
775
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
writeLine('');
|
|
776
|
+
if (
|
|
777
|
+
yield {
|
|
778
|
+
type: 'comment',
|
|
779
|
+
content: `
|
|
531
780
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
for (const table of tables) {
|
|
538
|
-
if (table.name.startsWith(this.prefix + 'entities_')) {
|
|
539
|
-
etypes.push(table.name.substr((this.prefix + 'entities_').length));
|
|
781
|
+
#
|
|
782
|
+
# Entities
|
|
783
|
+
#
|
|
784
|
+
|
|
785
|
+
`,
|
|
540
786
|
}
|
|
787
|
+
) {
|
|
788
|
+
return;
|
|
541
789
|
}
|
|
542
790
|
|
|
791
|
+
// Get the etypes.
|
|
792
|
+
const etypes = await this.getEtypes();
|
|
793
|
+
|
|
543
794
|
for (const etype of etypes) {
|
|
544
795
|
// Export entities.
|
|
545
|
-
const dataIterator = this.
|
|
546
|
-
`SELECT e.*, d."name"
|
|
547
|
-
`${this.prefix}entities_${etype}
|
|
796
|
+
const dataIterator: IterableIterator<any> = this.queryArray(
|
|
797
|
+
`SELECT e.*, d."name", d."value", json(d."json") as "json", d."string", d."number" FROM ${SQLite3Driver.escape(
|
|
798
|
+
`${this.prefix}entities_${etype}`,
|
|
548
799
|
)} e LEFT JOIN ${SQLite3Driver.escape(
|
|
549
|
-
`${this.prefix}data_${etype}
|
|
550
|
-
)} d USING ("guid")
|
|
551
|
-
`${this.prefix}comparisons_${etype}`
|
|
552
|
-
)} c USING ("guid", "name") ORDER BY e."guid";`
|
|
800
|
+
`${this.prefix}data_${etype}`,
|
|
801
|
+
)} d USING ("guid") ORDER BY e."guid";`,
|
|
553
802
|
)[Symbol.iterator]();
|
|
554
803
|
let datum = dataIterator.next();
|
|
555
804
|
while (!datum.done) {
|
|
@@ -557,30 +806,36 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
557
806
|
const tags = datum.value.tags.slice(1, -1);
|
|
558
807
|
const cdate = datum.value.cdate;
|
|
559
808
|
const mdate = datum.value.mdate;
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
809
|
+
let currentEntityExport: string[] = [];
|
|
810
|
+
currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
|
|
811
|
+
currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
|
|
812
|
+
currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
|
|
813
|
+
if (datum.value.name != null) {
|
|
564
814
|
// This do will keep going and adding the data until the
|
|
565
815
|
// next entity is reached. datum will end on the next entity.
|
|
566
816
|
do {
|
|
567
817
|
const value =
|
|
568
|
-
datum.value.
|
|
818
|
+
datum.value.value === 'N'
|
|
569
819
|
? JSON.stringify(datum.value.number)
|
|
570
|
-
: datum.value.
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
820
|
+
: datum.value.value === 'S'
|
|
821
|
+
? JSON.stringify(datum.value.string)
|
|
822
|
+
: datum.value.value === 'J'
|
|
823
|
+
? datum.value.json
|
|
824
|
+
: datum.value.value;
|
|
825
|
+
currentEntityExport.push(`\t${datum.value.name}=${value}`);
|
|
574
826
|
datum = dataIterator.next();
|
|
575
827
|
} while (!datum.done && datum.value.guid === guid);
|
|
576
828
|
} else {
|
|
577
829
|
// Make sure that datum is incremented :)
|
|
578
830
|
datum = dataIterator.next();
|
|
579
831
|
}
|
|
832
|
+
currentEntityExport.push('');
|
|
833
|
+
|
|
834
|
+
if (yield { type: 'entity', content: currentEntityExport.join('\n') }) {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
580
837
|
}
|
|
581
838
|
}
|
|
582
|
-
|
|
583
|
-
return;
|
|
584
839
|
}
|
|
585
840
|
|
|
586
841
|
/**
|
|
@@ -601,20 +856,21 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
601
856
|
params: { [k: string]: any } = {},
|
|
602
857
|
subquery = false,
|
|
603
858
|
tableSuffix = '',
|
|
604
|
-
etypes: string[] = []
|
|
859
|
+
etypes: string[] = [],
|
|
860
|
+
guidSelector: string | undefined = undefined,
|
|
605
861
|
) {
|
|
606
862
|
if (typeof options.class?.alterOptions === 'function') {
|
|
607
863
|
options = options.class.alterOptions(options);
|
|
608
864
|
}
|
|
609
865
|
const eTable = `e${tableSuffix}`;
|
|
610
866
|
const dTable = `d${tableSuffix}`;
|
|
611
|
-
const cTable = `c${tableSuffix}`;
|
|
612
867
|
const fTable = `f${tableSuffix}`;
|
|
613
868
|
const ieTable = `ie${tableSuffix}`;
|
|
869
|
+
const sTable = `s${tableSuffix}`;
|
|
614
870
|
const sort = options.sort ?? 'cdate';
|
|
615
871
|
const queryParts = this.iterateSelectorsForQuery(
|
|
616
872
|
formattedSelectors,
|
|
617
|
-
(key, value, typeIsOr, typeIsNot) => {
|
|
873
|
+
({ key, value, typeIsOr, typeIsNot }) => {
|
|
618
874
|
const clauseNot = key.startsWith('!');
|
|
619
875
|
let curQuery = '';
|
|
620
876
|
for (const curValue of value) {
|
|
@@ -699,10 +955,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
699
955
|
const name = `param${++count.i}`;
|
|
700
956
|
curQuery +=
|
|
701
957
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
958
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
959
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
960
|
+
' WHERE "guid"=' +
|
|
702
961
|
ieTable +
|
|
703
|
-
'."guid"
|
|
704
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
705
|
-
' WHERE "name"=@' +
|
|
962
|
+
'."guid" AND "name"=@' +
|
|
706
963
|
name +
|
|
707
964
|
' AND "truthy"=1)';
|
|
708
965
|
params[name] = curVar;
|
|
@@ -743,10 +1000,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
743
1000
|
const value = `param${++count.i}`;
|
|
744
1001
|
curQuery +=
|
|
745
1002
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1003
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1004
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1005
|
+
' WHERE "guid"=' +
|
|
746
1006
|
ieTable +
|
|
747
|
-
'."guid"
|
|
748
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
749
|
-
' WHERE "name"=@' +
|
|
1007
|
+
'."guid" AND "name"=@' +
|
|
750
1008
|
name +
|
|
751
1009
|
' AND "number"=@' +
|
|
752
1010
|
value +
|
|
@@ -761,10 +1019,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
761
1019
|
const value = `param${++count.i}`;
|
|
762
1020
|
curQuery +=
|
|
763
1021
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1022
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1023
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1024
|
+
' WHERE "guid"=' +
|
|
764
1025
|
ieTable +
|
|
765
|
-
'."guid"
|
|
766
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
767
|
-
' WHERE "name"=@' +
|
|
1026
|
+
'."guid" AND "name"=@' +
|
|
768
1027
|
name +
|
|
769
1028
|
' AND "string"=@' +
|
|
770
1029
|
value +
|
|
@@ -788,14 +1047,15 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
788
1047
|
const value = `param${++count.i}`;
|
|
789
1048
|
curQuery +=
|
|
790
1049
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
791
|
-
|
|
792
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1050
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
793
1051
|
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
794
|
-
' WHERE "
|
|
1052
|
+
' WHERE "guid"=' +
|
|
1053
|
+
ieTable +
|
|
1054
|
+
'."guid" AND "name"=@' +
|
|
795
1055
|
name +
|
|
796
|
-
' AND "
|
|
1056
|
+
' AND "json"=jsonb(@' +
|
|
797
1057
|
value +
|
|
798
|
-
')';
|
|
1058
|
+
'))';
|
|
799
1059
|
params[name] = curValue[0];
|
|
800
1060
|
params[value] = svalue;
|
|
801
1061
|
}
|
|
@@ -810,7 +1070,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
810
1070
|
curQuery +=
|
|
811
1071
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
812
1072
|
ieTable +
|
|
813
|
-
'."cdate"
|
|
1073
|
+
'."cdate"=@' +
|
|
814
1074
|
cdate;
|
|
815
1075
|
params[cdate] = Number(curValue[1]);
|
|
816
1076
|
break;
|
|
@@ -822,90 +1082,210 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
822
1082
|
curQuery +=
|
|
823
1083
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
824
1084
|
ieTable +
|
|
825
|
-
'."mdate"
|
|
1085
|
+
'."mdate"=@' +
|
|
826
1086
|
mdate;
|
|
827
1087
|
params[mdate] = Number(curValue[1]);
|
|
828
1088
|
break;
|
|
829
1089
|
} else {
|
|
1090
|
+
const containTableSuffix = makeTableSuffix();
|
|
830
1091
|
if (curQuery) {
|
|
831
1092
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
832
1093
|
}
|
|
833
1094
|
let svalue: string;
|
|
834
|
-
let stringValue: string;
|
|
835
1095
|
if (
|
|
836
1096
|
curValue[1] instanceof Object &&
|
|
837
1097
|
typeof curValue[1].toReference === 'function'
|
|
838
1098
|
) {
|
|
839
1099
|
svalue = JSON.stringify(curValue[1].toReference());
|
|
840
|
-
stringValue = `${curValue[1].toReference()}`;
|
|
841
1100
|
} else {
|
|
842
1101
|
svalue = JSON.stringify(curValue[1]);
|
|
843
|
-
stringValue = `${curValue[1]}`;
|
|
844
1102
|
}
|
|
845
1103
|
const name = `param${++count.i}`;
|
|
846
1104
|
const value = `param${++count.i}`;
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
863
|
-
' WHERE "name"=@' +
|
|
864
|
-
name +
|
|
865
|
-
' AND "string"=@' +
|
|
866
|
-
stringParam +
|
|
867
|
-
'))';
|
|
868
|
-
params[stringParam] = stringValue;
|
|
869
|
-
} else {
|
|
870
|
-
curQuery +=
|
|
871
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
872
|
-
ieTable +
|
|
873
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
874
|
-
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
875
|
-
' WHERE "name"=@' +
|
|
876
|
-
name +
|
|
877
|
-
' AND instr("value", @' +
|
|
878
|
-
value +
|
|
879
|
-
'))';
|
|
880
|
-
}
|
|
1105
|
+
curQuery +=
|
|
1106
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1107
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1108
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1109
|
+
' d' +
|
|
1110
|
+
containTableSuffix +
|
|
1111
|
+
' WHERE "guid"=' +
|
|
1112
|
+
ieTable +
|
|
1113
|
+
'."guid" AND "name"=@' +
|
|
1114
|
+
name +
|
|
1115
|
+
' AND json(@' +
|
|
1116
|
+
value +
|
|
1117
|
+
') IN (SELECT json_quote("value") FROM json_each(d' +
|
|
1118
|
+
containTableSuffix +
|
|
1119
|
+
'."json")))';
|
|
881
1120
|
params[name] = curValue[0];
|
|
882
1121
|
params[value] = svalue;
|
|
883
1122
|
}
|
|
884
1123
|
break;
|
|
885
|
-
case '
|
|
886
|
-
case '!
|
|
887
|
-
if (curValue[0] === 'cdate') {
|
|
1124
|
+
case 'search':
|
|
1125
|
+
case '!search':
|
|
1126
|
+
if (curValue[0] === 'cdate' || curValue[0] === 'mdate') {
|
|
888
1127
|
if (curQuery) {
|
|
889
1128
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
890
1129
|
}
|
|
891
|
-
|
|
892
|
-
curQuery +=
|
|
893
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
894
|
-
'(' +
|
|
895
|
-
ieTable +
|
|
896
|
-
'."cdate" REGEXP @' +
|
|
897
|
-
cdate +
|
|
898
|
-
')';
|
|
899
|
-
params[cdate] = curValue[1];
|
|
1130
|
+
curQuery += (xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(0)';
|
|
900
1131
|
break;
|
|
901
|
-
} else
|
|
1132
|
+
} else {
|
|
902
1133
|
if (curQuery) {
|
|
903
1134
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
904
1135
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1136
|
+
|
|
1137
|
+
const name = `param${++count.i}`;
|
|
1138
|
+
|
|
1139
|
+
const queryPartToken = (term: SearchTerm) => {
|
|
1140
|
+
const value = `param${++count.i}`;
|
|
1141
|
+
params[value] = term.token;
|
|
1142
|
+
return (
|
|
1143
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1144
|
+
SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
|
|
1145
|
+
' WHERE "guid"=' +
|
|
1146
|
+
ieTable +
|
|
1147
|
+
'."guid" AND "name"=@' +
|
|
1148
|
+
name +
|
|
1149
|
+
' AND "token"=@' +
|
|
1150
|
+
value +
|
|
1151
|
+
(term.nostemmed ? ' AND "stem"=0' : '') +
|
|
1152
|
+
')'
|
|
1153
|
+
);
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
const queryPartSeries = (series: SearchSeriesTerm) => {
|
|
1157
|
+
const tokenTableSuffix = makeTableSuffix();
|
|
1158
|
+
const tokenParts = series.tokens.map((token, i) => {
|
|
1159
|
+
const value = `param${++count.i}`;
|
|
1160
|
+
params[value] = token.token;
|
|
1161
|
+
return {
|
|
1162
|
+
fromClause:
|
|
1163
|
+
i === 0
|
|
1164
|
+
? 'FROM ' +
|
|
1165
|
+
SQLite3Driver.escape(
|
|
1166
|
+
this.prefix + 'tokens_' + etype,
|
|
1167
|
+
) +
|
|
1168
|
+
' t' +
|
|
1169
|
+
tokenTableSuffix +
|
|
1170
|
+
'0'
|
|
1171
|
+
: 'JOIN ' +
|
|
1172
|
+
SQLite3Driver.escape(
|
|
1173
|
+
this.prefix + 'tokens_' + etype,
|
|
1174
|
+
) +
|
|
1175
|
+
' t' +
|
|
1176
|
+
tokenTableSuffix +
|
|
1177
|
+
i +
|
|
1178
|
+
' ON t' +
|
|
1179
|
+
tokenTableSuffix +
|
|
1180
|
+
i +
|
|
1181
|
+
'."guid" = t' +
|
|
1182
|
+
tokenTableSuffix +
|
|
1183
|
+
'0."guid" AND t' +
|
|
1184
|
+
tokenTableSuffix +
|
|
1185
|
+
i +
|
|
1186
|
+
'."name" = t' +
|
|
1187
|
+
tokenTableSuffix +
|
|
1188
|
+
'0."name" AND t' +
|
|
1189
|
+
tokenTableSuffix +
|
|
1190
|
+
i +
|
|
1191
|
+
'."position" = t' +
|
|
1192
|
+
tokenTableSuffix +
|
|
1193
|
+
'0."position" + ' +
|
|
1194
|
+
i,
|
|
1195
|
+
whereClause:
|
|
1196
|
+
't' +
|
|
1197
|
+
tokenTableSuffix +
|
|
1198
|
+
i +
|
|
1199
|
+
'."token"=@' +
|
|
1200
|
+
value +
|
|
1201
|
+
(token.nostemmed
|
|
1202
|
+
? ' AND t' + tokenTableSuffix + i + '."stem"=0'
|
|
1203
|
+
: ''),
|
|
1204
|
+
};
|
|
1205
|
+
});
|
|
1206
|
+
return (
|
|
1207
|
+
'EXISTS (SELECT t' +
|
|
1208
|
+
tokenTableSuffix +
|
|
1209
|
+
'0."guid" ' +
|
|
1210
|
+
tokenParts.map((part) => part.fromClause).join(' ') +
|
|
1211
|
+
' WHERE t' +
|
|
1212
|
+
tokenTableSuffix +
|
|
1213
|
+
'0."guid"=' +
|
|
1214
|
+
ieTable +
|
|
1215
|
+
'."guid" AND t' +
|
|
1216
|
+
tokenTableSuffix +
|
|
1217
|
+
'0."name"=@' +
|
|
1218
|
+
name +
|
|
1219
|
+
' AND ' +
|
|
1220
|
+
tokenParts.map((part) => part.whereClause).join(' AND ') +
|
|
1221
|
+
')'
|
|
1222
|
+
);
|
|
1223
|
+
};
|
|
1224
|
+
|
|
1225
|
+
const queryPartTerm = (
|
|
1226
|
+
term:
|
|
1227
|
+
| SearchTerm
|
|
1228
|
+
| SearchOrTerm
|
|
1229
|
+
| SearchNotTerm
|
|
1230
|
+
| SearchSeriesTerm,
|
|
1231
|
+
): string => {
|
|
1232
|
+
if (term.type === 'series') {
|
|
1233
|
+
return queryPartSeries(term);
|
|
1234
|
+
} else if (term.type === 'not') {
|
|
1235
|
+
return 'NOT ' + queryPartTerm(term.operand);
|
|
1236
|
+
} else if (term.type === 'or') {
|
|
1237
|
+
let queryParts: string[] = [];
|
|
1238
|
+
for (let operand of term.operands) {
|
|
1239
|
+
queryParts.push(queryPartTerm(operand));
|
|
1240
|
+
}
|
|
1241
|
+
return '(' + queryParts.join(' OR ') + ')';
|
|
1242
|
+
}
|
|
1243
|
+
return queryPartToken(term);
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
const parsedFTSQuery = this.tokenizer.parseSearchQuery(
|
|
1247
|
+
curValue[1],
|
|
1248
|
+
);
|
|
1249
|
+
|
|
1250
|
+
// Run through the query and add terms.
|
|
1251
|
+
let termStrings: string[] = [];
|
|
1252
|
+
for (let term of parsedFTSQuery) {
|
|
1253
|
+
termStrings.push(queryPartTerm(term));
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
curQuery +=
|
|
1257
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1258
|
+
'(' +
|
|
1259
|
+
termStrings.join(' AND ') +
|
|
1260
|
+
')';
|
|
1261
|
+
|
|
1262
|
+
params[name] = curValue[0];
|
|
1263
|
+
}
|
|
1264
|
+
break;
|
|
1265
|
+
case 'match':
|
|
1266
|
+
case '!match':
|
|
1267
|
+
if (curValue[0] === 'cdate') {
|
|
1268
|
+
if (curQuery) {
|
|
1269
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1270
|
+
}
|
|
1271
|
+
const cdate = `param${++count.i}`;
|
|
1272
|
+
curQuery +=
|
|
1273
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1274
|
+
'(' +
|
|
1275
|
+
ieTable +
|
|
1276
|
+
'."cdate" REGEXP @' +
|
|
1277
|
+
cdate +
|
|
1278
|
+
')';
|
|
1279
|
+
params[cdate] = curValue[1];
|
|
1280
|
+
break;
|
|
1281
|
+
} else if (curValue[0] === 'mdate') {
|
|
1282
|
+
if (curQuery) {
|
|
1283
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1284
|
+
}
|
|
1285
|
+
const mdate = `param${++count.i}`;
|
|
1286
|
+
curQuery +=
|
|
1287
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1288
|
+
'(' +
|
|
909
1289
|
ieTable +
|
|
910
1290
|
'."mdate" REGEXP @' +
|
|
911
1291
|
mdate +
|
|
@@ -920,10 +1300,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
920
1300
|
const value = `param${++count.i}`;
|
|
921
1301
|
curQuery +=
|
|
922
1302
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1303
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1304
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1305
|
+
' WHERE "guid"=' +
|
|
923
1306
|
ieTable +
|
|
924
|
-
'."guid"
|
|
925
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
926
|
-
' WHERE "name"=@' +
|
|
1307
|
+
'."guid" AND "name"=@' +
|
|
927
1308
|
name +
|
|
928
1309
|
' AND "string" REGEXP @' +
|
|
929
1310
|
value +
|
|
@@ -970,10 +1351,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
970
1351
|
const value = `param${++count.i}`;
|
|
971
1352
|
curQuery +=
|
|
972
1353
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1354
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1355
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1356
|
+
' WHERE "guid"=' +
|
|
973
1357
|
ieTable +
|
|
974
|
-
'."guid"
|
|
975
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
976
|
-
' WHERE "name"=@' +
|
|
1358
|
+
'."guid" AND "name"=@' +
|
|
977
1359
|
name +
|
|
978
1360
|
' AND lower("string") REGEXP lower(@' +
|
|
979
1361
|
value +
|
|
@@ -1020,10 +1402,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1020
1402
|
const value = `param${++count.i}`;
|
|
1021
1403
|
curQuery +=
|
|
1022
1404
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1405
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1406
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1407
|
+
' WHERE "guid"=' +
|
|
1023
1408
|
ieTable +
|
|
1024
|
-
'."guid"
|
|
1025
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1026
|
-
' WHERE "name"=@' +
|
|
1409
|
+
'."guid" AND "name"=@' +
|
|
1027
1410
|
name +
|
|
1028
1411
|
' AND "string" LIKE @' +
|
|
1029
1412
|
value +
|
|
@@ -1070,10 +1453,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1070
1453
|
const value = `param${++count.i}`;
|
|
1071
1454
|
curQuery +=
|
|
1072
1455
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1456
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1457
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1458
|
+
' WHERE "guid"=' +
|
|
1073
1459
|
ieTable +
|
|
1074
|
-
'."guid"
|
|
1075
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1076
|
-
' WHERE "name"=@' +
|
|
1460
|
+
'."guid" AND "name"=@' +
|
|
1077
1461
|
name +
|
|
1078
1462
|
' AND lower("string") LIKE lower(@' +
|
|
1079
1463
|
value +
|
|
@@ -1116,10 +1500,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1116
1500
|
const value = `param${++count.i}`;
|
|
1117
1501
|
curQuery +=
|
|
1118
1502
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1503
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1504
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1505
|
+
' WHERE "guid"=' +
|
|
1119
1506
|
ieTable +
|
|
1120
|
-
'."guid"
|
|
1121
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1122
|
-
' WHERE "name"=@' +
|
|
1507
|
+
'."guid" AND "name"=@' +
|
|
1123
1508
|
name +
|
|
1124
1509
|
' AND "number">@' +
|
|
1125
1510
|
value +
|
|
@@ -1162,10 +1547,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1162
1547
|
const value = `param${++count.i}`;
|
|
1163
1548
|
curQuery +=
|
|
1164
1549
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1550
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1551
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1552
|
+
' WHERE "guid"=' +
|
|
1165
1553
|
ieTable +
|
|
1166
|
-
'."guid"
|
|
1167
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1168
|
-
' WHERE "name"=@' +
|
|
1554
|
+
'."guid" AND "name"=@' +
|
|
1169
1555
|
name +
|
|
1170
1556
|
' AND "number">=@' +
|
|
1171
1557
|
value +
|
|
@@ -1208,10 +1594,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1208
1594
|
const value = `param${++count.i}`;
|
|
1209
1595
|
curQuery +=
|
|
1210
1596
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1597
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1598
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1599
|
+
' WHERE "guid"=' +
|
|
1211
1600
|
ieTable +
|
|
1212
|
-
'."guid"
|
|
1213
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1214
|
-
' WHERE "name"=@' +
|
|
1601
|
+
'."guid" AND "name"=@' +
|
|
1215
1602
|
name +
|
|
1216
1603
|
' AND "number"<@' +
|
|
1217
1604
|
value +
|
|
@@ -1254,10 +1641,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1254
1641
|
const value = `param${++count.i}`;
|
|
1255
1642
|
curQuery +=
|
|
1256
1643
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1644
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1645
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1646
|
+
' WHERE "guid"=' +
|
|
1257
1647
|
ieTable +
|
|
1258
|
-
'."guid"
|
|
1259
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1260
|
-
' WHERE "name"=@' +
|
|
1648
|
+
'."guid" AND "name"=@' +
|
|
1261
1649
|
name +
|
|
1262
1650
|
' AND "number"<=@' +
|
|
1263
1651
|
value +
|
|
@@ -1283,10 +1671,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1283
1671
|
const guid = `param${++count.i}`;
|
|
1284
1672
|
curQuery +=
|
|
1285
1673
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1286
|
-
|
|
1287
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1674
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1288
1675
|
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
1289
|
-
' WHERE "
|
|
1676
|
+
' WHERE "guid"=' +
|
|
1677
|
+
ieTable +
|
|
1678
|
+
'."guid" AND "name"=@' +
|
|
1290
1679
|
name +
|
|
1291
1680
|
' AND "reference"=@' +
|
|
1292
1681
|
guid +
|
|
@@ -1304,7 +1693,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1304
1693
|
params,
|
|
1305
1694
|
true,
|
|
1306
1695
|
tableSuffix,
|
|
1307
|
-
etypes
|
|
1696
|
+
etypes,
|
|
1308
1697
|
);
|
|
1309
1698
|
if (curQuery) {
|
|
1310
1699
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1317,9 +1706,10 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1317
1706
|
break;
|
|
1318
1707
|
case 'qref':
|
|
1319
1708
|
case '!qref':
|
|
1709
|
+
const referenceTableSuffix = makeTableSuffix();
|
|
1320
1710
|
const [qrefOptions, ...qrefSelectors] = curValue[1] as [
|
|
1321
1711
|
Options,
|
|
1322
|
-
...FormattedSelector[]
|
|
1712
|
+
...FormattedSelector[],
|
|
1323
1713
|
];
|
|
1324
1714
|
const QrefEntityClass = qrefOptions.class as EntityConstructor;
|
|
1325
1715
|
etypes.push(QrefEntityClass.ETYPE);
|
|
@@ -1331,7 +1721,8 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1331
1721
|
params,
|
|
1332
1722
|
false,
|
|
1333
1723
|
makeTableSuffix(),
|
|
1334
|
-
etypes
|
|
1724
|
+
etypes,
|
|
1725
|
+
'r' + referenceTableSuffix + '."reference"',
|
|
1335
1726
|
);
|
|
1336
1727
|
if (curQuery) {
|
|
1337
1728
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1339,12 +1730,19 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1339
1730
|
const qrefName = `param${++count.i}`;
|
|
1340
1731
|
curQuery +=
|
|
1341
1732
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1342
|
-
|
|
1343
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1733
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1344
1734
|
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
1345
|
-
'
|
|
1735
|
+
' r' +
|
|
1736
|
+
referenceTableSuffix +
|
|
1737
|
+
' WHERE r' +
|
|
1738
|
+
referenceTableSuffix +
|
|
1739
|
+
'."guid"=' +
|
|
1740
|
+
ieTable +
|
|
1741
|
+
'."guid" AND r' +
|
|
1742
|
+
referenceTableSuffix +
|
|
1743
|
+
'."name"=@' +
|
|
1346
1744
|
qrefName +
|
|
1347
|
-
' AND
|
|
1745
|
+
' AND EXISTS (' +
|
|
1348
1746
|
qrefQuery.query +
|
|
1349
1747
|
'))';
|
|
1350
1748
|
params[qrefName] = curValue[0];
|
|
@@ -1352,22 +1750,35 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1352
1750
|
}
|
|
1353
1751
|
}
|
|
1354
1752
|
return curQuery;
|
|
1355
|
-
}
|
|
1753
|
+
},
|
|
1356
1754
|
);
|
|
1357
1755
|
|
|
1358
1756
|
let sortBy: string;
|
|
1757
|
+
let sortByInner: string;
|
|
1758
|
+
let sortJoin = '';
|
|
1759
|
+
const order = options.reverse ? ' DESC' : '';
|
|
1359
1760
|
switch (sort) {
|
|
1360
1761
|
case 'mdate':
|
|
1361
|
-
sortBy =
|
|
1762
|
+
sortBy = `${eTable}."mdate"${order}`;
|
|
1763
|
+
sortByInner = `${ieTable}."mdate"${order}`;
|
|
1362
1764
|
break;
|
|
1363
1765
|
case 'cdate':
|
|
1766
|
+
sortBy = `${eTable}."cdate"${order}`;
|
|
1767
|
+
sortByInner = `${ieTable}."cdate"${order}`;
|
|
1768
|
+
break;
|
|
1364
1769
|
default:
|
|
1365
|
-
|
|
1770
|
+
const name = `param${++count.i}`;
|
|
1771
|
+
sortJoin = `LEFT JOIN (
|
|
1772
|
+
SELECT "guid", "string", "number"
|
|
1773
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'data_' + etype)}
|
|
1774
|
+
WHERE "name"=@${name}
|
|
1775
|
+
ORDER BY "number"${order}, "string"${order}
|
|
1776
|
+
) ${sTable} USING ("guid")`;
|
|
1777
|
+
sortBy = `${sTable}."number"${order}, ${sTable}."string"${order}`;
|
|
1778
|
+
sortByInner = sortBy;
|
|
1779
|
+
params[name] = sort;
|
|
1366
1780
|
break;
|
|
1367
1781
|
}
|
|
1368
|
-
if (options.reverse) {
|
|
1369
|
-
sortBy += ' DESC';
|
|
1370
|
-
}
|
|
1371
1782
|
|
|
1372
1783
|
let query: string;
|
|
1373
1784
|
if (queryParts.length) {
|
|
@@ -1383,29 +1794,33 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1383
1794
|
offset = ` OFFSET ${Math.floor(Number(options.offset))}`;
|
|
1384
1795
|
}
|
|
1385
1796
|
const whereClause = queryParts.join(') AND (');
|
|
1797
|
+
const guidClause = guidSelector
|
|
1798
|
+
? `${ieTable}."guid"=${guidSelector} AND `
|
|
1799
|
+
: '';
|
|
1386
1800
|
if (options.return === 'count') {
|
|
1387
1801
|
if (limit || offset) {
|
|
1388
1802
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1389
1803
|
SELECT "guid"
|
|
1390
1804
|
FROM ${SQLite3Driver.escape(
|
|
1391
|
-
this.prefix + 'entities_' + etype
|
|
1805
|
+
this.prefix + 'entities_' + etype,
|
|
1392
1806
|
)} ${ieTable}
|
|
1393
|
-
WHERE (${whereClause})${limit}${offset}
|
|
1807
|
+
WHERE ${guidClause}(${whereClause})${limit}${offset}
|
|
1394
1808
|
)`;
|
|
1395
1809
|
} else {
|
|
1396
1810
|
query = `SELECT COUNT("guid") AS "count"
|
|
1397
1811
|
FROM ${SQLite3Driver.escape(
|
|
1398
|
-
this.prefix + 'entities_' + etype
|
|
1812
|
+
this.prefix + 'entities_' + etype,
|
|
1399
1813
|
)} ${ieTable}
|
|
1400
|
-
WHERE (${whereClause})`;
|
|
1814
|
+
WHERE ${guidClause}(${whereClause})`;
|
|
1401
1815
|
}
|
|
1402
1816
|
} else if (options.return === 'guid') {
|
|
1403
1817
|
query = `SELECT "guid"
|
|
1404
1818
|
FROM ${SQLite3Driver.escape(
|
|
1405
|
-
this.prefix + 'entities_' + etype
|
|
1819
|
+
this.prefix + 'entities_' + etype,
|
|
1406
1820
|
)} ${ieTable}
|
|
1407
|
-
|
|
1408
|
-
|
|
1821
|
+
${sortJoin}
|
|
1822
|
+
WHERE ${guidClause}(${whereClause})
|
|
1823
|
+
ORDER BY ${sortByInner}, "guid"${limit}${offset}`;
|
|
1409
1824
|
} else {
|
|
1410
1825
|
query = `SELECT
|
|
1411
1826
|
${eTable}."guid",
|
|
@@ -1414,26 +1829,26 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1414
1829
|
${eTable}."mdate",
|
|
1415
1830
|
${dTable}."name",
|
|
1416
1831
|
${dTable}."value",
|
|
1417
|
-
${
|
|
1418
|
-
${
|
|
1832
|
+
json(${dTable}."json") as "json",
|
|
1833
|
+
${dTable}."string",
|
|
1834
|
+
${dTable}."number"
|
|
1419
1835
|
FROM ${SQLite3Driver.escape(
|
|
1420
|
-
this.prefix + 'entities_' + etype
|
|
1836
|
+
this.prefix + 'entities_' + etype,
|
|
1421
1837
|
)} ${eTable}
|
|
1422
1838
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1423
|
-
this.prefix + 'data_' + etype
|
|
1839
|
+
this.prefix + 'data_' + etype,
|
|
1424
1840
|
)} ${dTable} USING ("guid")
|
|
1425
|
-
|
|
1426
|
-
this.prefix + 'comparisons_' + etype
|
|
1427
|
-
)} ${cTable} USING ("guid", "name")
|
|
1841
|
+
${sortJoin}
|
|
1428
1842
|
INNER JOIN (
|
|
1429
1843
|
SELECT "guid"
|
|
1430
1844
|
FROM ${SQLite3Driver.escape(
|
|
1431
|
-
this.prefix + 'entities_' + etype
|
|
1845
|
+
this.prefix + 'entities_' + etype,
|
|
1432
1846
|
)} ${ieTable}
|
|
1433
|
-
|
|
1434
|
-
|
|
1847
|
+
${sortJoin}
|
|
1848
|
+
WHERE ${guidClause}(${whereClause})
|
|
1849
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1435
1850
|
) ${fTable} USING ("guid")
|
|
1436
|
-
ORDER BY ${
|
|
1851
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1437
1852
|
}
|
|
1438
1853
|
}
|
|
1439
1854
|
} else {
|
|
@@ -1448,26 +1863,31 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1448
1863
|
if ('offset' in options) {
|
|
1449
1864
|
offset = ` OFFSET ${Math.floor(Number(options.offset))}`;
|
|
1450
1865
|
}
|
|
1866
|
+
const guidClause = guidSelector
|
|
1867
|
+
? ` WHERE ${ieTable}."guid"=${guidSelector}`
|
|
1868
|
+
: '';
|
|
1451
1869
|
if (options.return === 'count') {
|
|
1452
1870
|
if (limit || offset) {
|
|
1453
1871
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1454
1872
|
SELECT "guid"
|
|
1455
1873
|
FROM ${SQLite3Driver.escape(
|
|
1456
|
-
this.prefix + 'entities_' + etype
|
|
1457
|
-
)} ${ieTable}${limit}${offset}
|
|
1874
|
+
this.prefix + 'entities_' + etype,
|
|
1875
|
+
)} ${ieTable}${guidClause}${limit}${offset}
|
|
1458
1876
|
)`;
|
|
1459
1877
|
} else {
|
|
1460
1878
|
query = `SELECT COUNT("guid") AS "count"
|
|
1461
1879
|
FROM ${SQLite3Driver.escape(
|
|
1462
|
-
this.prefix + 'entities_' + etype
|
|
1463
|
-
)} ${ieTable}`;
|
|
1880
|
+
this.prefix + 'entities_' + etype,
|
|
1881
|
+
)} ${ieTable}${guidClause}`;
|
|
1464
1882
|
}
|
|
1465
1883
|
} else if (options.return === 'guid') {
|
|
1466
1884
|
query = `SELECT "guid"
|
|
1467
1885
|
FROM ${SQLite3Driver.escape(
|
|
1468
|
-
this.prefix + 'entities_' + etype
|
|
1886
|
+
this.prefix + 'entities_' + etype,
|
|
1469
1887
|
)} ${ieTable}
|
|
1470
|
-
|
|
1888
|
+
${sortJoin}
|
|
1889
|
+
${guidClause}
|
|
1890
|
+
ORDER BY ${sortByInner}, "guid"${limit}${offset}`;
|
|
1471
1891
|
} else {
|
|
1472
1892
|
if (limit || offset) {
|
|
1473
1893
|
query = `SELECT
|
|
@@ -1477,25 +1897,26 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1477
1897
|
${eTable}."mdate",
|
|
1478
1898
|
${dTable}."name",
|
|
1479
1899
|
${dTable}."value",
|
|
1480
|
-
${
|
|
1481
|
-
${
|
|
1900
|
+
json(${dTable}."json") as "json",
|
|
1901
|
+
${dTable}."string",
|
|
1902
|
+
${dTable}."number"
|
|
1482
1903
|
FROM ${SQLite3Driver.escape(
|
|
1483
|
-
this.prefix + 'entities_' + etype
|
|
1904
|
+
this.prefix + 'entities_' + etype,
|
|
1484
1905
|
)} ${eTable}
|
|
1485
1906
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1486
|
-
this.prefix + 'data_' + etype
|
|
1907
|
+
this.prefix + 'data_' + etype,
|
|
1487
1908
|
)} ${dTable} USING ("guid")
|
|
1488
|
-
|
|
1489
|
-
this.prefix + 'comparisons_' + etype
|
|
1490
|
-
)} c USING ("guid", "name")
|
|
1909
|
+
${sortJoin}
|
|
1491
1910
|
INNER JOIN (
|
|
1492
1911
|
SELECT "guid"
|
|
1493
1912
|
FROM ${SQLite3Driver.escape(
|
|
1494
|
-
this.prefix + 'entities_' + etype
|
|
1913
|
+
this.prefix + 'entities_' + etype,
|
|
1495
1914
|
)} ${ieTable}
|
|
1496
|
-
|
|
1915
|
+
${sortJoin}
|
|
1916
|
+
${guidClause}
|
|
1917
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1497
1918
|
) ${fTable} USING ("guid")
|
|
1498
|
-
ORDER BY ${
|
|
1919
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1499
1920
|
} else {
|
|
1500
1921
|
query = `SELECT
|
|
1501
1922
|
${eTable}."guid",
|
|
@@ -1504,18 +1925,18 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1504
1925
|
${eTable}."mdate",
|
|
1505
1926
|
${dTable}."name",
|
|
1506
1927
|
${dTable}."value",
|
|
1507
|
-
${
|
|
1508
|
-
${
|
|
1928
|
+
json(${dTable}."json") as "json",
|
|
1929
|
+
${dTable}."string",
|
|
1930
|
+
${dTable}."number"
|
|
1509
1931
|
FROM ${SQLite3Driver.escape(
|
|
1510
|
-
this.prefix + 'entities_' + etype
|
|
1932
|
+
this.prefix + 'entities_' + etype,
|
|
1511
1933
|
)} ${eTable}
|
|
1512
1934
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1513
|
-
this.prefix + 'data_' + etype
|
|
1935
|
+
this.prefix + 'data_' + etype,
|
|
1514
1936
|
)} ${dTable} USING ("guid")
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
ORDER BY ${eTable}.${sortBy}`;
|
|
1937
|
+
${sortJoin}
|
|
1938
|
+
${guidSelector ? `WHERE ${eTable}."guid"=${guidSelector}` : ''}
|
|
1939
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1519
1940
|
}
|
|
1520
1941
|
}
|
|
1521
1942
|
}
|
|
@@ -1535,16 +1956,18 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1535
1956
|
protected performQuery(
|
|
1536
1957
|
options: Options,
|
|
1537
1958
|
formattedSelectors: FormattedSelector[],
|
|
1538
|
-
etype: string
|
|
1959
|
+
etype: string,
|
|
1539
1960
|
): {
|
|
1540
1961
|
result: any;
|
|
1541
1962
|
} {
|
|
1542
1963
|
const { query, params, etypes } = this.makeEntityQuery(
|
|
1543
1964
|
options,
|
|
1544
1965
|
formattedSelectors,
|
|
1545
|
-
etype
|
|
1966
|
+
etype,
|
|
1546
1967
|
);
|
|
1547
|
-
const result = this.
|
|
1968
|
+
const result = this.queryArray(query, { etypes, params })[
|
|
1969
|
+
Symbol.iterator
|
|
1970
|
+
]();
|
|
1548
1971
|
return {
|
|
1549
1972
|
result,
|
|
1550
1973
|
};
|
|
@@ -1559,37 +1982,24 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1559
1982
|
...selectors: Selector[]
|
|
1560
1983
|
): Promise<string[]>;
|
|
1561
1984
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1562
|
-
options
|
|
1985
|
+
options: Options<T> & { return: 'object' },
|
|
1563
1986
|
...selectors: Selector[]
|
|
1564
|
-
): Promise<
|
|
1987
|
+
): Promise<EntityObjectType<T>[]>;
|
|
1565
1988
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1566
|
-
options: Options<T> = {},
|
|
1567
|
-
...selectors: Selector[]
|
|
1568
|
-
): Promise<ReturnType<T['factorySync']>[] | string[] | number> {
|
|
1569
|
-
return this.getEntitiesSync(options, ...selectors);
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1573
|
-
options: Options<T> & { return: 'count' },
|
|
1574
|
-
...selectors: Selector[]
|
|
1575
|
-
): number;
|
|
1576
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1577
|
-
options: Options<T> & { return: 'guid' },
|
|
1578
|
-
...selectors: Selector[]
|
|
1579
|
-
): string[];
|
|
1580
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1581
1989
|
options?: Options<T>,
|
|
1582
1990
|
...selectors: Selector[]
|
|
1583
|
-
):
|
|
1584
|
-
|
|
1991
|
+
): Promise<EntityInstanceType<T>[]>;
|
|
1992
|
+
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1585
1993
|
options: Options<T> = {},
|
|
1586
1994
|
...selectors: Selector[]
|
|
1587
|
-
):
|
|
1588
|
-
|
|
1995
|
+
): Promise<
|
|
1996
|
+
EntityInstanceType<T>[] | EntityObjectType<T>[] | string[] | number
|
|
1997
|
+
> {
|
|
1998
|
+
const { result, process } = this.getEntitiesRowLike<T>(
|
|
1589
1999
|
options,
|
|
1590
2000
|
selectors,
|
|
1591
|
-
(options,
|
|
1592
|
-
this.performQuery(options,
|
|
2001
|
+
({ options, selectors, etype }) =>
|
|
2002
|
+
this.performQuery(options, selectors, etype),
|
|
1593
2003
|
() => {
|
|
1594
2004
|
const next: any = result.next();
|
|
1595
2005
|
return next.done ? null : next.value;
|
|
@@ -1598,7 +2008,13 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1598
2008
|
(row) => Number(row.count),
|
|
1599
2009
|
(row) => row.guid,
|
|
1600
2010
|
(row) => ({
|
|
1601
|
-
tags:
|
|
2011
|
+
tags:
|
|
2012
|
+
row.tags.length > 2
|
|
2013
|
+
? row.tags
|
|
2014
|
+
.slice(1, -1)
|
|
2015
|
+
.split(',')
|
|
2016
|
+
.filter((tag: string) => tag)
|
|
2017
|
+
: [],
|
|
1602
2018
|
cdate: Number(row.cdate),
|
|
1603
2019
|
mdate: Number(row.mdate),
|
|
1604
2020
|
}),
|
|
@@ -1608,9 +2024,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1608
2024
|
row.value === 'N'
|
|
1609
2025
|
? JSON.stringify(row.number)
|
|
1610
2026
|
: row.value === 'S'
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
2027
|
+
? JSON.stringify(row.string)
|
|
2028
|
+
: row.value === 'J'
|
|
2029
|
+
? row.json
|
|
2030
|
+
: row.value,
|
|
2031
|
+
}),
|
|
1614
2032
|
);
|
|
1615
2033
|
const value = process();
|
|
1616
2034
|
if (value instanceof Error) {
|
|
@@ -1623,175 +2041,304 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1623
2041
|
if (name == null) {
|
|
1624
2042
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1625
2043
|
}
|
|
1626
|
-
const result = this.queryGet(
|
|
2044
|
+
const result: any = this.queryGet(
|
|
1627
2045
|
`SELECT "cur_uid" FROM ${SQLite3Driver.escape(
|
|
1628
|
-
`${this.prefix}uids
|
|
2046
|
+
`${this.prefix}uids`,
|
|
1629
2047
|
)} WHERE "name"=@name;`,
|
|
1630
2048
|
{
|
|
1631
2049
|
params: {
|
|
1632
2050
|
name: name,
|
|
1633
2051
|
},
|
|
1634
|
-
}
|
|
2052
|
+
},
|
|
1635
2053
|
);
|
|
1636
2054
|
return (result?.cur_uid as number | null) ?? null;
|
|
1637
2055
|
}
|
|
1638
2056
|
|
|
1639
|
-
public async
|
|
1640
|
-
|
|
2057
|
+
public async importEntity(entity: {
|
|
2058
|
+
guid: string;
|
|
2059
|
+
cdate: number;
|
|
2060
|
+
mdate: number;
|
|
2061
|
+
tags: string[];
|
|
2062
|
+
sdata: SerializedEntityData;
|
|
2063
|
+
etype: string;
|
|
2064
|
+
}) {
|
|
2065
|
+
return await this.importEntityInternal(entity, false);
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
public async importEntityTokens(entity: {
|
|
2069
|
+
guid: string;
|
|
2070
|
+
cdate: number;
|
|
2071
|
+
mdate: number;
|
|
2072
|
+
tags: string[];
|
|
2073
|
+
sdata: SerializedEntityData;
|
|
2074
|
+
etype: string;
|
|
2075
|
+
}) {
|
|
2076
|
+
return await this.importEntityInternal(entity, true);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
private async importEntityInternal(
|
|
2080
|
+
{
|
|
2081
|
+
guid,
|
|
2082
|
+
cdate,
|
|
2083
|
+
mdate,
|
|
2084
|
+
tags,
|
|
2085
|
+
sdata,
|
|
2086
|
+
etype,
|
|
2087
|
+
}: {
|
|
2088
|
+
guid: string;
|
|
2089
|
+
cdate: number;
|
|
2090
|
+
mdate: number;
|
|
2091
|
+
tags: string[];
|
|
2092
|
+
sdata: SerializedEntityData;
|
|
2093
|
+
etype: string;
|
|
2094
|
+
},
|
|
2095
|
+
onlyTokens: boolean,
|
|
2096
|
+
) {
|
|
1641
2097
|
try {
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
{
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
{
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
{
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
2098
|
+
if (!onlyTokens) {
|
|
2099
|
+
this.queryRun(
|
|
2100
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2101
|
+
`${this.prefix}entities_${etype}`,
|
|
2102
|
+
)} WHERE "guid"=@guid;`,
|
|
2103
|
+
{
|
|
2104
|
+
etypes: [etype],
|
|
2105
|
+
params: {
|
|
2106
|
+
guid,
|
|
2107
|
+
},
|
|
2108
|
+
},
|
|
2109
|
+
);
|
|
2110
|
+
this.queryRun(
|
|
2111
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2112
|
+
`${this.prefix}data_${etype}`,
|
|
2113
|
+
)} WHERE "guid"=@guid;`,
|
|
2114
|
+
{
|
|
2115
|
+
etypes: [etype],
|
|
2116
|
+
params: {
|
|
2117
|
+
guid,
|
|
2118
|
+
},
|
|
2119
|
+
},
|
|
2120
|
+
);
|
|
2121
|
+
this.queryRun(
|
|
2122
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2123
|
+
`${this.prefix}references_${etype}`,
|
|
2124
|
+
)} WHERE "guid"=@guid;`,
|
|
2125
|
+
{
|
|
2126
|
+
etypes: [etype],
|
|
2127
|
+
params: {
|
|
2128
|
+
guid,
|
|
2129
|
+
},
|
|
2130
|
+
},
|
|
2131
|
+
);
|
|
2132
|
+
}
|
|
2133
|
+
this.queryRun(
|
|
2134
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2135
|
+
`${this.prefix}tokens_${etype}`,
|
|
2136
|
+
)} WHERE "guid"=@guid;`,
|
|
2137
|
+
{
|
|
2138
|
+
etypes: [etype],
|
|
2139
|
+
params: {
|
|
2140
|
+
guid,
|
|
2141
|
+
},
|
|
2142
|
+
},
|
|
2143
|
+
);
|
|
2144
|
+
if (!onlyTokens) {
|
|
2145
|
+
this.queryRun(
|
|
2146
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2147
|
+
`${this.prefix}uniques_${etype}`,
|
|
2148
|
+
)} WHERE "guid"=@guid;`,
|
|
2149
|
+
{
|
|
2150
|
+
etypes: [etype],
|
|
2151
|
+
params: {
|
|
2152
|
+
guid,
|
|
2153
|
+
},
|
|
2154
|
+
},
|
|
2155
|
+
);
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
if (!onlyTokens) {
|
|
2159
|
+
this.queryRun(
|
|
2160
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2161
|
+
`${this.prefix}entities_${etype}`,
|
|
2162
|
+
)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @mdate);`,
|
|
2163
|
+
{
|
|
2164
|
+
etypes: [etype],
|
|
2165
|
+
params: {
|
|
2166
|
+
guid,
|
|
2167
|
+
tags: ',' + tags.join(',') + ',',
|
|
2168
|
+
cdate,
|
|
2169
|
+
mdate,
|
|
2170
|
+
},
|
|
2171
|
+
},
|
|
2172
|
+
);
|
|
2173
|
+
|
|
2174
|
+
for (const name in sdata) {
|
|
2175
|
+
const value = sdata[name];
|
|
2176
|
+
const uvalue = JSON.parse(value);
|
|
2177
|
+
if (value === undefined) {
|
|
2178
|
+
continue;
|
|
2179
|
+
}
|
|
2180
|
+
const storageValue =
|
|
2181
|
+
typeof uvalue === 'number'
|
|
2182
|
+
? 'N'
|
|
2183
|
+
: typeof uvalue === 'string'
|
|
2184
|
+
? 'S'
|
|
2185
|
+
: 'J';
|
|
2186
|
+
const jsonValue = storageValue === 'J' ? value : null;
|
|
2187
|
+
|
|
1689
2188
|
this.queryRun(
|
|
1690
2189
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1691
|
-
`${this.prefix}
|
|
1692
|
-
)} ("guid", "
|
|
2190
|
+
`${this.prefix}data_${etype}`,
|
|
2191
|
+
)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (@guid, @name, @storageValue, jsonb(@jsonValue), @string, @number, @truthy);`,
|
|
1693
2192
|
{
|
|
1694
2193
|
etypes: [etype],
|
|
1695
2194
|
params: {
|
|
1696
2195
|
guid,
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
2196
|
+
name,
|
|
2197
|
+
storageValue,
|
|
2198
|
+
jsonValue,
|
|
2199
|
+
string: storageValue === 'J' ? null : `${uvalue}`,
|
|
2200
|
+
number: Number(uvalue),
|
|
2201
|
+
truthy: uvalue ? 1 : 0,
|
|
1700
2202
|
},
|
|
1701
|
-
}
|
|
2203
|
+
},
|
|
1702
2204
|
);
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
for (const
|
|
1706
|
-
const value = sdata[name];
|
|
1707
|
-
const uvalue = JSON.parse(value);
|
|
1708
|
-
if (value === undefined) {
|
|
1709
|
-
continue;
|
|
1710
|
-
}
|
|
1711
|
-
const storageValue =
|
|
1712
|
-
typeof uvalue === 'number'
|
|
1713
|
-
? 'N'
|
|
1714
|
-
: typeof uvalue === 'string'
|
|
1715
|
-
? 'S'
|
|
1716
|
-
: value;
|
|
2205
|
+
|
|
2206
|
+
const references = this.findReferences(value);
|
|
2207
|
+
for (const reference of references) {
|
|
1717
2208
|
this.queryRun(
|
|
1718
2209
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1719
|
-
`${this.prefix}
|
|
1720
|
-
)} ("guid", "name", "
|
|
2210
|
+
`${this.prefix}references_${etype}`,
|
|
2211
|
+
)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`,
|
|
1721
2212
|
{
|
|
1722
2213
|
etypes: [etype],
|
|
1723
2214
|
params: {
|
|
1724
2215
|
guid,
|
|
1725
2216
|
name,
|
|
1726
|
-
|
|
2217
|
+
reference,
|
|
1727
2218
|
},
|
|
1728
|
-
}
|
|
2219
|
+
},
|
|
2220
|
+
);
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
2226
|
+
|
|
2227
|
+
for (let name in sdata) {
|
|
2228
|
+
let tokenString: string | null = null;
|
|
2229
|
+
try {
|
|
2230
|
+
tokenString = EntityClass.getFTSText(name, JSON.parse(sdata[name]));
|
|
2231
|
+
} catch (e: any) {
|
|
2232
|
+
// Ignore error.
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
if (tokenString != null) {
|
|
2236
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
2237
|
+
while (tokens.length) {
|
|
2238
|
+
const currentTokens = tokens.splice(0, 100);
|
|
2239
|
+
const params: { [k: string]: any } = {
|
|
2240
|
+
guid,
|
|
2241
|
+
name,
|
|
2242
|
+
};
|
|
2243
|
+
const values: string[] = [];
|
|
2244
|
+
|
|
2245
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
2246
|
+
const token = currentTokens[i];
|
|
2247
|
+
params['token' + i] = token.token;
|
|
2248
|
+
params['position' + i] = token.position;
|
|
2249
|
+
params['stem' + i] = token.stem ? 1 : 0;
|
|
2250
|
+
values.push(
|
|
2251
|
+
'(@guid, @name, @token' +
|
|
2252
|
+
i +
|
|
2253
|
+
', @position' +
|
|
2254
|
+
i +
|
|
2255
|
+
', @stem' +
|
|
2256
|
+
i +
|
|
2257
|
+
')',
|
|
2258
|
+
);
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
this.queryRun(
|
|
2262
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2263
|
+
`${this.prefix}tokens_${etype}`,
|
|
2264
|
+
)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`,
|
|
2265
|
+
{
|
|
2266
|
+
etypes: [etype],
|
|
2267
|
+
params,
|
|
2268
|
+
},
|
|
1729
2269
|
);
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
if (!onlyTokens) {
|
|
2275
|
+
const uniques = await EntityClass.getUniques({
|
|
2276
|
+
guid,
|
|
2277
|
+
cdate,
|
|
2278
|
+
mdate,
|
|
2279
|
+
tags,
|
|
2280
|
+
data: {},
|
|
2281
|
+
sdata,
|
|
2282
|
+
});
|
|
2283
|
+
for (const unique of uniques) {
|
|
2284
|
+
try {
|
|
1730
2285
|
this.queryRun(
|
|
1731
2286
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1732
|
-
`${this.prefix}
|
|
1733
|
-
)} ("guid", "
|
|
2287
|
+
`${this.prefix}uniques_${etype}`,
|
|
2288
|
+
)} ("guid", "unique") VALUES (@guid, @unique);`,
|
|
1734
2289
|
{
|
|
1735
2290
|
etypes: [etype],
|
|
1736
2291
|
params: {
|
|
1737
2292
|
guid,
|
|
1738
|
-
|
|
1739
|
-
truthy: uvalue ? 1 : 0,
|
|
1740
|
-
string: `${uvalue}`,
|
|
1741
|
-
number: Number(uvalue),
|
|
2293
|
+
unique,
|
|
1742
2294
|
},
|
|
1743
|
-
}
|
|
2295
|
+
},
|
|
1744
2296
|
);
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
this.
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`,
|
|
1751
|
-
{
|
|
1752
|
-
etypes: [etype],
|
|
1753
|
-
params: {
|
|
1754
|
-
guid,
|
|
1755
|
-
name,
|
|
1756
|
-
reference,
|
|
1757
|
-
},
|
|
1758
|
-
}
|
|
2297
|
+
} catch (e: any) {
|
|
2298
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2299
|
+
this.nymph.config.debugError(
|
|
2300
|
+
'sqlite3',
|
|
2301
|
+
`Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`,
|
|
1759
2302
|
);
|
|
1760
2303
|
}
|
|
2304
|
+
throw e;
|
|
1761
2305
|
}
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
} catch (e: any) {
|
|
2309
|
+
this.nymph.config.debugError('sqlite3', `Import entity error: "${e}"`);
|
|
2310
|
+
throw e;
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
public async importUID({ name, value }: { name: string; value: number }) {
|
|
2315
|
+
try {
|
|
2316
|
+
await this.startTransaction(`nymph-import-uid-${name}`);
|
|
2317
|
+
this.queryRun(
|
|
2318
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2319
|
+
`${this.prefix}uids`,
|
|
2320
|
+
)} WHERE "name"=@name;`,
|
|
2321
|
+
{
|
|
2322
|
+
params: {
|
|
2323
|
+
name,
|
|
2324
|
+
},
|
|
1762
2325
|
},
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
);
|
|
1774
|
-
this.queryRun(
|
|
1775
|
-
`INSERT INTO ${SQLite3Driver.escape(
|
|
1776
|
-
`${this.prefix}uids`
|
|
1777
|
-
)} ("name", "cur_uid") VALUES (@name, @curUid);`,
|
|
1778
|
-
{
|
|
1779
|
-
params: {
|
|
1780
|
-
name,
|
|
1781
|
-
curUid,
|
|
1782
|
-
},
|
|
1783
|
-
}
|
|
1784
|
-
);
|
|
1785
|
-
},
|
|
1786
|
-
async () => {
|
|
1787
|
-
await this.startTransaction('nymph-import');
|
|
2326
|
+
);
|
|
2327
|
+
this.queryRun(
|
|
2328
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2329
|
+
`${this.prefix}uids`,
|
|
2330
|
+
)} ("name", "cur_uid") VALUES (@name, @value);`,
|
|
2331
|
+
{
|
|
2332
|
+
params: {
|
|
2333
|
+
name,
|
|
2334
|
+
value,
|
|
2335
|
+
},
|
|
1788
2336
|
},
|
|
1789
|
-
async () => {
|
|
1790
|
-
await this.commit('nymph-import');
|
|
1791
|
-
}
|
|
1792
2337
|
);
|
|
2338
|
+
await this.commit(`nymph-import-uid-${name}`);
|
|
1793
2339
|
} catch (e: any) {
|
|
1794
|
-
|
|
2340
|
+
this.nymph.config.debugError('sqlite3', `Import UID error: "${e}"`);
|
|
2341
|
+
await this.rollback(`nymph-import-uid-${name}`);
|
|
1795
2342
|
throw e;
|
|
1796
2343
|
}
|
|
1797
2344
|
}
|
|
@@ -1800,78 +2347,83 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1800
2347
|
if (name == null) {
|
|
1801
2348
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1802
2349
|
}
|
|
1803
|
-
this.checkReadOnlyMode();
|
|
1804
2350
|
await this.startTransaction('nymph-newuid');
|
|
2351
|
+
let curUid: number | undefined = undefined;
|
|
1805
2352
|
try {
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
2353
|
+
curUid =
|
|
2354
|
+
(
|
|
2355
|
+
this.queryGet(
|
|
2356
|
+
`SELECT "cur_uid" FROM ${SQLite3Driver.escape(
|
|
2357
|
+
`${this.prefix}uids`,
|
|
2358
|
+
)} WHERE "name"=@name;`,
|
|
2359
|
+
{
|
|
2360
|
+
params: {
|
|
2361
|
+
name,
|
|
2362
|
+
},
|
|
1814
2363
|
},
|
|
1815
|
-
|
|
2364
|
+
) as any
|
|
1816
2365
|
)?.cur_uid ?? null;
|
|
1817
2366
|
if (curUid == null) {
|
|
1818
2367
|
curUid = 1;
|
|
1819
2368
|
this.queryRun(
|
|
1820
2369
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1821
|
-
`${this.prefix}uids
|
|
2370
|
+
`${this.prefix}uids`,
|
|
1822
2371
|
)} ("name", "cur_uid") VALUES (@name, @curUid);`,
|
|
1823
2372
|
{
|
|
1824
2373
|
params: {
|
|
1825
2374
|
name,
|
|
1826
2375
|
curUid,
|
|
1827
2376
|
},
|
|
1828
|
-
}
|
|
2377
|
+
},
|
|
1829
2378
|
);
|
|
1830
2379
|
} else {
|
|
1831
2380
|
curUid++;
|
|
1832
2381
|
this.queryRun(
|
|
1833
2382
|
`UPDATE ${SQLite3Driver.escape(
|
|
1834
|
-
`${this.prefix}uids
|
|
2383
|
+
`${this.prefix}uids`,
|
|
1835
2384
|
)} SET "cur_uid"=@curUid WHERE "name"=@name;`,
|
|
1836
2385
|
{
|
|
1837
2386
|
params: {
|
|
1838
2387
|
curUid,
|
|
1839
2388
|
name,
|
|
1840
2389
|
},
|
|
1841
|
-
}
|
|
2390
|
+
},
|
|
1842
2391
|
);
|
|
1843
2392
|
}
|
|
1844
|
-
await this.commit('nymph-newuid');
|
|
1845
|
-
return curUid as number;
|
|
1846
2393
|
} catch (e: any) {
|
|
2394
|
+
this.nymph.config.debugError('sqlite3', `New UID error: "${e}"`);
|
|
1847
2395
|
await this.rollback('nymph-newuid');
|
|
1848
2396
|
throw e;
|
|
1849
2397
|
}
|
|
2398
|
+
|
|
2399
|
+
await this.commit('nymph-newuid');
|
|
2400
|
+
return curUid as number;
|
|
1850
2401
|
}
|
|
1851
2402
|
|
|
1852
2403
|
public async renameUID(oldName: string, newName: string) {
|
|
1853
2404
|
if (oldName == null || newName == null) {
|
|
1854
2405
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1855
2406
|
}
|
|
1856
|
-
this.
|
|
2407
|
+
await this.startTransaction('nymph-rename-uid');
|
|
1857
2408
|
this.queryRun(
|
|
1858
2409
|
`UPDATE ${SQLite3Driver.escape(
|
|
1859
|
-
`${this.prefix}uids
|
|
2410
|
+
`${this.prefix}uids`,
|
|
1860
2411
|
)} SET "name"=@newName WHERE "name"=@oldName;`,
|
|
1861
2412
|
{
|
|
1862
2413
|
params: {
|
|
1863
2414
|
newName,
|
|
1864
2415
|
oldName,
|
|
1865
2416
|
},
|
|
1866
|
-
}
|
|
2417
|
+
},
|
|
1867
2418
|
);
|
|
2419
|
+
await this.commit('nymph-rename-uid');
|
|
1868
2420
|
return true;
|
|
1869
2421
|
}
|
|
1870
2422
|
|
|
1871
2423
|
public async rollback(name: string) {
|
|
1872
2424
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1873
2425
|
throw new InvalidParametersError(
|
|
1874
|
-
'Transaction rollback attempted without a name.'
|
|
2426
|
+
'Transaction rollback attempted without a name.',
|
|
1875
2427
|
);
|
|
1876
2428
|
}
|
|
1877
2429
|
if (this.store.transactionsStarted === 0) {
|
|
@@ -1879,17 +2431,30 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1879
2431
|
}
|
|
1880
2432
|
this.queryRun(`ROLLBACK TO SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
1881
2433
|
this.store.transactionsStarted--;
|
|
2434
|
+
|
|
2435
|
+
if (
|
|
2436
|
+
this.store.transactionsStarted === 0 &&
|
|
2437
|
+
this.store.linkWrite &&
|
|
2438
|
+
!this.config.explicitWrite
|
|
2439
|
+
) {
|
|
2440
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
2441
|
+
this.store.linkWrite.close();
|
|
2442
|
+
this.store.linkWrite = undefined;
|
|
2443
|
+
}
|
|
2444
|
+
|
|
1882
2445
|
return true;
|
|
1883
2446
|
}
|
|
1884
2447
|
|
|
1885
2448
|
public async saveEntity(entity: EntityInterface) {
|
|
1886
|
-
this.checkReadOnlyMode();
|
|
1887
2449
|
const insertData = (
|
|
1888
2450
|
guid: string,
|
|
1889
2451
|
data: EntityData,
|
|
1890
2452
|
sdata: SerializedEntityData,
|
|
1891
|
-
|
|
2453
|
+
uniques: string[],
|
|
2454
|
+
etype: string,
|
|
1892
2455
|
) => {
|
|
2456
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
2457
|
+
|
|
1893
2458
|
const runInsertQuery = (name: string, value: any, svalue: string) => {
|
|
1894
2459
|
if (value === undefined) {
|
|
1895
2460
|
return;
|
|
@@ -1898,41 +2463,33 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1898
2463
|
typeof value === 'number'
|
|
1899
2464
|
? 'N'
|
|
1900
2465
|
: typeof value === 'string'
|
|
1901
|
-
|
|
1902
|
-
|
|
2466
|
+
? 'S'
|
|
2467
|
+
: 'J';
|
|
2468
|
+
const jsonValue = storageValue === 'J' ? svalue : null;
|
|
2469
|
+
|
|
1903
2470
|
this.queryRun(
|
|
1904
2471
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1905
|
-
`${this.prefix}data_${etype}
|
|
1906
|
-
)} ("guid", "name", "value") VALUES (@guid, @name, @storageValue);`,
|
|
2472
|
+
`${this.prefix}data_${etype}`,
|
|
2473
|
+
)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (@guid, @name, @storageValue, jsonb(@jsonValue), @string, @number, @truthy);`,
|
|
1907
2474
|
{
|
|
1908
2475
|
etypes: [etype],
|
|
1909
2476
|
params: {
|
|
1910
2477
|
guid,
|
|
1911
2478
|
name,
|
|
1912
2479
|
storageValue,
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
);
|
|
1916
|
-
this.queryRun(
|
|
1917
|
-
`INSERT INTO ${SQLite3Driver.escape(
|
|
1918
|
-
`${this.prefix}comparisons_${etype}`
|
|
1919
|
-
)} ("guid", "name", "truthy", "string", "number") VALUES (@guid, @name, @truthy, @string, @number);`,
|
|
1920
|
-
{
|
|
1921
|
-
etypes: [etype],
|
|
1922
|
-
params: {
|
|
1923
|
-
guid,
|
|
1924
|
-
name,
|
|
1925
|
-
truthy: value ? 1 : 0,
|
|
1926
|
-
string: `${value}`,
|
|
2480
|
+
jsonValue,
|
|
2481
|
+
string: storageValue === 'J' ? null : `${value}`,
|
|
1927
2482
|
number: Number(value),
|
|
2483
|
+
truthy: value ? 1 : 0,
|
|
1928
2484
|
},
|
|
1929
|
-
}
|
|
2485
|
+
},
|
|
1930
2486
|
);
|
|
2487
|
+
|
|
1931
2488
|
const references = this.findReferences(svalue);
|
|
1932
2489
|
for (const reference of references) {
|
|
1933
2490
|
this.queryRun(
|
|
1934
2491
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1935
|
-
`${this.prefix}references_${etype}
|
|
2492
|
+
`${this.prefix}references_${etype}`,
|
|
1936
2493
|
)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`,
|
|
1937
2494
|
{
|
|
1938
2495
|
etypes: [etype],
|
|
@@ -1941,10 +2498,80 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1941
2498
|
name,
|
|
1942
2499
|
reference,
|
|
1943
2500
|
},
|
|
1944
|
-
}
|
|
2501
|
+
},
|
|
1945
2502
|
);
|
|
1946
2503
|
}
|
|
2504
|
+
|
|
2505
|
+
let tokenString: string | null = null;
|
|
2506
|
+
try {
|
|
2507
|
+
tokenString = EntityClass.getFTSText(name, value);
|
|
2508
|
+
} catch (e: any) {
|
|
2509
|
+
// Ignore error.
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
if (tokenString != null) {
|
|
2513
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
2514
|
+
while (tokens.length) {
|
|
2515
|
+
const currentTokens = tokens.splice(0, 100);
|
|
2516
|
+
const params: { [k: string]: any } = {
|
|
2517
|
+
guid,
|
|
2518
|
+
name,
|
|
2519
|
+
};
|
|
2520
|
+
const values: string[] = [];
|
|
2521
|
+
|
|
2522
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
2523
|
+
const token = currentTokens[i];
|
|
2524
|
+
params['token' + i] = token.token;
|
|
2525
|
+
params['position' + i] = token.position;
|
|
2526
|
+
params['stem' + i] = token.stem ? 1 : 0;
|
|
2527
|
+
values.push(
|
|
2528
|
+
'(@guid, @name, @token' +
|
|
2529
|
+
i +
|
|
2530
|
+
', @position' +
|
|
2531
|
+
i +
|
|
2532
|
+
', @stem' +
|
|
2533
|
+
i +
|
|
2534
|
+
')',
|
|
2535
|
+
);
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
this.queryRun(
|
|
2539
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2540
|
+
`${this.prefix}tokens_${etype}`,
|
|
2541
|
+
)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`,
|
|
2542
|
+
{
|
|
2543
|
+
etypes: [etype],
|
|
2544
|
+
params,
|
|
2545
|
+
},
|
|
2546
|
+
);
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
1947
2549
|
};
|
|
2550
|
+
|
|
2551
|
+
for (const unique of uniques) {
|
|
2552
|
+
try {
|
|
2553
|
+
this.queryRun(
|
|
2554
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2555
|
+
`${this.prefix}uniques_${etype}`,
|
|
2556
|
+
)} ("guid", "unique") VALUES (@guid, @unique);`,
|
|
2557
|
+
{
|
|
2558
|
+
etypes: [etype],
|
|
2559
|
+
params: {
|
|
2560
|
+
guid,
|
|
2561
|
+
unique,
|
|
2562
|
+
},
|
|
2563
|
+
},
|
|
2564
|
+
);
|
|
2565
|
+
} catch (e: any) {
|
|
2566
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2567
|
+
this.nymph.config.debugError(
|
|
2568
|
+
'sqlite3',
|
|
2569
|
+
`Save entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`,
|
|
2570
|
+
);
|
|
2571
|
+
}
|
|
2572
|
+
throw e;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
1948
2575
|
for (const name in data) {
|
|
1949
2576
|
runInsertQuery(name, data[name], JSON.stringify(data[name]));
|
|
1950
2577
|
}
|
|
@@ -1952,13 +2579,20 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1952
2579
|
runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
|
|
1953
2580
|
}
|
|
1954
2581
|
};
|
|
2582
|
+
let inTransaction = false;
|
|
1955
2583
|
try {
|
|
1956
2584
|
return this.saveEntityRowLike(
|
|
1957
2585
|
entity,
|
|
1958
|
-
async (
|
|
2586
|
+
async ({ guid, tags, data, sdata, uniques, cdate, etype }) => {
|
|
2587
|
+
if (
|
|
2588
|
+
Object.keys(data).length === 0 &&
|
|
2589
|
+
Object.keys(sdata).length === 0
|
|
2590
|
+
) {
|
|
2591
|
+
return false;
|
|
2592
|
+
}
|
|
1959
2593
|
this.queryRun(
|
|
1960
2594
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1961
|
-
`${this.prefix}entities_${etype}
|
|
2595
|
+
`${this.prefix}entities_${etype}`,
|
|
1962
2596
|
)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @cdate);`,
|
|
1963
2597
|
{
|
|
1964
2598
|
etypes: [etype],
|
|
@@ -1967,15 +2601,21 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1967
2601
|
tags: ',' + tags.join(',') + ',',
|
|
1968
2602
|
cdate,
|
|
1969
2603
|
},
|
|
1970
|
-
}
|
|
2604
|
+
},
|
|
1971
2605
|
);
|
|
1972
|
-
insertData(guid, data, sdata, etype);
|
|
2606
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
1973
2607
|
return true;
|
|
1974
2608
|
},
|
|
1975
|
-
async (entity, guid, tags, data, sdata, mdate, etype) => {
|
|
2609
|
+
async ({ entity, guid, tags, data, sdata, uniques, mdate, etype }) => {
|
|
2610
|
+
if (
|
|
2611
|
+
Object.keys(data).length === 0 &&
|
|
2612
|
+
Object.keys(sdata).length === 0
|
|
2613
|
+
) {
|
|
2614
|
+
return false;
|
|
2615
|
+
}
|
|
1976
2616
|
const info = this.queryRun(
|
|
1977
2617
|
`UPDATE ${SQLite3Driver.escape(
|
|
1978
|
-
`${this.prefix}entities_${etype}
|
|
2618
|
+
`${this.prefix}entities_${etype}`,
|
|
1979
2619
|
)} SET "tags"=@tags, "mdate"=@mdate WHERE "guid"=@guid AND "mdate" <= @emdate;`,
|
|
1980
2620
|
{
|
|
1981
2621
|
etypes: [etype],
|
|
@@ -1985,62 +2625,80 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1985
2625
|
guid,
|
|
1986
2626
|
emdate: Number(entity.mdate),
|
|
1987
2627
|
},
|
|
1988
|
-
}
|
|
2628
|
+
},
|
|
1989
2629
|
);
|
|
1990
2630
|
let success = false;
|
|
1991
2631
|
if (info.changes === 1) {
|
|
1992
2632
|
this.queryRun(
|
|
1993
2633
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
1994
|
-
`${this.prefix}data_${etype}
|
|
2634
|
+
`${this.prefix}data_${etype}`,
|
|
1995
2635
|
)} WHERE "guid"=@guid;`,
|
|
1996
2636
|
{
|
|
1997
2637
|
etypes: [etype],
|
|
1998
2638
|
params: {
|
|
1999
2639
|
guid,
|
|
2000
2640
|
},
|
|
2001
|
-
}
|
|
2641
|
+
},
|
|
2002
2642
|
);
|
|
2003
2643
|
this.queryRun(
|
|
2004
2644
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2005
|
-
`${this.prefix}
|
|
2645
|
+
`${this.prefix}references_${etype}`,
|
|
2006
2646
|
)} WHERE "guid"=@guid;`,
|
|
2007
2647
|
{
|
|
2008
2648
|
etypes: [etype],
|
|
2009
2649
|
params: {
|
|
2010
2650
|
guid,
|
|
2011
2651
|
},
|
|
2012
|
-
}
|
|
2652
|
+
},
|
|
2013
2653
|
);
|
|
2014
2654
|
this.queryRun(
|
|
2015
2655
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2016
|
-
`${this.prefix}
|
|
2656
|
+
`${this.prefix}tokens_${etype}`,
|
|
2017
2657
|
)} WHERE "guid"=@guid;`,
|
|
2018
2658
|
{
|
|
2019
2659
|
etypes: [etype],
|
|
2020
2660
|
params: {
|
|
2021
2661
|
guid,
|
|
2022
2662
|
},
|
|
2023
|
-
}
|
|
2663
|
+
},
|
|
2664
|
+
);
|
|
2665
|
+
this.queryRun(
|
|
2666
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2667
|
+
`${this.prefix}uniques_${etype}`,
|
|
2668
|
+
)} WHERE "guid"=@guid;`,
|
|
2669
|
+
{
|
|
2670
|
+
etypes: [etype],
|
|
2671
|
+
params: {
|
|
2672
|
+
guid,
|
|
2673
|
+
},
|
|
2674
|
+
},
|
|
2024
2675
|
);
|
|
2025
|
-
insertData(guid, data, sdata, etype);
|
|
2676
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
2026
2677
|
success = true;
|
|
2027
2678
|
}
|
|
2028
2679
|
return success;
|
|
2029
2680
|
},
|
|
2030
2681
|
async () => {
|
|
2031
2682
|
await this.startTransaction('nymph-save');
|
|
2683
|
+
inTransaction = true;
|
|
2032
2684
|
},
|
|
2033
2685
|
async (success) => {
|
|
2034
|
-
if (
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2686
|
+
if (inTransaction) {
|
|
2687
|
+
inTransaction = false;
|
|
2688
|
+
if (success) {
|
|
2689
|
+
await this.commit('nymph-save');
|
|
2690
|
+
} else {
|
|
2691
|
+
await this.rollback('nymph-save');
|
|
2692
|
+
}
|
|
2038
2693
|
}
|
|
2039
2694
|
return success;
|
|
2040
|
-
}
|
|
2695
|
+
},
|
|
2041
2696
|
);
|
|
2042
2697
|
} catch (e: any) {
|
|
2043
|
-
|
|
2698
|
+
this.nymph.config.debugError('sqlite3', `Save entity error: "${e}"`);
|
|
2699
|
+
if (inTransaction) {
|
|
2700
|
+
await this.rollback('nymph-save');
|
|
2701
|
+
}
|
|
2044
2702
|
throw e;
|
|
2045
2703
|
}
|
|
2046
2704
|
}
|
|
@@ -2049,39 +2707,91 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
2049
2707
|
if (name == null) {
|
|
2050
2708
|
throw new InvalidParametersError('Name not given for UID.');
|
|
2051
2709
|
}
|
|
2052
|
-
this.
|
|
2710
|
+
await this.startTransaction('nymph-set-uid');
|
|
2053
2711
|
this.queryRun(
|
|
2054
2712
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2055
|
-
`${this.prefix}uids
|
|
2713
|
+
`${this.prefix}uids`,
|
|
2056
2714
|
)} WHERE "name"=@name;`,
|
|
2057
2715
|
{
|
|
2058
2716
|
params: {
|
|
2059
2717
|
name,
|
|
2060
2718
|
},
|
|
2061
|
-
}
|
|
2719
|
+
},
|
|
2062
2720
|
);
|
|
2063
2721
|
this.queryRun(
|
|
2064
2722
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
2065
|
-
`${this.prefix}uids
|
|
2723
|
+
`${this.prefix}uids`,
|
|
2066
2724
|
)} ("name", "cur_uid") VALUES (@name, @curUid);`,
|
|
2067
2725
|
{
|
|
2068
2726
|
params: {
|
|
2069
2727
|
name,
|
|
2070
2728
|
curUid,
|
|
2071
2729
|
},
|
|
2072
|
-
}
|
|
2730
|
+
},
|
|
2073
2731
|
);
|
|
2732
|
+
await this.commit('nymph-set-uid');
|
|
2074
2733
|
return true;
|
|
2075
2734
|
}
|
|
2076
2735
|
|
|
2736
|
+
public async internalTransaction(name: string) {
|
|
2737
|
+
await this.startTransaction(name);
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2077
2740
|
public async startTransaction(name: string) {
|
|
2078
2741
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
2079
2742
|
throw new InvalidParametersError(
|
|
2080
|
-
'Transaction start attempted without a name.'
|
|
2743
|
+
'Transaction start attempted without a name.',
|
|
2081
2744
|
);
|
|
2082
2745
|
}
|
|
2746
|
+
if (!this.config.explicitWrite && !this.store.linkWrite) {
|
|
2747
|
+
this._connect(true);
|
|
2748
|
+
}
|
|
2083
2749
|
this.queryRun(`SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
2084
2750
|
this.store.transactionsStarted++;
|
|
2085
2751
|
return this.nymph;
|
|
2086
2752
|
}
|
|
2753
|
+
|
|
2754
|
+
public async needsMigration(): Promise<'json' | 'tokens' | false> {
|
|
2755
|
+
const table: any = this.queryGet(
|
|
2756
|
+
"SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix LIMIT 1;",
|
|
2757
|
+
{
|
|
2758
|
+
params: {
|
|
2759
|
+
prefix: this.prefix + 'data_' + '%',
|
|
2760
|
+
},
|
|
2761
|
+
},
|
|
2762
|
+
);
|
|
2763
|
+
if (table?.name) {
|
|
2764
|
+
const result: any = this.queryGet(
|
|
2765
|
+
"SELECT 1 AS `exists` FROM pragma_table_info(@table) WHERE `name`='json';",
|
|
2766
|
+
{
|
|
2767
|
+
params: {
|
|
2768
|
+
table: table.name,
|
|
2769
|
+
},
|
|
2770
|
+
},
|
|
2771
|
+
);
|
|
2772
|
+
if (!result?.exists) {
|
|
2773
|
+
return 'json';
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
const table2: any = this.queryGet(
|
|
2777
|
+
"SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @tokenTable LIMIT 1;",
|
|
2778
|
+
{
|
|
2779
|
+
params: {
|
|
2780
|
+
tokenTable: this.prefix + 'tokens_' + '%',
|
|
2781
|
+
},
|
|
2782
|
+
},
|
|
2783
|
+
);
|
|
2784
|
+
if (!table2 || !table2.name) {
|
|
2785
|
+
return 'tokens';
|
|
2786
|
+
}
|
|
2787
|
+
return false;
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2790
|
+
public async liveMigration(_migrationType: 'tokenTables') {
|
|
2791
|
+
const etypes = await this.getEtypes();
|
|
2792
|
+
|
|
2793
|
+
for (let etype of etypes) {
|
|
2794
|
+
this.createTokensTable(etype);
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2087
2797
|
}
|