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