@nymphjs/driver-sqlite3 1.0.0-beta.2 → 1.0.0-beta.21
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 +90 -0
- package/dist/SQLite3Driver.d.ts +13 -6
- package/dist/SQLite3Driver.js +173 -60
- package/dist/SQLite3Driver.js.map +1 -1
- package/dist/SQLite3Driver.test.js +39 -5
- package/dist/SQLite3Driver.test.js.map +1 -1
- package/dist/conf/d.d.ts +2 -1
- package/dist/conf/defaults.js +2 -1
- package/dist/conf/defaults.js.map +1 -1
- package/package.json +11 -11
- package/src/SQLite3Driver.test.ts +41 -6
- package/src/SQLite3Driver.ts +229 -89
- package/src/conf/d.ts +21 -2
- package/src/conf/defaults.ts +2 -1
package/src/SQLite3Driver.ts
CHANGED
|
@@ -21,16 +21,25 @@ import {
|
|
|
21
21
|
SQLite3DriverConfigDefaults as defaults,
|
|
22
22
|
} from './conf';
|
|
23
23
|
|
|
24
|
+
class InternalStore {
|
|
25
|
+
public link: SQLite3.Database;
|
|
26
|
+
public linkWrite?: SQLite3.Database;
|
|
27
|
+
public connected: boolean = false;
|
|
28
|
+
public transactionsStarted = 0;
|
|
29
|
+
|
|
30
|
+
constructor(link: SQLite3.Database) {
|
|
31
|
+
this.link = link;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
24
35
|
/**
|
|
25
36
|
* The SQLite3 Nymph database driver.
|
|
26
37
|
*/
|
|
27
38
|
export default class SQLite3Driver extends NymphDriver {
|
|
28
39
|
public config: SQLite3DriverConfig;
|
|
29
40
|
protected prefix: string;
|
|
30
|
-
protected connected: boolean = false;
|
|
31
41
|
// @ts-ignore: this is assigned in connect(), which is called by the constructor.
|
|
32
|
-
protected
|
|
33
|
-
protected transactionsStarted = 0;
|
|
42
|
+
protected store: InternalStore;
|
|
34
43
|
|
|
35
44
|
static escape(input: string) {
|
|
36
45
|
if (input.indexOf('\x00') !== -1) {
|
|
@@ -42,11 +51,27 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
42
51
|
return '"' + input.replace(/"/g, () => '""') + '"';
|
|
43
52
|
}
|
|
44
53
|
|
|
45
|
-
constructor(config: Partial<SQLite3DriverConfig
|
|
54
|
+
constructor(config: Partial<SQLite3DriverConfig>, store?: InternalStore) {
|
|
46
55
|
super();
|
|
47
56
|
this.config = { ...defaults, ...config };
|
|
57
|
+
if (this.config.filename === ':memory:') {
|
|
58
|
+
this.config.explicitWrite = true;
|
|
59
|
+
}
|
|
48
60
|
this.prefix = this.config.prefix;
|
|
49
|
-
|
|
61
|
+
if (store) {
|
|
62
|
+
this.store = store;
|
|
63
|
+
} else {
|
|
64
|
+
this.connect();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* This is used internally by Nymph. Don't call it yourself.
|
|
70
|
+
*
|
|
71
|
+
* @returns A clone of this instance.
|
|
72
|
+
*/
|
|
73
|
+
public clone() {
|
|
74
|
+
return new SQLite3Driver(this.config, this.store);
|
|
50
75
|
}
|
|
51
76
|
|
|
52
77
|
/**
|
|
@@ -54,41 +79,104 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
54
79
|
*
|
|
55
80
|
* @returns Whether this instance is connected to a SQLite3 database.
|
|
56
81
|
*/
|
|
57
|
-
public
|
|
58
|
-
|
|
82
|
+
public connect() {
|
|
83
|
+
if (this.store && this.store.connected) {
|
|
84
|
+
return Promise.resolve(true);
|
|
85
|
+
}
|
|
86
|
+
|
|
59
87
|
// Connecting
|
|
60
|
-
|
|
88
|
+
this._connect(false);
|
|
89
|
+
|
|
90
|
+
return Promise.resolve(this.store.connected);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private _connect(write: boolean) {
|
|
94
|
+
const { filename, fileMustExist, timeout, explicitWrite, wal, verbose } =
|
|
95
|
+
this.config;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
const setOptions = (link: SQLite3.Database) => {
|
|
99
|
+
// Set database and connection options.
|
|
100
|
+
if (wal) {
|
|
101
|
+
link.pragma('journal_mode = WAL;');
|
|
102
|
+
}
|
|
103
|
+
link.pragma('encoding = "UTF-8";');
|
|
104
|
+
link.pragma('foreign_keys = 1;');
|
|
105
|
+
link.pragma('case_sensitive_like = 1;');
|
|
106
|
+
// Create the preg_match and regexp functions.
|
|
107
|
+
link.function('regexp', { deterministic: true }, ((
|
|
108
|
+
pattern: string,
|
|
109
|
+
subject: string
|
|
110
|
+
) => (this.posixRegexMatch(pattern, subject) ? 1 : 0)) as (
|
|
111
|
+
...params: any[]
|
|
112
|
+
) => any);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
let link: SQLite3.Database;
|
|
61
116
|
try {
|
|
62
|
-
|
|
63
|
-
readonly,
|
|
117
|
+
link = new SQLite3(filename, {
|
|
118
|
+
readonly: !explicitWrite && !write,
|
|
64
119
|
fileMustExist,
|
|
65
120
|
timeout,
|
|
66
121
|
verbose,
|
|
67
122
|
});
|
|
68
|
-
this.connected = true;
|
|
69
|
-
// Set database and connection options.
|
|
70
|
-
this.link.pragma('encoding = "UTF-8";');
|
|
71
|
-
this.link.pragma('foreign_keys = 1;');
|
|
72
|
-
this.link.pragma('case_sensitive_like = 1;');
|
|
73
|
-
// Create the preg_match and regexp functions.
|
|
74
|
-
this.link.function(
|
|
75
|
-
'regexp',
|
|
76
|
-
{ deterministic: true },
|
|
77
|
-
(pattern: string, subject: string) =>
|
|
78
|
-
this.posixRegexMatch(pattern, subject) ? 1 : 0
|
|
79
|
-
);
|
|
80
123
|
} catch (e: any) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
124
|
+
if (
|
|
125
|
+
e.code === 'SQLITE_CANTOPEN' &&
|
|
126
|
+
!explicitWrite &&
|
|
127
|
+
!write &&
|
|
128
|
+
!this.config.fileMustExist
|
|
129
|
+
) {
|
|
130
|
+
// This happens when the file doesn't exist and we attempt to open it
|
|
131
|
+
// readonly.
|
|
132
|
+
// First open it in write mode.
|
|
133
|
+
const writeLink = new SQLite3(filename, {
|
|
134
|
+
readonly: false,
|
|
135
|
+
fileMustExist,
|
|
136
|
+
timeout,
|
|
137
|
+
verbose,
|
|
138
|
+
});
|
|
139
|
+
setOptions(writeLink);
|
|
140
|
+
writeLink.close();
|
|
141
|
+
// Now open in readonly.
|
|
142
|
+
link = new SQLite3(filename, {
|
|
143
|
+
readonly: true,
|
|
144
|
+
fileMustExist,
|
|
145
|
+
timeout,
|
|
146
|
+
verbose,
|
|
147
|
+
});
|
|
86
148
|
} else {
|
|
87
|
-
throw
|
|
149
|
+
throw e;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!this.store) {
|
|
154
|
+
if (write) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
'Tried to open in write without opening in read first.'
|
|
157
|
+
);
|
|
88
158
|
}
|
|
159
|
+
this.store = new InternalStore(link);
|
|
160
|
+
} else if (write) {
|
|
161
|
+
this.store.linkWrite = link;
|
|
162
|
+
} else {
|
|
163
|
+
this.store.link = link;
|
|
164
|
+
}
|
|
165
|
+
this.store.connected = true;
|
|
166
|
+
setOptions(link);
|
|
167
|
+
} catch (e: any) {
|
|
168
|
+
if (this.store) {
|
|
169
|
+
this.store.connected = false;
|
|
170
|
+
}
|
|
171
|
+
if (filename === ':memory:') {
|
|
172
|
+
throw new NotConfiguredError(
|
|
173
|
+
"It seems the config hasn't been set up correctly. Could not connect: " +
|
|
174
|
+
e?.message
|
|
175
|
+
);
|
|
176
|
+
} else {
|
|
177
|
+
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
89
178
|
}
|
|
90
179
|
}
|
|
91
|
-
return this.connected;
|
|
92
180
|
}
|
|
93
181
|
|
|
94
182
|
/**
|
|
@@ -97,16 +185,24 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
97
185
|
* @returns Whether this instance is connected to a SQLite3 database.
|
|
98
186
|
*/
|
|
99
187
|
public async disconnect() {
|
|
100
|
-
if (this.connected) {
|
|
101
|
-
this.
|
|
102
|
-
|
|
103
|
-
|
|
188
|
+
if (this.store.connected) {
|
|
189
|
+
if (this.store.linkWrite && !this.config.explicitWrite) {
|
|
190
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
191
|
+
this.store.linkWrite.close();
|
|
192
|
+
this.store.linkWrite = undefined;
|
|
193
|
+
}
|
|
194
|
+
if (this.config.explicitWrite) {
|
|
195
|
+
this.store.link.exec('PRAGMA optimize;');
|
|
196
|
+
}
|
|
197
|
+
this.store.link.close();
|
|
198
|
+
this.store.transactionsStarted = 0;
|
|
199
|
+
this.store.connected = false;
|
|
104
200
|
}
|
|
105
|
-
return this.connected;
|
|
201
|
+
return this.store.connected;
|
|
106
202
|
}
|
|
107
203
|
|
|
108
204
|
public async inTransaction() {
|
|
109
|
-
return this.transactionsStarted > 0;
|
|
205
|
+
return this.store.transactionsStarted > 0;
|
|
110
206
|
}
|
|
111
207
|
|
|
112
208
|
/**
|
|
@@ -115,18 +211,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
115
211
|
* @returns Whether this instance is connected to a SQLite3 database.
|
|
116
212
|
*/
|
|
117
213
|
public isConnected() {
|
|
118
|
-
return this.connected;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Check if SQLite3 DB is read only and throw error if so.
|
|
123
|
-
*/
|
|
124
|
-
private checkReadOnlyMode() {
|
|
125
|
-
if (this.config.readonly) {
|
|
126
|
-
throw new InvalidParametersError(
|
|
127
|
-
'Attempt to write to SQLite3 DB in read only mode.'
|
|
128
|
-
);
|
|
129
|
-
}
|
|
214
|
+
return this.store.connected;
|
|
130
215
|
}
|
|
131
216
|
|
|
132
217
|
/**
|
|
@@ -135,7 +220,6 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
135
220
|
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
136
221
|
*/
|
|
137
222
|
private createTables(etype: string | null = null) {
|
|
138
|
-
this.checkReadOnlyMode();
|
|
139
223
|
this.startTransaction('nymph-tablecreation');
|
|
140
224
|
try {
|
|
141
225
|
if (etype != null) {
|
|
@@ -326,7 +410,10 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
326
410
|
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
327
411
|
) {
|
|
328
412
|
return this.query(
|
|
329
|
-
() =>
|
|
413
|
+
() =>
|
|
414
|
+
(this.store.linkWrite || this.store.link)
|
|
415
|
+
.prepare(query)
|
|
416
|
+
.iterate(params),
|
|
330
417
|
`${query} -- ${JSON.stringify(params)}`,
|
|
331
418
|
etypes
|
|
332
419
|
);
|
|
@@ -340,7 +427,8 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
340
427
|
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
341
428
|
) {
|
|
342
429
|
return this.query(
|
|
343
|
-
() =>
|
|
430
|
+
() =>
|
|
431
|
+
(this.store.linkWrite || this.store.link).prepare(query).get(params),
|
|
344
432
|
`${query} -- ${JSON.stringify(params)}`,
|
|
345
433
|
etypes
|
|
346
434
|
);
|
|
@@ -354,7 +442,8 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
354
442
|
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
355
443
|
) {
|
|
356
444
|
return this.query(
|
|
357
|
-
() =>
|
|
445
|
+
() =>
|
|
446
|
+
(this.store.linkWrite || this.store.link).prepare(query).run(params),
|
|
358
447
|
`${query} -- ${JSON.stringify(params)}`,
|
|
359
448
|
etypes
|
|
360
449
|
);
|
|
@@ -366,11 +455,22 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
366
455
|
'Transaction commit attempted without a name.'
|
|
367
456
|
);
|
|
368
457
|
}
|
|
369
|
-
if (this.transactionsStarted === 0) {
|
|
458
|
+
if (this.store.transactionsStarted === 0) {
|
|
370
459
|
return true;
|
|
371
460
|
}
|
|
372
461
|
this.queryRun(`RELEASE SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
373
|
-
this.transactionsStarted--;
|
|
462
|
+
this.store.transactionsStarted--;
|
|
463
|
+
|
|
464
|
+
if (
|
|
465
|
+
this.store.transactionsStarted === 0 &&
|
|
466
|
+
this.store.linkWrite &&
|
|
467
|
+
!this.config.explicitWrite
|
|
468
|
+
) {
|
|
469
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
470
|
+
this.store.linkWrite.close();
|
|
471
|
+
this.store.linkWrite = undefined;
|
|
472
|
+
}
|
|
473
|
+
|
|
374
474
|
return true;
|
|
375
475
|
}
|
|
376
476
|
|
|
@@ -386,7 +486,6 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
386
486
|
EntityClass = className;
|
|
387
487
|
}
|
|
388
488
|
const etype = EntityClass.ETYPE;
|
|
389
|
-
this.checkReadOnlyMode();
|
|
390
489
|
await this.startTransaction('nymph-delete');
|
|
391
490
|
try {
|
|
392
491
|
this.queryRun(
|
|
@@ -449,7 +548,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
449
548
|
if (!name) {
|
|
450
549
|
throw new InvalidParametersError('Name not given for UID');
|
|
451
550
|
}
|
|
452
|
-
this.
|
|
551
|
+
await this.startTransaction('nymph-delete-uid');
|
|
453
552
|
this.queryRun(
|
|
454
553
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
455
554
|
`${this.prefix}uids`
|
|
@@ -460,6 +559,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
460
559
|
},
|
|
461
560
|
}
|
|
462
561
|
);
|
|
562
|
+
await this.commit('nymph-delete-uid');
|
|
463
563
|
return true;
|
|
464
564
|
}
|
|
465
565
|
|
|
@@ -477,7 +577,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
477
577
|
writeLine('');
|
|
478
578
|
|
|
479
579
|
// Export UIDs.
|
|
480
|
-
let uids = this.queryIter(
|
|
580
|
+
let uids: IterableIterator<any> = this.queryIter(
|
|
481
581
|
`SELECT * FROM ${SQLite3Driver.escape(
|
|
482
582
|
`${this.prefix}uids`
|
|
483
583
|
)} ORDER BY "name";`
|
|
@@ -493,7 +593,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
493
593
|
writeLine('');
|
|
494
594
|
|
|
495
595
|
// Get the etypes.
|
|
496
|
-
const tables = this.queryIter(
|
|
596
|
+
const tables: IterableIterator<any> = this.queryIter(
|
|
497
597
|
"SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name;"
|
|
498
598
|
);
|
|
499
599
|
const etypes = [];
|
|
@@ -505,7 +605,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
505
605
|
|
|
506
606
|
for (const etype of etypes) {
|
|
507
607
|
// Export entities.
|
|
508
|
-
const dataIterator = this.queryIter(
|
|
608
|
+
const dataIterator: IterableIterator<any> = this.queryIter(
|
|
509
609
|
`SELECT e.*, d."name" AS "dname", d."value" AS "dvalue", c."string", c."number" FROM ${SQLite3Driver.escape(
|
|
510
610
|
`${this.prefix}entities_${etype}`
|
|
511
611
|
)} e LEFT JOIN ${SQLite3Driver.escape(
|
|
@@ -574,6 +674,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
574
674
|
const cTable = `c${tableSuffix}`;
|
|
575
675
|
const fTable = `f${tableSuffix}`;
|
|
576
676
|
const ieTable = `ie${tableSuffix}`;
|
|
677
|
+
const sTable = `s${tableSuffix}`;
|
|
577
678
|
const sort = options.sort ?? 'cdate';
|
|
578
679
|
const queryParts = this.iterateSelectorsForQuery(
|
|
579
680
|
formattedSelectors,
|
|
@@ -1319,18 +1420,31 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1319
1420
|
);
|
|
1320
1421
|
|
|
1321
1422
|
let sortBy: string;
|
|
1423
|
+
let sortByInner: string;
|
|
1424
|
+
let sortJoin = '';
|
|
1425
|
+
const order = options.reverse ? ' DESC' : '';
|
|
1322
1426
|
switch (sort) {
|
|
1323
1427
|
case 'mdate':
|
|
1324
|
-
sortBy =
|
|
1428
|
+
sortBy = `${eTable}."mdate"${order}`;
|
|
1429
|
+
sortByInner = `${ieTable}."mdate"${order}`;
|
|
1325
1430
|
break;
|
|
1326
1431
|
case 'cdate':
|
|
1432
|
+
sortBy = `${eTable}."cdate"${order}`;
|
|
1433
|
+
sortByInner = `${ieTable}."cdate"${order}`;
|
|
1434
|
+
break;
|
|
1327
1435
|
default:
|
|
1328
|
-
|
|
1436
|
+
const name = `param${++count.i}`;
|
|
1437
|
+
sortJoin = `LEFT JOIN (
|
|
1438
|
+
SELECT "guid", "string", "number"
|
|
1439
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'comparisons_' + etype)}
|
|
1440
|
+
WHERE "name"=@${name}
|
|
1441
|
+
ORDER BY "number"${order}, "string"${order}
|
|
1442
|
+
) ${sTable} USING ("guid")`;
|
|
1443
|
+
sortBy = `${sTable}."number"${order}, ${sTable}."string"${order}`;
|
|
1444
|
+
sortByInner = sortBy;
|
|
1445
|
+
params[name] = sort;
|
|
1329
1446
|
break;
|
|
1330
1447
|
}
|
|
1331
|
-
if (options.reverse) {
|
|
1332
|
-
sortBy += ' DESC';
|
|
1333
|
-
}
|
|
1334
1448
|
|
|
1335
1449
|
let query: string;
|
|
1336
1450
|
if (queryParts.length) {
|
|
@@ -1367,8 +1481,9 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1367
1481
|
FROM ${SQLite3Driver.escape(
|
|
1368
1482
|
this.prefix + 'entities_' + etype
|
|
1369
1483
|
)} ${ieTable}
|
|
1484
|
+
${sortJoin}
|
|
1370
1485
|
WHERE (${whereClause})
|
|
1371
|
-
ORDER BY ${
|
|
1486
|
+
ORDER BY ${sortByInner}, "guid"${limit}${offset}`;
|
|
1372
1487
|
} else {
|
|
1373
1488
|
query = `SELECT
|
|
1374
1489
|
${eTable}."guid",
|
|
@@ -1388,15 +1503,17 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1388
1503
|
INNER JOIN ${SQLite3Driver.escape(
|
|
1389
1504
|
this.prefix + 'comparisons_' + etype
|
|
1390
1505
|
)} ${cTable} USING ("guid", "name")
|
|
1506
|
+
${sortJoin}
|
|
1391
1507
|
INNER JOIN (
|
|
1392
1508
|
SELECT "guid"
|
|
1393
1509
|
FROM ${SQLite3Driver.escape(
|
|
1394
1510
|
this.prefix + 'entities_' + etype
|
|
1395
1511
|
)} ${ieTable}
|
|
1512
|
+
${sortJoin}
|
|
1396
1513
|
WHERE (${whereClause})
|
|
1397
|
-
ORDER BY ${
|
|
1514
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1398
1515
|
) ${fTable} USING ("guid")
|
|
1399
|
-
ORDER BY ${
|
|
1516
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1400
1517
|
}
|
|
1401
1518
|
}
|
|
1402
1519
|
} else {
|
|
@@ -1430,7 +1547,8 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1430
1547
|
FROM ${SQLite3Driver.escape(
|
|
1431
1548
|
this.prefix + 'entities_' + etype
|
|
1432
1549
|
)} ${ieTable}
|
|
1433
|
-
|
|
1550
|
+
${sortJoin}
|
|
1551
|
+
ORDER BY ${sortByInner}, "guid"${limit}${offset}`;
|
|
1434
1552
|
} else {
|
|
1435
1553
|
if (limit || offset) {
|
|
1436
1554
|
query = `SELECT
|
|
@@ -1451,14 +1569,16 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1451
1569
|
INNER JOIN ${SQLite3Driver.escape(
|
|
1452
1570
|
this.prefix + 'comparisons_' + etype
|
|
1453
1571
|
)} c USING ("guid", "name")
|
|
1572
|
+
${sortJoin}
|
|
1454
1573
|
INNER JOIN (
|
|
1455
1574
|
SELECT "guid"
|
|
1456
1575
|
FROM ${SQLite3Driver.escape(
|
|
1457
1576
|
this.prefix + 'entities_' + etype
|
|
1458
1577
|
)} ${ieTable}
|
|
1459
|
-
|
|
1578
|
+
${sortJoin}
|
|
1579
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1460
1580
|
) ${fTable} USING ("guid")
|
|
1461
|
-
ORDER BY ${
|
|
1581
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1462
1582
|
} else {
|
|
1463
1583
|
query = `SELECT
|
|
1464
1584
|
${eTable}."guid",
|
|
@@ -1478,7 +1598,8 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1478
1598
|
INNER JOIN ${SQLite3Driver.escape(
|
|
1479
1599
|
this.prefix + 'comparisons_' + etype
|
|
1480
1600
|
)} ${cTable} USING ("guid", "name")
|
|
1481
|
-
|
|
1601
|
+
${sortJoin}
|
|
1602
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1482
1603
|
}
|
|
1483
1604
|
}
|
|
1484
1605
|
}
|
|
@@ -1575,14 +1696,18 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1575
1696
|
: row.value,
|
|
1576
1697
|
})
|
|
1577
1698
|
);
|
|
1578
|
-
|
|
1699
|
+
const value = process();
|
|
1700
|
+
if (value instanceof Error) {
|
|
1701
|
+
throw value;
|
|
1702
|
+
}
|
|
1703
|
+
return value;
|
|
1579
1704
|
}
|
|
1580
1705
|
|
|
1581
1706
|
public async getUID(name: string) {
|
|
1582
1707
|
if (name == null) {
|
|
1583
1708
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1584
1709
|
}
|
|
1585
|
-
const result = this.queryGet(
|
|
1710
|
+
const result: any = this.queryGet(
|
|
1586
1711
|
`SELECT "cur_uid" FROM ${SQLite3Driver.escape(
|
|
1587
1712
|
`${this.prefix}uids`
|
|
1588
1713
|
)} WHERE "name"=@name;`,
|
|
@@ -1596,7 +1721,6 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1596
1721
|
}
|
|
1597
1722
|
|
|
1598
1723
|
public async import(filename: string) {
|
|
1599
|
-
this.checkReadOnlyMode();
|
|
1600
1724
|
try {
|
|
1601
1725
|
return this.importFromFile(
|
|
1602
1726
|
filename,
|
|
@@ -1759,19 +1883,20 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1759
1883
|
if (name == null) {
|
|
1760
1884
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1761
1885
|
}
|
|
1762
|
-
this.checkReadOnlyMode();
|
|
1763
1886
|
await this.startTransaction('nymph-newuid');
|
|
1764
1887
|
try {
|
|
1765
1888
|
let curUid =
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1889
|
+
(
|
|
1890
|
+
this.queryGet(
|
|
1891
|
+
`SELECT "cur_uid" FROM ${SQLite3Driver.escape(
|
|
1892
|
+
`${this.prefix}uids`
|
|
1893
|
+
)} WHERE "name"=@name;`,
|
|
1894
|
+
{
|
|
1895
|
+
params: {
|
|
1896
|
+
name,
|
|
1897
|
+
},
|
|
1898
|
+
}
|
|
1899
|
+
) as any
|
|
1775
1900
|
)?.cur_uid ?? null;
|
|
1776
1901
|
if (curUid == null) {
|
|
1777
1902
|
curUid = 1;
|
|
@@ -1812,7 +1937,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1812
1937
|
if (oldName == null || newName == null) {
|
|
1813
1938
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1814
1939
|
}
|
|
1815
|
-
this.
|
|
1940
|
+
await this.startTransaction('nymph-rename-uid');
|
|
1816
1941
|
this.queryRun(
|
|
1817
1942
|
`UPDATE ${SQLite3Driver.escape(
|
|
1818
1943
|
`${this.prefix}uids`
|
|
@@ -1824,6 +1949,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1824
1949
|
},
|
|
1825
1950
|
}
|
|
1826
1951
|
);
|
|
1952
|
+
await this.commit('nymph-rename-uid');
|
|
1827
1953
|
return true;
|
|
1828
1954
|
}
|
|
1829
1955
|
|
|
@@ -1833,16 +1959,26 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
1833
1959
|
'Transaction rollback attempted without a name.'
|
|
1834
1960
|
);
|
|
1835
1961
|
}
|
|
1836
|
-
if (this.transactionsStarted === 0) {
|
|
1962
|
+
if (this.store.transactionsStarted === 0) {
|
|
1837
1963
|
return true;
|
|
1838
1964
|
}
|
|
1839
1965
|
this.queryRun(`ROLLBACK TO SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
1840
|
-
this.transactionsStarted--;
|
|
1966
|
+
this.store.transactionsStarted--;
|
|
1967
|
+
|
|
1968
|
+
if (
|
|
1969
|
+
this.store.transactionsStarted === 0 &&
|
|
1970
|
+
this.store.linkWrite &&
|
|
1971
|
+
!this.config.explicitWrite
|
|
1972
|
+
) {
|
|
1973
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
1974
|
+
this.store.linkWrite.close();
|
|
1975
|
+
this.store.linkWrite = undefined;
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1841
1978
|
return true;
|
|
1842
1979
|
}
|
|
1843
1980
|
|
|
1844
1981
|
public async saveEntity(entity: EntityInterface) {
|
|
1845
|
-
this.checkReadOnlyMode();
|
|
1846
1982
|
const insertData = (
|
|
1847
1983
|
guid: string,
|
|
1848
1984
|
data: EntityData,
|
|
@@ -2008,7 +2144,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
2008
2144
|
if (name == null) {
|
|
2009
2145
|
throw new InvalidParametersError('Name not given for UID.');
|
|
2010
2146
|
}
|
|
2011
|
-
this.
|
|
2147
|
+
await this.startTransaction('nymph-set-uid');
|
|
2012
2148
|
this.queryRun(
|
|
2013
2149
|
`DELETE FROM ${SQLite3Driver.escape(
|
|
2014
2150
|
`${this.prefix}uids`
|
|
@@ -2030,6 +2166,7 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
2030
2166
|
},
|
|
2031
2167
|
}
|
|
2032
2168
|
);
|
|
2169
|
+
await this.commit('nymph-set-uid');
|
|
2033
2170
|
return true;
|
|
2034
2171
|
}
|
|
2035
2172
|
|
|
@@ -2039,8 +2176,11 @@ export default class SQLite3Driver extends NymphDriver {
|
|
|
2039
2176
|
'Transaction start attempted without a name.'
|
|
2040
2177
|
);
|
|
2041
2178
|
}
|
|
2179
|
+
if (!this.config.explicitWrite && !this.store.linkWrite) {
|
|
2180
|
+
this._connect(true);
|
|
2181
|
+
}
|
|
2042
2182
|
this.queryRun(`SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
2043
|
-
this.transactionsStarted++;
|
|
2183
|
+
this.store.transactionsStarted++;
|
|
2044
2184
|
return this.nymph;
|
|
2045
2185
|
}
|
|
2046
2186
|
}
|
package/src/conf/d.ts
CHANGED
|
@@ -23,9 +23,28 @@ export interface SQLite3DriverConfig {
|
|
|
23
23
|
*/
|
|
24
24
|
timeout: number;
|
|
25
25
|
/**
|
|
26
|
-
* Open
|
|
26
|
+
* Open explicitly for writing.
|
|
27
|
+
*
|
|
28
|
+
* By default, the driver will always open the DB as readonly, and attempt to
|
|
29
|
+
* open another link to perform write operations. If you know that only one
|
|
30
|
+
* instance will be writing, you can force the driver to open for writing by
|
|
31
|
+
* default, which will block any other instance from opening it for writing.
|
|
32
|
+
*
|
|
33
|
+
* One thing to note is that starting a transaction is a write operation, so
|
|
34
|
+
* as long as an instance is in a transaction, no other instances can write.
|
|
35
|
+
*
|
|
36
|
+
* PubSub also needs to open the DB, and it only needs read access.
|
|
37
|
+
*/
|
|
38
|
+
explicitWrite: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Turn on WAL mode.
|
|
41
|
+
*
|
|
42
|
+
* This will generally increase performance, but does mean that the DB must be
|
|
43
|
+
* on a local disk.
|
|
44
|
+
*
|
|
45
|
+
* See: https://www.sqlite.org/wal.html
|
|
27
46
|
*/
|
|
28
|
-
|
|
47
|
+
wal: boolean;
|
|
29
48
|
/**
|
|
30
49
|
* Function that gets called with every SQL string executed.
|
|
31
50
|
*/
|