@nymphjs/driver-sqlite3 1.0.0-beta.7 → 1.0.0-beta.71
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 +295 -0
- package/dist/SQLite3Driver.d.ts +59 -12
- package/dist/SQLite3Driver.js +508 -224
- package/dist/SQLite3Driver.js.map +1 -1
- package/dist/SQLite3Driver.test.js +43 -6
- package/dist/SQLite3Driver.test.js.map +1 -1
- package/dist/conf/d.d.ts +59 -1
- package/dist/conf/defaults.js +3 -1
- package/dist/conf/defaults.js.map +1 -1
- package/package.json +13 -13
- package/src/SQLite3Driver.test.ts +43 -8
- package/src/SQLite3Driver.ts +784 -473
- package/src/conf/d.ts +35 -2
- package/src/conf/defaults.ts +3 -1
- package/tsconfig.json +3 -3
- package/typedoc.json +4 -0
package/src/SQLite3Driver.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import SQLite3 from 'better-sqlite3';
|
|
2
2
|
import {
|
|
3
3
|
NymphDriver,
|
|
4
|
-
EntityConstructor,
|
|
5
|
-
EntityData,
|
|
6
|
-
EntityInterface,
|
|
7
|
-
|
|
4
|
+
type EntityConstructor,
|
|
5
|
+
type EntityData,
|
|
6
|
+
type EntityInterface,
|
|
7
|
+
type EntityInstanceType,
|
|
8
|
+
type SerializedEntityData,
|
|
9
|
+
type FormattedSelector,
|
|
10
|
+
type Options,
|
|
11
|
+
type Selector,
|
|
12
|
+
EntityUniqueConstraintError,
|
|
8
13
|
InvalidParametersError,
|
|
9
14
|
NotConfiguredError,
|
|
10
15
|
QueryFailedError,
|
|
11
16
|
UnableToConnectError,
|
|
12
|
-
FormattedSelector,
|
|
13
|
-
Options,
|
|
14
|
-
Selector,
|
|
15
17
|
xor,
|
|
16
18
|
} from '@nymphjs/nymph';
|
|
17
19
|
import { makeTableSuffix } from '@nymphjs/guid';
|
|
@@ -23,6 +25,7 @@ import {
|
|
|
23
25
|
|
|
24
26
|
class InternalStore {
|
|
25
27
|
public link: SQLite3.Database;
|
|
28
|
+
public linkWrite?: SQLite3.Database;
|
|
26
29
|
public connected: boolean = false;
|
|
27
30
|
public transactionsStarted = 0;
|
|
28
31
|
|
|
@@ -43,7 +46,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
43
46
|
static escape(input: string) {
|
|
44
47
|
if (input.indexOf('\x00') !== -1) {
|
|
45
48
|
throw new InvalidParametersError(
|
|
46
|
-
'SQLite3 identifiers (like entity ETYPE) cannot contain null characters.'
|
|
49
|
+
'SQLite3 identifiers (like entity ETYPE) cannot contain null characters.',
|
|
47
50
|
);
|
|
48
51
|
}
|
|
49
52
|
|
|
@@ -53,6 +56,9 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
53
56
|
constructor(config: Partial<SQLite3DriverConfig>, store?: InternalStore) {
|
|
54
57
|
super();
|
|
55
58
|
this.config = { ...defaults, ...config };
|
|
59
|
+
if (this.config.filename === ':memory:') {
|
|
60
|
+
this.config.explicitWrite = true;
|
|
61
|
+
}
|
|
56
62
|
this.prefix = this.config.prefix;
|
|
57
63
|
if (store) {
|
|
58
64
|
this.store = store;
|
|
@@ -75,53 +81,107 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
75
81
|
*
|
|
76
82
|
* @returns Whether this instance is connected to a SQLite3 database.
|
|
77
83
|
*/
|
|
78
|
-
public
|
|
79
|
-
const { filename, fileMustExist, timeout, readonly, verbose } = this.config;
|
|
80
|
-
|
|
84
|
+
public connect() {
|
|
81
85
|
if (this.store && this.store.connected) {
|
|
82
|
-
return true;
|
|
86
|
+
return Promise.resolve(true);
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
// Connecting
|
|
90
|
+
this._connect(false);
|
|
91
|
+
|
|
92
|
+
return Promise.resolve(this.store.connected);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private _connect(write: boolean) {
|
|
96
|
+
const { filename, fileMustExist, timeout, explicitWrite, wal, verbose } =
|
|
97
|
+
this.config;
|
|
98
|
+
|
|
86
99
|
try {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
100
|
+
const setOptions = (link: SQLite3.Database) => {
|
|
101
|
+
// Set database and connection options.
|
|
102
|
+
if (wal) {
|
|
103
|
+
link.pragma('journal_mode = WAL;');
|
|
104
|
+
}
|
|
105
|
+
link.pragma('encoding = "UTF-8";');
|
|
106
|
+
link.pragma('foreign_keys = 1;');
|
|
107
|
+
link.pragma('case_sensitive_like = 1;');
|
|
108
|
+
for (let pragma of this.config.pragmas) {
|
|
109
|
+
link.pragma(pragma);
|
|
110
|
+
}
|
|
111
|
+
// Create the preg_match and regexp functions.
|
|
112
|
+
link.function('regexp', { deterministic: true }, ((
|
|
113
|
+
pattern: string,
|
|
114
|
+
subject: string,
|
|
115
|
+
) => (this.posixRegexMatch(pattern, subject) ? 1 : 0)) as (
|
|
116
|
+
...params: any[]
|
|
117
|
+
) => any);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
let link: SQLite3.Database;
|
|
121
|
+
try {
|
|
122
|
+
link = new SQLite3(filename, {
|
|
123
|
+
readonly: !explicitWrite && !write,
|
|
124
|
+
fileMustExist,
|
|
125
|
+
timeout,
|
|
126
|
+
verbose,
|
|
127
|
+
});
|
|
128
|
+
} catch (e: any) {
|
|
129
|
+
if (
|
|
130
|
+
e.code === 'SQLITE_CANTOPEN' &&
|
|
131
|
+
!explicitWrite &&
|
|
132
|
+
!write &&
|
|
133
|
+
!this.config.fileMustExist
|
|
134
|
+
) {
|
|
135
|
+
// This happens when the file doesn't exist and we attempt to open it
|
|
136
|
+
// readonly.
|
|
137
|
+
// First open it in write mode.
|
|
138
|
+
const writeLink = new SQLite3(filename, {
|
|
139
|
+
readonly: false,
|
|
140
|
+
fileMustExist,
|
|
141
|
+
timeout,
|
|
142
|
+
verbose,
|
|
143
|
+
});
|
|
144
|
+
setOptions(writeLink);
|
|
145
|
+
writeLink.close();
|
|
146
|
+
// Now open in readonly.
|
|
147
|
+
link = new SQLite3(filename, {
|
|
148
|
+
readonly: true,
|
|
149
|
+
fileMustExist,
|
|
150
|
+
timeout,
|
|
151
|
+
verbose,
|
|
152
|
+
});
|
|
153
|
+
} else {
|
|
154
|
+
throw e;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
93
157
|
|
|
94
158
|
if (!this.store) {
|
|
159
|
+
if (write) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
'Tried to open in write without opening in read first.',
|
|
162
|
+
);
|
|
163
|
+
}
|
|
95
164
|
this.store = new InternalStore(link);
|
|
165
|
+
} else if (write) {
|
|
166
|
+
this.store.linkWrite = link;
|
|
96
167
|
} else {
|
|
97
168
|
this.store.link = link;
|
|
98
169
|
}
|
|
99
170
|
this.store.connected = true;
|
|
100
|
-
|
|
101
|
-
this.store.link.pragma('encoding = "UTF-8";');
|
|
102
|
-
this.store.link.pragma('foreign_keys = 1;');
|
|
103
|
-
this.store.link.pragma('case_sensitive_like = 1;');
|
|
104
|
-
// Create the preg_match and regexp functions.
|
|
105
|
-
this.store.link.function(
|
|
106
|
-
'regexp',
|
|
107
|
-
{ deterministic: true },
|
|
108
|
-
(pattern: string, subject: string) =>
|
|
109
|
-
this.posixRegexMatch(pattern, subject) ? 1 : 0
|
|
110
|
-
);
|
|
171
|
+
setOptions(link);
|
|
111
172
|
} catch (e: any) {
|
|
112
173
|
if (this.store) {
|
|
113
174
|
this.store.connected = false;
|
|
114
175
|
}
|
|
115
176
|
if (filename === ':memory:') {
|
|
116
177
|
throw new NotConfiguredError(
|
|
117
|
-
"It seems the config hasn't been set up correctly."
|
|
178
|
+
"It seems the config hasn't been set up correctly. Could not connect: " +
|
|
179
|
+
e?.message,
|
|
118
180
|
);
|
|
119
181
|
} else {
|
|
120
182
|
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
121
183
|
}
|
|
122
184
|
}
|
|
123
|
-
|
|
124
|
-
return this.store.connected;
|
|
125
185
|
}
|
|
126
186
|
|
|
127
187
|
/**
|
|
@@ -131,8 +191,16 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
131
191
|
*/
|
|
132
192
|
public async disconnect() {
|
|
133
193
|
if (this.store.connected) {
|
|
134
|
-
this.store.
|
|
194
|
+
if (this.store.linkWrite && !this.config.explicitWrite) {
|
|
195
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
196
|
+
this.store.linkWrite.close();
|
|
197
|
+
this.store.linkWrite = undefined;
|
|
198
|
+
}
|
|
199
|
+
if (this.config.explicitWrite) {
|
|
200
|
+
this.store.link.exec('PRAGMA optimize;');
|
|
201
|
+
}
|
|
135
202
|
this.store.link.close();
|
|
203
|
+
this.store.transactionsStarted = 0;
|
|
136
204
|
this.store.connected = false;
|
|
137
205
|
}
|
|
138
206
|
return this.store.connected;
|
|
@@ -151,175 +219,200 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
151
219
|
return this.store.connected;
|
|
152
220
|
}
|
|
153
221
|
|
|
154
|
-
/**
|
|
155
|
-
* Check if SQLite3 DB is read only and throw error if so.
|
|
156
|
-
*/
|
|
157
|
-
private checkReadOnlyMode() {
|
|
158
|
-
if (this.config.readonly) {
|
|
159
|
-
throw new InvalidParametersError(
|
|
160
|
-
'Attempt to write to SQLite3 DB in read only mode.'
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
222
|
/**
|
|
166
223
|
* Create entity tables in the database.
|
|
167
224
|
*
|
|
168
225
|
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
169
226
|
*/
|
|
170
227
|
private createTables(etype: string | null = null) {
|
|
171
|
-
this.checkReadOnlyMode();
|
|
172
228
|
this.startTransaction('nymph-tablecreation');
|
|
173
229
|
try {
|
|
174
230
|
if (etype != null) {
|
|
175
231
|
// Create the entity table.
|
|
176
232
|
this.queryRun(
|
|
177
233
|
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
178
|
-
`${this.prefix}entities_${etype}
|
|
179
|
-
)} ("guid" CHARACTER(24) PRIMARY KEY, "tags" TEXT, "cdate" REAL NOT NULL, "mdate" REAL NOT NULL)
|
|
234
|
+
`${this.prefix}entities_${etype}`,
|
|
235
|
+
)} ("guid" CHARACTER(24) PRIMARY KEY, "tags" TEXT, "cdate" REAL NOT NULL, "mdate" REAL NOT NULL);`,
|
|
180
236
|
);
|
|
181
237
|
this.queryRun(
|
|
182
238
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
183
|
-
`${this.prefix}entities_${etype}_id_cdate
|
|
239
|
+
`${this.prefix}entities_${etype}_id_cdate`,
|
|
184
240
|
)} ON ${SQLite3Driver.escape(
|
|
185
|
-
`${this.prefix}entities_${etype}
|
|
186
|
-
)} ("cdate")
|
|
241
|
+
`${this.prefix}entities_${etype}`,
|
|
242
|
+
)} ("cdate");`,
|
|
187
243
|
);
|
|
188
244
|
this.queryRun(
|
|
189
245
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
190
|
-
`${this.prefix}entities_${etype}_id_mdate
|
|
246
|
+
`${this.prefix}entities_${etype}_id_mdate`,
|
|
191
247
|
)} ON ${SQLite3Driver.escape(
|
|
192
|
-
`${this.prefix}entities_${etype}
|
|
193
|
-
)} ("mdate")
|
|
248
|
+
`${this.prefix}entities_${etype}`,
|
|
249
|
+
)} ("mdate");`,
|
|
194
250
|
);
|
|
195
251
|
this.queryRun(
|
|
196
252
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
197
|
-
`${this.prefix}entities_${etype}_id_tags
|
|
253
|
+
`${this.prefix}entities_${etype}_id_tags`,
|
|
198
254
|
)} ON ${SQLite3Driver.escape(
|
|
199
|
-
`${this.prefix}entities_${etype}
|
|
200
|
-
)} ("tags")
|
|
255
|
+
`${this.prefix}entities_${etype}`,
|
|
256
|
+
)} ("tags");`,
|
|
201
257
|
);
|
|
202
258
|
// Create the data table.
|
|
203
259
|
this.queryRun(
|
|
204
260
|
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
205
|
-
`${this.prefix}data_${etype}
|
|
261
|
+
`${this.prefix}data_${etype}`,
|
|
206
262
|
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
207
|
-
`${this.prefix}entities_${etype}
|
|
208
|
-
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "value" TEXT NOT NULL, PRIMARY KEY("guid", "name"))
|
|
263
|
+
`${this.prefix}entities_${etype}`,
|
|
264
|
+
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "value" TEXT NOT NULL, PRIMARY KEY("guid", "name"));`,
|
|
209
265
|
);
|
|
210
266
|
this.queryRun(
|
|
211
267
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
212
|
-
`${this.prefix}data_${etype}_id_guid
|
|
268
|
+
`${this.prefix}data_${etype}_id_guid`,
|
|
213
269
|
)} ON ${SQLite3Driver.escape(
|
|
214
|
-
`${this.prefix}data_${etype}
|
|
215
|
-
)} ("guid")
|
|
270
|
+
`${this.prefix}data_${etype}`,
|
|
271
|
+
)} ("guid");`,
|
|
216
272
|
);
|
|
217
273
|
this.queryRun(
|
|
218
274
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
219
|
-
`${this.prefix}data_${etype}_id_name
|
|
275
|
+
`${this.prefix}data_${etype}_id_name`,
|
|
220
276
|
)} ON ${SQLite3Driver.escape(
|
|
221
|
-
`${this.prefix}data_${etype}
|
|
222
|
-
)} ("name")
|
|
277
|
+
`${this.prefix}data_${etype}`,
|
|
278
|
+
)} ("name");`,
|
|
223
279
|
);
|
|
224
280
|
this.queryRun(
|
|
225
281
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
226
|
-
`${this.prefix}data_${etype}
|
|
282
|
+
`${this.prefix}data_${etype}_id_name_value`,
|
|
227
283
|
)} ON ${SQLite3Driver.escape(
|
|
228
|
-
`${this.prefix}data_${etype}
|
|
229
|
-
)} ("value")
|
|
284
|
+
`${this.prefix}data_${etype}`,
|
|
285
|
+
)} ("name", "value");`,
|
|
230
286
|
);
|
|
231
287
|
this.queryRun(
|
|
232
288
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
233
|
-
`${this.prefix}data_${etype}
|
|
289
|
+
`${this.prefix}data_${etype}_id_value`,
|
|
234
290
|
)} ON ${SQLite3Driver.escape(
|
|
235
|
-
`${this.prefix}data_${etype}
|
|
236
|
-
)} ("
|
|
291
|
+
`${this.prefix}data_${etype}`,
|
|
292
|
+
)} ("value");`,
|
|
237
293
|
);
|
|
238
294
|
this.queryRun(
|
|
239
295
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
240
|
-
`${this.prefix}data_${etype}
|
|
296
|
+
`${this.prefix}data_${etype}_id_guid__name_user`,
|
|
241
297
|
)} ON ${SQLite3Driver.escape(
|
|
242
|
-
`${this.prefix}data_${etype}
|
|
243
|
-
)} ("guid") WHERE "name" = \'
|
|
298
|
+
`${this.prefix}data_${etype}`,
|
|
299
|
+
)} ("guid") WHERE "name" = \'user\';`,
|
|
300
|
+
);
|
|
301
|
+
this.queryRun(
|
|
302
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
303
|
+
`${this.prefix}data_${etype}_id_guid__name_group`,
|
|
304
|
+
)} ON ${SQLite3Driver.escape(
|
|
305
|
+
`${this.prefix}data_${etype}`,
|
|
306
|
+
)} ("guid") WHERE "name" = \'group\';`,
|
|
244
307
|
);
|
|
245
308
|
// Create the comparisons table.
|
|
246
309
|
this.queryRun(
|
|
247
310
|
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
248
|
-
`${this.prefix}comparisons_${etype}
|
|
311
|
+
`${this.prefix}comparisons_${etype}`,
|
|
249
312
|
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
250
|
-
`${this.prefix}entities_${etype}
|
|
251
|
-
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "truthy" INTEGER, "string" TEXT, "number" REAL, PRIMARY KEY("guid", "name"))
|
|
313
|
+
`${this.prefix}entities_${etype}`,
|
|
314
|
+
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "truthy" INTEGER, "string" TEXT, "number" REAL, PRIMARY KEY("guid", "name"));`,
|
|
315
|
+
);
|
|
316
|
+
this.queryRun(
|
|
317
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
318
|
+
`${this.prefix}comparisons_${etype}_id_guid`,
|
|
319
|
+
)} ON ${SQLite3Driver.escape(
|
|
320
|
+
`${this.prefix}comparisons_${etype}`,
|
|
321
|
+
)} ("guid");`,
|
|
322
|
+
);
|
|
323
|
+
this.queryRun(
|
|
324
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
325
|
+
`${this.prefix}comparisons_${etype}_id_name`,
|
|
326
|
+
)} ON ${SQLite3Driver.escape(
|
|
327
|
+
`${this.prefix}comparisons_${etype}`,
|
|
328
|
+
)} ("name");`,
|
|
252
329
|
);
|
|
253
330
|
this.queryRun(
|
|
254
331
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
255
|
-
`${this.prefix}comparisons_${etype}
|
|
332
|
+
`${this.prefix}comparisons_${etype}_id_name__truthy`,
|
|
256
333
|
)} ON ${SQLite3Driver.escape(
|
|
257
|
-
`${this.prefix}comparisons_${etype}
|
|
258
|
-
)} ("
|
|
334
|
+
`${this.prefix}comparisons_${etype}`,
|
|
335
|
+
)} ("name") WHERE "truthy" = 1;`,
|
|
259
336
|
);
|
|
260
337
|
this.queryRun(
|
|
261
338
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
262
|
-
`${this.prefix}comparisons_${etype}
|
|
339
|
+
`${this.prefix}comparisons_${etype}_id_name__falsy`,
|
|
263
340
|
)} ON ${SQLite3Driver.escape(
|
|
264
|
-
`${this.prefix}comparisons_${etype}
|
|
265
|
-
)} ("name")
|
|
341
|
+
`${this.prefix}comparisons_${etype}`,
|
|
342
|
+
)} ("name") WHERE "truthy" <> 1;`,
|
|
266
343
|
);
|
|
267
344
|
this.queryRun(
|
|
268
345
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
269
|
-
`${this.prefix}comparisons_${etype}
|
|
346
|
+
`${this.prefix}comparisons_${etype}_id_name_string`,
|
|
270
347
|
)} ON ${SQLite3Driver.escape(
|
|
271
|
-
`${this.prefix}comparisons_${etype}
|
|
272
|
-
)} ("name"
|
|
348
|
+
`${this.prefix}comparisons_${etype}`,
|
|
349
|
+
)} ("name", "string");`,
|
|
350
|
+
);
|
|
351
|
+
this.queryRun(
|
|
352
|
+
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
353
|
+
`${this.prefix}comparisons_${etype}_id_name_number`,
|
|
354
|
+
)} ON ${SQLite3Driver.escape(
|
|
355
|
+
`${this.prefix}comparisons_${etype}`,
|
|
356
|
+
)} ("name", "number");`,
|
|
273
357
|
);
|
|
274
358
|
// Create the references table.
|
|
275
359
|
this.queryRun(
|
|
276
360
|
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
277
|
-
`${this.prefix}references_${etype}
|
|
361
|
+
`${this.prefix}references_${etype}`,
|
|
278
362
|
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
279
|
-
`${this.prefix}entities_${etype}
|
|
280
|
-
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "reference" CHARACTER(24) NOT NULL, PRIMARY KEY("guid", "name", "reference"))
|
|
363
|
+
`${this.prefix}entities_${etype}`,
|
|
364
|
+
)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "reference" CHARACTER(24) NOT NULL, PRIMARY KEY("guid", "name", "reference"));`,
|
|
281
365
|
);
|
|
282
366
|
this.queryRun(
|
|
283
367
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
284
|
-
`${this.prefix}references_${etype}_id_guid
|
|
368
|
+
`${this.prefix}references_${etype}_id_guid`,
|
|
285
369
|
)} ON ${SQLite3Driver.escape(
|
|
286
|
-
`${this.prefix}references_${etype}
|
|
287
|
-
)} ("guid")
|
|
370
|
+
`${this.prefix}references_${etype}`,
|
|
371
|
+
)} ("guid");`,
|
|
288
372
|
);
|
|
289
373
|
this.queryRun(
|
|
290
374
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
291
|
-
`${this.prefix}references_${etype}_id_name
|
|
375
|
+
`${this.prefix}references_${etype}_id_name`,
|
|
292
376
|
)} ON ${SQLite3Driver.escape(
|
|
293
|
-
`${this.prefix}references_${etype}
|
|
294
|
-
)} ("name")
|
|
377
|
+
`${this.prefix}references_${etype}`,
|
|
378
|
+
)} ("name");`,
|
|
295
379
|
);
|
|
296
380
|
this.queryRun(
|
|
297
381
|
`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(
|
|
298
|
-
`${this.prefix}references_${etype}
|
|
382
|
+
`${this.prefix}references_${etype}_id_name_reference`,
|
|
299
383
|
)} ON ${SQLite3Driver.escape(
|
|
300
|
-
`${this.prefix}references_${etype}
|
|
301
|
-
)} ("reference")
|
|
384
|
+
`${this.prefix}references_${etype}`,
|
|
385
|
+
)} ("name", "reference");`,
|
|
386
|
+
);
|
|
387
|
+
// Create the unique strings table.
|
|
388
|
+
this.queryRun(
|
|
389
|
+
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
390
|
+
`${this.prefix}uniques_${etype}`,
|
|
391
|
+
)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(
|
|
392
|
+
`${this.prefix}entities_${etype}`,
|
|
393
|
+
)} ("guid") ON DELETE CASCADE, "unique" TEXT NOT NULL UNIQUE, PRIMARY KEY("guid", "unique"));`,
|
|
302
394
|
);
|
|
303
395
|
} else {
|
|
304
396
|
// Create the UID table.
|
|
305
397
|
this.queryRun(
|
|
306
398
|
`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(
|
|
307
|
-
`${this.prefix}uids
|
|
308
|
-
)} ("name" TEXT PRIMARY KEY NOT NULL, "cur_uid" INTEGER NOT NULL)
|
|
399
|
+
`${this.prefix}uids`,
|
|
400
|
+
)} ("name" TEXT PRIMARY KEY NOT NULL, "cur_uid" INTEGER NOT NULL);`,
|
|
309
401
|
);
|
|
310
402
|
}
|
|
311
|
-
this.commit('nymph-tablecreation');
|
|
312
|
-
return true;
|
|
313
403
|
} catch (e: any) {
|
|
314
404
|
this.rollback('nymph-tablecreation');
|
|
315
405
|
throw e;
|
|
316
406
|
}
|
|
407
|
+
|
|
408
|
+
this.commit('nymph-tablecreation');
|
|
409
|
+
return true;
|
|
317
410
|
}
|
|
318
411
|
|
|
319
412
|
private query<T extends () => any>(
|
|
320
413
|
runQuery: T,
|
|
321
414
|
query: string,
|
|
322
|
-
etypes: string[] = []
|
|
415
|
+
etypes: string[] = [],
|
|
323
416
|
): ReturnType<T> {
|
|
324
417
|
try {
|
|
325
418
|
return runQuery();
|
|
@@ -339,13 +432,18 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
339
432
|
} catch (e2: any) {
|
|
340
433
|
throw new QueryFailedError(
|
|
341
434
|
'Query failed: ' + e2?.code + ' - ' + e2?.message,
|
|
342
|
-
query
|
|
435
|
+
query,
|
|
343
436
|
);
|
|
344
437
|
}
|
|
438
|
+
} else if (
|
|
439
|
+
errorCode === 'SQLITE_CONSTRAINT_UNIQUE' &&
|
|
440
|
+
errorMsg.match(/^UNIQUE constraint failed: /)
|
|
441
|
+
) {
|
|
442
|
+
throw new EntityUniqueConstraintError(`Unique constraint violation.`);
|
|
345
443
|
} else {
|
|
346
444
|
throw new QueryFailedError(
|
|
347
445
|
'Query failed: ' + e?.code + ' - ' + e?.message,
|
|
348
|
-
query
|
|
446
|
+
query,
|
|
349
447
|
);
|
|
350
448
|
}
|
|
351
449
|
}
|
|
@@ -356,12 +454,15 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
356
454
|
{
|
|
357
455
|
etypes = [],
|
|
358
456
|
params = {},
|
|
359
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
457
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
360
458
|
) {
|
|
361
459
|
return this.query(
|
|
362
|
-
() =>
|
|
460
|
+
() =>
|
|
461
|
+
(this.store.linkWrite || this.store.link)
|
|
462
|
+
.prepare(query)
|
|
463
|
+
.iterate(params),
|
|
363
464
|
`${query} -- ${JSON.stringify(params)}`,
|
|
364
|
-
etypes
|
|
465
|
+
etypes,
|
|
365
466
|
);
|
|
366
467
|
}
|
|
367
468
|
|
|
@@ -370,12 +471,13 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
370
471
|
{
|
|
371
472
|
etypes = [],
|
|
372
473
|
params = {},
|
|
373
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
474
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
374
475
|
) {
|
|
375
476
|
return this.query(
|
|
376
|
-
() =>
|
|
477
|
+
() =>
|
|
478
|
+
(this.store.linkWrite || this.store.link).prepare(query).get(params),
|
|
377
479
|
`${query} -- ${JSON.stringify(params)}`,
|
|
378
|
-
etypes
|
|
480
|
+
etypes,
|
|
379
481
|
);
|
|
380
482
|
}
|
|
381
483
|
|
|
@@ -384,19 +486,20 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
384
486
|
{
|
|
385
487
|
etypes = [],
|
|
386
488
|
params = {},
|
|
387
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
489
|
+
}: { etypes?: string[]; params?: { [k: string]: any } } = {},
|
|
388
490
|
) {
|
|
389
491
|
return this.query(
|
|
390
|
-
() =>
|
|
492
|
+
() =>
|
|
493
|
+
(this.store.linkWrite || this.store.link).prepare(query).run(params),
|
|
391
494
|
`${query} -- ${JSON.stringify(params)}`,
|
|
392
|
-
etypes
|
|
495
|
+
etypes,
|
|
393
496
|
);
|
|
394
497
|
}
|
|
395
498
|
|
|
396
499
|
public async commit(name: string) {
|
|
397
500
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
398
501
|
throw new InvalidParametersError(
|
|
399
|
-
'Transaction commit attempted without a name.'
|
|
502
|
+
'Transaction commit attempted without a name.',
|
|
400
503
|
);
|
|
401
504
|
}
|
|
402
505
|
if (this.store.transactionsStarted === 0) {
|
|
@@ -404,12 +507,23 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
404
507
|
}
|
|
405
508
|
this.queryRun(`RELEASE SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
406
509
|
this.store.transactionsStarted--;
|
|
510
|
+
|
|
511
|
+
if (
|
|
512
|
+
this.store.transactionsStarted === 0 &&
|
|
513
|
+
this.store.linkWrite &&
|
|
514
|
+
!this.config.explicitWrite
|
|
515
|
+
) {
|
|
516
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
517
|
+
this.store.linkWrite.close();
|
|
518
|
+
this.store.linkWrite = undefined;
|
|
519
|
+
}
|
|
520
|
+
|
|
407
521
|
return true;
|
|
408
522
|
}
|
|
409
523
|
|
|
410
524
|
public async deleteEntityByID(
|
|
411
525
|
guid: string,
|
|
412
|
-
className?: EntityConstructor | string | null
|
|
526
|
+
className?: EntityConstructor | string | null,
|
|
413
527
|
) {
|
|
414
528
|
let EntityClass: EntityConstructor;
|
|
415
529
|
if (typeof className === 'string' || className == null) {
|
|
@@ -419,115 +533,160 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
419
533
|
EntityClass = className;
|
|
420
534
|
}
|
|
421
535
|
const etype = EntityClass.ETYPE;
|
|
422
|
-
this.checkReadOnlyMode();
|
|
423
536
|
await this.startTransaction('nymph-delete');
|
|
424
537
|
try {
|
|
425
538
|
this.queryRun(
|
|
426
539
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
427
|
-
`${this.prefix}entities_${etype}
|
|
540
|
+
`${this.prefix}entities_${etype}`,
|
|
428
541
|
)} WHERE "guid"=@guid;`,
|
|
429
542
|
{
|
|
430
543
|
etypes: [etype],
|
|
431
544
|
params: {
|
|
432
545
|
guid,
|
|
433
546
|
},
|
|
434
|
-
}
|
|
547
|
+
},
|
|
435
548
|
);
|
|
436
549
|
this.queryRun(
|
|
437
550
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
438
|
-
`${this.prefix}data_${etype}
|
|
551
|
+
`${this.prefix}data_${etype}`,
|
|
439
552
|
)} WHERE "guid"=@guid;`,
|
|
440
553
|
{
|
|
441
554
|
etypes: [etype],
|
|
442
555
|
params: {
|
|
443
556
|
guid,
|
|
444
557
|
},
|
|
445
|
-
}
|
|
558
|
+
},
|
|
446
559
|
);
|
|
447
560
|
this.queryRun(
|
|
448
561
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
449
|
-
`${this.prefix}comparisons_${etype}
|
|
562
|
+
`${this.prefix}comparisons_${etype}`,
|
|
450
563
|
)} WHERE "guid"=@guid;`,
|
|
451
564
|
{
|
|
452
565
|
etypes: [etype],
|
|
453
566
|
params: {
|
|
454
567
|
guid,
|
|
455
568
|
},
|
|
456
|
-
}
|
|
569
|
+
},
|
|
457
570
|
);
|
|
458
571
|
this.queryRun(
|
|
459
572
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
460
|
-
`${this.prefix}references_${etype}
|
|
573
|
+
`${this.prefix}references_${etype}`,
|
|
461
574
|
)} WHERE "guid"=@guid;`,
|
|
462
575
|
{
|
|
463
576
|
etypes: [etype],
|
|
464
577
|
params: {
|
|
465
578
|
guid,
|
|
466
579
|
},
|
|
467
|
-
}
|
|
580
|
+
},
|
|
581
|
+
);
|
|
582
|
+
this.queryRun(
|
|
583
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
584
|
+
`${this.prefix}uniques_${etype}`,
|
|
585
|
+
)} WHERE "guid"=@guid;`,
|
|
586
|
+
{
|
|
587
|
+
etypes: [etype],
|
|
588
|
+
params: {
|
|
589
|
+
guid,
|
|
590
|
+
},
|
|
591
|
+
},
|
|
468
592
|
);
|
|
469
|
-
await this.commit('nymph-delete');
|
|
470
|
-
// Remove any cached versions of this entity.
|
|
471
|
-
if (this.nymph.config.cache) {
|
|
472
|
-
this.cleanCache(guid);
|
|
473
|
-
}
|
|
474
|
-
return true;
|
|
475
593
|
} catch (e: any) {
|
|
594
|
+
this.nymph.config.debugError('sqlite3', `Delete entity error: "${e}"`);
|
|
476
595
|
await this.rollback('nymph-delete');
|
|
477
596
|
throw e;
|
|
478
597
|
}
|
|
598
|
+
|
|
599
|
+
await this.commit('nymph-delete');
|
|
600
|
+
// Remove any cached versions of this entity.
|
|
601
|
+
if (this.nymph.config.cache) {
|
|
602
|
+
this.cleanCache(guid);
|
|
603
|
+
}
|
|
604
|
+
return true;
|
|
479
605
|
}
|
|
480
606
|
|
|
481
607
|
public async deleteUID(name: string) {
|
|
482
608
|
if (!name) {
|
|
483
609
|
throw new InvalidParametersError('Name not given for UID');
|
|
484
610
|
}
|
|
485
|
-
this.
|
|
611
|
+
await this.startTransaction('nymph-delete-uid');
|
|
486
612
|
this.queryRun(
|
|
487
613
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
488
|
-
`${this.prefix}uids
|
|
614
|
+
`${this.prefix}uids`,
|
|
489
615
|
)} WHERE "name"=@name;`,
|
|
490
616
|
{
|
|
491
617
|
params: {
|
|
492
618
|
name,
|
|
493
619
|
},
|
|
494
|
-
}
|
|
620
|
+
},
|
|
495
621
|
);
|
|
622
|
+
await this.commit('nymph-delete-uid');
|
|
496
623
|
return true;
|
|
497
624
|
}
|
|
498
625
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
626
|
+
public async *exportDataIterator(): AsyncGenerator<
|
|
627
|
+
{ type: 'comment' | 'uid' | 'entity'; content: string },
|
|
628
|
+
void,
|
|
629
|
+
false | undefined
|
|
630
|
+
> {
|
|
631
|
+
if (
|
|
632
|
+
yield {
|
|
633
|
+
type: 'comment',
|
|
634
|
+
content: `#nex2
|
|
635
|
+
# Nymph Entity Exchange v2
|
|
636
|
+
# http://nymph.io
|
|
637
|
+
#
|
|
638
|
+
# Generation Time: ${new Date().toLocaleString()}
|
|
639
|
+
`,
|
|
640
|
+
}
|
|
641
|
+
) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
if (
|
|
646
|
+
yield {
|
|
647
|
+
type: 'comment',
|
|
648
|
+
content: `
|
|
506
649
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
650
|
+
#
|
|
651
|
+
# UIDs
|
|
652
|
+
#
|
|
653
|
+
|
|
654
|
+
`,
|
|
655
|
+
}
|
|
656
|
+
) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
511
659
|
|
|
512
660
|
// Export UIDs.
|
|
513
|
-
let uids = this.queryIter(
|
|
661
|
+
let uids: IterableIterator<any> = this.queryIter(
|
|
514
662
|
`SELECT * FROM ${SQLite3Driver.escape(
|
|
515
|
-
`${this.prefix}uids
|
|
516
|
-
)} ORDER BY "name"
|
|
663
|
+
`${this.prefix}uids`,
|
|
664
|
+
)} ORDER BY "name";`,
|
|
517
665
|
);
|
|
518
666
|
for (const uid of uids) {
|
|
519
|
-
|
|
667
|
+
if (yield { type: 'uid', content: `<${uid.name}>[${uid.cur_uid}]\n` }) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
520
670
|
}
|
|
521
671
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
672
|
+
if (
|
|
673
|
+
yield {
|
|
674
|
+
type: 'comment',
|
|
675
|
+
content: `
|
|
676
|
+
|
|
677
|
+
#
|
|
678
|
+
# Entities
|
|
679
|
+
#
|
|
680
|
+
|
|
681
|
+
`,
|
|
682
|
+
}
|
|
683
|
+
) {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
527
686
|
|
|
528
687
|
// Get the etypes.
|
|
529
|
-
const tables = this.queryIter(
|
|
530
|
-
"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name;"
|
|
688
|
+
const tables: IterableIterator<any> = this.queryIter(
|
|
689
|
+
"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name;",
|
|
531
690
|
);
|
|
532
691
|
const etypes = [];
|
|
533
692
|
for (const table of tables) {
|
|
@@ -538,14 +697,14 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
538
697
|
|
|
539
698
|
for (const etype of etypes) {
|
|
540
699
|
// Export entities.
|
|
541
|
-
const dataIterator = this.queryIter(
|
|
700
|
+
const dataIterator: IterableIterator<any> = this.queryIter(
|
|
542
701
|
`SELECT e.*, d."name" AS "dname", d."value" AS "dvalue", c."string", c."number" FROM ${SQLite3Driver.escape(
|
|
543
|
-
`${this.prefix}entities_${etype}
|
|
702
|
+
`${this.prefix}entities_${etype}`,
|
|
544
703
|
)} e LEFT JOIN ${SQLite3Driver.escape(
|
|
545
|
-
`${this.prefix}data_${etype}
|
|
704
|
+
`${this.prefix}data_${etype}`,
|
|
546
705
|
)} d USING ("guid") INNER JOIN ${SQLite3Driver.escape(
|
|
547
|
-
`${this.prefix}comparisons_${etype}
|
|
548
|
-
)} c USING ("guid", "name") ORDER BY e."guid"
|
|
706
|
+
`${this.prefix}comparisons_${etype}`,
|
|
707
|
+
)} c USING ("guid", "name") ORDER BY e."guid";`,
|
|
549
708
|
)[Symbol.iterator]();
|
|
550
709
|
let datum = dataIterator.next();
|
|
551
710
|
while (!datum.done) {
|
|
@@ -553,9 +712,10 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
553
712
|
const tags = datum.value.tags.slice(1, -1);
|
|
554
713
|
const cdate = datum.value.cdate;
|
|
555
714
|
const mdate = datum.value.mdate;
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
715
|
+
let currentEntityExport: string[] = [];
|
|
716
|
+
currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
|
|
717
|
+
currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
|
|
718
|
+
currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
|
|
559
719
|
if (datum.value.dname != null) {
|
|
560
720
|
// This do will keep going and adding the data until the
|
|
561
721
|
// next entity is reached. datum will end on the next entity.
|
|
@@ -566,17 +726,20 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
566
726
|
: datum.value.dvalue === 'S'
|
|
567
727
|
? JSON.stringify(datum.value.string)
|
|
568
728
|
: datum.value.dvalue;
|
|
569
|
-
|
|
729
|
+
currentEntityExport.push(`\t${datum.value.dname}=${value}`);
|
|
570
730
|
datum = dataIterator.next();
|
|
571
731
|
} while (!datum.done && datum.value.guid === guid);
|
|
572
732
|
} else {
|
|
573
733
|
// Make sure that datum is incremented :)
|
|
574
734
|
datum = dataIterator.next();
|
|
575
735
|
}
|
|
736
|
+
currentEntityExport.push('');
|
|
737
|
+
|
|
738
|
+
if (yield { type: 'entity', content: currentEntityExport.join('\n') }) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
576
741
|
}
|
|
577
742
|
}
|
|
578
|
-
|
|
579
|
-
return;
|
|
580
743
|
}
|
|
581
744
|
|
|
582
745
|
/**
|
|
@@ -597,7 +760,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
597
760
|
params: { [k: string]: any } = {},
|
|
598
761
|
subquery = false,
|
|
599
762
|
tableSuffix = '',
|
|
600
|
-
etypes: string[] = []
|
|
763
|
+
etypes: string[] = [],
|
|
601
764
|
) {
|
|
602
765
|
if (typeof options.class?.alterOptions === 'function') {
|
|
603
766
|
options = options.class.alterOptions(options);
|
|
@@ -607,10 +770,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
607
770
|
const cTable = `c${tableSuffix}`;
|
|
608
771
|
const fTable = `f${tableSuffix}`;
|
|
609
772
|
const ieTable = `ie${tableSuffix}`;
|
|
773
|
+
const sTable = `s${tableSuffix}`;
|
|
610
774
|
const sort = options.sort ?? 'cdate';
|
|
611
775
|
const queryParts = this.iterateSelectorsForQuery(
|
|
612
776
|
formattedSelectors,
|
|
613
|
-
(key, value, typeIsOr, typeIsNot) => {
|
|
777
|
+
({ key, value, typeIsOr, typeIsNot }) => {
|
|
614
778
|
const clauseNot = key.startsWith('!');
|
|
615
779
|
let curQuery = '';
|
|
616
780
|
for (const curValue of value) {
|
|
@@ -695,10 +859,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
695
859
|
const name = `param${++count.i}`;
|
|
696
860
|
curQuery +=
|
|
697
861
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
698
|
-
|
|
699
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
862
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
700
863
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
701
|
-
' WHERE "
|
|
864
|
+
' WHERE "guid"=' +
|
|
865
|
+
ieTable +
|
|
866
|
+
'."guid" AND "name"=@' +
|
|
702
867
|
name +
|
|
703
868
|
' AND "truthy"=1)';
|
|
704
869
|
params[name] = curVar;
|
|
@@ -739,10 +904,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
739
904
|
const value = `param${++count.i}`;
|
|
740
905
|
curQuery +=
|
|
741
906
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
742
|
-
|
|
743
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
907
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
744
908
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
745
|
-
' WHERE "
|
|
909
|
+
' WHERE "guid"=' +
|
|
910
|
+
ieTable +
|
|
911
|
+
'."guid" AND "name"=@' +
|
|
746
912
|
name +
|
|
747
913
|
' AND "number"=@' +
|
|
748
914
|
value +
|
|
@@ -757,10 +923,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
757
923
|
const value = `param${++count.i}`;
|
|
758
924
|
curQuery +=
|
|
759
925
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
760
|
-
|
|
761
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
926
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
762
927
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
763
|
-
' WHERE "
|
|
928
|
+
' WHERE "guid"=' +
|
|
929
|
+
ieTable +
|
|
930
|
+
'."guid" AND "name"=@' +
|
|
764
931
|
name +
|
|
765
932
|
' AND "string"=@' +
|
|
766
933
|
value +
|
|
@@ -784,10 +951,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
784
951
|
const value = `param${++count.i}`;
|
|
785
952
|
curQuery +=
|
|
786
953
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
787
|
-
|
|
788
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
954
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
789
955
|
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
790
|
-
' WHERE "
|
|
956
|
+
' WHERE "guid"=' +
|
|
957
|
+
ieTable +
|
|
958
|
+
'."guid" AND "name"=@' +
|
|
791
959
|
name +
|
|
792
960
|
' AND "value"=@' +
|
|
793
961
|
value +
|
|
@@ -844,19 +1012,19 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
844
1012
|
const stringParam = `param${++count.i}`;
|
|
845
1013
|
curQuery +=
|
|
846
1014
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
847
|
-
'(' +
|
|
848
|
-
ieTable +
|
|
849
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1015
|
+
'(EXISTS (SELECT "guid" FROM ' +
|
|
850
1016
|
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
851
|
-
' WHERE "
|
|
1017
|
+
' WHERE "guid"=' +
|
|
1018
|
+
ieTable +
|
|
1019
|
+
'."guid" AND "name"=@' +
|
|
852
1020
|
name +
|
|
853
1021
|
' AND instr("value", @' +
|
|
854
1022
|
value +
|
|
855
|
-
')) OR ' +
|
|
856
|
-
ieTable +
|
|
857
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1023
|
+
')) OR EXISTS (SELECT "guid" FROM ' +
|
|
858
1024
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
859
|
-
' WHERE "
|
|
1025
|
+
' WHERE "guid"=' +
|
|
1026
|
+
ieTable +
|
|
1027
|
+
'."guid" AND "name"=@' +
|
|
860
1028
|
name +
|
|
861
1029
|
' AND "string"=@' +
|
|
862
1030
|
stringParam +
|
|
@@ -865,10 +1033,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
865
1033
|
} else {
|
|
866
1034
|
curQuery +=
|
|
867
1035
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
868
|
-
|
|
869
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1036
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
870
1037
|
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
871
|
-
' WHERE "
|
|
1038
|
+
' WHERE "guid"=' +
|
|
1039
|
+
ieTable +
|
|
1040
|
+
'."guid" AND "name"=@' +
|
|
872
1041
|
name +
|
|
873
1042
|
' AND instr("value", @' +
|
|
874
1043
|
value +
|
|
@@ -916,10 +1085,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
916
1085
|
const value = `param${++count.i}`;
|
|
917
1086
|
curQuery +=
|
|
918
1087
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
919
|
-
|
|
920
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1088
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
921
1089
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
922
|
-
' WHERE "
|
|
1090
|
+
' WHERE "guid"=' +
|
|
1091
|
+
ieTable +
|
|
1092
|
+
'."guid" AND "name"=@' +
|
|
923
1093
|
name +
|
|
924
1094
|
' AND "string" REGEXP @' +
|
|
925
1095
|
value +
|
|
@@ -966,10 +1136,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
966
1136
|
const value = `param${++count.i}`;
|
|
967
1137
|
curQuery +=
|
|
968
1138
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
969
|
-
|
|
970
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1139
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
971
1140
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
972
|
-
' WHERE "
|
|
1141
|
+
' WHERE "guid"=' +
|
|
1142
|
+
ieTable +
|
|
1143
|
+
'."guid" AND "name"=@' +
|
|
973
1144
|
name +
|
|
974
1145
|
' AND lower("string") REGEXP lower(@' +
|
|
975
1146
|
value +
|
|
@@ -1016,10 +1187,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1016
1187
|
const value = `param${++count.i}`;
|
|
1017
1188
|
curQuery +=
|
|
1018
1189
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1019
|
-
|
|
1020
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1190
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1021
1191
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1022
|
-
' WHERE "
|
|
1192
|
+
' WHERE "guid"=' +
|
|
1193
|
+
ieTable +
|
|
1194
|
+
'."guid" AND "name"=@' +
|
|
1023
1195
|
name +
|
|
1024
1196
|
' AND "string" LIKE @' +
|
|
1025
1197
|
value +
|
|
@@ -1066,10 +1238,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1066
1238
|
const value = `param${++count.i}`;
|
|
1067
1239
|
curQuery +=
|
|
1068
1240
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1069
|
-
|
|
1070
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1241
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1071
1242
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1072
|
-
' WHERE "
|
|
1243
|
+
' WHERE "guid"=' +
|
|
1244
|
+
ieTable +
|
|
1245
|
+
'."guid" AND "name"=@' +
|
|
1073
1246
|
name +
|
|
1074
1247
|
' AND lower("string") LIKE lower(@' +
|
|
1075
1248
|
value +
|
|
@@ -1112,10 +1285,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1112
1285
|
const value = `param${++count.i}`;
|
|
1113
1286
|
curQuery +=
|
|
1114
1287
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1115
|
-
|
|
1116
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1288
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1117
1289
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1118
|
-
' WHERE "
|
|
1290
|
+
' WHERE "guid"=' +
|
|
1291
|
+
ieTable +
|
|
1292
|
+
'."guid" AND "name"=@' +
|
|
1119
1293
|
name +
|
|
1120
1294
|
' AND "number">@' +
|
|
1121
1295
|
value +
|
|
@@ -1158,10 +1332,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1158
1332
|
const value = `param${++count.i}`;
|
|
1159
1333
|
curQuery +=
|
|
1160
1334
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1161
|
-
|
|
1162
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1335
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1163
1336
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1164
|
-
' WHERE "
|
|
1337
|
+
' WHERE "guid"=' +
|
|
1338
|
+
ieTable +
|
|
1339
|
+
'."guid" AND "name"=@' +
|
|
1165
1340
|
name +
|
|
1166
1341
|
' AND "number">=@' +
|
|
1167
1342
|
value +
|
|
@@ -1204,10 +1379,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1204
1379
|
const value = `param${++count.i}`;
|
|
1205
1380
|
curQuery +=
|
|
1206
1381
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1207
|
-
|
|
1208
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1382
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1209
1383
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1210
|
-
' WHERE "
|
|
1384
|
+
' WHERE "guid"=' +
|
|
1385
|
+
ieTable +
|
|
1386
|
+
'."guid" AND "name"=@' +
|
|
1211
1387
|
name +
|
|
1212
1388
|
' AND "number"<@' +
|
|
1213
1389
|
value +
|
|
@@ -1250,10 +1426,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1250
1426
|
const value = `param${++count.i}`;
|
|
1251
1427
|
curQuery +=
|
|
1252
1428
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1253
|
-
|
|
1254
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1429
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1255
1430
|
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1256
|
-
' WHERE "
|
|
1431
|
+
' WHERE "guid"=' +
|
|
1432
|
+
ieTable +
|
|
1433
|
+
'."guid" AND "name"=@' +
|
|
1257
1434
|
name +
|
|
1258
1435
|
' AND "number"<=@' +
|
|
1259
1436
|
value +
|
|
@@ -1279,10 +1456,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1279
1456
|
const guid = `param${++count.i}`;
|
|
1280
1457
|
curQuery +=
|
|
1281
1458
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1282
|
-
|
|
1283
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1459
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1284
1460
|
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
1285
|
-
' WHERE "
|
|
1461
|
+
' WHERE "guid"=' +
|
|
1462
|
+
ieTable +
|
|
1463
|
+
'."guid" AND "name"=@' +
|
|
1286
1464
|
name +
|
|
1287
1465
|
' AND "reference"=@' +
|
|
1288
1466
|
guid +
|
|
@@ -1300,7 +1478,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1300
1478
|
params,
|
|
1301
1479
|
true,
|
|
1302
1480
|
tableSuffix,
|
|
1303
|
-
etypes
|
|
1481
|
+
etypes,
|
|
1304
1482
|
);
|
|
1305
1483
|
if (curQuery) {
|
|
1306
1484
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1315,7 +1493,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1315
1493
|
case '!qref':
|
|
1316
1494
|
const [qrefOptions, ...qrefSelectors] = curValue[1] as [
|
|
1317
1495
|
Options,
|
|
1318
|
-
...FormattedSelector[]
|
|
1496
|
+
...FormattedSelector[],
|
|
1319
1497
|
];
|
|
1320
1498
|
const QrefEntityClass = qrefOptions.class as EntityConstructor;
|
|
1321
1499
|
etypes.push(QrefEntityClass.ETYPE);
|
|
@@ -1327,7 +1505,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1327
1505
|
params,
|
|
1328
1506
|
false,
|
|
1329
1507
|
makeTableSuffix(),
|
|
1330
|
-
etypes
|
|
1508
|
+
etypes,
|
|
1331
1509
|
);
|
|
1332
1510
|
if (curQuery) {
|
|
1333
1511
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1335,10 +1513,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1335
1513
|
const qrefName = `param${++count.i}`;
|
|
1336
1514
|
curQuery +=
|
|
1337
1515
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1338
|
-
|
|
1339
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1516
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1340
1517
|
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
1341
|
-
' WHERE "
|
|
1518
|
+
' WHERE "guid"=' +
|
|
1519
|
+
ieTable +
|
|
1520
|
+
'."guid" AND "name"=@' +
|
|
1342
1521
|
qrefName +
|
|
1343
1522
|
' AND "reference" IN (' +
|
|
1344
1523
|
qrefQuery.query +
|
|
@@ -1348,22 +1527,35 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1348
1527
|
}
|
|
1349
1528
|
}
|
|
1350
1529
|
return curQuery;
|
|
1351
|
-
}
|
|
1530
|
+
},
|
|
1352
1531
|
);
|
|
1353
1532
|
|
|
1354
1533
|
let sortBy: string;
|
|
1534
|
+
let sortByInner: string;
|
|
1535
|
+
let sortJoin = '';
|
|
1536
|
+
const order = options.reverse ? ' DESC' : '';
|
|
1355
1537
|
switch (sort) {
|
|
1356
1538
|
case 'mdate':
|
|
1357
|
-
sortBy =
|
|
1539
|
+
sortBy = `${eTable}."mdate"${order}`;
|
|
1540
|
+
sortByInner = `${ieTable}."mdate"${order}`;
|
|
1358
1541
|
break;
|
|
1359
1542
|
case 'cdate':
|
|
1543
|
+
sortBy = `${eTable}."cdate"${order}`;
|
|
1544
|
+
sortByInner = `${ieTable}."cdate"${order}`;
|
|
1545
|
+
break;
|
|
1360
1546
|
default:
|
|
1361
|
-
|
|
1547
|
+
const name = `param${++count.i}`;
|
|
1548
|
+
sortJoin = `LEFT JOIN (
|
|
1549
|
+
SELECT "guid", "string", "number"
|
|
1550
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'comparisons_' + etype)}
|
|
1551
|
+
WHERE "name"=@${name}
|
|
1552
|
+
ORDER BY "number"${order}, "string"${order}
|
|
1553
|
+
) ${sTable} USING ("guid")`;
|
|
1554
|
+
sortBy = `${sTable}."number"${order}, ${sTable}."string"${order}`;
|
|
1555
|
+
sortByInner = sortBy;
|
|
1556
|
+
params[name] = sort;
|
|
1362
1557
|
break;
|
|
1363
1558
|
}
|
|
1364
|
-
if (options.reverse) {
|
|
1365
|
-
sortBy += ' DESC';
|
|
1366
|
-
}
|
|
1367
1559
|
|
|
1368
1560
|
let query: string;
|
|
1369
1561
|
if (queryParts.length) {
|
|
@@ -1384,24 +1576,25 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1384
1576
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1385
1577
|
SELECT "guid"
|
|
1386
1578
|
FROM ${SQLite3Driver.escape(
|
|
1387
|
-
this.prefix + 'entities_' + etype
|
|
1579
|
+
this.prefix + 'entities_' + etype,
|
|
1388
1580
|
)} ${ieTable}
|
|
1389
1581
|
WHERE (${whereClause})${limit}${offset}
|
|
1390
1582
|
)`;
|
|
1391
1583
|
} else {
|
|
1392
1584
|
query = `SELECT COUNT("guid") AS "count"
|
|
1393
1585
|
FROM ${SQLite3Driver.escape(
|
|
1394
|
-
this.prefix + 'entities_' + etype
|
|
1586
|
+
this.prefix + 'entities_' + etype,
|
|
1395
1587
|
)} ${ieTable}
|
|
1396
1588
|
WHERE (${whereClause})`;
|
|
1397
1589
|
}
|
|
1398
1590
|
} else if (options.return === 'guid') {
|
|
1399
1591
|
query = `SELECT "guid"
|
|
1400
1592
|
FROM ${SQLite3Driver.escape(
|
|
1401
|
-
this.prefix + 'entities_' + etype
|
|
1593
|
+
this.prefix + 'entities_' + etype,
|
|
1402
1594
|
)} ${ieTable}
|
|
1595
|
+
${sortJoin}
|
|
1403
1596
|
WHERE (${whereClause})
|
|
1404
|
-
ORDER BY ${
|
|
1597
|
+
ORDER BY ${sortByInner}, "guid"${limit}${offset}`;
|
|
1405
1598
|
} else {
|
|
1406
1599
|
query = `SELECT
|
|
1407
1600
|
${eTable}."guid",
|
|
@@ -1413,23 +1606,25 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1413
1606
|
${cTable}."string",
|
|
1414
1607
|
${cTable}."number"
|
|
1415
1608
|
FROM ${SQLite3Driver.escape(
|
|
1416
|
-
this.prefix + 'entities_' + etype
|
|
1609
|
+
this.prefix + 'entities_' + etype,
|
|
1417
1610
|
)} ${eTable}
|
|
1418
1611
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1419
|
-
this.prefix + 'data_' + etype
|
|
1612
|
+
this.prefix + 'data_' + etype,
|
|
1420
1613
|
)} ${dTable} USING ("guid")
|
|
1421
1614
|
INNER JOIN ${SQLite3Driver.escape(
|
|
1422
|
-
this.prefix + 'comparisons_' + etype
|
|
1615
|
+
this.prefix + 'comparisons_' + etype,
|
|
1423
1616
|
)} ${cTable} USING ("guid", "name")
|
|
1617
|
+
${sortJoin}
|
|
1424
1618
|
INNER JOIN (
|
|
1425
1619
|
SELECT "guid"
|
|
1426
1620
|
FROM ${SQLite3Driver.escape(
|
|
1427
|
-
this.prefix + 'entities_' + etype
|
|
1621
|
+
this.prefix + 'entities_' + etype,
|
|
1428
1622
|
)} ${ieTable}
|
|
1623
|
+
${sortJoin}
|
|
1429
1624
|
WHERE (${whereClause})
|
|
1430
|
-
ORDER BY ${
|
|
1625
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1431
1626
|
) ${fTable} USING ("guid")
|
|
1432
|
-
ORDER BY ${
|
|
1627
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1433
1628
|
}
|
|
1434
1629
|
}
|
|
1435
1630
|
} else {
|
|
@@ -1449,21 +1644,22 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1449
1644
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1450
1645
|
SELECT "guid"
|
|
1451
1646
|
FROM ${SQLite3Driver.escape(
|
|
1452
|
-
this.prefix + 'entities_' + etype
|
|
1647
|
+
this.prefix + 'entities_' + etype,
|
|
1453
1648
|
)} ${ieTable}${limit}${offset}
|
|
1454
1649
|
)`;
|
|
1455
1650
|
} else {
|
|
1456
1651
|
query = `SELECT COUNT("guid") AS "count"
|
|
1457
1652
|
FROM ${SQLite3Driver.escape(
|
|
1458
|
-
this.prefix + 'entities_' + etype
|
|
1653
|
+
this.prefix + 'entities_' + etype,
|
|
1459
1654
|
)} ${ieTable}`;
|
|
1460
1655
|
}
|
|
1461
1656
|
} else if (options.return === 'guid') {
|
|
1462
1657
|
query = `SELECT "guid"
|
|
1463
1658
|
FROM ${SQLite3Driver.escape(
|
|
1464
|
-
this.prefix + 'entities_' + etype
|
|
1659
|
+
this.prefix + 'entities_' + etype,
|
|
1465
1660
|
)} ${ieTable}
|
|
1466
|
-
|
|
1661
|
+
${sortJoin}
|
|
1662
|
+
ORDER BY ${sortByInner}, "guid"${limit}${offset}`;
|
|
1467
1663
|
} else {
|
|
1468
1664
|
if (limit || offset) {
|
|
1469
1665
|
query = `SELECT
|
|
@@ -1476,22 +1672,24 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1476
1672
|
${cTable}."string",
|
|
1477
1673
|
${cTable}."number"
|
|
1478
1674
|
FROM ${SQLite3Driver.escape(
|
|
1479
|
-
this.prefix + 'entities_' + etype
|
|
1675
|
+
this.prefix + 'entities_' + etype,
|
|
1480
1676
|
)} ${eTable}
|
|
1481
1677
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1482
|
-
this.prefix + 'data_' + etype
|
|
1678
|
+
this.prefix + 'data_' + etype,
|
|
1483
1679
|
)} ${dTable} USING ("guid")
|
|
1484
1680
|
INNER JOIN ${SQLite3Driver.escape(
|
|
1485
|
-
this.prefix + 'comparisons_' + etype
|
|
1681
|
+
this.prefix + 'comparisons_' + etype,
|
|
1486
1682
|
)} c USING ("guid", "name")
|
|
1683
|
+
${sortJoin}
|
|
1487
1684
|
INNER JOIN (
|
|
1488
1685
|
SELECT "guid"
|
|
1489
1686
|
FROM ${SQLite3Driver.escape(
|
|
1490
|
-
this.prefix + 'entities_' + etype
|
|
1687
|
+
this.prefix + 'entities_' + etype,
|
|
1491
1688
|
)} ${ieTable}
|
|
1492
|
-
|
|
1689
|
+
${sortJoin}
|
|
1690
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1493
1691
|
) ${fTable} USING ("guid")
|
|
1494
|
-
ORDER BY ${
|
|
1692
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1495
1693
|
} else {
|
|
1496
1694
|
query = `SELECT
|
|
1497
1695
|
${eTable}."guid",
|
|
@@ -1503,15 +1701,16 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1503
1701
|
${cTable}."string",
|
|
1504
1702
|
${cTable}."number"
|
|
1505
1703
|
FROM ${SQLite3Driver.escape(
|
|
1506
|
-
this.prefix + 'entities_' + etype
|
|
1704
|
+
this.prefix + 'entities_' + etype,
|
|
1507
1705
|
)} ${eTable}
|
|
1508
1706
|
LEFT JOIN ${SQLite3Driver.escape(
|
|
1509
|
-
this.prefix + 'data_' + etype
|
|
1707
|
+
this.prefix + 'data_' + etype,
|
|
1510
1708
|
)} ${dTable} USING ("guid")
|
|
1511
1709
|
INNER JOIN ${SQLite3Driver.escape(
|
|
1512
|
-
this.prefix + 'comparisons_' + etype
|
|
1710
|
+
this.prefix + 'comparisons_' + etype,
|
|
1513
1711
|
)} ${cTable} USING ("guid", "name")
|
|
1514
|
-
|
|
1712
|
+
${sortJoin}
|
|
1713
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1515
1714
|
}
|
|
1516
1715
|
}
|
|
1517
1716
|
}
|
|
@@ -1531,14 +1730,14 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1531
1730
|
protected performQuery(
|
|
1532
1731
|
options: Options,
|
|
1533
1732
|
formattedSelectors: FormattedSelector[],
|
|
1534
|
-
etype: string
|
|
1733
|
+
etype: string,
|
|
1535
1734
|
): {
|
|
1536
1735
|
result: any;
|
|
1537
1736
|
} {
|
|
1538
1737
|
const { query, params, etypes } = this.makeEntityQuery(
|
|
1539
1738
|
options,
|
|
1540
1739
|
formattedSelectors,
|
|
1541
|
-
etype
|
|
1740
|
+
etype,
|
|
1542
1741
|
);
|
|
1543
1742
|
const result = this.queryIter(query, { etypes, params })[Symbol.iterator]();
|
|
1544
1743
|
return {
|
|
@@ -1557,35 +1756,16 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1557
1756
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1558
1757
|
options?: Options<T>,
|
|
1559
1758
|
...selectors: Selector[]
|
|
1560
|
-
): Promise<
|
|
1759
|
+
): Promise<EntityInstanceType<T>[]>;
|
|
1561
1760
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1562
1761
|
options: Options<T> = {},
|
|
1563
1762
|
...selectors: Selector[]
|
|
1564
|
-
): Promise<
|
|
1565
|
-
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1569
|
-
options: Options<T> & { return: 'count' },
|
|
1570
|
-
...selectors: Selector[]
|
|
1571
|
-
): number;
|
|
1572
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1573
|
-
options: Options<T> & { return: 'guid' },
|
|
1574
|
-
...selectors: Selector[]
|
|
1575
|
-
): string[];
|
|
1576
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1577
|
-
options?: Options<T>,
|
|
1578
|
-
...selectors: Selector[]
|
|
1579
|
-
): ReturnType<T['factorySync']>[];
|
|
1580
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1581
|
-
options: Options<T> = {},
|
|
1582
|
-
...selectors: Selector[]
|
|
1583
|
-
): ReturnType<T['factorySync']>[] | string[] | number {
|
|
1584
|
-
const { result, process } = this.getEntitesRowLike<T>(
|
|
1763
|
+
): Promise<EntityInstanceType<T>[] | string[] | number> {
|
|
1764
|
+
const { result, process } = this.getEntitiesRowLike<T>(
|
|
1585
1765
|
options,
|
|
1586
1766
|
selectors,
|
|
1587
|
-
(options,
|
|
1588
|
-
this.performQuery(options,
|
|
1767
|
+
({ options, selectors, etype }) =>
|
|
1768
|
+
this.performQuery(options, selectors, etype),
|
|
1589
1769
|
() => {
|
|
1590
1770
|
const next: any = result.next();
|
|
1591
1771
|
return next.done ? null : next.value;
|
|
@@ -1606,7 +1786,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1606
1786
|
: row.value === 'S'
|
|
1607
1787
|
? JSON.stringify(row.string)
|
|
1608
1788
|
: row.value,
|
|
1609
|
-
})
|
|
1789
|
+
}),
|
|
1610
1790
|
);
|
|
1611
1791
|
const value = process();
|
|
1612
1792
|
if (value instanceof Error) {
|
|
@@ -1619,175 +1799,227 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1619
1799
|
if (name == null) {
|
|
1620
1800
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1621
1801
|
}
|
|
1622
|
-
const result = this.queryGet(
|
|
1802
|
+
const result: any = this.queryGet(
|
|
1623
1803
|
`SELECT "cur_uid" FROM ${SQLite3Driver.escape(
|
|
1624
|
-
`${this.prefix}uids
|
|
1804
|
+
`${this.prefix}uids`,
|
|
1625
1805
|
)} WHERE "name"=@name;`,
|
|
1626
1806
|
{
|
|
1627
1807
|
params: {
|
|
1628
1808
|
name: name,
|
|
1629
1809
|
},
|
|
1630
|
-
}
|
|
1810
|
+
},
|
|
1631
1811
|
);
|
|
1632
1812
|
return (result?.cur_uid as number | null) ?? null;
|
|
1633
1813
|
}
|
|
1634
1814
|
|
|
1635
|
-
public async
|
|
1636
|
-
|
|
1815
|
+
public async importEntity({
|
|
1816
|
+
guid,
|
|
1817
|
+
cdate,
|
|
1818
|
+
mdate,
|
|
1819
|
+
tags,
|
|
1820
|
+
sdata,
|
|
1821
|
+
etype,
|
|
1822
|
+
}: {
|
|
1823
|
+
guid: string;
|
|
1824
|
+
cdate: number;
|
|
1825
|
+
mdate: number;
|
|
1826
|
+
tags: string[];
|
|
1827
|
+
sdata: SerializedEntityData;
|
|
1828
|
+
etype: string;
|
|
1829
|
+
}) {
|
|
1637
1830
|
try {
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
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
|
-
|
|
1831
|
+
await this.startTransaction(`nymph-import-entity-${guid}`);
|
|
1832
|
+
|
|
1833
|
+
this.queryRun(
|
|
1834
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
1835
|
+
`${this.prefix}entities_${etype}`,
|
|
1836
|
+
)} WHERE "guid"=@guid;`,
|
|
1837
|
+
{
|
|
1838
|
+
etypes: [etype],
|
|
1839
|
+
params: {
|
|
1840
|
+
guid,
|
|
1841
|
+
},
|
|
1842
|
+
},
|
|
1843
|
+
);
|
|
1844
|
+
this.queryRun(
|
|
1845
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
1846
|
+
`${this.prefix}data_${etype}`,
|
|
1847
|
+
)} WHERE "guid"=@guid;`,
|
|
1848
|
+
{
|
|
1849
|
+
etypes: [etype],
|
|
1850
|
+
params: {
|
|
1851
|
+
guid,
|
|
1852
|
+
},
|
|
1853
|
+
},
|
|
1854
|
+
);
|
|
1855
|
+
this.queryRun(
|
|
1856
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
1857
|
+
`${this.prefix}comparisons_${etype}`,
|
|
1858
|
+
)} WHERE "guid"=@guid;`,
|
|
1859
|
+
{
|
|
1860
|
+
etypes: [etype],
|
|
1861
|
+
params: {
|
|
1862
|
+
guid,
|
|
1863
|
+
},
|
|
1864
|
+
},
|
|
1865
|
+
);
|
|
1866
|
+
this.queryRun(
|
|
1867
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
1868
|
+
`${this.prefix}references_${etype}`,
|
|
1869
|
+
)} WHERE "guid"=@guid;`,
|
|
1870
|
+
{
|
|
1871
|
+
etypes: [etype],
|
|
1872
|
+
params: {
|
|
1873
|
+
guid,
|
|
1874
|
+
},
|
|
1875
|
+
},
|
|
1876
|
+
);
|
|
1877
|
+
this.queryRun(
|
|
1878
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
1879
|
+
`${this.prefix}uniques_${etype}`,
|
|
1880
|
+
)} WHERE "guid"=@guid;`,
|
|
1881
|
+
{
|
|
1882
|
+
etypes: [etype],
|
|
1883
|
+
params: {
|
|
1884
|
+
guid,
|
|
1885
|
+
},
|
|
1886
|
+
},
|
|
1887
|
+
);
|
|
1888
|
+
|
|
1889
|
+
this.queryRun(
|
|
1890
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
1891
|
+
`${this.prefix}entities_${etype}`,
|
|
1892
|
+
)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @mdate);`,
|
|
1893
|
+
{
|
|
1894
|
+
etypes: [etype],
|
|
1895
|
+
params: {
|
|
1896
|
+
guid,
|
|
1897
|
+
tags: ',' + tags.join(',') + ',',
|
|
1898
|
+
cdate,
|
|
1899
|
+
mdate,
|
|
1900
|
+
},
|
|
1901
|
+
},
|
|
1902
|
+
);
|
|
1903
|
+
for (const name in sdata) {
|
|
1904
|
+
const value = sdata[name];
|
|
1905
|
+
const uvalue = JSON.parse(value);
|
|
1906
|
+
if (value === undefined) {
|
|
1907
|
+
continue;
|
|
1908
|
+
}
|
|
1909
|
+
const storageValue =
|
|
1910
|
+
typeof uvalue === 'number'
|
|
1911
|
+
? 'N'
|
|
1912
|
+
: typeof uvalue === 'string'
|
|
1913
|
+
? 'S'
|
|
1914
|
+
: value;
|
|
1915
|
+
this.queryRun(
|
|
1916
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
1917
|
+
`${this.prefix}data_${etype}`,
|
|
1918
|
+
)} ("guid", "name", "value") VALUES (@guid, @name, @storageValue);`,
|
|
1919
|
+
{
|
|
1920
|
+
etypes: [etype],
|
|
1921
|
+
params: {
|
|
1922
|
+
guid,
|
|
1923
|
+
name,
|
|
1924
|
+
storageValue,
|
|
1925
|
+
},
|
|
1926
|
+
},
|
|
1927
|
+
);
|
|
1928
|
+
this.queryRun(
|
|
1929
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
1930
|
+
`${this.prefix}comparisons_${etype}`,
|
|
1931
|
+
)} ("guid", "name", "truthy", "string", "number") VALUES (@guid, @name, @truthy, @string, @number);`,
|
|
1932
|
+
{
|
|
1933
|
+
etypes: [etype],
|
|
1934
|
+
params: {
|
|
1935
|
+
guid,
|
|
1936
|
+
name,
|
|
1937
|
+
truthy: uvalue ? 1 : 0,
|
|
1938
|
+
string: `${uvalue}`,
|
|
1939
|
+
number: Number(uvalue),
|
|
1940
|
+
},
|
|
1941
|
+
},
|
|
1942
|
+
);
|
|
1943
|
+
const references = this.findReferences(value);
|
|
1944
|
+
for (const reference of references) {
|
|
1674
1945
|
this.queryRun(
|
|
1675
|
-
`
|
|
1676
|
-
`${this.prefix}references_${etype}
|
|
1677
|
-
)}
|
|
1946
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
1947
|
+
`${this.prefix}references_${etype}`,
|
|
1948
|
+
)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`,
|
|
1678
1949
|
{
|
|
1679
1950
|
etypes: [etype],
|
|
1680
1951
|
params: {
|
|
1681
1952
|
guid,
|
|
1953
|
+
name,
|
|
1954
|
+
reference,
|
|
1682
1955
|
},
|
|
1683
|
-
}
|
|
1956
|
+
},
|
|
1684
1957
|
);
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
const uniques = await this.nymph
|
|
1961
|
+
.getEntityClassByEtype(etype)
|
|
1962
|
+
.getUniques({ guid, cdate, mdate, tags, data: {}, sdata });
|
|
1963
|
+
for (const unique of uniques) {
|
|
1964
|
+
try {
|
|
1685
1965
|
this.queryRun(
|
|
1686
1966
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1687
|
-
`${this.prefix}
|
|
1688
|
-
)} ("guid", "
|
|
1967
|
+
`${this.prefix}uniques_${etype}`,
|
|
1968
|
+
)} ("guid", "unique") VALUES (@guid, @unique);`,
|
|
1689
1969
|
{
|
|
1690
1970
|
etypes: [etype],
|
|
1691
1971
|
params: {
|
|
1692
1972
|
guid,
|
|
1693
|
-
|
|
1694
|
-
cdate: Number(JSON.parse(sdata.cdate)),
|
|
1695
|
-
mdate: Number(JSON.parse(sdata.mdate)),
|
|
1973
|
+
unique,
|
|
1696
1974
|
},
|
|
1697
|
-
}
|
|
1975
|
+
},
|
|
1698
1976
|
);
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
if (value === undefined) {
|
|
1705
|
-
continue;
|
|
1706
|
-
}
|
|
1707
|
-
const storageValue =
|
|
1708
|
-
typeof uvalue === 'number'
|
|
1709
|
-
? 'N'
|
|
1710
|
-
: typeof uvalue === 'string'
|
|
1711
|
-
? 'S'
|
|
1712
|
-
: value;
|
|
1713
|
-
this.queryRun(
|
|
1714
|
-
`INSERT INTO ${SQLite3Driver.escape(
|
|
1715
|
-
`${this.prefix}data_${etype}`
|
|
1716
|
-
)} ("guid", "name", "value") VALUES (@guid, @name, @storageValue);`,
|
|
1717
|
-
{
|
|
1718
|
-
etypes: [etype],
|
|
1719
|
-
params: {
|
|
1720
|
-
guid,
|
|
1721
|
-
name,
|
|
1722
|
-
storageValue,
|
|
1723
|
-
},
|
|
1724
|
-
}
|
|
1725
|
-
);
|
|
1726
|
-
this.queryRun(
|
|
1727
|
-
`INSERT INTO ${SQLite3Driver.escape(
|
|
1728
|
-
`${this.prefix}comparisons_${etype}`
|
|
1729
|
-
)} ("guid", "name", "truthy", "string", "number") VALUES (@guid, @name, @truthy, @string, @number);`,
|
|
1730
|
-
{
|
|
1731
|
-
etypes: [etype],
|
|
1732
|
-
params: {
|
|
1733
|
-
guid,
|
|
1734
|
-
name,
|
|
1735
|
-
truthy: uvalue ? 1 : 0,
|
|
1736
|
-
string: `${uvalue}`,
|
|
1737
|
-
number: Number(uvalue),
|
|
1738
|
-
},
|
|
1739
|
-
}
|
|
1977
|
+
} catch (e: any) {
|
|
1978
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
1979
|
+
this.nymph.config.debugError(
|
|
1980
|
+
'sqlite3',
|
|
1981
|
+
`Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`,
|
|
1740
1982
|
);
|
|
1741
|
-
const references = this.findReferences(value);
|
|
1742
|
-
for (const reference of references) {
|
|
1743
|
-
this.queryRun(
|
|
1744
|
-
`INSERT INTO ${SQLite3Driver.escape(
|
|
1745
|
-
`${this.prefix}references_${etype}`
|
|
1746
|
-
)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`,
|
|
1747
|
-
{
|
|
1748
|
-
etypes: [etype],
|
|
1749
|
-
params: {
|
|
1750
|
-
guid,
|
|
1751
|
-
name,
|
|
1752
|
-
reference,
|
|
1753
|
-
},
|
|
1754
|
-
}
|
|
1755
|
-
);
|
|
1756
|
-
}
|
|
1757
1983
|
}
|
|
1984
|
+
throw e;
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
await this.commit(`nymph-import-entity-${guid}`);
|
|
1988
|
+
} catch (e: any) {
|
|
1989
|
+
this.nymph.config.debugError('sqlite3', `Import entity error: "${e}"`);
|
|
1990
|
+
await this.rollback(`nymph-import-entity-${guid}`);
|
|
1991
|
+
throw e;
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
public async importUID({ name, value }: { name: string; value: number }) {
|
|
1996
|
+
try {
|
|
1997
|
+
await this.startTransaction(`nymph-import-uid-${name}`);
|
|
1998
|
+
this.queryRun(
|
|
1999
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2000
|
+
`${this.prefix}uids`,
|
|
2001
|
+
)} WHERE "name"=@name;`,
|
|
2002
|
+
{
|
|
2003
|
+
params: {
|
|
2004
|
+
name,
|
|
2005
|
+
},
|
|
1758
2006
|
},
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
);
|
|
1770
|
-
this.queryRun(
|
|
1771
|
-
`INSERT INTO ${SQLite3Driver.escape(
|
|
1772
|
-
`${this.prefix}uids`
|
|
1773
|
-
)} ("name", "cur_uid") VALUES (@name, @curUid);`,
|
|
1774
|
-
{
|
|
1775
|
-
params: {
|
|
1776
|
-
name,
|
|
1777
|
-
curUid,
|
|
1778
|
-
},
|
|
1779
|
-
}
|
|
1780
|
-
);
|
|
1781
|
-
},
|
|
1782
|
-
async () => {
|
|
1783
|
-
await this.startTransaction('nymph-import');
|
|
2007
|
+
);
|
|
2008
|
+
this.queryRun(
|
|
2009
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2010
|
+
`${this.prefix}uids`,
|
|
2011
|
+
)} ("name", "cur_uid") VALUES (@name, @value);`,
|
|
2012
|
+
{
|
|
2013
|
+
params: {
|
|
2014
|
+
name,
|
|
2015
|
+
value,
|
|
2016
|
+
},
|
|
1784
2017
|
},
|
|
1785
|
-
async () => {
|
|
1786
|
-
await this.commit('nymph-import');
|
|
1787
|
-
}
|
|
1788
2018
|
);
|
|
2019
|
+
await this.commit(`nymph-import-uid-${name}`);
|
|
1789
2020
|
} catch (e: any) {
|
|
1790
|
-
|
|
2021
|
+
this.nymph.config.debugError('sqlite3', `Import UID error: "${e}"`);
|
|
2022
|
+
await this.rollback(`nymph-import-uid-${name}`);
|
|
1791
2023
|
throw e;
|
|
1792
2024
|
}
|
|
1793
2025
|
}
|
|
@@ -1796,78 +2028,83 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1796
2028
|
if (name == null) {
|
|
1797
2029
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1798
2030
|
}
|
|
1799
|
-
this.checkReadOnlyMode();
|
|
1800
2031
|
await this.startTransaction('nymph-newuid');
|
|
2032
|
+
let curUid: number | undefined = undefined;
|
|
1801
2033
|
try {
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
2034
|
+
curUid =
|
|
2035
|
+
(
|
|
2036
|
+
this.queryGet(
|
|
2037
|
+
`SELECT "cur_uid" FROM ${SQLite3Driver.escape(
|
|
2038
|
+
`${this.prefix}uids`,
|
|
2039
|
+
)} WHERE "name"=@name;`,
|
|
2040
|
+
{
|
|
2041
|
+
params: {
|
|
2042
|
+
name,
|
|
2043
|
+
},
|
|
1810
2044
|
},
|
|
1811
|
-
|
|
2045
|
+
) as any
|
|
1812
2046
|
)?.cur_uid ?? null;
|
|
1813
2047
|
if (curUid == null) {
|
|
1814
2048
|
curUid = 1;
|
|
1815
2049
|
this.queryRun(
|
|
1816
2050
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1817
|
-
`${this.prefix}uids
|
|
2051
|
+
`${this.prefix}uids`,
|
|
1818
2052
|
)} ("name", "cur_uid") VALUES (@name, @curUid);`,
|
|
1819
2053
|
{
|
|
1820
2054
|
params: {
|
|
1821
2055
|
name,
|
|
1822
2056
|
curUid,
|
|
1823
2057
|
},
|
|
1824
|
-
}
|
|
2058
|
+
},
|
|
1825
2059
|
);
|
|
1826
2060
|
} else {
|
|
1827
2061
|
curUid++;
|
|
1828
2062
|
this.queryRun(
|
|
1829
2063
|
`UPDATE ${SQLite3Driver.escape(
|
|
1830
|
-
`${this.prefix}uids
|
|
2064
|
+
`${this.prefix}uids`,
|
|
1831
2065
|
)} SET "cur_uid"=@curUid WHERE "name"=@name;`,
|
|
1832
2066
|
{
|
|
1833
2067
|
params: {
|
|
1834
2068
|
curUid,
|
|
1835
2069
|
name,
|
|
1836
2070
|
},
|
|
1837
|
-
}
|
|
2071
|
+
},
|
|
1838
2072
|
);
|
|
1839
2073
|
}
|
|
1840
|
-
await this.commit('nymph-newuid');
|
|
1841
|
-
return curUid as number;
|
|
1842
2074
|
} catch (e: any) {
|
|
2075
|
+
this.nymph.config.debugError('sqlite3', `New UID error: "${e}"`);
|
|
1843
2076
|
await this.rollback('nymph-newuid');
|
|
1844
2077
|
throw e;
|
|
1845
2078
|
}
|
|
2079
|
+
|
|
2080
|
+
await this.commit('nymph-newuid');
|
|
2081
|
+
return curUid as number;
|
|
1846
2082
|
}
|
|
1847
2083
|
|
|
1848
2084
|
public async renameUID(oldName: string, newName: string) {
|
|
1849
2085
|
if (oldName == null || newName == null) {
|
|
1850
2086
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1851
2087
|
}
|
|
1852
|
-
this.
|
|
2088
|
+
await this.startTransaction('nymph-rename-uid');
|
|
1853
2089
|
this.queryRun(
|
|
1854
2090
|
`UPDATE ${SQLite3Driver.escape(
|
|
1855
|
-
`${this.prefix}uids
|
|
2091
|
+
`${this.prefix}uids`,
|
|
1856
2092
|
)} SET "name"=@newName WHERE "name"=@oldName;`,
|
|
1857
2093
|
{
|
|
1858
2094
|
params: {
|
|
1859
2095
|
newName,
|
|
1860
2096
|
oldName,
|
|
1861
2097
|
},
|
|
1862
|
-
}
|
|
2098
|
+
},
|
|
1863
2099
|
);
|
|
2100
|
+
await this.commit('nymph-rename-uid');
|
|
1864
2101
|
return true;
|
|
1865
2102
|
}
|
|
1866
2103
|
|
|
1867
2104
|
public async rollback(name: string) {
|
|
1868
2105
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1869
2106
|
throw new InvalidParametersError(
|
|
1870
|
-
'Transaction rollback attempted without a name.'
|
|
2107
|
+
'Transaction rollback attempted without a name.',
|
|
1871
2108
|
);
|
|
1872
2109
|
}
|
|
1873
2110
|
if (this.store.transactionsStarted === 0) {
|
|
@@ -1875,16 +2112,27 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1875
2112
|
}
|
|
1876
2113
|
this.queryRun(`ROLLBACK TO SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
1877
2114
|
this.store.transactionsStarted--;
|
|
2115
|
+
|
|
2116
|
+
if (
|
|
2117
|
+
this.store.transactionsStarted === 0 &&
|
|
2118
|
+
this.store.linkWrite &&
|
|
2119
|
+
!this.config.explicitWrite
|
|
2120
|
+
) {
|
|
2121
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
2122
|
+
this.store.linkWrite.close();
|
|
2123
|
+
this.store.linkWrite = undefined;
|
|
2124
|
+
}
|
|
2125
|
+
|
|
1878
2126
|
return true;
|
|
1879
2127
|
}
|
|
1880
2128
|
|
|
1881
2129
|
public async saveEntity(entity: EntityInterface) {
|
|
1882
|
-
this.checkReadOnlyMode();
|
|
1883
2130
|
const insertData = (
|
|
1884
2131
|
guid: string,
|
|
1885
2132
|
data: EntityData,
|
|
1886
2133
|
sdata: SerializedEntityData,
|
|
1887
|
-
|
|
2134
|
+
uniques: string[],
|
|
2135
|
+
etype: string,
|
|
1888
2136
|
) => {
|
|
1889
2137
|
const runInsertQuery = (name: string, value: any, svalue: string) => {
|
|
1890
2138
|
if (value === undefined) {
|
|
@@ -1898,7 +2146,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1898
2146
|
: svalue;
|
|
1899
2147
|
this.queryRun(
|
|
1900
2148
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1901
|
-
`${this.prefix}data_${etype}
|
|
2149
|
+
`${this.prefix}data_${etype}`,
|
|
1902
2150
|
)} ("guid", "name", "value") VALUES (@guid, @name, @storageValue);`,
|
|
1903
2151
|
{
|
|
1904
2152
|
etypes: [etype],
|
|
@@ -1907,11 +2155,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1907
2155
|
name,
|
|
1908
2156
|
storageValue,
|
|
1909
2157
|
},
|
|
1910
|
-
}
|
|
2158
|
+
},
|
|
1911
2159
|
);
|
|
1912
2160
|
this.queryRun(
|
|
1913
2161
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1914
|
-
`${this.prefix}comparisons_${etype}
|
|
2162
|
+
`${this.prefix}comparisons_${etype}`,
|
|
1915
2163
|
)} ("guid", "name", "truthy", "string", "number") VALUES (@guid, @name, @truthy, @string, @number);`,
|
|
1916
2164
|
{
|
|
1917
2165
|
etypes: [etype],
|
|
@@ -1922,13 +2170,13 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1922
2170
|
string: `${value}`,
|
|
1923
2171
|
number: Number(value),
|
|
1924
2172
|
},
|
|
1925
|
-
}
|
|
2173
|
+
},
|
|
1926
2174
|
);
|
|
1927
2175
|
const references = this.findReferences(svalue);
|
|
1928
2176
|
for (const reference of references) {
|
|
1929
2177
|
this.queryRun(
|
|
1930
2178
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1931
|
-
`${this.prefix}references_${etype}
|
|
2179
|
+
`${this.prefix}references_${etype}`,
|
|
1932
2180
|
)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`,
|
|
1933
2181
|
{
|
|
1934
2182
|
etypes: [etype],
|
|
@@ -1937,10 +2185,34 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1937
2185
|
name,
|
|
1938
2186
|
reference,
|
|
1939
2187
|
},
|
|
1940
|
-
}
|
|
2188
|
+
},
|
|
1941
2189
|
);
|
|
1942
2190
|
}
|
|
1943
2191
|
};
|
|
2192
|
+
for (const unique of uniques) {
|
|
2193
|
+
try {
|
|
2194
|
+
this.queryRun(
|
|
2195
|
+
`INSERT INTO ${SQLite3Driver.escape(
|
|
2196
|
+
`${this.prefix}uniques_${etype}`,
|
|
2197
|
+
)} ("guid", "unique") VALUES (@guid, @unique);`,
|
|
2198
|
+
{
|
|
2199
|
+
etypes: [etype],
|
|
2200
|
+
params: {
|
|
2201
|
+
guid,
|
|
2202
|
+
unique,
|
|
2203
|
+
},
|
|
2204
|
+
},
|
|
2205
|
+
);
|
|
2206
|
+
} catch (e: any) {
|
|
2207
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2208
|
+
this.nymph.config.debugError(
|
|
2209
|
+
'sqlite3',
|
|
2210
|
+
`Save entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`,
|
|
2211
|
+
);
|
|
2212
|
+
}
|
|
2213
|
+
throw e;
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
1944
2216
|
for (const name in data) {
|
|
1945
2217
|
runInsertQuery(name, data[name], JSON.stringify(data[name]));
|
|
1946
2218
|
}
|
|
@@ -1948,13 +2220,20 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1948
2220
|
runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
|
|
1949
2221
|
}
|
|
1950
2222
|
};
|
|
2223
|
+
let inTransaction = false;
|
|
1951
2224
|
try {
|
|
1952
2225
|
return this.saveEntityRowLike(
|
|
1953
2226
|
entity,
|
|
1954
|
-
async (
|
|
2227
|
+
async ({ guid, tags, data, sdata, uniques, cdate, etype }) => {
|
|
2228
|
+
if (
|
|
2229
|
+
Object.keys(data).length === 0 &&
|
|
2230
|
+
Object.keys(sdata).length === 0
|
|
2231
|
+
) {
|
|
2232
|
+
return false;
|
|
2233
|
+
}
|
|
1955
2234
|
this.queryRun(
|
|
1956
2235
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
1957
|
-
`${this.prefix}entities_${etype}
|
|
2236
|
+
`${this.prefix}entities_${etype}`,
|
|
1958
2237
|
)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @cdate);`,
|
|
1959
2238
|
{
|
|
1960
2239
|
etypes: [etype],
|
|
@@ -1963,15 +2242,21 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1963
2242
|
tags: ',' + tags.join(',') + ',',
|
|
1964
2243
|
cdate,
|
|
1965
2244
|
},
|
|
1966
|
-
}
|
|
2245
|
+
},
|
|
1967
2246
|
);
|
|
1968
|
-
insertData(guid, data, sdata, etype);
|
|
2247
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
1969
2248
|
return true;
|
|
1970
2249
|
},
|
|
1971
|
-
async (entity, guid, tags, data, sdata, mdate, etype) => {
|
|
2250
|
+
async ({ entity, guid, tags, data, sdata, uniques, mdate, etype }) => {
|
|
2251
|
+
if (
|
|
2252
|
+
Object.keys(data).length === 0 &&
|
|
2253
|
+
Object.keys(sdata).length === 0
|
|
2254
|
+
) {
|
|
2255
|
+
return false;
|
|
2256
|
+
}
|
|
1972
2257
|
const info = this.queryRun(
|
|
1973
2258
|
`UPDATE ${SQLite3Driver.escape(
|
|
1974
|
-
`${this.prefix}entities_${etype}
|
|
2259
|
+
`${this.prefix}entities_${etype}`,
|
|
1975
2260
|
)} SET "tags"=@tags, "mdate"=@mdate WHERE "guid"=@guid AND "mdate" <= @emdate;`,
|
|
1976
2261
|
{
|
|
1977
2262
|
etypes: [etype],
|
|
@@ -1981,62 +2266,80 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1981
2266
|
guid,
|
|
1982
2267
|
emdate: Number(entity.mdate),
|
|
1983
2268
|
},
|
|
1984
|
-
}
|
|
2269
|
+
},
|
|
1985
2270
|
);
|
|
1986
2271
|
let success = false;
|
|
1987
2272
|
if (info.changes === 1) {
|
|
1988
2273
|
this.queryRun(
|
|
1989
2274
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
1990
|
-
`${this.prefix}data_${etype}
|
|
2275
|
+
`${this.prefix}data_${etype}`,
|
|
1991
2276
|
)} WHERE "guid"=@guid;`,
|
|
1992
2277
|
{
|
|
1993
2278
|
etypes: [etype],
|
|
1994
2279
|
params: {
|
|
1995
2280
|
guid,
|
|
1996
2281
|
},
|
|
1997
|
-
}
|
|
2282
|
+
},
|
|
1998
2283
|
);
|
|
1999
2284
|
this.queryRun(
|
|
2000
2285
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2001
|
-
`${this.prefix}comparisons_${etype}
|
|
2286
|
+
`${this.prefix}comparisons_${etype}`,
|
|
2002
2287
|
)} WHERE "guid"=@guid;`,
|
|
2003
2288
|
{
|
|
2004
2289
|
etypes: [etype],
|
|
2005
2290
|
params: {
|
|
2006
2291
|
guid,
|
|
2007
2292
|
},
|
|
2008
|
-
}
|
|
2293
|
+
},
|
|
2009
2294
|
);
|
|
2010
2295
|
this.queryRun(
|
|
2011
2296
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2012
|
-
`${this.prefix}references_${etype}
|
|
2297
|
+
`${this.prefix}references_${etype}`,
|
|
2013
2298
|
)} WHERE "guid"=@guid;`,
|
|
2014
2299
|
{
|
|
2015
2300
|
etypes: [etype],
|
|
2016
2301
|
params: {
|
|
2017
2302
|
guid,
|
|
2018
2303
|
},
|
|
2019
|
-
}
|
|
2304
|
+
},
|
|
2305
|
+
);
|
|
2306
|
+
this.queryRun(
|
|
2307
|
+
`DELETE FROM ${SQLite3Driver.escape(
|
|
2308
|
+
`${this.prefix}uniques_${etype}`,
|
|
2309
|
+
)} WHERE "guid"=@guid;`,
|
|
2310
|
+
{
|
|
2311
|
+
etypes: [etype],
|
|
2312
|
+
params: {
|
|
2313
|
+
guid,
|
|
2314
|
+
},
|
|
2315
|
+
},
|
|
2020
2316
|
);
|
|
2021
|
-
insertData(guid, data, sdata, etype);
|
|
2317
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
2022
2318
|
success = true;
|
|
2023
2319
|
}
|
|
2024
2320
|
return success;
|
|
2025
2321
|
},
|
|
2026
2322
|
async () => {
|
|
2027
2323
|
await this.startTransaction('nymph-save');
|
|
2324
|
+
inTransaction = true;
|
|
2028
2325
|
},
|
|
2029
2326
|
async (success) => {
|
|
2030
|
-
if (
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2327
|
+
if (inTransaction) {
|
|
2328
|
+
inTransaction = false;
|
|
2329
|
+
if (success) {
|
|
2330
|
+
await this.commit('nymph-save');
|
|
2331
|
+
} else {
|
|
2332
|
+
await this.rollback('nymph-save');
|
|
2333
|
+
}
|
|
2034
2334
|
}
|
|
2035
2335
|
return success;
|
|
2036
|
-
}
|
|
2336
|
+
},
|
|
2037
2337
|
);
|
|
2038
2338
|
} catch (e: any) {
|
|
2039
|
-
|
|
2339
|
+
this.nymph.config.debugError('sqlite3', `Save entity error: "${e}"`);
|
|
2340
|
+
if (inTransaction) {
|
|
2341
|
+
await this.rollback('nymph-save');
|
|
2342
|
+
}
|
|
2040
2343
|
throw e;
|
|
2041
2344
|
}
|
|
2042
2345
|
}
|
|
@@ -2045,37 +2348,45 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
2045
2348
|
if (name == null) {
|
|
2046
2349
|
throw new InvalidParametersError('Name not given for UID.');
|
|
2047
2350
|
}
|
|
2048
|
-
this.
|
|
2351
|
+
await this.startTransaction('nymph-set-uid');
|
|
2049
2352
|
this.queryRun(
|
|
2050
2353
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2051
|
-
`${this.prefix}uids
|
|
2354
|
+
`${this.prefix}uids`,
|
|
2052
2355
|
)} WHERE "name"=@name;`,
|
|
2053
2356
|
{
|
|
2054
2357
|
params: {
|
|
2055
2358
|
name,
|
|
2056
2359
|
},
|
|
2057
|
-
}
|
|
2360
|
+
},
|
|
2058
2361
|
);
|
|
2059
2362
|
this.queryRun(
|
|
2060
2363
|
`INSERT INTO ${SQLite3Driver.escape(
|
|
2061
|
-
`${this.prefix}uids
|
|
2364
|
+
`${this.prefix}uids`,
|
|
2062
2365
|
)} ("name", "cur_uid") VALUES (@name, @curUid);`,
|
|
2063
2366
|
{
|
|
2064
2367
|
params: {
|
|
2065
2368
|
name,
|
|
2066
2369
|
curUid,
|
|
2067
2370
|
},
|
|
2068
|
-
}
|
|
2371
|
+
},
|
|
2069
2372
|
);
|
|
2373
|
+
await this.commit('nymph-set-uid');
|
|
2070
2374
|
return true;
|
|
2071
2375
|
}
|
|
2072
2376
|
|
|
2377
|
+
public async internalTransaction(name: string) {
|
|
2378
|
+
await this.startTransaction(name);
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2073
2381
|
public async startTransaction(name: string) {
|
|
2074
2382
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
2075
2383
|
throw new InvalidParametersError(
|
|
2076
|
-
'Transaction start attempted without a name.'
|
|
2384
|
+
'Transaction start attempted without a name.',
|
|
2077
2385
|
);
|
|
2078
2386
|
}
|
|
2387
|
+
if (!this.config.explicitWrite && !this.store.linkWrite) {
|
|
2388
|
+
this._connect(true);
|
|
2389
|
+
}
|
|
2079
2390
|
this.queryRun(`SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
2080
2391
|
this.store.transactionsStarted++;
|
|
2081
2392
|
return this.nymph;
|