@nymphjs/driver-sqlite3 1.0.0-beta.11 → 1.0.0-beta.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +495 -0
- package/README.md +1 -1
- package/dist/SQLite3Driver.d.ts +104 -14
- package/dist/SQLite3Driver.js +1558 -569
- package/dist/SQLite3Driver.js.map +1 -1
- package/dist/SQLite3Driver.test.js +54 -15
- package/dist/SQLite3Driver.test.js.map +1 -1
- package/dist/conf/d.d.ts +58 -1
- package/dist/conf/d.js +1 -2
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +3 -4
- package/dist/conf/defaults.js.map +1 -1
- package/dist/conf/index.d.ts +2 -2
- package/dist/conf/index.js +2 -8
- package/dist/conf/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -24
- package/dist/index.js.map +1 -1
- package/jest.config.js +12 -2
- package/package.json +19 -16
- package/src/SQLite3Driver.test.ts +53 -9
- package/src/SQLite3Driver.ts +2362 -892
- package/src/conf/d.ts +26 -2
- package/src/conf/defaults.ts +3 -2
- package/src/conf/index.ts +2 -2
- package/src/index.ts +2 -2
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
package/dist/SQLite3Driver.js
CHANGED
|
@@ -1,29 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
7
|
-
const nymph_1 = require("@nymphjs/nymph");
|
|
8
|
-
const guid_1 = require("@nymphjs/guid");
|
|
9
|
-
const conf_1 = require("./conf");
|
|
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';
|
|
10
5
|
class InternalStore {
|
|
6
|
+
link;
|
|
7
|
+
linkWrite;
|
|
8
|
+
connected = false;
|
|
9
|
+
transactionsStarted = 0;
|
|
11
10
|
constructor(link) {
|
|
12
|
-
this.connected = false;
|
|
13
|
-
this.transactionsStarted = 0;
|
|
14
11
|
this.link = link;
|
|
15
12
|
}
|
|
16
13
|
}
|
|
17
|
-
|
|
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;
|
|
18
22
|
static escape(input) {
|
|
19
23
|
if (input.indexOf('\x00') !== -1) {
|
|
20
|
-
throw new
|
|
24
|
+
throw new InvalidParametersError('SQLite3 identifiers (like entity ETYPE) cannot contain null characters.');
|
|
21
25
|
}
|
|
22
26
|
return '"' + input.replace(/"/g, () => '""') + '"';
|
|
23
27
|
}
|
|
28
|
+
static escapeValue(input) {
|
|
29
|
+
return "'" + input.replace(/'/g, () => "''") + "'";
|
|
30
|
+
}
|
|
24
31
|
constructor(config, store) {
|
|
25
32
|
super();
|
|
26
|
-
this.config = { ...
|
|
33
|
+
this.config = { ...defaults, ...config };
|
|
34
|
+
if (this.config.filename === ':memory:') {
|
|
35
|
+
this.config.explicitWrite = true;
|
|
36
|
+
}
|
|
27
37
|
this.prefix = this.config.prefix;
|
|
28
38
|
if (store) {
|
|
29
39
|
this.store = store;
|
|
@@ -32,53 +42,126 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
32
42
|
this.connect();
|
|
33
43
|
}
|
|
34
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* This is used internally by Nymph. Don't call it yourself.
|
|
47
|
+
*
|
|
48
|
+
* @returns A clone of this instance.
|
|
49
|
+
*/
|
|
35
50
|
clone() {
|
|
36
51
|
return new SQLite3Driver(this.config, this.store);
|
|
37
52
|
}
|
|
38
|
-
|
|
39
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Connect to the SQLite3 database.
|
|
55
|
+
*
|
|
56
|
+
* @returns Whether this instance is connected to a SQLite3 database.
|
|
57
|
+
*/
|
|
58
|
+
connect() {
|
|
40
59
|
if (this.store && this.store.connected) {
|
|
41
|
-
return true;
|
|
60
|
+
return Promise.resolve(true);
|
|
42
61
|
}
|
|
62
|
+
// Connecting
|
|
63
|
+
this._connect(false);
|
|
64
|
+
return Promise.resolve(this.store.connected);
|
|
65
|
+
}
|
|
66
|
+
_connect(write) {
|
|
67
|
+
const { filename, fileMustExist, timeout, explicitWrite, wal, verbose } = this.config;
|
|
43
68
|
try {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
const setOptions = (link) => {
|
|
70
|
+
// Set database and connection options.
|
|
71
|
+
if (wal) {
|
|
72
|
+
link.pragma('journal_mode = WAL;');
|
|
73
|
+
}
|
|
74
|
+
link.pragma('encoding = "UTF-8";');
|
|
75
|
+
link.pragma('foreign_keys = 1;');
|
|
76
|
+
link.pragma('case_sensitive_like = 1;');
|
|
77
|
+
for (let pragma of this.config.pragmas) {
|
|
78
|
+
link.pragma(pragma);
|
|
79
|
+
}
|
|
80
|
+
// Create the preg_match and regexp functions.
|
|
81
|
+
link.function('regexp', { deterministic: true }, ((pattern, subject) => (this.posixRegexMatch(pattern, subject) ? 1 : 0)));
|
|
82
|
+
};
|
|
83
|
+
let link;
|
|
84
|
+
try {
|
|
85
|
+
link = new SQLite3(filename, {
|
|
86
|
+
readonly: !explicitWrite && !write,
|
|
87
|
+
fileMustExist,
|
|
88
|
+
timeout,
|
|
89
|
+
verbose,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
if (e.code === 'SQLITE_CANTOPEN' &&
|
|
94
|
+
!explicitWrite &&
|
|
95
|
+
!write &&
|
|
96
|
+
!this.config.fileMustExist) {
|
|
97
|
+
// This happens when the file doesn't exist and we attempt to open it
|
|
98
|
+
// readonly.
|
|
99
|
+
// First open it in write mode.
|
|
100
|
+
const writeLink = new SQLite3(filename, {
|
|
101
|
+
readonly: false,
|
|
102
|
+
fileMustExist,
|
|
103
|
+
timeout,
|
|
104
|
+
verbose,
|
|
105
|
+
});
|
|
106
|
+
setOptions(writeLink);
|
|
107
|
+
writeLink.close();
|
|
108
|
+
// Now open in readonly.
|
|
109
|
+
link = new SQLite3(filename, {
|
|
110
|
+
readonly: true,
|
|
111
|
+
fileMustExist,
|
|
112
|
+
timeout,
|
|
113
|
+
verbose,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
throw e;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
50
120
|
if (!this.store) {
|
|
121
|
+
if (write) {
|
|
122
|
+
throw new Error('Tried to open in write without opening in read first.');
|
|
123
|
+
}
|
|
51
124
|
this.store = new InternalStore(link);
|
|
52
125
|
}
|
|
126
|
+
else if (write) {
|
|
127
|
+
this.store.linkWrite = link;
|
|
128
|
+
}
|
|
53
129
|
else {
|
|
54
130
|
this.store.link = link;
|
|
55
131
|
}
|
|
56
132
|
this.store.connected = true;
|
|
57
|
-
|
|
58
|
-
this.store.link.pragma('journal_mode = WAL;');
|
|
59
|
-
}
|
|
60
|
-
this.store.link.pragma('encoding = "UTF-8";');
|
|
61
|
-
this.store.link.pragma('foreign_keys = 1;');
|
|
62
|
-
this.store.link.pragma('case_sensitive_like = 1;');
|
|
63
|
-
this.store.link.function('regexp', { deterministic: true }, (pattern, subject) => this.posixRegexMatch(pattern, subject) ? 1 : 0);
|
|
133
|
+
setOptions(link);
|
|
64
134
|
}
|
|
65
135
|
catch (e) {
|
|
66
136
|
if (this.store) {
|
|
67
137
|
this.store.connected = false;
|
|
68
138
|
}
|
|
69
139
|
if (filename === ':memory:') {
|
|
70
|
-
throw new
|
|
140
|
+
throw new NotConfiguredError("It seems the config hasn't been set up correctly. Could not connect: " +
|
|
141
|
+
e?.message);
|
|
71
142
|
}
|
|
72
143
|
else {
|
|
73
|
-
throw new
|
|
144
|
+
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
74
145
|
}
|
|
75
146
|
}
|
|
76
|
-
return this.store.connected;
|
|
77
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Disconnect from the SQLite3 database.
|
|
150
|
+
*
|
|
151
|
+
* @returns Whether this instance is connected to a SQLite3 database.
|
|
152
|
+
*/
|
|
78
153
|
async disconnect() {
|
|
79
154
|
if (this.store.connected) {
|
|
80
|
-
this.store.
|
|
155
|
+
if (this.store.linkWrite && !this.config.explicitWrite) {
|
|
156
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
157
|
+
this.store.linkWrite.close();
|
|
158
|
+
this.store.linkWrite = undefined;
|
|
159
|
+
}
|
|
160
|
+
if (this.config.explicitWrite) {
|
|
161
|
+
this.store.link.exec('PRAGMA optimize;');
|
|
162
|
+
}
|
|
81
163
|
this.store.link.close();
|
|
164
|
+
this.store.transactionsStarted = 0;
|
|
82
165
|
this.store.connected = false;
|
|
83
166
|
}
|
|
84
167
|
return this.store.connected;
|
|
@@ -86,51 +169,113 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
86
169
|
async inTransaction() {
|
|
87
170
|
return this.store.transactionsStarted > 0;
|
|
88
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Check connection status.
|
|
174
|
+
*
|
|
175
|
+
* @returns Whether this instance is connected to a SQLite3 database.
|
|
176
|
+
*/
|
|
89
177
|
isConnected() {
|
|
90
178
|
return this.store.connected;
|
|
91
179
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
180
|
+
createEntitiesTable(etype) {
|
|
181
|
+
// Create the entity table.
|
|
182
|
+
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, "user" CHARACTER(24), "group" CHARACTER(24), "acUser" INT(1), "acGroup" INT(1), "acOther" INT(1), "acRead" TEXT, "acWrite" TEXT, "acFull" TEXT);`);
|
|
183
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_cdate`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("cdate");`);
|
|
184
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_mdate`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("mdate");`);
|
|
185
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_tags`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("tags");`);
|
|
186
|
+
this.createEntitiesTilmeldIndexes(etype);
|
|
96
187
|
}
|
|
188
|
+
addTilmeldColumnsAndIndexes(etype) {
|
|
189
|
+
this.queryRun(`ALTER TABLE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN "user" CHARACTER(24);`);
|
|
190
|
+
this.queryRun(`ALTER TABLE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN "group" CHARACTER(24);`);
|
|
191
|
+
this.queryRun(`ALTER TABLE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN "acUser" INT(1);`);
|
|
192
|
+
this.queryRun(`ALTER TABLE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN "acGroup" INT(1);`);
|
|
193
|
+
this.queryRun(`ALTER TABLE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN "acOther" INT(1);`);
|
|
194
|
+
this.queryRun(`ALTER TABLE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN "acRead" TEXT;`);
|
|
195
|
+
this.queryRun(`ALTER TABLE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN "acWrite" TEXT;`);
|
|
196
|
+
this.queryRun(`ALTER TABLE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN "acFull" TEXT;`);
|
|
197
|
+
this.createEntitiesTilmeldIndexes(etype);
|
|
198
|
+
}
|
|
199
|
+
createEntitiesTilmeldIndexes(etype) {
|
|
200
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_user_acUser`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("user", "acUser");`);
|
|
201
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_group_acGroup`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("group", "acGroup");`);
|
|
202
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_acUser`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("acUser");`);
|
|
203
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_acGroup`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("acGroup");`);
|
|
204
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_acOther`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("acOther");`);
|
|
205
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_acRead`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("acRead");`);
|
|
206
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_acWrite`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("acWrite");`);
|
|
207
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_acFull`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("acFull");`);
|
|
208
|
+
}
|
|
209
|
+
createDataTable(etype) {
|
|
210
|
+
// Create the data table.
|
|
211
|
+
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"));`);
|
|
212
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`);
|
|
213
|
+
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");`);
|
|
214
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`);
|
|
215
|
+
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");`);
|
|
216
|
+
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");`);
|
|
217
|
+
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");`);
|
|
218
|
+
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");`);
|
|
219
|
+
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");`);
|
|
220
|
+
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;`);
|
|
221
|
+
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;`);
|
|
222
|
+
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;`);
|
|
223
|
+
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\';`);
|
|
224
|
+
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\';`);
|
|
225
|
+
}
|
|
226
|
+
createReferencesTable(etype) {
|
|
227
|
+
// Create the references table.
|
|
228
|
+
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"));`);
|
|
229
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid");`);
|
|
230
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name");`);
|
|
231
|
+
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");`);
|
|
232
|
+
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.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "name");`);
|
|
234
|
+
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");`);
|
|
235
|
+
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");`);
|
|
236
|
+
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");`);
|
|
237
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference_guid_nameuser`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference", "guid") WHERE "name"=\'user\';`);
|
|
238
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference_guid_namegroup`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference", "guid") WHERE "name"=\'group\';`);
|
|
239
|
+
}
|
|
240
|
+
createTokensTable(etype) {
|
|
241
|
+
// Create the tokens table.
|
|
242
|
+
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"));`);
|
|
243
|
+
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");`);
|
|
244
|
+
}
|
|
245
|
+
createUniquesTable(etype) {
|
|
246
|
+
// Create the unique strings table.
|
|
247
|
+
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"));`);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Create entity tables in the database.
|
|
251
|
+
*
|
|
252
|
+
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
253
|
+
*/
|
|
97
254
|
createTables(etype = null) {
|
|
98
|
-
this.checkReadOnlyMode();
|
|
99
255
|
this.startTransaction('nymph-tablecreation');
|
|
100
256
|
try {
|
|
101
257
|
if (etype != null) {
|
|
102
|
-
this.
|
|
103
|
-
this.
|
|
104
|
-
this.
|
|
105
|
-
this.
|
|
106
|
-
this.
|
|
107
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`);
|
|
108
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`);
|
|
109
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_value`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("value");`);
|
|
110
|
-
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\';`);
|
|
111
|
-
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\';`);
|
|
112
|
-
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"));`);
|
|
113
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("guid");`);
|
|
114
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("name");`);
|
|
115
|
-
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;`);
|
|
116
|
-
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"));`);
|
|
117
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid");`);
|
|
118
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name");`);
|
|
119
|
-
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference");`);
|
|
258
|
+
this.createEntitiesTable(etype);
|
|
259
|
+
this.createDataTable(etype);
|
|
260
|
+
this.createReferencesTable(etype);
|
|
261
|
+
this.createTokensTable(etype);
|
|
262
|
+
this.createUniquesTable(etype);
|
|
120
263
|
}
|
|
121
264
|
else {
|
|
265
|
+
// Create the UID table.
|
|
122
266
|
this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}uids`)} ("name" TEXT PRIMARY KEY NOT NULL, "cur_uid" INTEGER NOT NULL);`);
|
|
123
267
|
}
|
|
124
|
-
this.commit('nymph-tablecreation');
|
|
125
|
-
return true;
|
|
126
268
|
}
|
|
127
269
|
catch (e) {
|
|
128
270
|
this.rollback('nymph-tablecreation');
|
|
129
271
|
throw e;
|
|
130
272
|
}
|
|
273
|
+
this.commit('nymph-tablecreation');
|
|
274
|
+
return true;
|
|
131
275
|
}
|
|
132
276
|
query(runQuery, query, etypes = []) {
|
|
133
277
|
try {
|
|
278
|
+
this.nymph.config.debugInfo('sqlite3:query', query);
|
|
134
279
|
return runQuery();
|
|
135
280
|
}
|
|
136
281
|
catch (e) {
|
|
@@ -146,32 +291,45 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
146
291
|
return runQuery();
|
|
147
292
|
}
|
|
148
293
|
catch (e2) {
|
|
149
|
-
throw new
|
|
294
|
+
throw new QueryFailedError('Query failed: ' + e2?.code + ' - ' + e2?.message, query, e2?.code);
|
|
150
295
|
}
|
|
151
296
|
}
|
|
297
|
+
else if (errorCode === 'SQLITE_CONSTRAINT_UNIQUE' &&
|
|
298
|
+
errorMsg.match(/^UNIQUE constraint failed: /)) {
|
|
299
|
+
throw new EntityUniqueConstraintError(`Unique constraint violation.`);
|
|
300
|
+
}
|
|
152
301
|
else {
|
|
153
|
-
throw new
|
|
302
|
+
throw new QueryFailedError('Query failed: ' + e?.code + ' - ' + e?.message, query, e?.code);
|
|
154
303
|
}
|
|
155
304
|
}
|
|
156
305
|
}
|
|
157
|
-
|
|
158
|
-
return this.query(() => this.store.
|
|
306
|
+
queryArray(query, { etypes = [], params = {}, } = {}) {
|
|
307
|
+
return this.query(() => (this.store.linkWrite || this.store.link)
|
|
308
|
+
.prepare(query)
|
|
309
|
+
.iterate(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
159
310
|
}
|
|
160
311
|
queryGet(query, { etypes = [], params = {}, } = {}) {
|
|
161
|
-
return this.query(() => this.store.link.prepare(query).get(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
312
|
+
return this.query(() => (this.store.linkWrite || this.store.link).prepare(query).get(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
162
313
|
}
|
|
163
314
|
queryRun(query, { etypes = [], params = {}, } = {}) {
|
|
164
|
-
return this.query(() => this.store.link.prepare(query).run(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
315
|
+
return this.query(() => (this.store.linkWrite || this.store.link).prepare(query).run(params), `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
165
316
|
}
|
|
166
317
|
async commit(name) {
|
|
167
318
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
168
|
-
throw new
|
|
319
|
+
throw new InvalidParametersError('Transaction commit attempted without a name.');
|
|
169
320
|
}
|
|
170
321
|
if (this.store.transactionsStarted === 0) {
|
|
171
322
|
return true;
|
|
172
323
|
}
|
|
173
324
|
this.queryRun(`RELEASE SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
174
325
|
this.store.transactionsStarted--;
|
|
326
|
+
if (this.store.transactionsStarted === 0 &&
|
|
327
|
+
this.store.linkWrite &&
|
|
328
|
+
!this.config.explicitWrite) {
|
|
329
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
330
|
+
this.store.linkWrite.close();
|
|
331
|
+
this.store.linkWrite = undefined;
|
|
332
|
+
}
|
|
175
333
|
return true;
|
|
176
334
|
}
|
|
177
335
|
async deleteEntityByID(guid, className) {
|
|
@@ -184,7 +342,6 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
184
342
|
EntityClass = className;
|
|
185
343
|
}
|
|
186
344
|
const etype = EntityClass.ETYPE;
|
|
187
|
-
this.checkReadOnlyMode();
|
|
188
345
|
await this.startTransaction('nymph-delete');
|
|
189
346
|
try {
|
|
190
347
|
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=@guid;`, {
|
|
@@ -199,108 +356,256 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
199
356
|
guid,
|
|
200
357
|
},
|
|
201
358
|
});
|
|
202
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
359
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=@guid;`, {
|
|
203
360
|
etypes: [etype],
|
|
204
361
|
params: {
|
|
205
362
|
guid,
|
|
206
363
|
},
|
|
207
364
|
});
|
|
208
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
365
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
|
|
366
|
+
etypes: [etype],
|
|
367
|
+
params: {
|
|
368
|
+
guid,
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
|
|
209
372
|
etypes: [etype],
|
|
210
373
|
params: {
|
|
211
374
|
guid,
|
|
212
375
|
},
|
|
213
376
|
});
|
|
214
|
-
await this.commit('nymph-delete');
|
|
215
|
-
if (this.nymph.config.cache) {
|
|
216
|
-
this.cleanCache(guid);
|
|
217
|
-
}
|
|
218
|
-
return true;
|
|
219
377
|
}
|
|
220
378
|
catch (e) {
|
|
379
|
+
this.nymph.config.debugError('sqlite3', `Delete entity error: "${e}"`);
|
|
221
380
|
await this.rollback('nymph-delete');
|
|
222
381
|
throw e;
|
|
223
382
|
}
|
|
383
|
+
await this.commit('nymph-delete');
|
|
384
|
+
// Remove any cached versions of this entity.
|
|
385
|
+
if (this.nymph.config.cache) {
|
|
386
|
+
this.cleanCache(guid);
|
|
387
|
+
}
|
|
388
|
+
return true;
|
|
224
389
|
}
|
|
225
390
|
async deleteUID(name) {
|
|
226
391
|
if (!name) {
|
|
227
|
-
throw new
|
|
392
|
+
throw new InvalidParametersError('Name not given for UID');
|
|
228
393
|
}
|
|
229
|
-
this.
|
|
394
|
+
await this.startTransaction('nymph-delete-uid');
|
|
230
395
|
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
231
396
|
params: {
|
|
232
397
|
name,
|
|
233
398
|
},
|
|
234
399
|
});
|
|
400
|
+
await this.commit('nymph-delete-uid');
|
|
235
401
|
return true;
|
|
236
402
|
}
|
|
237
|
-
async
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
403
|
+
async getIndexes(etype) {
|
|
404
|
+
const indexes = [];
|
|
405
|
+
for (let [scope, suffix] of [
|
|
406
|
+
['data', '_json'],
|
|
407
|
+
['references', '_reference_guid'],
|
|
408
|
+
['tokens', '_token_position_stem'],
|
|
409
|
+
]) {
|
|
410
|
+
const indexDefinitions = this.queryArray(`SELECT "name", "sql" FROM "sqlite_master" WHERE "type"='index' AND "name" LIKE @pattern;`, {
|
|
411
|
+
params: {
|
|
412
|
+
pattern: `${this.prefix}${scope}_${etype}_id_custom_%${suffix}`,
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
for (const indexDefinition of indexDefinitions) {
|
|
416
|
+
indexes.push({
|
|
417
|
+
scope,
|
|
418
|
+
name: indexDefinition.name.substring(`${this.prefix}${scope}_${etype}_id_custom_`.length, indexDefinition.name.length - suffix.length),
|
|
419
|
+
property: (indexDefinition.sql.match(/WHERE\s+"name"\s*=\s*'(.*)'/) ?? [])[1] ?? '',
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return indexes;
|
|
424
|
+
}
|
|
425
|
+
async addIndex(etype, definition) {
|
|
426
|
+
this.checkIndexName(definition.name);
|
|
427
|
+
await this.deleteIndex(etype, definition.scope, definition.name);
|
|
428
|
+
if (definition.scope === 'data') {
|
|
429
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_json`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("json") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
|
|
430
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_string`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("string") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
|
|
431
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_number`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("number") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
|
|
432
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_truthy`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("truthy") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
|
|
433
|
+
}
|
|
434
|
+
else if (definition.scope === 'references') {
|
|
435
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_custom_${definition.name}_reference_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference", "guid") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
|
|
436
|
+
}
|
|
437
|
+
else if (definition.scope === 'tokens') {
|
|
438
|
+
this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_custom_${definition.name}_token_position_stem`)} ON ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("token", "position", "stem") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
|
|
439
|
+
}
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
async deleteIndex(etype, scope, name) {
|
|
443
|
+
this.checkIndexName(name);
|
|
444
|
+
if (scope === 'data') {
|
|
445
|
+
this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_json`)};`);
|
|
446
|
+
this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_string`)};`);
|
|
447
|
+
this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_number`)};`);
|
|
448
|
+
this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_truthy`)};`);
|
|
449
|
+
}
|
|
450
|
+
else if (scope === 'references') {
|
|
451
|
+
this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_custom_${name}_reference_guid`)};`);
|
|
452
|
+
}
|
|
453
|
+
else if (scope === 'tokens') {
|
|
454
|
+
this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_custom_${name}_token_position_stem`)};`);
|
|
455
|
+
}
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
async getEtypes() {
|
|
459
|
+
const tables = this.queryArray("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix;", {
|
|
460
|
+
params: {
|
|
461
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
462
|
+
},
|
|
463
|
+
});
|
|
258
464
|
const etypes = [];
|
|
259
465
|
for (const table of tables) {
|
|
260
|
-
|
|
261
|
-
|
|
466
|
+
etypes.push(table.name.substr((this.prefix + 'entities_').length));
|
|
467
|
+
}
|
|
468
|
+
return etypes;
|
|
469
|
+
}
|
|
470
|
+
async *exportDataIterator() {
|
|
471
|
+
if (yield {
|
|
472
|
+
type: 'comment',
|
|
473
|
+
content: `#nex2
|
|
474
|
+
# Nymph Entity Exchange v2
|
|
475
|
+
# http://nymph.io
|
|
476
|
+
#
|
|
477
|
+
# Generation Time: ${new Date().toLocaleString()}
|
|
478
|
+
`,
|
|
479
|
+
}) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (yield {
|
|
483
|
+
type: 'comment',
|
|
484
|
+
content: `
|
|
485
|
+
|
|
486
|
+
#
|
|
487
|
+
# UIDs
|
|
488
|
+
#
|
|
489
|
+
|
|
490
|
+
`,
|
|
491
|
+
}) {
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
// Export UIDs.
|
|
495
|
+
let uids = this.queryArray(`SELECT * FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} ORDER BY "name";`);
|
|
496
|
+
for (const uid of uids) {
|
|
497
|
+
if (yield { type: 'uid', content: `<${uid.name}>[${uid.cur_uid}]\n` }) {
|
|
498
|
+
return;
|
|
262
499
|
}
|
|
263
500
|
}
|
|
501
|
+
if (yield {
|
|
502
|
+
type: 'comment',
|
|
503
|
+
content: `
|
|
504
|
+
|
|
505
|
+
#
|
|
506
|
+
# Entities
|
|
507
|
+
#
|
|
508
|
+
|
|
509
|
+
`,
|
|
510
|
+
}) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
// Get the etypes.
|
|
514
|
+
const etypes = await this.getEtypes();
|
|
264
515
|
for (const etype of etypes) {
|
|
265
|
-
|
|
516
|
+
// Export entities.
|
|
517
|
+
const dataIterator = this.queryArray(`SELECT e."guid", e."tags", e."cdate", e."mdate", e."user", e."group", e."acUser", e."acGroup", e."acOther", e."acRead", e."acWrite", e."acFull", d."name", d."value", json(d."json") as "json", d."string", d."number" FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} e LEFT JOIN ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} d USING ("guid") ORDER BY e."guid";`)[Symbol.iterator]();
|
|
266
518
|
let datum = dataIterator.next();
|
|
267
519
|
while (!datum.done) {
|
|
268
520
|
const guid = datum.value.guid;
|
|
269
521
|
const tags = datum.value.tags.slice(1, -1);
|
|
270
522
|
const cdate = datum.value.cdate;
|
|
271
523
|
const mdate = datum.value.mdate;
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
524
|
+
const user = datum.value.user;
|
|
525
|
+
const group = datum.value.group;
|
|
526
|
+
const acUser = datum.value.acUser;
|
|
527
|
+
const acGroup = datum.value.acGroup;
|
|
528
|
+
const acOther = datum.value.acOther;
|
|
529
|
+
const acRead = datum.value.acRead?.slice(1, -1).split(',');
|
|
530
|
+
const acWrite = datum.value.acWrite?.slice(1, -1).split(',');
|
|
531
|
+
const acFull = datum.value.acFull?.slice(1, -1).split(',');
|
|
532
|
+
let currentEntityExport = [];
|
|
533
|
+
currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
|
|
534
|
+
currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
|
|
535
|
+
currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
|
|
536
|
+
if (this.nymph.tilmeld != null) {
|
|
537
|
+
if (user != null) {
|
|
538
|
+
currentEntityExport.push(`\tuser=${JSON.stringify(['nymph_entity_reference', user, 'User'])}`);
|
|
539
|
+
}
|
|
540
|
+
if (group != null) {
|
|
541
|
+
currentEntityExport.push(`\tgroup=${JSON.stringify(['nymph_entity_reference', group, 'Group'])}`);
|
|
542
|
+
}
|
|
543
|
+
if (acUser != null) {
|
|
544
|
+
currentEntityExport.push(`\tacUser=${JSON.stringify(acUser)}`);
|
|
545
|
+
}
|
|
546
|
+
if (acGroup != null) {
|
|
547
|
+
currentEntityExport.push(`\tacGroup=${JSON.stringify(acGroup)}`);
|
|
548
|
+
}
|
|
549
|
+
if (acOther != null) {
|
|
550
|
+
currentEntityExport.push(`\tacOther=${JSON.stringify(acOther)}`);
|
|
551
|
+
}
|
|
552
|
+
if (acRead != null) {
|
|
553
|
+
currentEntityExport.push(`\tacRead=${JSON.stringify(acRead)}`);
|
|
554
|
+
}
|
|
555
|
+
if (acWrite != null) {
|
|
556
|
+
currentEntityExport.push(`\tacWrite=${JSON.stringify(acWrite)}`);
|
|
557
|
+
}
|
|
558
|
+
if (acFull != null) {
|
|
559
|
+
currentEntityExport.push(`\tacFull=${JSON.stringify(acFull)}`);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
if (datum.value.name != null) {
|
|
563
|
+
// This do will keep going and adding the data until the
|
|
564
|
+
// next entity is reached. datum will end on the next entity.
|
|
276
565
|
do {
|
|
277
|
-
const value = datum.value.
|
|
566
|
+
const value = datum.value.value === 'N'
|
|
278
567
|
? JSON.stringify(datum.value.number)
|
|
279
|
-
: datum.value.
|
|
568
|
+
: datum.value.value === 'S'
|
|
280
569
|
? JSON.stringify(datum.value.string)
|
|
281
|
-
: datum.value.
|
|
282
|
-
|
|
570
|
+
: datum.value.value === 'J'
|
|
571
|
+
? datum.value.json
|
|
572
|
+
: datum.value.value;
|
|
573
|
+
currentEntityExport.push(`\t${datum.value.name}=${value}`);
|
|
283
574
|
datum = dataIterator.next();
|
|
284
575
|
} while (!datum.done && datum.value.guid === guid);
|
|
285
576
|
}
|
|
286
577
|
else {
|
|
578
|
+
// Make sure that datum is incremented :)
|
|
287
579
|
datum = dataIterator.next();
|
|
288
580
|
}
|
|
581
|
+
currentEntityExport.push('');
|
|
582
|
+
if (yield { type: 'entity', content: currentEntityExport.join('\n') }) {
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
289
585
|
}
|
|
290
586
|
}
|
|
291
|
-
return;
|
|
292
587
|
}
|
|
293
|
-
|
|
588
|
+
/**
|
|
589
|
+
* Generate the SQLite3 query.
|
|
590
|
+
* @param options The options array.
|
|
591
|
+
* @param formattedSelectors The formatted selector array.
|
|
592
|
+
* @param etype
|
|
593
|
+
* @param count Used to track internal params.
|
|
594
|
+
* @param params Used to store internal params.
|
|
595
|
+
* @param subquery Whether only a subquery should be returned.
|
|
596
|
+
* @returns The SQL query.
|
|
597
|
+
*/
|
|
598
|
+
makeEntityQuery(options, formattedSelectors, etype, count = { i: 0 }, params = {}, subquery = false, tableSuffix = '', etypes = [], guidSelector = undefined) {
|
|
294
599
|
if (typeof options.class?.alterOptions === 'function') {
|
|
295
600
|
options = options.class.alterOptions(options);
|
|
296
601
|
}
|
|
297
602
|
const eTable = `e${tableSuffix}`;
|
|
298
603
|
const dTable = `d${tableSuffix}`;
|
|
299
|
-
const cTable = `c${tableSuffix}`;
|
|
300
604
|
const fTable = `f${tableSuffix}`;
|
|
301
605
|
const ieTable = `ie${tableSuffix}`;
|
|
302
|
-
const
|
|
303
|
-
const
|
|
606
|
+
const sTable = `s${tableSuffix}`;
|
|
607
|
+
const sort = options.sort === undefined ? 'cdate' : options.sort;
|
|
608
|
+
const queryParts = this.iterateSelectorsForQuery(formattedSelectors, ({ key, value, typeIsOr, typeIsNot }) => {
|
|
304
609
|
const clauseNot = key.startsWith('!');
|
|
305
610
|
let curQuery = '';
|
|
306
611
|
for (const curValue of value) {
|
|
@@ -313,7 +618,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
313
618
|
}
|
|
314
619
|
const guid = `param${++count.i}`;
|
|
315
620
|
curQuery +=
|
|
316
|
-
(
|
|
621
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
317
622
|
ieTable +
|
|
318
623
|
'."guid"=@' +
|
|
319
624
|
guid;
|
|
@@ -328,7 +633,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
328
633
|
}
|
|
329
634
|
const tag = `param${++count.i}`;
|
|
330
635
|
curQuery +=
|
|
331
|
-
(
|
|
636
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
332
637
|
ieTable +
|
|
333
638
|
'."tags" LIKE @' +
|
|
334
639
|
tag +
|
|
@@ -348,17 +653,38 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
348
653
|
if (curQuery) {
|
|
349
654
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
350
655
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
656
|
+
if (curVar === 'cdate' ||
|
|
657
|
+
curVar === 'mdate' ||
|
|
658
|
+
(this.nymph.tilmeld != null &&
|
|
659
|
+
(curVar === 'user' ||
|
|
660
|
+
curVar === 'group' ||
|
|
661
|
+
curVar === 'acUser' ||
|
|
662
|
+
curVar === 'acGroup' ||
|
|
663
|
+
curVar === 'acOther' ||
|
|
664
|
+
curVar === 'acRead' ||
|
|
665
|
+
curVar === 'acWrite' ||
|
|
666
|
+
curVar === 'acFull'))) {
|
|
667
|
+
curQuery +=
|
|
668
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
669
|
+
'(' +
|
|
670
|
+
ieTable +
|
|
671
|
+
'.' +
|
|
672
|
+
SQLite3Driver.escape(curVar) +
|
|
673
|
+
' IS NOT NULL)';
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
const name = `param${++count.i}`;
|
|
677
|
+
curQuery +=
|
|
678
|
+
ieTable +
|
|
679
|
+
'."guid" ' +
|
|
680
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
681
|
+
'IN (SELECT "guid" FROM ' +
|
|
682
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
683
|
+
' WHERE "name"=@' +
|
|
684
|
+
name +
|
|
685
|
+
')';
|
|
686
|
+
params[name] = curVar;
|
|
687
|
+
}
|
|
362
688
|
}
|
|
363
689
|
break;
|
|
364
690
|
case 'truthy':
|
|
@@ -367,30 +693,34 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
367
693
|
if (curQuery) {
|
|
368
694
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
369
695
|
}
|
|
370
|
-
if (curVar === 'cdate'
|
|
696
|
+
if (curVar === 'cdate' ||
|
|
697
|
+
curVar === 'mdate' ||
|
|
698
|
+
(this.nymph.tilmeld != null &&
|
|
699
|
+
(curVar === 'user' ||
|
|
700
|
+
curVar === 'group' ||
|
|
701
|
+
curVar === 'acUser' ||
|
|
702
|
+
curVar === 'acGroup' ||
|
|
703
|
+
curVar === 'acOther' ||
|
|
704
|
+
curVar === 'acRead' ||
|
|
705
|
+
curVar === 'acWrite' ||
|
|
706
|
+
curVar === 'acFull'))) {
|
|
371
707
|
curQuery +=
|
|
372
|
-
(
|
|
708
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
373
709
|
'(' +
|
|
374
710
|
ieTable +
|
|
375
|
-
'.
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
else if (curVar === 'mdate') {
|
|
379
|
-
curQuery +=
|
|
380
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
381
|
-
'(' +
|
|
382
|
-
ieTable +
|
|
383
|
-
'."mdate" NOT NULL)';
|
|
384
|
-
break;
|
|
711
|
+
'.' +
|
|
712
|
+
SQLite3Driver.escape(curVar) +
|
|
713
|
+
' IS NOT NULL)';
|
|
385
714
|
}
|
|
386
715
|
else {
|
|
387
716
|
const name = `param${++count.i}`;
|
|
388
717
|
curQuery +=
|
|
389
|
-
(
|
|
718
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
719
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
720
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
721
|
+
' WHERE "guid"=' +
|
|
390
722
|
ieTable +
|
|
391
|
-
'."guid"
|
|
392
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
393
|
-
' WHERE "name"=@' +
|
|
723
|
+
'."guid" AND "name"=@' +
|
|
394
724
|
name +
|
|
395
725
|
' AND "truthy"=1)';
|
|
396
726
|
params[name] = curVar;
|
|
@@ -399,31 +729,58 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
399
729
|
break;
|
|
400
730
|
case 'equal':
|
|
401
731
|
case '!equal':
|
|
402
|
-
if (curValue[0] === 'cdate'
|
|
732
|
+
if (curValue[0] === 'cdate' ||
|
|
733
|
+
curValue[0] === 'mdate' ||
|
|
734
|
+
(this.nymph.tilmeld != null &&
|
|
735
|
+
(curValue[0] === 'acUser' ||
|
|
736
|
+
curValue[0] === 'acGroup' ||
|
|
737
|
+
curValue[0] === 'acOther'))) {
|
|
403
738
|
if (curQuery) {
|
|
404
739
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
405
740
|
}
|
|
406
|
-
const
|
|
741
|
+
const value = `param${++count.i}`;
|
|
407
742
|
curQuery +=
|
|
408
|
-
(
|
|
743
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
409
744
|
ieTable +
|
|
410
|
-
'.
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
745
|
+
'.' +
|
|
746
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
747
|
+
'=@' +
|
|
748
|
+
value;
|
|
749
|
+
params[value] = Number(curValue[1]);
|
|
414
750
|
}
|
|
415
|
-
else if (
|
|
751
|
+
else if (this.nymph.tilmeld != null &&
|
|
752
|
+
(curValue[0] === 'user' || curValue[0] === 'group')) {
|
|
416
753
|
if (curQuery) {
|
|
417
754
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
418
755
|
}
|
|
419
|
-
const
|
|
756
|
+
const value = `param${++count.i}`;
|
|
420
757
|
curQuery +=
|
|
421
|
-
(
|
|
758
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
422
759
|
ieTable +
|
|
423
|
-
'.
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
760
|
+
'.' +
|
|
761
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
762
|
+
'=@' +
|
|
763
|
+
value;
|
|
764
|
+
params[value] = `${curValue[1]}`;
|
|
765
|
+
}
|
|
766
|
+
else if (this.nymph.tilmeld != null &&
|
|
767
|
+
(curValue[0] === 'acRead' ||
|
|
768
|
+
curValue[0] === 'acWrite' ||
|
|
769
|
+
curValue[0] === 'acFull')) {
|
|
770
|
+
if (curQuery) {
|
|
771
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
772
|
+
}
|
|
773
|
+
const value = `param${++count.i}`;
|
|
774
|
+
curQuery +=
|
|
775
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
776
|
+
ieTable +
|
|
777
|
+
'.' +
|
|
778
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
779
|
+
'=@' +
|
|
780
|
+
value;
|
|
781
|
+
params[value] = Array.isArray(curValue[1])
|
|
782
|
+
? ',' + curValue[1].join(',') + ','
|
|
783
|
+
: '';
|
|
427
784
|
}
|
|
428
785
|
else if (typeof curValue[1] === 'number') {
|
|
429
786
|
if (curQuery) {
|
|
@@ -432,11 +789,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
432
789
|
const name = `param${++count.i}`;
|
|
433
790
|
const value = `param${++count.i}`;
|
|
434
791
|
curQuery +=
|
|
435
|
-
(
|
|
792
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
793
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
794
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
795
|
+
' WHERE "guid"=' +
|
|
436
796
|
ieTable +
|
|
437
|
-
'."guid"
|
|
438
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
439
|
-
' WHERE "name"=@' +
|
|
797
|
+
'."guid" AND "name"=@' +
|
|
440
798
|
name +
|
|
441
799
|
' AND "number"=@' +
|
|
442
800
|
value +
|
|
@@ -451,11 +809,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
451
809
|
const name = `param${++count.i}`;
|
|
452
810
|
const value = `param${++count.i}`;
|
|
453
811
|
curQuery +=
|
|
454
|
-
(
|
|
812
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
813
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
814
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
815
|
+
' WHERE "guid"=' +
|
|
455
816
|
ieTable +
|
|
456
|
-
'."guid"
|
|
457
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
458
|
-
' WHERE "name"=@' +
|
|
817
|
+
'."guid" AND "name"=@' +
|
|
459
818
|
name +
|
|
460
819
|
' AND "string"=@' +
|
|
461
820
|
value +
|
|
@@ -478,134 +837,273 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
478
837
|
const name = `param${++count.i}`;
|
|
479
838
|
const value = `param${++count.i}`;
|
|
480
839
|
curQuery +=
|
|
481
|
-
(
|
|
482
|
-
|
|
483
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
840
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
841
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
484
842
|
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
485
|
-
' WHERE "
|
|
843
|
+
' WHERE "guid"=' +
|
|
844
|
+
ieTable +
|
|
845
|
+
'."guid" AND "name"=@' +
|
|
486
846
|
name +
|
|
487
|
-
' AND "
|
|
847
|
+
' AND "json"=jsonb(@' +
|
|
488
848
|
value +
|
|
489
|
-
')';
|
|
849
|
+
'))';
|
|
490
850
|
params[name] = curValue[0];
|
|
491
851
|
params[value] = svalue;
|
|
492
852
|
}
|
|
493
853
|
break;
|
|
494
854
|
case 'contain':
|
|
495
855
|
case '!contain':
|
|
496
|
-
if (curValue[0] === 'cdate'
|
|
856
|
+
if (curValue[0] === 'cdate' ||
|
|
857
|
+
curValue[0] === 'mdate' ||
|
|
858
|
+
(this.nymph.tilmeld != null &&
|
|
859
|
+
(curValue[0] === 'acUser' ||
|
|
860
|
+
curValue[0] === 'acGroup' ||
|
|
861
|
+
curValue[0] === 'acOther'))) {
|
|
497
862
|
if (curQuery) {
|
|
498
863
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
499
864
|
}
|
|
500
|
-
const
|
|
865
|
+
const value = `param${++count.i}`;
|
|
501
866
|
curQuery +=
|
|
502
|
-
(
|
|
867
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
503
868
|
ieTable +
|
|
504
|
-
'.
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
869
|
+
'.' +
|
|
870
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
871
|
+
'=@' +
|
|
872
|
+
value;
|
|
873
|
+
params[value] = Number(curValue[1]);
|
|
508
874
|
}
|
|
509
|
-
else if (
|
|
875
|
+
else if (this.nymph.tilmeld != null &&
|
|
876
|
+
(curValue[0] === 'user' || curValue[0] === 'group')) {
|
|
510
877
|
if (curQuery) {
|
|
511
878
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
512
879
|
}
|
|
513
|
-
const
|
|
880
|
+
const value = `param${++count.i}`;
|
|
514
881
|
curQuery +=
|
|
515
|
-
(
|
|
882
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
516
883
|
ieTable +
|
|
517
|
-
'.
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
884
|
+
'.' +
|
|
885
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
886
|
+
'=@' +
|
|
887
|
+
value;
|
|
888
|
+
params[value] = `${curValue[1]}`;
|
|
889
|
+
}
|
|
890
|
+
else if (this.nymph.tilmeld != null &&
|
|
891
|
+
(curValue[0] === 'acRead' ||
|
|
892
|
+
curValue[0] === 'acWrite' ||
|
|
893
|
+
curValue[0] === 'acFull')) {
|
|
894
|
+
if (curQuery) {
|
|
895
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
896
|
+
}
|
|
897
|
+
const id = `param${++count.i}`;
|
|
898
|
+
curQuery +=
|
|
899
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
900
|
+
ieTable +
|
|
901
|
+
'.' +
|
|
902
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
903
|
+
' LIKE @' +
|
|
904
|
+
id +
|
|
905
|
+
" ESCAPE '\\'";
|
|
906
|
+
params[id] =
|
|
907
|
+
'%,' +
|
|
908
|
+
curValue[1]
|
|
909
|
+
.replace('\\', '\\\\')
|
|
910
|
+
.replace('%', '\\%')
|
|
911
|
+
.replace('_', '\\_') +
|
|
912
|
+
',%';
|
|
521
913
|
}
|
|
522
914
|
else {
|
|
915
|
+
const containTableSuffix = makeTableSuffix();
|
|
523
916
|
if (curQuery) {
|
|
524
917
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
525
918
|
}
|
|
526
919
|
let svalue;
|
|
527
|
-
let stringValue;
|
|
528
920
|
if (curValue[1] instanceof Object &&
|
|
529
921
|
typeof curValue[1].toReference === 'function') {
|
|
530
922
|
svalue = JSON.stringify(curValue[1].toReference());
|
|
531
|
-
stringValue = `${curValue[1].toReference()}`;
|
|
532
923
|
}
|
|
533
924
|
else {
|
|
534
925
|
svalue = JSON.stringify(curValue[1]);
|
|
535
|
-
stringValue = `${curValue[1]}`;
|
|
536
926
|
}
|
|
537
927
|
const name = `param${++count.i}`;
|
|
538
928
|
const value = `param${++count.i}`;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
(
|
|
543
|
-
|
|
929
|
+
curQuery +=
|
|
930
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
931
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
932
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
933
|
+
' d' +
|
|
934
|
+
containTableSuffix +
|
|
935
|
+
' WHERE "guid"=' +
|
|
936
|
+
ieTable +
|
|
937
|
+
'."guid" AND "name"=@' +
|
|
938
|
+
name +
|
|
939
|
+
' AND json(@' +
|
|
940
|
+
value +
|
|
941
|
+
') IN (SELECT json_quote("value") FROM json_each(d' +
|
|
942
|
+
containTableSuffix +
|
|
943
|
+
'."json")))';
|
|
944
|
+
params[name] = curValue[0];
|
|
945
|
+
params[value] = svalue;
|
|
946
|
+
}
|
|
947
|
+
break;
|
|
948
|
+
case 'search':
|
|
949
|
+
case '!search':
|
|
950
|
+
if (curValue[0] === 'cdate' ||
|
|
951
|
+
curValue[0] === 'mdate' ||
|
|
952
|
+
(this.nymph.tilmeld != null &&
|
|
953
|
+
(curValue[0] === 'user' ||
|
|
954
|
+
curValue[0] === 'group' ||
|
|
955
|
+
curValue[0] === 'acUser' ||
|
|
956
|
+
curValue[0] === 'acGroup' ||
|
|
957
|
+
curValue[0] === 'acOther' ||
|
|
958
|
+
curValue[0] === 'acRead' ||
|
|
959
|
+
curValue[0] === 'acWrite' ||
|
|
960
|
+
curValue[0] === 'acFull'))) {
|
|
961
|
+
if (curQuery) {
|
|
962
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
963
|
+
}
|
|
964
|
+
curQuery += (xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(0)';
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
if (curQuery) {
|
|
968
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
969
|
+
}
|
|
970
|
+
const parsedFTSQuery = this.tokenizer.parseSearchQuery(curValue[1]);
|
|
971
|
+
if (!parsedFTSQuery.length) {
|
|
972
|
+
curQuery += (xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(0)';
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
const name = `param${++count.i}`;
|
|
976
|
+
const queryPartToken = (term) => {
|
|
977
|
+
const value = `param${++count.i}`;
|
|
978
|
+
params[value] = term.token;
|
|
979
|
+
return ('EXISTS (SELECT "guid" FROM ' +
|
|
980
|
+
SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
|
|
981
|
+
' WHERE "guid"=' +
|
|
544
982
|
ieTable +
|
|
545
|
-
'."guid"
|
|
546
|
-
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
547
|
-
' WHERE "name"=@' +
|
|
983
|
+
'."guid" AND "name"=@' +
|
|
548
984
|
name +
|
|
549
|
-
' AND
|
|
985
|
+
' AND "token"=@' +
|
|
550
986
|
value +
|
|
551
|
-
'
|
|
987
|
+
(term.nostemmed ? ' AND "stem"=0' : '') +
|
|
988
|
+
')');
|
|
989
|
+
};
|
|
990
|
+
const queryPartSeries = (series) => {
|
|
991
|
+
const tokenTableSuffix = makeTableSuffix();
|
|
992
|
+
const tokenParts = series.tokens.map((token, i) => {
|
|
993
|
+
const value = `param${++count.i}`;
|
|
994
|
+
params[value] = token.token;
|
|
995
|
+
return {
|
|
996
|
+
fromClause: i === 0
|
|
997
|
+
? 'FROM ' +
|
|
998
|
+
SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
|
|
999
|
+
' t' +
|
|
1000
|
+
tokenTableSuffix +
|
|
1001
|
+
'0'
|
|
1002
|
+
: 'JOIN ' +
|
|
1003
|
+
SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
|
|
1004
|
+
' t' +
|
|
1005
|
+
tokenTableSuffix +
|
|
1006
|
+
i +
|
|
1007
|
+
' ON t' +
|
|
1008
|
+
tokenTableSuffix +
|
|
1009
|
+
i +
|
|
1010
|
+
'."guid" = t' +
|
|
1011
|
+
tokenTableSuffix +
|
|
1012
|
+
'0."guid" AND t' +
|
|
1013
|
+
tokenTableSuffix +
|
|
1014
|
+
i +
|
|
1015
|
+
'."name" = t' +
|
|
1016
|
+
tokenTableSuffix +
|
|
1017
|
+
'0."name" AND t' +
|
|
1018
|
+
tokenTableSuffix +
|
|
1019
|
+
i +
|
|
1020
|
+
'."position" = t' +
|
|
1021
|
+
tokenTableSuffix +
|
|
1022
|
+
'0."position" + ' +
|
|
1023
|
+
i,
|
|
1024
|
+
whereClause: 't' +
|
|
1025
|
+
tokenTableSuffix +
|
|
1026
|
+
i +
|
|
1027
|
+
'."token"=@' +
|
|
1028
|
+
value +
|
|
1029
|
+
(token.nostemmed
|
|
1030
|
+
? ' AND t' + tokenTableSuffix + i + '."stem"=0'
|
|
1031
|
+
: ''),
|
|
1032
|
+
};
|
|
1033
|
+
});
|
|
1034
|
+
return ('EXISTS (SELECT t' +
|
|
1035
|
+
tokenTableSuffix +
|
|
1036
|
+
'0."guid" ' +
|
|
1037
|
+
tokenParts.map((part) => part.fromClause).join(' ') +
|
|
1038
|
+
' WHERE t' +
|
|
1039
|
+
tokenTableSuffix +
|
|
1040
|
+
'0."guid"=' +
|
|
552
1041
|
ieTable +
|
|
553
|
-
'."guid"
|
|
554
|
-
|
|
555
|
-
'
|
|
1042
|
+
'."guid" AND t' +
|
|
1043
|
+
tokenTableSuffix +
|
|
1044
|
+
'0."name"=@' +
|
|
556
1045
|
name +
|
|
557
|
-
' AND
|
|
558
|
-
|
|
559
|
-
'))
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
1046
|
+
' AND ' +
|
|
1047
|
+
tokenParts.map((part) => part.whereClause).join(' AND ') +
|
|
1048
|
+
')');
|
|
1049
|
+
};
|
|
1050
|
+
const queryPartTerm = (term) => {
|
|
1051
|
+
if (term.type === 'series') {
|
|
1052
|
+
return queryPartSeries(term);
|
|
1053
|
+
}
|
|
1054
|
+
else if (term.type === 'not') {
|
|
1055
|
+
return 'NOT ' + queryPartTerm(term.operand);
|
|
1056
|
+
}
|
|
1057
|
+
else if (term.type === 'or') {
|
|
1058
|
+
let queryParts = [];
|
|
1059
|
+
for (let operand of term.operands) {
|
|
1060
|
+
queryParts.push(queryPartTerm(operand));
|
|
1061
|
+
}
|
|
1062
|
+
return '(' + queryParts.join(' OR ') + ')';
|
|
1063
|
+
}
|
|
1064
|
+
return queryPartToken(term);
|
|
1065
|
+
};
|
|
1066
|
+
// Run through the query and add terms.
|
|
1067
|
+
let termStrings = [];
|
|
1068
|
+
for (let term of parsedFTSQuery) {
|
|
1069
|
+
termStrings.push(queryPartTerm(term));
|
|
1070
|
+
}
|
|
563
1071
|
curQuery +=
|
|
564
|
-
(
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
name +
|
|
570
|
-
' AND instr("value", @' +
|
|
571
|
-
value +
|
|
572
|
-
'))';
|
|
1072
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1073
|
+
'(' +
|
|
1074
|
+
termStrings.join(' AND ') +
|
|
1075
|
+
')';
|
|
1076
|
+
params[name] = curValue[0];
|
|
573
1077
|
}
|
|
574
|
-
params[name] = curValue[0];
|
|
575
|
-
params[value] = svalue;
|
|
576
1078
|
}
|
|
577
1079
|
break;
|
|
578
1080
|
case 'match':
|
|
579
1081
|
case '!match':
|
|
580
|
-
if (curValue[0] === 'cdate'
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
'
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
')';
|
|
592
|
-
params[cdate] = curValue[1];
|
|
593
|
-
break;
|
|
594
|
-
}
|
|
595
|
-
else if (curValue[0] === 'mdate') {
|
|
1082
|
+
if (curValue[0] === 'cdate' ||
|
|
1083
|
+
curValue[0] === 'mdate' ||
|
|
1084
|
+
(this.nymph.tilmeld != null &&
|
|
1085
|
+
(curValue[0] === 'user' ||
|
|
1086
|
+
curValue[0] === 'group' ||
|
|
1087
|
+
curValue[0] === 'acUser' ||
|
|
1088
|
+
curValue[0] === 'acGroup' ||
|
|
1089
|
+
curValue[0] === 'acOther' ||
|
|
1090
|
+
curValue[0] === 'acRead' ||
|
|
1091
|
+
curValue[0] === 'acWrite' ||
|
|
1092
|
+
curValue[0] === 'acFull'))) {
|
|
596
1093
|
if (curQuery) {
|
|
597
1094
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
598
1095
|
}
|
|
599
|
-
const
|
|
1096
|
+
const value = `param${++count.i}`;
|
|
600
1097
|
curQuery +=
|
|
601
|
-
(
|
|
1098
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
602
1099
|
'(' +
|
|
603
1100
|
ieTable +
|
|
604
|
-
'.
|
|
605
|
-
|
|
1101
|
+
'.' +
|
|
1102
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1103
|
+
' REGEXP @' +
|
|
1104
|
+
value +
|
|
606
1105
|
')';
|
|
607
|
-
params[
|
|
608
|
-
break;
|
|
1106
|
+
params[value] = curValue[1];
|
|
609
1107
|
}
|
|
610
1108
|
else {
|
|
611
1109
|
if (curQuery) {
|
|
@@ -614,11 +1112,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
614
1112
|
const name = `param${++count.i}`;
|
|
615
1113
|
const value = `param${++count.i}`;
|
|
616
1114
|
curQuery +=
|
|
617
|
-
(
|
|
1115
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1116
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1117
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1118
|
+
' WHERE "guid"=' +
|
|
618
1119
|
ieTable +
|
|
619
|
-
'."guid"
|
|
620
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
621
|
-
' WHERE "name"=@' +
|
|
1120
|
+
'."guid" AND "name"=@' +
|
|
622
1121
|
name +
|
|
623
1122
|
' AND "string" REGEXP @' +
|
|
624
1123
|
value +
|
|
@@ -629,35 +1128,31 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
629
1128
|
break;
|
|
630
1129
|
case 'imatch':
|
|
631
1130
|
case '!imatch':
|
|
632
|
-
if (curValue[0] === 'cdate'
|
|
1131
|
+
if (curValue[0] === 'cdate' ||
|
|
1132
|
+
curValue[0] === 'mdate' ||
|
|
1133
|
+
(this.nymph.tilmeld != null &&
|
|
1134
|
+
(curValue[0] === 'user' ||
|
|
1135
|
+
curValue[0] === 'group' ||
|
|
1136
|
+
curValue[0] === 'acUser' ||
|
|
1137
|
+
curValue[0] === 'acGroup' ||
|
|
1138
|
+
curValue[0] === 'acOther' ||
|
|
1139
|
+
curValue[0] === 'acRead' ||
|
|
1140
|
+
curValue[0] === 'acWrite' ||
|
|
1141
|
+
curValue[0] === 'acFull'))) {
|
|
633
1142
|
if (curQuery) {
|
|
634
1143
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
635
1144
|
}
|
|
636
|
-
const
|
|
637
|
-
curQuery +=
|
|
638
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
639
|
-
'(' +
|
|
640
|
-
ieTable +
|
|
641
|
-
'."cdate" REGEXP @' +
|
|
642
|
-
cdate +
|
|
643
|
-
')';
|
|
644
|
-
params[cdate] = curValue[1];
|
|
645
|
-
break;
|
|
646
|
-
}
|
|
647
|
-
else if (curValue[0] === 'mdate') {
|
|
648
|
-
if (curQuery) {
|
|
649
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
650
|
-
}
|
|
651
|
-
const mdate = `param${++count.i}`;
|
|
1145
|
+
const value = `param${++count.i}`;
|
|
652
1146
|
curQuery +=
|
|
653
|
-
(
|
|
654
|
-
'(' +
|
|
1147
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1148
|
+
'(lower(' +
|
|
655
1149
|
ieTable +
|
|
656
|
-
'.
|
|
657
|
-
|
|
658
|
-
')'
|
|
659
|
-
|
|
660
|
-
|
|
1150
|
+
'.' +
|
|
1151
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1152
|
+
') REGEXP lower(@' +
|
|
1153
|
+
value +
|
|
1154
|
+
'))';
|
|
1155
|
+
params[value] = curValue[1];
|
|
661
1156
|
}
|
|
662
1157
|
else {
|
|
663
1158
|
if (curQuery) {
|
|
@@ -666,11 +1161,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
666
1161
|
const name = `param${++count.i}`;
|
|
667
1162
|
const value = `param${++count.i}`;
|
|
668
1163
|
curQuery +=
|
|
669
|
-
(
|
|
1164
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1165
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1166
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1167
|
+
' WHERE "guid"=' +
|
|
670
1168
|
ieTable +
|
|
671
|
-
'."guid"
|
|
672
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
673
|
-
' WHERE "name"=@' +
|
|
1169
|
+
'."guid" AND "name"=@' +
|
|
674
1170
|
name +
|
|
675
1171
|
' AND lower("string") REGEXP lower(@' +
|
|
676
1172
|
value +
|
|
@@ -681,35 +1177,31 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
681
1177
|
break;
|
|
682
1178
|
case 'like':
|
|
683
1179
|
case '!like':
|
|
684
|
-
if (curValue[0] === 'cdate'
|
|
1180
|
+
if (curValue[0] === 'cdate' ||
|
|
1181
|
+
curValue[0] === 'mdate' ||
|
|
1182
|
+
(this.nymph.tilmeld != null &&
|
|
1183
|
+
(curValue[0] === 'user' ||
|
|
1184
|
+
curValue[0] === 'group' ||
|
|
1185
|
+
curValue[0] === 'acUser' ||
|
|
1186
|
+
curValue[0] === 'acGroup' ||
|
|
1187
|
+
curValue[0] === 'acOther' ||
|
|
1188
|
+
curValue[0] === 'acRead' ||
|
|
1189
|
+
curValue[0] === 'acWrite' ||
|
|
1190
|
+
curValue[0] === 'acFull'))) {
|
|
685
1191
|
if (curQuery) {
|
|
686
1192
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
687
1193
|
}
|
|
688
|
-
const
|
|
689
|
-
curQuery +=
|
|
690
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
691
|
-
'(' +
|
|
692
|
-
ieTable +
|
|
693
|
-
'."cdate" LIKE @' +
|
|
694
|
-
cdate +
|
|
695
|
-
" ESCAPE '\\')";
|
|
696
|
-
params[cdate] = curValue[1];
|
|
697
|
-
break;
|
|
698
|
-
}
|
|
699
|
-
else if (curValue[0] === 'mdate') {
|
|
700
|
-
if (curQuery) {
|
|
701
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
702
|
-
}
|
|
703
|
-
const mdate = `param${++count.i}`;
|
|
1194
|
+
const value = `param${++count.i}`;
|
|
704
1195
|
curQuery +=
|
|
705
|
-
(
|
|
1196
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
706
1197
|
'(' +
|
|
707
1198
|
ieTable +
|
|
708
|
-
'.
|
|
709
|
-
|
|
1199
|
+
'.' +
|
|
1200
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1201
|
+
' LIKE @' +
|
|
1202
|
+
value +
|
|
710
1203
|
" ESCAPE '\\')";
|
|
711
|
-
params[
|
|
712
|
-
break;
|
|
1204
|
+
params[value] = curValue[1];
|
|
713
1205
|
}
|
|
714
1206
|
else {
|
|
715
1207
|
if (curQuery) {
|
|
@@ -718,11 +1210,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
718
1210
|
const name = `param${++count.i}`;
|
|
719
1211
|
const value = `param${++count.i}`;
|
|
720
1212
|
curQuery +=
|
|
721
|
-
(
|
|
1213
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1214
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1215
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1216
|
+
' WHERE "guid"=' +
|
|
722
1217
|
ieTable +
|
|
723
|
-
'."guid"
|
|
724
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
725
|
-
' WHERE "name"=@' +
|
|
1218
|
+
'."guid" AND "name"=@' +
|
|
726
1219
|
name +
|
|
727
1220
|
' AND "string" LIKE @' +
|
|
728
1221
|
value +
|
|
@@ -733,35 +1226,31 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
733
1226
|
break;
|
|
734
1227
|
case 'ilike':
|
|
735
1228
|
case '!ilike':
|
|
736
|
-
if (curValue[0] === 'cdate'
|
|
1229
|
+
if (curValue[0] === 'cdate' ||
|
|
1230
|
+
curValue[0] === 'mdate' ||
|
|
1231
|
+
(this.nymph.tilmeld != null &&
|
|
1232
|
+
(curValue[0] === 'user' ||
|
|
1233
|
+
curValue[0] === 'group' ||
|
|
1234
|
+
curValue[0] === 'acUser' ||
|
|
1235
|
+
curValue[0] === 'acGroup' ||
|
|
1236
|
+
curValue[0] === 'acOther' ||
|
|
1237
|
+
curValue[0] === 'acRead' ||
|
|
1238
|
+
curValue[0] === 'acWrite' ||
|
|
1239
|
+
curValue[0] === 'acFull'))) {
|
|
737
1240
|
if (curQuery) {
|
|
738
1241
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
739
1242
|
}
|
|
740
|
-
const
|
|
741
|
-
curQuery +=
|
|
742
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
743
|
-
'(' +
|
|
744
|
-
ieTable +
|
|
745
|
-
'."cdate" LIKE @' +
|
|
746
|
-
cdate +
|
|
747
|
-
" ESCAPE '\\')";
|
|
748
|
-
params[cdate] = curValue[1];
|
|
749
|
-
break;
|
|
750
|
-
}
|
|
751
|
-
else if (curValue[0] === 'mdate') {
|
|
752
|
-
if (curQuery) {
|
|
753
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
754
|
-
}
|
|
755
|
-
const mdate = `param${++count.i}`;
|
|
1243
|
+
const value = `param${++count.i}`;
|
|
756
1244
|
curQuery +=
|
|
757
|
-
(
|
|
758
|
-
'(' +
|
|
1245
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1246
|
+
'(lower(' +
|
|
759
1247
|
ieTable +
|
|
760
|
-
'.
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
1248
|
+
'.' +
|
|
1249
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1250
|
+
') LIKE lower(@' +
|
|
1251
|
+
value +
|
|
1252
|
+
") ESCAPE '\\')";
|
|
1253
|
+
params[value] = curValue[1];
|
|
765
1254
|
}
|
|
766
1255
|
else {
|
|
767
1256
|
if (curQuery) {
|
|
@@ -770,11 +1259,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
770
1259
|
const name = `param${++count.i}`;
|
|
771
1260
|
const value = `param${++count.i}`;
|
|
772
1261
|
curQuery +=
|
|
773
|
-
(
|
|
1262
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1263
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1264
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1265
|
+
' WHERE "guid"=' +
|
|
774
1266
|
ieTable +
|
|
775
|
-
'."guid"
|
|
776
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
777
|
-
' WHERE "name"=@' +
|
|
1267
|
+
'."guid" AND "name"=@' +
|
|
778
1268
|
name +
|
|
779
1269
|
' AND lower("string") LIKE lower(@' +
|
|
780
1270
|
value +
|
|
@@ -785,31 +1275,29 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
785
1275
|
break;
|
|
786
1276
|
case 'gt':
|
|
787
1277
|
case '!gt':
|
|
788
|
-
if (curValue[0] === 'cdate'
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
'
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
break;
|
|
800
|
-
}
|
|
801
|
-
else if (curValue[0] === 'mdate') {
|
|
1278
|
+
if (curValue[0] === 'cdate' ||
|
|
1279
|
+
curValue[0] === 'mdate' ||
|
|
1280
|
+
(this.nymph.tilmeld != null &&
|
|
1281
|
+
(curValue[0] === 'user' ||
|
|
1282
|
+
curValue[0] === 'group' ||
|
|
1283
|
+
curValue[0] === 'acUser' ||
|
|
1284
|
+
curValue[0] === 'acGroup' ||
|
|
1285
|
+
curValue[0] === 'acOther' ||
|
|
1286
|
+
curValue[0] === 'acRead' ||
|
|
1287
|
+
curValue[0] === 'acWrite' ||
|
|
1288
|
+
curValue[0] === 'acFull'))) {
|
|
802
1289
|
if (curQuery) {
|
|
803
1290
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
804
1291
|
}
|
|
805
|
-
const
|
|
1292
|
+
const value = `param${++count.i}`;
|
|
806
1293
|
curQuery +=
|
|
807
|
-
(
|
|
1294
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
808
1295
|
ieTable +
|
|
809
|
-
'.
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1296
|
+
'.' +
|
|
1297
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1298
|
+
'>@' +
|
|
1299
|
+
value;
|
|
1300
|
+
params[value] = Number(curValue[1]);
|
|
813
1301
|
}
|
|
814
1302
|
else {
|
|
815
1303
|
if (curQuery) {
|
|
@@ -818,11 +1306,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
818
1306
|
const name = `param${++count.i}`;
|
|
819
1307
|
const value = `param${++count.i}`;
|
|
820
1308
|
curQuery +=
|
|
821
|
-
(
|
|
1309
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1310
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1311
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1312
|
+
' WHERE "guid"=' +
|
|
822
1313
|
ieTable +
|
|
823
|
-
'."guid"
|
|
824
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
825
|
-
' WHERE "name"=@' +
|
|
1314
|
+
'."guid" AND "name"=@' +
|
|
826
1315
|
name +
|
|
827
1316
|
' AND "number">@' +
|
|
828
1317
|
value +
|
|
@@ -833,31 +1322,29 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
833
1322
|
break;
|
|
834
1323
|
case 'gte':
|
|
835
1324
|
case '!gte':
|
|
836
|
-
if (curValue[0] === 'cdate'
|
|
1325
|
+
if (curValue[0] === 'cdate' ||
|
|
1326
|
+
curValue[0] === 'mdate' ||
|
|
1327
|
+
(this.nymph.tilmeld != null &&
|
|
1328
|
+
(curValue[0] === 'user' ||
|
|
1329
|
+
curValue[0] === 'group' ||
|
|
1330
|
+
curValue[0] === 'acUser' ||
|
|
1331
|
+
curValue[0] === 'acGroup' ||
|
|
1332
|
+
curValue[0] === 'acOther' ||
|
|
1333
|
+
curValue[0] === 'acRead' ||
|
|
1334
|
+
curValue[0] === 'acWrite' ||
|
|
1335
|
+
curValue[0] === 'acFull'))) {
|
|
837
1336
|
if (curQuery) {
|
|
838
1337
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
839
1338
|
}
|
|
840
|
-
const
|
|
841
|
-
curQuery +=
|
|
842
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
843
|
-
ieTable +
|
|
844
|
-
'."cdate">=@' +
|
|
845
|
-
cdate;
|
|
846
|
-
params[cdate] = Number(curValue[1]);
|
|
847
|
-
break;
|
|
848
|
-
}
|
|
849
|
-
else if (curValue[0] === 'mdate') {
|
|
850
|
-
if (curQuery) {
|
|
851
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
852
|
-
}
|
|
853
|
-
const mdate = `param${++count.i}`;
|
|
1339
|
+
const value = `param${++count.i}`;
|
|
854
1340
|
curQuery +=
|
|
855
|
-
(
|
|
1341
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
856
1342
|
ieTable +
|
|
857
|
-
'.
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
1343
|
+
'.' +
|
|
1344
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1345
|
+
'>=@' +
|
|
1346
|
+
value;
|
|
1347
|
+
params[value] = Number(curValue[1]);
|
|
861
1348
|
}
|
|
862
1349
|
else {
|
|
863
1350
|
if (curQuery) {
|
|
@@ -866,11 +1353,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
866
1353
|
const name = `param${++count.i}`;
|
|
867
1354
|
const value = `param${++count.i}`;
|
|
868
1355
|
curQuery +=
|
|
869
|
-
(
|
|
1356
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1357
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1358
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1359
|
+
' WHERE "guid"=' +
|
|
870
1360
|
ieTable +
|
|
871
|
-
'."guid"
|
|
872
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
873
|
-
' WHERE "name"=@' +
|
|
1361
|
+
'."guid" AND "name"=@' +
|
|
874
1362
|
name +
|
|
875
1363
|
' AND "number">=@' +
|
|
876
1364
|
value +
|
|
@@ -881,31 +1369,29 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
881
1369
|
break;
|
|
882
1370
|
case 'lt':
|
|
883
1371
|
case '!lt':
|
|
884
|
-
if (curValue[0] === 'cdate'
|
|
1372
|
+
if (curValue[0] === 'cdate' ||
|
|
1373
|
+
curValue[0] === 'mdate' ||
|
|
1374
|
+
(this.nymph.tilmeld != null &&
|
|
1375
|
+
(curValue[0] === 'user' ||
|
|
1376
|
+
curValue[0] === 'group' ||
|
|
1377
|
+
curValue[0] === 'acUser' ||
|
|
1378
|
+
curValue[0] === 'acGroup' ||
|
|
1379
|
+
curValue[0] === 'acOther' ||
|
|
1380
|
+
curValue[0] === 'acRead' ||
|
|
1381
|
+
curValue[0] === 'acWrite' ||
|
|
1382
|
+
curValue[0] === 'acFull'))) {
|
|
885
1383
|
if (curQuery) {
|
|
886
1384
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
887
1385
|
}
|
|
888
|
-
const
|
|
889
|
-
curQuery +=
|
|
890
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
891
|
-
ieTable +
|
|
892
|
-
'."cdate"<@' +
|
|
893
|
-
cdate;
|
|
894
|
-
params[cdate] = Number(curValue[1]);
|
|
895
|
-
break;
|
|
896
|
-
}
|
|
897
|
-
else if (curValue[0] === 'mdate') {
|
|
898
|
-
if (curQuery) {
|
|
899
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
900
|
-
}
|
|
901
|
-
const mdate = `param${++count.i}`;
|
|
1386
|
+
const value = `param${++count.i}`;
|
|
902
1387
|
curQuery +=
|
|
903
|
-
(
|
|
1388
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
904
1389
|
ieTable +
|
|
905
|
-
'.
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1390
|
+
'.' +
|
|
1391
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1392
|
+
'<@' +
|
|
1393
|
+
value;
|
|
1394
|
+
params[value] = Number(curValue[1]);
|
|
909
1395
|
}
|
|
910
1396
|
else {
|
|
911
1397
|
if (curQuery) {
|
|
@@ -914,11 +1400,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
914
1400
|
const name = `param${++count.i}`;
|
|
915
1401
|
const value = `param${++count.i}`;
|
|
916
1402
|
curQuery +=
|
|
917
|
-
(
|
|
1403
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1404
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1405
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1406
|
+
' WHERE "guid"=' +
|
|
918
1407
|
ieTable +
|
|
919
|
-
'."guid"
|
|
920
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
921
|
-
' WHERE "name"=@' +
|
|
1408
|
+
'."guid" AND "name"=@' +
|
|
922
1409
|
name +
|
|
923
1410
|
' AND "number"<@' +
|
|
924
1411
|
value +
|
|
@@ -929,31 +1416,29 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
929
1416
|
break;
|
|
930
1417
|
case 'lte':
|
|
931
1418
|
case '!lte':
|
|
932
|
-
if (curValue[0] === 'cdate'
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
'
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
break;
|
|
944
|
-
}
|
|
945
|
-
else if (curValue[0] === 'mdate') {
|
|
1419
|
+
if (curValue[0] === 'cdate' ||
|
|
1420
|
+
curValue[0] === 'mdate' ||
|
|
1421
|
+
(this.nymph.tilmeld != null &&
|
|
1422
|
+
(curValue[0] === 'user' ||
|
|
1423
|
+
curValue[0] === 'group' ||
|
|
1424
|
+
curValue[0] === 'acUser' ||
|
|
1425
|
+
curValue[0] === 'acGroup' ||
|
|
1426
|
+
curValue[0] === 'acOther' ||
|
|
1427
|
+
curValue[0] === 'acRead' ||
|
|
1428
|
+
curValue[0] === 'acWrite' ||
|
|
1429
|
+
curValue[0] === 'acFull'))) {
|
|
946
1430
|
if (curQuery) {
|
|
947
1431
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
948
1432
|
}
|
|
949
|
-
const
|
|
1433
|
+
const value = `param${++count.i}`;
|
|
950
1434
|
curQuery +=
|
|
951
|
-
(
|
|
1435
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
952
1436
|
ieTable +
|
|
953
|
-
'.
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1437
|
+
'.' +
|
|
1438
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1439
|
+
'<=@' +
|
|
1440
|
+
value;
|
|
1441
|
+
params[value] = Number(curValue[1]);
|
|
957
1442
|
}
|
|
958
1443
|
else {
|
|
959
1444
|
if (curQuery) {
|
|
@@ -962,11 +1447,12 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
962
1447
|
const name = `param${++count.i}`;
|
|
963
1448
|
const value = `param${++count.i}`;
|
|
964
1449
|
curQuery +=
|
|
965
|
-
(
|
|
1450
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1451
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1452
|
+
SQLite3Driver.escape(this.prefix + 'data_' + etype) +
|
|
1453
|
+
' WHERE "guid"=' +
|
|
966
1454
|
ieTable +
|
|
967
|
-
'."guid"
|
|
968
|
-
SQLite3Driver.escape(this.prefix + 'comparisons_' + etype) +
|
|
969
|
-
' WHERE "name"=@' +
|
|
1455
|
+
'."guid" AND "name"=@' +
|
|
970
1456
|
name +
|
|
971
1457
|
' AND "number"<=@' +
|
|
972
1458
|
value +
|
|
@@ -990,71 +1476,205 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
990
1476
|
if (curQuery) {
|
|
991
1477
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
992
1478
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1479
|
+
if (this.nymph.tilmeld != null &&
|
|
1480
|
+
(curValue[0] === 'user' || curValue[0] === 'group')) {
|
|
1481
|
+
const guid = `param${++count.i}`;
|
|
1482
|
+
curQuery +=
|
|
1483
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1484
|
+
ieTable +
|
|
1485
|
+
'.' +
|
|
1486
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1487
|
+
'=@' +
|
|
1488
|
+
guid;
|
|
1489
|
+
params[guid] = curQguid;
|
|
1490
|
+
}
|
|
1491
|
+
else if (this.nymph.tilmeld != null &&
|
|
1492
|
+
(curValue[0] === 'acRead' ||
|
|
1493
|
+
curValue[0] === 'acWrite' ||
|
|
1494
|
+
curValue[0] === 'acFull')) {
|
|
1495
|
+
const guid = `param${++count.i}`;
|
|
1496
|
+
curQuery +=
|
|
1497
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1498
|
+
ieTable +
|
|
1499
|
+
'.' +
|
|
1500
|
+
SQLite3Driver.escape(curValue[0]) +
|
|
1501
|
+
' LIKE @' +
|
|
1502
|
+
guid +
|
|
1503
|
+
" ESCAPE '\\'";
|
|
1504
|
+
params[guid] =
|
|
1505
|
+
'%,' +
|
|
1506
|
+
curQguid
|
|
1507
|
+
.replace('\\', '\\\\')
|
|
1508
|
+
.replace('%', '\\%')
|
|
1509
|
+
.replace('_', '\\_') +
|
|
1510
|
+
',%';
|
|
1511
|
+
}
|
|
1512
|
+
else {
|
|
1513
|
+
const name = `param${++count.i}`;
|
|
1514
|
+
const guid = `param${++count.i}`;
|
|
1515
|
+
curQuery +=
|
|
1516
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1517
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1518
|
+
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
1519
|
+
' WHERE "guid"=' +
|
|
1520
|
+
ieTable +
|
|
1521
|
+
'."guid" AND "name"=@' +
|
|
1522
|
+
name +
|
|
1523
|
+
' AND "reference"=@' +
|
|
1524
|
+
guid +
|
|
1525
|
+
')';
|
|
1526
|
+
params[name] = curValue[0];
|
|
1527
|
+
params[guid] = curQguid;
|
|
1528
|
+
}
|
|
1007
1529
|
break;
|
|
1008
1530
|
case 'selector':
|
|
1009
1531
|
case '!selector':
|
|
1010
|
-
const
|
|
1532
|
+
const innerquery = this.makeEntityQuery({ ...options, sort: null, limit: undefined }, [curValue], etype, count, params, true, tableSuffix, etypes);
|
|
1011
1533
|
if (curQuery) {
|
|
1012
1534
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1013
1535
|
}
|
|
1014
1536
|
curQuery +=
|
|
1015
|
-
(
|
|
1537
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1016
1538
|
'(' +
|
|
1017
|
-
|
|
1539
|
+
innerquery.query +
|
|
1018
1540
|
')';
|
|
1019
1541
|
break;
|
|
1020
1542
|
case 'qref':
|
|
1021
1543
|
case '!qref':
|
|
1544
|
+
const referenceTableSuffix = makeTableSuffix();
|
|
1022
1545
|
const [qrefOptions, ...qrefSelectors] = curValue[1];
|
|
1023
1546
|
const QrefEntityClass = qrefOptions.class;
|
|
1024
1547
|
etypes.push(QrefEntityClass.ETYPE);
|
|
1025
|
-
const qrefQuery = this.makeEntityQuery({ ...qrefOptions, return: 'guid', class: QrefEntityClass }, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, (0, guid_1.makeTableSuffix)(), etypes);
|
|
1026
1548
|
if (curQuery) {
|
|
1027
1549
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1028
1550
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1551
|
+
if (this.nymph.tilmeld != null &&
|
|
1552
|
+
(curValue[0] === 'user' || curValue[0] === 'group')) {
|
|
1553
|
+
const qrefQuery = this.makeEntityQuery({
|
|
1554
|
+
...qrefOptions,
|
|
1555
|
+
sort: qrefOptions.sort ?? null,
|
|
1556
|
+
return: 'guid',
|
|
1557
|
+
class: QrefEntityClass,
|
|
1558
|
+
}, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes, 'r' +
|
|
1559
|
+
referenceTableSuffix +
|
|
1560
|
+
'.' +
|
|
1561
|
+
SQLite3Driver.escape(curValue[0]));
|
|
1562
|
+
curQuery +=
|
|
1563
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1564
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1565
|
+
SQLite3Driver.escape(this.prefix + 'entities_' + etype) +
|
|
1566
|
+
' r' +
|
|
1567
|
+
referenceTableSuffix +
|
|
1568
|
+
' WHERE r' +
|
|
1569
|
+
referenceTableSuffix +
|
|
1570
|
+
'."guid"=' +
|
|
1571
|
+
ieTable +
|
|
1572
|
+
'."guid" AND EXISTS (' +
|
|
1573
|
+
qrefQuery.query +
|
|
1574
|
+
'))';
|
|
1575
|
+
}
|
|
1576
|
+
else if (this.nymph.tilmeld != null &&
|
|
1577
|
+
(curValue[0] === 'acRead' ||
|
|
1578
|
+
curValue[0] === 'acWrite' ||
|
|
1579
|
+
curValue[0] === 'acFull')) {
|
|
1580
|
+
const qrefQuery = this.makeEntityQuery({
|
|
1581
|
+
...qrefOptions,
|
|
1582
|
+
sort: qrefOptions.sort ?? null,
|
|
1583
|
+
return: 'guid',
|
|
1584
|
+
class: QrefEntityClass,
|
|
1585
|
+
}, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes, 'r' + referenceTableSuffix + '."ref"');
|
|
1586
|
+
const splitTableSuffix = makeTableSuffix();
|
|
1587
|
+
curQuery +=
|
|
1588
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1589
|
+
`EXISTS (SELECT "guid", "ref" FROM (
|
|
1590
|
+
WITH RECURSIVE "spl${splitTableSuffix}" AS (
|
|
1591
|
+
SELECT
|
|
1592
|
+
"guid",
|
|
1593
|
+
SUBSTR(${SQLite3Driver.escape(curValue[0])}, 1, INSTR(${SQLite3Driver.escape(curValue[0])}, ',') - 1) AS "ref",
|
|
1594
|
+
SUBSTR(${SQLite3Driver.escape(curValue[0])}, INSTR(${SQLite3Driver.escape(curValue[0])}, ',') + 1) AS "remainder"
|
|
1595
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)}
|
|
1596
|
+
UNION ALL
|
|
1597
|
+
SELECT
|
|
1598
|
+
"guid",
|
|
1599
|
+
SUBSTR("remainder", 1, INSTR("remainder", ',') - 1) AS "ref",
|
|
1600
|
+
SUBSTR("remainder", INSTR("remainder", ',') + 1) AS "remainder"
|
|
1601
|
+
FROM "spl${splitTableSuffix}" WHERE "remainder" != ''
|
|
1602
|
+
)
|
|
1603
|
+
SELECT "guid", "ref" FROM "spl${splitTableSuffix}" WHERE "ref" != ''
|
|
1604
|
+
) ` +
|
|
1605
|
+
' r' +
|
|
1606
|
+
referenceTableSuffix +
|
|
1607
|
+
' WHERE r' +
|
|
1608
|
+
referenceTableSuffix +
|
|
1609
|
+
'."guid"=' +
|
|
1610
|
+
ieTable +
|
|
1611
|
+
'."guid" AND EXISTS (' +
|
|
1612
|
+
qrefQuery.query +
|
|
1613
|
+
'))';
|
|
1614
|
+
}
|
|
1615
|
+
else {
|
|
1616
|
+
const qrefQuery = this.makeEntityQuery({
|
|
1617
|
+
...qrefOptions,
|
|
1618
|
+
sort: qrefOptions.sort ?? null,
|
|
1619
|
+
return: 'guid',
|
|
1620
|
+
class: QrefEntityClass,
|
|
1621
|
+
}, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes, 'r' + referenceTableSuffix + '."reference"');
|
|
1622
|
+
const qrefName = `param${++count.i}`;
|
|
1623
|
+
curQuery +=
|
|
1624
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1625
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1626
|
+
SQLite3Driver.escape(this.prefix + 'references_' + etype) +
|
|
1627
|
+
' r' +
|
|
1628
|
+
referenceTableSuffix +
|
|
1629
|
+
' WHERE r' +
|
|
1630
|
+
referenceTableSuffix +
|
|
1631
|
+
'."guid"=' +
|
|
1632
|
+
ieTable +
|
|
1633
|
+
'."guid" AND r' +
|
|
1634
|
+
referenceTableSuffix +
|
|
1635
|
+
'."name"=@' +
|
|
1636
|
+
qrefName +
|
|
1637
|
+
' AND EXISTS (' +
|
|
1638
|
+
qrefQuery.query +
|
|
1639
|
+
'))';
|
|
1640
|
+
params[qrefName] = curValue[0];
|
|
1641
|
+
}
|
|
1041
1642
|
break;
|
|
1042
1643
|
}
|
|
1043
1644
|
}
|
|
1044
1645
|
return curQuery;
|
|
1045
1646
|
});
|
|
1046
1647
|
let sortBy;
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1648
|
+
let sortByInner;
|
|
1649
|
+
let sortJoin = '';
|
|
1650
|
+
const order = options.reverse ? ' DESC' : '';
|
|
1651
|
+
if (sort == null) {
|
|
1652
|
+
sortBy = '';
|
|
1653
|
+
sortByInner = '';
|
|
1654
|
+
}
|
|
1655
|
+
else {
|
|
1656
|
+
switch (sort) {
|
|
1657
|
+
case 'mdate':
|
|
1658
|
+
sortBy = `ORDER BY ${eTable}."mdate"${order}`;
|
|
1659
|
+
sortByInner = `ORDER BY ${ieTable}."mdate"${order}`;
|
|
1660
|
+
break;
|
|
1661
|
+
case 'cdate':
|
|
1662
|
+
sortBy = `ORDER BY ${eTable}."cdate"${order}`;
|
|
1663
|
+
sortByInner = `ORDER BY ${ieTable}."cdate"${order}`;
|
|
1664
|
+
break;
|
|
1665
|
+
default:
|
|
1666
|
+
const name = `param${++count.i}`;
|
|
1667
|
+
sortJoin = `LEFT JOIN (
|
|
1668
|
+
SELECT "guid", "string", "number"
|
|
1669
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'data_' + etype)}
|
|
1670
|
+
WHERE "name"=@${name}
|
|
1671
|
+
ORDER BY "number"${order}, "string"${order}
|
|
1672
|
+
) ${sTable} USING ("guid")`;
|
|
1673
|
+
sortBy = `ORDER BY ${sTable}."number"${order}, ${sTable}."string"${order}`;
|
|
1674
|
+
sortByInner = sortBy;
|
|
1675
|
+
params[name] = sort;
|
|
1676
|
+
break;
|
|
1677
|
+
}
|
|
1058
1678
|
}
|
|
1059
1679
|
let query;
|
|
1060
1680
|
if (queryParts.length) {
|
|
@@ -1071,25 +1691,29 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1071
1691
|
offset = ` OFFSET ${Math.floor(Number(options.offset))}`;
|
|
1072
1692
|
}
|
|
1073
1693
|
const whereClause = queryParts.join(') AND (');
|
|
1694
|
+
const guidClause = guidSelector
|
|
1695
|
+
? `${ieTable}."guid"=${guidSelector} AND `
|
|
1696
|
+
: '';
|
|
1074
1697
|
if (options.return === 'count') {
|
|
1075
1698
|
if (limit || offset) {
|
|
1076
1699
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1077
1700
|
SELECT "guid"
|
|
1078
1701
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1079
|
-
WHERE (${whereClause})${limit}${offset}
|
|
1702
|
+
WHERE ${guidClause}(${whereClause})${limit}${offset}
|
|
1080
1703
|
)`;
|
|
1081
1704
|
}
|
|
1082
1705
|
else {
|
|
1083
1706
|
query = `SELECT COUNT("guid") AS "count"
|
|
1084
1707
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1085
|
-
WHERE (${whereClause})`;
|
|
1708
|
+
WHERE ${guidClause}(${whereClause})`;
|
|
1086
1709
|
}
|
|
1087
1710
|
}
|
|
1088
1711
|
else if (options.return === 'guid') {
|
|
1089
1712
|
query = `SELECT "guid"
|
|
1090
1713
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1091
|
-
|
|
1092
|
-
|
|
1714
|
+
${sortJoin}
|
|
1715
|
+
WHERE ${guidClause}(${whereClause})
|
|
1716
|
+
${sortByInner ? sortByInner + ', ' : 'ORDER BY '}"guid"${limit}${offset}`;
|
|
1093
1717
|
}
|
|
1094
1718
|
else {
|
|
1095
1719
|
query = `SELECT
|
|
@@ -1097,20 +1721,30 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1097
1721
|
${eTable}."tags",
|
|
1098
1722
|
${eTable}."cdate",
|
|
1099
1723
|
${eTable}."mdate",
|
|
1724
|
+
${eTable}."user",
|
|
1725
|
+
${eTable}."group",
|
|
1726
|
+
${eTable}."acUser",
|
|
1727
|
+
${eTable}."acGroup",
|
|
1728
|
+
${eTable}."acOther",
|
|
1729
|
+
${eTable}."acRead",
|
|
1730
|
+
${eTable}."acWrite",
|
|
1731
|
+
${eTable}."acFull",
|
|
1100
1732
|
${dTable}."name",
|
|
1101
1733
|
${dTable}."value",
|
|
1102
|
-
${
|
|
1103
|
-
${
|
|
1734
|
+
json(${dTable}."json") as "json",
|
|
1735
|
+
${dTable}."string",
|
|
1736
|
+
${dTable}."number"
|
|
1104
1737
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${eTable}
|
|
1105
1738
|
LEFT JOIN ${SQLite3Driver.escape(this.prefix + 'data_' + etype)} ${dTable} USING ("guid")
|
|
1106
|
-
|
|
1739
|
+
${sortJoin}
|
|
1107
1740
|
INNER JOIN (
|
|
1108
1741
|
SELECT "guid"
|
|
1109
1742
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1110
|
-
|
|
1111
|
-
|
|
1743
|
+
${sortJoin}
|
|
1744
|
+
WHERE ${guidClause}(${whereClause})
|
|
1745
|
+
${sortByInner}${limit}${offset}
|
|
1112
1746
|
) ${fTable} USING ("guid")
|
|
1113
|
-
ORDER BY ${eTable}
|
|
1747
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}."guid"`;
|
|
1114
1748
|
}
|
|
1115
1749
|
}
|
|
1116
1750
|
}
|
|
@@ -1127,22 +1761,27 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1127
1761
|
if ('offset' in options) {
|
|
1128
1762
|
offset = ` OFFSET ${Math.floor(Number(options.offset))}`;
|
|
1129
1763
|
}
|
|
1764
|
+
const guidClause = guidSelector
|
|
1765
|
+
? ` WHERE ${ieTable}."guid"=${guidSelector}`
|
|
1766
|
+
: '';
|
|
1130
1767
|
if (options.return === 'count') {
|
|
1131
1768
|
if (limit || offset) {
|
|
1132
1769
|
query = `SELECT COUNT("guid") AS "count" FROM (
|
|
1133
1770
|
SELECT "guid"
|
|
1134
|
-
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}${limit}${offset}
|
|
1771
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}${guidClause}${limit}${offset}
|
|
1135
1772
|
)`;
|
|
1136
1773
|
}
|
|
1137
1774
|
else {
|
|
1138
1775
|
query = `SELECT COUNT("guid") AS "count"
|
|
1139
|
-
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}`;
|
|
1776
|
+
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}${guidClause}`;
|
|
1140
1777
|
}
|
|
1141
1778
|
}
|
|
1142
1779
|
else if (options.return === 'guid') {
|
|
1143
1780
|
query = `SELECT "guid"
|
|
1144
1781
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1145
|
-
|
|
1782
|
+
${sortJoin}
|
|
1783
|
+
${guidClause}
|
|
1784
|
+
${sortByInner ? sortByInner + ', ' : 'ORDER BY '}"guid"${limit}${offset}`;
|
|
1146
1785
|
}
|
|
1147
1786
|
else {
|
|
1148
1787
|
if (limit || offset) {
|
|
@@ -1151,19 +1790,30 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1151
1790
|
${eTable}."tags",
|
|
1152
1791
|
${eTable}."cdate",
|
|
1153
1792
|
${eTable}."mdate",
|
|
1793
|
+
${eTable}."user",
|
|
1794
|
+
${eTable}."group",
|
|
1795
|
+
${eTable}."acUser",
|
|
1796
|
+
${eTable}."acGroup",
|
|
1797
|
+
${eTable}."acOther",
|
|
1798
|
+
${eTable}."acRead",
|
|
1799
|
+
${eTable}."acWrite",
|
|
1800
|
+
${eTable}."acFull",
|
|
1154
1801
|
${dTable}."name",
|
|
1155
1802
|
${dTable}."value",
|
|
1156
|
-
${
|
|
1157
|
-
${
|
|
1803
|
+
json(${dTable}."json") as "json",
|
|
1804
|
+
${dTable}."string",
|
|
1805
|
+
${dTable}."number"
|
|
1158
1806
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${eTable}
|
|
1159
1807
|
LEFT JOIN ${SQLite3Driver.escape(this.prefix + 'data_' + etype)} ${dTable} USING ("guid")
|
|
1160
|
-
|
|
1808
|
+
${sortJoin}
|
|
1161
1809
|
INNER JOIN (
|
|
1162
1810
|
SELECT "guid"
|
|
1163
1811
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${ieTable}
|
|
1164
|
-
|
|
1812
|
+
${sortJoin}
|
|
1813
|
+
${guidClause}
|
|
1814
|
+
${sortByInner}${limit}${offset}
|
|
1165
1815
|
) ${fTable} USING ("guid")
|
|
1166
|
-
ORDER BY ${eTable}
|
|
1816
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}."guid"`;
|
|
1167
1817
|
}
|
|
1168
1818
|
else {
|
|
1169
1819
|
query = `SELECT
|
|
@@ -1171,14 +1821,24 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1171
1821
|
${eTable}."tags",
|
|
1172
1822
|
${eTable}."cdate",
|
|
1173
1823
|
${eTable}."mdate",
|
|
1824
|
+
${eTable}."user",
|
|
1825
|
+
${eTable}."group",
|
|
1826
|
+
${eTable}."acUser",
|
|
1827
|
+
${eTable}."acGroup",
|
|
1828
|
+
${eTable}."acOther",
|
|
1829
|
+
${eTable}."acRead",
|
|
1830
|
+
${eTable}."acWrite",
|
|
1831
|
+
${eTable}."acFull",
|
|
1174
1832
|
${dTable}."name",
|
|
1175
1833
|
${dTable}."value",
|
|
1176
|
-
${
|
|
1177
|
-
${
|
|
1834
|
+
json(${dTable}."json") as "json",
|
|
1835
|
+
${dTable}."string",
|
|
1836
|
+
${dTable}."number"
|
|
1178
1837
|
FROM ${SQLite3Driver.escape(this.prefix + 'entities_' + etype)} ${eTable}
|
|
1179
1838
|
LEFT JOIN ${SQLite3Driver.escape(this.prefix + 'data_' + etype)} ${dTable} USING ("guid")
|
|
1180
|
-
|
|
1181
|
-
|
|
1839
|
+
${sortJoin}
|
|
1840
|
+
${guidSelector ? `WHERE ${eTable}."guid"=${guidSelector}` : ''}
|
|
1841
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}."guid"`;
|
|
1182
1842
|
}
|
|
1183
1843
|
}
|
|
1184
1844
|
}
|
|
@@ -1194,29 +1854,41 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1194
1854
|
}
|
|
1195
1855
|
performQuery(options, formattedSelectors, etype) {
|
|
1196
1856
|
const { query, params, etypes } = this.makeEntityQuery(options, formattedSelectors, etype);
|
|
1197
|
-
const result = this.
|
|
1857
|
+
const result = this.queryArray(query, { etypes, params })[Symbol.iterator]();
|
|
1198
1858
|
return {
|
|
1199
1859
|
result,
|
|
1200
1860
|
};
|
|
1201
1861
|
}
|
|
1202
1862
|
async getEntities(options = {}, ...selectors) {
|
|
1203
|
-
|
|
1204
|
-
}
|
|
1205
|
-
getEntitiesSync(options = {}, ...selectors) {
|
|
1206
|
-
const { result, process } = this.getEntitesRowLike(options, selectors, (options, formattedSelectors, etype) => this.performQuery(options, formattedSelectors, etype), () => {
|
|
1863
|
+
const { result, process } = this.getEntitiesRowLike(options, selectors, ({ options, selectors, etype }) => this.performQuery(options, selectors, etype), () => {
|
|
1207
1864
|
const next = result.next();
|
|
1208
1865
|
return next.done ? null : next.value;
|
|
1209
1866
|
}, () => undefined, (row) => Number(row.count), (row) => row.guid, (row) => ({
|
|
1210
|
-
tags: row.tags.length > 2
|
|
1867
|
+
tags: row.tags.length > 2
|
|
1868
|
+
? row.tags
|
|
1869
|
+
.slice(1, -1)
|
|
1870
|
+
.split(',')
|
|
1871
|
+
.filter((tag) => tag)
|
|
1872
|
+
: [],
|
|
1211
1873
|
cdate: Number(row.cdate),
|
|
1212
1874
|
mdate: Number(row.mdate),
|
|
1875
|
+
user: row.user,
|
|
1876
|
+
group: row.group,
|
|
1877
|
+
acUser: row.acUser,
|
|
1878
|
+
acGroup: row.acGroup,
|
|
1879
|
+
acOther: row.acOther,
|
|
1880
|
+
acRead: row.acRead?.slice(1, -1).split(',') ?? [],
|
|
1881
|
+
acWrite: row.acWrite?.slice(1, -1).split(',') ?? [],
|
|
1882
|
+
acFull: row.acFull?.slice(1, -1).split(',') ?? [],
|
|
1213
1883
|
}), (row) => ({
|
|
1214
1884
|
name: row.name,
|
|
1215
1885
|
svalue: row.value === 'N'
|
|
1216
1886
|
? JSON.stringify(row.number)
|
|
1217
1887
|
: row.value === 'S'
|
|
1218
1888
|
? JSON.stringify(row.string)
|
|
1219
|
-
: row.value
|
|
1889
|
+
: row.value === 'J'
|
|
1890
|
+
? row.json
|
|
1891
|
+
: row.value,
|
|
1220
1892
|
}));
|
|
1221
1893
|
const value = process();
|
|
1222
1894
|
if (value instanceof Error) {
|
|
@@ -1226,7 +1898,7 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1226
1898
|
}
|
|
1227
1899
|
async getUID(name) {
|
|
1228
1900
|
if (name == null) {
|
|
1229
|
-
throw new
|
|
1901
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1230
1902
|
}
|
|
1231
1903
|
const result = this.queryGet(`SELECT "cur_uid" FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
1232
1904
|
params: {
|
|
@@ -1235,10 +1907,18 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1235
1907
|
});
|
|
1236
1908
|
return result?.cur_uid ?? null;
|
|
1237
1909
|
}
|
|
1238
|
-
async
|
|
1239
|
-
this.
|
|
1910
|
+
async importEntity(entity) {
|
|
1911
|
+
return await this.importEntityInternal(entity);
|
|
1912
|
+
}
|
|
1913
|
+
async importEntityTokens(entity) {
|
|
1914
|
+
return await this.importEntityInternal(entity, { only: 'tokens' });
|
|
1915
|
+
}
|
|
1916
|
+
async importEntityTilmeldAC(entity) {
|
|
1917
|
+
return await this.importEntityInternal(entity, { only: 'tilmeldAC' });
|
|
1918
|
+
}
|
|
1919
|
+
async importEntityInternal({ guid, cdate, mdate, tags, sdata, etype, }, { only = undefined } = {}) {
|
|
1240
1920
|
try {
|
|
1241
|
-
|
|
1921
|
+
if (only == null) {
|
|
1242
1922
|
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1243
1923
|
etypes: [etype],
|
|
1244
1924
|
params: {
|
|
@@ -1251,29 +1931,48 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1251
1931
|
guid,
|
|
1252
1932
|
},
|
|
1253
1933
|
});
|
|
1254
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
1934
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1255
1935
|
etypes: [etype],
|
|
1256
1936
|
params: {
|
|
1257
1937
|
guid,
|
|
1258
1938
|
},
|
|
1259
1939
|
});
|
|
1260
|
-
|
|
1940
|
+
}
|
|
1941
|
+
if (only == null || only === 'tokens') {
|
|
1942
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1943
|
+
etypes: [etype],
|
|
1944
|
+
params: {
|
|
1945
|
+
guid,
|
|
1946
|
+
},
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
if (only == null) {
|
|
1950
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1261
1951
|
etypes: [etype],
|
|
1262
1952
|
params: {
|
|
1263
1953
|
guid,
|
|
1264
1954
|
},
|
|
1265
1955
|
});
|
|
1266
|
-
|
|
1956
|
+
}
|
|
1957
|
+
if (only == null) {
|
|
1958
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull } = this.removeAndReturnACValues(etype, {}, sdata);
|
|
1959
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate", "user", "group", "acUser", "acGroup", "acOther", "acRead", "acWrite", "acFull") VALUES (@guid, @tags, @cdate, @mdate, @user, @group, @acUser, @acGroup, @acOther, @acRead, @acWrite, @acFull);`, {
|
|
1267
1960
|
etypes: [etype],
|
|
1268
1961
|
params: {
|
|
1269
1962
|
guid,
|
|
1270
1963
|
tags: ',' + tags.join(',') + ',',
|
|
1271
|
-
cdate
|
|
1272
|
-
mdate
|
|
1964
|
+
cdate,
|
|
1965
|
+
mdate,
|
|
1966
|
+
user,
|
|
1967
|
+
group,
|
|
1968
|
+
acUser,
|
|
1969
|
+
acGroup,
|
|
1970
|
+
acOther,
|
|
1971
|
+
acRead: acRead && ',' + acRead.join(',') + ',',
|
|
1972
|
+
acWrite: acWrite && ',' + acWrite.join(',') + ',',
|
|
1973
|
+
acFull: acFull && ',' + acFull.join(',') + ',',
|
|
1273
1974
|
},
|
|
1274
1975
|
});
|
|
1275
|
-
delete sdata.cdate;
|
|
1276
|
-
delete sdata.mdate;
|
|
1277
1976
|
for (const name in sdata) {
|
|
1278
1977
|
const value = sdata[name];
|
|
1279
1978
|
const uvalue = JSON.parse(value);
|
|
@@ -1284,23 +1983,18 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1284
1983
|
? 'N'
|
|
1285
1984
|
: typeof uvalue === 'string'
|
|
1286
1985
|
? 'S'
|
|
1287
|
-
:
|
|
1288
|
-
|
|
1986
|
+
: 'J';
|
|
1987
|
+
const jsonValue = storageValue === 'J' ? value : null;
|
|
1988
|
+
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);`, {
|
|
1289
1989
|
etypes: [etype],
|
|
1290
1990
|
params: {
|
|
1291
1991
|
guid,
|
|
1292
1992
|
name,
|
|
1293
1993
|
storageValue,
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("guid", "name", "truthy", "string", "number") VALUES (@guid, @name, @truthy, @string, @number);`, {
|
|
1297
|
-
etypes: [etype],
|
|
1298
|
-
params: {
|
|
1299
|
-
guid,
|
|
1300
|
-
name,
|
|
1301
|
-
truthy: uvalue ? 1 : 0,
|
|
1302
|
-
string: `${uvalue}`,
|
|
1994
|
+
jsonValue,
|
|
1995
|
+
string: storageValue === 'J' ? null : `${uvalue}`,
|
|
1303
1996
|
number: Number(uvalue),
|
|
1997
|
+
truthy: uvalue ? 1 : 0,
|
|
1304
1998
|
},
|
|
1305
1999
|
});
|
|
1306
2000
|
const references = this.findReferences(value);
|
|
@@ -1315,41 +2009,132 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1315
2009
|
});
|
|
1316
2010
|
}
|
|
1317
2011
|
}
|
|
1318
|
-
}
|
|
1319
|
-
|
|
2012
|
+
}
|
|
2013
|
+
if (only === 'tilmeldAC') {
|
|
2014
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull } = this.removeAndReturnACValues(etype, {}, sdata);
|
|
2015
|
+
this.queryRun(`UPDATE OR IGNORE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} SET "user"=@user, "group"=@group, "acUser"=@acUser, "acGroup"=@acGroup, "acOther"=@acOther, "acRead"=@acRead, "acWrite"=@acWrite, "acFull"=@acFull WHERE "guid"=@guid;`, {
|
|
2016
|
+
etypes: [etype],
|
|
1320
2017
|
params: {
|
|
1321
|
-
|
|
2018
|
+
user,
|
|
2019
|
+
group,
|
|
2020
|
+
acUser,
|
|
2021
|
+
acGroup,
|
|
2022
|
+
acOther,
|
|
2023
|
+
acRead: acRead && ',' + acRead.join(',') + ',',
|
|
2024
|
+
acWrite: acWrite && ',' + acWrite.join(',') + ',',
|
|
2025
|
+
acFull: acFull && ',' + acFull.join(',') + ',',
|
|
2026
|
+
guid,
|
|
1322
2027
|
},
|
|
1323
2028
|
});
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
2029
|
+
}
|
|
2030
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
2031
|
+
if (only == null || only === 'tokens') {
|
|
2032
|
+
for (let name in sdata) {
|
|
2033
|
+
let tokenString = null;
|
|
2034
|
+
try {
|
|
2035
|
+
tokenString = EntityClass.getFTSText(name, JSON.parse(sdata[name]));
|
|
2036
|
+
}
|
|
2037
|
+
catch (e) {
|
|
2038
|
+
// Ignore error.
|
|
2039
|
+
}
|
|
2040
|
+
if (tokenString != null) {
|
|
2041
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
2042
|
+
while (tokens.length) {
|
|
2043
|
+
const currentTokens = tokens.splice(0, 100);
|
|
2044
|
+
const params = {
|
|
2045
|
+
guid,
|
|
2046
|
+
name,
|
|
2047
|
+
};
|
|
2048
|
+
const values = [];
|
|
2049
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
2050
|
+
const token = currentTokens[i];
|
|
2051
|
+
params['token' + i] = token.token;
|
|
2052
|
+
params['position' + i] = token.position;
|
|
2053
|
+
params['stem' + i] = token.stem ? 1 : 0;
|
|
2054
|
+
values.push('(@guid, @name, @token' +
|
|
2055
|
+
i +
|
|
2056
|
+
', @position' +
|
|
2057
|
+
i +
|
|
2058
|
+
', @stem' +
|
|
2059
|
+
i +
|
|
2060
|
+
')');
|
|
2061
|
+
}
|
|
2062
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`, {
|
|
2063
|
+
etypes: [etype],
|
|
2064
|
+
params,
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
if (only == null) {
|
|
2071
|
+
const uniques = await EntityClass.getUniques({
|
|
2072
|
+
guid,
|
|
2073
|
+
cdate,
|
|
2074
|
+
mdate,
|
|
2075
|
+
tags,
|
|
2076
|
+
data: {},
|
|
2077
|
+
sdata,
|
|
1329
2078
|
});
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
2079
|
+
for (const unique of uniques) {
|
|
2080
|
+
try {
|
|
2081
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid", "unique") VALUES (@guid, @unique);`, {
|
|
2082
|
+
etypes: [etype],
|
|
2083
|
+
params: {
|
|
2084
|
+
guid,
|
|
2085
|
+
unique,
|
|
2086
|
+
},
|
|
2087
|
+
});
|
|
2088
|
+
}
|
|
2089
|
+
catch (e) {
|
|
2090
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2091
|
+
this.nymph.config.debugError('sqlite3', `Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
|
|
2092
|
+
}
|
|
2093
|
+
throw e;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
catch (e) {
|
|
2099
|
+
this.nymph.config.debugError('sqlite3', `Import entity error: "${e}"`);
|
|
2100
|
+
throw e;
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
async importUID({ name, value }) {
|
|
2104
|
+
try {
|
|
2105
|
+
await this.startTransaction(`nymph-import-uid-${name}`);
|
|
2106
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
2107
|
+
params: {
|
|
2108
|
+
name,
|
|
2109
|
+
},
|
|
2110
|
+
});
|
|
2111
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @value);`, {
|
|
2112
|
+
params: {
|
|
2113
|
+
name,
|
|
2114
|
+
value,
|
|
2115
|
+
},
|
|
1334
2116
|
});
|
|
2117
|
+
await this.commit(`nymph-import-uid-${name}`);
|
|
1335
2118
|
}
|
|
1336
2119
|
catch (e) {
|
|
1337
|
-
|
|
2120
|
+
this.nymph.config.debugError('sqlite3', `Import UID error: "${e}"`);
|
|
2121
|
+
await this.rollback(`nymph-import-uid-${name}`);
|
|
1338
2122
|
throw e;
|
|
1339
2123
|
}
|
|
1340
2124
|
}
|
|
1341
2125
|
async newUID(name) {
|
|
1342
2126
|
if (name == null) {
|
|
1343
|
-
throw new
|
|
2127
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1344
2128
|
}
|
|
1345
|
-
this.checkReadOnlyMode();
|
|
1346
2129
|
await this.startTransaction('nymph-newuid');
|
|
2130
|
+
let curUid = undefined;
|
|
1347
2131
|
try {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
2132
|
+
curUid =
|
|
2133
|
+
this.queryGet(`SELECT "cur_uid" FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
2134
|
+
params: {
|
|
2135
|
+
name,
|
|
2136
|
+
},
|
|
2137
|
+
})?.cur_uid ?? null;
|
|
1353
2138
|
if (curUid == null) {
|
|
1354
2139
|
curUid = 1;
|
|
1355
2140
|
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @curUid);`, {
|
|
@@ -1368,41 +2153,50 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1368
2153
|
},
|
|
1369
2154
|
});
|
|
1370
2155
|
}
|
|
1371
|
-
await this.commit('nymph-newuid');
|
|
1372
|
-
return curUid;
|
|
1373
2156
|
}
|
|
1374
2157
|
catch (e) {
|
|
2158
|
+
this.nymph.config.debugError('sqlite3', `New UID error: "${e}"`);
|
|
1375
2159
|
await this.rollback('nymph-newuid');
|
|
1376
2160
|
throw e;
|
|
1377
2161
|
}
|
|
2162
|
+
await this.commit('nymph-newuid');
|
|
2163
|
+
return curUid;
|
|
1378
2164
|
}
|
|
1379
2165
|
async renameUID(oldName, newName) {
|
|
1380
2166
|
if (oldName == null || newName == null) {
|
|
1381
|
-
throw new
|
|
2167
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1382
2168
|
}
|
|
1383
|
-
this.
|
|
2169
|
+
await this.startTransaction('nymph-rename-uid');
|
|
1384
2170
|
this.queryRun(`UPDATE ${SQLite3Driver.escape(`${this.prefix}uids`)} SET "name"=@newName WHERE "name"=@oldName;`, {
|
|
1385
2171
|
params: {
|
|
1386
2172
|
newName,
|
|
1387
2173
|
oldName,
|
|
1388
2174
|
},
|
|
1389
2175
|
});
|
|
2176
|
+
await this.commit('nymph-rename-uid');
|
|
1390
2177
|
return true;
|
|
1391
2178
|
}
|
|
1392
2179
|
async rollback(name) {
|
|
1393
2180
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1394
|
-
throw new
|
|
2181
|
+
throw new InvalidParametersError('Transaction rollback attempted without a name.');
|
|
1395
2182
|
}
|
|
1396
2183
|
if (this.store.transactionsStarted === 0) {
|
|
1397
2184
|
return true;
|
|
1398
2185
|
}
|
|
1399
2186
|
this.queryRun(`ROLLBACK TO SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
1400
2187
|
this.store.transactionsStarted--;
|
|
2188
|
+
if (this.store.transactionsStarted === 0 &&
|
|
2189
|
+
this.store.linkWrite &&
|
|
2190
|
+
!this.config.explicitWrite) {
|
|
2191
|
+
this.store.linkWrite.exec('PRAGMA optimize;');
|
|
2192
|
+
this.store.linkWrite.close();
|
|
2193
|
+
this.store.linkWrite = undefined;
|
|
2194
|
+
}
|
|
1401
2195
|
return true;
|
|
1402
2196
|
}
|
|
1403
2197
|
async saveEntity(entity) {
|
|
1404
|
-
|
|
1405
|
-
|
|
2198
|
+
const insertData = (guid, data, sdata, uniques, etype) => {
|
|
2199
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
1406
2200
|
const runInsertQuery = (name, value, svalue) => {
|
|
1407
2201
|
if (value === undefined) {
|
|
1408
2202
|
return;
|
|
@@ -1411,23 +2205,18 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1411
2205
|
? 'N'
|
|
1412
2206
|
: typeof value === 'string'
|
|
1413
2207
|
? 'S'
|
|
1414
|
-
:
|
|
1415
|
-
|
|
2208
|
+
: 'J';
|
|
2209
|
+
const jsonValue = storageValue === 'J' ? svalue : null;
|
|
2210
|
+
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);`, {
|
|
1416
2211
|
etypes: [etype],
|
|
1417
2212
|
params: {
|
|
1418
2213
|
guid,
|
|
1419
2214
|
name,
|
|
1420
2215
|
storageValue,
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}comparisons_${etype}`)} ("guid", "name", "truthy", "string", "number") VALUES (@guid, @name, @truthy, @string, @number);`, {
|
|
1424
|
-
etypes: [etype],
|
|
1425
|
-
params: {
|
|
1426
|
-
guid,
|
|
1427
|
-
name,
|
|
1428
|
-
truthy: value ? 1 : 0,
|
|
1429
|
-
string: `${value}`,
|
|
2216
|
+
jsonValue,
|
|
2217
|
+
string: storageValue === 'J' ? null : `${value}`,
|
|
1430
2218
|
number: Number(value),
|
|
2219
|
+
truthy: value ? 1 : 0,
|
|
1431
2220
|
},
|
|
1432
2221
|
});
|
|
1433
2222
|
const references = this.findReferences(svalue);
|
|
@@ -1441,7 +2230,59 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1441
2230
|
},
|
|
1442
2231
|
});
|
|
1443
2232
|
}
|
|
2233
|
+
let tokenString = null;
|
|
2234
|
+
try {
|
|
2235
|
+
tokenString = EntityClass.getFTSText(name, value);
|
|
2236
|
+
}
|
|
2237
|
+
catch (e) {
|
|
2238
|
+
// Ignore error.
|
|
2239
|
+
}
|
|
2240
|
+
if (tokenString != null) {
|
|
2241
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
2242
|
+
while (tokens.length) {
|
|
2243
|
+
const currentTokens = tokens.splice(0, 100);
|
|
2244
|
+
const params = {
|
|
2245
|
+
guid,
|
|
2246
|
+
name,
|
|
2247
|
+
};
|
|
2248
|
+
const values = [];
|
|
2249
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
2250
|
+
const token = currentTokens[i];
|
|
2251
|
+
params['token' + i] = token.token;
|
|
2252
|
+
params['position' + i] = token.position;
|
|
2253
|
+
params['stem' + i] = token.stem ? 1 : 0;
|
|
2254
|
+
values.push('(@guid, @name, @token' +
|
|
2255
|
+
i +
|
|
2256
|
+
', @position' +
|
|
2257
|
+
i +
|
|
2258
|
+
', @stem' +
|
|
2259
|
+
i +
|
|
2260
|
+
')');
|
|
2261
|
+
}
|
|
2262
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`, {
|
|
2263
|
+
etypes: [etype],
|
|
2264
|
+
params,
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
1444
2268
|
};
|
|
2269
|
+
for (const unique of uniques) {
|
|
2270
|
+
try {
|
|
2271
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid", "unique") VALUES (@guid, @unique);`, {
|
|
2272
|
+
etypes: [etype],
|
|
2273
|
+
params: {
|
|
2274
|
+
guid,
|
|
2275
|
+
unique,
|
|
2276
|
+
},
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
catch (e) {
|
|
2280
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2281
|
+
this.nymph.config.debugError('sqlite3', `Save entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
|
|
2282
|
+
}
|
|
2283
|
+
throw e;
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
1445
2286
|
for (const name in data) {
|
|
1446
2287
|
runInsertQuery(name, data[name], JSON.stringify(data[name]));
|
|
1447
2288
|
}
|
|
@@ -1449,24 +2290,51 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1449
2290
|
runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
|
|
1450
2291
|
}
|
|
1451
2292
|
};
|
|
2293
|
+
let inTransaction = false;
|
|
1452
2294
|
try {
|
|
1453
|
-
return this.saveEntityRowLike(entity, async (
|
|
1454
|
-
|
|
2295
|
+
return this.saveEntityRowLike(entity, async ({ guid, tags, data, sdata, uniques, cdate, etype }) => {
|
|
2296
|
+
if (Object.keys(data).length === 0 &&
|
|
2297
|
+
Object.keys(sdata).length === 0) {
|
|
2298
|
+
return false;
|
|
2299
|
+
}
|
|
2300
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull, } = this.removeAndReturnACValues(etype, data, sdata);
|
|
2301
|
+
this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate", "user", "group", "acUser", "acGroup", "acOther", "acRead", "acWrite", "acFull") VALUES (@guid, @tags, @cdate, @cdate, @user, @group, @acUser, @acGroup, @acOther, @acRead, @acWrite, @acFull);`, {
|
|
1455
2302
|
etypes: [etype],
|
|
1456
2303
|
params: {
|
|
1457
2304
|
guid,
|
|
1458
2305
|
tags: ',' + tags.join(',') + ',',
|
|
1459
2306
|
cdate,
|
|
2307
|
+
user,
|
|
2308
|
+
group,
|
|
2309
|
+
acUser,
|
|
2310
|
+
acGroup,
|
|
2311
|
+
acOther,
|
|
2312
|
+
acRead: acRead && ',' + acRead.join(',') + ',',
|
|
2313
|
+
acWrite: acWrite && ',' + acWrite.join(',') + ',',
|
|
2314
|
+
acFull: acFull && ',' + acFull.join(',') + ',',
|
|
1460
2315
|
},
|
|
1461
2316
|
});
|
|
1462
|
-
insertData(guid, data, sdata, etype);
|
|
2317
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
1463
2318
|
return true;
|
|
1464
|
-
}, async (entity, guid, tags, data, sdata, mdate, etype) => {
|
|
1465
|
-
|
|
2319
|
+
}, async ({ entity, guid, tags, data, sdata, uniques, mdate, etype }) => {
|
|
2320
|
+
if (Object.keys(data).length === 0 &&
|
|
2321
|
+
Object.keys(sdata).length === 0) {
|
|
2322
|
+
return false;
|
|
2323
|
+
}
|
|
2324
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull, } = this.removeAndReturnACValues(etype, data, sdata);
|
|
2325
|
+
const info = this.queryRun(`UPDATE ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} SET "tags"=@tags, "mdate"=@mdate, "user"=@user, "group"=@group, "acUser"=@acUser, "acGroup"=@acGroup, "acOther"=@acOther, "acRead"=@acRead, "acWrite"=@acWrite, "acFull"=@acFull WHERE "guid"=@guid AND "mdate" <= @emdate;`, {
|
|
1466
2326
|
etypes: [etype],
|
|
1467
2327
|
params: {
|
|
1468
2328
|
tags: ',' + tags.join(',') + ',',
|
|
1469
2329
|
mdate,
|
|
2330
|
+
user,
|
|
2331
|
+
group,
|
|
2332
|
+
acUser,
|
|
2333
|
+
acGroup,
|
|
2334
|
+
acOther,
|
|
2335
|
+
acRead: acRead && ',' + acRead.join(',') + ',',
|
|
2336
|
+
acWrite: acWrite && ',' + acWrite.join(',') + ',',
|
|
2337
|
+
acFull: acFull && ',' + acFull.join(',') + ',',
|
|
1470
2338
|
guid,
|
|
1471
2339
|
emdate: Number(entity.mdate),
|
|
1472
2340
|
},
|
|
@@ -1479,44 +2347,57 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1479
2347
|
guid,
|
|
1480
2348
|
},
|
|
1481
2349
|
});
|
|
1482
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
2350
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1483
2351
|
etypes: [etype],
|
|
1484
2352
|
params: {
|
|
1485
2353
|
guid,
|
|
1486
2354
|
},
|
|
1487
2355
|
});
|
|
1488
|
-
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}
|
|
2356
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
|
|
2357
|
+
etypes: [etype],
|
|
2358
|
+
params: {
|
|
2359
|
+
guid,
|
|
2360
|
+
},
|
|
2361
|
+
});
|
|
2362
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
|
|
1489
2363
|
etypes: [etype],
|
|
1490
2364
|
params: {
|
|
1491
2365
|
guid,
|
|
1492
2366
|
},
|
|
1493
2367
|
});
|
|
1494
|
-
insertData(guid, data, sdata, etype);
|
|
2368
|
+
insertData(guid, data, sdata, uniques, etype);
|
|
1495
2369
|
success = true;
|
|
1496
2370
|
}
|
|
1497
2371
|
return success;
|
|
1498
2372
|
}, async () => {
|
|
1499
2373
|
await this.startTransaction('nymph-save');
|
|
2374
|
+
inTransaction = true;
|
|
1500
2375
|
}, async (success) => {
|
|
1501
|
-
if (
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
2376
|
+
if (inTransaction) {
|
|
2377
|
+
inTransaction = false;
|
|
2378
|
+
if (success) {
|
|
2379
|
+
await this.commit('nymph-save');
|
|
2380
|
+
}
|
|
2381
|
+
else {
|
|
2382
|
+
await this.rollback('nymph-save');
|
|
2383
|
+
}
|
|
1506
2384
|
}
|
|
1507
2385
|
return success;
|
|
1508
2386
|
});
|
|
1509
2387
|
}
|
|
1510
2388
|
catch (e) {
|
|
1511
|
-
|
|
2389
|
+
this.nymph.config.debugError('sqlite3', `Save entity error: "${e}"`);
|
|
2390
|
+
if (inTransaction) {
|
|
2391
|
+
await this.rollback('nymph-save');
|
|
2392
|
+
}
|
|
1512
2393
|
throw e;
|
|
1513
2394
|
}
|
|
1514
2395
|
}
|
|
1515
2396
|
async setUID(name, curUid) {
|
|
1516
2397
|
if (name == null) {
|
|
1517
|
-
throw new
|
|
2398
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1518
2399
|
}
|
|
1519
|
-
this.
|
|
2400
|
+
await this.startTransaction('nymph-set-uid');
|
|
1520
2401
|
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
1521
2402
|
params: {
|
|
1522
2403
|
name,
|
|
@@ -1528,16 +2409,124 @@ class SQLite3Driver extends nymph_1.NymphDriver {
|
|
|
1528
2409
|
curUid,
|
|
1529
2410
|
},
|
|
1530
2411
|
});
|
|
2412
|
+
await this.commit('nymph-set-uid');
|
|
1531
2413
|
return true;
|
|
1532
2414
|
}
|
|
2415
|
+
async internalTransaction(name) {
|
|
2416
|
+
await this.startTransaction(name);
|
|
2417
|
+
}
|
|
1533
2418
|
async startTransaction(name) {
|
|
1534
2419
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1535
|
-
throw new
|
|
2420
|
+
throw new InvalidParametersError('Transaction start attempted without a name.');
|
|
2421
|
+
}
|
|
2422
|
+
if (!this.config.explicitWrite && !this.store.linkWrite) {
|
|
2423
|
+
this._connect(true);
|
|
1536
2424
|
}
|
|
1537
2425
|
this.queryRun(`SAVEPOINT ${SQLite3Driver.escape(name)};`);
|
|
1538
2426
|
this.store.transactionsStarted++;
|
|
1539
2427
|
return this.nymph;
|
|
1540
2428
|
}
|
|
2429
|
+
async removeTilmeldOldRows(etype) {
|
|
2430
|
+
await this.startTransaction('nymph-remove-tilmeld-rows');
|
|
2431
|
+
try {
|
|
2432
|
+
for (let name of [
|
|
2433
|
+
'user',
|
|
2434
|
+
'group',
|
|
2435
|
+
'acUser',
|
|
2436
|
+
'acGroup',
|
|
2437
|
+
'acOther',
|
|
2438
|
+
'acRead',
|
|
2439
|
+
'acWrite',
|
|
2440
|
+
'acFull',
|
|
2441
|
+
]) {
|
|
2442
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} WHERE "name"=@name;`, {
|
|
2443
|
+
etypes: [etype],
|
|
2444
|
+
params: {
|
|
2445
|
+
name,
|
|
2446
|
+
},
|
|
2447
|
+
});
|
|
2448
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "name"=@name;`, {
|
|
2449
|
+
etypes: [etype],
|
|
2450
|
+
params: {
|
|
2451
|
+
name,
|
|
2452
|
+
},
|
|
2453
|
+
});
|
|
2454
|
+
this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "name"=@name;`, {
|
|
2455
|
+
etypes: [etype],
|
|
2456
|
+
params: {
|
|
2457
|
+
name,
|
|
2458
|
+
},
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
catch (e) {
|
|
2463
|
+
this.nymph.config.debugError('sqlite3', `Remove tilmeld rows error: "${e}"`);
|
|
2464
|
+
await this.rollback('nymph-remove-tilmeld-rows');
|
|
2465
|
+
throw e;
|
|
2466
|
+
}
|
|
2467
|
+
await this.commit('nymph-remove-tilmeld-rows');
|
|
2468
|
+
return true;
|
|
2469
|
+
}
|
|
2470
|
+
async needsMigration() {
|
|
2471
|
+
const table = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix LIMIT 1;", {
|
|
2472
|
+
params: {
|
|
2473
|
+
prefix: this.prefix + 'data_' + '%',
|
|
2474
|
+
},
|
|
2475
|
+
});
|
|
2476
|
+
if (table?.name) {
|
|
2477
|
+
const result = this.queryGet("SELECT 1 AS `exists` FROM pragma_table_info(@table) WHERE `name`='json';", {
|
|
2478
|
+
params: {
|
|
2479
|
+
table: table.name,
|
|
2480
|
+
},
|
|
2481
|
+
});
|
|
2482
|
+
if (!result?.exists) {
|
|
2483
|
+
return 'json';
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
const table2 = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @tokenTable LIMIT 1;", {
|
|
2487
|
+
params: {
|
|
2488
|
+
tokenTable: this.prefix + 'tokens_' + '%',
|
|
2489
|
+
},
|
|
2490
|
+
});
|
|
2491
|
+
if (!table2 || !table2.name) {
|
|
2492
|
+
return 'tokens';
|
|
2493
|
+
}
|
|
2494
|
+
const table3 = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix LIMIT 1;", {
|
|
2495
|
+
params: {
|
|
2496
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
2497
|
+
},
|
|
2498
|
+
});
|
|
2499
|
+
if (table3?.name) {
|
|
2500
|
+
const result = this.queryGet("SELECT 1 AS `exists` FROM pragma_table_info(@table) WHERE `name`='user';", {
|
|
2501
|
+
params: {
|
|
2502
|
+
table: table3.name,
|
|
2503
|
+
},
|
|
2504
|
+
});
|
|
2505
|
+
if (!result?.exists) {
|
|
2506
|
+
return 'tilmeldColumns';
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
return false;
|
|
2510
|
+
}
|
|
2511
|
+
async liveMigration(migrationType) {
|
|
2512
|
+
if (migrationType === 'tokenTables') {
|
|
2513
|
+
const etypes = await this.getEtypes();
|
|
2514
|
+
for (let etype of etypes) {
|
|
2515
|
+
this.createTokensTable(etype);
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
else if (migrationType === 'tilmeldColumns') {
|
|
2519
|
+
const etypes = await this.getEtypes();
|
|
2520
|
+
for (let etype of etypes) {
|
|
2521
|
+
this.addTilmeldColumnsAndIndexes(etype);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
else if (migrationType === 'tilmeldRemoveOldRows') {
|
|
2525
|
+
const etypes = await this.getEtypes();
|
|
2526
|
+
for (let etype of etypes) {
|
|
2527
|
+
await this.removeTilmeldOldRows(etype);
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
1541
2531
|
}
|
|
1542
|
-
exports.default = SQLite3Driver;
|
|
1543
2532
|
//# sourceMappingURL=SQLite3Driver.js.map
|