@nymphjs/driver-sqlite3 1.0.0-beta.1 → 1.0.0-beta.100
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 +484 -0
- package/README.md +1 -1
- package/dist/SQLite3Driver.d.ts +92 -19
- package/dist/SQLite3Driver.js +925 -359
- package/dist/SQLite3Driver.js.map +1 -1
- package/dist/SQLite3Driver.test.js +47 -15
- package/dist/SQLite3Driver.test.js.map +1 -1
- package/dist/conf/d.d.ts +59 -1
- package/dist/conf/d.js +1 -2
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +4 -4
- package/dist/conf/defaults.js.map +1 -1
- package/dist/conf/index.d.ts +2 -2
- package/dist/conf/index.js +2 -8
- package/dist/conf/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -24
- package/dist/index.js.map +1 -1
- package/jest.config.js +12 -2
- package/package.json +18 -16
- package/src/SQLite3Driver.test.ts +44 -9
- package/src/SQLite3Driver.ts +1387 -636
- package/src/conf/d.ts +35 -2
- package/src/conf/defaults.ts +4 -2
- package/src/conf/index.ts +2 -2
- package/src/index.ts +2 -2
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
package/dist/SQLite3Driver.js
CHANGED
|
@@ -1,111 +1,256 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import SQLite3 from 'better-sqlite3';
|
|
2
|
+
import { NymphDriver, EntityUniqueConstraintError, InvalidParametersError, NotConfiguredError, QueryFailedError, UnableToConnectError, xor, } from '@nymphjs/nymph';
|
|
3
|
+
import { makeTableSuffix } from '@nymphjs/guid';
|
|
4
|
+
import { SQLite3DriverConfigDefaults as defaults, } from './conf/index.js';
|
|
5
|
+
class InternalStore {
|
|
6
|
+
link;
|
|
7
|
+
linkWrite;
|
|
8
|
+
connected = false;
|
|
9
|
+
transactionsStarted = 0;
|
|
10
|
+
constructor(link) {
|
|
11
|
+
this.link = link;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The SQLite3 Nymph database driver.
|
|
16
|
+
*/
|
|
17
|
+
export default class SQLite3Driver extends NymphDriver {
|
|
18
|
+
config;
|
|
19
|
+
prefix;
|
|
20
|
+
// @ts-ignore: this is assigned in connect(), which is called by the constructor.
|
|
21
|
+
store;
|
|
11
22
|
static escape(input) {
|
|
12
23
|
if (input.indexOf('\x00') !== -1) {
|
|
13
|
-
throw new
|
|
24
|
+
throw new InvalidParametersError('SQLite3 identifiers (like entity ETYPE) cannot contain null characters.');
|
|
14
25
|
}
|
|
15
26
|
return '"' + input.replace(/"/g, () => '""') + '"';
|
|
16
27
|
}
|
|
17
|
-
constructor(config) {
|
|
28
|
+
constructor(config, store) {
|
|
18
29
|
super();
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
-
|
|
30
|
+
this.config = { ...defaults, ...config };
|
|
31
|
+
if (this.config.filename === ':memory:') {
|
|
32
|
+
this.config.explicitWrite = true;
|
|
33
|
+
}
|
|
22
34
|
this.prefix = this.config.prefix;
|
|
23
|
-
|
|
35
|
+
if (store) {
|
|
36
|
+
this.store = store;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.connect();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* This is used internally by Nymph. Don't call it yourself.
|
|
44
|
+
*
|
|
45
|
+
* @returns A clone of this instance.
|
|
46
|
+
*/
|
|
47
|
+
clone() {
|
|
48
|
+
return new SQLite3Driver(this.config, this.store);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Connect to the SQLite3 database.
|
|
52
|
+
*
|
|
53
|
+
* @returns Whether this instance is connected to a SQLite3 database.
|
|
54
|
+
*/
|
|
55
|
+
connect() {
|
|
56
|
+
if (this.store && this.store.connected) {
|
|
57
|
+
return Promise.resolve(true);
|
|
58
|
+
}
|
|
59
|
+
// Connecting
|
|
60
|
+
this._connect(false);
|
|
61
|
+
return Promise.resolve(this.store.connected);
|
|
24
62
|
}
|
|
25
|
-
|
|
26
|
-
const { filename, fileMustExist, timeout,
|
|
27
|
-
|
|
63
|
+
_connect(write) {
|
|
64
|
+
const { filename, fileMustExist, timeout, explicitWrite, wal, verbose } = this.config;
|
|
65
|
+
try {
|
|
66
|
+
const setOptions = (link) => {
|
|
67
|
+
// Set database and connection options.
|
|
68
|
+
if (wal) {
|
|
69
|
+
link.pragma('journal_mode = WAL;');
|
|
70
|
+
}
|
|
71
|
+
link.pragma('encoding = "UTF-8";');
|
|
72
|
+
link.pragma('foreign_keys = 1;');
|
|
73
|
+
link.pragma('case_sensitive_like = 1;');
|
|
74
|
+
for (let pragma of this.config.pragmas) {
|
|
75
|
+
link.pragma(pragma);
|
|
76
|
+
}
|
|
77
|
+
// Create the preg_match and regexp functions.
|
|
78
|
+
link.function('regexp', { deterministic: true }, ((pattern, subject) => (this.posixRegexMatch(pattern, subject) ? 1 : 0)));
|
|
79
|
+
};
|
|
80
|
+
let link;
|
|
28
81
|
try {
|
|
29
|
-
|
|
30
|
-
readonly,
|
|
82
|
+
link = new SQLite3(filename, {
|
|
83
|
+
readonly: !explicitWrite && !write,
|
|
31
84
|
fileMustExist,
|
|
32
85
|
timeout,
|
|
33
86
|
verbose,
|
|
34
87
|
});
|
|
35
|
-
this.connected = true;
|
|
36
|
-
this.link.pragma('encoding = "UTF-8";');
|
|
37
|
-
this.link.pragma('foreign_keys = 1;');
|
|
38
|
-
this.link.pragma('case_sensitive_like = 1;');
|
|
39
|
-
this.link.function('regexp', { deterministic: true }, (pattern, subject) => this.posixRegexMatch(pattern, subject) ? 1 : 0);
|
|
40
88
|
}
|
|
41
89
|
catch (e) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
90
|
+
if (e.code === 'SQLITE_CANTOPEN' &&
|
|
91
|
+
!explicitWrite &&
|
|
92
|
+
!write &&
|
|
93
|
+
!this.config.fileMustExist) {
|
|
94
|
+
// This happens when the file doesn't exist and we attempt to open it
|
|
95
|
+
// readonly.
|
|
96
|
+
// First open it in write mode.
|
|
97
|
+
const writeLink = new SQLite3(filename, {
|
|
98
|
+
readonly: false,
|
|
99
|
+
fileMustExist,
|
|
100
|
+
timeout,
|
|
101
|
+
verbose,
|
|
102
|
+
});
|
|
103
|
+
setOptions(writeLink);
|
|
104
|
+
writeLink.close();
|
|
105
|
+
// Now open in readonly.
|
|
106
|
+
link = new SQLite3(filename, {
|
|
107
|
+
readonly: true,
|
|
108
|
+
fileMustExist,
|
|
109
|
+
timeout,
|
|
110
|
+
verbose,
|
|
111
|
+
});
|
|
45
112
|
}
|
|
46
113
|
else {
|
|
47
|
-
throw
|
|
114
|
+
throw e;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!this.store) {
|
|
118
|
+
if (write) {
|
|
119
|
+
throw new Error('Tried to open in write without opening in read first.');
|
|
48
120
|
}
|
|
121
|
+
this.store = new InternalStore(link);
|
|
122
|
+
}
|
|
123
|
+
else if (write) {
|
|
124
|
+
this.store.linkWrite = link;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
this.store.link = link;
|
|
128
|
+
}
|
|
129
|
+
this.store.connected = true;
|
|
130
|
+
setOptions(link);
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
if (this.store) {
|
|
134
|
+
this.store.connected = false;
|
|
135
|
+
}
|
|
136
|
+
if (filename === ':memory:') {
|
|
137
|
+
throw new NotConfiguredError("It seems the config hasn't been set up correctly. Could not connect: " +
|
|
138
|
+
e?.message);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
49
142
|
}
|
|
50
143
|
}
|
|
51
|
-
return this.connected;
|
|
52
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Disconnect from the SQLite3 database.
|
|
147
|
+
*
|
|
148
|
+
* @returns Whether this instance is connected to a SQLite3 database.
|
|
149
|
+
*/
|
|
53
150
|
async disconnect() {
|
|
54
|
-
if (this.connected) {
|
|
55
|
-
this.
|
|
56
|
-
|
|
57
|
-
|
|
151
|
+
if (this.store.connected) {
|
|
152
|
+
if (this.store.linkWrite && !this.config.explicitWrite) {
|
|
153
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
154
|
+
this.store.linkWrite.close();
|
|
155
|
+
this.store.linkWrite = undefined;
|
|
156
|
+
}
|
|
157
|
+
if (this.config.explicitWrite) {
|
|
158
|
+
this.store.link.exec('PRAGMA optimize;');
|
|
159
|
+
}
|
|
160
|
+
this.store.link.close();
|
|
161
|
+
this.store.transactionsStarted = 0;
|
|
162
|
+
this.store.connected = false;
|
|
58
163
|
}
|
|
59
|
-
return this.connected;
|
|
164
|
+
return this.store.connected;
|
|
60
165
|
}
|
|
61
166
|
async inTransaction() {
|
|
62
|
-
return this.transactionsStarted > 0;
|
|
167
|
+
return this.store.transactionsStarted > 0;
|
|
63
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Check connection status.
|
|
171
|
+
*
|
|
172
|
+
* @returns Whether this instance is connected to a SQLite3 database.
|
|
173
|
+
*/
|
|
64
174
|
isConnected() {
|
|
65
|
-
return this.connected;
|
|
175
|
+
return this.store.connected;
|
|
66
176
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
177
|
+
createEntitiesTable(etype) {
|
|
178
|
+
// Create the entity table.
|
|
179
|
+
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid" CHARACTER(24) PRIMARY KEY, "tags" TEXT, "cdate" REAL NOT NULL, "mdate" REAL NOT NULL);`);
|
|
180
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_cdate`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("cdate");`);
|
|
181
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_mdate`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("mdate");`);
|
|
182
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_tags`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("tags");`);
|
|
183
|
+
}
|
|
184
|
+
createDataTable(etype) {
|
|
185
|
+
// Create the data table.
|
|
186
|
+
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "value" CHARACTER(1) NOT NULL, "json" BLOB, "string" TEXT, "number" REAL, "truthy" INTEGER, PRIMARY KEY("guid", "name"));`);
|
|
187
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`);
|
|
188
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name");`);
|
|
189
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`);
|
|
190
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_string`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "string");`);
|
|
191
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_number`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "number");`);
|
|
192
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid_name_number`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "number");`);
|
|
193
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_truthy`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "truthy");`);
|
|
194
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid_name_truthy`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "truthy");`);
|
|
195
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acuserread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acUser\' AND "number" >= 1;`);
|
|
196
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acgroupread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acGroup\' AND "number" >= 1;`);
|
|
197
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acotherread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acOther\' AND "number" >= 1;`);
|
|
198
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acuser`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'user\';`);
|
|
199
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acgroup`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'group\';`);
|
|
71
200
|
}
|
|
201
|
+
createReferencesTable(etype) {
|
|
202
|
+
// Create the references table.
|
|
203
|
+
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "reference" CHARACTER(24) NOT NULL, PRIMARY KEY("guid", "name", "reference"));`);
|
|
204
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid");`);
|
|
205
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name");`);
|
|
206
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name", "reference");`);
|
|
207
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference");`);
|
|
208
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "name");`);
|
|
209
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_name_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "name", "reference");`);
|
|
210
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference_name_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference", "name", "guid");`);
|
|
211
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference_guid_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference", "guid", "name");`);
|
|
212
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_reference_nameuser`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "reference") WHERE "name"=\'user\';`);
|
|
213
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_reference_namegroup`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "reference") WHERE "name"=\'group\';`);
|
|
214
|
+
}
|
|
215
|
+
createTokensTable(etype) {
|
|
216
|
+
// Create the tokens table.
|
|
217
|
+
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "token" INTEGER NOT NULL, "position" INTEGER NOT NULL, "stem" INTEGER NOT NULL, PRIMARY KEY("guid", "name", "token", "position"));`);
|
|
218
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_name_token`)} ON ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("name", "token");`);
|
|
219
|
+
}
|
|
220
|
+
createUniquesTable(etype) {
|
|
221
|
+
// Create the unique strings table.
|
|
222
|
+
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "unique" TEXT NOT NULL UNIQUE, PRIMARY KEY("guid", "unique"));`);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Create entity tables in the database.
|
|
226
|
+
*
|
|
227
|
+
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
228
|
+
*/
|
|
72
229
|
createTables(etype = null) {
|
|
73
|
-
this.checkReadOnlyMode();
|
|
74
230
|
this.startTransaction('nymph-tablecreation');
|
|
75
231
|
try {
|
|
76
232
|
if (etype != null) {
|
|
77
|
-
this.
|
|
78
|
-
this.
|
|
79
|
-
this.
|
|
80
|
-
this.
|
|
81
|
-
this.
|
|
82
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`);
|
|
83
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`);
|
|
84
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_value`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("value");`);
|
|
85
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid__name_user`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name" = \'user\';`);
|
|
86
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid__name_group`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name" = \'group\';`);
|
|
87
|
-
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "truthy" INTEGER, "string" TEXT, "number" REAL, PRIMARY KEY("guid", "name"));`);
|
|
88
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("guid");`);
|
|
89
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("name");`);
|
|
90
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}_id_name__truthy`)} ON ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("name") WHERE "truthy" = 1;`);
|
|
91
|
-
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "reference" CHARACTER(24) NOT NULL, PRIMARY KEY("guid", "name", "reference"));`);
|
|
92
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid");`);
|
|
93
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name");`);
|
|
94
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference");`);
|
|
233
|
+
this.createEntitiesTable(etype);
|
|
234
|
+
this.createDataTable(etype);
|
|
235
|
+
this.createReferencesTable(etype);
|
|
236
|
+
this.createTokensTable(etype);
|
|
237
|
+
this.createUniquesTable(etype);
|
|
95
238
|
}
|
|
96
239
|
else {
|
|
240
|
+
// Create the UID table.
|
|
97
241
|
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}uids`)} ("name" TEXT PRIMARY KEY NOT NULL, "cur_uid" INTEGER NOT NULL);`);
|
|
98
242
|
}
|
|
99
|
-
this.commit('nymph-tablecreation');
|
|
100
|
-
return true;
|
|
101
243
|
}
|
|
102
244
|
catch (e) {
|
|
103
245
|
this.rollback('nymph-tablecreation');
|
|
104
246
|
throw e;
|
|
105
247
|
}
|
|
248
|
+
this.commit('nymph-tablecreation');
|
|
249
|
+
return true;
|
|
106
250
|
}
|
|
107
251
|
query(runQuery, query, etypes = []) {
|
|
108
252
|
try {
|
|
253
|
+
this.nymph.config.debugInfo('sqlite3:query', query);
|
|
109
254
|
return runQuery();
|
|
110
255
|
}
|
|
111
256
|
catch (e) {
|
|
@@ -121,32 +266,45 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
121
266
|
return runQuery();
|
|
122
267
|
}
|
|
123
268
|
catch (e2) {
|
|
124
|
-
throw new
|
|
269
|
+
throw new QueryFailedError('Query failed: ' + e2?.code + ' - ' + e2?.message, query);
|
|
125
270
|
}
|
|
126
271
|
}
|
|
272
|
+
else if (errorCode === 'SQLITE_CONSTRAINT_UNIQUE' &&
|
|
273
|
+
errorMsg.match(/^UNIQUE constraint failed: /)) {
|
|
274
|
+
throw new EntityUniqueConstraintError(`Unique constraint violation.`);
|
|
275
|
+
}
|
|
127
276
|
else {
|
|
128
|
-
throw new
|
|
277
|
+
throw new QueryFailedError('Query failed: ' + e?.code + ' - ' + e?.message, query);
|
|
129
278
|
}
|
|
130
279
|
}
|
|
131
280
|
}
|
|
132
|
-
|
|
133
|
-
return this.query(() => this.
|
|
281
|
+
queryArray(query, { etypes = [], params = {}, } = {}) {
|
|
282
|
+
return this.query(() => (this.store.linkWrite || this.store.link)
|
|
283
|
+
.prepare(query)
|
|
284
|
+
.iterate(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
134
285
|
}
|
|
135
286
|
queryGet(query, { etypes = [], params = {}, } = {}) {
|
|
136
|
-
return this.query(() => this.link.prepare(query).get(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
287
|
+
return this.query(() => (this.store.linkWrite || this.store.link).prepare(query).get(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
137
288
|
}
|
|
138
289
|
queryRun(query, { etypes = [], params = {}, } = {}) {
|
|
139
|
-
return this.query(() => this.link.prepare(query).run(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
290
|
+
return this.query(() => (this.store.linkWrite || this.store.link).prepare(query).run(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
140
291
|
}
|
|
141
292
|
async commit(name) {
|
|
142
293
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
143
|
-
throw new
|
|
294
|
+
throw new InvalidParametersError('Transaction commit attempted without a name.');
|
|
144
295
|
}
|
|
145
|
-
if (this.transactionsStarted === 0) {
|
|
296
|
+
if (this.store.transactionsStarted === 0) {
|
|
146
297
|
return true;
|
|
147
298
|
}
|
|
148
299
|
this.queryRun(`RELEASE SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
149
|
-
this.transactionsStarted--;
|
|
300
|
+
this.store.transactionsStarted--;
|
|
301
|
+
if (this.store.transactionsStarted === 0 &&
|
|
302
|
+
this.store.linkWrite &&
|
|
303
|
+
!this.config.explicitWrite) {
|
|
304
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
305
|
+
this.store.linkWrite.close();
|
|
306
|
+
this.store.linkWrite = undefined;
|
|
307
|
+
}
|
|
150
308
|
return true;
|
|
151
309
|
}
|
|
152
310
|
async deleteEntityByID(guid, className) {
|
|
@@ -159,7 +317,6 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
159
317
|
EntityClass = className;
|
|
160
318
|
}
|
|
161
319
|
const etype = EntityClass.ETYPE;
|
|
162
|
-
this.checkReadOnlyMode();
|
|
163
320
|
await this.startTransaction('nymph-delete');
|
|
164
321
|
try {
|
|
165
322
|
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=@guid;`, {
|
|
@@ -174,108 +331,167 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
174
331
|
guid,
|
|
175
332
|
},
|
|
176
333
|
});
|
|
177
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
334
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=@guid;`, {
|
|
178
335
|
etypes: [etype],
|
|
179
336
|
params: {
|
|
180
337
|
guid,
|
|
181
338
|
},
|
|
182
339
|
});
|
|
183
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
340
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
|
|
341
|
+
etypes: [etype],
|
|
342
|
+
params: {
|
|
343
|
+
guid,
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
|
|
184
347
|
etypes: [etype],
|
|
185
348
|
params: {
|
|
186
349
|
guid,
|
|
187
350
|
},
|
|
188
351
|
});
|
|
189
|
-
await this.commit('nymph-delete');
|
|
190
|
-
if (this.nymph.config.cache) {
|
|
191
|
-
this.cleanCache(guid);
|
|
192
|
-
}
|
|
193
|
-
return true;
|
|
194
352
|
}
|
|
195
353
|
catch (e) {
|
|
354
|
+
this.nymph.config.debugError('sqlite3', `Delete entity error: "${e}"`);
|
|
196
355
|
await this.rollback('nymph-delete');
|
|
197
356
|
throw e;
|
|
198
357
|
}
|
|
358
|
+
await this.commit('nymph-delete');
|
|
359
|
+
// Remove any cached versions of this entity.
|
|
360
|
+
if (this.nymph.config.cache) {
|
|
361
|
+
this.cleanCache(guid);
|
|
362
|
+
}
|
|
363
|
+
return true;
|
|
199
364
|
}
|
|
200
365
|
async deleteUID(name) {
|
|
201
366
|
if (!name) {
|
|
202
|
-
throw new
|
|
367
|
+
throw new InvalidParametersError('Name not given for UID');
|
|
203
368
|
}
|
|
204
|
-
this.
|
|
369
|
+
await this.startTransaction('nymph-delete-uid');
|
|
205
370
|
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
206
371
|
params: {
|
|
207
372
|
name,
|
|
208
373
|
},
|
|
209
374
|
});
|
|
375
|
+
await this.commit('nymph-delete-uid');
|
|
210
376
|
return true;
|
|
211
377
|
}
|
|
212
|
-
async
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
writeLine('');
|
|
219
|
-
writeLine('#');
|
|
220
|
-
writeLine('# UIDs');
|
|
221
|
-
writeLine('#');
|
|
222
|
-
writeLine('');
|
|
223
|
-
let uids = this.queryIter(`SELECT * FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} ORDER BY "name";`);
|
|
224
|
-
for (const uid of uids) {
|
|
225
|
-
writeLine(`<${uid.name}>[${uid.cur_uid}]`);
|
|
226
|
-
}
|
|
227
|
-
writeLine('');
|
|
228
|
-
writeLine('#');
|
|
229
|
-
writeLine('# Entities');
|
|
230
|
-
writeLine('#');
|
|
231
|
-
writeLine('');
|
|
232
|
-
const tables = this.queryIter("SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name;");
|
|
378
|
+
async getEtypes() {
|
|
379
|
+
const tables = this.queryArray("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix;", {
|
|
380
|
+
params: {
|
|
381
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
382
|
+
},
|
|
383
|
+
});
|
|
233
384
|
const etypes = [];
|
|
234
385
|
for (const table of tables) {
|
|
235
|
-
|
|
236
|
-
|
|
386
|
+
etypes.push(table.name.substr((this.prefix + 'entities_').length));
|
|
387
|
+
}
|
|
388
|
+
return etypes;
|
|
389
|
+
}
|
|
390
|
+
async *exportDataIterator() {
|
|
391
|
+
if (yield {
|
|
392
|
+
type: 'comment',
|
|
393
|
+
content: `#nex2
|
|
394
|
+
# Nymph Entity Exchange v2
|
|
395
|
+
# http://nymph.io
|
|
396
|
+
#
|
|
397
|
+
# Generation Time: ${new Date().toLocaleString()}
|
|
398
|
+
`,
|
|
399
|
+
}) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (yield {
|
|
403
|
+
type: 'comment',
|
|
404
|
+
content: `
|
|
405
|
+
|
|
406
|
+
#
|
|
407
|
+
# UIDs
|
|
408
|
+
#
|
|
409
|
+
|
|
410
|
+
`,
|
|
411
|
+
}) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
// Export UIDs.
|
|
415
|
+
let uids = this.queryArray(`SELECT * FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} ORDER BY "name";`);
|
|
416
|
+
for (const uid of uids) {
|
|
417
|
+
if (yield { type: 'uid', content: `<${uid.name}>[${uid.cur_uid}]\n` }) {
|
|
418
|
+
return;
|
|
237
419
|
}
|
|
238
420
|
}
|
|
421
|
+
if (yield {
|
|
422
|
+
type: 'comment',
|
|
423
|
+
content: `
|
|
424
|
+
|
|
425
|
+
#
|
|
426
|
+
# Entities
|
|
427
|
+
#
|
|
428
|
+
|
|
429
|
+
`,
|
|
430
|
+
}) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
// Get the etypes.
|
|
434
|
+
const etypes = await this.getEtypes();
|
|
239
435
|
for (const etype of etypes) {
|
|
240
|
-
|
|
436
|
+
// Export entities.
|
|
437
|
+
const dataIterator = this.queryArray(`SELECT e.*, d."name", d."value", json(d."json") as "json", d."string", d."number" FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} e LEFT JOIN ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} d USING ("guid") ORDER BY e."guid";`)[Symbol.iterator]();
|
|
241
438
|
let datum = dataIterator.next();
|
|
242
439
|
while (!datum.done) {
|
|
243
440
|
const guid = datum.value.guid;
|
|
244
441
|
const tags = datum.value.tags.slice(1, -1);
|
|
245
442
|
const cdate = datum.value.cdate;
|
|
246
443
|
const mdate = datum.value.mdate;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
444
|
+
let currentEntityExport = [];
|
|
445
|
+
currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
|
|
446
|
+
currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
|
|
447
|
+
currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
|
|
448
|
+
if (datum.value.name != null) {
|
|
449
|
+
// This do will keep going and adding the data until the
|
|
450
|
+
// next entity is reached. datum will end on the next entity.
|
|
251
451
|
do {
|
|
252
|
-
const value = datum.value.
|
|
452
|
+
const value = datum.value.value === 'N'
|
|
253
453
|
? JSON.stringify(datum.value.number)
|
|
254
|
-
: datum.value.
|
|
454
|
+
: datum.value.value === 'S'
|
|
255
455
|
? JSON.stringify(datum.value.string)
|
|
256
|
-
: datum.value.
|
|
257
|
-
|
|
456
|
+
: datum.value.value === 'J'
|
|
457
|
+
? datum.value.json
|
|
458
|
+
: datum.value.value;
|
|
459
|
+
currentEntityExport.push(`\t${datum.value.name}=${value}`);
|
|
258
460
|
datum = dataIterator.next();
|
|
259
461
|
} while (!datum.done && datum.value.guid === guid);
|
|
260
462
|
}
|
|
261
463
|
else {
|
|
464
|
+
// Make sure that datum is incremented :)
|
|
262
465
|
datum = dataIterator.next();
|
|
263
466
|
}
|
|
467
|
+
currentEntityExport.push('');
|
|
468
|
+
if (yield { type: 'entity', content: currentEntityExport.join('\n') }) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
264
471
|
}
|
|
265
472
|
}
|
|
266
|
-
return;
|
|
267
473
|
}
|
|
268
|
-
|
|
474
|
+
/**
|
|
475
|
+
* Generate the SQLite3 query.
|
|
476
|
+
* @param options The options array.
|
|
477
|
+
* @param formattedSelectors The formatted selector array.
|
|
478
|
+
* @param etype
|
|
479
|
+
* @param count Used to track internal params.
|
|
480
|
+
* @param params Used to store internal params.
|
|
481
|
+
* @param subquery Whether only a subquery should be returned.
|
|
482
|
+
* @returns The SQL query.
|
|
483
|
+
*/
|
|
484
|
+
makeEntityQuery(options, formattedSelectors, etype, count = { i: 0 }, params = {}, subquery = false, tableSuffix = '', etypes = [], guidSelector = undefined) {
|
|
269
485
|
if (typeof options.class?.alterOptions === 'function') {
|
|
270
486
|
options = options.class.alterOptions(options);
|
|
271
487
|
}
|
|
272
488
|
const eTable = `e${tableSuffix}`;
|
|
273
489
|
const dTable = `d${tableSuffix}`;
|
|
274
|
-
const cTable = `c${tableSuffix}`;
|
|
275
490
|
const fTable = `f${tableSuffix}`;
|
|
276
491
|
const ieTable = `ie${tableSuffix}`;
|
|
492
|
+
const sTable = `s${tableSuffix}`;
|
|
277
493
|
const sort = options.sort ?? 'cdate';
|
|
278
|
-
const queryParts = this.iterateSelectorsForQuery(formattedSelectors, (key, value, typeIsOr, typeIsNot) => {
|
|
494
|
+
const queryParts = this.iterateSelectorsForQuery(formattedSelectors, ({ key, value, typeIsOr, typeIsNot }) => {
|
|
279
495
|
const clauseNot = key.startsWith('!');
|
|
280
496
|
let curQuery = '';
|
|
281
497
|
for (const curValue of value) {
|
|
@@ -288,7 +504,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
288
504
|
}
|
|
289
505
|
const guid = `param${++count.i}`;
|
|
290
506
|
curQuery +=
|
|
291
|
-
(
|
|
507
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
292
508
|
ieTable +
|
|
293
509
|
'."guid"=@' +
|
|
294
510
|
guid;
|
|
@@ -303,7 +519,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
303
519
|
}
|
|
304
520
|
const tag = `param${++count.i}`;
|
|
305
521
|
curQuery +=
|
|
306
|
-
(
|
|
522
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
307
523
|
ieTable +
|
|
308
524
|
'."tags" LIKE @' +
|
|
309
525
|
tag +
|
|
@@ -327,7 +543,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
327
543
|
curQuery +=
|
|
328
544
|
ieTable +
|
|
329
545
|
'."guid" ' +
|
|
330
|
-
(
|
|
546
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
331
547
|
'IN (SELECT "guid" FROM ' +
|
|
332
548
|
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
333
549
|
' WHERE "name"=@' +
|
|
@@ -344,7 +560,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
344
560
|
}
|
|
345
561
|
if (curVar === 'cdate') {
|
|
346
562
|
curQuery +=
|
|
347
|
-
(
|
|
563
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
348
564
|
'(' +
|
|
349
565
|
ieTable +
|
|
350
566
|
'."cdate" NOT NULL)';
|
|
@@ -352,7 +568,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
352
568
|
}
|
|
353
569
|
else if (curVar === 'mdate') {
|
|
354
570
|
curQuery +=
|
|
355
|
-
(
|
|
571
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
356
572
|
'(' +
|
|
357
573
|
ieTable +
|
|
358
574
|
'."mdate" NOT NULL)';
|
|
@@ -361,11 +577,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
361
577
|
else {
|
|
362
578
|
const name = `param${++count.i}`;
|
|
363
579
|
curQuery +=
|
|
364
|
-
(
|
|
580
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
581
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
582
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
583
|
+
' WHERE "guid"=' +
|
|
365
584
|
ieTable +
|
|
366
|
-
'."guid"
|
|
367
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
368
|
-
' WHERE "name"=@' +
|
|
585
|
+
'."guid" AND "name"=@' +
|
|
369
586
|
name +
|
|
370
587
|
' AND "truthy"=1)';
|
|
371
588
|
params[name] = curVar;
|
|
@@ -380,7 +597,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
380
597
|
}
|
|
381
598
|
const cdate = `param${++count.i}`;
|
|
382
599
|
curQuery +=
|
|
383
|
-
(
|
|
600
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
384
601
|
ieTable +
|
|
385
602
|
'."cdate"=@' +
|
|
386
603
|
cdate;
|
|
@@ -393,7 +610,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
393
610
|
}
|
|
394
611
|
const mdate = `param${++count.i}`;
|
|
395
612
|
curQuery +=
|
|
396
|
-
(
|
|
613
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
397
614
|
ieTable +
|
|
398
615
|
'."mdate"=@' +
|
|
399
616
|
mdate;
|
|
@@ -407,11 +624,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
407
624
|
const name = `param${++count.i}`;
|
|
408
625
|
const value = `param${++count.i}`;
|
|
409
626
|
curQuery +=
|
|
410
|
-
(
|
|
627
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
628
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
629
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
630
|
+
' WHERE "guid"=' +
|
|
411
631
|
ieTable +
|
|
412
|
-
'."guid"
|
|
413
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
414
|
-
' WHERE "name"=@' +
|
|
632
|
+
'."guid" AND "name"=@' +
|
|
415
633
|
name +
|
|
416
634
|
' AND "number"=@' +
|
|
417
635
|
value +
|
|
@@ -426,11 +644,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
426
644
|
const name = `param${++count.i}`;
|
|
427
645
|
const value = `param${++count.i}`;
|
|
428
646
|
curQuery +=
|
|
429
|
-
(
|
|
647
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
648
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
649
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
650
|
+
' WHERE "guid"=' +
|
|
430
651
|
ieTable +
|
|
431
|
-
'."guid"
|
|
432
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
433
|
-
' WHERE "name"=@' +
|
|
652
|
+
'."guid" AND "name"=@' +
|
|
434
653
|
name +
|
|
435
654
|
' AND "string"=@' +
|
|
436
655
|
value +
|
|
@@ -453,15 +672,16 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
453
672
|
const name = `param${++count.i}`;
|
|
454
673
|
const value = `param${++count.i}`;
|
|
455
674
|
curQuery +=
|
|
456
|
-
(
|
|
457
|
-
|
|
458
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
675
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
676
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
459
677
|
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
460
|
-
' WHERE "
|
|
678
|
+
' WHERE "guid"=' +
|
|
679
|
+
ieTable +
|
|
680
|
+
'."guid" AND "name"=@' +
|
|
461
681
|
name +
|
|
462
|
-
' AND "
|
|
682
|
+
' AND "json"=jsonb(@' +
|
|
463
683
|
value +
|
|
464
|
-
')';
|
|
684
|
+
'))';
|
|
465
685
|
params[name] = curValue[0];
|
|
466
686
|
params[value] = svalue;
|
|
467
687
|
}
|
|
@@ -474,9 +694,9 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
474
694
|
}
|
|
475
695
|
const cdate = `param${++count.i}`;
|
|
476
696
|
curQuery +=
|
|
477
|
-
(
|
|
697
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
478
698
|
ieTable +
|
|
479
|
-
'."cdate"
|
|
699
|
+
'."cdate"=@' +
|
|
480
700
|
cdate;
|
|
481
701
|
params[cdate] = Number(curValue[1]);
|
|
482
702
|
break;
|
|
@@ -487,67 +707,163 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
487
707
|
}
|
|
488
708
|
const mdate = `param${++count.i}`;
|
|
489
709
|
curQuery +=
|
|
490
|
-
(
|
|
710
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
491
711
|
ieTable +
|
|
492
|
-
'."mdate"
|
|
712
|
+
'."mdate"=@' +
|
|
493
713
|
mdate;
|
|
494
714
|
params[mdate] = Number(curValue[1]);
|
|
495
715
|
break;
|
|
496
716
|
}
|
|
497
717
|
else {
|
|
718
|
+
const containTableSuffix = makeTableSuffix();
|
|
498
719
|
if (curQuery) {
|
|
499
720
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
500
721
|
}
|
|
501
722
|
let svalue;
|
|
502
|
-
let stringValue;
|
|
503
723
|
if (curValue[1] instanceof Object &&
|
|
504
724
|
typeof curValue[1].toReference === 'function') {
|
|
505
725
|
svalue = JSON.stringify(curValue[1].toReference());
|
|
506
|
-
stringValue = `${curValue[1].toReference()}`;
|
|
507
726
|
}
|
|
508
727
|
else {
|
|
509
728
|
svalue = JSON.stringify(curValue[1]);
|
|
510
|
-
stringValue = `${curValue[1]}`;
|
|
511
729
|
}
|
|
512
730
|
const name = `param${++count.i}`;
|
|
513
731
|
const value = `param${++count.i}`;
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
(
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
732
|
+
curQuery +=
|
|
733
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
734
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
735
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
736
|
+
' d' +
|
|
737
|
+
containTableSuffix +
|
|
738
|
+
' WHERE "guid"=' +
|
|
739
|
+
ieTable +
|
|
740
|
+
'."guid" AND "name"=@' +
|
|
741
|
+
name +
|
|
742
|
+
' AND json(@' +
|
|
743
|
+
value +
|
|
744
|
+
') IN (SELECT json_quote("value") FROM json_each(d' +
|
|
745
|
+
containTableSuffix +
|
|
746
|
+
'."json")))';
|
|
747
|
+
params[name] = curValue[0];
|
|
748
|
+
params[value] = svalue;
|
|
749
|
+
}
|
|
750
|
+
break;
|
|
751
|
+
case 'search':
|
|
752
|
+
case '!search':
|
|
753
|
+
if (curValue[0] === 'cdate' || curValue[0] === 'mdate') {
|
|
754
|
+
if (curQuery) {
|
|
755
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
536
756
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
757
|
+
curQuery += (xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(0)';
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
if (curQuery) {
|
|
762
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
763
|
+
}
|
|
764
|
+
const name = `param${++count.i}`;
|
|
765
|
+
const queryPartToken = (term) => {
|
|
766
|
+
const value = `param${++count.i}`;
|
|
767
|
+
params[value] = term.token;
|
|
768
|
+
return ('EXISTS (SELECT "guid" FROM ' +
|
|
769
|
+
SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
|
|
770
|
+
' WHERE "guid"=' +
|
|
771
|
+
ieTable +
|
|
772
|
+
'."guid" AND "name"=@' +
|
|
773
|
+
name +
|
|
774
|
+
' AND "token"=@' +
|
|
775
|
+
value +
|
|
776
|
+
(term.nostemmed ? ' AND "stem"=0' : '') +
|
|
777
|
+
')');
|
|
778
|
+
};
|
|
779
|
+
const queryPartSeries = (series) => {
|
|
780
|
+
const tokenTableSuffix = makeTableSuffix();
|
|
781
|
+
const tokenParts = series.tokens.map((token, i) => {
|
|
782
|
+
const value = `param${++count.i}`;
|
|
783
|
+
params[value] = token.token;
|
|
784
|
+
return {
|
|
785
|
+
fromClause: i === 0
|
|
786
|
+
? 'FROM ' +
|
|
787
|
+
SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
|
|
788
|
+
' t' +
|
|
789
|
+
tokenTableSuffix +
|
|
790
|
+
'0'
|
|
791
|
+
: 'JOIN ' +
|
|
792
|
+
SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
|
|
793
|
+
' t' +
|
|
794
|
+
tokenTableSuffix +
|
|
795
|
+
i +
|
|
796
|
+
' ON t' +
|
|
797
|
+
tokenTableSuffix +
|
|
798
|
+
i +
|
|
799
|
+
'."guid" = t' +
|
|
800
|
+
tokenTableSuffix +
|
|
801
|
+
'0."guid" AND t' +
|
|
802
|
+
tokenTableSuffix +
|
|
803
|
+
i +
|
|
804
|
+
'."name" = t' +
|
|
805
|
+
tokenTableSuffix +
|
|
806
|
+
'0."name" AND t' +
|
|
807
|
+
tokenTableSuffix +
|
|
808
|
+
i +
|
|
809
|
+
'."position" = t' +
|
|
810
|
+
tokenTableSuffix +
|
|
811
|
+
'0."position" + ' +
|
|
812
|
+
i,
|
|
813
|
+
whereClause: 't' +
|
|
814
|
+
tokenTableSuffix +
|
|
815
|
+
i +
|
|
816
|
+
'."token"=@' +
|
|
817
|
+
value +
|
|
818
|
+
(token.nostemmed
|
|
819
|
+
? ' AND t' + tokenTableSuffix + i + '."stem"=0'
|
|
820
|
+
: ''),
|
|
821
|
+
};
|
|
822
|
+
});
|
|
823
|
+
return ('EXISTS (SELECT t' +
|
|
824
|
+
tokenTableSuffix +
|
|
825
|
+
'0."guid" ' +
|
|
826
|
+
tokenParts.map((part) => part.fromClause).join(' ') +
|
|
827
|
+
' WHERE t' +
|
|
828
|
+
tokenTableSuffix +
|
|
829
|
+
'0."guid"=' +
|
|
830
|
+
ieTable +
|
|
831
|
+
'."guid" AND t' +
|
|
832
|
+
tokenTableSuffix +
|
|
833
|
+
'0."name"=@' +
|
|
834
|
+
name +
|
|
835
|
+
' AND ' +
|
|
836
|
+
tokenParts.map((part) => part.whereClause).join(' AND ') +
|
|
837
|
+
')');
|
|
838
|
+
};
|
|
839
|
+
const queryPartTerm = (term) => {
|
|
840
|
+
if (term.type === 'series') {
|
|
841
|
+
return queryPartSeries(term);
|
|
842
|
+
}
|
|
843
|
+
else if (term.type === 'not') {
|
|
844
|
+
return 'NOT ' + queryPartTerm(term.operand);
|
|
845
|
+
}
|
|
846
|
+
else if (term.type === 'or') {
|
|
847
|
+
let queryParts = [];
|
|
848
|
+
for (let operand of term.operands) {
|
|
849
|
+
queryParts.push(queryPartTerm(operand));
|
|
850
|
+
}
|
|
851
|
+
return '(' + queryParts.join(' OR ') + ')';
|
|
852
|
+
}
|
|
853
|
+
return queryPartToken(term);
|
|
854
|
+
};
|
|
855
|
+
const parsedFTSQuery = this.tokenizer.parseSearchQuery(curValue[1]);
|
|
856
|
+
// Run through the query and add terms.
|
|
857
|
+
let termStrings = [];
|
|
858
|
+
for (let term of parsedFTSQuery) {
|
|
859
|
+
termStrings.push(queryPartTerm(term));
|
|
548
860
|
}
|
|
861
|
+
curQuery +=
|
|
862
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
863
|
+
'(' +
|
|
864
|
+
termStrings.join(' AND ') +
|
|
865
|
+
')';
|
|
549
866
|
params[name] = curValue[0];
|
|
550
|
-
params[value] = svalue;
|
|
551
867
|
}
|
|
552
868
|
break;
|
|
553
869
|
case 'match':
|
|
@@ -558,7 +874,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
558
874
|
}
|
|
559
875
|
const cdate = `param${++count.i}`;
|
|
560
876
|
curQuery +=
|
|
561
|
-
(
|
|
877
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
562
878
|
'(' +
|
|
563
879
|
ieTable +
|
|
564
880
|
'."cdate" REGEXP @' +
|
|
@@ -573,7 +889,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
573
889
|
}
|
|
574
890
|
const mdate = `param${++count.i}`;
|
|
575
891
|
curQuery +=
|
|
576
|
-
(
|
|
892
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
577
893
|
'(' +
|
|
578
894
|
ieTable +
|
|
579
895
|
'."mdate" REGEXP @' +
|
|
@@ -589,11 +905,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
589
905
|
const name = `param${++count.i}`;
|
|
590
906
|
const value = `param${++count.i}`;
|
|
591
907
|
curQuery +=
|
|
592
|
-
(
|
|
908
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
909
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
910
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
911
|
+
' WHERE "guid"=' +
|
|
593
912
|
ieTable +
|
|
594
|
-
'."guid"
|
|
595
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
596
|
-
' WHERE "name"=@' +
|
|
913
|
+
'."guid" AND "name"=@' +
|
|
597
914
|
name +
|
|
598
915
|
' AND "string" REGEXP @' +
|
|
599
916
|
value +
|
|
@@ -610,7 +927,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
610
927
|
}
|
|
611
928
|
const cdate = `param${++count.i}`;
|
|
612
929
|
curQuery +=
|
|
613
|
-
(
|
|
930
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
614
931
|
'(' +
|
|
615
932
|
ieTable +
|
|
616
933
|
'."cdate" REGEXP @' +
|
|
@@ -625,7 +942,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
625
942
|
}
|
|
626
943
|
const mdate = `param${++count.i}`;
|
|
627
944
|
curQuery +=
|
|
628
|
-
(
|
|
945
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
629
946
|
'(' +
|
|
630
947
|
ieTable +
|
|
631
948
|
'."mdate" REGEXP @' +
|
|
@@ -641,11 +958,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
641
958
|
const name = `param${++count.i}`;
|
|
642
959
|
const value = `param${++count.i}`;
|
|
643
960
|
curQuery +=
|
|
644
|
-
(
|
|
961
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
962
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
963
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
964
|
+
' WHERE "guid"=' +
|
|
645
965
|
ieTable +
|
|
646
|
-
'."guid"
|
|
647
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
648
|
-
' WHERE "name"=@' +
|
|
966
|
+
'."guid" AND "name"=@' +
|
|
649
967
|
name +
|
|
650
968
|
' AND lower("string") REGEXP lower(@' +
|
|
651
969
|
value +
|
|
@@ -662,7 +980,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
662
980
|
}
|
|
663
981
|
const cdate = `param${++count.i}`;
|
|
664
982
|
curQuery +=
|
|
665
|
-
(
|
|
983
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
666
984
|
'(' +
|
|
667
985
|
ieTable +
|
|
668
986
|
'."cdate" LIKE @' +
|
|
@@ -677,7 +995,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
677
995
|
}
|
|
678
996
|
const mdate = `param${++count.i}`;
|
|
679
997
|
curQuery +=
|
|
680
|
-
(
|
|
998
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
681
999
|
'(' +
|
|
682
1000
|
ieTable +
|
|
683
1001
|
'."mdate" LIKE @' +
|
|
@@ -693,11 +1011,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
693
1011
|
const name = `param${++count.i}`;
|
|
694
1012
|
const value = `param${++count.i}`;
|
|
695
1013
|
curQuery +=
|
|
696
|
-
(
|
|
1014
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1015
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1016
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1017
|
+
' WHERE "guid"=' +
|
|
697
1018
|
ieTable +
|
|
698
|
-
'."guid"
|
|
699
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
700
|
-
' WHERE "name"=@' +
|
|
1019
|
+
'."guid" AND "name"=@' +
|
|
701
1020
|
name +
|
|
702
1021
|
' AND "string" LIKE @' +
|
|
703
1022
|
value +
|
|
@@ -714,7 +1033,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
714
1033
|
}
|
|
715
1034
|
const cdate = `param${++count.i}`;
|
|
716
1035
|
curQuery +=
|
|
717
|
-
(
|
|
1036
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
718
1037
|
'(' +
|
|
719
1038
|
ieTable +
|
|
720
1039
|
'."cdate" LIKE @' +
|
|
@@ -729,7 +1048,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
729
1048
|
}
|
|
730
1049
|
const mdate = `param${++count.i}`;
|
|
731
1050
|
curQuery +=
|
|
732
|
-
(
|
|
1051
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
733
1052
|
'(' +
|
|
734
1053
|
ieTable +
|
|
735
1054
|
'."mdate" LIKE @' +
|
|
@@ -745,11 +1064,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
745
1064
|
const name = `param${++count.i}`;
|
|
746
1065
|
const value = `param${++count.i}`;
|
|
747
1066
|
curQuery +=
|
|
748
|
-
(
|
|
1067
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1068
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1069
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1070
|
+
' WHERE "guid"=' +
|
|
749
1071
|
ieTable +
|
|
750
|
-
'."guid"
|
|
751
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
752
|
-
' WHERE "name"=@' +
|
|
1072
|
+
'."guid" AND "name"=@' +
|
|
753
1073
|
name +
|
|
754
1074
|
' AND lower("string") LIKE lower(@' +
|
|
755
1075
|
value +
|
|
@@ -766,7 +1086,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
766
1086
|
}
|
|
767
1087
|
const cdate = `param${++count.i}`;
|
|
768
1088
|
curQuery +=
|
|
769
|
-
(
|
|
1089
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
770
1090
|
ieTable +
|
|
771
1091
|
'."cdate">@' +
|
|
772
1092
|
cdate;
|
|
@@ -779,7 +1099,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
779
1099
|
}
|
|
780
1100
|
const mdate = `param${++count.i}`;
|
|
781
1101
|
curQuery +=
|
|
782
|
-
(
|
|
1102
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
783
1103
|
ieTable +
|
|
784
1104
|
'."mdate">@' +
|
|
785
1105
|
mdate;
|
|
@@ -793,11 +1113,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
793
1113
|
const name = `param${++count.i}`;
|
|
794
1114
|
const value = `param${++count.i}`;
|
|
795
1115
|
curQuery +=
|
|
796
|
-
(
|
|
1116
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1117
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1118
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1119
|
+
' WHERE "guid"=' +
|
|
797
1120
|
ieTable +
|
|
798
|
-
'."guid"
|
|
799
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
800
|
-
' WHERE "name"=@' +
|
|
1121
|
+
'."guid" AND "name"=@' +
|
|
801
1122
|
name +
|
|
802
1123
|
' AND "number">@' +
|
|
803
1124
|
value +
|
|
@@ -814,7 +1135,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
814
1135
|
}
|
|
815
1136
|
const cdate = `param${++count.i}`;
|
|
816
1137
|
curQuery +=
|
|
817
|
-
(
|
|
1138
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
818
1139
|
ieTable +
|
|
819
1140
|
'."cdate">=@' +
|
|
820
1141
|
cdate;
|
|
@@ -827,7 +1148,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
827
1148
|
}
|
|
828
1149
|
const mdate = `param${++count.i}`;
|
|
829
1150
|
curQuery +=
|
|
830
|
-
(
|
|
1151
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
831
1152
|
ieTable +
|
|
832
1153
|
'."mdate">=@' +
|
|
833
1154
|
mdate;
|
|
@@ -841,11 +1162,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
841
1162
|
const name = `param${++count.i}`;
|
|
842
1163
|
const value = `param${++count.i}`;
|
|
843
1164
|
curQuery +=
|
|
844
|
-
(
|
|
1165
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1166
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1167
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1168
|
+
' WHERE "guid"=' +
|
|
845
1169
|
ieTable +
|
|
846
|
-
'."guid"
|
|
847
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
848
|
-
' WHERE "name"=@' +
|
|
1170
|
+
'."guid" AND "name"=@' +
|
|
849
1171
|
name +
|
|
850
1172
|
' AND "number">=@' +
|
|
851
1173
|
value +
|
|
@@ -862,7 +1184,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
862
1184
|
}
|
|
863
1185
|
const cdate = `param${++count.i}`;
|
|
864
1186
|
curQuery +=
|
|
865
|
-
(
|
|
1187
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
866
1188
|
ieTable +
|
|
867
1189
|
'."cdate"<@' +
|
|
868
1190
|
cdate;
|
|
@@ -875,7 +1197,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
875
1197
|
}
|
|
876
1198
|
const mdate = `param${++count.i}`;
|
|
877
1199
|
curQuery +=
|
|
878
|
-
(
|
|
1200
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
879
1201
|
ieTable +
|
|
880
1202
|
'."mdate"<@' +
|
|
881
1203
|
mdate;
|
|
@@ -889,11 +1211,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
889
1211
|
const name = `param${++count.i}`;
|
|
890
1212
|
const value = `param${++count.i}`;
|
|
891
1213
|
curQuery +=
|
|
892
|
-
(
|
|
1214
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1215
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1216
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1217
|
+
' WHERE "guid"=' +
|
|
893
1218
|
ieTable +
|
|
894
|
-
'."guid"
|
|
895
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
896
|
-
' WHERE "name"=@' +
|
|
1219
|
+
'."guid" AND "name"=@' +
|
|
897
1220
|
name +
|
|
898
1221
|
' AND "number"<@' +
|
|
899
1222
|
value +
|
|
@@ -910,7 +1233,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
910
1233
|
}
|
|
911
1234
|
const cdate = `param${++count.i}`;
|
|
912
1235
|
curQuery +=
|
|
913
|
-
(
|
|
1236
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
914
1237
|
ieTable +
|
|
915
1238
|
'."cdate"<=@' +
|
|
916
1239
|
cdate;
|
|
@@ -923,7 +1246,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
923
1246
|
}
|
|
924
1247
|
const mdate = `param${++count.i}`;
|
|
925
1248
|
curQuery +=
|
|
926
|
-
(
|
|
1249
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
927
1250
|
ieTable +
|
|
928
1251
|
'."mdate"<=@' +
|
|
929
1252
|
mdate;
|
|
@@ -937,11 +1260,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
937
1260
|
const name = `param${++count.i}`;
|
|
938
1261
|
const value = `param${++count.i}`;
|
|
939
1262
|
curQuery +=
|
|
940
|
-
(
|
|
1263
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1264
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1265
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1266
|
+
' WHERE "guid"=' +
|
|
941
1267
|
ieTable +
|
|
942
|
-
'."guid"
|
|
943
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
944
|
-
' WHERE "name"=@' +
|
|
1268
|
+
'."guid" AND "name"=@' +
|
|
945
1269
|
name +
|
|
946
1270
|
' AND "number"<=@' +
|
|
947
1271
|
value +
|
|
@@ -968,11 +1292,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
968
1292
|
const name = `param${++count.i}`;
|
|
969
1293
|
const guid = `param${++count.i}`;
|
|
970
1294
|
curQuery +=
|
|
971
|
-
(
|
|
972
|
-
|
|
973
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1295
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1296
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
974
1297
|
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
975
|
-
' WHERE "
|
|
1298
|
+
' WHERE "guid"=' +
|
|
1299
|
+
ieTable +
|
|
1300
|
+
'."guid" AND "name"=@' +
|
|
976
1301
|
name +
|
|
977
1302
|
' AND "reference"=@' +
|
|
978
1303
|
guid +
|
|
@@ -987,29 +1312,37 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
987
1312
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
988
1313
|
}
|
|
989
1314
|
curQuery +=
|
|
990
|
-
(
|
|
1315
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
991
1316
|
'(' +
|
|
992
1317
|
subquery.query +
|
|
993
1318
|
')';
|
|
994
1319
|
break;
|
|
995
1320
|
case 'qref':
|
|
996
1321
|
case '!qref':
|
|
1322
|
+
const referenceTableSuffix = makeTableSuffix();
|
|
997
1323
|
const [qrefOptions, ...qrefSelectors] = curValue[1];
|
|
998
1324
|
const QrefEntityClass = qrefOptions.class;
|
|
999
1325
|
etypes.push(QrefEntityClass.ETYPE);
|
|
1000
|
-
const qrefQuery = this.makeEntityQuery({ ...qrefOptions, return: 'guid', class: QrefEntityClass }, qrefSelectors, QrefEntityClass.ETYPE, count, params, false,
|
|
1326
|
+
const qrefQuery = this.makeEntityQuery({ ...qrefOptions, return: 'guid', class: QrefEntityClass }, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes, 'r' + referenceTableSuffix + '."reference"');
|
|
1001
1327
|
if (curQuery) {
|
|
1002
1328
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1003
1329
|
}
|
|
1004
1330
|
const qrefName = `param${++count.i}`;
|
|
1005
1331
|
curQuery +=
|
|
1006
|
-
(
|
|
1007
|
-
|
|
1008
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1332
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1333
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1009
1334
|
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
1010
|
-
'
|
|
1335
|
+
' r' +
|
|
1336
|
+
referenceTableSuffix +
|
|
1337
|
+
' WHERE r' +
|
|
1338
|
+
referenceTableSuffix +
|
|
1339
|
+
'."guid"=' +
|
|
1340
|
+
ieTable +
|
|
1341
|
+
'."guid" AND r' +
|
|
1342
|
+
referenceTableSuffix +
|
|
1343
|
+
'."name"=@' +
|
|
1011
1344
|
qrefName +
|
|
1012
|
-
' AND
|
|
1345
|
+
' AND EXISTS (' +
|
|
1013
1346
|
qrefQuery.query +
|
|
1014
1347
|
'))';
|
|
1015
1348
|
params[qrefName] = curValue[0];
|
|
@@ -1019,18 +1352,31 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1019
1352
|
return curQuery;
|
|
1020
1353
|
});
|
|
1021
1354
|
let sortBy;
|
|
1355
|
+
let sortByInner;
|
|
1356
|
+
let sortJoin = '';
|
|
1357
|
+
const order = options.reverse ? ' DESC' : '';
|
|
1022
1358
|
switch (sort) {
|
|
1023
1359
|
case 'mdate':
|
|
1024
|
-
sortBy =
|
|
1360
|
+
sortBy = `${eTable}."mdate"${order}`;
|
|
1361
|
+
sortByInner = `${ieTable}."mdate"${order}`;
|
|
1025
1362
|
break;
|
|
1026
1363
|
case 'cdate':
|
|
1364
|
+
sortBy = `${eTable}."cdate"${order}`;
|
|
1365
|
+
sortByInner = `${ieTable}."cdate"${order}`;
|
|
1366
|
+
break;
|
|
1027
1367
|
default:
|
|
1028
|
-
|
|
1368
|
+
const name = `param${++count.i}`;
|
|
1369
|
+
sortJoin = `LEFT JOIN (
|
|
1370
|
+
SELECT "guid", "string", "number"
|
|
1371
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'data_' + etype)}
|
|
1372
|
+
WHERE "name"=@${name}
|
|
1373
|
+
ORDER BY "number"${order}, "string"${order}
|
|
1374
|
+
) ${sTable} USING ("guid")`;
|
|
1375
|
+
sortBy = `${sTable}."number"${order}, ${sTable}."string"${order}`;
|
|
1376
|
+
sortByInner = sortBy;
|
|
1377
|
+
params[name] = sort;
|
|
1029
1378
|
break;
|
|
1030
1379
|
}
|
|
1031
|
-
if (options.reverse) {
|
|
1032
|
-
sortBy += ' DESC';
|
|
1033
|
-
}
|
|
1034
1380
|
let query;
|
|
1035
1381
|
if (queryParts.length) {
|
|
1036
1382
|
if (subquery) {
|
|
@@ -1046,25 +1392,29 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1046
1392
|
offset = ` OFFSET ${Math.floor(Number(options.offset))}`;
|
|
1047
1393
|
}
|
|
1048
1394
|
const whereClause = queryParts.join(') AND (');
|
|
1395
|
+
const guidClause = guidSelector
|
|
1396
|
+
? `${ieTable}."guid"=${guidSelector} AND `
|
|
1397
|
+
: '';
|
|
1049
1398
|
if (options.return === 'count') {
|
|
1050
1399
|
if (limit || offset) {
|
|
1051
1400
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1052
1401
|
SELECT "guid"
|
|
1053
1402
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1054
|
-
WHERE (${whereClause})${limit}${offset}
|
|
1403
|
+
WHERE ${guidClause}(${whereClause})${limit}${offset}
|
|
1055
1404
|
)`;
|
|
1056
1405
|
}
|
|
1057
1406
|
else {
|
|
1058
1407
|
query = `SELECT COUNT("guid") AS "count"
|
|
1059
1408
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1060
|
-
WHERE (${whereClause})`;
|
|
1409
|
+
WHERE ${guidClause}(${whereClause})`;
|
|
1061
1410
|
}
|
|
1062
1411
|
}
|
|
1063
1412
|
else if (options.return === 'guid') {
|
|
1064
1413
|
query = `SELECT "guid"
|
|
1065
1414
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1066
|
-
|
|
1067
|
-
|
|
1415
|
+
${sortJoin}
|
|
1416
|
+
WHERE ${guidClause}(${whereClause})
|
|
1417
|
+
ORDER BY ${sortByInner}, "guid"${limit}${offset}`;
|
|
1068
1418
|
}
|
|
1069
1419
|
else {
|
|
1070
1420
|
query = `SELECT
|
|
@@ -1074,18 +1424,20 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1074
1424
|
${eTable}."mdate",
|
|
1075
1425
|
${dTable}."name",
|
|
1076
1426
|
${dTable}."value",
|
|
1077
|
-
${
|
|
1078
|
-
${
|
|
1427
|
+
json(${dTable}."json") as "json",
|
|
1428
|
+
${dTable}."string",
|
|
1429
|
+
${dTable}."number"
|
|
1079
1430
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${eTable}
|
|
1080
1431
|
LEFT JOIN ${SQLite3Driver.escape(this.prefix + 'data_' + etype)} ${dTable} USING ("guid")
|
|
1081
|
-
|
|
1432
|
+
${sortJoin}
|
|
1082
1433
|
INNER JOIN (
|
|
1083
1434
|
SELECT "guid"
|
|
1084
1435
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1085
|
-
|
|
1086
|
-
|
|
1436
|
+
${sortJoin}
|
|
1437
|
+
WHERE ${guidClause}(${whereClause})
|
|
1438
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1087
1439
|
) ${fTable} USING ("guid")
|
|
1088
|
-
ORDER BY ${
|
|
1440
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1089
1441
|
}
|
|
1090
1442
|
}
|
|
1091
1443
|
}
|
|
@@ -1102,22 +1454,27 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1102
1454
|
if ('offset' in options) {
|
|
1103
1455
|
offset = ` OFFSET ${Math.floor(Number(options.offset))}`;
|
|
1104
1456
|
}
|
|
1457
|
+
const guidClause = guidSelector
|
|
1458
|
+
? ` WHERE ${ieTable}."guid"=${guidSelector}`
|
|
1459
|
+
: '';
|
|
1105
1460
|
if (options.return === 'count') {
|
|
1106
1461
|
if (limit || offset) {
|
|
1107
1462
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1108
1463
|
SELECT "guid"
|
|
1109
|
-
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}${limit}${offset}
|
|
1464
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}${guidClause}${limit}${offset}
|
|
1110
1465
|
)`;
|
|
1111
1466
|
}
|
|
1112
1467
|
else {
|
|
1113
1468
|
query = `SELECT COUNT("guid") AS "count"
|
|
1114
|
-
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}`;
|
|
1469
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}${guidClause}`;
|
|
1115
1470
|
}
|
|
1116
1471
|
}
|
|
1117
1472
|
else if (options.return === 'guid') {
|
|
1118
1473
|
query = `SELECT "guid"
|
|
1119
1474
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1120
|
-
|
|
1475
|
+
${sortJoin}
|
|
1476
|
+
${guidClause}
|
|
1477
|
+
ORDER BY ${sortByInner}, "guid"${limit}${offset}`;
|
|
1121
1478
|
}
|
|
1122
1479
|
else {
|
|
1123
1480
|
if (limit || offset) {
|
|
@@ -1128,17 +1485,20 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1128
1485
|
${eTable}."mdate",
|
|
1129
1486
|
${dTable}."name",
|
|
1130
1487
|
${dTable}."value",
|
|
1131
|
-
${
|
|
1132
|
-
${
|
|
1488
|
+
json(${dTable}."json") as "json",
|
|
1489
|
+
${dTable}."string",
|
|
1490
|
+
${dTable}."number"
|
|
1133
1491
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${eTable}
|
|
1134
1492
|
LEFT JOIN ${SQLite3Driver.escape(this.prefix + 'data_' + etype)} ${dTable} USING ("guid")
|
|
1135
|
-
|
|
1493
|
+
${sortJoin}
|
|
1136
1494
|
INNER JOIN (
|
|
1137
1495
|
SELECT "guid"
|
|
1138
1496
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1139
|
-
|
|
1497
|
+
${sortJoin}
|
|
1498
|
+
${guidClause}
|
|
1499
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1140
1500
|
) ${fTable} USING ("guid")
|
|
1141
|
-
ORDER BY ${
|
|
1501
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1142
1502
|
}
|
|
1143
1503
|
else {
|
|
1144
1504
|
query = `SELECT
|
|
@@ -1148,12 +1508,14 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1148
1508
|
${eTable}."mdate",
|
|
1149
1509
|
${dTable}."name",
|
|
1150
1510
|
${dTable}."value",
|
|
1151
|
-
${
|
|
1152
|
-
${
|
|
1511
|
+
json(${dTable}."json") as "json",
|
|
1512
|
+
${dTable}."string",
|
|
1513
|
+
${dTable}."number"
|
|
1153
1514
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${eTable}
|
|
1154
1515
|
LEFT JOIN ${SQLite3Driver.escape(this.prefix + 'data_' + etype)} ${dTable} USING ("guid")
|
|
1155
|
-
|
|
1156
|
-
|
|
1516
|
+
${sortJoin}
|
|
1517
|
+
${guidSelector ? `WHERE ${eTable}."guid"=${guidSelector}` : ''}
|
|
1518
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1157
1519
|
}
|
|
1158
1520
|
}
|
|
1159
1521
|
}
|
|
@@ -1169,20 +1531,22 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1169
1531
|
}
|
|
1170
1532
|
performQuery(options, formattedSelectors, etype) {
|
|
1171
1533
|
const { query, params, etypes } = this.makeEntityQuery(options, formattedSelectors, etype);
|
|
1172
|
-
const result = this.
|
|
1534
|
+
const result = this.queryArray(query, { etypes, params })[Symbol.iterator]();
|
|
1173
1535
|
return {
|
|
1174
1536
|
result,
|
|
1175
1537
|
};
|
|
1176
1538
|
}
|
|
1177
1539
|
async getEntities(options = {}, ...selectors) {
|
|
1178
|
-
|
|
1179
|
-
}
|
|
1180
|
-
getEntitiesSync(options = {}, ...selectors) {
|
|
1181
|
-
const { result, process } = this.getEntitesRowLike(options, selectors, (options, formattedSelectors, etype) => this.performQuery(options, formattedSelectors, etype), () => {
|
|
1540
|
+
const { result, process } = this.getEntitiesRowLike(options, selectors, ({ options, selectors, etype }) => this.performQuery(options, selectors, etype), () => {
|
|
1182
1541
|
const next = result.next();
|
|
1183
1542
|
return next.done ? null : next.value;
|
|
1184
1543
|
}, () => undefined, (row) => Number(row.count), (row) => row.guid, (row) => ({
|
|
1185
|
-
tags: row.tags.length > 2
|
|
1544
|
+
tags: row.tags.length > 2
|
|
1545
|
+
? row.tags
|
|
1546
|
+
.slice(1, -1)
|
|
1547
|
+
.split(',')
|
|
1548
|
+
.filter((tag) => tag)
|
|
1549
|
+
: [],
|
|
1186
1550
|
cdate: Number(row.cdate),
|
|
1187
1551
|
mdate: Number(row.mdate),
|
|
1188
1552
|
}), (row) => ({
|
|
@@ -1191,13 +1555,19 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1191
1555
|
? JSON.stringify(row.number)
|
|
1192
1556
|
: row.value === 'S'
|
|
1193
1557
|
? JSON.stringify(row.string)
|
|
1194
|
-
: row.value
|
|
1558
|
+
: row.value === 'J'
|
|
1559
|
+
? row.json
|
|
1560
|
+
: row.value,
|
|
1195
1561
|
}));
|
|
1196
|
-
|
|
1562
|
+
const value = process();
|
|
1563
|
+
if (value instanceof Error) {
|
|
1564
|
+
throw value;
|
|
1565
|
+
}
|
|
1566
|
+
return value;
|
|
1197
1567
|
}
|
|
1198
1568
|
async getUID(name) {
|
|
1199
1569
|
if (name == null) {
|
|
1200
|
-
throw new
|
|
1570
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1201
1571
|
}
|
|
1202
1572
|
const result = this.queryGet(`SELECT "cur_uid" FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
1203
1573
|
params: {
|
|
@@ -1206,10 +1576,15 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1206
1576
|
});
|
|
1207
1577
|
return result?.cur_uid ?? null;
|
|
1208
1578
|
}
|
|
1209
|
-
async
|
|
1210
|
-
this.
|
|
1579
|
+
async importEntity(entity) {
|
|
1580
|
+
return await this.importEntityInternal(entity, false);
|
|
1581
|
+
}
|
|
1582
|
+
async importEntityTokens(entity) {
|
|
1583
|
+
return await this.importEntityInternal(entity, true);
|
|
1584
|
+
}
|
|
1585
|
+
async importEntityInternal({ guid, cdate, mdate, tags, sdata, etype, }, onlyTokens) {
|
|
1211
1586
|
try {
|
|
1212
|
-
|
|
1587
|
+
if (!onlyTokens) {
|
|
1213
1588
|
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1214
1589
|
etypes: [etype],
|
|
1215
1590
|
params: {
|
|
@@ -1222,29 +1597,37 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1222
1597
|
guid,
|
|
1223
1598
|
},
|
|
1224
1599
|
});
|
|
1225
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
1600
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1226
1601
|
etypes: [etype],
|
|
1227
1602
|
params: {
|
|
1228
1603
|
guid,
|
|
1229
1604
|
},
|
|
1230
1605
|
});
|
|
1231
|
-
|
|
1606
|
+
}
|
|
1607
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1608
|
+
etypes: [etype],
|
|
1609
|
+
params: {
|
|
1610
|
+
guid,
|
|
1611
|
+
},
|
|
1612
|
+
});
|
|
1613
|
+
if (!onlyTokens) {
|
|
1614
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1232
1615
|
etypes: [etype],
|
|
1233
1616
|
params: {
|
|
1234
1617
|
guid,
|
|
1235
1618
|
},
|
|
1236
1619
|
});
|
|
1620
|
+
}
|
|
1621
|
+
if (!onlyTokens) {
|
|
1237
1622
|
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @mdate);`, {
|
|
1238
1623
|
etypes: [etype],
|
|
1239
1624
|
params: {
|
|
1240
1625
|
guid,
|
|
1241
1626
|
tags: ',' + tags.join(',') + ',',
|
|
1242
|
-
cdate
|
|
1243
|
-
mdate
|
|
1627
|
+
cdate,
|
|
1628
|
+
mdate,
|
|
1244
1629
|
},
|
|
1245
1630
|
});
|
|
1246
|
-
delete sdata.cdate;
|
|
1247
|
-
delete sdata.mdate;
|
|
1248
1631
|
for (const name in sdata) {
|
|
1249
1632
|
const value = sdata[name];
|
|
1250
1633
|
const uvalue = JSON.parse(value);
|
|
@@ -1255,23 +1638,18 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1255
1638
|
? 'N'
|
|
1256
1639
|
: typeof uvalue === 'string'
|
|
1257
1640
|
? 'S'
|
|
1258
|
-
:
|
|
1259
|
-
|
|
1641
|
+
: 'J';
|
|
1642
|
+
const jsonValue = storageValue === 'J' ? value : null;
|
|
1643
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (@guid, @name, @storageValue, jsonb(@jsonValue), @string, @number, @truthy);`, {
|
|
1260
1644
|
etypes: [etype],
|
|
1261
1645
|
params: {
|
|
1262
1646
|
guid,
|
|
1263
1647
|
name,
|
|
1264
1648
|
storageValue,
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("guid", "name", "truthy", "string", "number") VALUES (@guid, @name, @truthy, @string, @number);`, {
|
|
1268
|
-
etypes: [etype],
|
|
1269
|
-
params: {
|
|
1270
|
-
guid,
|
|
1271
|
-
name,
|
|
1272
|
-
truthy: uvalue ? 1 : 0,
|
|
1273
|
-
string: `${uvalue}`,
|
|
1649
|
+
jsonValue,
|
|
1650
|
+
string: storageValue === 'J' ? null : `${uvalue}`,
|
|
1274
1651
|
number: Number(uvalue),
|
|
1652
|
+
truthy: uvalue ? 1 : 0,
|
|
1275
1653
|
},
|
|
1276
1654
|
});
|
|
1277
1655
|
const references = this.findReferences(value);
|
|
@@ -1286,41 +1664,113 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1286
1664
|
});
|
|
1287
1665
|
}
|
|
1288
1666
|
}
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1667
|
+
}
|
|
1668
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
1669
|
+
for (let name in sdata) {
|
|
1670
|
+
let tokenString = null;
|
|
1671
|
+
try {
|
|
1672
|
+
tokenString = EntityClass.getFTSText(name, JSON.parse(sdata[name]));
|
|
1673
|
+
}
|
|
1674
|
+
catch (e) {
|
|
1675
|
+
// Ignore error.
|
|
1676
|
+
}
|
|
1677
|
+
if (tokenString != null) {
|
|
1678
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
1679
|
+
while (tokens.length) {
|
|
1680
|
+
const currentTokens = tokens.splice(0, 100);
|
|
1681
|
+
const params = {
|
|
1682
|
+
guid,
|
|
1683
|
+
name,
|
|
1684
|
+
};
|
|
1685
|
+
const values = [];
|
|
1686
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
1687
|
+
const token = currentTokens[i];
|
|
1688
|
+
params['token' + i] = token.token;
|
|
1689
|
+
params['position' + i] = token.position;
|
|
1690
|
+
params['stem' + i] = token.stem ? 1 : 0;
|
|
1691
|
+
values.push('(@guid, @name, @token' +
|
|
1692
|
+
i +
|
|
1693
|
+
', @position' +
|
|
1694
|
+
i +
|
|
1695
|
+
', @stem' +
|
|
1696
|
+
i +
|
|
1697
|
+
')');
|
|
1698
|
+
}
|
|
1699
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`, {
|
|
1700
|
+
etypes: [etype],
|
|
1701
|
+
params,
|
|
1702
|
+
});
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
if (!onlyTokens) {
|
|
1707
|
+
const uniques = await EntityClass.getUniques({
|
|
1708
|
+
guid,
|
|
1709
|
+
cdate,
|
|
1710
|
+
mdate,
|
|
1711
|
+
tags,
|
|
1712
|
+
data: {},
|
|
1713
|
+
sdata,
|
|
1300
1714
|
});
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1715
|
+
for (const unique of uniques) {
|
|
1716
|
+
try {
|
|
1717
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid", "unique") VALUES (@guid, @unique);`, {
|
|
1718
|
+
etypes: [etype],
|
|
1719
|
+
params: {
|
|
1720
|
+
guid,
|
|
1721
|
+
unique,
|
|
1722
|
+
},
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
catch (e) {
|
|
1726
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
1727
|
+
this.nymph.config.debugError('sqlite3', `Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
|
|
1728
|
+
}
|
|
1729
|
+
throw e;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
catch (e) {
|
|
1735
|
+
this.nymph.config.debugError('sqlite3', `Import entity error: "${e}"`);
|
|
1736
|
+
throw e;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
async importUID({ name, value }) {
|
|
1740
|
+
try {
|
|
1741
|
+
await this.startTransaction(`nymph-import-uid-${name}`);
|
|
1742
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
1743
|
+
params: {
|
|
1744
|
+
name,
|
|
1745
|
+
},
|
|
1746
|
+
});
|
|
1747
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @value);`, {
|
|
1748
|
+
params: {
|
|
1749
|
+
name,
|
|
1750
|
+
value,
|
|
1751
|
+
},
|
|
1305
1752
|
});
|
|
1753
|
+
await this.commit(`nymph-import-uid-${name}`);
|
|
1306
1754
|
}
|
|
1307
1755
|
catch (e) {
|
|
1308
|
-
|
|
1756
|
+
this.nymph.config.debugError('sqlite3', `Import UID error: "${e}"`);
|
|
1757
|
+
await this.rollback(`nymph-import-uid-${name}`);
|
|
1309
1758
|
throw e;
|
|
1310
1759
|
}
|
|
1311
1760
|
}
|
|
1312
1761
|
async newUID(name) {
|
|
1313
1762
|
if (name == null) {
|
|
1314
|
-
throw new
|
|
1763
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1315
1764
|
}
|
|
1316
|
-
this.checkReadOnlyMode();
|
|
1317
1765
|
await this.startTransaction('nymph-newuid');
|
|
1766
|
+
let curUid = undefined;
|
|
1318
1767
|
try {
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1768
|
+
curUid =
|
|
1769
|
+
this.queryGet(`SELECT "cur_uid" FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
1770
|
+
params: {
|
|
1771
|
+
name,
|
|
1772
|
+
},
|
|
1773
|
+
})?.cur_uid ?? null;
|
|
1324
1774
|
if (curUid == null) {
|
|
1325
1775
|
curUid = 1;
|
|
1326
1776
|
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @curUid);`, {
|
|
@@ -1339,41 +1789,50 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1339
1789
|
},
|
|
1340
1790
|
});
|
|
1341
1791
|
}
|
|
1342
|
-
await this.commit('nymph-newuid');
|
|
1343
|
-
return curUid;
|
|
1344
1792
|
}
|
|
1345
1793
|
catch (e) {
|
|
1794
|
+
this.nymph.config.debugError('sqlite3', `New UID error: "${e}"`);
|
|
1346
1795
|
await this.rollback('nymph-newuid');
|
|
1347
1796
|
throw e;
|
|
1348
1797
|
}
|
|
1798
|
+
await this.commit('nymph-newuid');
|
|
1799
|
+
return curUid;
|
|
1349
1800
|
}
|
|
1350
1801
|
async renameUID(oldName, newName) {
|
|
1351
1802
|
if (oldName == null || newName == null) {
|
|
1352
|
-
throw new
|
|
1803
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1353
1804
|
}
|
|
1354
|
-
this.
|
|
1805
|
+
await this.startTransaction('nymph-rename-uid');
|
|
1355
1806
|
this.queryRun(`UPDATE ${SQLite3Driver.escape(`${this.prefix}uids`)} SET "name"=@newName WHERE "name"=@oldName;`, {
|
|
1356
1807
|
params: {
|
|
1357
1808
|
newName,
|
|
1358
1809
|
oldName,
|
|
1359
1810
|
},
|
|
1360
1811
|
});
|
|
1812
|
+
await this.commit('nymph-rename-uid');
|
|
1361
1813
|
return true;
|
|
1362
1814
|
}
|
|
1363
1815
|
async rollback(name) {
|
|
1364
1816
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1365
|
-
throw new
|
|
1817
|
+
throw new InvalidParametersError('Transaction rollback attempted without a name.');
|
|
1366
1818
|
}
|
|
1367
|
-
if (this.transactionsStarted === 0) {
|
|
1819
|
+
if (this.store.transactionsStarted === 0) {
|
|
1368
1820
|
return true;
|
|
1369
1821
|
}
|
|
1370
1822
|
this.queryRun(`ROLLBACK TO SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
1371
|
-
this.transactionsStarted--;
|
|
1823
|
+
this.store.transactionsStarted--;
|
|
1824
|
+
if (this.store.transactionsStarted === 0 &&
|
|
1825
|
+
this.store.linkWrite &&
|
|
1826
|
+
!this.config.explicitWrite) {
|
|
1827
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
1828
|
+
this.store.linkWrite.close();
|
|
1829
|
+
this.store.linkWrite = undefined;
|
|
1830
|
+
}
|
|
1372
1831
|
return true;
|
|
1373
1832
|
}
|
|
1374
1833
|
async saveEntity(entity) {
|
|
1375
|
-
|
|
1376
|
-
|
|
1834
|
+
const insertData = (guid, data, sdata, uniques, etype) => {
|
|
1835
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
1377
1836
|
const runInsertQuery = (name, value, svalue) => {
|
|
1378
1837
|
if (value === undefined) {
|
|
1379
1838
|
return;
|
|
@@ -1382,23 +1841,18 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1382
1841
|
? 'N'
|
|
1383
1842
|
: typeof value === 'string'
|
|
1384
1843
|
? 'S'
|
|
1385
|
-
:
|
|
1386
|
-
|
|
1844
|
+
: 'J';
|
|
1845
|
+
const jsonValue = storageValue === 'J' ? svalue : null;
|
|
1846
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (@guid, @name, @storageValue, jsonb(@jsonValue), @string, @number, @truthy);`, {
|
|
1387
1847
|
etypes: [etype],
|
|
1388
1848
|
params: {
|
|
1389
1849
|
guid,
|
|
1390
1850
|
name,
|
|
1391
1851
|
storageValue,
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("guid", "name", "truthy", "string", "number") VALUES (@guid, @name, @truthy, @string, @number);`, {
|
|
1395
|
-
etypes: [etype],
|
|
1396
|
-
params: {
|
|
1397
|
-
guid,
|
|
1398
|
-
name,
|
|
1399
|
-
truthy: value ? 1 : 0,
|
|
1400
|
-
string: `${value}`,
|
|
1852
|
+
jsonValue,
|
|
1853
|
+
string: storageValue === 'J' ? null : `${value}`,
|
|
1401
1854
|
number: Number(value),
|
|
1855
|
+
truthy: value ? 1 : 0,
|
|
1402
1856
|
},
|
|
1403
1857
|
});
|
|
1404
1858
|
const references = this.findReferences(svalue);
|
|
@@ -1412,7 +1866,59 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1412
1866
|
},
|
|
1413
1867
|
});
|
|
1414
1868
|
}
|
|
1869
|
+
let tokenString = null;
|
|
1870
|
+
try {
|
|
1871
|
+
tokenString = EntityClass.getFTSText(name, value);
|
|
1872
|
+
}
|
|
1873
|
+
catch (e) {
|
|
1874
|
+
// Ignore error.
|
|
1875
|
+
}
|
|
1876
|
+
if (tokenString != null) {
|
|
1877
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
1878
|
+
while (tokens.length) {
|
|
1879
|
+
const currentTokens = tokens.splice(0, 100);
|
|
1880
|
+
const params = {
|
|
1881
|
+
guid,
|
|
1882
|
+
name,
|
|
1883
|
+
};
|
|
1884
|
+
const values = [];
|
|
1885
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
1886
|
+
const token = currentTokens[i];
|
|
1887
|
+
params['token' + i] = token.token;
|
|
1888
|
+
params['position' + i] = token.position;
|
|
1889
|
+
params['stem' + i] = token.stem ? 1 : 0;
|
|
1890
|
+
values.push('(@guid, @name, @token' +
|
|
1891
|
+
i +
|
|
1892
|
+
', @position' +
|
|
1893
|
+
i +
|
|
1894
|
+
', @stem' +
|
|
1895
|
+
i +
|
|
1896
|
+
')');
|
|
1897
|
+
}
|
|
1898
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`, {
|
|
1899
|
+
etypes: [etype],
|
|
1900
|
+
params,
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1415
1904
|
};
|
|
1905
|
+
for (const unique of uniques) {
|
|
1906
|
+
try {
|
|
1907
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid", "unique") VALUES (@guid, @unique);`, {
|
|
1908
|
+
etypes: [etype],
|
|
1909
|
+
params: {
|
|
1910
|
+
guid,
|
|
1911
|
+
unique,
|
|
1912
|
+
},
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
catch (e) {
|
|
1916
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
1917
|
+
this.nymph.config.debugError('sqlite3', `Save entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
|
|
1918
|
+
}
|
|
1919
|
+
throw e;
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1416
1922
|
for (const name in data) {
|
|
1417
1923
|
runInsertQuery(name, data[name], JSON.stringify(data[name]));
|
|
1418
1924
|
}
|
|
@@ -1420,8 +1926,13 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1420
1926
|
runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
|
|
1421
1927
|
}
|
|
1422
1928
|
};
|
|
1929
|
+
let inTransaction = false;
|
|
1423
1930
|
try {
|
|
1424
|
-
return this.saveEntityRowLike(entity, async (
|
|
1931
|
+
return this.saveEntityRowLike(entity, async ({ guid, tags, data, sdata, uniques, cdate, etype }) => {
|
|
1932
|
+
if (Object.keys(data).length === 0 &&
|
|
1933
|
+
Object.keys(sdata).length === 0) {
|
|
1934
|
+
return false;
|
|
1935
|
+
}
|
|
1425
1936
|
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @cdate);`, {
|
|
1426
1937
|
etypes: [etype],
|
|
1427
1938
|
params: {
|
|
@@ -1430,9 +1941,13 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1430
1941
|
cdate,
|
|
1431
1942
|
},
|
|
1432
1943
|
});
|
|
1433
|
-
insertData(guid, data, sdata, etype);
|
|
1944
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
1434
1945
|
return true;
|
|
1435
|
-
}, async (entity, guid, tags, data, sdata, mdate, etype) => {
|
|
1946
|
+
}, async ({ entity, guid, tags, data, sdata, uniques, mdate, etype }) => {
|
|
1947
|
+
if (Object.keys(data).length === 0 &&
|
|
1948
|
+
Object.keys(sdata).length === 0) {
|
|
1949
|
+
return false;
|
|
1950
|
+
}
|
|
1436
1951
|
const info = this.queryRun(`UPDATE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} SET "tags"=@tags, "mdate"=@mdate WHERE "guid"=@guid AND "mdate" <= @emdate;`, {
|
|
1437
1952
|
etypes: [etype],
|
|
1438
1953
|
params: {
|
|
@@ -1450,44 +1965,57 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1450
1965
|
guid,
|
|
1451
1966
|
},
|
|
1452
1967
|
});
|
|
1453
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
1968
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1454
1969
|
etypes: [etype],
|
|
1455
1970
|
params: {
|
|
1456
1971
|
guid,
|
|
1457
1972
|
},
|
|
1458
1973
|
});
|
|
1459
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
1974
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1460
1975
|
etypes: [etype],
|
|
1461
1976
|
params: {
|
|
1462
1977
|
guid,
|
|
1463
1978
|
},
|
|
1464
1979
|
});
|
|
1465
|
-
|
|
1980
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1981
|
+
etypes: [etype],
|
|
1982
|
+
params: {
|
|
1983
|
+
guid,
|
|
1984
|
+
},
|
|
1985
|
+
});
|
|
1986
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
1466
1987
|
success = true;
|
|
1467
1988
|
}
|
|
1468
1989
|
return success;
|
|
1469
1990
|
}, async () => {
|
|
1470
1991
|
await this.startTransaction('nymph-save');
|
|
1992
|
+
inTransaction = true;
|
|
1471
1993
|
}, async (success) => {
|
|
1472
|
-
if (
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1994
|
+
if (inTransaction) {
|
|
1995
|
+
inTransaction = false;
|
|
1996
|
+
if (success) {
|
|
1997
|
+
await this.commit('nymph-save');
|
|
1998
|
+
}
|
|
1999
|
+
else {
|
|
2000
|
+
await this.rollback('nymph-save');
|
|
2001
|
+
}
|
|
1477
2002
|
}
|
|
1478
2003
|
return success;
|
|
1479
2004
|
});
|
|
1480
2005
|
}
|
|
1481
2006
|
catch (e) {
|
|
1482
|
-
|
|
2007
|
+
this.nymph.config.debugError('sqlite3', `Save entity error: "${e}"`);
|
|
2008
|
+
if (inTransaction) {
|
|
2009
|
+
await this.rollback('nymph-save');
|
|
2010
|
+
}
|
|
1483
2011
|
throw e;
|
|
1484
2012
|
}
|
|
1485
2013
|
}
|
|
1486
2014
|
async setUID(name, curUid) {
|
|
1487
2015
|
if (name == null) {
|
|
1488
|
-
throw new
|
|
2016
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1489
2017
|
}
|
|
1490
|
-
this.
|
|
2018
|
+
await this.startTransaction('nymph-set-uid');
|
|
1491
2019
|
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
1492
2020
|
params: {
|
|
1493
2021
|
name,
|
|
@@ -1499,16 +2027,54 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1499
2027
|
curUid,
|
|
1500
2028
|
},
|
|
1501
2029
|
});
|
|
2030
|
+
await this.commit('nymph-set-uid');
|
|
1502
2031
|
return true;
|
|
1503
2032
|
}
|
|
2033
|
+
async internalTransaction(name) {
|
|
2034
|
+
await this.startTransaction(name);
|
|
2035
|
+
}
|
|
1504
2036
|
async startTransaction(name) {
|
|
1505
2037
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1506
|
-
throw new
|
|
2038
|
+
throw new InvalidParametersError('Transaction start attempted without a name.');
|
|
2039
|
+
}
|
|
2040
|
+
if (!this.config.explicitWrite && !this.store.linkWrite) {
|
|
2041
|
+
this._connect(true);
|
|
1507
2042
|
}
|
|
1508
2043
|
this.queryRun(`SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
1509
|
-
this.transactionsStarted++;
|
|
2044
|
+
this.store.transactionsStarted++;
|
|
1510
2045
|
return this.nymph;
|
|
1511
2046
|
}
|
|
2047
|
+
async needsMigration() {
|
|
2048
|
+
const table = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix LIMIT 1;", {
|
|
2049
|
+
params: {
|
|
2050
|
+
prefix: this.prefix + 'data_' + '%',
|
|
2051
|
+
},
|
|
2052
|
+
});
|
|
2053
|
+
if (table?.name) {
|
|
2054
|
+
const result = this.queryGet("SELECT 1 AS `exists` FROM pragma_table_info(@table) WHERE `name`='json';", {
|
|
2055
|
+
params: {
|
|
2056
|
+
table: table.name,
|
|
2057
|
+
},
|
|
2058
|
+
});
|
|
2059
|
+
if (!result?.exists) {
|
|
2060
|
+
return 'json';
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
const table2 = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @tokenTable LIMIT 1;", {
|
|
2064
|
+
params: {
|
|
2065
|
+
tokenTable: this.prefix + 'tokens_' + '%',
|
|
2066
|
+
},
|
|
2067
|
+
});
|
|
2068
|
+
if (!table2 || !table2.name) {
|
|
2069
|
+
return 'tokens';
|
|
2070
|
+
}
|
|
2071
|
+
return false;
|
|
2072
|
+
}
|
|
2073
|
+
async liveMigration(_migrationType) {
|
|
2074
|
+
const etypes = await this.getEtypes();
|
|
2075
|
+
for (let etype of etypes) {
|
|
2076
|
+
this.createTokensTable(etype);
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
1512
2079
|
}
|
|
1513
|
-
exports.default = SQLite3Driver;
|
|
1514
2080
|
//# sourceMappingURL=SQLite3Driver.js.map
|