@nymphjs/driver-sqlite3 1.0.0-beta.11 → 1.0.0-beta.110
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 +495 -0
- package/README.md +1 -1
- package/dist/SQLite3Driver.d.ts +104 -14
- package/dist/SQLite3Driver.js +1558 -569
- package/dist/SQLite3Driver.js.map +1 -1
- package/dist/SQLite3Driver.test.js +54 -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 +19 -16
- package/src/SQLite3Driver.test.ts +53 -9
- package/src/SQLite3Driver.ts +2362 -892
- 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,16 +53,23 @@ 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
|
|
|
50
60
|
return '"' + input.replace(/"/g, () => '""') + '"';
|
|
51
61
|
}
|
|
52
62
|
|
|
63
|
+
static escapeValue(input: string) {
|
|
64
|
+
return "'" + input.replace(/'/g, () => "''") + "'";
|
|
65
|
+
}
|
|
66
|
+
|
|
53
67
|
constructor(config: Partial<SQLite3DriverConfig>, store?: InternalStore) {
|
|
54
68
|
super();
|
|
55
69
|
this.config = { ...defaults, ...config };
|
|
70
|
+
if (this.config.filename === ':memory:') {
|
|
71
|
+
this.config.explicitWrite = true;
|
|
72
|
+
}
|
|
56
73
|
this.prefix = this.config.prefix;
|
|
57
74
|
if (store) {
|
|
58
75
|
this.store = store;
|
|
@@ -75,57 +92,107 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
75
92
|
*
|
|
76
93
|
* @returns Whether this instance is connected to a SQLite3 database.
|
|
77
94
|
*/
|
|
78
|
-
public
|
|
79
|
-
const { filename, fileMustExist, timeout, readonly, wal, verbose } =
|
|
80
|
-
this.config;
|
|
81
|
-
|
|
95
|
+
public connect() {
|
|
82
96
|
if (this.store && this.store.connected) {
|
|
83
|
-
return true;
|
|
97
|
+
return Promise.resolve(true);
|
|
84
98
|
}
|
|
85
99
|
|
|
86
100
|
// Connecting
|
|
101
|
+
this._connect(false);
|
|
102
|
+
|
|
103
|
+
return Promise.resolve(this.store.connected);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private _connect(write: boolean) {
|
|
107
|
+
const { filename, fileMustExist, timeout, explicitWrite, wal, verbose } =
|
|
108
|
+
this.config;
|
|
109
|
+
|
|
87
110
|
try {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
111
|
+
const setOptions = (link: SQLite3.Database) => {
|
|
112
|
+
// Set database and connection options.
|
|
113
|
+
if (wal) {
|
|
114
|
+
link.pragma('journal_mode = WAL;');
|
|
115
|
+
}
|
|
116
|
+
link.pragma('encoding = "UTF-8";');
|
|
117
|
+
link.pragma('foreign_keys = 1;');
|
|
118
|
+
link.pragma('case_sensitive_like = 1;');
|
|
119
|
+
for (let pragma of this.config.pragmas) {
|
|
120
|
+
link.pragma(pragma);
|
|
121
|
+
}
|
|
122
|
+
// Create the preg_match and regexp functions.
|
|
123
|
+
link.function('regexp', { deterministic: true }, ((
|
|
124
|
+
pattern: string,
|
|
125
|
+
subject: string,
|
|
126
|
+
) => (this.posixRegexMatch(pattern, subject) ? 1 : 0)) as (
|
|
127
|
+
...params: any[]
|
|
128
|
+
) => any);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
let link: SQLite3.Database;
|
|
132
|
+
try {
|
|
133
|
+
link = new SQLite3(filename, {
|
|
134
|
+
readonly: !explicitWrite && !write,
|
|
135
|
+
fileMustExist,
|
|
136
|
+
timeout,
|
|
137
|
+
verbose,
|
|
138
|
+
});
|
|
139
|
+
} catch (e: any) {
|
|
140
|
+
if (
|
|
141
|
+
e.code === 'SQLITE_CANTOPEN' &&
|
|
142
|
+
!explicitWrite &&
|
|
143
|
+
!write &&
|
|
144
|
+
!this.config.fileMustExist
|
|
145
|
+
) {
|
|
146
|
+
// This happens when the file doesn't exist and we attempt to open it
|
|
147
|
+
// readonly.
|
|
148
|
+
// First open it in write mode.
|
|
149
|
+
const writeLink = new SQLite3(filename, {
|
|
150
|
+
readonly: false,
|
|
151
|
+
fileMustExist,
|
|
152
|
+
timeout,
|
|
153
|
+
verbose,
|
|
154
|
+
});
|
|
155
|
+
setOptions(writeLink);
|
|
156
|
+
writeLink.close();
|
|
157
|
+
// Now open in readonly.
|
|
158
|
+
link = new SQLite3(filename, {
|
|
159
|
+
readonly: true,
|
|
160
|
+
fileMustExist,
|
|
161
|
+
timeout,
|
|
162
|
+
verbose,
|
|
163
|
+
});
|
|
164
|
+
} else {
|
|
165
|
+
throw e;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
94
168
|
|
|
95
169
|
if (!this.store) {
|
|
170
|
+
if (write) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
'Tried to open in write without opening in read first.',
|
|
173
|
+
);
|
|
174
|
+
}
|
|
96
175
|
this.store = new InternalStore(link);
|
|
176
|
+
} else if (write) {
|
|
177
|
+
this.store.linkWrite = link;
|
|
97
178
|
} else {
|
|
98
179
|
this.store.link = link;
|
|
99
180
|
}
|
|
100
181
|
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
|
-
);
|
|
182
|
+
setOptions(link);
|
|
115
183
|
} catch (e: any) {
|
|
116
184
|
if (this.store) {
|
|
117
185
|
this.store.connected = false;
|
|
118
186
|
}
|
|
119
187
|
if (filename === ':memory:') {
|
|
120
188
|
throw new NotConfiguredError(
|
|
121
|
-
"It seems the config hasn't been set up correctly."
|
|
189
|
+
"It seems the config hasn't been set up correctly. Could not connect: " +
|
|
190
|
+
e?.message,
|
|
122
191
|
);
|
|
123
192
|
} else {
|
|
124
193
|
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
125
194
|
}
|
|
126
195
|
}
|
|
127
|
-
|
|
128
|
-
return this.store.connected;
|
|
129
196
|
}
|
|
130
197
|
|
|
131
198
|
/**
|
|
@@ -135,8 +202,16 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
135
202
|
*/
|
|
136
203
|
public async disconnect() {
|
|
137
204
|
if (this.store.connected) {
|
|
138
|
-
this.store.
|
|
205
|
+
if (this.store.linkWrite && !this.config.explicitWrite) {
|
|
206
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
207
|
+
this.store.linkWrite.close();
|
|
208
|
+
this.store.linkWrite = undefined;
|
|
209
|
+
}
|
|
210
|
+
if (this.config.explicitWrite) {
|
|
211
|
+
this.store.link.exec('PRAGMA optimize;');
|
|
212
|
+
}
|
|
139
213
|
this.store.link.close();
|
|
214
|
+
this.store.transactionsStarted = 0;
|
|
140
215
|
this.store.connected = false;
|
|
141
216
|
}
|
|
142
217
|
return this.store.connected;
|
|
@@ -155,15 +230,346 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
155
230
|
return this.store.connected;
|
|
156
231
|
}
|
|
157
232
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
233
|
+
private createEntitiesTable(etype: string) {
|
|
234
|
+
// Create the entity table.
|
|
235
|
+
this.queryRun(
|
|
236
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
237
|
+
`${this.prefix}entities_${etype}`,
|
|
238
|
+
)} ("guid" CHARACTER(24) PRIMARY KEY, "tags" TEXT, "cdate" REAL NOT NULL, "mdate" REAL NOT NULL, "user" CHARACTER(24), "group" CHARACTER(24), "acUser" INT(1), "acGroup" INT(1), "acOther" INT(1), "acRead" TEXT, "acWrite" TEXT, "acFull" TEXT);`,
|
|
239
|
+
);
|
|
240
|
+
this.queryRun(
|
|
241
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
242
|
+
`${this.prefix}entities_${etype}_id_cdate`,
|
|
243
|
+
)} ON ${SQLite3Driver.escape(
|
|
244
|
+
`${this.prefix}entities_${etype}`,
|
|
245
|
+
)} ("cdate");`,
|
|
246
|
+
);
|
|
247
|
+
this.queryRun(
|
|
248
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
249
|
+
`${this.prefix}entities_${etype}_id_mdate`,
|
|
250
|
+
)} ON ${SQLite3Driver.escape(
|
|
251
|
+
`${this.prefix}entities_${etype}`,
|
|
252
|
+
)} ("mdate");`,
|
|
253
|
+
);
|
|
254
|
+
this.queryRun(
|
|
255
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
256
|
+
`${this.prefix}entities_${etype}_id_tags`,
|
|
257
|
+
)} ON ${SQLite3Driver.escape(
|
|
258
|
+
`${this.prefix}entities_${etype}`,
|
|
259
|
+
)} ("tags");`,
|
|
260
|
+
);
|
|
261
|
+
this.createEntitiesTilmeldIndexes(etype);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private addTilmeldColumnsAndIndexes(etype: string) {
|
|
265
|
+
this.queryRun(
|
|
266
|
+
`ALTER TABLE ${SQLite3Driver.escape(
|
|
267
|
+
`${this.prefix}entities_${etype}`,
|
|
268
|
+
)} ADD COLUMN "user" CHARACTER(24);`,
|
|
269
|
+
);
|
|
270
|
+
this.queryRun(
|
|
271
|
+
`ALTER TABLE ${SQLite3Driver.escape(
|
|
272
|
+
`${this.prefix}entities_${etype}`,
|
|
273
|
+
)} ADD COLUMN "group" CHARACTER(24);`,
|
|
274
|
+
);
|
|
275
|
+
this.queryRun(
|
|
276
|
+
`ALTER TABLE ${SQLite3Driver.escape(
|
|
277
|
+
`${this.prefix}entities_${etype}`,
|
|
278
|
+
)} ADD COLUMN "acUser" INT(1);`,
|
|
279
|
+
);
|
|
280
|
+
this.queryRun(
|
|
281
|
+
`ALTER TABLE ${SQLite3Driver.escape(
|
|
282
|
+
`${this.prefix}entities_${etype}`,
|
|
283
|
+
)} ADD COLUMN "acGroup" INT(1);`,
|
|
284
|
+
);
|
|
285
|
+
this.queryRun(
|
|
286
|
+
`ALTER TABLE ${SQLite3Driver.escape(
|
|
287
|
+
`${this.prefix}entities_${etype}`,
|
|
288
|
+
)} ADD COLUMN "acOther" INT(1);`,
|
|
289
|
+
);
|
|
290
|
+
this.queryRun(
|
|
291
|
+
`ALTER TABLE ${SQLite3Driver.escape(
|
|
292
|
+
`${this.prefix}entities_${etype}`,
|
|
293
|
+
)} ADD COLUMN "acRead" TEXT;`,
|
|
294
|
+
);
|
|
295
|
+
this.queryRun(
|
|
296
|
+
`ALTER TABLE ${SQLite3Driver.escape(
|
|
297
|
+
`${this.prefix}entities_${etype}`,
|
|
298
|
+
)} ADD COLUMN "acWrite" TEXT;`,
|
|
299
|
+
);
|
|
300
|
+
this.queryRun(
|
|
301
|
+
`ALTER TABLE ${SQLite3Driver.escape(
|
|
302
|
+
`${this.prefix}entities_${etype}`,
|
|
303
|
+
)} ADD COLUMN "acFull" TEXT;`,
|
|
304
|
+
);
|
|
305
|
+
this.createEntitiesTilmeldIndexes(etype);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
private createEntitiesTilmeldIndexes(etype: string) {
|
|
309
|
+
this.queryRun(
|
|
310
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
311
|
+
`${this.prefix}entities_${etype}_id_user_acUser`,
|
|
312
|
+
)} ON ${SQLite3Driver.escape(
|
|
313
|
+
`${this.prefix}entities_${etype}`,
|
|
314
|
+
)} ("user", "acUser");`,
|
|
315
|
+
);
|
|
316
|
+
this.queryRun(
|
|
317
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
318
|
+
`${this.prefix}entities_${etype}_id_group_acGroup`,
|
|
319
|
+
)} ON ${SQLite3Driver.escape(
|
|
320
|
+
`${this.prefix}entities_${etype}`,
|
|
321
|
+
)} ("group", "acGroup");`,
|
|
322
|
+
);
|
|
323
|
+
this.queryRun(
|
|
324
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
325
|
+
`${this.prefix}entities_${etype}_id_acUser`,
|
|
326
|
+
)} ON ${SQLite3Driver.escape(
|
|
327
|
+
`${this.prefix}entities_${etype}`,
|
|
328
|
+
)} ("acUser");`,
|
|
329
|
+
);
|
|
330
|
+
this.queryRun(
|
|
331
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
332
|
+
`${this.prefix}entities_${etype}_id_acGroup`,
|
|
333
|
+
)} ON ${SQLite3Driver.escape(
|
|
334
|
+
`${this.prefix}entities_${etype}`,
|
|
335
|
+
)} ("acGroup");`,
|
|
336
|
+
);
|
|
337
|
+
this.queryRun(
|
|
338
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
339
|
+
`${this.prefix}entities_${etype}_id_acOther`,
|
|
340
|
+
)} ON ${SQLite3Driver.escape(
|
|
341
|
+
`${this.prefix}entities_${etype}`,
|
|
342
|
+
)} ("acOther");`,
|
|
343
|
+
);
|
|
344
|
+
this.queryRun(
|
|
345
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
346
|
+
`${this.prefix}entities_${etype}_id_acRead`,
|
|
347
|
+
)} ON ${SQLite3Driver.escape(
|
|
348
|
+
`${this.prefix}entities_${etype}`,
|
|
349
|
+
)} ("acRead");`,
|
|
350
|
+
);
|
|
351
|
+
this.queryRun(
|
|
352
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
353
|
+
`${this.prefix}entities_${etype}_id_acWrite`,
|
|
354
|
+
)} ON ${SQLite3Driver.escape(
|
|
355
|
+
`${this.prefix}entities_${etype}`,
|
|
356
|
+
)} ("acWrite");`,
|
|
357
|
+
);
|
|
358
|
+
this.queryRun(
|
|
359
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
360
|
+
`${this.prefix}entities_${etype}_id_acFull`,
|
|
361
|
+
)} ON ${SQLite3Driver.escape(
|
|
362
|
+
`${this.prefix}entities_${etype}`,
|
|
363
|
+
)} ("acFull");`,
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
private createDataTable(etype: string) {
|
|
368
|
+
// Create the data table.
|
|
369
|
+
this.queryRun(
|
|
370
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
371
|
+
`${this.prefix}data_${etype}`,
|
|
372
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
373
|
+
`${this.prefix}entities_${etype}`,
|
|
374
|
+
)} ("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"));`,
|
|
375
|
+
);
|
|
376
|
+
this.queryRun(
|
|
377
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
378
|
+
`${this.prefix}data_${etype}_id_guid`,
|
|
379
|
+
)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`,
|
|
380
|
+
);
|
|
381
|
+
this.queryRun(
|
|
382
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
383
|
+
`${this.prefix}data_${etype}_id_guid_name`,
|
|
384
|
+
)} ON ${SQLite3Driver.escape(
|
|
385
|
+
`${this.prefix}data_${etype}`,
|
|
386
|
+
)} ("guid", "name");`,
|
|
387
|
+
);
|
|
388
|
+
this.queryRun(
|
|
389
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
390
|
+
`${this.prefix}data_${etype}_id_name`,
|
|
391
|
+
)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`,
|
|
392
|
+
);
|
|
393
|
+
this.queryRun(
|
|
394
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
395
|
+
`${this.prefix}data_${etype}_id_name_string`,
|
|
396
|
+
)} ON ${SQLite3Driver.escape(
|
|
397
|
+
`${this.prefix}data_${etype}`,
|
|
398
|
+
)} ("name", "string");`,
|
|
399
|
+
);
|
|
400
|
+
this.queryRun(
|
|
401
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
402
|
+
`${this.prefix}data_${etype}_id_name_number`,
|
|
403
|
+
)} ON ${SQLite3Driver.escape(
|
|
404
|
+
`${this.prefix}data_${etype}`,
|
|
405
|
+
)} ("name", "number");`,
|
|
406
|
+
);
|
|
407
|
+
this.queryRun(
|
|
408
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
409
|
+
`${this.prefix}data_${etype}_id_guid_name_number`,
|
|
410
|
+
)} ON ${SQLite3Driver.escape(
|
|
411
|
+
`${this.prefix}data_${etype}`,
|
|
412
|
+
)} ("guid", "name", "number");`,
|
|
413
|
+
);
|
|
414
|
+
this.queryRun(
|
|
415
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
416
|
+
`${this.prefix}data_${etype}_id_name_truthy`,
|
|
417
|
+
)} ON ${SQLite3Driver.escape(
|
|
418
|
+
`${this.prefix}data_${etype}`,
|
|
419
|
+
)} ("name", "truthy");`,
|
|
420
|
+
);
|
|
421
|
+
this.queryRun(
|
|
422
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
423
|
+
`${this.prefix}data_${etype}_id_guid_name_truthy`,
|
|
424
|
+
)} ON ${SQLite3Driver.escape(
|
|
425
|
+
`${this.prefix}data_${etype}`,
|
|
426
|
+
)} ("guid", "name", "truthy");`,
|
|
427
|
+
);
|
|
428
|
+
this.queryRun(
|
|
429
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
430
|
+
`${this.prefix}data_${etype}_id_acuserread`,
|
|
431
|
+
)} ON ${SQLite3Driver.escape(
|
|
432
|
+
`${this.prefix}data_${etype}`,
|
|
433
|
+
)} ("guid") WHERE "name"=\'acUser\' AND "number" >= 1;`,
|
|
434
|
+
);
|
|
435
|
+
this.queryRun(
|
|
436
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
437
|
+
`${this.prefix}data_${etype}_id_acgroupread`,
|
|
438
|
+
)} ON ${SQLite3Driver.escape(
|
|
439
|
+
`${this.prefix}data_${etype}`,
|
|
440
|
+
)} ("guid") WHERE "name"=\'acGroup\' AND "number" >= 1;`,
|
|
441
|
+
);
|
|
442
|
+
this.queryRun(
|
|
443
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
444
|
+
`${this.prefix}data_${etype}_id_acotherread`,
|
|
445
|
+
)} ON ${SQLite3Driver.escape(
|
|
446
|
+
`${this.prefix}data_${etype}`,
|
|
447
|
+
)} ("guid") WHERE "name"=\'acOther\' AND "number" >= 1;`,
|
|
448
|
+
);
|
|
449
|
+
this.queryRun(
|
|
450
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
451
|
+
`${this.prefix}data_${etype}_id_acuser`,
|
|
452
|
+
)} ON ${SQLite3Driver.escape(
|
|
453
|
+
`${this.prefix}data_${etype}`,
|
|
454
|
+
)} ("guid") WHERE "name"=\'user\';`,
|
|
455
|
+
);
|
|
456
|
+
this.queryRun(
|
|
457
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
458
|
+
`${this.prefix}data_${etype}_id_acgroup`,
|
|
459
|
+
)} ON ${SQLite3Driver.escape(
|
|
460
|
+
`${this.prefix}data_${etype}`,
|
|
461
|
+
)} ("guid") WHERE "name"=\'group\';`,
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
private createReferencesTable(etype: string) {
|
|
466
|
+
// Create the references table.
|
|
467
|
+
this.queryRun(
|
|
468
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
469
|
+
`${this.prefix}references_${etype}`,
|
|
470
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
471
|
+
`${this.prefix}entities_${etype}`,
|
|
472
|
+
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "reference" CHARACTER(24) NOT NULL, PRIMARY KEY("guid", "name", "reference"));`,
|
|
473
|
+
);
|
|
474
|
+
this.queryRun(
|
|
475
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
476
|
+
`${this.prefix}references_${etype}_id_guid`,
|
|
477
|
+
)} ON ${SQLite3Driver.escape(
|
|
478
|
+
`${this.prefix}references_${etype}`,
|
|
479
|
+
)} ("guid");`,
|
|
480
|
+
);
|
|
481
|
+
this.queryRun(
|
|
482
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
483
|
+
`${this.prefix}references_${etype}_id_name`,
|
|
484
|
+
)} ON ${SQLite3Driver.escape(
|
|
485
|
+
`${this.prefix}references_${etype}`,
|
|
486
|
+
)} ("name");`,
|
|
487
|
+
);
|
|
488
|
+
this.queryRun(
|
|
489
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
490
|
+
`${this.prefix}references_${etype}_id_name_reference`,
|
|
491
|
+
)} ON ${SQLite3Driver.escape(
|
|
492
|
+
`${this.prefix}references_${etype}`,
|
|
493
|
+
)} ("name", "reference");`,
|
|
494
|
+
);
|
|
495
|
+
this.queryRun(
|
|
496
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
497
|
+
`${this.prefix}references_${etype}_id_reference`,
|
|
498
|
+
)} ON ${SQLite3Driver.escape(
|
|
499
|
+
`${this.prefix}references_${etype}`,
|
|
500
|
+
)} ("reference");`,
|
|
501
|
+
);
|
|
502
|
+
this.queryRun(
|
|
503
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
504
|
+
`${this.prefix}references_${etype}_id_guid_name`,
|
|
505
|
+
)} ON ${SQLite3Driver.escape(
|
|
506
|
+
`${this.prefix}references_${etype}`,
|
|
507
|
+
)} ("guid", "name");`,
|
|
508
|
+
);
|
|
509
|
+
this.queryRun(
|
|
510
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
511
|
+
`${this.prefix}references_${etype}_id_guid_name_reference`,
|
|
512
|
+
)} ON ${SQLite3Driver.escape(
|
|
513
|
+
`${this.prefix}references_${etype}`,
|
|
514
|
+
)} ("guid", "name", "reference");`,
|
|
515
|
+
);
|
|
516
|
+
this.queryRun(
|
|
517
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
518
|
+
`${this.prefix}references_${etype}_id_reference_name_guid`,
|
|
519
|
+
)} ON ${SQLite3Driver.escape(
|
|
520
|
+
`${this.prefix}references_${etype}`,
|
|
521
|
+
)} ("reference", "name", "guid");`,
|
|
522
|
+
);
|
|
523
|
+
this.queryRun(
|
|
524
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
525
|
+
`${this.prefix}references_${etype}_id_reference_guid_name`,
|
|
526
|
+
)} ON ${SQLite3Driver.escape(
|
|
527
|
+
`${this.prefix}references_${etype}`,
|
|
528
|
+
)} ("reference", "guid", "name");`,
|
|
529
|
+
);
|
|
530
|
+
this.queryRun(
|
|
531
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
532
|
+
`${this.prefix}references_${etype}_id_reference_guid_nameuser`,
|
|
533
|
+
)} ON ${SQLite3Driver.escape(
|
|
534
|
+
`${this.prefix}references_${etype}`,
|
|
535
|
+
)} ("reference", "guid") WHERE "name"=\'user\';`,
|
|
536
|
+
);
|
|
537
|
+
this.queryRun(
|
|
538
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
539
|
+
`${this.prefix}references_${etype}_id_reference_guid_namegroup`,
|
|
540
|
+
)} ON ${SQLite3Driver.escape(
|
|
541
|
+
`${this.prefix}references_${etype}`,
|
|
542
|
+
)} ("reference", "guid") WHERE "name"=\'group\';`,
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
private createTokensTable(etype: string) {
|
|
547
|
+
// Create the tokens table.
|
|
548
|
+
this.queryRun(
|
|
549
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
550
|
+
`${this.prefix}tokens_${etype}`,
|
|
551
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
552
|
+
`${this.prefix}entities_${etype}`,
|
|
553
|
+
)} ("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"));`,
|
|
554
|
+
);
|
|
555
|
+
this.queryRun(
|
|
556
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
557
|
+
`${this.prefix}tokens_${etype}_id_name_token`,
|
|
558
|
+
)} ON ${SQLite3Driver.escape(
|
|
559
|
+
`${this.prefix}tokens_${etype}`,
|
|
560
|
+
)} ("name", "token");`,
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
private createUniquesTable(etype: string) {
|
|
565
|
+
// Create the unique strings table.
|
|
566
|
+
this.queryRun(
|
|
567
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
568
|
+
`${this.prefix}uniques_${etype}`,
|
|
569
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
570
|
+
`${this.prefix}entities_${etype}`,
|
|
571
|
+
)} ("guid") ON DELETE CASCADE, "unique" TEXT NOT NULL UNIQUE, PRIMARY KEY("guid", "unique"));`,
|
|
572
|
+
);
|
|
167
573
|
}
|
|
168
574
|
|
|
169
575
|
/**
|
|
@@ -172,160 +578,38 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
172
578
|
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
173
579
|
*/
|
|
174
580
|
private createTables(etype: string | null = null) {
|
|
175
|
-
this.checkReadOnlyMode();
|
|
176
581
|
this.startTransaction('nymph-tablecreation');
|
|
177
582
|
try {
|
|
178
583
|
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
|
-
);
|
|
584
|
+
this.createEntitiesTable(etype);
|
|
585
|
+
this.createDataTable(etype);
|
|
586
|
+
this.createReferencesTable(etype);
|
|
587
|
+
this.createTokensTable(etype);
|
|
588
|
+
this.createUniquesTable(etype);
|
|
307
589
|
} else {
|
|
308
590
|
// Create the UID table.
|
|
309
591
|
this.queryRun(
|
|
310
592
|
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
311
|
-
`${this.prefix}uids
|
|
312
|
-
)} ("name" TEXT PRIMARY KEY NOT NULL, "cur_uid" INTEGER NOT NULL)
|
|
593
|
+
`${this.prefix}uids`,
|
|
594
|
+
)} ("name" TEXT PRIMARY KEY NOT NULL, "cur_uid" INTEGER NOT NULL);`,
|
|
313
595
|
);
|
|
314
596
|
}
|
|
315
|
-
this.commit('nymph-tablecreation');
|
|
316
|
-
return true;
|
|
317
597
|
} catch (e: any) {
|
|
318
598
|
this.rollback('nymph-tablecreation');
|
|
319
599
|
throw e;
|
|
320
600
|
}
|
|
601
|
+
|
|
602
|
+
this.commit('nymph-tablecreation');
|
|
603
|
+
return true;
|
|
321
604
|
}
|
|
322
605
|
|
|
323
606
|
private query<T extends () => any>(
|
|
324
607
|
runQuery: T,
|
|
325
608
|
query: string,
|
|
326
|
-
etypes: string[] = []
|
|
609
|
+
etypes: string[] = [],
|
|
327
610
|
): ReturnType<T> {
|
|
328
611
|
try {
|
|
612
|
+
this.nymph.config.debugInfo('sqlite3:query', query);
|
|
329
613
|
return runQuery();
|
|
330
614
|
} catch (e: any) {
|
|
331
615
|
const errorCode = e?.code;
|
|
@@ -343,29 +627,39 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
343
627
|
} catch (e2: any) {
|
|
344
628
|
throw new QueryFailedError(
|
|
345
629
|
'Query failed: ' + e2?.code + ' - ' + e2?.message,
|
|
346
|
-
query
|
|
630
|
+
query,
|
|
631
|
+
e2?.code,
|
|
347
632
|
);
|
|
348
633
|
}
|
|
634
|
+
} else if (
|
|
635
|
+
errorCode === 'SQLITE_CONSTRAINT_UNIQUE' &&
|
|
636
|
+
errorMsg.match(/^UNIQUE constraint failed: /)
|
|
637
|
+
) {
|
|
638
|
+
throw new EntityUniqueConstraintError(`Unique constraint violation.`);
|
|
349
639
|
} else {
|
|
350
640
|
throw new QueryFailedError(
|
|
351
641
|
'Query failed: ' + e?.code + ' - ' + e?.message,
|
|
352
|
-
query
|
|
642
|
+
query,
|
|
643
|
+
e?.code,
|
|
353
644
|
);
|
|
354
645
|
}
|
|
355
646
|
}
|
|
356
647
|
}
|
|
357
648
|
|
|
358
|
-
private
|
|
649
|
+
private queryArray(
|
|
359
650
|
query: string,
|
|
360
651
|
{
|
|
361
652
|
etypes = [],
|
|
362
653
|
params = {},
|
|
363
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
654
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
364
655
|
) {
|
|
365
656
|
return this.query(
|
|
366
|
-
() =>
|
|
657
|
+
() =>
|
|
658
|
+
(this.store.linkWrite || this.store.link)
|
|
659
|
+
.prepare(query)
|
|
660
|
+
.iterate(params),
|
|
367
661
|
`${query} -- ${JSON.stringify(params)}`,
|
|
368
|
-
etypes
|
|
662
|
+
etypes,
|
|
369
663
|
);
|
|
370
664
|
}
|
|
371
665
|
|
|
@@ -374,12 +668,13 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
374
668
|
{
|
|
375
669
|
etypes = [],
|
|
376
670
|
params = {},
|
|
377
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
671
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
378
672
|
) {
|
|
379
673
|
return this.query(
|
|
380
|
-
() =>
|
|
674
|
+
() =>
|
|
675
|
+
(this.store.linkWrite || this.store.link).prepare(query).get(params),
|
|
381
676
|
`${query} -- ${JSON.stringify(params)}`,
|
|
382
|
-
etypes
|
|
677
|
+
etypes,
|
|
383
678
|
);
|
|
384
679
|
}
|
|
385
680
|
|
|
@@ -388,19 +683,20 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
388
683
|
{
|
|
389
684
|
etypes = [],
|
|
390
685
|
params = {},
|
|
391
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
686
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
392
687
|
) {
|
|
393
688
|
return this.query(
|
|
394
|
-
() =>
|
|
689
|
+
() =>
|
|
690
|
+
(this.store.linkWrite || this.store.link).prepare(query).run(params),
|
|
395
691
|
`${query} -- ${JSON.stringify(params)}`,
|
|
396
|
-
etypes
|
|
692
|
+
etypes,
|
|
397
693
|
);
|
|
398
694
|
}
|
|
399
695
|
|
|
400
696
|
public async commit(name: string) {
|
|
401
697
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
402
698
|
throw new InvalidParametersError(
|
|
403
|
-
'Transaction commit attempted without a name.'
|
|
699
|
+
'Transaction commit attempted without a name.',
|
|
404
700
|
);
|
|
405
701
|
}
|
|
406
702
|
if (this.store.transactionsStarted === 0) {
|
|
@@ -408,12 +704,23 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
408
704
|
}
|
|
409
705
|
this.queryRun(`RELEASE SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
410
706
|
this.store.transactionsStarted--;
|
|
707
|
+
|
|
708
|
+
if (
|
|
709
|
+
this.store.transactionsStarted === 0 &&
|
|
710
|
+
this.store.linkWrite &&
|
|
711
|
+
!this.config.explicitWrite
|
|
712
|
+
) {
|
|
713
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
714
|
+
this.store.linkWrite.close();
|
|
715
|
+
this.store.linkWrite = undefined;
|
|
716
|
+
}
|
|
717
|
+
|
|
411
718
|
return true;
|
|
412
719
|
}
|
|
413
720
|
|
|
414
721
|
public async deleteEntityByID(
|
|
415
722
|
guid: string,
|
|
416
|
-
className?: EntityConstructor | string | null
|
|
723
|
+
className?: EntityConstructor | string | null,
|
|
417
724
|
) {
|
|
418
725
|
let EntityClass: EntityConstructor;
|
|
419
726
|
if (typeof className === 'string' || className == null) {
|
|
@@ -423,168 +730,408 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
423
730
|
EntityClass = className;
|
|
424
731
|
}
|
|
425
732
|
const etype = EntityClass.ETYPE;
|
|
426
|
-
this.checkReadOnlyMode();
|
|
427
733
|
await this.startTransaction('nymph-delete');
|
|
428
734
|
try {
|
|
429
735
|
this.queryRun(
|
|
430
736
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
431
|
-
`${this.prefix}entities_${etype}
|
|
737
|
+
`${this.prefix}entities_${etype}`,
|
|
432
738
|
)} WHERE "guid"=@guid;`,
|
|
433
739
|
{
|
|
434
740
|
etypes: [etype],
|
|
435
741
|
params: {
|
|
436
742
|
guid,
|
|
437
743
|
},
|
|
438
|
-
}
|
|
744
|
+
},
|
|
439
745
|
);
|
|
440
746
|
this.queryRun(
|
|
441
747
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
442
|
-
`${this.prefix}data_${etype}
|
|
748
|
+
`${this.prefix}data_${etype}`,
|
|
443
749
|
)} WHERE "guid"=@guid;`,
|
|
444
750
|
{
|
|
445
751
|
etypes: [etype],
|
|
446
752
|
params: {
|
|
447
753
|
guid,
|
|
448
754
|
},
|
|
449
|
-
}
|
|
755
|
+
},
|
|
450
756
|
);
|
|
451
757
|
this.queryRun(
|
|
452
758
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
453
|
-
`${this.prefix}
|
|
759
|
+
`${this.prefix}references_${etype}`,
|
|
454
760
|
)} WHERE "guid"=@guid;`,
|
|
455
761
|
{
|
|
456
762
|
etypes: [etype],
|
|
457
763
|
params: {
|
|
458
764
|
guid,
|
|
459
765
|
},
|
|
460
|
-
}
|
|
766
|
+
},
|
|
461
767
|
);
|
|
462
768
|
this.queryRun(
|
|
463
769
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
464
|
-
`${this.prefix}
|
|
770
|
+
`${this.prefix}tokens_${etype}`,
|
|
465
771
|
)} WHERE "guid"=@guid;`,
|
|
466
772
|
{
|
|
467
773
|
etypes: [etype],
|
|
468
774
|
params: {
|
|
469
775
|
guid,
|
|
470
776
|
},
|
|
471
|
-
}
|
|
777
|
+
},
|
|
778
|
+
);
|
|
779
|
+
this.queryRun(
|
|
780
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
781
|
+
`${this.prefix}uniques_${etype}`,
|
|
782
|
+
)} WHERE "guid"=@guid;`,
|
|
783
|
+
{
|
|
784
|
+
etypes: [etype],
|
|
785
|
+
params: {
|
|
786
|
+
guid,
|
|
787
|
+
},
|
|
788
|
+
},
|
|
472
789
|
);
|
|
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
790
|
} catch (e: any) {
|
|
791
|
+
this.nymph.config.debugError('sqlite3', `Delete entity error: "${e}"`);
|
|
480
792
|
await this.rollback('nymph-delete');
|
|
481
793
|
throw e;
|
|
482
794
|
}
|
|
795
|
+
|
|
796
|
+
await this.commit('nymph-delete');
|
|
797
|
+
// Remove any cached versions of this entity.
|
|
798
|
+
if (this.nymph.config.cache) {
|
|
799
|
+
this.cleanCache(guid);
|
|
800
|
+
}
|
|
801
|
+
return true;
|
|
483
802
|
}
|
|
484
803
|
|
|
485
804
|
public async deleteUID(name: string) {
|
|
486
805
|
if (!name) {
|
|
487
806
|
throw new InvalidParametersError('Name not given for UID');
|
|
488
807
|
}
|
|
489
|
-
this.
|
|
808
|
+
await this.startTransaction('nymph-delete-uid');
|
|
490
809
|
this.queryRun(
|
|
491
810
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
492
|
-
`${this.prefix}uids
|
|
811
|
+
`${this.prefix}uids`,
|
|
493
812
|
)} WHERE "name"=@name;`,
|
|
494
813
|
{
|
|
495
814
|
params: {
|
|
496
815
|
name,
|
|
497
816
|
},
|
|
498
|
-
}
|
|
817
|
+
},
|
|
499
818
|
);
|
|
819
|
+
await this.commit('nymph-delete-uid');
|
|
500
820
|
return true;
|
|
501
821
|
}
|
|
502
822
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
writeLine('');
|
|
510
|
-
|
|
511
|
-
writeLine('#');
|
|
512
|
-
writeLine('# UIDs');
|
|
513
|
-
writeLine('#');
|
|
514
|
-
writeLine('');
|
|
515
|
-
|
|
516
|
-
// Export UIDs.
|
|
517
|
-
let uids = this.queryIter(
|
|
518
|
-
`SELECT * FROM ${SQLite3Driver.escape(
|
|
519
|
-
`${this.prefix}uids`
|
|
520
|
-
)} ORDER BY "name";`
|
|
521
|
-
);
|
|
522
|
-
for (const uid of uids) {
|
|
523
|
-
writeLine(`<${uid.name}>[${uid.cur_uid}]`);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
writeLine('');
|
|
527
|
-
writeLine('#');
|
|
528
|
-
writeLine('# Entities');
|
|
529
|
-
writeLine('#');
|
|
530
|
-
writeLine('');
|
|
531
|
-
|
|
532
|
-
// Get the etypes.
|
|
533
|
-
const tables = this.queryIter(
|
|
534
|
-
"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name;"
|
|
535
|
-
);
|
|
536
|
-
const etypes = [];
|
|
537
|
-
for (const table of tables) {
|
|
538
|
-
if (table.name.startsWith(this.prefix + 'entities_')) {
|
|
539
|
-
etypes.push(table.name.substr((this.prefix + 'entities_').length));
|
|
540
|
-
}
|
|
541
|
-
}
|
|
823
|
+
public async getIndexes(etype: string) {
|
|
824
|
+
const indexes: {
|
|
825
|
+
scope: 'data' | 'references' | 'tokens';
|
|
826
|
+
name: string;
|
|
827
|
+
property: string;
|
|
828
|
+
}[] = [];
|
|
542
829
|
|
|
543
|
-
for (
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
: datum.value.dvalue;
|
|
573
|
-
writeLine(`\t${datum.value.dname}=${value}`);
|
|
574
|
-
datum = dataIterator.next();
|
|
575
|
-
} while (!datum.done && datum.value.guid === guid);
|
|
576
|
-
} else {
|
|
577
|
-
// Make sure that datum is incremented :)
|
|
578
|
-
datum = dataIterator.next();
|
|
579
|
-
}
|
|
830
|
+
for (let [scope, suffix] of [
|
|
831
|
+
['data', '_json'],
|
|
832
|
+
['references', '_reference_guid'],
|
|
833
|
+
['tokens', '_token_position_stem'],
|
|
834
|
+
] as (
|
|
835
|
+
| ['data', '_json']
|
|
836
|
+
| ['references', '_reference_guid']
|
|
837
|
+
| ['tokens', '_token_position_stem']
|
|
838
|
+
)[]) {
|
|
839
|
+
const indexDefinitions: IterableIterator<any> = this.queryArray(
|
|
840
|
+
`SELECT "name", "sql" FROM "sqlite_master" WHERE "type"='index' AND "name" LIKE @pattern;`,
|
|
841
|
+
{
|
|
842
|
+
params: {
|
|
843
|
+
pattern: `${this.prefix}${scope}_${etype}_id_custom_%${suffix}`,
|
|
844
|
+
},
|
|
845
|
+
},
|
|
846
|
+
);
|
|
847
|
+
for (const indexDefinition of indexDefinitions) {
|
|
848
|
+
indexes.push({
|
|
849
|
+
scope,
|
|
850
|
+
name: (indexDefinition.name as string).substring(
|
|
851
|
+
`${this.prefix}${scope}_${etype}_id_custom_`.length,
|
|
852
|
+
indexDefinition.name.length - suffix.length,
|
|
853
|
+
),
|
|
854
|
+
property:
|
|
855
|
+
((indexDefinition.sql as string).match(
|
|
856
|
+
/WHERE\s+"name"\s*=\s*'(.*)'/,
|
|
857
|
+
) ?? [])[1] ?? '',
|
|
858
|
+
});
|
|
580
859
|
}
|
|
581
860
|
}
|
|
582
861
|
|
|
583
|
-
return;
|
|
862
|
+
return indexes;
|
|
584
863
|
}
|
|
585
864
|
|
|
586
|
-
|
|
587
|
-
|
|
865
|
+
public async addIndex(
|
|
866
|
+
etype: string,
|
|
867
|
+
definition: {
|
|
868
|
+
scope: 'data' | 'references' | 'tokens';
|
|
869
|
+
name: string;
|
|
870
|
+
property: string;
|
|
871
|
+
},
|
|
872
|
+
) {
|
|
873
|
+
this.checkIndexName(definition.name);
|
|
874
|
+
await this.deleteIndex(etype, definition.scope, definition.name);
|
|
875
|
+
if (definition.scope === 'data') {
|
|
876
|
+
this.queryRun(
|
|
877
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
878
|
+
`${this.prefix}data_${etype}_id_custom_${definition.name}_json`,
|
|
879
|
+
)} ON ${SQLite3Driver.escape(
|
|
880
|
+
`${this.prefix}data_${etype}`,
|
|
881
|
+
)} ("json") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`,
|
|
882
|
+
);
|
|
883
|
+
this.queryRun(
|
|
884
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
885
|
+
`${this.prefix}data_${etype}_id_custom_${definition.name}_string`,
|
|
886
|
+
)} ON ${SQLite3Driver.escape(
|
|
887
|
+
`${this.prefix}data_${etype}`,
|
|
888
|
+
)} ("string") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`,
|
|
889
|
+
);
|
|
890
|
+
this.queryRun(
|
|
891
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
892
|
+
`${this.prefix}data_${etype}_id_custom_${definition.name}_number`,
|
|
893
|
+
)} ON ${SQLite3Driver.escape(
|
|
894
|
+
`${this.prefix}data_${etype}`,
|
|
895
|
+
)} ("number") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`,
|
|
896
|
+
);
|
|
897
|
+
this.queryRun(
|
|
898
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
899
|
+
`${this.prefix}data_${etype}_id_custom_${definition.name}_truthy`,
|
|
900
|
+
)} ON ${SQLite3Driver.escape(
|
|
901
|
+
`${this.prefix}data_${etype}`,
|
|
902
|
+
)} ("truthy") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`,
|
|
903
|
+
);
|
|
904
|
+
} else if (definition.scope === 'references') {
|
|
905
|
+
this.queryRun(
|
|
906
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
907
|
+
`${this.prefix}references_${etype}_id_custom_${definition.name}_reference_guid`,
|
|
908
|
+
)} ON ${SQLite3Driver.escape(
|
|
909
|
+
`${this.prefix}references_${etype}`,
|
|
910
|
+
)} ("reference", "guid") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`,
|
|
911
|
+
);
|
|
912
|
+
} else if (definition.scope === 'tokens') {
|
|
913
|
+
this.queryRun(
|
|
914
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
915
|
+
`${this.prefix}tokens_${etype}_id_custom_${definition.name}_token_position_stem`,
|
|
916
|
+
)} ON ${SQLite3Driver.escape(
|
|
917
|
+
`${this.prefix}tokens_${etype}`,
|
|
918
|
+
)} ("token", "position", "stem") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`,
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
return true;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
public async deleteIndex(
|
|
925
|
+
etype: string,
|
|
926
|
+
scope: 'data' | 'references' | 'tokens',
|
|
927
|
+
name: string,
|
|
928
|
+
) {
|
|
929
|
+
this.checkIndexName(name);
|
|
930
|
+
if (scope === 'data') {
|
|
931
|
+
this.queryRun(
|
|
932
|
+
`DROP INDEX IF EXISTS ${SQLite3Driver.escape(
|
|
933
|
+
`${this.prefix}data_${etype}_id_custom_${name}_json`,
|
|
934
|
+
)};`,
|
|
935
|
+
);
|
|
936
|
+
this.queryRun(
|
|
937
|
+
`DROP INDEX IF EXISTS ${SQLite3Driver.escape(
|
|
938
|
+
`${this.prefix}data_${etype}_id_custom_${name}_string`,
|
|
939
|
+
)};`,
|
|
940
|
+
);
|
|
941
|
+
this.queryRun(
|
|
942
|
+
`DROP INDEX IF EXISTS ${SQLite3Driver.escape(
|
|
943
|
+
`${this.prefix}data_${etype}_id_custom_${name}_number`,
|
|
944
|
+
)};`,
|
|
945
|
+
);
|
|
946
|
+
this.queryRun(
|
|
947
|
+
`DROP INDEX IF EXISTS ${SQLite3Driver.escape(
|
|
948
|
+
`${this.prefix}data_${etype}_id_custom_${name}_truthy`,
|
|
949
|
+
)};`,
|
|
950
|
+
);
|
|
951
|
+
} else if (scope === 'references') {
|
|
952
|
+
this.queryRun(
|
|
953
|
+
`DROP INDEX IF EXISTS ${SQLite3Driver.escape(
|
|
954
|
+
`${this.prefix}references_${etype}_id_custom_${name}_reference_guid`,
|
|
955
|
+
)};`,
|
|
956
|
+
);
|
|
957
|
+
} else if (scope === 'tokens') {
|
|
958
|
+
this.queryRun(
|
|
959
|
+
`DROP INDEX IF EXISTS ${SQLite3Driver.escape(
|
|
960
|
+
`${this.prefix}tokens_${etype}_id_custom_${name}_token_position_stem`,
|
|
961
|
+
)};`,
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
return true;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
public async getEtypes() {
|
|
968
|
+
const tables: IterableIterator<any> = this.queryArray(
|
|
969
|
+
"SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix;",
|
|
970
|
+
{
|
|
971
|
+
params: {
|
|
972
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
973
|
+
},
|
|
974
|
+
},
|
|
975
|
+
);
|
|
976
|
+
const etypes: string[] = [];
|
|
977
|
+
for (const table of tables) {
|
|
978
|
+
etypes.push(table.name.substr((this.prefix + 'entities_').length));
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
return etypes;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
public async *exportDataIterator(): AsyncGenerator<
|
|
985
|
+
{ type: 'comment' | 'uid' | 'entity'; content: string },
|
|
986
|
+
void,
|
|
987
|
+
false | undefined
|
|
988
|
+
> {
|
|
989
|
+
if (
|
|
990
|
+
yield {
|
|
991
|
+
type: 'comment',
|
|
992
|
+
content: `#nex2
|
|
993
|
+
# Nymph Entity Exchange v2
|
|
994
|
+
# http://nymph.io
|
|
995
|
+
#
|
|
996
|
+
# Generation Time: ${new Date().toLocaleString()}
|
|
997
|
+
`,
|
|
998
|
+
}
|
|
999
|
+
) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
if (
|
|
1004
|
+
yield {
|
|
1005
|
+
type: 'comment',
|
|
1006
|
+
content: `
|
|
1007
|
+
|
|
1008
|
+
#
|
|
1009
|
+
# UIDs
|
|
1010
|
+
#
|
|
1011
|
+
|
|
1012
|
+
`,
|
|
1013
|
+
}
|
|
1014
|
+
) {
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// Export UIDs.
|
|
1019
|
+
let uids: IterableIterator<any> = this.queryArray(
|
|
1020
|
+
`SELECT * FROM ${SQLite3Driver.escape(
|
|
1021
|
+
`${this.prefix}uids`,
|
|
1022
|
+
)} ORDER BY "name";`,
|
|
1023
|
+
);
|
|
1024
|
+
for (const uid of uids) {
|
|
1025
|
+
if (yield { type: 'uid', content: `<${uid.name}>[${uid.cur_uid}]\n` }) {
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
if (
|
|
1031
|
+
yield {
|
|
1032
|
+
type: 'comment',
|
|
1033
|
+
content: `
|
|
1034
|
+
|
|
1035
|
+
#
|
|
1036
|
+
# Entities
|
|
1037
|
+
#
|
|
1038
|
+
|
|
1039
|
+
`,
|
|
1040
|
+
}
|
|
1041
|
+
) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// Get the etypes.
|
|
1046
|
+
const etypes = await this.getEtypes();
|
|
1047
|
+
|
|
1048
|
+
for (const etype of etypes) {
|
|
1049
|
+
// Export entities.
|
|
1050
|
+
const dataIterator: IterableIterator<any> = this.queryArray(
|
|
1051
|
+
`SELECT e."guid", e."tags", e."cdate", e."mdate", e."user", e."group", e."acUser", e."acGroup", e."acOther", e."acRead", e."acWrite", e."acFull", d."name", d."value", json(d."json") as "json", d."string", d."number" FROM ${SQLite3Driver.escape(
|
|
1052
|
+
`${this.prefix}entities_${etype}`,
|
|
1053
|
+
)} e LEFT JOIN ${SQLite3Driver.escape(
|
|
1054
|
+
`${this.prefix}data_${etype}`,
|
|
1055
|
+
)} d USING ("guid") ORDER BY e."guid";`,
|
|
1056
|
+
)[Symbol.iterator]();
|
|
1057
|
+
let datum = dataIterator.next();
|
|
1058
|
+
while (!datum.done) {
|
|
1059
|
+
const guid = datum.value.guid;
|
|
1060
|
+
const tags = datum.value.tags.slice(1, -1);
|
|
1061
|
+
const cdate = datum.value.cdate;
|
|
1062
|
+
const mdate = datum.value.mdate;
|
|
1063
|
+
const user = datum.value.user;
|
|
1064
|
+
const group = datum.value.group;
|
|
1065
|
+
const acUser = datum.value.acUser;
|
|
1066
|
+
const acGroup = datum.value.acGroup;
|
|
1067
|
+
const acOther = datum.value.acOther;
|
|
1068
|
+
const acRead = datum.value.acRead?.slice(1, -1).split(',');
|
|
1069
|
+
const acWrite = datum.value.acWrite?.slice(1, -1).split(',');
|
|
1070
|
+
const acFull = datum.value.acFull?.slice(1, -1).split(',');
|
|
1071
|
+
let currentEntityExport: string[] = [];
|
|
1072
|
+
currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
|
|
1073
|
+
currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
|
|
1074
|
+
currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
|
|
1075
|
+
if (this.nymph.tilmeld != null) {
|
|
1076
|
+
if (user != null) {
|
|
1077
|
+
currentEntityExport.push(
|
|
1078
|
+
`\tuser=${JSON.stringify(['nymph_entity_reference', user, 'User'])}`,
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
if (group != null) {
|
|
1082
|
+
currentEntityExport.push(
|
|
1083
|
+
`\tgroup=${JSON.stringify(['nymph_entity_reference', group, 'Group'])}`,
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
if (acUser != null) {
|
|
1087
|
+
currentEntityExport.push(`\tacUser=${JSON.stringify(acUser)}`);
|
|
1088
|
+
}
|
|
1089
|
+
if (acGroup != null) {
|
|
1090
|
+
currentEntityExport.push(`\tacGroup=${JSON.stringify(acGroup)}`);
|
|
1091
|
+
}
|
|
1092
|
+
if (acOther != null) {
|
|
1093
|
+
currentEntityExport.push(`\tacOther=${JSON.stringify(acOther)}`);
|
|
1094
|
+
}
|
|
1095
|
+
if (acRead != null) {
|
|
1096
|
+
currentEntityExport.push(`\tacRead=${JSON.stringify(acRead)}`);
|
|
1097
|
+
}
|
|
1098
|
+
if (acWrite != null) {
|
|
1099
|
+
currentEntityExport.push(`\tacWrite=${JSON.stringify(acWrite)}`);
|
|
1100
|
+
}
|
|
1101
|
+
if (acFull != null) {
|
|
1102
|
+
currentEntityExport.push(`\tacFull=${JSON.stringify(acFull)}`);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
if (datum.value.name != null) {
|
|
1106
|
+
// This do will keep going and adding the data until the
|
|
1107
|
+
// next entity is reached. datum will end on the next entity.
|
|
1108
|
+
do {
|
|
1109
|
+
const value =
|
|
1110
|
+
datum.value.value === 'N'
|
|
1111
|
+
? JSON.stringify(datum.value.number)
|
|
1112
|
+
: datum.value.value === 'S'
|
|
1113
|
+
? JSON.stringify(datum.value.string)
|
|
1114
|
+
: datum.value.value === 'J'
|
|
1115
|
+
? datum.value.json
|
|
1116
|
+
: datum.value.value;
|
|
1117
|
+
currentEntityExport.push(`\t${datum.value.name}=${value}`);
|
|
1118
|
+
datum = dataIterator.next();
|
|
1119
|
+
} while (!datum.done && datum.value.guid === guid);
|
|
1120
|
+
} else {
|
|
1121
|
+
// Make sure that datum is incremented :)
|
|
1122
|
+
datum = dataIterator.next();
|
|
1123
|
+
}
|
|
1124
|
+
currentEntityExport.push('');
|
|
1125
|
+
|
|
1126
|
+
if (yield { type: 'entity', content: currentEntityExport.join('\n') }) {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* Generate the SQLite3 query.
|
|
588
1135
|
* @param options The options array.
|
|
589
1136
|
* @param formattedSelectors The formatted selector array.
|
|
590
1137
|
* @param etype
|
|
@@ -601,20 +1148,21 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
601
1148
|
params: { [k: string]: any } = {},
|
|
602
1149
|
subquery = false,
|
|
603
1150
|
tableSuffix = '',
|
|
604
|
-
etypes: string[] = []
|
|
1151
|
+
etypes: string[] = [],
|
|
1152
|
+
guidSelector: string | undefined = undefined,
|
|
605
1153
|
) {
|
|
606
1154
|
if (typeof options.class?.alterOptions === 'function') {
|
|
607
1155
|
options = options.class.alterOptions(options);
|
|
608
1156
|
}
|
|
609
1157
|
const eTable = `e${tableSuffix}`;
|
|
610
1158
|
const dTable = `d${tableSuffix}`;
|
|
611
|
-
const cTable = `c${tableSuffix}`;
|
|
612
1159
|
const fTable = `f${tableSuffix}`;
|
|
613
1160
|
const ieTable = `ie${tableSuffix}`;
|
|
614
|
-
const
|
|
1161
|
+
const sTable = `s${tableSuffix}`;
|
|
1162
|
+
const sort = options.sort === undefined ? 'cdate' : options.sort;
|
|
615
1163
|
const queryParts = this.iterateSelectorsForQuery(
|
|
616
1164
|
formattedSelectors,
|
|
617
|
-
(key, value, typeIsOr, typeIsNot) => {
|
|
1165
|
+
({ key, value, typeIsOr, typeIsNot }) => {
|
|
618
1166
|
const clauseNot = key.startsWith('!');
|
|
619
1167
|
let curQuery = '';
|
|
620
1168
|
for (const curValue of value) {
|
|
@@ -662,17 +1210,39 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
662
1210
|
if (curQuery) {
|
|
663
1211
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
664
1212
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
1213
|
+
if (
|
|
1214
|
+
curVar === 'cdate' ||
|
|
1215
|
+
curVar === 'mdate' ||
|
|
1216
|
+
(this.nymph.tilmeld != null &&
|
|
1217
|
+
(curVar === 'user' ||
|
|
1218
|
+
curVar === 'group' ||
|
|
1219
|
+
curVar === 'acUser' ||
|
|
1220
|
+
curVar === 'acGroup' ||
|
|
1221
|
+
curVar === 'acOther' ||
|
|
1222
|
+
curVar === 'acRead' ||
|
|
1223
|
+
curVar === 'acWrite' ||
|
|
1224
|
+
curVar === 'acFull'))
|
|
1225
|
+
) {
|
|
1226
|
+
curQuery +=
|
|
1227
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1228
|
+
'(' +
|
|
1229
|
+
ieTable +
|
|
1230
|
+
'.' +
|
|
1231
|
+
SQLite3Driver.escape(curVar) +
|
|
1232
|
+
' IS NOT NULL)';
|
|
1233
|
+
} else {
|
|
1234
|
+
const name = `param${++count.i}`;
|
|
1235
|
+
curQuery +=
|
|
1236
|
+
ieTable +
|
|
1237
|
+
'."guid" ' +
|
|
1238
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1239
|
+
'IN (SELECT "guid" FROM ' +
|
|
1240
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1241
|
+
' WHERE "name"=@' +
|
|
1242
|
+
name +
|
|
1243
|
+
')';
|
|
1244
|
+
params[name] = curVar;
|
|
1245
|
+
}
|
|
676
1246
|
}
|
|
677
1247
|
break;
|
|
678
1248
|
case 'truthy':
|
|
@@ -681,28 +1251,35 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
681
1251
|
if (curQuery) {
|
|
682
1252
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
683
1253
|
}
|
|
684
|
-
if (
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
1254
|
+
if (
|
|
1255
|
+
curVar === 'cdate' ||
|
|
1256
|
+
curVar === 'mdate' ||
|
|
1257
|
+
(this.nymph.tilmeld != null &&
|
|
1258
|
+
(curVar === 'user' ||
|
|
1259
|
+
curVar === 'group' ||
|
|
1260
|
+
curVar === 'acUser' ||
|
|
1261
|
+
curVar === 'acGroup' ||
|
|
1262
|
+
curVar === 'acOther' ||
|
|
1263
|
+
curVar === 'acRead' ||
|
|
1264
|
+
curVar === 'acWrite' ||
|
|
1265
|
+
curVar === 'acFull'))
|
|
1266
|
+
) {
|
|
692
1267
|
curQuery +=
|
|
693
1268
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
694
1269
|
'(' +
|
|
695
1270
|
ieTable +
|
|
696
|
-
'.
|
|
697
|
-
|
|
1271
|
+
'.' +
|
|
1272
|
+
SQLite3Driver.escape(curVar) +
|
|
1273
|
+
' IS NOT NULL)';
|
|
698
1274
|
} else {
|
|
699
1275
|
const name = `param${++count.i}`;
|
|
700
1276
|
curQuery +=
|
|
701
1277
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1278
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1279
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1280
|
+
' WHERE "guid"=' +
|
|
702
1281
|
ieTable +
|
|
703
|
-
'."guid"
|
|
704
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
705
|
-
' WHERE "name"=@' +
|
|
1282
|
+
'."guid" AND "name"=@' +
|
|
706
1283
|
name +
|
|
707
1284
|
' AND "truthy"=1)';
|
|
708
1285
|
params[name] = curVar;
|
|
@@ -711,30 +1288,62 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
711
1288
|
break;
|
|
712
1289
|
case 'equal':
|
|
713
1290
|
case '!equal':
|
|
714
|
-
if (
|
|
1291
|
+
if (
|
|
1292
|
+
curValue[0] === 'cdate' ||
|
|
1293
|
+
curValue[0] === 'mdate' ||
|
|
1294
|
+
(this.nymph.tilmeld != null &&
|
|
1295
|
+
(curValue[0] === 'acUser' ||
|
|
1296
|
+
curValue[0] === 'acGroup' ||
|
|
1297
|
+
curValue[0] === 'acOther'))
|
|
1298
|
+
) {
|
|
1299
|
+
if (curQuery) {
|
|
1300
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1301
|
+
}
|
|
1302
|
+
const value = `param${++count.i}`;
|
|
1303
|
+
curQuery +=
|
|
1304
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1305
|
+
ieTable +
|
|
1306
|
+
'.' +
|
|
1307
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1308
|
+
'=@' +
|
|
1309
|
+
value;
|
|
1310
|
+
params[value] = Number(curValue[1]);
|
|
1311
|
+
} else if (
|
|
1312
|
+
this.nymph.tilmeld != null &&
|
|
1313
|
+
(curValue[0] === 'user' || curValue[0] === 'group')
|
|
1314
|
+
) {
|
|
715
1315
|
if (curQuery) {
|
|
716
1316
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
717
1317
|
}
|
|
718
|
-
const
|
|
1318
|
+
const value = `param${++count.i}`;
|
|
719
1319
|
curQuery +=
|
|
720
1320
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
721
1321
|
ieTable +
|
|
722
|
-
'.
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
1322
|
+
'.' +
|
|
1323
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1324
|
+
'=@' +
|
|
1325
|
+
value;
|
|
1326
|
+
params[value] = `${curValue[1]}`;
|
|
1327
|
+
} else if (
|
|
1328
|
+
this.nymph.tilmeld != null &&
|
|
1329
|
+
(curValue[0] === 'acRead' ||
|
|
1330
|
+
curValue[0] === 'acWrite' ||
|
|
1331
|
+
curValue[0] === 'acFull')
|
|
1332
|
+
) {
|
|
727
1333
|
if (curQuery) {
|
|
728
1334
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
729
1335
|
}
|
|
730
|
-
const
|
|
1336
|
+
const value = `param${++count.i}`;
|
|
731
1337
|
curQuery +=
|
|
732
1338
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
733
1339
|
ieTable +
|
|
734
|
-
'.
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
1340
|
+
'.' +
|
|
1341
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1342
|
+
'=@' +
|
|
1343
|
+
value;
|
|
1344
|
+
params[value] = Array.isArray(curValue[1])
|
|
1345
|
+
? ',' + curValue[1].join(',') + ','
|
|
1346
|
+
: '';
|
|
738
1347
|
} else if (typeof curValue[1] === 'number') {
|
|
739
1348
|
if (curQuery) {
|
|
740
1349
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -743,10 +1352,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
743
1352
|
const value = `param${++count.i}`;
|
|
744
1353
|
curQuery +=
|
|
745
1354
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1355
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1356
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1357
|
+
' WHERE "guid"=' +
|
|
746
1358
|
ieTable +
|
|
747
|
-
'."guid"
|
|
748
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
749
|
-
' WHERE "name"=@' +
|
|
1359
|
+
'."guid" AND "name"=@' +
|
|
750
1360
|
name +
|
|
751
1361
|
' AND "number"=@' +
|
|
752
1362
|
value +
|
|
@@ -761,10 +1371,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
761
1371
|
const value = `param${++count.i}`;
|
|
762
1372
|
curQuery +=
|
|
763
1373
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1374
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1375
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1376
|
+
' WHERE "guid"=' +
|
|
764
1377
|
ieTable +
|
|
765
|
-
'."guid"
|
|
766
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
767
|
-
' WHERE "name"=@' +
|
|
1378
|
+
'."guid" AND "name"=@' +
|
|
768
1379
|
name +
|
|
769
1380
|
' AND "string"=@' +
|
|
770
1381
|
value +
|
|
@@ -788,130 +1399,302 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
788
1399
|
const value = `param${++count.i}`;
|
|
789
1400
|
curQuery +=
|
|
790
1401
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
791
|
-
|
|
792
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1402
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
793
1403
|
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
794
|
-
' WHERE "
|
|
1404
|
+
' WHERE "guid"=' +
|
|
1405
|
+
ieTable +
|
|
1406
|
+
'."guid" AND "name"=@' +
|
|
795
1407
|
name +
|
|
796
|
-
' AND "
|
|
1408
|
+
' AND "json"=jsonb(@' +
|
|
797
1409
|
value +
|
|
798
|
-
')';
|
|
1410
|
+
'))';
|
|
799
1411
|
params[name] = curValue[0];
|
|
800
1412
|
params[value] = svalue;
|
|
801
1413
|
}
|
|
802
1414
|
break;
|
|
803
1415
|
case 'contain':
|
|
804
1416
|
case '!contain':
|
|
805
|
-
if (
|
|
1417
|
+
if (
|
|
1418
|
+
curValue[0] === 'cdate' ||
|
|
1419
|
+
curValue[0] === 'mdate' ||
|
|
1420
|
+
(this.nymph.tilmeld != null &&
|
|
1421
|
+
(curValue[0] === 'acUser' ||
|
|
1422
|
+
curValue[0] === 'acGroup' ||
|
|
1423
|
+
curValue[0] === 'acOther'))
|
|
1424
|
+
) {
|
|
1425
|
+
if (curQuery) {
|
|
1426
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1427
|
+
}
|
|
1428
|
+
const value = `param${++count.i}`;
|
|
1429
|
+
curQuery +=
|
|
1430
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1431
|
+
ieTable +
|
|
1432
|
+
'.' +
|
|
1433
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1434
|
+
'=@' +
|
|
1435
|
+
value;
|
|
1436
|
+
params[value] = Number(curValue[1]);
|
|
1437
|
+
} else if (
|
|
1438
|
+
this.nymph.tilmeld != null &&
|
|
1439
|
+
(curValue[0] === 'user' || curValue[0] === 'group')
|
|
1440
|
+
) {
|
|
806
1441
|
if (curQuery) {
|
|
807
1442
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
808
1443
|
}
|
|
809
|
-
const
|
|
1444
|
+
const value = `param${++count.i}`;
|
|
810
1445
|
curQuery +=
|
|
811
1446
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
812
1447
|
ieTable +
|
|
813
|
-
'.
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
1448
|
+
'.' +
|
|
1449
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1450
|
+
'=@' +
|
|
1451
|
+
value;
|
|
1452
|
+
params[value] = `${curValue[1]}`;
|
|
1453
|
+
} else if (
|
|
1454
|
+
this.nymph.tilmeld != null &&
|
|
1455
|
+
(curValue[0] === 'acRead' ||
|
|
1456
|
+
curValue[0] === 'acWrite' ||
|
|
1457
|
+
curValue[0] === 'acFull')
|
|
1458
|
+
) {
|
|
818
1459
|
if (curQuery) {
|
|
819
1460
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
820
1461
|
}
|
|
821
|
-
const
|
|
1462
|
+
const id = `param${++count.i}`;
|
|
822
1463
|
curQuery +=
|
|
823
1464
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
824
1465
|
ieTable +
|
|
825
|
-
'.
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
1466
|
+
'.' +
|
|
1467
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1468
|
+
' LIKE @' +
|
|
1469
|
+
id +
|
|
1470
|
+
" ESCAPE '\\'";
|
|
1471
|
+
params[id] =
|
|
1472
|
+
'%,' +
|
|
1473
|
+
curValue[1]
|
|
1474
|
+
.replace('\\', '\\\\')
|
|
1475
|
+
.replace('%', '\\%')
|
|
1476
|
+
.replace('_', '\\_') +
|
|
1477
|
+
',%';
|
|
829
1478
|
} else {
|
|
1479
|
+
const containTableSuffix = makeTableSuffix();
|
|
830
1480
|
if (curQuery) {
|
|
831
1481
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
832
1482
|
}
|
|
833
1483
|
let svalue: string;
|
|
834
|
-
let stringValue: string;
|
|
835
1484
|
if (
|
|
836
1485
|
curValue[1] instanceof Object &&
|
|
837
1486
|
typeof curValue[1].toReference === 'function'
|
|
838
1487
|
) {
|
|
839
1488
|
svalue = JSON.stringify(curValue[1].toReference());
|
|
840
|
-
stringValue = `${curValue[1].toReference()}`;
|
|
841
1489
|
} else {
|
|
842
1490
|
svalue = JSON.stringify(curValue[1]);
|
|
843
|
-
stringValue = `${curValue[1]}`;
|
|
844
1491
|
}
|
|
845
1492
|
const name = `param${++count.i}`;
|
|
846
1493
|
const value = `param${++count.i}`;
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1494
|
+
curQuery +=
|
|
1495
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1496
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1497
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1498
|
+
' d' +
|
|
1499
|
+
containTableSuffix +
|
|
1500
|
+
' WHERE "guid"=' +
|
|
1501
|
+
ieTable +
|
|
1502
|
+
'."guid" AND "name"=@' +
|
|
1503
|
+
name +
|
|
1504
|
+
' AND json(@' +
|
|
1505
|
+
value +
|
|
1506
|
+
') IN (SELECT json_quote("value") FROM json_each(d' +
|
|
1507
|
+
containTableSuffix +
|
|
1508
|
+
'."json")))';
|
|
1509
|
+
params[name] = curValue[0];
|
|
1510
|
+
params[value] = svalue;
|
|
1511
|
+
}
|
|
1512
|
+
break;
|
|
1513
|
+
case 'search':
|
|
1514
|
+
case '!search':
|
|
1515
|
+
if (
|
|
1516
|
+
curValue[0] === 'cdate' ||
|
|
1517
|
+
curValue[0] === 'mdate' ||
|
|
1518
|
+
(this.nymph.tilmeld != null &&
|
|
1519
|
+
(curValue[0] === 'user' ||
|
|
1520
|
+
curValue[0] === 'group' ||
|
|
1521
|
+
curValue[0] === 'acUser' ||
|
|
1522
|
+
curValue[0] === 'acGroup' ||
|
|
1523
|
+
curValue[0] === 'acOther' ||
|
|
1524
|
+
curValue[0] === 'acRead' ||
|
|
1525
|
+
curValue[0] === 'acWrite' ||
|
|
1526
|
+
curValue[0] === 'acFull'))
|
|
1527
|
+
) {
|
|
1528
|
+
if (curQuery) {
|
|
1529
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1530
|
+
}
|
|
1531
|
+
curQuery += (xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(0)';
|
|
1532
|
+
} else {
|
|
1533
|
+
if (curQuery) {
|
|
1534
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
const parsedFTSQuery = this.tokenizer.parseSearchQuery(
|
|
1538
|
+
curValue[1],
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
if (!parsedFTSQuery.length) {
|
|
1542
|
+
curQuery += (xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(0)';
|
|
869
1543
|
} else {
|
|
1544
|
+
const name = `param${++count.i}`;
|
|
1545
|
+
|
|
1546
|
+
const queryPartToken = (term: SearchTerm) => {
|
|
1547
|
+
const value = `param${++count.i}`;
|
|
1548
|
+
params[value] = term.token;
|
|
1549
|
+
return (
|
|
1550
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1551
|
+
SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
|
|
1552
|
+
' WHERE "guid"=' +
|
|
1553
|
+
ieTable +
|
|
1554
|
+
'."guid" AND "name"=@' +
|
|
1555
|
+
name +
|
|
1556
|
+
' AND "token"=@' +
|
|
1557
|
+
value +
|
|
1558
|
+
(term.nostemmed ? ' AND "stem"=0' : '') +
|
|
1559
|
+
')'
|
|
1560
|
+
);
|
|
1561
|
+
};
|
|
1562
|
+
|
|
1563
|
+
const queryPartSeries = (series: SearchSeriesTerm) => {
|
|
1564
|
+
const tokenTableSuffix = makeTableSuffix();
|
|
1565
|
+
const tokenParts = series.tokens.map((token, i) => {
|
|
1566
|
+
const value = `param${++count.i}`;
|
|
1567
|
+
params[value] = token.token;
|
|
1568
|
+
return {
|
|
1569
|
+
fromClause:
|
|
1570
|
+
i === 0
|
|
1571
|
+
? 'FROM ' +
|
|
1572
|
+
SQLite3Driver.escape(
|
|
1573
|
+
this.prefix + 'tokens_' + etype,
|
|
1574
|
+
) +
|
|
1575
|
+
' t' +
|
|
1576
|
+
tokenTableSuffix +
|
|
1577
|
+
'0'
|
|
1578
|
+
: 'JOIN ' +
|
|
1579
|
+
SQLite3Driver.escape(
|
|
1580
|
+
this.prefix + 'tokens_' + etype,
|
|
1581
|
+
) +
|
|
1582
|
+
' t' +
|
|
1583
|
+
tokenTableSuffix +
|
|
1584
|
+
i +
|
|
1585
|
+
' ON t' +
|
|
1586
|
+
tokenTableSuffix +
|
|
1587
|
+
i +
|
|
1588
|
+
'."guid" = t' +
|
|
1589
|
+
tokenTableSuffix +
|
|
1590
|
+
'0."guid" AND t' +
|
|
1591
|
+
tokenTableSuffix +
|
|
1592
|
+
i +
|
|
1593
|
+
'."name" = t' +
|
|
1594
|
+
tokenTableSuffix +
|
|
1595
|
+
'0."name" AND t' +
|
|
1596
|
+
tokenTableSuffix +
|
|
1597
|
+
i +
|
|
1598
|
+
'."position" = t' +
|
|
1599
|
+
tokenTableSuffix +
|
|
1600
|
+
'0."position" + ' +
|
|
1601
|
+
i,
|
|
1602
|
+
whereClause:
|
|
1603
|
+
't' +
|
|
1604
|
+
tokenTableSuffix +
|
|
1605
|
+
i +
|
|
1606
|
+
'."token"=@' +
|
|
1607
|
+
value +
|
|
1608
|
+
(token.nostemmed
|
|
1609
|
+
? ' AND t' + tokenTableSuffix + i + '."stem"=0'
|
|
1610
|
+
: ''),
|
|
1611
|
+
};
|
|
1612
|
+
});
|
|
1613
|
+
return (
|
|
1614
|
+
'EXISTS (SELECT t' +
|
|
1615
|
+
tokenTableSuffix +
|
|
1616
|
+
'0."guid" ' +
|
|
1617
|
+
tokenParts.map((part) => part.fromClause).join(' ') +
|
|
1618
|
+
' WHERE t' +
|
|
1619
|
+
tokenTableSuffix +
|
|
1620
|
+
'0."guid"=' +
|
|
1621
|
+
ieTable +
|
|
1622
|
+
'."guid" AND t' +
|
|
1623
|
+
tokenTableSuffix +
|
|
1624
|
+
'0."name"=@' +
|
|
1625
|
+
name +
|
|
1626
|
+
' AND ' +
|
|
1627
|
+
tokenParts.map((part) => part.whereClause).join(' AND ') +
|
|
1628
|
+
')'
|
|
1629
|
+
);
|
|
1630
|
+
};
|
|
1631
|
+
|
|
1632
|
+
const queryPartTerm = (
|
|
1633
|
+
term:
|
|
1634
|
+
| SearchTerm
|
|
1635
|
+
| SearchOrTerm
|
|
1636
|
+
| SearchNotTerm
|
|
1637
|
+
| SearchSeriesTerm,
|
|
1638
|
+
): string => {
|
|
1639
|
+
if (term.type === 'series') {
|
|
1640
|
+
return queryPartSeries(term);
|
|
1641
|
+
} else if (term.type === 'not') {
|
|
1642
|
+
return 'NOT ' + queryPartTerm(term.operand);
|
|
1643
|
+
} else if (term.type === 'or') {
|
|
1644
|
+
let queryParts: string[] = [];
|
|
1645
|
+
for (let operand of term.operands) {
|
|
1646
|
+
queryParts.push(queryPartTerm(operand));
|
|
1647
|
+
}
|
|
1648
|
+
return '(' + queryParts.join(' OR ') + ')';
|
|
1649
|
+
}
|
|
1650
|
+
return queryPartToken(term);
|
|
1651
|
+
};
|
|
1652
|
+
|
|
1653
|
+
// Run through the query and add terms.
|
|
1654
|
+
let termStrings: string[] = [];
|
|
1655
|
+
for (let term of parsedFTSQuery) {
|
|
1656
|
+
termStrings.push(queryPartTerm(term));
|
|
1657
|
+
}
|
|
1658
|
+
|
|
870
1659
|
curQuery +=
|
|
871
1660
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
' AND instr("value", @' +
|
|
878
|
-
value +
|
|
879
|
-
'))';
|
|
1661
|
+
'(' +
|
|
1662
|
+
termStrings.join(' AND ') +
|
|
1663
|
+
')';
|
|
1664
|
+
|
|
1665
|
+
params[name] = curValue[0];
|
|
880
1666
|
}
|
|
881
|
-
params[name] = curValue[0];
|
|
882
|
-
params[value] = svalue;
|
|
883
1667
|
}
|
|
884
1668
|
break;
|
|
885
1669
|
case 'match':
|
|
886
1670
|
case '!match':
|
|
887
|
-
if (
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
break;
|
|
901
|
-
} else if (curValue[0] === 'mdate') {
|
|
1671
|
+
if (
|
|
1672
|
+
curValue[0] === 'cdate' ||
|
|
1673
|
+
curValue[0] === 'mdate' ||
|
|
1674
|
+
(this.nymph.tilmeld != null &&
|
|
1675
|
+
(curValue[0] === 'user' ||
|
|
1676
|
+
curValue[0] === 'group' ||
|
|
1677
|
+
curValue[0] === 'acUser' ||
|
|
1678
|
+
curValue[0] === 'acGroup' ||
|
|
1679
|
+
curValue[0] === 'acOther' ||
|
|
1680
|
+
curValue[0] === 'acRead' ||
|
|
1681
|
+
curValue[0] === 'acWrite' ||
|
|
1682
|
+
curValue[0] === 'acFull'))
|
|
1683
|
+
) {
|
|
902
1684
|
if (curQuery) {
|
|
903
1685
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
904
1686
|
}
|
|
905
|
-
const
|
|
1687
|
+
const value = `param${++count.i}`;
|
|
906
1688
|
curQuery +=
|
|
907
1689
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
908
1690
|
'(' +
|
|
909
1691
|
ieTable +
|
|
910
|
-
'.
|
|
911
|
-
|
|
1692
|
+
'.' +
|
|
1693
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1694
|
+
' REGEXP @' +
|
|
1695
|
+
value +
|
|
912
1696
|
')';
|
|
913
|
-
params[
|
|
914
|
-
break;
|
|
1697
|
+
params[value] = curValue[1];
|
|
915
1698
|
} else {
|
|
916
1699
|
if (curQuery) {
|
|
917
1700
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -920,10 +1703,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
920
1703
|
const value = `param${++count.i}`;
|
|
921
1704
|
curQuery +=
|
|
922
1705
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1706
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1707
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1708
|
+
' WHERE "guid"=' +
|
|
923
1709
|
ieTable +
|
|
924
|
-
'."guid"
|
|
925
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
926
|
-
' WHERE "name"=@' +
|
|
1710
|
+
'."guid" AND "name"=@' +
|
|
927
1711
|
name +
|
|
928
1712
|
' AND "string" REGEXP @' +
|
|
929
1713
|
value +
|
|
@@ -934,34 +1718,33 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
934
1718
|
break;
|
|
935
1719
|
case 'imatch':
|
|
936
1720
|
case '!imatch':
|
|
937
|
-
if (
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
break;
|
|
951
|
-
} else if (curValue[0] === 'mdate') {
|
|
1721
|
+
if (
|
|
1722
|
+
curValue[0] === 'cdate' ||
|
|
1723
|
+
curValue[0] === 'mdate' ||
|
|
1724
|
+
(this.nymph.tilmeld != null &&
|
|
1725
|
+
(curValue[0] === 'user' ||
|
|
1726
|
+
curValue[0] === 'group' ||
|
|
1727
|
+
curValue[0] === 'acUser' ||
|
|
1728
|
+
curValue[0] === 'acGroup' ||
|
|
1729
|
+
curValue[0] === 'acOther' ||
|
|
1730
|
+
curValue[0] === 'acRead' ||
|
|
1731
|
+
curValue[0] === 'acWrite' ||
|
|
1732
|
+
curValue[0] === 'acFull'))
|
|
1733
|
+
) {
|
|
952
1734
|
if (curQuery) {
|
|
953
1735
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
954
1736
|
}
|
|
955
|
-
const
|
|
1737
|
+
const value = `param${++count.i}`;
|
|
956
1738
|
curQuery +=
|
|
957
1739
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
958
|
-
'(' +
|
|
1740
|
+
'(lower(' +
|
|
959
1741
|
ieTable +
|
|
960
|
-
'.
|
|
961
|
-
|
|
962
|
-
')'
|
|
963
|
-
|
|
964
|
-
|
|
1742
|
+
'.' +
|
|
1743
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1744
|
+
') REGEXP lower(@' +
|
|
1745
|
+
value +
|
|
1746
|
+
'))';
|
|
1747
|
+
params[value] = curValue[1];
|
|
965
1748
|
} else {
|
|
966
1749
|
if (curQuery) {
|
|
967
1750
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -970,10 +1753,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
970
1753
|
const value = `param${++count.i}`;
|
|
971
1754
|
curQuery +=
|
|
972
1755
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1756
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1757
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1758
|
+
' WHERE "guid"=' +
|
|
973
1759
|
ieTable +
|
|
974
|
-
'."guid"
|
|
975
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
976
|
-
' WHERE "name"=@' +
|
|
1760
|
+
'."guid" AND "name"=@' +
|
|
977
1761
|
name +
|
|
978
1762
|
' AND lower("string") REGEXP lower(@' +
|
|
979
1763
|
value +
|
|
@@ -984,34 +1768,33 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
984
1768
|
break;
|
|
985
1769
|
case 'like':
|
|
986
1770
|
case '!like':
|
|
987
|
-
if (
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
break;
|
|
1001
|
-
} else if (curValue[0] === 'mdate') {
|
|
1771
|
+
if (
|
|
1772
|
+
curValue[0] === 'cdate' ||
|
|
1773
|
+
curValue[0] === 'mdate' ||
|
|
1774
|
+
(this.nymph.tilmeld != null &&
|
|
1775
|
+
(curValue[0] === 'user' ||
|
|
1776
|
+
curValue[0] === 'group' ||
|
|
1777
|
+
curValue[0] === 'acUser' ||
|
|
1778
|
+
curValue[0] === 'acGroup' ||
|
|
1779
|
+
curValue[0] === 'acOther' ||
|
|
1780
|
+
curValue[0] === 'acRead' ||
|
|
1781
|
+
curValue[0] === 'acWrite' ||
|
|
1782
|
+
curValue[0] === 'acFull'))
|
|
1783
|
+
) {
|
|
1002
1784
|
if (curQuery) {
|
|
1003
1785
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1004
1786
|
}
|
|
1005
|
-
const
|
|
1787
|
+
const value = `param${++count.i}`;
|
|
1006
1788
|
curQuery +=
|
|
1007
1789
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1008
1790
|
'(' +
|
|
1009
1791
|
ieTable +
|
|
1010
|
-
'.
|
|
1011
|
-
|
|
1792
|
+
'.' +
|
|
1793
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1794
|
+
' LIKE @' +
|
|
1795
|
+
value +
|
|
1012
1796
|
" ESCAPE '\\')";
|
|
1013
|
-
params[
|
|
1014
|
-
break;
|
|
1797
|
+
params[value] = curValue[1];
|
|
1015
1798
|
} else {
|
|
1016
1799
|
if (curQuery) {
|
|
1017
1800
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1020,10 +1803,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1020
1803
|
const value = `param${++count.i}`;
|
|
1021
1804
|
curQuery +=
|
|
1022
1805
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1806
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1807
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1808
|
+
' WHERE "guid"=' +
|
|
1023
1809
|
ieTable +
|
|
1024
|
-
'."guid"
|
|
1025
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1026
|
-
' WHERE "name"=@' +
|
|
1810
|
+
'."guid" AND "name"=@' +
|
|
1027
1811
|
name +
|
|
1028
1812
|
' AND "string" LIKE @' +
|
|
1029
1813
|
value +
|
|
@@ -1034,34 +1818,33 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1034
1818
|
break;
|
|
1035
1819
|
case 'ilike':
|
|
1036
1820
|
case '!ilike':
|
|
1037
|
-
if (
|
|
1821
|
+
if (
|
|
1822
|
+
curValue[0] === 'cdate' ||
|
|
1823
|
+
curValue[0] === 'mdate' ||
|
|
1824
|
+
(this.nymph.tilmeld != null &&
|
|
1825
|
+
(curValue[0] === 'user' ||
|
|
1826
|
+
curValue[0] === 'group' ||
|
|
1827
|
+
curValue[0] === 'acUser' ||
|
|
1828
|
+
curValue[0] === 'acGroup' ||
|
|
1829
|
+
curValue[0] === 'acOther' ||
|
|
1830
|
+
curValue[0] === 'acRead' ||
|
|
1831
|
+
curValue[0] === 'acWrite' ||
|
|
1832
|
+
curValue[0] === 'acFull'))
|
|
1833
|
+
) {
|
|
1038
1834
|
if (curQuery) {
|
|
1039
1835
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1040
1836
|
}
|
|
1041
|
-
const
|
|
1837
|
+
const value = `param${++count.i}`;
|
|
1042
1838
|
curQuery +=
|
|
1043
1839
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1044
|
-
'(' +
|
|
1840
|
+
'(lower(' +
|
|
1045
1841
|
ieTable +
|
|
1046
|
-
'.
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
if (curQuery) {
|
|
1053
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1054
|
-
}
|
|
1055
|
-
const mdate = `param${++count.i}`;
|
|
1056
|
-
curQuery +=
|
|
1057
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1058
|
-
'(' +
|
|
1059
|
-
ieTable +
|
|
1060
|
-
'."mdate" LIKE @' +
|
|
1061
|
-
mdate +
|
|
1062
|
-
" ESCAPE '\\')";
|
|
1063
|
-
params[mdate] = curValue[1];
|
|
1064
|
-
break;
|
|
1842
|
+
'.' +
|
|
1843
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1844
|
+
') LIKE lower(@' +
|
|
1845
|
+
value +
|
|
1846
|
+
") ESCAPE '\\')";
|
|
1847
|
+
params[value] = curValue[1];
|
|
1065
1848
|
} else {
|
|
1066
1849
|
if (curQuery) {
|
|
1067
1850
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1070,10 +1853,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1070
1853
|
const value = `param${++count.i}`;
|
|
1071
1854
|
curQuery +=
|
|
1072
1855
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1856
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1857
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1858
|
+
' WHERE "guid"=' +
|
|
1073
1859
|
ieTable +
|
|
1074
|
-
'."guid"
|
|
1075
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1076
|
-
' WHERE "name"=@' +
|
|
1860
|
+
'."guid" AND "name"=@' +
|
|
1077
1861
|
name +
|
|
1078
1862
|
' AND lower("string") LIKE lower(@' +
|
|
1079
1863
|
value +
|
|
@@ -1084,30 +1868,31 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1084
1868
|
break;
|
|
1085
1869
|
case 'gt':
|
|
1086
1870
|
case '!gt':
|
|
1087
|
-
if (
|
|
1871
|
+
if (
|
|
1872
|
+
curValue[0] === 'cdate' ||
|
|
1873
|
+
curValue[0] === 'mdate' ||
|
|
1874
|
+
(this.nymph.tilmeld != null &&
|
|
1875
|
+
(curValue[0] === 'user' ||
|
|
1876
|
+
curValue[0] === 'group' ||
|
|
1877
|
+
curValue[0] === 'acUser' ||
|
|
1878
|
+
curValue[0] === 'acGroup' ||
|
|
1879
|
+
curValue[0] === 'acOther' ||
|
|
1880
|
+
curValue[0] === 'acRead' ||
|
|
1881
|
+
curValue[0] === 'acWrite' ||
|
|
1882
|
+
curValue[0] === 'acFull'))
|
|
1883
|
+
) {
|
|
1088
1884
|
if (curQuery) {
|
|
1089
1885
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1090
1886
|
}
|
|
1091
|
-
const
|
|
1092
|
-
curQuery +=
|
|
1093
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1094
|
-
ieTable +
|
|
1095
|
-
'."cdate">@' +
|
|
1096
|
-
cdate;
|
|
1097
|
-
params[cdate] = Number(curValue[1]);
|
|
1098
|
-
break;
|
|
1099
|
-
} else if (curValue[0] === 'mdate') {
|
|
1100
|
-
if (curQuery) {
|
|
1101
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1102
|
-
}
|
|
1103
|
-
const mdate = `param${++count.i}`;
|
|
1887
|
+
const value = `param${++count.i}`;
|
|
1104
1888
|
curQuery +=
|
|
1105
1889
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1106
1890
|
ieTable +
|
|
1107
|
-
'.
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1891
|
+
'.' +
|
|
1892
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1893
|
+
'>@' +
|
|
1894
|
+
value;
|
|
1895
|
+
params[value] = Number(curValue[1]);
|
|
1111
1896
|
} else {
|
|
1112
1897
|
if (curQuery) {
|
|
1113
1898
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1116,10 +1901,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1116
1901
|
const value = `param${++count.i}`;
|
|
1117
1902
|
curQuery +=
|
|
1118
1903
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1904
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1905
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1906
|
+
' WHERE "guid"=' +
|
|
1119
1907
|
ieTable +
|
|
1120
|
-
'."guid"
|
|
1121
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1122
|
-
' WHERE "name"=@' +
|
|
1908
|
+
'."guid" AND "name"=@' +
|
|
1123
1909
|
name +
|
|
1124
1910
|
' AND "number">@' +
|
|
1125
1911
|
value +
|
|
@@ -1130,30 +1916,31 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1130
1916
|
break;
|
|
1131
1917
|
case 'gte':
|
|
1132
1918
|
case '!gte':
|
|
1133
|
-
if (
|
|
1919
|
+
if (
|
|
1920
|
+
curValue[0] === 'cdate' ||
|
|
1921
|
+
curValue[0] === 'mdate' ||
|
|
1922
|
+
(this.nymph.tilmeld != null &&
|
|
1923
|
+
(curValue[0] === 'user' ||
|
|
1924
|
+
curValue[0] === 'group' ||
|
|
1925
|
+
curValue[0] === 'acUser' ||
|
|
1926
|
+
curValue[0] === 'acGroup' ||
|
|
1927
|
+
curValue[0] === 'acOther' ||
|
|
1928
|
+
curValue[0] === 'acRead' ||
|
|
1929
|
+
curValue[0] === 'acWrite' ||
|
|
1930
|
+
curValue[0] === 'acFull'))
|
|
1931
|
+
) {
|
|
1134
1932
|
if (curQuery) {
|
|
1135
1933
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1136
1934
|
}
|
|
1137
|
-
const
|
|
1138
|
-
curQuery +=
|
|
1139
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1140
|
-
ieTable +
|
|
1141
|
-
'."cdate">=@' +
|
|
1142
|
-
cdate;
|
|
1143
|
-
params[cdate] = Number(curValue[1]);
|
|
1144
|
-
break;
|
|
1145
|
-
} else if (curValue[0] === 'mdate') {
|
|
1146
|
-
if (curQuery) {
|
|
1147
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1148
|
-
}
|
|
1149
|
-
const mdate = `param${++count.i}`;
|
|
1935
|
+
const value = `param${++count.i}`;
|
|
1150
1936
|
curQuery +=
|
|
1151
1937
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1152
1938
|
ieTable +
|
|
1153
|
-
'.
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1939
|
+
'.' +
|
|
1940
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1941
|
+
'>=@' +
|
|
1942
|
+
value;
|
|
1943
|
+
params[value] = Number(curValue[1]);
|
|
1157
1944
|
} else {
|
|
1158
1945
|
if (curQuery) {
|
|
1159
1946
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1162,10 +1949,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1162
1949
|
const value = `param${++count.i}`;
|
|
1163
1950
|
curQuery +=
|
|
1164
1951
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1952
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1953
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1954
|
+
' WHERE "guid"=' +
|
|
1165
1955
|
ieTable +
|
|
1166
|
-
'."guid"
|
|
1167
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1168
|
-
' WHERE "name"=@' +
|
|
1956
|
+
'."guid" AND "name"=@' +
|
|
1169
1957
|
name +
|
|
1170
1958
|
' AND "number">=@' +
|
|
1171
1959
|
value +
|
|
@@ -1176,30 +1964,31 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1176
1964
|
break;
|
|
1177
1965
|
case 'lt':
|
|
1178
1966
|
case '!lt':
|
|
1179
|
-
if (
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1967
|
+
if (
|
|
1968
|
+
curValue[0] === 'cdate' ||
|
|
1969
|
+
curValue[0] === 'mdate' ||
|
|
1970
|
+
(this.nymph.tilmeld != null &&
|
|
1971
|
+
(curValue[0] === 'user' ||
|
|
1972
|
+
curValue[0] === 'group' ||
|
|
1973
|
+
curValue[0] === 'acUser' ||
|
|
1974
|
+
curValue[0] === 'acGroup' ||
|
|
1975
|
+
curValue[0] === 'acOther' ||
|
|
1976
|
+
curValue[0] === 'acRead' ||
|
|
1977
|
+
curValue[0] === 'acWrite' ||
|
|
1978
|
+
curValue[0] === 'acFull'))
|
|
1979
|
+
) {
|
|
1192
1980
|
if (curQuery) {
|
|
1193
1981
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1194
1982
|
}
|
|
1195
|
-
const
|
|
1983
|
+
const value = `param${++count.i}`;
|
|
1196
1984
|
curQuery +=
|
|
1197
1985
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1198
1986
|
ieTable +
|
|
1199
|
-
'.
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1987
|
+
'.' +
|
|
1988
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1989
|
+
'<@' +
|
|
1990
|
+
value;
|
|
1991
|
+
params[value] = Number(curValue[1]);
|
|
1203
1992
|
} else {
|
|
1204
1993
|
if (curQuery) {
|
|
1205
1994
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1208,10 +1997,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1208
1997
|
const value = `param${++count.i}`;
|
|
1209
1998
|
curQuery +=
|
|
1210
1999
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2000
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
2001
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
2002
|
+
' WHERE "guid"=' +
|
|
1211
2003
|
ieTable +
|
|
1212
|
-
'."guid"
|
|
1213
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1214
|
-
' WHERE "name"=@' +
|
|
2004
|
+
'."guid" AND "name"=@' +
|
|
1215
2005
|
name +
|
|
1216
2006
|
' AND "number"<@' +
|
|
1217
2007
|
value +
|
|
@@ -1222,30 +2012,31 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1222
2012
|
break;
|
|
1223
2013
|
case 'lte':
|
|
1224
2014
|
case '!lte':
|
|
1225
|
-
if (
|
|
2015
|
+
if (
|
|
2016
|
+
curValue[0] === 'cdate' ||
|
|
2017
|
+
curValue[0] === 'mdate' ||
|
|
2018
|
+
(this.nymph.tilmeld != null &&
|
|
2019
|
+
(curValue[0] === 'user' ||
|
|
2020
|
+
curValue[0] === 'group' ||
|
|
2021
|
+
curValue[0] === 'acUser' ||
|
|
2022
|
+
curValue[0] === 'acGroup' ||
|
|
2023
|
+
curValue[0] === 'acOther' ||
|
|
2024
|
+
curValue[0] === 'acRead' ||
|
|
2025
|
+
curValue[0] === 'acWrite' ||
|
|
2026
|
+
curValue[0] === 'acFull'))
|
|
2027
|
+
) {
|
|
1226
2028
|
if (curQuery) {
|
|
1227
2029
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1228
2030
|
}
|
|
1229
|
-
const
|
|
1230
|
-
curQuery +=
|
|
1231
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1232
|
-
ieTable +
|
|
1233
|
-
'."cdate"<=@' +
|
|
1234
|
-
cdate;
|
|
1235
|
-
params[cdate] = Number(curValue[1]);
|
|
1236
|
-
break;
|
|
1237
|
-
} else if (curValue[0] === 'mdate') {
|
|
1238
|
-
if (curQuery) {
|
|
1239
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1240
|
-
}
|
|
1241
|
-
const mdate = `param${++count.i}`;
|
|
2031
|
+
const value = `param${++count.i}`;
|
|
1242
2032
|
curQuery +=
|
|
1243
2033
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1244
2034
|
ieTable +
|
|
1245
|
-
'.
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
2035
|
+
'.' +
|
|
2036
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
2037
|
+
'<=@' +
|
|
2038
|
+
value;
|
|
2039
|
+
params[value] = Number(curValue[1]);
|
|
1249
2040
|
} else {
|
|
1250
2041
|
if (curQuery) {
|
|
1251
2042
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1254,10 +2045,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1254
2045
|
const value = `param${++count.i}`;
|
|
1255
2046
|
curQuery +=
|
|
1256
2047
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2048
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
2049
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
2050
|
+
' WHERE "guid"=' +
|
|
1257
2051
|
ieTable +
|
|
1258
|
-
'."guid"
|
|
1259
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1260
|
-
' WHERE "name"=@' +
|
|
2052
|
+
'."guid" AND "name"=@' +
|
|
1261
2053
|
name +
|
|
1262
2054
|
' AND "number"<=@' +
|
|
1263
2055
|
value +
|
|
@@ -1279,32 +2071,70 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1279
2071
|
if (curQuery) {
|
|
1280
2072
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1281
2073
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
2074
|
+
if (
|
|
2075
|
+
this.nymph.tilmeld != null &&
|
|
2076
|
+
(curValue[0] === 'user' || curValue[0] === 'group')
|
|
2077
|
+
) {
|
|
2078
|
+
const guid = `param${++count.i}`;
|
|
2079
|
+
curQuery +=
|
|
2080
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2081
|
+
ieTable +
|
|
2082
|
+
'.' +
|
|
2083
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
2084
|
+
'=@' +
|
|
2085
|
+
guid;
|
|
2086
|
+
params[guid] = curQguid;
|
|
2087
|
+
} else if (
|
|
2088
|
+
this.nymph.tilmeld != null &&
|
|
2089
|
+
(curValue[0] === 'acRead' ||
|
|
2090
|
+
curValue[0] === 'acWrite' ||
|
|
2091
|
+
curValue[0] === 'acFull')
|
|
2092
|
+
) {
|
|
2093
|
+
const guid = `param${++count.i}`;
|
|
2094
|
+
curQuery +=
|
|
2095
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2096
|
+
ieTable +
|
|
2097
|
+
'.' +
|
|
2098
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
2099
|
+
' LIKE @' +
|
|
2100
|
+
guid +
|
|
2101
|
+
" ESCAPE '\\'";
|
|
2102
|
+
params[guid] =
|
|
2103
|
+
'%,' +
|
|
2104
|
+
curQguid
|
|
2105
|
+
.replace('\\', '\\\\')
|
|
2106
|
+
.replace('%', '\\%')
|
|
2107
|
+
.replace('_', '\\_') +
|
|
2108
|
+
',%';
|
|
2109
|
+
} else {
|
|
2110
|
+
const name = `param${++count.i}`;
|
|
2111
|
+
const guid = `param${++count.i}`;
|
|
2112
|
+
curQuery +=
|
|
2113
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2114
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
2115
|
+
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
2116
|
+
' WHERE "guid"=' +
|
|
2117
|
+
ieTable +
|
|
2118
|
+
'."guid" AND "name"=@' +
|
|
2119
|
+
name +
|
|
2120
|
+
' AND "reference"=@' +
|
|
2121
|
+
guid +
|
|
2122
|
+
')';
|
|
2123
|
+
params[name] = curValue[0];
|
|
2124
|
+
params[guid] = curQguid;
|
|
2125
|
+
}
|
|
1296
2126
|
break;
|
|
1297
2127
|
case 'selector':
|
|
1298
2128
|
case '!selector':
|
|
1299
|
-
const
|
|
1300
|
-
options,
|
|
2129
|
+
const innerquery = this.makeEntityQuery(
|
|
2130
|
+
{ ...options, sort: null, limit: undefined },
|
|
1301
2131
|
[curValue],
|
|
1302
2132
|
etype,
|
|
1303
2133
|
count,
|
|
1304
2134
|
params,
|
|
1305
2135
|
true,
|
|
1306
2136
|
tableSuffix,
|
|
1307
|
-
etypes
|
|
2137
|
+
etypes,
|
|
1308
2138
|
);
|
|
1309
2139
|
if (curQuery) {
|
|
1310
2140
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1312,61 +2142,184 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1312
2142
|
curQuery +=
|
|
1313
2143
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1314
2144
|
'(' +
|
|
1315
|
-
|
|
2145
|
+
innerquery.query +
|
|
1316
2146
|
')';
|
|
1317
2147
|
break;
|
|
1318
2148
|
case 'qref':
|
|
1319
2149
|
case '!qref':
|
|
2150
|
+
const referenceTableSuffix = makeTableSuffix();
|
|
1320
2151
|
const [qrefOptions, ...qrefSelectors] = curValue[1] as [
|
|
1321
2152
|
Options,
|
|
1322
|
-
...FormattedSelector[]
|
|
2153
|
+
...FormattedSelector[],
|
|
1323
2154
|
];
|
|
1324
2155
|
const QrefEntityClass = qrefOptions.class as EntityConstructor;
|
|
1325
2156
|
etypes.push(QrefEntityClass.ETYPE);
|
|
1326
|
-
const qrefQuery = this.makeEntityQuery(
|
|
1327
|
-
{ ...qrefOptions, return: 'guid', class: QrefEntityClass },
|
|
1328
|
-
qrefSelectors,
|
|
1329
|
-
QrefEntityClass.ETYPE,
|
|
1330
|
-
count,
|
|
1331
|
-
params,
|
|
1332
|
-
false,
|
|
1333
|
-
makeTableSuffix(),
|
|
1334
|
-
etypes
|
|
1335
|
-
);
|
|
1336
2157
|
if (curQuery) {
|
|
1337
2158
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1338
2159
|
}
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
(
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
2160
|
+
if (
|
|
2161
|
+
this.nymph.tilmeld != null &&
|
|
2162
|
+
(curValue[0] === 'user' || curValue[0] === 'group')
|
|
2163
|
+
) {
|
|
2164
|
+
const qrefQuery = this.makeEntityQuery(
|
|
2165
|
+
{
|
|
2166
|
+
...qrefOptions,
|
|
2167
|
+
sort: qrefOptions.sort ?? null,
|
|
2168
|
+
return: 'guid',
|
|
2169
|
+
class: QrefEntityClass,
|
|
2170
|
+
},
|
|
2171
|
+
qrefSelectors,
|
|
2172
|
+
QrefEntityClass.ETYPE,
|
|
2173
|
+
count,
|
|
2174
|
+
params,
|
|
2175
|
+
false,
|
|
2176
|
+
makeTableSuffix(),
|
|
2177
|
+
etypes,
|
|
2178
|
+
'r' +
|
|
2179
|
+
referenceTableSuffix +
|
|
2180
|
+
'.' +
|
|
2181
|
+
SQLite3Driver.escape(curValue[0]),
|
|
2182
|
+
);
|
|
2183
|
+
|
|
2184
|
+
curQuery +=
|
|
2185
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2186
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
2187
|
+
SQLite3Driver.escape(this.prefix + 'entities_' + etype) +
|
|
2188
|
+
' r' +
|
|
2189
|
+
referenceTableSuffix +
|
|
2190
|
+
' WHERE r' +
|
|
2191
|
+
referenceTableSuffix +
|
|
2192
|
+
'."guid"=' +
|
|
2193
|
+
ieTable +
|
|
2194
|
+
'."guid" AND EXISTS (' +
|
|
2195
|
+
qrefQuery.query +
|
|
2196
|
+
'))';
|
|
2197
|
+
} else if (
|
|
2198
|
+
this.nymph.tilmeld != null &&
|
|
2199
|
+
(curValue[0] === 'acRead' ||
|
|
2200
|
+
curValue[0] === 'acWrite' ||
|
|
2201
|
+
curValue[0] === 'acFull')
|
|
2202
|
+
) {
|
|
2203
|
+
const qrefQuery = this.makeEntityQuery(
|
|
2204
|
+
{
|
|
2205
|
+
...qrefOptions,
|
|
2206
|
+
sort: qrefOptions.sort ?? null,
|
|
2207
|
+
return: 'guid',
|
|
2208
|
+
class: QrefEntityClass,
|
|
2209
|
+
},
|
|
2210
|
+
qrefSelectors,
|
|
2211
|
+
QrefEntityClass.ETYPE,
|
|
2212
|
+
count,
|
|
2213
|
+
params,
|
|
2214
|
+
false,
|
|
2215
|
+
makeTableSuffix(),
|
|
2216
|
+
etypes,
|
|
2217
|
+
'r' + referenceTableSuffix + '."ref"',
|
|
2218
|
+
);
|
|
2219
|
+
|
|
2220
|
+
const splitTableSuffix = makeTableSuffix();
|
|
2221
|
+
curQuery +=
|
|
2222
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2223
|
+
`EXISTS (SELECT "guid", "ref" FROM (
|
|
2224
|
+
WITH RECURSIVE "spl${splitTableSuffix}" AS (
|
|
2225
|
+
SELECT
|
|
2226
|
+
"guid",
|
|
2227
|
+
SUBSTR(${SQLite3Driver.escape(curValue[0])}, 1, INSTR(${SQLite3Driver.escape(curValue[0])}, ',') - 1) AS "ref",
|
|
2228
|
+
SUBSTR(${SQLite3Driver.escape(curValue[0])}, INSTR(${SQLite3Driver.escape(curValue[0])}, ',') + 1) AS "remainder"
|
|
2229
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)}
|
|
2230
|
+
UNION ALL
|
|
2231
|
+
SELECT
|
|
2232
|
+
"guid",
|
|
2233
|
+
SUBSTR("remainder", 1, INSTR("remainder", ',') - 1) AS "ref",
|
|
2234
|
+
SUBSTR("remainder", INSTR("remainder", ',') + 1) AS "remainder"
|
|
2235
|
+
FROM "spl${splitTableSuffix}" WHERE "remainder" != ''
|
|
2236
|
+
)
|
|
2237
|
+
SELECT "guid", "ref" FROM "spl${splitTableSuffix}" WHERE "ref" != ''
|
|
2238
|
+
) ` +
|
|
2239
|
+
' r' +
|
|
2240
|
+
referenceTableSuffix +
|
|
2241
|
+
' WHERE r' +
|
|
2242
|
+
referenceTableSuffix +
|
|
2243
|
+
'."guid"=' +
|
|
2244
|
+
ieTable +
|
|
2245
|
+
'."guid" AND EXISTS (' +
|
|
2246
|
+
qrefQuery.query +
|
|
2247
|
+
'))';
|
|
2248
|
+
} else {
|
|
2249
|
+
const qrefQuery = this.makeEntityQuery(
|
|
2250
|
+
{
|
|
2251
|
+
...qrefOptions,
|
|
2252
|
+
sort: qrefOptions.sort ?? null,
|
|
2253
|
+
return: 'guid',
|
|
2254
|
+
class: QrefEntityClass,
|
|
2255
|
+
},
|
|
2256
|
+
qrefSelectors,
|
|
2257
|
+
QrefEntityClass.ETYPE,
|
|
2258
|
+
count,
|
|
2259
|
+
params,
|
|
2260
|
+
false,
|
|
2261
|
+
makeTableSuffix(),
|
|
2262
|
+
etypes,
|
|
2263
|
+
'r' + referenceTableSuffix + '."reference"',
|
|
2264
|
+
);
|
|
2265
|
+
|
|
2266
|
+
const qrefName = `param${++count.i}`;
|
|
2267
|
+
curQuery +=
|
|
2268
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2269
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
2270
|
+
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
2271
|
+
' r' +
|
|
2272
|
+
referenceTableSuffix +
|
|
2273
|
+
' WHERE r' +
|
|
2274
|
+
referenceTableSuffix +
|
|
2275
|
+
'."guid"=' +
|
|
2276
|
+
ieTable +
|
|
2277
|
+
'."guid" AND r' +
|
|
2278
|
+
referenceTableSuffix +
|
|
2279
|
+
'."name"=@' +
|
|
2280
|
+
qrefName +
|
|
2281
|
+
' AND EXISTS (' +
|
|
2282
|
+
qrefQuery.query +
|
|
2283
|
+
'))';
|
|
2284
|
+
params[qrefName] = curValue[0];
|
|
2285
|
+
}
|
|
1351
2286
|
break;
|
|
1352
2287
|
}
|
|
1353
2288
|
}
|
|
1354
2289
|
return curQuery;
|
|
1355
|
-
}
|
|
2290
|
+
},
|
|
1356
2291
|
);
|
|
1357
2292
|
|
|
1358
2293
|
let sortBy: string;
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
2294
|
+
let sortByInner: string;
|
|
2295
|
+
let sortJoin = '';
|
|
2296
|
+
const order = options.reverse ? ' DESC' : '';
|
|
2297
|
+
if (sort == null) {
|
|
2298
|
+
sortBy = '';
|
|
2299
|
+
sortByInner = '';
|
|
2300
|
+
} else {
|
|
2301
|
+
switch (sort) {
|
|
2302
|
+
case 'mdate':
|
|
2303
|
+
sortBy = `ORDER BY ${eTable}."mdate"${order}`;
|
|
2304
|
+
sortByInner = `ORDER BY ${ieTable}."mdate"${order}`;
|
|
2305
|
+
break;
|
|
2306
|
+
case 'cdate':
|
|
2307
|
+
sortBy = `ORDER BY ${eTable}."cdate"${order}`;
|
|
2308
|
+
sortByInner = `ORDER BY ${ieTable}."cdate"${order}`;
|
|
2309
|
+
break;
|
|
2310
|
+
default:
|
|
2311
|
+
const name = `param${++count.i}`;
|
|
2312
|
+
sortJoin = `LEFT JOIN (
|
|
2313
|
+
SELECT "guid", "string", "number"
|
|
2314
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'data_' + etype)}
|
|
2315
|
+
WHERE "name"=@${name}
|
|
2316
|
+
ORDER BY "number"${order}, "string"${order}
|
|
2317
|
+
) ${sTable} USING ("guid")`;
|
|
2318
|
+
sortBy = `ORDER BY ${sTable}."number"${order}, ${sTable}."string"${order}`;
|
|
2319
|
+
sortByInner = sortBy;
|
|
2320
|
+
params[name] = sort;
|
|
2321
|
+
break;
|
|
2322
|
+
}
|
|
1370
2323
|
}
|
|
1371
2324
|
|
|
1372
2325
|
let query: string;
|
|
@@ -1383,57 +2336,69 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1383
2336
|
offset = ` OFFSET ${Math.floor(Number(options.offset))}`;
|
|
1384
2337
|
}
|
|
1385
2338
|
const whereClause = queryParts.join(') AND (');
|
|
2339
|
+
const guidClause = guidSelector
|
|
2340
|
+
? `${ieTable}."guid"=${guidSelector} AND `
|
|
2341
|
+
: '';
|
|
1386
2342
|
if (options.return === 'count') {
|
|
1387
2343
|
if (limit || offset) {
|
|
1388
2344
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1389
2345
|
SELECT "guid"
|
|
1390
2346
|
FROM ${SQLite3Driver.escape(
|
|
1391
|
-
this.prefix + 'entities_' + etype
|
|
2347
|
+
this.prefix + 'entities_' + etype,
|
|
1392
2348
|
)} ${ieTable}
|
|
1393
|
-
WHERE (${whereClause})${limit}${offset}
|
|
2349
|
+
WHERE ${guidClause}(${whereClause})${limit}${offset}
|
|
1394
2350
|
)`;
|
|
1395
2351
|
} else {
|
|
1396
2352
|
query = `SELECT COUNT("guid") AS "count"
|
|
1397
2353
|
FROM ${SQLite3Driver.escape(
|
|
1398
|
-
this.prefix + 'entities_' + etype
|
|
2354
|
+
this.prefix + 'entities_' + etype,
|
|
1399
2355
|
)} ${ieTable}
|
|
1400
|
-
WHERE (${whereClause})`;
|
|
2356
|
+
WHERE ${guidClause}(${whereClause})`;
|
|
1401
2357
|
}
|
|
1402
2358
|
} else if (options.return === 'guid') {
|
|
1403
2359
|
query = `SELECT "guid"
|
|
1404
2360
|
FROM ${SQLite3Driver.escape(
|
|
1405
|
-
this.prefix + 'entities_' + etype
|
|
2361
|
+
this.prefix + 'entities_' + etype,
|
|
1406
2362
|
)} ${ieTable}
|
|
1407
|
-
|
|
1408
|
-
|
|
2363
|
+
${sortJoin}
|
|
2364
|
+
WHERE ${guidClause}(${whereClause})
|
|
2365
|
+
${sortByInner ? sortByInner + ', ' : 'ORDER BY '}"guid"${limit}${offset}`;
|
|
1409
2366
|
} else {
|
|
1410
2367
|
query = `SELECT
|
|
1411
2368
|
${eTable}."guid",
|
|
1412
2369
|
${eTable}."tags",
|
|
1413
2370
|
${eTable}."cdate",
|
|
1414
2371
|
${eTable}."mdate",
|
|
2372
|
+
${eTable}."user",
|
|
2373
|
+
${eTable}."group",
|
|
2374
|
+
${eTable}."acUser",
|
|
2375
|
+
${eTable}."acGroup",
|
|
2376
|
+
${eTable}."acOther",
|
|
2377
|
+
${eTable}."acRead",
|
|
2378
|
+
${eTable}."acWrite",
|
|
2379
|
+
${eTable}."acFull",
|
|
1415
2380
|
${dTable}."name",
|
|
1416
2381
|
${dTable}."value",
|
|
1417
|
-
${
|
|
1418
|
-
${
|
|
2382
|
+
json(${dTable}."json") as "json",
|
|
2383
|
+
${dTable}."string",
|
|
2384
|
+
${dTable}."number"
|
|
1419
2385
|
FROM ${SQLite3Driver.escape(
|
|
1420
|
-
this.prefix + 'entities_' + etype
|
|
2386
|
+
this.prefix + 'entities_' + etype,
|
|
1421
2387
|
)} ${eTable}
|
|
1422
2388
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1423
|
-
this.prefix + 'data_' + etype
|
|
2389
|
+
this.prefix + 'data_' + etype,
|
|
1424
2390
|
)} ${dTable} USING ("guid")
|
|
1425
|
-
|
|
1426
|
-
this.prefix + 'comparisons_' + etype
|
|
1427
|
-
)} ${cTable} USING ("guid", "name")
|
|
2391
|
+
${sortJoin}
|
|
1428
2392
|
INNER JOIN (
|
|
1429
2393
|
SELECT "guid"
|
|
1430
2394
|
FROM ${SQLite3Driver.escape(
|
|
1431
|
-
this.prefix + 'entities_' + etype
|
|
2395
|
+
this.prefix + 'entities_' + etype,
|
|
1432
2396
|
)} ${ieTable}
|
|
1433
|
-
|
|
1434
|
-
|
|
2397
|
+
${sortJoin}
|
|
2398
|
+
WHERE ${guidClause}(${whereClause})
|
|
2399
|
+
${sortByInner}${limit}${offset}
|
|
1435
2400
|
) ${fTable} USING ("guid")
|
|
1436
|
-
ORDER BY ${eTable}
|
|
2401
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}."guid"`;
|
|
1437
2402
|
}
|
|
1438
2403
|
}
|
|
1439
2404
|
} else {
|
|
@@ -1448,26 +2413,31 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1448
2413
|
if ('offset' in options) {
|
|
1449
2414
|
offset = ` OFFSET ${Math.floor(Number(options.offset))}`;
|
|
1450
2415
|
}
|
|
2416
|
+
const guidClause = guidSelector
|
|
2417
|
+
? ` WHERE ${ieTable}."guid"=${guidSelector}`
|
|
2418
|
+
: '';
|
|
1451
2419
|
if (options.return === 'count') {
|
|
1452
2420
|
if (limit || offset) {
|
|
1453
2421
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1454
2422
|
SELECT "guid"
|
|
1455
2423
|
FROM ${SQLite3Driver.escape(
|
|
1456
|
-
this.prefix + 'entities_' + etype
|
|
1457
|
-
)} ${ieTable}${limit}${offset}
|
|
2424
|
+
this.prefix + 'entities_' + etype,
|
|
2425
|
+
)} ${ieTable}${guidClause}${limit}${offset}
|
|
1458
2426
|
)`;
|
|
1459
2427
|
} else {
|
|
1460
2428
|
query = `SELECT COUNT("guid") AS "count"
|
|
1461
2429
|
FROM ${SQLite3Driver.escape(
|
|
1462
|
-
this.prefix + 'entities_' + etype
|
|
1463
|
-
)} ${ieTable}`;
|
|
2430
|
+
this.prefix + 'entities_' + etype,
|
|
2431
|
+
)} ${ieTable}${guidClause}`;
|
|
1464
2432
|
}
|
|
1465
2433
|
} else if (options.return === 'guid') {
|
|
1466
2434
|
query = `SELECT "guid"
|
|
1467
2435
|
FROM ${SQLite3Driver.escape(
|
|
1468
|
-
this.prefix + 'entities_' + etype
|
|
2436
|
+
this.prefix + 'entities_' + etype,
|
|
1469
2437
|
)} ${ieTable}
|
|
1470
|
-
|
|
2438
|
+
${sortJoin}
|
|
2439
|
+
${guidClause}
|
|
2440
|
+
${sortByInner ? sortByInner + ', ' : 'ORDER BY '}"guid"${limit}${offset}`;
|
|
1471
2441
|
} else {
|
|
1472
2442
|
if (limit || offset) {
|
|
1473
2443
|
query = `SELECT
|
|
@@ -1475,47 +2445,64 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1475
2445
|
${eTable}."tags",
|
|
1476
2446
|
${eTable}."cdate",
|
|
1477
2447
|
${eTable}."mdate",
|
|
2448
|
+
${eTable}."user",
|
|
2449
|
+
${eTable}."group",
|
|
2450
|
+
${eTable}."acUser",
|
|
2451
|
+
${eTable}."acGroup",
|
|
2452
|
+
${eTable}."acOther",
|
|
2453
|
+
${eTable}."acRead",
|
|
2454
|
+
${eTable}."acWrite",
|
|
2455
|
+
${eTable}."acFull",
|
|
1478
2456
|
${dTable}."name",
|
|
1479
2457
|
${dTable}."value",
|
|
1480
|
-
${
|
|
1481
|
-
${
|
|
2458
|
+
json(${dTable}."json") as "json",
|
|
2459
|
+
${dTable}."string",
|
|
2460
|
+
${dTable}."number"
|
|
1482
2461
|
FROM ${SQLite3Driver.escape(
|
|
1483
|
-
this.prefix + 'entities_' + etype
|
|
2462
|
+
this.prefix + 'entities_' + etype,
|
|
1484
2463
|
)} ${eTable}
|
|
1485
2464
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1486
|
-
this.prefix + 'data_' + etype
|
|
2465
|
+
this.prefix + 'data_' + etype,
|
|
1487
2466
|
)} ${dTable} USING ("guid")
|
|
1488
|
-
|
|
1489
|
-
this.prefix + 'comparisons_' + etype
|
|
1490
|
-
)} c USING ("guid", "name")
|
|
2467
|
+
${sortJoin}
|
|
1491
2468
|
INNER JOIN (
|
|
1492
2469
|
SELECT "guid"
|
|
1493
2470
|
FROM ${SQLite3Driver.escape(
|
|
1494
|
-
this.prefix + 'entities_' + etype
|
|
2471
|
+
this.prefix + 'entities_' + etype,
|
|
1495
2472
|
)} ${ieTable}
|
|
1496
|
-
|
|
2473
|
+
${sortJoin}
|
|
2474
|
+
${guidClause}
|
|
2475
|
+
${sortByInner}${limit}${offset}
|
|
1497
2476
|
) ${fTable} USING ("guid")
|
|
1498
|
-
ORDER BY ${eTable}
|
|
2477
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}."guid"`;
|
|
1499
2478
|
} else {
|
|
1500
2479
|
query = `SELECT
|
|
1501
2480
|
${eTable}."guid",
|
|
1502
2481
|
${eTable}."tags",
|
|
1503
2482
|
${eTable}."cdate",
|
|
1504
2483
|
${eTable}."mdate",
|
|
2484
|
+
${eTable}."user",
|
|
2485
|
+
${eTable}."group",
|
|
2486
|
+
${eTable}."acUser",
|
|
2487
|
+
${eTable}."acGroup",
|
|
2488
|
+
${eTable}."acOther",
|
|
2489
|
+
${eTable}."acRead",
|
|
2490
|
+
${eTable}."acWrite",
|
|
2491
|
+
${eTable}."acFull",
|
|
1505
2492
|
${dTable}."name",
|
|
1506
2493
|
${dTable}."value",
|
|
1507
|
-
${
|
|
1508
|
-
${
|
|
2494
|
+
json(${dTable}."json") as "json",
|
|
2495
|
+
${dTable}."string",
|
|
2496
|
+
${dTable}."number"
|
|
1509
2497
|
FROM ${SQLite3Driver.escape(
|
|
1510
|
-
this.prefix + 'entities_' + etype
|
|
2498
|
+
this.prefix + 'entities_' + etype,
|
|
1511
2499
|
)} ${eTable}
|
|
1512
2500
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1513
|
-
this.prefix + 'data_' + etype
|
|
2501
|
+
this.prefix + 'data_' + etype,
|
|
1514
2502
|
)} ${dTable} USING ("guid")
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
ORDER BY ${eTable}.${sortBy}`;
|
|
2503
|
+
${sortJoin}
|
|
2504
|
+
${guidSelector ? `WHERE ${eTable}."guid"=${guidSelector}` : ''}
|
|
2505
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}."guid"`;
|
|
1519
2506
|
}
|
|
1520
2507
|
}
|
|
1521
2508
|
}
|
|
@@ -1535,16 +2522,18 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1535
2522
|
protected performQuery(
|
|
1536
2523
|
options: Options,
|
|
1537
2524
|
formattedSelectors: FormattedSelector[],
|
|
1538
|
-
etype: string
|
|
2525
|
+
etype: string,
|
|
1539
2526
|
): {
|
|
1540
2527
|
result: any;
|
|
1541
2528
|
} {
|
|
1542
2529
|
const { query, params, etypes } = this.makeEntityQuery(
|
|
1543
2530
|
options,
|
|
1544
2531
|
formattedSelectors,
|
|
1545
|
-
etype
|
|
2532
|
+
etype,
|
|
1546
2533
|
);
|
|
1547
|
-
const result = this.
|
|
2534
|
+
const result = this.queryArray(query, { etypes, params })[
|
|
2535
|
+
Symbol.iterator
|
|
2536
|
+
]();
|
|
1548
2537
|
return {
|
|
1549
2538
|
result,
|
|
1550
2539
|
};
|
|
@@ -1559,37 +2548,24 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1559
2548
|
...selectors: Selector[]
|
|
1560
2549
|
): Promise<string[]>;
|
|
1561
2550
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1562
|
-
options
|
|
2551
|
+
options: Options<T> & { return: 'object' },
|
|
1563
2552
|
...selectors: Selector[]
|
|
1564
|
-
): Promise<
|
|
2553
|
+
): Promise<EntityObjectType<T>[]>;
|
|
1565
2554
|
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
2555
|
options?: Options<T>,
|
|
1582
2556
|
...selectors: Selector[]
|
|
1583
|
-
):
|
|
1584
|
-
|
|
2557
|
+
): Promise<EntityInstanceType<T>[]>;
|
|
2558
|
+
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1585
2559
|
options: Options<T> = {},
|
|
1586
2560
|
...selectors: Selector[]
|
|
1587
|
-
):
|
|
1588
|
-
|
|
2561
|
+
): Promise<
|
|
2562
|
+
EntityInstanceType<T>[] | EntityObjectType<T>[] | string[] | number
|
|
2563
|
+
> {
|
|
2564
|
+
const { result, process } = this.getEntitiesRowLike<T>(
|
|
1589
2565
|
options,
|
|
1590
2566
|
selectors,
|
|
1591
|
-
(options,
|
|
1592
|
-
this.performQuery(options,
|
|
2567
|
+
({ options, selectors, etype }) =>
|
|
2568
|
+
this.performQuery(options, selectors, etype),
|
|
1593
2569
|
() => {
|
|
1594
2570
|
const next: any = result.next();
|
|
1595
2571
|
return next.done ? null : next.value;
|
|
@@ -1598,9 +2574,23 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1598
2574
|
(row) => Number(row.count),
|
|
1599
2575
|
(row) => row.guid,
|
|
1600
2576
|
(row) => ({
|
|
1601
|
-
tags:
|
|
2577
|
+
tags:
|
|
2578
|
+
row.tags.length > 2
|
|
2579
|
+
? row.tags
|
|
2580
|
+
.slice(1, -1)
|
|
2581
|
+
.split(',')
|
|
2582
|
+
.filter((tag: string) => tag)
|
|
2583
|
+
: [],
|
|
1602
2584
|
cdate: Number(row.cdate),
|
|
1603
2585
|
mdate: Number(row.mdate),
|
|
2586
|
+
user: row.user,
|
|
2587
|
+
group: row.group,
|
|
2588
|
+
acUser: row.acUser,
|
|
2589
|
+
acGroup: row.acGroup,
|
|
2590
|
+
acOther: row.acOther,
|
|
2591
|
+
acRead: row.acRead?.slice(1, -1).split(',') ?? [],
|
|
2592
|
+
acWrite: row.acWrite?.slice(1, -1).split(',') ?? [],
|
|
2593
|
+
acFull: row.acFull?.slice(1, -1).split(',') ?? [],
|
|
1604
2594
|
}),
|
|
1605
2595
|
(row) => ({
|
|
1606
2596
|
name: row.name,
|
|
@@ -1608,9 +2598,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1608
2598
|
row.value === 'N'
|
|
1609
2599
|
? JSON.stringify(row.number)
|
|
1610
2600
|
: row.value === 'S'
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
2601
|
+
? JSON.stringify(row.string)
|
|
2602
|
+
: row.value === 'J'
|
|
2603
|
+
? row.json
|
|
2604
|
+
: row.value,
|
|
2605
|
+
}),
|
|
1614
2606
|
);
|
|
1615
2607
|
const value = process();
|
|
1616
2608
|
if (value instanceof Error) {
|
|
@@ -1623,175 +2615,355 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1623
2615
|
if (name == null) {
|
|
1624
2616
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1625
2617
|
}
|
|
1626
|
-
const result = this.queryGet(
|
|
2618
|
+
const result: any = this.queryGet(
|
|
1627
2619
|
`SELECT "cur_uid" FROM ${SQLite3Driver.escape(
|
|
1628
|
-
`${this.prefix}uids
|
|
2620
|
+
`${this.prefix}uids`,
|
|
1629
2621
|
)} WHERE "name"=@name;`,
|
|
1630
2622
|
{
|
|
1631
2623
|
params: {
|
|
1632
2624
|
name: name,
|
|
1633
2625
|
},
|
|
1634
|
-
}
|
|
2626
|
+
},
|
|
1635
2627
|
);
|
|
1636
2628
|
return (result?.cur_uid as number | null) ?? null;
|
|
1637
2629
|
}
|
|
1638
2630
|
|
|
1639
|
-
public async
|
|
1640
|
-
|
|
2631
|
+
public async importEntity(entity: {
|
|
2632
|
+
guid: string;
|
|
2633
|
+
cdate: number;
|
|
2634
|
+
mdate: number;
|
|
2635
|
+
tags: string[];
|
|
2636
|
+
sdata: SerializedEntityData;
|
|
2637
|
+
etype: string;
|
|
2638
|
+
}) {
|
|
2639
|
+
return await this.importEntityInternal(entity);
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
public async importEntityTokens(entity: {
|
|
2643
|
+
guid: string;
|
|
2644
|
+
cdate: number;
|
|
2645
|
+
mdate: number;
|
|
2646
|
+
tags: string[];
|
|
2647
|
+
sdata: SerializedEntityData;
|
|
2648
|
+
etype: string;
|
|
2649
|
+
}) {
|
|
2650
|
+
return await this.importEntityInternal(entity, { only: 'tokens' });
|
|
2651
|
+
}
|
|
2652
|
+
|
|
2653
|
+
public async importEntityTilmeldAC(entity: {
|
|
2654
|
+
guid: string;
|
|
2655
|
+
cdate: number;
|
|
2656
|
+
mdate: number;
|
|
2657
|
+
tags: string[];
|
|
2658
|
+
sdata: SerializedEntityData;
|
|
2659
|
+
etype: string;
|
|
2660
|
+
}) {
|
|
2661
|
+
return await this.importEntityInternal(entity, { only: 'tilmeldAC' });
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
private async importEntityInternal(
|
|
2665
|
+
{
|
|
2666
|
+
guid,
|
|
2667
|
+
cdate,
|
|
2668
|
+
mdate,
|
|
2669
|
+
tags,
|
|
2670
|
+
sdata,
|
|
2671
|
+
etype,
|
|
2672
|
+
}: {
|
|
2673
|
+
guid: string;
|
|
2674
|
+
cdate: number;
|
|
2675
|
+
mdate: number;
|
|
2676
|
+
tags: string[];
|
|
2677
|
+
sdata: SerializedEntityData;
|
|
2678
|
+
etype: string;
|
|
2679
|
+
},
|
|
2680
|
+
{ only = undefined }: { only?: 'tokens' | 'tilmeldAC' } = {},
|
|
2681
|
+
) {
|
|
1641
2682
|
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
|
-
|
|
2683
|
+
if (only == null) {
|
|
2684
|
+
this.queryRun(
|
|
2685
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2686
|
+
`${this.prefix}entities_${etype}`,
|
|
2687
|
+
)} WHERE "guid"=@guid;`,
|
|
2688
|
+
{
|
|
2689
|
+
etypes: [etype],
|
|
2690
|
+
params: {
|
|
2691
|
+
guid,
|
|
2692
|
+
},
|
|
2693
|
+
},
|
|
2694
|
+
);
|
|
2695
|
+
this.queryRun(
|
|
2696
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2697
|
+
`${this.prefix}data_${etype}`,
|
|
2698
|
+
)} WHERE "guid"=@guid;`,
|
|
2699
|
+
{
|
|
2700
|
+
etypes: [etype],
|
|
2701
|
+
params: {
|
|
2702
|
+
guid,
|
|
2703
|
+
},
|
|
2704
|
+
},
|
|
2705
|
+
);
|
|
2706
|
+
this.queryRun(
|
|
2707
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2708
|
+
`${this.prefix}references_${etype}`,
|
|
2709
|
+
)} WHERE "guid"=@guid;`,
|
|
2710
|
+
{
|
|
2711
|
+
etypes: [etype],
|
|
2712
|
+
params: {
|
|
2713
|
+
guid,
|
|
2714
|
+
},
|
|
2715
|
+
},
|
|
2716
|
+
);
|
|
2717
|
+
}
|
|
2718
|
+
if (only == null || only === 'tokens') {
|
|
2719
|
+
this.queryRun(
|
|
2720
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2721
|
+
`${this.prefix}tokens_${etype}`,
|
|
2722
|
+
)} WHERE "guid"=@guid;`,
|
|
2723
|
+
{
|
|
2724
|
+
etypes: [etype],
|
|
2725
|
+
params: {
|
|
2726
|
+
guid,
|
|
2727
|
+
},
|
|
2728
|
+
},
|
|
2729
|
+
);
|
|
2730
|
+
}
|
|
2731
|
+
if (only == null) {
|
|
2732
|
+
this.queryRun(
|
|
2733
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2734
|
+
`${this.prefix}uniques_${etype}`,
|
|
2735
|
+
)} WHERE "guid"=@guid;`,
|
|
2736
|
+
{
|
|
2737
|
+
etypes: [etype],
|
|
2738
|
+
params: {
|
|
2739
|
+
guid,
|
|
2740
|
+
},
|
|
2741
|
+
},
|
|
2742
|
+
);
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
if (only == null) {
|
|
2746
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull } =
|
|
2747
|
+
this.removeAndReturnACValues(etype, {}, sdata);
|
|
2748
|
+
|
|
2749
|
+
this.queryRun(
|
|
2750
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2751
|
+
`${this.prefix}entities_${etype}`,
|
|
2752
|
+
)} ("guid", "tags", "cdate", "mdate", "user", "group", "acUser", "acGroup", "acOther", "acRead", "acWrite", "acFull") VALUES (@guid, @tags, @cdate, @mdate, @user, @group, @acUser, @acGroup, @acOther, @acRead, @acWrite, @acFull);`,
|
|
2753
|
+
{
|
|
2754
|
+
etypes: [etype],
|
|
2755
|
+
params: {
|
|
2756
|
+
guid,
|
|
2757
|
+
tags: ',' + tags.join(',') + ',',
|
|
2758
|
+
cdate,
|
|
2759
|
+
mdate,
|
|
2760
|
+
user,
|
|
2761
|
+
group,
|
|
2762
|
+
acUser,
|
|
2763
|
+
acGroup,
|
|
2764
|
+
acOther,
|
|
2765
|
+
acRead: acRead && ',' + acRead.join(',') + ',',
|
|
2766
|
+
acWrite: acWrite && ',' + acWrite.join(',') + ',',
|
|
2767
|
+
acFull: acFull && ',' + acFull.join(',') + ',',
|
|
2768
|
+
},
|
|
2769
|
+
},
|
|
2770
|
+
);
|
|
2771
|
+
|
|
2772
|
+
for (const name in sdata) {
|
|
2773
|
+
const value = sdata[name];
|
|
2774
|
+
const uvalue = JSON.parse(value);
|
|
2775
|
+
if (value === undefined) {
|
|
2776
|
+
continue;
|
|
2777
|
+
}
|
|
2778
|
+
const storageValue =
|
|
2779
|
+
typeof uvalue === 'number'
|
|
2780
|
+
? 'N'
|
|
2781
|
+
: typeof uvalue === 'string'
|
|
2782
|
+
? 'S'
|
|
2783
|
+
: 'J';
|
|
2784
|
+
const jsonValue = storageValue === 'J' ? value : null;
|
|
2785
|
+
|
|
1689
2786
|
this.queryRun(
|
|
1690
2787
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1691
|
-
`${this.prefix}
|
|
1692
|
-
)} ("guid", "
|
|
2788
|
+
`${this.prefix}data_${etype}`,
|
|
2789
|
+
)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (@guid, @name, @storageValue, jsonb(@jsonValue), @string, @number, @truthy);`,
|
|
1693
2790
|
{
|
|
1694
2791
|
etypes: [etype],
|
|
1695
2792
|
params: {
|
|
1696
2793
|
guid,
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
2794
|
+
name,
|
|
2795
|
+
storageValue,
|
|
2796
|
+
jsonValue,
|
|
2797
|
+
string: storageValue === 'J' ? null : `${uvalue}`,
|
|
2798
|
+
number: Number(uvalue),
|
|
2799
|
+
truthy: uvalue ? 1 : 0,
|
|
1700
2800
|
},
|
|
1701
|
-
}
|
|
2801
|
+
},
|
|
1702
2802
|
);
|
|
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;
|
|
2803
|
+
|
|
2804
|
+
const references = this.findReferences(value);
|
|
2805
|
+
for (const reference of references) {
|
|
1717
2806
|
this.queryRun(
|
|
1718
2807
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1719
|
-
`${this.prefix}
|
|
1720
|
-
)} ("guid", "name", "
|
|
2808
|
+
`${this.prefix}references_${etype}`,
|
|
2809
|
+
)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`,
|
|
1721
2810
|
{
|
|
1722
2811
|
etypes: [etype],
|
|
1723
2812
|
params: {
|
|
1724
2813
|
guid,
|
|
1725
2814
|
name,
|
|
1726
|
-
|
|
2815
|
+
reference,
|
|
1727
2816
|
},
|
|
1728
|
-
}
|
|
2817
|
+
},
|
|
1729
2818
|
);
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
if (only === 'tilmeldAC') {
|
|
2824
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull } =
|
|
2825
|
+
this.removeAndReturnACValues(etype, {}, sdata);
|
|
2826
|
+
|
|
2827
|
+
this.queryRun(
|
|
2828
|
+
`UPDATE OR IGNORE ${SQLite3Driver.escape(
|
|
2829
|
+
`${this.prefix}entities_${etype}`,
|
|
2830
|
+
)} SET "user"=@user, "group"=@group, "acUser"=@acUser, "acGroup"=@acGroup, "acOther"=@acOther, "acRead"=@acRead, "acWrite"=@acWrite, "acFull"=@acFull WHERE "guid"=@guid;`,
|
|
2831
|
+
{
|
|
2832
|
+
etypes: [etype],
|
|
2833
|
+
params: {
|
|
2834
|
+
user,
|
|
2835
|
+
group,
|
|
2836
|
+
acUser,
|
|
2837
|
+
acGroup,
|
|
2838
|
+
acOther,
|
|
2839
|
+
acRead: acRead && ',' + acRead.join(',') + ',',
|
|
2840
|
+
acWrite: acWrite && ',' + acWrite.join(',') + ',',
|
|
2841
|
+
acFull: acFull && ',' + acFull.join(',') + ',',
|
|
2842
|
+
guid,
|
|
2843
|
+
},
|
|
2844
|
+
},
|
|
2845
|
+
);
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
2849
|
+
|
|
2850
|
+
if (only == null || only === 'tokens') {
|
|
2851
|
+
for (let name in sdata) {
|
|
2852
|
+
let tokenString: string | null = null;
|
|
2853
|
+
try {
|
|
2854
|
+
tokenString = EntityClass.getFTSText(name, JSON.parse(sdata[name]));
|
|
2855
|
+
} catch (e: any) {
|
|
2856
|
+
// Ignore error.
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
if (tokenString != null) {
|
|
2860
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
2861
|
+
while (tokens.length) {
|
|
2862
|
+
const currentTokens = tokens.splice(0, 100);
|
|
2863
|
+
const params: { [k: string]: any } = {
|
|
2864
|
+
guid,
|
|
2865
|
+
name,
|
|
2866
|
+
};
|
|
2867
|
+
const values: string[] = [];
|
|
2868
|
+
|
|
2869
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
2870
|
+
const token = currentTokens[i];
|
|
2871
|
+
params['token' + i] = token.token;
|
|
2872
|
+
params['position' + i] = token.position;
|
|
2873
|
+
params['stem' + i] = token.stem ? 1 : 0;
|
|
2874
|
+
values.push(
|
|
2875
|
+
'(@guid, @name, @token' +
|
|
2876
|
+
i +
|
|
2877
|
+
', @position' +
|
|
2878
|
+
i +
|
|
2879
|
+
', @stem' +
|
|
2880
|
+
i +
|
|
2881
|
+
')',
|
|
2882
|
+
);
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
this.queryRun(
|
|
2886
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2887
|
+
`${this.prefix}tokens_${etype}`,
|
|
2888
|
+
)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`,
|
|
2889
|
+
{
|
|
2890
|
+
etypes: [etype],
|
|
2891
|
+
params,
|
|
2892
|
+
},
|
|
2893
|
+
);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
if (only == null) {
|
|
2900
|
+
const uniques = await EntityClass.getUniques({
|
|
2901
|
+
guid,
|
|
2902
|
+
cdate,
|
|
2903
|
+
mdate,
|
|
2904
|
+
tags,
|
|
2905
|
+
data: {},
|
|
2906
|
+
sdata,
|
|
2907
|
+
});
|
|
2908
|
+
for (const unique of uniques) {
|
|
2909
|
+
try {
|
|
1730
2910
|
this.queryRun(
|
|
1731
2911
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1732
|
-
`${this.prefix}
|
|
1733
|
-
)} ("guid", "
|
|
2912
|
+
`${this.prefix}uniques_${etype}`,
|
|
2913
|
+
)} ("guid", "unique") VALUES (@guid, @unique);`,
|
|
1734
2914
|
{
|
|
1735
2915
|
etypes: [etype],
|
|
1736
2916
|
params: {
|
|
1737
2917
|
guid,
|
|
1738
|
-
|
|
1739
|
-
truthy: uvalue ? 1 : 0,
|
|
1740
|
-
string: `${uvalue}`,
|
|
1741
|
-
number: Number(uvalue),
|
|
2918
|
+
unique,
|
|
1742
2919
|
},
|
|
1743
|
-
}
|
|
2920
|
+
},
|
|
1744
2921
|
);
|
|
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
|
-
}
|
|
2922
|
+
} catch (e: any) {
|
|
2923
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2924
|
+
this.nymph.config.debugError(
|
|
2925
|
+
'sqlite3',
|
|
2926
|
+
`Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`,
|
|
1759
2927
|
);
|
|
1760
2928
|
}
|
|
2929
|
+
throw e;
|
|
1761
2930
|
}
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
} catch (e: any) {
|
|
2934
|
+
this.nymph.config.debugError('sqlite3', `Import entity error: "${e}"`);
|
|
2935
|
+
throw e;
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
public async importUID({ name, value }: { name: string; value: number }) {
|
|
2940
|
+
try {
|
|
2941
|
+
await this.startTransaction(`nymph-import-uid-${name}`);
|
|
2942
|
+
this.queryRun(
|
|
2943
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2944
|
+
`${this.prefix}uids`,
|
|
2945
|
+
)} WHERE "name"=@name;`,
|
|
2946
|
+
{
|
|
2947
|
+
params: {
|
|
2948
|
+
name,
|
|
2949
|
+
},
|
|
1762
2950
|
},
|
|
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');
|
|
2951
|
+
);
|
|
2952
|
+
this.queryRun(
|
|
2953
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2954
|
+
`${this.prefix}uids`,
|
|
2955
|
+
)} ("name", "cur_uid") VALUES (@name, @value);`,
|
|
2956
|
+
{
|
|
2957
|
+
params: {
|
|
2958
|
+
name,
|
|
2959
|
+
value,
|
|
2960
|
+
},
|
|
1788
2961
|
},
|
|
1789
|
-
async () => {
|
|
1790
|
-
await this.commit('nymph-import');
|
|
1791
|
-
}
|
|
1792
2962
|
);
|
|
2963
|
+
await this.commit(`nymph-import-uid-${name}`);
|
|
1793
2964
|
} catch (e: any) {
|
|
1794
|
-
|
|
2965
|
+
this.nymph.config.debugError('sqlite3', `Import UID error: "${e}"`);
|
|
2966
|
+
await this.rollback(`nymph-import-uid-${name}`);
|
|
1795
2967
|
throw e;
|
|
1796
2968
|
}
|
|
1797
2969
|
}
|
|
@@ -1800,78 +2972,83 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1800
2972
|
if (name == null) {
|
|
1801
2973
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1802
2974
|
}
|
|
1803
|
-
this.checkReadOnlyMode();
|
|
1804
2975
|
await this.startTransaction('nymph-newuid');
|
|
2976
|
+
let curUid: number | undefined = undefined;
|
|
1805
2977
|
try {
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
2978
|
+
curUid =
|
|
2979
|
+
(
|
|
2980
|
+
this.queryGet(
|
|
2981
|
+
`SELECT "cur_uid" FROM ${SQLite3Driver.escape(
|
|
2982
|
+
`${this.prefix}uids`,
|
|
2983
|
+
)} WHERE "name"=@name;`,
|
|
2984
|
+
{
|
|
2985
|
+
params: {
|
|
2986
|
+
name,
|
|
2987
|
+
},
|
|
1814
2988
|
},
|
|
1815
|
-
|
|
2989
|
+
) as any
|
|
1816
2990
|
)?.cur_uid ?? null;
|
|
1817
2991
|
if (curUid == null) {
|
|
1818
2992
|
curUid = 1;
|
|
1819
2993
|
this.queryRun(
|
|
1820
2994
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1821
|
-
`${this.prefix}uids
|
|
2995
|
+
`${this.prefix}uids`,
|
|
1822
2996
|
)} ("name", "cur_uid") VALUES (@name, @curUid);`,
|
|
1823
2997
|
{
|
|
1824
2998
|
params: {
|
|
1825
2999
|
name,
|
|
1826
3000
|
curUid,
|
|
1827
3001
|
},
|
|
1828
|
-
}
|
|
3002
|
+
},
|
|
1829
3003
|
);
|
|
1830
3004
|
} else {
|
|
1831
3005
|
curUid++;
|
|
1832
3006
|
this.queryRun(
|
|
1833
3007
|
`UPDATE ${SQLite3Driver.escape(
|
|
1834
|
-
`${this.prefix}uids
|
|
3008
|
+
`${this.prefix}uids`,
|
|
1835
3009
|
)} SET "cur_uid"=@curUid WHERE "name"=@name;`,
|
|
1836
3010
|
{
|
|
1837
3011
|
params: {
|
|
1838
3012
|
curUid,
|
|
1839
3013
|
name,
|
|
1840
3014
|
},
|
|
1841
|
-
}
|
|
3015
|
+
},
|
|
1842
3016
|
);
|
|
1843
3017
|
}
|
|
1844
|
-
await this.commit('nymph-newuid');
|
|
1845
|
-
return curUid as number;
|
|
1846
3018
|
} catch (e: any) {
|
|
3019
|
+
this.nymph.config.debugError('sqlite3', `New UID error: "${e}"`);
|
|
1847
3020
|
await this.rollback('nymph-newuid');
|
|
1848
3021
|
throw e;
|
|
1849
3022
|
}
|
|
3023
|
+
|
|
3024
|
+
await this.commit('nymph-newuid');
|
|
3025
|
+
return curUid as number;
|
|
1850
3026
|
}
|
|
1851
3027
|
|
|
1852
3028
|
public async renameUID(oldName: string, newName: string) {
|
|
1853
3029
|
if (oldName == null || newName == null) {
|
|
1854
3030
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1855
3031
|
}
|
|
1856
|
-
this.
|
|
3032
|
+
await this.startTransaction('nymph-rename-uid');
|
|
1857
3033
|
this.queryRun(
|
|
1858
3034
|
`UPDATE ${SQLite3Driver.escape(
|
|
1859
|
-
`${this.prefix}uids
|
|
3035
|
+
`${this.prefix}uids`,
|
|
1860
3036
|
)} SET "name"=@newName WHERE "name"=@oldName;`,
|
|
1861
3037
|
{
|
|
1862
3038
|
params: {
|
|
1863
3039
|
newName,
|
|
1864
3040
|
oldName,
|
|
1865
3041
|
},
|
|
1866
|
-
}
|
|
3042
|
+
},
|
|
1867
3043
|
);
|
|
3044
|
+
await this.commit('nymph-rename-uid');
|
|
1868
3045
|
return true;
|
|
1869
3046
|
}
|
|
1870
3047
|
|
|
1871
3048
|
public async rollback(name: string) {
|
|
1872
3049
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1873
3050
|
throw new InvalidParametersError(
|
|
1874
|
-
'Transaction rollback attempted without a name.'
|
|
3051
|
+
'Transaction rollback attempted without a name.',
|
|
1875
3052
|
);
|
|
1876
3053
|
}
|
|
1877
3054
|
if (this.store.transactionsStarted === 0) {
|
|
@@ -1879,17 +3056,30 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1879
3056
|
}
|
|
1880
3057
|
this.queryRun(`ROLLBACK TO SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
1881
3058
|
this.store.transactionsStarted--;
|
|
3059
|
+
|
|
3060
|
+
if (
|
|
3061
|
+
this.store.transactionsStarted === 0 &&
|
|
3062
|
+
this.store.linkWrite &&
|
|
3063
|
+
!this.config.explicitWrite
|
|
3064
|
+
) {
|
|
3065
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
3066
|
+
this.store.linkWrite.close();
|
|
3067
|
+
this.store.linkWrite = undefined;
|
|
3068
|
+
}
|
|
3069
|
+
|
|
1882
3070
|
return true;
|
|
1883
3071
|
}
|
|
1884
3072
|
|
|
1885
3073
|
public async saveEntity(entity: EntityInterface) {
|
|
1886
|
-
this.checkReadOnlyMode();
|
|
1887
3074
|
const insertData = (
|
|
1888
3075
|
guid: string,
|
|
1889
3076
|
data: EntityData,
|
|
1890
3077
|
sdata: SerializedEntityData,
|
|
1891
|
-
|
|
3078
|
+
uniques: string[],
|
|
3079
|
+
etype: string,
|
|
1892
3080
|
) => {
|
|
3081
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
3082
|
+
|
|
1893
3083
|
const runInsertQuery = (name: string, value: any, svalue: string) => {
|
|
1894
3084
|
if (value === undefined) {
|
|
1895
3085
|
return;
|
|
@@ -1898,41 +3088,33 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1898
3088
|
typeof value === 'number'
|
|
1899
3089
|
? 'N'
|
|
1900
3090
|
: typeof value === 'string'
|
|
1901
|
-
|
|
1902
|
-
|
|
3091
|
+
? 'S'
|
|
3092
|
+
: 'J';
|
|
3093
|
+
const jsonValue = storageValue === 'J' ? svalue : null;
|
|
3094
|
+
|
|
1903
3095
|
this.queryRun(
|
|
1904
3096
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1905
|
-
`${this.prefix}data_${etype}
|
|
1906
|
-
)} ("guid", "name", "value") VALUES (@guid, @name, @storageValue);`,
|
|
3097
|
+
`${this.prefix}data_${etype}`,
|
|
3098
|
+
)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (@guid, @name, @storageValue, jsonb(@jsonValue), @string, @number, @truthy);`,
|
|
1907
3099
|
{
|
|
1908
3100
|
etypes: [etype],
|
|
1909
3101
|
params: {
|
|
1910
3102
|
guid,
|
|
1911
3103
|
name,
|
|
1912
3104
|
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}`,
|
|
3105
|
+
jsonValue,
|
|
3106
|
+
string: storageValue === 'J' ? null : `${value}`,
|
|
1927
3107
|
number: Number(value),
|
|
3108
|
+
truthy: value ? 1 : 0,
|
|
1928
3109
|
},
|
|
1929
|
-
}
|
|
3110
|
+
},
|
|
1930
3111
|
);
|
|
3112
|
+
|
|
1931
3113
|
const references = this.findReferences(svalue);
|
|
1932
3114
|
for (const reference of references) {
|
|
1933
3115
|
this.queryRun(
|
|
1934
3116
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1935
|
-
`${this.prefix}references_${etype}
|
|
3117
|
+
`${this.prefix}references_${etype}`,
|
|
1936
3118
|
)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`,
|
|
1937
3119
|
{
|
|
1938
3120
|
etypes: [etype],
|
|
@@ -1941,10 +3123,80 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1941
3123
|
name,
|
|
1942
3124
|
reference,
|
|
1943
3125
|
},
|
|
1944
|
-
}
|
|
3126
|
+
},
|
|
1945
3127
|
);
|
|
1946
3128
|
}
|
|
3129
|
+
|
|
3130
|
+
let tokenString: string | null = null;
|
|
3131
|
+
try {
|
|
3132
|
+
tokenString = EntityClass.getFTSText(name, value);
|
|
3133
|
+
} catch (e: any) {
|
|
3134
|
+
// Ignore error.
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
if (tokenString != null) {
|
|
3138
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
3139
|
+
while (tokens.length) {
|
|
3140
|
+
const currentTokens = tokens.splice(0, 100);
|
|
3141
|
+
const params: { [k: string]: any } = {
|
|
3142
|
+
guid,
|
|
3143
|
+
name,
|
|
3144
|
+
};
|
|
3145
|
+
const values: string[] = [];
|
|
3146
|
+
|
|
3147
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
3148
|
+
const token = currentTokens[i];
|
|
3149
|
+
params['token' + i] = token.token;
|
|
3150
|
+
params['position' + i] = token.position;
|
|
3151
|
+
params['stem' + i] = token.stem ? 1 : 0;
|
|
3152
|
+
values.push(
|
|
3153
|
+
'(@guid, @name, @token' +
|
|
3154
|
+
i +
|
|
3155
|
+
', @position' +
|
|
3156
|
+
i +
|
|
3157
|
+
', @stem' +
|
|
3158
|
+
i +
|
|
3159
|
+
')',
|
|
3160
|
+
);
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
this.queryRun(
|
|
3164
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
3165
|
+
`${this.prefix}tokens_${etype}`,
|
|
3166
|
+
)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`,
|
|
3167
|
+
{
|
|
3168
|
+
etypes: [etype],
|
|
3169
|
+
params,
|
|
3170
|
+
},
|
|
3171
|
+
);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
1947
3174
|
};
|
|
3175
|
+
|
|
3176
|
+
for (const unique of uniques) {
|
|
3177
|
+
try {
|
|
3178
|
+
this.queryRun(
|
|
3179
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
3180
|
+
`${this.prefix}uniques_${etype}`,
|
|
3181
|
+
)} ("guid", "unique") VALUES (@guid, @unique);`,
|
|
3182
|
+
{
|
|
3183
|
+
etypes: [etype],
|
|
3184
|
+
params: {
|
|
3185
|
+
guid,
|
|
3186
|
+
unique,
|
|
3187
|
+
},
|
|
3188
|
+
},
|
|
3189
|
+
);
|
|
3190
|
+
} catch (e: any) {
|
|
3191
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
3192
|
+
this.nymph.config.debugError(
|
|
3193
|
+
'sqlite3',
|
|
3194
|
+
`Save entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`,
|
|
3195
|
+
);
|
|
3196
|
+
}
|
|
3197
|
+
throw e;
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
1948
3200
|
for (const name in data) {
|
|
1949
3201
|
runInsertQuery(name, data[name], JSON.stringify(data[name]));
|
|
1950
3202
|
}
|
|
@@ -1952,95 +3204,162 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1952
3204
|
runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
|
|
1953
3205
|
}
|
|
1954
3206
|
};
|
|
3207
|
+
let inTransaction = false;
|
|
1955
3208
|
try {
|
|
1956
3209
|
return this.saveEntityRowLike(
|
|
1957
3210
|
entity,
|
|
1958
|
-
async (
|
|
3211
|
+
async ({ guid, tags, data, sdata, uniques, cdate, etype }) => {
|
|
3212
|
+
if (
|
|
3213
|
+
Object.keys(data).length === 0 &&
|
|
3214
|
+
Object.keys(sdata).length === 0
|
|
3215
|
+
) {
|
|
3216
|
+
return false;
|
|
3217
|
+
}
|
|
3218
|
+
let {
|
|
3219
|
+
user,
|
|
3220
|
+
group,
|
|
3221
|
+
acUser,
|
|
3222
|
+
acGroup,
|
|
3223
|
+
acOther,
|
|
3224
|
+
acRead,
|
|
3225
|
+
acWrite,
|
|
3226
|
+
acFull,
|
|
3227
|
+
} = this.removeAndReturnACValues(etype, data, sdata);
|
|
1959
3228
|
this.queryRun(
|
|
1960
3229
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1961
|
-
`${this.prefix}entities_${etype}
|
|
1962
|
-
)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @cdate);`,
|
|
3230
|
+
`${this.prefix}entities_${etype}`,
|
|
3231
|
+
)} ("guid", "tags", "cdate", "mdate", "user", "group", "acUser", "acGroup", "acOther", "acRead", "acWrite", "acFull") VALUES (@guid, @tags, @cdate, @cdate, @user, @group, @acUser, @acGroup, @acOther, @acRead, @acWrite, @acFull);`,
|
|
1963
3232
|
{
|
|
1964
3233
|
etypes: [etype],
|
|
1965
3234
|
params: {
|
|
1966
3235
|
guid,
|
|
1967
3236
|
tags: ',' + tags.join(',') + ',',
|
|
1968
3237
|
cdate,
|
|
3238
|
+
user,
|
|
3239
|
+
group,
|
|
3240
|
+
acUser,
|
|
3241
|
+
acGroup,
|
|
3242
|
+
acOther,
|
|
3243
|
+
acRead: acRead && ',' + acRead.join(',') + ',',
|
|
3244
|
+
acWrite: acWrite && ',' + acWrite.join(',') + ',',
|
|
3245
|
+
acFull: acFull && ',' + acFull.join(',') + ',',
|
|
1969
3246
|
},
|
|
1970
|
-
}
|
|
3247
|
+
},
|
|
1971
3248
|
);
|
|
1972
|
-
insertData(guid, data, sdata, etype);
|
|
3249
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
1973
3250
|
return true;
|
|
1974
3251
|
},
|
|
1975
|
-
async (entity, guid, tags, data, sdata, mdate, etype) => {
|
|
3252
|
+
async ({ entity, guid, tags, data, sdata, uniques, mdate, etype }) => {
|
|
3253
|
+
if (
|
|
3254
|
+
Object.keys(data).length === 0 &&
|
|
3255
|
+
Object.keys(sdata).length === 0
|
|
3256
|
+
) {
|
|
3257
|
+
return false;
|
|
3258
|
+
}
|
|
3259
|
+
let {
|
|
3260
|
+
user,
|
|
3261
|
+
group,
|
|
3262
|
+
acUser,
|
|
3263
|
+
acGroup,
|
|
3264
|
+
acOther,
|
|
3265
|
+
acRead,
|
|
3266
|
+
acWrite,
|
|
3267
|
+
acFull,
|
|
3268
|
+
} = this.removeAndReturnACValues(etype, data, sdata);
|
|
1976
3269
|
const info = this.queryRun(
|
|
1977
3270
|
`UPDATE ${SQLite3Driver.escape(
|
|
1978
|
-
`${this.prefix}entities_${etype}
|
|
1979
|
-
)} SET "tags"=@tags, "mdate"=@mdate WHERE "guid"=@guid AND "mdate" <= @emdate;`,
|
|
3271
|
+
`${this.prefix}entities_${etype}`,
|
|
3272
|
+
)} SET "tags"=@tags, "mdate"=@mdate, "user"=@user, "group"=@group, "acUser"=@acUser, "acGroup"=@acGroup, "acOther"=@acOther, "acRead"=@acRead, "acWrite"=@acWrite, "acFull"=@acFull WHERE "guid"=@guid AND "mdate" <= @emdate;`,
|
|
1980
3273
|
{
|
|
1981
3274
|
etypes: [etype],
|
|
1982
3275
|
params: {
|
|
1983
3276
|
tags: ',' + tags.join(',') + ',',
|
|
1984
3277
|
mdate,
|
|
3278
|
+
user,
|
|
3279
|
+
group,
|
|
3280
|
+
acUser,
|
|
3281
|
+
acGroup,
|
|
3282
|
+
acOther,
|
|
3283
|
+
acRead: acRead && ',' + acRead.join(',') + ',',
|
|
3284
|
+
acWrite: acWrite && ',' + acWrite.join(',') + ',',
|
|
3285
|
+
acFull: acFull && ',' + acFull.join(',') + ',',
|
|
1985
3286
|
guid,
|
|
1986
3287
|
emdate: Number(entity.mdate),
|
|
1987
3288
|
},
|
|
1988
|
-
}
|
|
3289
|
+
},
|
|
1989
3290
|
);
|
|
1990
3291
|
let success = false;
|
|
1991
3292
|
if (info.changes === 1) {
|
|
1992
3293
|
this.queryRun(
|
|
1993
3294
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
1994
|
-
`${this.prefix}data_${etype}
|
|
3295
|
+
`${this.prefix}data_${etype}`,
|
|
1995
3296
|
)} WHERE "guid"=@guid;`,
|
|
1996
3297
|
{
|
|
1997
3298
|
etypes: [etype],
|
|
1998
3299
|
params: {
|
|
1999
3300
|
guid,
|
|
2000
3301
|
},
|
|
2001
|
-
}
|
|
3302
|
+
},
|
|
2002
3303
|
);
|
|
2003
3304
|
this.queryRun(
|
|
2004
3305
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2005
|
-
`${this.prefix}
|
|
3306
|
+
`${this.prefix}references_${etype}`,
|
|
2006
3307
|
)} WHERE "guid"=@guid;`,
|
|
2007
3308
|
{
|
|
2008
3309
|
etypes: [etype],
|
|
2009
3310
|
params: {
|
|
2010
3311
|
guid,
|
|
2011
3312
|
},
|
|
2012
|
-
}
|
|
3313
|
+
},
|
|
2013
3314
|
);
|
|
2014
3315
|
this.queryRun(
|
|
2015
3316
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2016
|
-
`${this.prefix}
|
|
3317
|
+
`${this.prefix}tokens_${etype}`,
|
|
2017
3318
|
)} WHERE "guid"=@guid;`,
|
|
2018
3319
|
{
|
|
2019
3320
|
etypes: [etype],
|
|
2020
3321
|
params: {
|
|
2021
3322
|
guid,
|
|
2022
3323
|
},
|
|
2023
|
-
}
|
|
3324
|
+
},
|
|
3325
|
+
);
|
|
3326
|
+
this.queryRun(
|
|
3327
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
3328
|
+
`${this.prefix}uniques_${etype}`,
|
|
3329
|
+
)} WHERE "guid"=@guid;`,
|
|
3330
|
+
{
|
|
3331
|
+
etypes: [etype],
|
|
3332
|
+
params: {
|
|
3333
|
+
guid,
|
|
3334
|
+
},
|
|
3335
|
+
},
|
|
2024
3336
|
);
|
|
2025
|
-
insertData(guid, data, sdata, etype);
|
|
3337
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
2026
3338
|
success = true;
|
|
2027
3339
|
}
|
|
2028
3340
|
return success;
|
|
2029
3341
|
},
|
|
2030
3342
|
async () => {
|
|
2031
3343
|
await this.startTransaction('nymph-save');
|
|
3344
|
+
inTransaction = true;
|
|
2032
3345
|
},
|
|
2033
3346
|
async (success) => {
|
|
2034
|
-
if (
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
3347
|
+
if (inTransaction) {
|
|
3348
|
+
inTransaction = false;
|
|
3349
|
+
if (success) {
|
|
3350
|
+
await this.commit('nymph-save');
|
|
3351
|
+
} else {
|
|
3352
|
+
await this.rollback('nymph-save');
|
|
3353
|
+
}
|
|
2038
3354
|
}
|
|
2039
3355
|
return success;
|
|
2040
|
-
}
|
|
3356
|
+
},
|
|
2041
3357
|
);
|
|
2042
3358
|
} catch (e: any) {
|
|
2043
|
-
|
|
3359
|
+
this.nymph.config.debugError('sqlite3', `Save entity error: "${e}"`);
|
|
3360
|
+
if (inTransaction) {
|
|
3361
|
+
await this.rollback('nymph-save');
|
|
3362
|
+
}
|
|
2044
3363
|
throw e;
|
|
2045
3364
|
}
|
|
2046
3365
|
}
|
|
@@ -2049,39 +3368,190 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
2049
3368
|
if (name == null) {
|
|
2050
3369
|
throw new InvalidParametersError('Name not given for UID.');
|
|
2051
3370
|
}
|
|
2052
|
-
this.
|
|
3371
|
+
await this.startTransaction('nymph-set-uid');
|
|
2053
3372
|
this.queryRun(
|
|
2054
3373
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2055
|
-
`${this.prefix}uids
|
|
3374
|
+
`${this.prefix}uids`,
|
|
2056
3375
|
)} WHERE "name"=@name;`,
|
|
2057
3376
|
{
|
|
2058
3377
|
params: {
|
|
2059
3378
|
name,
|
|
2060
3379
|
},
|
|
2061
|
-
}
|
|
3380
|
+
},
|
|
2062
3381
|
);
|
|
2063
3382
|
this.queryRun(
|
|
2064
3383
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
2065
|
-
`${this.prefix}uids
|
|
3384
|
+
`${this.prefix}uids`,
|
|
2066
3385
|
)} ("name", "cur_uid") VALUES (@name, @curUid);`,
|
|
2067
3386
|
{
|
|
2068
3387
|
params: {
|
|
2069
3388
|
name,
|
|
2070
3389
|
curUid,
|
|
2071
3390
|
},
|
|
2072
|
-
}
|
|
3391
|
+
},
|
|
2073
3392
|
);
|
|
3393
|
+
await this.commit('nymph-set-uid');
|
|
2074
3394
|
return true;
|
|
2075
3395
|
}
|
|
2076
3396
|
|
|
3397
|
+
public async internalTransaction(name: string) {
|
|
3398
|
+
await this.startTransaction(name);
|
|
3399
|
+
}
|
|
3400
|
+
|
|
2077
3401
|
public async startTransaction(name: string) {
|
|
2078
3402
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
2079
3403
|
throw new InvalidParametersError(
|
|
2080
|
-
'Transaction start attempted without a name.'
|
|
3404
|
+
'Transaction start attempted without a name.',
|
|
2081
3405
|
);
|
|
2082
3406
|
}
|
|
3407
|
+
if (!this.config.explicitWrite && !this.store.linkWrite) {
|
|
3408
|
+
this._connect(true);
|
|
3409
|
+
}
|
|
2083
3410
|
this.queryRun(`SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
2084
3411
|
this.store.transactionsStarted++;
|
|
2085
3412
|
return this.nymph;
|
|
2086
3413
|
}
|
|
3414
|
+
|
|
3415
|
+
private async removeTilmeldOldRows(etype: string) {
|
|
3416
|
+
await this.startTransaction('nymph-remove-tilmeld-rows');
|
|
3417
|
+
try {
|
|
3418
|
+
for (let name of [
|
|
3419
|
+
'user',
|
|
3420
|
+
'group',
|
|
3421
|
+
'acUser',
|
|
3422
|
+
'acGroup',
|
|
3423
|
+
'acOther',
|
|
3424
|
+
'acRead',
|
|
3425
|
+
'acWrite',
|
|
3426
|
+
'acFull',
|
|
3427
|
+
]) {
|
|
3428
|
+
this.queryRun(
|
|
3429
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
3430
|
+
`${this.prefix}data_${etype}`,
|
|
3431
|
+
)} WHERE "name"=@name;`,
|
|
3432
|
+
{
|
|
3433
|
+
etypes: [etype],
|
|
3434
|
+
params: {
|
|
3435
|
+
name,
|
|
3436
|
+
},
|
|
3437
|
+
},
|
|
3438
|
+
);
|
|
3439
|
+
this.queryRun(
|
|
3440
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
3441
|
+
`${this.prefix}references_${etype}`,
|
|
3442
|
+
)} WHERE "name"=@name;`,
|
|
3443
|
+
{
|
|
3444
|
+
etypes: [etype],
|
|
3445
|
+
params: {
|
|
3446
|
+
name,
|
|
3447
|
+
},
|
|
3448
|
+
},
|
|
3449
|
+
);
|
|
3450
|
+
this.queryRun(
|
|
3451
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
3452
|
+
`${this.prefix}tokens_${etype}`,
|
|
3453
|
+
)} WHERE "name"=@name;`,
|
|
3454
|
+
{
|
|
3455
|
+
etypes: [etype],
|
|
3456
|
+
params: {
|
|
3457
|
+
name,
|
|
3458
|
+
},
|
|
3459
|
+
},
|
|
3460
|
+
);
|
|
3461
|
+
}
|
|
3462
|
+
} catch (e: any) {
|
|
3463
|
+
this.nymph.config.debugError(
|
|
3464
|
+
'sqlite3',
|
|
3465
|
+
`Remove tilmeld rows error: "${e}"`,
|
|
3466
|
+
);
|
|
3467
|
+
await this.rollback('nymph-remove-tilmeld-rows');
|
|
3468
|
+
throw e;
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3471
|
+
await this.commit('nymph-remove-tilmeld-rows');
|
|
3472
|
+
return true;
|
|
3473
|
+
}
|
|
3474
|
+
|
|
3475
|
+
public async needsMigration(): Promise<
|
|
3476
|
+
'json' | 'tokens' | 'tilmeldColumns' | false
|
|
3477
|
+
> {
|
|
3478
|
+
const table: any = this.queryGet(
|
|
3479
|
+
"SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix LIMIT 1;",
|
|
3480
|
+
{
|
|
3481
|
+
params: {
|
|
3482
|
+
prefix: this.prefix + 'data_' + '%',
|
|
3483
|
+
},
|
|
3484
|
+
},
|
|
3485
|
+
);
|
|
3486
|
+
if (table?.name) {
|
|
3487
|
+
const result: any = this.queryGet(
|
|
3488
|
+
"SELECT 1 AS `exists` FROM pragma_table_info(@table) WHERE `name`='json';",
|
|
3489
|
+
{
|
|
3490
|
+
params: {
|
|
3491
|
+
table: table.name,
|
|
3492
|
+
},
|
|
3493
|
+
},
|
|
3494
|
+
);
|
|
3495
|
+
if (!result?.exists) {
|
|
3496
|
+
return 'json';
|
|
3497
|
+
}
|
|
3498
|
+
}
|
|
3499
|
+
const table2: any = this.queryGet(
|
|
3500
|
+
"SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @tokenTable LIMIT 1;",
|
|
3501
|
+
{
|
|
3502
|
+
params: {
|
|
3503
|
+
tokenTable: this.prefix + 'tokens_' + '%',
|
|
3504
|
+
},
|
|
3505
|
+
},
|
|
3506
|
+
);
|
|
3507
|
+
if (!table2 || !table2.name) {
|
|
3508
|
+
return 'tokens';
|
|
3509
|
+
}
|
|
3510
|
+
const table3: any = this.queryGet(
|
|
3511
|
+
"SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix LIMIT 1;",
|
|
3512
|
+
{
|
|
3513
|
+
params: {
|
|
3514
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
3515
|
+
},
|
|
3516
|
+
},
|
|
3517
|
+
);
|
|
3518
|
+
if (table3?.name) {
|
|
3519
|
+
const result: any = this.queryGet(
|
|
3520
|
+
"SELECT 1 AS `exists` FROM pragma_table_info(@table) WHERE `name`='user';",
|
|
3521
|
+
{
|
|
3522
|
+
params: {
|
|
3523
|
+
table: table3.name,
|
|
3524
|
+
},
|
|
3525
|
+
},
|
|
3526
|
+
);
|
|
3527
|
+
if (!result?.exists) {
|
|
3528
|
+
return 'tilmeldColumns';
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
return false;
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
public async liveMigration(
|
|
3535
|
+
migrationType: 'tokenTables' | 'tilmeldColumns' | 'tilmeldRemoveOldRows',
|
|
3536
|
+
) {
|
|
3537
|
+
if (migrationType === 'tokenTables') {
|
|
3538
|
+
const etypes = await this.getEtypes();
|
|
3539
|
+
|
|
3540
|
+
for (let etype of etypes) {
|
|
3541
|
+
this.createTokensTable(etype);
|
|
3542
|
+
}
|
|
3543
|
+
} else if (migrationType === 'tilmeldColumns') {
|
|
3544
|
+
const etypes = await this.getEtypes();
|
|
3545
|
+
|
|
3546
|
+
for (let etype of etypes) {
|
|
3547
|
+
this.addTilmeldColumnsAndIndexes(etype);
|
|
3548
|
+
}
|
|
3549
|
+
} else if (migrationType === 'tilmeldRemoveOldRows') {
|
|
3550
|
+
const etypes = await this.getEtypes();
|
|
3551
|
+
|
|
3552
|
+
for (let etype of etypes) {
|
|
3553
|
+
await this.removeTilmeldOldRows(etype);
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
2087
3557
|
}
|