@nymphjs/driver-mysql 1.0.0-beta.12 → 1.0.0-beta.120
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 +557 -0
- package/README.md +1 -1
- package/dist/MySQLDriver.d.ts +106 -24
- package/dist/MySQLDriver.js +1554 -705
- package/dist/MySQLDriver.js.map +1 -1
- package/dist/MySQLDriver.test.js +13 -12
- package/dist/MySQLDriver.test.js.map +1 -1
- package/dist/conf/defaults.d.ts +1 -1
- package/dist/conf/defaults.js +1 -3
- package/dist/conf/defaults.js.map +1 -1
- package/dist/conf/index.d.ts +66 -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 +31 -6
- package/package.json +31 -23
- package/src/MySQLDriver.test.ts +14 -3
- package/src/MySQLDriver.ts +2219 -1040
- package/src/conf/defaults.ts +1 -1
- package/src/conf/index.ts +67 -2
- package/src/index.ts +2 -2
- package/tsconfig.json +6 -3
- package/typedoc.json +4 -0
- package/dist/conf/d.d.ts +0 -15
- package/dist/conf/d.js +0 -3
- package/dist/conf/d.js.map +0 -1
- package/dist/runMysqlSync.js +0 -44
- package/src/conf/d.ts +0 -67
- package/src/runMysqlSync.js +0 -44
- package/src/testmysql.js +0 -32
package/src/MySQLDriver.ts
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { Pool, PoolOptions, PoolConnection } from 'mysql2';
|
|
2
|
+
import mysql from 'mysql2';
|
|
3
|
+
import SqlString from 'sqlstring';
|
|
4
|
+
import type {
|
|
5
|
+
SearchTerm,
|
|
6
|
+
SearchOrTerm,
|
|
7
|
+
SearchNotTerm,
|
|
8
|
+
SearchSeriesTerm,
|
|
9
|
+
} from '@sciactive/tokenizer';
|
|
6
10
|
import {
|
|
7
11
|
NymphDriver,
|
|
8
|
-
EntityConstructor,
|
|
9
|
-
EntityData,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
type EntityConstructor,
|
|
13
|
+
type EntityData,
|
|
14
|
+
type EntityObjectType,
|
|
15
|
+
type EntityInterface,
|
|
16
|
+
type EntityInstanceType,
|
|
17
|
+
type SerializedEntityData,
|
|
18
|
+
type FormattedSelector,
|
|
19
|
+
type Options,
|
|
20
|
+
type Selector,
|
|
21
|
+
EntityUniqueConstraintError,
|
|
12
22
|
InvalidParametersError,
|
|
13
23
|
NotConfiguredError,
|
|
14
24
|
QueryFailedError,
|
|
15
25
|
UnableToConnectError,
|
|
16
|
-
FormattedSelector,
|
|
17
|
-
Options,
|
|
18
|
-
Selector,
|
|
19
26
|
xor,
|
|
20
27
|
} from '@nymphjs/nymph';
|
|
21
28
|
import { makeTableSuffix } from '@nymphjs/guid';
|
|
@@ -23,29 +30,27 @@ import { makeTableSuffix } from '@nymphjs/guid';
|
|
|
23
30
|
import {
|
|
24
31
|
MySQLDriverConfig,
|
|
25
32
|
MySQLDriverConfigDefaults as defaults,
|
|
26
|
-
} from './conf';
|
|
33
|
+
} from './conf/index.js';
|
|
27
34
|
|
|
28
35
|
type MySQLDriverTransaction = {
|
|
29
|
-
connection:
|
|
36
|
+
connection: PoolConnection | null;
|
|
30
37
|
count: number;
|
|
31
38
|
};
|
|
32
39
|
|
|
33
|
-
const mysql = vlaskyMysql as typeof MySQLType;
|
|
34
|
-
|
|
35
40
|
/**
|
|
36
41
|
* The MySQL Nymph database driver.
|
|
37
42
|
*/
|
|
38
43
|
export default class MySQLDriver extends NymphDriver {
|
|
39
44
|
public config: MySQLDriverConfig;
|
|
40
|
-
private mysqlConfig:
|
|
45
|
+
private mysqlConfig: PoolOptions;
|
|
41
46
|
protected prefix: string;
|
|
42
47
|
protected connected: boolean = false;
|
|
43
48
|
// @ts-ignore: this is assigned in connect(), which is called by the constructor.
|
|
44
|
-
protected link:
|
|
49
|
+
protected link: Pool;
|
|
45
50
|
protected transaction: MySQLDriverTransaction | null = null;
|
|
46
51
|
|
|
47
52
|
static escape(input: string) {
|
|
48
|
-
return
|
|
53
|
+
return SqlString.escapeId(input, true);
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
static escapeValue(input: string) {
|
|
@@ -54,8 +59,8 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
54
59
|
|
|
55
60
|
constructor(
|
|
56
61
|
config: Partial<MySQLDriverConfig>,
|
|
57
|
-
link?:
|
|
58
|
-
transaction?: MySQLDriverTransaction
|
|
62
|
+
link?: Pool,
|
|
63
|
+
transaction?: MySQLDriverTransaction,
|
|
59
64
|
) {
|
|
60
65
|
super();
|
|
61
66
|
this.config = { ...defaults, ...config };
|
|
@@ -90,16 +95,16 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
90
95
|
return new MySQLDriver(
|
|
91
96
|
this.config,
|
|
92
97
|
this.link,
|
|
93
|
-
this.transaction ?? undefined
|
|
98
|
+
this.transaction ?? undefined,
|
|
94
99
|
);
|
|
95
100
|
}
|
|
96
101
|
|
|
97
|
-
private getConnection(): Promise<
|
|
102
|
+
private getConnection(): Promise<PoolConnection> {
|
|
98
103
|
if (this.transaction != null && this.transaction.connection != null) {
|
|
99
104
|
return Promise.resolve(this.transaction.connection);
|
|
100
105
|
}
|
|
101
106
|
return new Promise((resolve, reject) =>
|
|
102
|
-
this.link.getConnection((err, con) => (err ? reject(err) : resolve(con)))
|
|
107
|
+
this.link.getConnection((err, con) => (err ? reject(err) : resolve(con))),
|
|
103
108
|
);
|
|
104
109
|
}
|
|
105
110
|
|
|
@@ -112,16 +117,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
112
117
|
// If we think we're connected, try pinging the server.
|
|
113
118
|
try {
|
|
114
119
|
if (this.connected) {
|
|
115
|
-
const connection:
|
|
120
|
+
const connection: PoolConnection = await new Promise(
|
|
116
121
|
(resolve, reject) =>
|
|
117
122
|
this.link.getConnection((err, con) =>
|
|
118
|
-
err ? reject(err) : resolve(con)
|
|
119
|
-
)
|
|
120
|
-
);
|
|
121
|
-
await new Promise((resolve) =>
|
|
122
|
-
connection.ping(() => {
|
|
123
|
-
resolve(0);
|
|
124
|
-
})
|
|
123
|
+
err ? reject(err) : resolve(con),
|
|
124
|
+
),
|
|
125
125
|
);
|
|
126
126
|
connection.release();
|
|
127
127
|
}
|
|
@@ -132,7 +132,10 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
132
132
|
// Connecting, selecting database
|
|
133
133
|
if (!this.connected) {
|
|
134
134
|
try {
|
|
135
|
-
this.link = mysql.createPool(
|
|
135
|
+
this.link = mysql.createPool({
|
|
136
|
+
...this.mysqlConfig,
|
|
137
|
+
charset: 'utf8mb4_bin',
|
|
138
|
+
});
|
|
136
139
|
this.connected = true;
|
|
137
140
|
} catch (e: any) {
|
|
138
141
|
if (
|
|
@@ -142,7 +145,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
142
145
|
this.mysqlConfig.database === 'nymph'
|
|
143
146
|
) {
|
|
144
147
|
throw new NotConfiguredError(
|
|
145
|
-
"It seems the config hasn't been set up correctly."
|
|
148
|
+
"It seems the config hasn't been set up correctly.",
|
|
146
149
|
);
|
|
147
150
|
} else {
|
|
148
151
|
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
@@ -166,6 +169,9 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
166
169
|
}
|
|
167
170
|
|
|
168
171
|
public async inTransaction() {
|
|
172
|
+
if (this.transaction && this.transaction.count === 0) {
|
|
173
|
+
this.transaction = null;
|
|
174
|
+
}
|
|
169
175
|
return !!this.transaction;
|
|
170
176
|
}
|
|
171
177
|
|
|
@@ -178,106 +184,283 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
178
184
|
return this.connected;
|
|
179
185
|
}
|
|
180
186
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
private createTables(etype: string | null = null) {
|
|
188
|
-
this.queryRunSync('SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";');
|
|
189
|
-
let foreignKeyDataTableGuid = '';
|
|
190
|
-
let foreignKeyDataComparisonsTableGuid = '';
|
|
191
|
-
let foreignKeyReferencesTableGuid = '';
|
|
192
|
-
if (this.config.foreignKeys) {
|
|
193
|
-
foreignKeyDataTableGuid = ` REFERENCES ${MySQLDriver.escape(
|
|
194
|
-
`${this.prefix}entities_${etype}`
|
|
195
|
-
)}(\`guid\`) ON DELETE CASCADE`;
|
|
196
|
-
foreignKeyDataComparisonsTableGuid = ` REFERENCES ${MySQLDriver.escape(
|
|
197
|
-
`${this.prefix}entities_${etype}`
|
|
198
|
-
)}(\`guid\`) ON DELETE CASCADE`;
|
|
199
|
-
foreignKeyReferencesTableGuid = ` REFERENCES ${MySQLDriver.escape(
|
|
200
|
-
`${this.prefix}entities_${etype}`
|
|
201
|
-
)}(\`guid\`) ON DELETE CASCADE`;
|
|
202
|
-
}
|
|
203
|
-
if (etype != null) {
|
|
204
|
-
// Create the entity table.
|
|
205
|
-
this.queryRunSync(
|
|
206
|
-
`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(
|
|
207
|
-
`${this.prefix}entities_${etype}`
|
|
208
|
-
)} (
|
|
187
|
+
private async createEntitiesTable(etype: string) {
|
|
188
|
+
// Create the entity table.
|
|
189
|
+
await this.queryRun(
|
|
190
|
+
`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(
|
|
191
|
+
`${this.prefix}entities_${etype}`,
|
|
192
|
+
)} (
|
|
209
193
|
\`guid\` BINARY(12) NOT NULL,
|
|
210
194
|
\`tags\` LONGTEXT,
|
|
211
195
|
\`cdate\` DOUBLE PRECISION NOT NULL,
|
|
212
196
|
\`mdate\` DOUBLE PRECISION NOT NULL,
|
|
197
|
+
\`user\` BINARY(12),
|
|
198
|
+
\`group\` BINARY(12),
|
|
199
|
+
\`acUser\` TINYINT UNSIGNED,
|
|
200
|
+
\`acGroup\` TINYINT UNSIGNED,
|
|
201
|
+
\`acOther\` TINYINT UNSIGNED,
|
|
202
|
+
\`acRead\` LONGTEXT,
|
|
203
|
+
\`acWrite\` LONGTEXT,
|
|
204
|
+
\`acFull\` LONGTEXT,
|
|
213
205
|
PRIMARY KEY (\`guid\`),
|
|
206
|
+
INDEX \`id_guid\` USING HASH (\`guid\`),
|
|
214
207
|
INDEX \`id_cdate\` USING BTREE (\`cdate\`),
|
|
215
208
|
INDEX \`id_mdate\` USING BTREE (\`mdate\`),
|
|
216
|
-
FULLTEXT \`id_tags\` (\`tags\`)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
\`guid\` BINARY(12) NOT NULL${foreignKeyDataTableGuid},
|
|
226
|
-
\`name\` TEXT NOT NULL,
|
|
227
|
-
\`value\` LONGTEXT NOT NULL,
|
|
228
|
-
PRIMARY KEY (\`guid\`,\`name\`(255)),
|
|
229
|
-
INDEX \`id_name\` USING HASH (\`name\`(255)),
|
|
230
|
-
INDEX \`id_name_value\` USING BTREE (\`name\`(255), \`value\`(512))
|
|
209
|
+
FULLTEXT \`id_tags\` (\`tags\`),
|
|
210
|
+
INDEX \`id_user_acUser\` USING BTREE (\`user\`, \`acUser\`),
|
|
211
|
+
INDEX \`id_group_acGroup\` USING BTREE (\`group\`, \`acGroup\`),
|
|
212
|
+
INDEX \`id_acUser\` USING BTREE (\`acUser\`),
|
|
213
|
+
INDEX \`id_acGroup\` USING BTREE (\`acGroup\`),
|
|
214
|
+
INDEX \`id_acOther\` USING BTREE (\`acOther\`),
|
|
215
|
+
FULLTEXT \`id_acRead\` (\`acRead\`),
|
|
216
|
+
FULLTEXT \`id_acWrite\` (\`acWrite\`),
|
|
217
|
+
FULLTEXT \`id_acFull\` (\`acFull\`)
|
|
231
218
|
) ENGINE ${this.config.engine}
|
|
232
|
-
CHARACTER SET
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
219
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private async addTilmeldColumnsAndIndexes(etype: string) {
|
|
224
|
+
await this.queryRun(
|
|
225
|
+
`ALTER TABLE ${MySQLDriver.escape(
|
|
226
|
+
`${this.prefix}entities_${etype}`,
|
|
227
|
+
)} ADD COLUMN \`user\` BINARY(12);`,
|
|
228
|
+
);
|
|
229
|
+
await this.queryRun(
|
|
230
|
+
`ALTER TABLE ${MySQLDriver.escape(
|
|
231
|
+
`${this.prefix}entities_${etype}`,
|
|
232
|
+
)} ADD COLUMN \`group\` BINARY(12);`,
|
|
233
|
+
);
|
|
234
|
+
await this.queryRun(
|
|
235
|
+
`ALTER TABLE ${MySQLDriver.escape(
|
|
236
|
+
`${this.prefix}entities_${etype}`,
|
|
237
|
+
)} ADD COLUMN \`acUser\` TINYINT UNSIGNED;`,
|
|
238
|
+
);
|
|
239
|
+
await this.queryRun(
|
|
240
|
+
`ALTER TABLE ${MySQLDriver.escape(
|
|
241
|
+
`${this.prefix}entities_${etype}`,
|
|
242
|
+
)} ADD COLUMN \`acGroup\` TINYINT UNSIGNED;`,
|
|
243
|
+
);
|
|
244
|
+
await this.queryRun(
|
|
245
|
+
`ALTER TABLE ${MySQLDriver.escape(
|
|
246
|
+
`${this.prefix}entities_${etype}`,
|
|
247
|
+
)} ADD COLUMN \`acOther\` TINYINT UNSIGNED;`,
|
|
248
|
+
);
|
|
249
|
+
await this.queryRun(
|
|
250
|
+
`ALTER TABLE ${MySQLDriver.escape(
|
|
251
|
+
`${this.prefix}entities_${etype}`,
|
|
252
|
+
)} ADD COLUMN \`acRead\` LONGTEXT;`,
|
|
253
|
+
);
|
|
254
|
+
await this.queryRun(
|
|
255
|
+
`ALTER TABLE ${MySQLDriver.escape(
|
|
256
|
+
`${this.prefix}entities_${etype}`,
|
|
257
|
+
)} ADD COLUMN \`acWrite\` LONGTEXT;`,
|
|
258
|
+
);
|
|
259
|
+
await this.queryRun(
|
|
260
|
+
`ALTER TABLE ${MySQLDriver.escape(
|
|
261
|
+
`${this.prefix}entities_${etype}`,
|
|
262
|
+
)} ADD COLUMN \`acFull\` LONGTEXT;`,
|
|
263
|
+
);
|
|
264
|
+
await this.createEntitiesTilmeldIndexes(etype);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private async createEntitiesTilmeldIndexes(etype: string) {
|
|
268
|
+
await this.queryRun(
|
|
269
|
+
`CREATE INDEX \`id_user_acUser\` ON ${MySQLDriver.escape(
|
|
270
|
+
`${this.prefix}entities_${etype}`,
|
|
271
|
+
)} (\`user\`, \`acUser\`) USING BTREE;`,
|
|
272
|
+
);
|
|
273
|
+
await this.queryRun(
|
|
274
|
+
`CREATE INDEX \`id_group_acGroup\` ON ${MySQLDriver.escape(
|
|
275
|
+
`${this.prefix}entities_${etype}`,
|
|
276
|
+
)} (\`group\`, \`acGroup\`) USING BTREE;`,
|
|
277
|
+
);
|
|
278
|
+
await this.queryRun(
|
|
279
|
+
`CREATE INDEX \`id_acUser\` ON ${MySQLDriver.escape(
|
|
280
|
+
`${this.prefix}entities_${etype}`,
|
|
281
|
+
)} (\`acUser\`) USING BTREE;`,
|
|
282
|
+
);
|
|
283
|
+
await this.queryRun(
|
|
284
|
+
`CREATE INDEX \`id_acGroup\` ON ${MySQLDriver.escape(
|
|
285
|
+
`${this.prefix}entities_${etype}`,
|
|
286
|
+
)} (\`acGroup\`) USING BTREE;`,
|
|
287
|
+
);
|
|
288
|
+
await this.queryRun(
|
|
289
|
+
`CREATE INDEX \`id_acOther\` ON ${MySQLDriver.escape(
|
|
290
|
+
`${this.prefix}entities_${etype}`,
|
|
291
|
+
)} (\`acOther\`) USING BTREE;`,
|
|
292
|
+
);
|
|
293
|
+
await this.queryRun(
|
|
294
|
+
`CREATE FULLTEXT INDEX \`id_acRead\` ON ${MySQLDriver.escape(
|
|
295
|
+
`${this.prefix}entities_${etype}`,
|
|
296
|
+
)} (\`acRead\`);`,
|
|
297
|
+
);
|
|
298
|
+
await this.queryRun(
|
|
299
|
+
`CREATE FULLTEXT INDEX \`id_acWrite\` ON ${MySQLDriver.escape(
|
|
300
|
+
`${this.prefix}entities_${etype}`,
|
|
301
|
+
)} (\`acWrite\`);`,
|
|
302
|
+
);
|
|
303
|
+
await this.queryRun(
|
|
304
|
+
`CREATE FULLTEXT INDEX \`id_acFull\` ON ${MySQLDriver.escape(
|
|
305
|
+
`${this.prefix}entities_${etype}`,
|
|
306
|
+
)} (\`acFull\`);`,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
private async createDataTable(etype: string) {
|
|
311
|
+
let foreignKey = '';
|
|
312
|
+
if (this.config.foreignKeys) {
|
|
313
|
+
foreignKey = ` REFERENCES ${MySQLDriver.escape(
|
|
314
|
+
`${this.prefix}entities_${etype}`,
|
|
315
|
+
)}(\`guid\`) ON DELETE CASCADE`;
|
|
316
|
+
}
|
|
317
|
+
// Create the data table.
|
|
318
|
+
await this.queryRun(
|
|
319
|
+
`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(
|
|
320
|
+
`${this.prefix}data_${etype}`,
|
|
321
|
+
)} (
|
|
322
|
+
\`guid\` BINARY(12) NOT NULL${foreignKey},
|
|
240
323
|
\`name\` TEXT NOT NULL,
|
|
241
|
-
\`
|
|
324
|
+
\`value\` CHAR(1) NOT NULL,
|
|
325
|
+
\`json\` JSON,
|
|
242
326
|
\`string\` LONGTEXT,
|
|
243
327
|
\`number\` DOUBLE,
|
|
328
|
+
\`truthy\` BOOLEAN,
|
|
244
329
|
PRIMARY KEY (\`guid\`, \`name\`(255)),
|
|
245
|
-
INDEX \`
|
|
330
|
+
INDEX \`id_guid\` USING HASH (\`guid\`),
|
|
331
|
+
INDEX \`id_guid_name\` USING HASH (\`guid\`, \`name\`(255)),
|
|
332
|
+
INDEX \`id_name\` USING BTREE (\`name\`(255)),
|
|
333
|
+
INDEX \`id_name_json\` USING BTREE (\`name\`(255), (CAST(\`json\` AS CHAR(512)) COLLATE utf8mb4_bin)),
|
|
334
|
+
INDEX \`id_name_string\` USING BTREE (\`name\`(255), \`string\`(512)),
|
|
335
|
+
INDEX \`id_name_number\` USING BTREE (\`name\`(255), \`number\`),
|
|
336
|
+
INDEX \`id_guid_name_number\` USING BTREE (\`guid\`, \`name\`(255), \`number\`),
|
|
337
|
+
INDEX \`id_name_truthy\` USING HASH (\`name\`(255), \`truthy\`),
|
|
338
|
+
INDEX \`id_guid_name_truthy\` USING HASH (\`guid\`, \`name\`(255), \`truthy\`)
|
|
246
339
|
) ENGINE ${this.config.engine}
|
|
247
|
-
CHARACTER SET
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
340
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`,
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private async createReferencesTable(etype: string) {
|
|
345
|
+
let foreignKey = '';
|
|
346
|
+
if (this.config.foreignKeys) {
|
|
347
|
+
foreignKey = ` REFERENCES ${MySQLDriver.escape(
|
|
348
|
+
`${this.prefix}entities_${etype}`,
|
|
349
|
+
)}(\`guid\`) ON DELETE CASCADE`;
|
|
350
|
+
}
|
|
351
|
+
// Create the references table.
|
|
352
|
+
await this.queryRun(
|
|
353
|
+
`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(
|
|
354
|
+
`${this.prefix}references_${etype}`,
|
|
355
|
+
)} (
|
|
356
|
+
\`guid\` BINARY(12) NOT NULL${foreignKey},
|
|
255
357
|
\`name\` TEXT NOT NULL,
|
|
256
358
|
\`reference\` BINARY(12) NOT NULL,
|
|
257
359
|
PRIMARY KEY (\`guid\`, \`name\`(255), \`reference\`),
|
|
258
|
-
INDEX \`
|
|
360
|
+
INDEX \`id_guid\` USING HASH (\`guid\`),
|
|
361
|
+
INDEX \`id_name\` USING HASH (\`name\`(255)),
|
|
362
|
+
INDEX \`id_name_reference\` USING HASH (\`name\`(255), \`reference\`),
|
|
363
|
+
INDEX \`id_reference\` USING HASH (\`reference\`),
|
|
364
|
+
INDEX \`id_guid_name\` USING HASH (\`guid\`, \`name\`(255)),
|
|
365
|
+
INDEX \`id_guid_name_reference\` USING HASH (\`guid\`, \`name\`(255), \`reference\`),
|
|
366
|
+
INDEX \`id_reference_name_guid\` USING BTREE (\`reference\`, \`name\`(255), \`guid\`),
|
|
367
|
+
INDEX \`id_reference_guid_name\` USING BTREE (\`reference\`, \`guid\`, \`name\`(255))
|
|
259
368
|
) ENGINE ${this.config.engine}
|
|
260
|
-
CHARACTER SET
|
|
261
|
-
|
|
369
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`,
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
private async createTokensTable(etype: string) {
|
|
374
|
+
let foreignKey = '';
|
|
375
|
+
if (this.config.foreignKeys) {
|
|
376
|
+
foreignKey = ` REFERENCES ${MySQLDriver.escape(
|
|
377
|
+
`${this.prefix}entities_${etype}`,
|
|
378
|
+
)}(\`guid\`) ON DELETE CASCADE`;
|
|
379
|
+
}
|
|
380
|
+
// Create the tokens table.
|
|
381
|
+
await this.queryRun(
|
|
382
|
+
`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(
|
|
383
|
+
`${this.prefix}tokens_${etype}`,
|
|
384
|
+
)} (
|
|
385
|
+
\`guid\` BINARY(12) NOT NULL${foreignKey},
|
|
386
|
+
\`name\` TEXT NOT NULL,
|
|
387
|
+
\`token\` INT NOT NULL,
|
|
388
|
+
\`position\` INT UNSIGNED NOT NULL,
|
|
389
|
+
\`stem\` BOOLEAN NOT NULL,
|
|
390
|
+
PRIMARY KEY (\`guid\`, \`name\`(255), \`token\`, \`position\`),
|
|
391
|
+
INDEX \`id_guid_name_token_position\` USING HASH (\`guid\`, \`name\`(255), \`token\`, \`position\`),
|
|
392
|
+
INDEX \`id_name_token\` USING btree (\`name\`(255), \`token\`)
|
|
393
|
+
) ENGINE ${this.config.engine}
|
|
394
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private async createUniquesTable(etype: string) {
|
|
399
|
+
let foreignKey = '';
|
|
400
|
+
if (this.config.foreignKeys) {
|
|
401
|
+
foreignKey = ` REFERENCES ${MySQLDriver.escape(
|
|
402
|
+
`${this.prefix}entities_${etype}`,
|
|
403
|
+
)}(\`guid\`) ON DELETE CASCADE`;
|
|
404
|
+
}
|
|
405
|
+
// Create the unique strings table.
|
|
406
|
+
// 255 key is max length for charset UTF8.
|
|
407
|
+
await this.queryRun(
|
|
408
|
+
`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(
|
|
409
|
+
`${this.prefix}uniques_${etype}`,
|
|
410
|
+
)} (
|
|
411
|
+
\`guid\` BINARY(12) NOT NULL${foreignKey},
|
|
412
|
+
\`unique\` TEXT NOT NULL,
|
|
413
|
+
PRIMARY KEY (\`guid\`, \`unique\`(255)),
|
|
414
|
+
INDEX \`id_guid\` USING HASH (\`guid\`),
|
|
415
|
+
CONSTRAINT \`uc_unique\` UNIQUE (\`unique\`(255))
|
|
416
|
+
) ENGINE ${this.config.engine}
|
|
417
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Create entity tables in the database.
|
|
423
|
+
*
|
|
424
|
+
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
425
|
+
* @returns True on success, false on failure.
|
|
426
|
+
*/
|
|
427
|
+
private async createTables(etype: string | null = null) {
|
|
428
|
+
await this.queryRun('SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";');
|
|
429
|
+
if (etype != null) {
|
|
430
|
+
await this.createEntitiesTable(etype);
|
|
431
|
+
await this.createDataTable(etype);
|
|
432
|
+
await this.createReferencesTable(etype);
|
|
433
|
+
await this.createTokensTable(etype);
|
|
434
|
+
await this.createUniquesTable(etype);
|
|
262
435
|
} else {
|
|
263
436
|
// Create the UID table.
|
|
264
|
-
this.
|
|
437
|
+
await this.queryRun(
|
|
265
438
|
`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(
|
|
266
|
-
`${this.prefix}uids
|
|
439
|
+
`${this.prefix}uids`,
|
|
267
440
|
)} (
|
|
268
441
|
\`name\` TEXT NOT NULL,
|
|
269
442
|
\`cur_uid\` BIGINT(20) UNSIGNED NOT NULL,
|
|
270
443
|
PRIMARY KEY (\`name\`(100))
|
|
271
444
|
) ENGINE ${this.config.engine}
|
|
272
|
-
CHARACTER SET
|
|
445
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`,
|
|
273
446
|
);
|
|
274
447
|
}
|
|
448
|
+
if (
|
|
449
|
+
this.transaction &&
|
|
450
|
+
this.transaction.count > 0 &&
|
|
451
|
+
this.config.transactions
|
|
452
|
+
) {
|
|
453
|
+
this.transaction.count = 0;
|
|
454
|
+
this.transaction.connection?.release();
|
|
455
|
+
this.transaction.connection = null;
|
|
456
|
+
this.transaction = null;
|
|
457
|
+
}
|
|
275
458
|
return true;
|
|
276
459
|
}
|
|
277
460
|
|
|
278
461
|
private translateQuery(
|
|
279
462
|
origQuery: string,
|
|
280
|
-
origParams: { [k: string]: any }
|
|
463
|
+
origParams: { [k: string]: any },
|
|
281
464
|
): { query: string; params: any[] } {
|
|
282
465
|
const params: any[] = [];
|
|
283
466
|
let query = origQuery;
|
|
@@ -296,32 +479,37 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
296
479
|
private async query<T extends () => any>(
|
|
297
480
|
runQuery: T,
|
|
298
481
|
query: string,
|
|
299
|
-
etypes: string[] = []
|
|
482
|
+
etypes: string[] = [],
|
|
300
483
|
// @ts-ignore: The return type of T is a promise.
|
|
301
484
|
): ReturnType<T> {
|
|
302
485
|
try {
|
|
486
|
+
this.nymph.config.debugInfo('mysql:query', query);
|
|
303
487
|
return await runQuery();
|
|
304
488
|
} catch (e: any) {
|
|
305
489
|
const errorCode = e?.errno;
|
|
306
|
-
if (errorCode === 1146 && this.createTables()) {
|
|
490
|
+
if (errorCode === 1146 && (await this.createTables())) {
|
|
307
491
|
// If the tables don't exist yet, create them.
|
|
308
492
|
for (let etype of etypes) {
|
|
309
|
-
this.createTables(etype);
|
|
493
|
+
await this.createTables(etype);
|
|
310
494
|
}
|
|
311
495
|
try {
|
|
312
496
|
return await runQuery();
|
|
313
497
|
} catch (e2: any) {
|
|
314
498
|
throw new QueryFailedError(
|
|
315
499
|
'Query failed: ' + e2?.errno + ' - ' + e2?.message,
|
|
316
|
-
query
|
|
500
|
+
query,
|
|
501
|
+
e2?.errno,
|
|
317
502
|
);
|
|
318
503
|
}
|
|
504
|
+
} else if (errorCode === 1062) {
|
|
505
|
+
throw new EntityUniqueConstraintError(`Unique constraint violation.`);
|
|
319
506
|
} else if (errorCode === 2006) {
|
|
320
507
|
// If the MySQL server disconnected, reconnect to it.
|
|
321
508
|
if (!this.connect()) {
|
|
322
509
|
throw new QueryFailedError(
|
|
323
510
|
'Query failed: ' + e?.errno + ' - ' + e?.message,
|
|
324
|
-
query
|
|
511
|
+
query,
|
|
512
|
+
e?.errno,
|
|
325
513
|
);
|
|
326
514
|
}
|
|
327
515
|
try {
|
|
@@ -329,60 +517,21 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
329
517
|
} catch (e2: any) {
|
|
330
518
|
throw new QueryFailedError(
|
|
331
519
|
'Query failed: ' + e2?.errno + ' - ' + e2?.message,
|
|
332
|
-
query
|
|
333
|
-
|
|
334
|
-
}
|
|
335
|
-
} else {
|
|
336
|
-
throw e;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
private querySync<T extends () => any>(
|
|
342
|
-
runQuery: T,
|
|
343
|
-
query: string,
|
|
344
|
-
etypes: string[] = []
|
|
345
|
-
): ReturnType<T> {
|
|
346
|
-
try {
|
|
347
|
-
return runQuery();
|
|
348
|
-
} catch (e: any) {
|
|
349
|
-
const errorCode = e?.errno;
|
|
350
|
-
if (errorCode === 1146 && this.createTables()) {
|
|
351
|
-
// If the tables don't exist yet, create them.
|
|
352
|
-
for (let etype of etypes) {
|
|
353
|
-
this.createTables(etype);
|
|
354
|
-
}
|
|
355
|
-
try {
|
|
356
|
-
return runQuery();
|
|
357
|
-
} catch (e2: any) {
|
|
358
|
-
throw new QueryFailedError(
|
|
359
|
-
'Query failed: ' + e2?.errno + ' - ' + e2?.message,
|
|
360
|
-
query
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
} else if (errorCode === 2006) {
|
|
364
|
-
// If the MySQL server disconnected, reconnect to it.
|
|
365
|
-
if (!this.connect()) {
|
|
366
|
-
throw new QueryFailedError(
|
|
367
|
-
'Query failed: ' + e?.errno + ' - ' + e?.message,
|
|
368
|
-
query
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
try {
|
|
372
|
-
return runQuery();
|
|
373
|
-
} catch (e2: any) {
|
|
374
|
-
throw new QueryFailedError(
|
|
375
|
-
'Query failed: ' + e2?.errno + ' - ' + e2?.message,
|
|
376
|
-
query
|
|
520
|
+
query,
|
|
521
|
+
e2?.errno,
|
|
377
522
|
);
|
|
378
523
|
}
|
|
379
524
|
} else {
|
|
380
|
-
throw
|
|
525
|
+
throw new QueryFailedError(
|
|
526
|
+
'Query failed: ' + e?.errno + ' - ' + e?.message,
|
|
527
|
+
query,
|
|
528
|
+
e?.errno,
|
|
529
|
+
);
|
|
381
530
|
}
|
|
382
531
|
}
|
|
383
532
|
}
|
|
384
533
|
|
|
385
|
-
private
|
|
534
|
+
private queryArray(
|
|
386
535
|
query: string,
|
|
387
536
|
{
|
|
388
537
|
etypes = [],
|
|
@@ -390,11 +539,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
390
539
|
}: {
|
|
391
540
|
etypes?: string[];
|
|
392
541
|
params?: { [k: string]: any };
|
|
393
|
-
} = {}
|
|
542
|
+
} = {},
|
|
394
543
|
) {
|
|
395
544
|
const { query: newQuery, params: newParams } = this.translateQuery(
|
|
396
545
|
query,
|
|
397
|
-
params
|
|
546
|
+
params,
|
|
398
547
|
);
|
|
399
548
|
return this.query(
|
|
400
549
|
async () => {
|
|
@@ -408,7 +557,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
408
557
|
reject(error);
|
|
409
558
|
}
|
|
410
559
|
resolve(results);
|
|
411
|
-
}
|
|
560
|
+
},
|
|
412
561
|
);
|
|
413
562
|
} catch (e) {
|
|
414
563
|
reject(e);
|
|
@@ -417,55 +566,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
417
566
|
return results;
|
|
418
567
|
},
|
|
419
568
|
`${query} -- ${JSON.stringify(params)}`,
|
|
420
|
-
etypes
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
private queryIterSync(
|
|
425
|
-
query: string,
|
|
426
|
-
{
|
|
427
|
-
etypes = [],
|
|
428
|
-
params = {},
|
|
429
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
430
|
-
) {
|
|
431
|
-
const { query: newQuery, params: newParams } = this.translateQuery(
|
|
432
|
-
query,
|
|
433
|
-
params
|
|
434
|
-
);
|
|
435
|
-
return this.querySync(
|
|
436
|
-
() => {
|
|
437
|
-
const output = cp.spawnSync(
|
|
438
|
-
process.argv0,
|
|
439
|
-
[__dirname + '/runMysqlSync.js'],
|
|
440
|
-
{
|
|
441
|
-
input: JSON.stringify({
|
|
442
|
-
mysqlConfig: this.mysqlConfig,
|
|
443
|
-
query: newQuery,
|
|
444
|
-
params: newParams,
|
|
445
|
-
}),
|
|
446
|
-
timeout: 30000,
|
|
447
|
-
maxBuffer: 100 * 1024 * 1024,
|
|
448
|
-
encoding: 'utf8',
|
|
449
|
-
windowsHide: true,
|
|
450
|
-
}
|
|
451
|
-
);
|
|
452
|
-
try {
|
|
453
|
-
const { results } = JSON.parse(output.stdout);
|
|
454
|
-
return results;
|
|
455
|
-
} catch (e) {
|
|
456
|
-
// Do nothing.
|
|
457
|
-
}
|
|
458
|
-
if (output.status === 0) {
|
|
459
|
-
throw new Error('Unknown parse error.');
|
|
460
|
-
}
|
|
461
|
-
const err = JSON.parse(output.stderr);
|
|
462
|
-
const e = new Error(err.name);
|
|
463
|
-
for (const name in err) {
|
|
464
|
-
(e as any)[name] = err[name];
|
|
465
|
-
}
|
|
466
|
-
},
|
|
467
|
-
`${query} -- ${JSON.stringify(params)}`,
|
|
468
|
-
etypes
|
|
569
|
+
etypes,
|
|
469
570
|
);
|
|
470
571
|
}
|
|
471
572
|
|
|
@@ -477,11 +578,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
477
578
|
}: {
|
|
478
579
|
etypes?: string[];
|
|
479
580
|
params?: { [k: string]: any };
|
|
480
|
-
} = {}
|
|
581
|
+
} = {},
|
|
481
582
|
) {
|
|
482
583
|
const { query: newQuery, params: newParams } = this.translateQuery(
|
|
483
584
|
query,
|
|
484
|
-
params
|
|
585
|
+
params,
|
|
485
586
|
);
|
|
486
587
|
return this.query(
|
|
487
588
|
async () => {
|
|
@@ -495,7 +596,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
495
596
|
reject(error);
|
|
496
597
|
}
|
|
497
598
|
resolve(results);
|
|
498
|
-
}
|
|
599
|
+
},
|
|
499
600
|
);
|
|
500
601
|
} catch (e) {
|
|
501
602
|
reject(e);
|
|
@@ -504,7 +605,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
504
605
|
return results[0];
|
|
505
606
|
},
|
|
506
607
|
`${query} -- ${JSON.stringify(params)}`,
|
|
507
|
-
etypes
|
|
608
|
+
etypes,
|
|
508
609
|
);
|
|
509
610
|
}
|
|
510
611
|
|
|
@@ -516,11 +617,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
516
617
|
}: {
|
|
517
618
|
etypes?: string[];
|
|
518
619
|
params?: { [k: string]: any };
|
|
519
|
-
} = {}
|
|
620
|
+
} = {},
|
|
520
621
|
) {
|
|
521
622
|
const { query: newQuery, params: newParams } = this.translateQuery(
|
|
522
623
|
query,
|
|
523
|
-
params
|
|
624
|
+
params,
|
|
524
625
|
);
|
|
525
626
|
return this.query(
|
|
526
627
|
async () => {
|
|
@@ -534,7 +635,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
534
635
|
reject(error);
|
|
535
636
|
}
|
|
536
637
|
resolve(results);
|
|
537
|
-
}
|
|
638
|
+
},
|
|
538
639
|
);
|
|
539
640
|
} catch (e) {
|
|
540
641
|
reject(e);
|
|
@@ -543,62 +644,14 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
543
644
|
return { changes: results.changedRows ?? 0 };
|
|
544
645
|
},
|
|
545
646
|
`${query} -- ${JSON.stringify(params)}`,
|
|
546
|
-
etypes
|
|
547
|
-
);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
private queryRunSync(
|
|
551
|
-
query: string,
|
|
552
|
-
{
|
|
553
|
-
etypes = [],
|
|
554
|
-
params = {},
|
|
555
|
-
}: { etypes?: string[]; params?: { [k: string]: any } } = {}
|
|
556
|
-
) {
|
|
557
|
-
const { query: newQuery, params: newParams } = this.translateQuery(
|
|
558
|
-
query,
|
|
559
|
-
params
|
|
560
|
-
);
|
|
561
|
-
return this.querySync(
|
|
562
|
-
() => {
|
|
563
|
-
const output = cp.spawnSync(
|
|
564
|
-
process.argv0,
|
|
565
|
-
[__dirname + '/runMysqlSync.js'],
|
|
566
|
-
{
|
|
567
|
-
input: JSON.stringify({
|
|
568
|
-
mysqlConfig: this.mysqlConfig,
|
|
569
|
-
query: newQuery,
|
|
570
|
-
params: newParams,
|
|
571
|
-
}),
|
|
572
|
-
timeout: 30000,
|
|
573
|
-
maxBuffer: 100 * 1024 * 1024,
|
|
574
|
-
encoding: 'utf8',
|
|
575
|
-
windowsHide: true,
|
|
576
|
-
}
|
|
577
|
-
);
|
|
578
|
-
try {
|
|
579
|
-
const { results } = JSON.parse(output.stdout);
|
|
580
|
-
return { changes: results.changedRows ?? 0 };
|
|
581
|
-
} catch (e) {
|
|
582
|
-
// Do nothing.
|
|
583
|
-
}
|
|
584
|
-
if (output.status === 0) {
|
|
585
|
-
throw new Error('Unknown parse error.');
|
|
586
|
-
}
|
|
587
|
-
const err = JSON.parse(output.stderr);
|
|
588
|
-
const e = new Error(err.name);
|
|
589
|
-
for (const name in err) {
|
|
590
|
-
(e as any)[name] = err[name];
|
|
591
|
-
}
|
|
592
|
-
},
|
|
593
|
-
`${query} -- ${JSON.stringify(params)}`,
|
|
594
|
-
etypes
|
|
647
|
+
etypes,
|
|
595
648
|
);
|
|
596
649
|
}
|
|
597
650
|
|
|
598
651
|
public async commit(name: string) {
|
|
599
652
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
600
653
|
throw new InvalidParametersError(
|
|
601
|
-
'Transaction commit attempted without a name.'
|
|
654
|
+
'Transaction commit attempted without a name.',
|
|
602
655
|
);
|
|
603
656
|
}
|
|
604
657
|
if (!this.transaction || this.transaction.count === 0) {
|
|
@@ -620,7 +673,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
620
673
|
|
|
621
674
|
public async deleteEntityByID(
|
|
622
675
|
guid: string,
|
|
623
|
-
className?: EntityConstructor | string | null
|
|
676
|
+
className?: EntityConstructor | string | null,
|
|
624
677
|
) {
|
|
625
678
|
let EntityClass: EntityConstructor;
|
|
626
679
|
if (typeof className === 'string' || className == null) {
|
|
@@ -634,58 +687,71 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
634
687
|
try {
|
|
635
688
|
await this.queryRun(
|
|
636
689
|
`DELETE FROM ${MySQLDriver.escape(
|
|
637
|
-
`${this.prefix}entities_${etype}
|
|
690
|
+
`${this.prefix}entities_${etype}`,
|
|
638
691
|
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
639
692
|
{
|
|
640
693
|
etypes: [etype],
|
|
641
694
|
params: {
|
|
642
695
|
guid,
|
|
643
696
|
},
|
|
644
|
-
}
|
|
697
|
+
},
|
|
645
698
|
);
|
|
646
699
|
await this.queryRun(
|
|
647
700
|
`DELETE FROM ${MySQLDriver.escape(
|
|
648
|
-
`${this.prefix}data_${etype}
|
|
701
|
+
`${this.prefix}data_${etype}`,
|
|
649
702
|
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
650
703
|
{
|
|
651
704
|
etypes: [etype],
|
|
652
705
|
params: {
|
|
653
706
|
guid,
|
|
654
707
|
},
|
|
655
|
-
}
|
|
708
|
+
},
|
|
656
709
|
);
|
|
657
710
|
await this.queryRun(
|
|
658
711
|
`DELETE FROM ${MySQLDriver.escape(
|
|
659
|
-
`${this.prefix}
|
|
712
|
+
`${this.prefix}references_${etype}`,
|
|
660
713
|
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
661
714
|
{
|
|
662
715
|
etypes: [etype],
|
|
663
716
|
params: {
|
|
664
717
|
guid,
|
|
665
718
|
},
|
|
666
|
-
}
|
|
719
|
+
},
|
|
667
720
|
);
|
|
668
721
|
await this.queryRun(
|
|
669
722
|
`DELETE FROM ${MySQLDriver.escape(
|
|
670
|
-
`${this.prefix}
|
|
723
|
+
`${this.prefix}tokens_${etype}`,
|
|
671
724
|
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
672
725
|
{
|
|
673
726
|
etypes: [etype],
|
|
674
727
|
params: {
|
|
675
728
|
guid,
|
|
676
729
|
},
|
|
677
|
-
}
|
|
730
|
+
},
|
|
731
|
+
);
|
|
732
|
+
await this.queryRun(
|
|
733
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
734
|
+
`${this.prefix}uniques_${etype}`,
|
|
735
|
+
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
736
|
+
{
|
|
737
|
+
etypes: [etype],
|
|
738
|
+
params: {
|
|
739
|
+
guid,
|
|
740
|
+
},
|
|
741
|
+
},
|
|
678
742
|
);
|
|
679
|
-
await this.commit('nymph-delete');
|
|
680
|
-
// Remove any cached versions of this entity.
|
|
681
|
-
if (this.nymph.config.cache) {
|
|
682
|
-
this.cleanCache(guid);
|
|
683
|
-
}
|
|
684
|
-
return true;
|
|
685
743
|
} catch (e: any) {
|
|
744
|
+
this.nymph.config.debugError('mysql', `Delete entity error: "${e}"`);
|
|
686
745
|
await this.rollback('nymph-delete');
|
|
687
746
|
throw e;
|
|
688
747
|
}
|
|
748
|
+
|
|
749
|
+
await this.commit('nymph-delete');
|
|
750
|
+
// Remove any cached versions of this entity.
|
|
751
|
+
if (this.nymph.config.cache) {
|
|
752
|
+
this.cleanCache(guid);
|
|
753
|
+
}
|
|
754
|
+
return true;
|
|
689
755
|
}
|
|
690
756
|
|
|
691
757
|
public async deleteUID(name: string) {
|
|
@@ -694,101 +760,341 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
694
760
|
}
|
|
695
761
|
await this.queryRun(
|
|
696
762
|
`DELETE FROM ${MySQLDriver.escape(
|
|
697
|
-
`${this.prefix}uids
|
|
763
|
+
`${this.prefix}uids`,
|
|
698
764
|
)} WHERE \`name\`=@name;`,
|
|
699
765
|
{
|
|
700
766
|
params: {
|
|
701
767
|
name,
|
|
702
768
|
},
|
|
703
|
-
}
|
|
769
|
+
},
|
|
704
770
|
);
|
|
705
771
|
return true;
|
|
706
772
|
}
|
|
707
773
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
writeLine('');
|
|
715
|
-
|
|
716
|
-
writeLine('#');
|
|
717
|
-
writeLine('# UIDs');
|
|
718
|
-
writeLine('#');
|
|
719
|
-
writeLine('');
|
|
720
|
-
|
|
721
|
-
// Export UIDs.
|
|
722
|
-
let uids = await this.queryIter(
|
|
723
|
-
`SELECT * FROM ${MySQLDriver.escape(
|
|
724
|
-
`${this.prefix}uids`
|
|
725
|
-
)} ORDER BY \`name\`;`
|
|
726
|
-
);
|
|
727
|
-
for (const uid of uids) {
|
|
728
|
-
writeLine(`<${uid.name}>[${uid.cur_uid}]`);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
writeLine('');
|
|
732
|
-
writeLine('#');
|
|
733
|
-
writeLine('# Entities');
|
|
734
|
-
writeLine('#');
|
|
735
|
-
writeLine('');
|
|
774
|
+
public async getIndexes(etype: string) {
|
|
775
|
+
const indexes: {
|
|
776
|
+
scope: 'data' | 'references' | 'tokens';
|
|
777
|
+
name: string;
|
|
778
|
+
property: string;
|
|
779
|
+
}[] = [];
|
|
736
780
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
781
|
+
for (let [scope, suffix] of [
|
|
782
|
+
['data', '_json'],
|
|
783
|
+
['references', '_reference_guid'],
|
|
784
|
+
['tokens', '_token_position_stem'],
|
|
785
|
+
] as (
|
|
786
|
+
| ['data', '_json']
|
|
787
|
+
| ['references', '_reference_guid']
|
|
788
|
+
| ['tokens', '_token_position_stem']
|
|
789
|
+
)[]) {
|
|
790
|
+
const indexDefinitions = await this.queryArray(
|
|
791
|
+
`SHOW INDEXES FROM ${MySQLDriver.escape(
|
|
792
|
+
`${this.prefix}${scope}_${etype}`,
|
|
793
|
+
)} WHERE \`Key_name\` LIKE @pattern AND \`Seq_in_index\`=1;`,
|
|
794
|
+
{
|
|
795
|
+
params: {
|
|
796
|
+
pattern: `${this.prefix}${scope}_${etype}_id_custom_%${suffix}`,
|
|
797
|
+
},
|
|
798
|
+
},
|
|
799
|
+
);
|
|
800
|
+
for (const indexDefinition of indexDefinitions) {
|
|
801
|
+
indexes.push({
|
|
802
|
+
scope,
|
|
803
|
+
name: (indexDefinition.Key_name as string).substring(
|
|
804
|
+
`${this.prefix}${scope}_${etype}_id_custom_`.length,
|
|
805
|
+
indexDefinition.Key_name.length - suffix.length,
|
|
806
|
+
),
|
|
807
|
+
property:
|
|
808
|
+
((indexDefinition.Expression as string).match(
|
|
809
|
+
/\s*\(?\s*`?name`?\s*=\s*(?:\w*)\\*'(.*?)\\*'/,
|
|
810
|
+
) ?? [])[1] ?? '',
|
|
811
|
+
});
|
|
744
812
|
}
|
|
745
813
|
}
|
|
746
814
|
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
815
|
+
return indexes;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
public async addIndex(
|
|
819
|
+
etype: string,
|
|
820
|
+
definition: {
|
|
821
|
+
scope: 'data' | 'references' | 'tokens';
|
|
822
|
+
name: string;
|
|
823
|
+
property: string;
|
|
824
|
+
},
|
|
825
|
+
) {
|
|
826
|
+
this.checkIndexName(definition.name);
|
|
827
|
+
await this.deleteIndex(etype, definition.scope, definition.name);
|
|
828
|
+
if (definition.scope === 'data') {
|
|
829
|
+
await this.queryRun(
|
|
830
|
+
`CREATE INDEX ${MySQLDriver.escape(
|
|
831
|
+
`${this.prefix}data_${etype}_id_custom_${definition.name}_json`,
|
|
832
|
+
)} USING btree ON ${MySQLDriver.escape(
|
|
833
|
+
`${this.prefix}data_${etype}`,
|
|
834
|
+
)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), (CAST(\`json\` AS CHAR(512)) COLLATE utf8mb4_bin));`,
|
|
835
|
+
);
|
|
836
|
+
await this.queryRun(
|
|
837
|
+
`CREATE INDEX ${MySQLDriver.escape(
|
|
838
|
+
`${this.prefix}data_${etype}_id_custom_${definition.name}_string`,
|
|
839
|
+
)} USING btree ON ${MySQLDriver.escape(
|
|
840
|
+
`${this.prefix}data_${etype}`,
|
|
841
|
+
)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`string\`(512));`,
|
|
842
|
+
);
|
|
843
|
+
await this.queryRun(
|
|
844
|
+
`CREATE INDEX ${MySQLDriver.escape(
|
|
845
|
+
`${this.prefix}data_${etype}_id_custom_${definition.name}_number`,
|
|
846
|
+
)} USING btree ON ${MySQLDriver.escape(
|
|
847
|
+
`${this.prefix}data_${etype}`,
|
|
848
|
+
)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`number\`);`,
|
|
849
|
+
);
|
|
850
|
+
await this.queryRun(
|
|
851
|
+
`CREATE INDEX ${MySQLDriver.escape(
|
|
852
|
+
`${this.prefix}data_${etype}_id_custom_${definition.name}_truthy`,
|
|
853
|
+
)} USING btree ON ${MySQLDriver.escape(
|
|
854
|
+
`${this.prefix}data_${etype}`,
|
|
855
|
+
)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`truthy\`);`,
|
|
856
|
+
);
|
|
857
|
+
} else if (definition.scope === 'references') {
|
|
858
|
+
await this.queryRun(
|
|
859
|
+
`CREATE INDEX ${MySQLDriver.escape(
|
|
860
|
+
`${this.prefix}references_${etype}_id_custom_${definition.name}_reference_guid`,
|
|
861
|
+
)} USING btree ON ${MySQLDriver.escape(
|
|
862
|
+
`${this.prefix}references_${etype}`,
|
|
863
|
+
)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`reference\`, \`guid\`);`,
|
|
864
|
+
);
|
|
865
|
+
} else if (definition.scope === 'tokens') {
|
|
866
|
+
await this.queryRun(
|
|
867
|
+
`CREATE INDEX ${MySQLDriver.escape(
|
|
868
|
+
`${this.prefix}tokens_${etype}_id_custom_${definition.name}_token_position_stem`,
|
|
869
|
+
)} USING btree ON ${MySQLDriver.escape(
|
|
870
|
+
`${this.prefix}tokens_${etype}`,
|
|
871
|
+
)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`token\`, \`position\`, \`stem\`);`,
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
return true;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
public async deleteIndex(
|
|
878
|
+
etype: string,
|
|
879
|
+
scope: 'data' | 'references' | 'tokens',
|
|
880
|
+
name: string,
|
|
881
|
+
) {
|
|
882
|
+
this.checkIndexName(name);
|
|
883
|
+
try {
|
|
884
|
+
if (scope === 'data') {
|
|
885
|
+
await this.queryRun(
|
|
886
|
+
`DROP INDEX ${MySQLDriver.escape(
|
|
887
|
+
`${this.prefix}data_${etype}_id_custom_${name}_json`,
|
|
888
|
+
)} ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)};`,
|
|
889
|
+
);
|
|
890
|
+
await this.queryRun(
|
|
891
|
+
`DROP INDEX ${MySQLDriver.escape(
|
|
892
|
+
`${this.prefix}data_${etype}_id_custom_${name}_string`,
|
|
893
|
+
)} ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)};`,
|
|
894
|
+
);
|
|
895
|
+
await this.queryRun(
|
|
896
|
+
`DROP INDEX ${MySQLDriver.escape(
|
|
897
|
+
`${this.prefix}data_${etype}_id_custom_${name}_number`,
|
|
898
|
+
)} ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)};`,
|
|
899
|
+
);
|
|
900
|
+
await this.queryRun(
|
|
901
|
+
`DROP INDEX ${MySQLDriver.escape(
|
|
902
|
+
`${this.prefix}data_${etype}_id_custom_${name}_truthy`,
|
|
903
|
+
)} ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)};`,
|
|
904
|
+
);
|
|
905
|
+
} else if (scope === 'references') {
|
|
906
|
+
await this.queryRun(
|
|
907
|
+
`DROP INDEX ${MySQLDriver.escape(
|
|
908
|
+
`${this.prefix}references_${etype}_id_custom_${name}_reference_guid`,
|
|
909
|
+
)} ON ${MySQLDriver.escape(`${this.prefix}references_${etype}`)};`,
|
|
910
|
+
);
|
|
911
|
+
} else if (scope === 'tokens') {
|
|
912
|
+
await this.queryRun(
|
|
913
|
+
`DROP INDEX ${MySQLDriver.escape(
|
|
914
|
+
`${this.prefix}tokens_${etype}_id_custom_${name}_token_position_stem`,
|
|
915
|
+
)} ON ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)};`,
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
} catch (e: any) {
|
|
919
|
+
if (e?.errorCode !== 1091) {
|
|
920
|
+
throw e;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return true;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
public async getEtypes() {
|
|
927
|
+
const tables = await this.queryArray(
|
|
928
|
+
'SELECT `table_name` AS `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=@db AND `table_name` LIKE @prefix;',
|
|
929
|
+
{
|
|
930
|
+
params: {
|
|
931
|
+
db: this.config.database,
|
|
932
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
933
|
+
},
|
|
934
|
+
},
|
|
935
|
+
);
|
|
936
|
+
const etypes: string[] = [];
|
|
937
|
+
for (const table of tables) {
|
|
938
|
+
etypes.push(table.table_name.substr((this.prefix + 'entities_').length));
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
return etypes;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
public async *exportDataIterator(): AsyncGenerator<
|
|
945
|
+
{ type: 'comment' | 'uid' | 'entity'; content: string },
|
|
946
|
+
void,
|
|
947
|
+
false | undefined
|
|
948
|
+
> {
|
|
949
|
+
if (
|
|
950
|
+
yield {
|
|
951
|
+
type: 'comment',
|
|
952
|
+
content: `#nex2
|
|
953
|
+
# Nymph Entity Exchange v2
|
|
954
|
+
# http://nymph.io
|
|
955
|
+
#
|
|
956
|
+
# Generation Time: ${new Date().toLocaleString()}
|
|
957
|
+
`,
|
|
958
|
+
}
|
|
959
|
+
) {
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
if (
|
|
964
|
+
yield {
|
|
965
|
+
type: 'comment',
|
|
966
|
+
content: `
|
|
967
|
+
|
|
968
|
+
#
|
|
969
|
+
# UIDs
|
|
970
|
+
#
|
|
971
|
+
|
|
972
|
+
`,
|
|
973
|
+
}
|
|
974
|
+
) {
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// Export UIDs.
|
|
979
|
+
let uids = await this.queryArray(
|
|
980
|
+
`SELECT * FROM ${MySQLDriver.escape(
|
|
981
|
+
`${this.prefix}uids`,
|
|
982
|
+
)} ORDER BY \`name\`;`,
|
|
983
|
+
);
|
|
984
|
+
for (const uid of uids) {
|
|
985
|
+
if (yield { type: 'uid', content: `<${uid.name}>[${uid.cur_uid}]\n` }) {
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
if (
|
|
991
|
+
yield {
|
|
992
|
+
type: 'comment',
|
|
993
|
+
content: `
|
|
994
|
+
|
|
995
|
+
#
|
|
996
|
+
# Entities
|
|
997
|
+
#
|
|
998
|
+
|
|
999
|
+
`,
|
|
1000
|
+
}
|
|
1001
|
+
) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// Get the etypes.
|
|
1006
|
+
const etypes = await this.getEtypes();
|
|
1007
|
+
|
|
1008
|
+
for (const etype of etypes) {
|
|
1009
|
+
// Export entities.
|
|
1010
|
+
const dataIterator = (
|
|
1011
|
+
await this.queryArray(
|
|
1012
|
+
`SELECT LOWER(HEX(e.\`guid\`)) AS \`guid\`, e.\`tags\`, e.\`cdate\`, e.\`mdate\`, LOWER(HEX(e.\`user\`)) AS \`user\`, LOWER(HEX(e.\`group\`)) AS \`group\`, e.\`acUser\`, e.\`acGroup\`, e.\`acOther\`, e.\`acRead\`, e.\`acWrite\`, e.\`acFull\`, d.\`name\`, d.\`value\`, d.\`json\`, d.\`string\`, d.\`number\`
|
|
1013
|
+
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} e
|
|
1014
|
+
LEFT JOIN ${MySQLDriver.escape(
|
|
1015
|
+
`${this.prefix}data_${etype}`,
|
|
1016
|
+
)} d ON e.\`guid\`=d.\`guid\`
|
|
1017
|
+
ORDER BY e.\`guid\`;`,
|
|
760
1018
|
)
|
|
761
1019
|
)[Symbol.iterator]();
|
|
762
1020
|
let datum = dataIterator.next();
|
|
763
1021
|
while (!datum.done) {
|
|
764
1022
|
const guid = datum.value.guid;
|
|
765
|
-
const tags = datum.value.tags
|
|
1023
|
+
const tags = datum.value.tags
|
|
1024
|
+
.slice(1, -1)
|
|
1025
|
+
.split(' ')
|
|
1026
|
+
.filter((tag: string) => tag)
|
|
1027
|
+
.join(',');
|
|
766
1028
|
const cdate = datum.value.cdate;
|
|
767
1029
|
const mdate = datum.value.mdate;
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1030
|
+
const user = datum.value.user;
|
|
1031
|
+
const group = datum.value.group;
|
|
1032
|
+
const acUser = datum.value.acUser;
|
|
1033
|
+
const acGroup = datum.value.acGroup;
|
|
1034
|
+
const acOther = datum.value.acOther;
|
|
1035
|
+
const acRead = datum.value.acRead?.slice(1, -1).split(' ');
|
|
1036
|
+
const acWrite = datum.value.acWrite?.slice(1, -1).split(' ');
|
|
1037
|
+
const acFull = datum.value.acFull?.slice(1, -1).split(' ');
|
|
1038
|
+
let currentEntityExport: string[] = [];
|
|
1039
|
+
currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
|
|
1040
|
+
currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
|
|
1041
|
+
currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
|
|
1042
|
+
if (this.nymph.tilmeld != null) {
|
|
1043
|
+
if (user != null) {
|
|
1044
|
+
currentEntityExport.push(
|
|
1045
|
+
`\tuser=${JSON.stringify(['nymph_entity_reference', user, 'User'])}`,
|
|
1046
|
+
);
|
|
1047
|
+
}
|
|
1048
|
+
if (group != null) {
|
|
1049
|
+
currentEntityExport.push(
|
|
1050
|
+
`\tgroup=${JSON.stringify(['nymph_entity_reference', group, 'Group'])}`,
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
if (acUser != null) {
|
|
1054
|
+
currentEntityExport.push(`\tacUser=${JSON.stringify(acUser)}`);
|
|
1055
|
+
}
|
|
1056
|
+
if (acGroup != null) {
|
|
1057
|
+
currentEntityExport.push(`\tacGroup=${JSON.stringify(acGroup)}`);
|
|
1058
|
+
}
|
|
1059
|
+
if (acOther != null) {
|
|
1060
|
+
currentEntityExport.push(`\tacOther=${JSON.stringify(acOther)}`);
|
|
1061
|
+
}
|
|
1062
|
+
if (acRead != null) {
|
|
1063
|
+
currentEntityExport.push(`\tacRead=${JSON.stringify(acRead)}`);
|
|
1064
|
+
}
|
|
1065
|
+
if (acWrite != null) {
|
|
1066
|
+
currentEntityExport.push(`\tacWrite=${JSON.stringify(acWrite)}`);
|
|
1067
|
+
}
|
|
1068
|
+
if (acFull != null) {
|
|
1069
|
+
currentEntityExport.push(`\tacFull=${JSON.stringify(acFull)}`);
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
if (datum.value.name != null) {
|
|
772
1073
|
// This do will keep going and adding the data until the
|
|
773
1074
|
// next entity is reached. $row will end on the next entity.
|
|
774
1075
|
do {
|
|
775
1076
|
const value =
|
|
776
|
-
datum.value.
|
|
1077
|
+
datum.value.value === 'N'
|
|
777
1078
|
? JSON.stringify(datum.value.number)
|
|
778
|
-
: datum.value.
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1079
|
+
: datum.value.value === 'S'
|
|
1080
|
+
? JSON.stringify(datum.value.string)
|
|
1081
|
+
: datum.value.value === 'J'
|
|
1082
|
+
? JSON.stringify(datum.value.json)
|
|
1083
|
+
: datum.value.value;
|
|
1084
|
+
currentEntityExport.push(`\t${datum.value.name}=${value}`);
|
|
782
1085
|
datum = dataIterator.next();
|
|
783
1086
|
} while (!datum.done && datum.value.guid === guid);
|
|
784
1087
|
} else {
|
|
785
1088
|
// Make sure that datum is incremented :)
|
|
786
1089
|
datum = dataIterator.next();
|
|
787
1090
|
}
|
|
1091
|
+
currentEntityExport.push('');
|
|
1092
|
+
|
|
1093
|
+
if (yield { type: 'entity', content: currentEntityExport.join('\n') }) {
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
788
1096
|
}
|
|
789
1097
|
}
|
|
790
|
-
|
|
791
|
-
return;
|
|
792
1098
|
}
|
|
793
1099
|
|
|
794
1100
|
/**
|
|
@@ -809,21 +1115,23 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
809
1115
|
params: { [k: string]: any } = {},
|
|
810
1116
|
subquery = false,
|
|
811
1117
|
tableSuffix = '',
|
|
812
|
-
etypes: string[] = []
|
|
1118
|
+
etypes: string[] = [],
|
|
1119
|
+
guidSelector: string | undefined = undefined,
|
|
1120
|
+
guidExplicitSelector: ((guid: string) => string) | undefined = undefined,
|
|
813
1121
|
) {
|
|
814
1122
|
if (typeof options.class?.alterOptions === 'function') {
|
|
815
1123
|
options = options.class.alterOptions(options);
|
|
816
1124
|
}
|
|
817
1125
|
const eTable = `e${tableSuffix}`;
|
|
818
1126
|
const dTable = `d${tableSuffix}`;
|
|
819
|
-
const cTable = `c${tableSuffix}`;
|
|
820
1127
|
const fTable = `f${tableSuffix}`;
|
|
821
1128
|
const ieTable = `ie${tableSuffix}`;
|
|
822
1129
|
const countTable = `count${tableSuffix}`;
|
|
823
|
-
const
|
|
1130
|
+
const sTable = `s${tableSuffix}`;
|
|
1131
|
+
const sort = options.sort === undefined ? 'cdate' : options.sort;
|
|
824
1132
|
const queryParts = this.iterateSelectorsForQuery(
|
|
825
1133
|
formattedSelectors,
|
|
826
|
-
(key, value, typeIsOr, typeIsNot) => {
|
|
1134
|
+
({ key, value, typeIsOr, typeIsNot }) => {
|
|
827
1135
|
const clauseNot = key.startsWith('!');
|
|
828
1136
|
let curQuery = '';
|
|
829
1137
|
for (const curValue of value) {
|
|
@@ -885,17 +1193,39 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
885
1193
|
if (curQuery) {
|
|
886
1194
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
887
1195
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1196
|
+
if (
|
|
1197
|
+
curVar === 'cdate' ||
|
|
1198
|
+
curVar === 'mdate' ||
|
|
1199
|
+
(this.nymph.tilmeld != null &&
|
|
1200
|
+
(curVar === 'user' ||
|
|
1201
|
+
curVar === 'group' ||
|
|
1202
|
+
curVar === 'acUser' ||
|
|
1203
|
+
curVar === 'acGroup' ||
|
|
1204
|
+
curVar === 'acOther' ||
|
|
1205
|
+
curVar === 'acRead' ||
|
|
1206
|
+
curVar === 'acWrite' ||
|
|
1207
|
+
curVar === 'acFull'))
|
|
1208
|
+
) {
|
|
1209
|
+
curQuery +=
|
|
1210
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1211
|
+
'(' +
|
|
1212
|
+
ieTable +
|
|
1213
|
+
'.' +
|
|
1214
|
+
MySQLDriver.escape(curVar) +
|
|
1215
|
+
' IS NOT NULL)';
|
|
1216
|
+
} else {
|
|
1217
|
+
const name = `param${++count.i}`;
|
|
1218
|
+
curQuery +=
|
|
1219
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1220
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1221
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1222
|
+
' WHERE `guid`=' +
|
|
1223
|
+
ieTable +
|
|
1224
|
+
'.`guid` AND `name`=@' +
|
|
1225
|
+
name +
|
|
1226
|
+
')';
|
|
1227
|
+
params[name] = curVar;
|
|
1228
|
+
}
|
|
899
1229
|
}
|
|
900
1230
|
break;
|
|
901
1231
|
case 'truthy':
|
|
@@ -904,28 +1234,35 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
904
1234
|
if (curQuery) {
|
|
905
1235
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
906
1236
|
}
|
|
907
|
-
if (
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
1237
|
+
if (
|
|
1238
|
+
curVar === 'cdate' ||
|
|
1239
|
+
curVar === 'mdate' ||
|
|
1240
|
+
(this.nymph.tilmeld != null &&
|
|
1241
|
+
(curVar === 'user' ||
|
|
1242
|
+
curVar === 'group' ||
|
|
1243
|
+
curVar === 'acUser' ||
|
|
1244
|
+
curVar === 'acGroup' ||
|
|
1245
|
+
curVar === 'acOther' ||
|
|
1246
|
+
curVar === 'acRead' ||
|
|
1247
|
+
curVar === 'acWrite' ||
|
|
1248
|
+
curVar === 'acFull'))
|
|
1249
|
+
) {
|
|
915
1250
|
curQuery +=
|
|
916
1251
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
917
1252
|
'(' +
|
|
918
1253
|
ieTable +
|
|
919
|
-
'
|
|
920
|
-
|
|
1254
|
+
'.' +
|
|
1255
|
+
MySQLDriver.escape(curVar) +
|
|
1256
|
+
' IS NOT NULL)';
|
|
921
1257
|
} else {
|
|
922
1258
|
const name = `param${++count.i}`;
|
|
923
1259
|
curQuery +=
|
|
924
1260
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1261
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1262
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1263
|
+
' WHERE `guid`=' +
|
|
925
1264
|
ieTable +
|
|
926
|
-
'.`guid`
|
|
927
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
928
|
-
' WHERE `name`=@' +
|
|
1265
|
+
'.`guid` AND `name`=@' +
|
|
929
1266
|
name +
|
|
930
1267
|
' AND `truthy`=TRUE)';
|
|
931
1268
|
params[name] = curVar;
|
|
@@ -934,34 +1271,65 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
934
1271
|
break;
|
|
935
1272
|
case 'equal':
|
|
936
1273
|
case '!equal':
|
|
937
|
-
if (
|
|
1274
|
+
if (
|
|
1275
|
+
curValue[0] === 'cdate' ||
|
|
1276
|
+
curValue[0] === 'mdate' ||
|
|
1277
|
+
(this.nymph.tilmeld != null &&
|
|
1278
|
+
(curValue[0] === 'acUser' ||
|
|
1279
|
+
curValue[0] === 'acGroup' ||
|
|
1280
|
+
curValue[0] === 'acOther'))
|
|
1281
|
+
) {
|
|
938
1282
|
if (curQuery) {
|
|
939
1283
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
940
1284
|
}
|
|
941
|
-
const
|
|
1285
|
+
const value = `param${++count.i}`;
|
|
942
1286
|
curQuery +=
|
|
943
1287
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
944
1288
|
ieTable +
|
|
945
|
-
'
|
|
946
|
-
|
|
947
|
-
|
|
1289
|
+
'.' +
|
|
1290
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1291
|
+
'=@' +
|
|
1292
|
+
value;
|
|
1293
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
948
1294
|
? null
|
|
949
1295
|
: Number(curValue[1]);
|
|
950
|
-
|
|
951
|
-
|
|
1296
|
+
} else if (
|
|
1297
|
+
this.nymph.tilmeld != null &&
|
|
1298
|
+
(curValue[0] === 'user' || curValue[0] === 'group')
|
|
1299
|
+
) {
|
|
952
1300
|
if (curQuery) {
|
|
953
1301
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
954
1302
|
}
|
|
955
|
-
const
|
|
1303
|
+
const value = `param${++count.i}`;
|
|
956
1304
|
curQuery +=
|
|
957
1305
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
958
1306
|
ieTable +
|
|
959
|
-
'
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1307
|
+
'.' +
|
|
1308
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1309
|
+
'=UNHEX(@' +
|
|
1310
|
+
value +
|
|
1311
|
+
')';
|
|
1312
|
+
params[value] = `${curValue[1]}`;
|
|
1313
|
+
} else if (
|
|
1314
|
+
this.nymph.tilmeld != null &&
|
|
1315
|
+
(curValue[0] === 'acRead' ||
|
|
1316
|
+
curValue[0] === 'acWrite' ||
|
|
1317
|
+
curValue[0] === 'acFull')
|
|
1318
|
+
) {
|
|
1319
|
+
if (curQuery) {
|
|
1320
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1321
|
+
}
|
|
1322
|
+
const value = `param${++count.i}`;
|
|
1323
|
+
curQuery +=
|
|
1324
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1325
|
+
ieTable +
|
|
1326
|
+
'.' +
|
|
1327
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1328
|
+
'=@' +
|
|
1329
|
+
value;
|
|
1330
|
+
params[value] = Array.isArray(curValue[1])
|
|
1331
|
+
? ' ' + curValue[1].join(' ') + ' '
|
|
1332
|
+
: '';
|
|
965
1333
|
} else if (typeof curValue[1] === 'number') {
|
|
966
1334
|
if (curQuery) {
|
|
967
1335
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -970,10 +1338,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
970
1338
|
const value = `param${++count.i}`;
|
|
971
1339
|
curQuery +=
|
|
972
1340
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1341
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1342
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1343
|
+
' WHERE `guid`=' +
|
|
973
1344
|
ieTable +
|
|
974
|
-
'.`guid`
|
|
975
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
976
|
-
' WHERE `name`=@' +
|
|
1345
|
+
'.`guid` AND `name`=@' +
|
|
977
1346
|
name +
|
|
978
1347
|
' AND `number`=@' +
|
|
979
1348
|
value +
|
|
@@ -988,10 +1357,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
988
1357
|
const value = `param${++count.i}`;
|
|
989
1358
|
curQuery +=
|
|
990
1359
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1360
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1361
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1362
|
+
' WHERE `guid`=' +
|
|
991
1363
|
ieTable +
|
|
992
|
-
'.`guid`
|
|
993
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
994
|
-
' WHERE `name`=@' +
|
|
1364
|
+
'.`guid` AND `name`=@' +
|
|
995
1365
|
name +
|
|
996
1366
|
' AND `string`=@' +
|
|
997
1367
|
value +
|
|
@@ -1013,136 +1383,313 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1013
1383
|
}
|
|
1014
1384
|
const name = `param${++count.i}`;
|
|
1015
1385
|
const value = `param${++count.i}`;
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1386
|
+
if (svalue.length < 512) {
|
|
1387
|
+
curQuery +=
|
|
1388
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1389
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1390
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1391
|
+
' WHERE `guid`=' +
|
|
1392
|
+
ieTable +
|
|
1393
|
+
'.`guid` AND `name`=@' +
|
|
1394
|
+
name +
|
|
1395
|
+
' AND (CAST(`json` AS CHAR(512)) COLLATE utf8mb4_bin)=CAST(CAST(@' +
|
|
1396
|
+
value +
|
|
1397
|
+
' AS JSON) AS CHAR(512)))';
|
|
1398
|
+
} else {
|
|
1399
|
+
curQuery +=
|
|
1400
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1401
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1402
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1403
|
+
' WHERE `guid`=' +
|
|
1404
|
+
ieTable +
|
|
1405
|
+
'.`guid` AND `name`=@' +
|
|
1406
|
+
name +
|
|
1407
|
+
' AND `json`=CAST(@' +
|
|
1408
|
+
value +
|
|
1409
|
+
' AS JSON))';
|
|
1410
|
+
}
|
|
1026
1411
|
params[name] = curValue[0];
|
|
1027
1412
|
params[value] = svalue;
|
|
1028
1413
|
}
|
|
1029
1414
|
break;
|
|
1030
1415
|
case 'contain':
|
|
1031
1416
|
case '!contain':
|
|
1032
|
-
if (
|
|
1417
|
+
if (
|
|
1418
|
+
curValue[0] === 'cdate' ||
|
|
1419
|
+
curValue[0] === 'mdate' ||
|
|
1420
|
+
(this.nymph.tilmeld != null &&
|
|
1421
|
+
(curValue[0] === 'acUser' ||
|
|
1422
|
+
curValue[0] === 'acGroup' ||
|
|
1423
|
+
curValue[0] === 'acOther'))
|
|
1424
|
+
) {
|
|
1033
1425
|
if (curQuery) {
|
|
1034
1426
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1035
1427
|
}
|
|
1036
|
-
const
|
|
1428
|
+
const value = `param${++count.i}`;
|
|
1037
1429
|
curQuery +=
|
|
1038
1430
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1039
1431
|
ieTable +
|
|
1040
|
-
'
|
|
1041
|
-
|
|
1042
|
-
|
|
1432
|
+
'.' +
|
|
1433
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1434
|
+
'=@' +
|
|
1435
|
+
value;
|
|
1436
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1043
1437
|
? null
|
|
1044
1438
|
: Number(curValue[1]);
|
|
1045
|
-
|
|
1046
|
-
|
|
1439
|
+
} else if (
|
|
1440
|
+
this.nymph.tilmeld != null &&
|
|
1441
|
+
(curValue[0] === 'user' || curValue[0] === 'group')
|
|
1442
|
+
) {
|
|
1047
1443
|
if (curQuery) {
|
|
1048
1444
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1049
1445
|
}
|
|
1050
|
-
const
|
|
1446
|
+
const value = `param${++count.i}`;
|
|
1051
1447
|
curQuery +=
|
|
1052
1448
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1053
1449
|
ieTable +
|
|
1054
|
-
'
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1450
|
+
'.' +
|
|
1451
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1452
|
+
'=UNHEX(@' +
|
|
1453
|
+
value +
|
|
1454
|
+
')';
|
|
1455
|
+
params[value] = `${curValue[1]}`;
|
|
1456
|
+
} else if (
|
|
1457
|
+
this.nymph.tilmeld != null &&
|
|
1458
|
+
(curValue[0] === 'acRead' ||
|
|
1459
|
+
curValue[0] === 'acWrite' ||
|
|
1460
|
+
curValue[0] === 'acFull')
|
|
1461
|
+
) {
|
|
1462
|
+
if (curQuery) {
|
|
1463
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1464
|
+
}
|
|
1465
|
+
const queryParam = `param${++count.i}`;
|
|
1466
|
+
curQuery +=
|
|
1467
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1468
|
+
'MATCH (' +
|
|
1469
|
+
ieTable +
|
|
1470
|
+
'.' +
|
|
1471
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1472
|
+
') AGAINST (@' +
|
|
1473
|
+
queryParam +
|
|
1474
|
+
' IN BOOLEAN MODE)';
|
|
1475
|
+
params[queryParam] = '+' + curValue[1];
|
|
1060
1476
|
} else {
|
|
1061
1477
|
if (curQuery) {
|
|
1062
1478
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1063
1479
|
}
|
|
1064
1480
|
let svalue: string;
|
|
1065
|
-
let stringValue: string;
|
|
1066
1481
|
if (
|
|
1067
1482
|
curValue[1] instanceof Object &&
|
|
1068
1483
|
typeof curValue[1].toReference === 'function'
|
|
1069
1484
|
) {
|
|
1070
1485
|
svalue = JSON.stringify(curValue[1].toReference());
|
|
1071
|
-
stringValue = `${curValue[1].toReference()}`;
|
|
1072
1486
|
} else {
|
|
1073
1487
|
svalue = JSON.stringify(curValue[1]);
|
|
1074
|
-
stringValue = `${curValue[1]}`;
|
|
1075
1488
|
}
|
|
1076
1489
|
const name = `param${++count.i}`;
|
|
1077
1490
|
const value = `param${++count.i}`;
|
|
1078
|
-
|
|
1079
|
-
|
|
1491
|
+
curQuery +=
|
|
1492
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1493
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1494
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1495
|
+
' WHERE `guid`=' +
|
|
1496
|
+
ieTable +
|
|
1497
|
+
'.`guid` AND `name`=@' +
|
|
1498
|
+
name +
|
|
1499
|
+
' AND JSON_CONTAINS(`json`, @' +
|
|
1500
|
+
value +
|
|
1501
|
+
'))';
|
|
1502
|
+
params[name] = curValue[0];
|
|
1503
|
+
params[value] = svalue;
|
|
1504
|
+
}
|
|
1505
|
+
break;
|
|
1506
|
+
case 'search':
|
|
1507
|
+
case '!search':
|
|
1508
|
+
if (
|
|
1509
|
+
curValue[0] === 'cdate' ||
|
|
1510
|
+
curValue[0] === 'mdate' ||
|
|
1511
|
+
(this.nymph.tilmeld != null &&
|
|
1512
|
+
(curValue[0] === 'user' ||
|
|
1513
|
+
curValue[0] === 'group' ||
|
|
1514
|
+
curValue[0] === 'acUser' ||
|
|
1515
|
+
curValue[0] === 'acGroup' ||
|
|
1516
|
+
curValue[0] === 'acOther' ||
|
|
1517
|
+
curValue[0] === 'acRead' ||
|
|
1518
|
+
curValue[0] === 'acWrite' ||
|
|
1519
|
+
curValue[0] === 'acFull'))
|
|
1520
|
+
) {
|
|
1521
|
+
if (curQuery) {
|
|
1522
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1523
|
+
}
|
|
1524
|
+
curQuery +=
|
|
1525
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(FALSE)';
|
|
1526
|
+
} else {
|
|
1527
|
+
if (curQuery) {
|
|
1528
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
const parsedFTSQuery = this.tokenizer.parseSearchQuery(
|
|
1532
|
+
curValue[1],
|
|
1533
|
+
);
|
|
1534
|
+
|
|
1535
|
+
if (!parsedFTSQuery.length) {
|
|
1080
1536
|
curQuery +=
|
|
1081
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1082
|
-
'(' +
|
|
1083
|
-
ieTable +
|
|
1084
|
-
'.`guid` IN (SELECT `guid` FROM ' +
|
|
1085
|
-
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1086
|
-
' WHERE `name`=@' +
|
|
1087
|
-
name +
|
|
1088
|
-
' AND INSTR(`value`, @' +
|
|
1089
|
-
value +
|
|
1090
|
-
')) OR ' +
|
|
1091
|
-
ieTable +
|
|
1092
|
-
'.`guid` IN (SELECT `guid` FROM ' +
|
|
1093
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1094
|
-
' WHERE `name`=@' +
|
|
1095
|
-
name +
|
|
1096
|
-
' AND `string`=@' +
|
|
1097
|
-
stringParam +
|
|
1098
|
-
'))';
|
|
1099
|
-
params[stringParam] = stringValue;
|
|
1537
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(FALSE)';
|
|
1100
1538
|
} else {
|
|
1539
|
+
const name = `param${++count.i}`;
|
|
1540
|
+
|
|
1541
|
+
const queryPartToken = (term: SearchTerm) => {
|
|
1542
|
+
const value = `param${++count.i}`;
|
|
1543
|
+
params[value] = term.token;
|
|
1544
|
+
return (
|
|
1545
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1546
|
+
MySQLDriver.escape(this.prefix + 'tokens_' + etype) +
|
|
1547
|
+
' WHERE `guid`=' +
|
|
1548
|
+
ieTable +
|
|
1549
|
+
'.`guid` AND `name`=@' +
|
|
1550
|
+
name +
|
|
1551
|
+
' AND `token`=@' +
|
|
1552
|
+
value +
|
|
1553
|
+
(term.nostemmed ? ' AND `stem`=FALSE' : '') +
|
|
1554
|
+
')'
|
|
1555
|
+
);
|
|
1556
|
+
};
|
|
1557
|
+
|
|
1558
|
+
const queryPartSeries = (series: SearchSeriesTerm) => {
|
|
1559
|
+
const tokenTableSuffix = makeTableSuffix();
|
|
1560
|
+
const tokenParts = series.tokens.map((token, i) => {
|
|
1561
|
+
const value = `param${++count.i}`;
|
|
1562
|
+
params[value] = token.token;
|
|
1563
|
+
return {
|
|
1564
|
+
fromClause:
|
|
1565
|
+
i === 0
|
|
1566
|
+
? 'FROM ' +
|
|
1567
|
+
MySQLDriver.escape(
|
|
1568
|
+
this.prefix + 'tokens_' + etype,
|
|
1569
|
+
) +
|
|
1570
|
+
' t' +
|
|
1571
|
+
tokenTableSuffix +
|
|
1572
|
+
'0'
|
|
1573
|
+
: 'JOIN ' +
|
|
1574
|
+
MySQLDriver.escape(
|
|
1575
|
+
this.prefix + 'tokens_' + etype,
|
|
1576
|
+
) +
|
|
1577
|
+
' t' +
|
|
1578
|
+
tokenTableSuffix +
|
|
1579
|
+
i +
|
|
1580
|
+
' ON t' +
|
|
1581
|
+
tokenTableSuffix +
|
|
1582
|
+
i +
|
|
1583
|
+
'.`guid` = t' +
|
|
1584
|
+
tokenTableSuffix +
|
|
1585
|
+
'0.`guid` AND t' +
|
|
1586
|
+
tokenTableSuffix +
|
|
1587
|
+
i +
|
|
1588
|
+
'.`name` = t' +
|
|
1589
|
+
tokenTableSuffix +
|
|
1590
|
+
'0.`name` AND t' +
|
|
1591
|
+
tokenTableSuffix +
|
|
1592
|
+
i +
|
|
1593
|
+
'.`position` = t' +
|
|
1594
|
+
tokenTableSuffix +
|
|
1595
|
+
'0.`position` + ' +
|
|
1596
|
+
i,
|
|
1597
|
+
whereClause:
|
|
1598
|
+
't' +
|
|
1599
|
+
tokenTableSuffix +
|
|
1600
|
+
i +
|
|
1601
|
+
'.`token`=@' +
|
|
1602
|
+
value +
|
|
1603
|
+
(token.nostemmed
|
|
1604
|
+
? ' AND t' + tokenTableSuffix + i + '.`stem`=FALSE'
|
|
1605
|
+
: ''),
|
|
1606
|
+
};
|
|
1607
|
+
});
|
|
1608
|
+
return (
|
|
1609
|
+
'EXISTS (SELECT t' +
|
|
1610
|
+
tokenTableSuffix +
|
|
1611
|
+
'0.`guid` ' +
|
|
1612
|
+
tokenParts.map((part) => part.fromClause).join(' ') +
|
|
1613
|
+
' WHERE t' +
|
|
1614
|
+
tokenTableSuffix +
|
|
1615
|
+
'0.`guid`=' +
|
|
1616
|
+
ieTable +
|
|
1617
|
+
'.`guid` AND t' +
|
|
1618
|
+
tokenTableSuffix +
|
|
1619
|
+
'0.`name`=@' +
|
|
1620
|
+
name +
|
|
1621
|
+
' AND ' +
|
|
1622
|
+
tokenParts.map((part) => part.whereClause).join(' AND ') +
|
|
1623
|
+
')'
|
|
1624
|
+
);
|
|
1625
|
+
};
|
|
1626
|
+
|
|
1627
|
+
const queryPartTerm = (
|
|
1628
|
+
term:
|
|
1629
|
+
| SearchTerm
|
|
1630
|
+
| SearchOrTerm
|
|
1631
|
+
| SearchNotTerm
|
|
1632
|
+
| SearchSeriesTerm,
|
|
1633
|
+
): string => {
|
|
1634
|
+
if (term.type === 'series') {
|
|
1635
|
+
return queryPartSeries(term);
|
|
1636
|
+
} else if (term.type === 'not') {
|
|
1637
|
+
return 'NOT ' + queryPartTerm(term.operand);
|
|
1638
|
+
} else if (term.type === 'or') {
|
|
1639
|
+
let queryParts: string[] = [];
|
|
1640
|
+
for (let operand of term.operands) {
|
|
1641
|
+
queryParts.push(queryPartTerm(operand));
|
|
1642
|
+
}
|
|
1643
|
+
return '(' + queryParts.join(' OR ') + ')';
|
|
1644
|
+
}
|
|
1645
|
+
return queryPartToken(term);
|
|
1646
|
+
};
|
|
1647
|
+
|
|
1648
|
+
// Run through the query and add terms.
|
|
1649
|
+
let termStrings: string[] = [];
|
|
1650
|
+
for (let term of parsedFTSQuery) {
|
|
1651
|
+
termStrings.push(queryPartTerm(term));
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1101
1654
|
curQuery +=
|
|
1102
1655
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1103
|
-
|
|
1104
|
-
'
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
' AND INSTR(`value`, @' +
|
|
1109
|
-
value +
|
|
1110
|
-
'))';
|
|
1656
|
+
'(' +
|
|
1657
|
+
termStrings.join(' AND ') +
|
|
1658
|
+
')';
|
|
1659
|
+
|
|
1660
|
+
params[name] = curValue[0];
|
|
1111
1661
|
}
|
|
1112
|
-
params[name] = curValue[0];
|
|
1113
|
-
params[value] = svalue;
|
|
1114
1662
|
}
|
|
1115
1663
|
break;
|
|
1116
1664
|
case 'match':
|
|
1117
1665
|
case '!match':
|
|
1118
|
-
if (
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
break;
|
|
1132
|
-
} else if (curValue[0] === 'mdate') {
|
|
1666
|
+
if (
|
|
1667
|
+
curValue[0] === 'cdate' ||
|
|
1668
|
+
curValue[0] === 'mdate' ||
|
|
1669
|
+
(this.nymph.tilmeld != null &&
|
|
1670
|
+
(curValue[0] === 'user' ||
|
|
1671
|
+
curValue[0] === 'group' ||
|
|
1672
|
+
curValue[0] === 'acUser' ||
|
|
1673
|
+
curValue[0] === 'acGroup' ||
|
|
1674
|
+
curValue[0] === 'acOther' ||
|
|
1675
|
+
curValue[0] === 'acRead' ||
|
|
1676
|
+
curValue[0] === 'acWrite' ||
|
|
1677
|
+
curValue[0] === 'acFull'))
|
|
1678
|
+
) {
|
|
1133
1679
|
if (curQuery) {
|
|
1134
1680
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1135
1681
|
}
|
|
1136
|
-
const
|
|
1682
|
+
const value = `param${++count.i}`;
|
|
1137
1683
|
curQuery +=
|
|
1138
1684
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1139
1685
|
'(' +
|
|
1140
1686
|
ieTable +
|
|
1141
|
-
'
|
|
1142
|
-
|
|
1687
|
+
'.' +
|
|
1688
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1689
|
+
' REGEXP @' +
|
|
1690
|
+
value +
|
|
1143
1691
|
')';
|
|
1144
|
-
params[
|
|
1145
|
-
break;
|
|
1692
|
+
params[value] = curValue[1];
|
|
1146
1693
|
} else {
|
|
1147
1694
|
if (curQuery) {
|
|
1148
1695
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1151,10 +1698,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1151
1698
|
const value = `param${++count.i}`;
|
|
1152
1699
|
curQuery +=
|
|
1153
1700
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1701
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1702
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1703
|
+
' WHERE `guid`=' +
|
|
1154
1704
|
ieTable +
|
|
1155
|
-
'.`guid`
|
|
1156
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1157
|
-
' WHERE `name`=@' +
|
|
1705
|
+
'.`guid` AND `name`=@' +
|
|
1158
1706
|
name +
|
|
1159
1707
|
' AND `string` REGEXP @' +
|
|
1160
1708
|
value +
|
|
@@ -1165,34 +1713,33 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1165
1713
|
break;
|
|
1166
1714
|
case 'imatch':
|
|
1167
1715
|
case '!imatch':
|
|
1168
|
-
if (
|
|
1716
|
+
if (
|
|
1717
|
+
curValue[0] === 'cdate' ||
|
|
1718
|
+
curValue[0] === 'mdate' ||
|
|
1719
|
+
(this.nymph.tilmeld != null &&
|
|
1720
|
+
(curValue[0] === 'user' ||
|
|
1721
|
+
curValue[0] === 'group' ||
|
|
1722
|
+
curValue[0] === 'acUser' ||
|
|
1723
|
+
curValue[0] === 'acGroup' ||
|
|
1724
|
+
curValue[0] === 'acOther' ||
|
|
1725
|
+
curValue[0] === 'acRead' ||
|
|
1726
|
+
curValue[0] === 'acWrite' ||
|
|
1727
|
+
curValue[0] === 'acFull'))
|
|
1728
|
+
) {
|
|
1169
1729
|
if (curQuery) {
|
|
1170
1730
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1171
1731
|
}
|
|
1172
|
-
const
|
|
1173
|
-
curQuery +=
|
|
1174
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1175
|
-
'(' +
|
|
1176
|
-
ieTable +
|
|
1177
|
-
'.`cdate` REGEXP @' +
|
|
1178
|
-
cdate +
|
|
1179
|
-
')';
|
|
1180
|
-
params[cdate] = curValue[1];
|
|
1181
|
-
break;
|
|
1182
|
-
} else if (curValue[0] === 'mdate') {
|
|
1183
|
-
if (curQuery) {
|
|
1184
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1185
|
-
}
|
|
1186
|
-
const mdate = `param${++count.i}`;
|
|
1732
|
+
const value = `param${++count.i}`;
|
|
1187
1733
|
curQuery +=
|
|
1188
1734
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1189
1735
|
'(' +
|
|
1190
1736
|
ieTable +
|
|
1191
|
-
'
|
|
1192
|
-
|
|
1737
|
+
'.' +
|
|
1738
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1739
|
+
' REGEXP @' +
|
|
1740
|
+
value +
|
|
1193
1741
|
')';
|
|
1194
|
-
params[
|
|
1195
|
-
break;
|
|
1742
|
+
params[value] = curValue[1];
|
|
1196
1743
|
} else {
|
|
1197
1744
|
if (curQuery) {
|
|
1198
1745
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1201,10 +1748,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1201
1748
|
const value = `param${++count.i}`;
|
|
1202
1749
|
curQuery +=
|
|
1203
1750
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1751
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1752
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1753
|
+
' WHERE `guid`=' +
|
|
1204
1754
|
ieTable +
|
|
1205
|
-
'.`guid`
|
|
1206
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1207
|
-
' WHERE `name`=@' +
|
|
1755
|
+
'.`guid` AND `name`=@' +
|
|
1208
1756
|
name +
|
|
1209
1757
|
' AND LOWER(`string`) REGEXP LOWER(@' +
|
|
1210
1758
|
value +
|
|
@@ -1215,34 +1763,33 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1215
1763
|
break;
|
|
1216
1764
|
case 'like':
|
|
1217
1765
|
case '!like':
|
|
1218
|
-
if (
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
break;
|
|
1232
|
-
} else if (curValue[0] === 'mdate') {
|
|
1766
|
+
if (
|
|
1767
|
+
curValue[0] === 'cdate' ||
|
|
1768
|
+
curValue[0] === 'mdate' ||
|
|
1769
|
+
(this.nymph.tilmeld != null &&
|
|
1770
|
+
(curValue[0] === 'user' ||
|
|
1771
|
+
curValue[0] === 'group' ||
|
|
1772
|
+
curValue[0] === 'acUser' ||
|
|
1773
|
+
curValue[0] === 'acGroup' ||
|
|
1774
|
+
curValue[0] === 'acOther' ||
|
|
1775
|
+
curValue[0] === 'acRead' ||
|
|
1776
|
+
curValue[0] === 'acWrite' ||
|
|
1777
|
+
curValue[0] === 'acFull'))
|
|
1778
|
+
) {
|
|
1233
1779
|
if (curQuery) {
|
|
1234
1780
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1235
1781
|
}
|
|
1236
|
-
const
|
|
1782
|
+
const value = `param${++count.i}`;
|
|
1237
1783
|
curQuery +=
|
|
1238
1784
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1239
1785
|
'(' +
|
|
1240
1786
|
ieTable +
|
|
1241
|
-
'
|
|
1242
|
-
|
|
1787
|
+
'.' +
|
|
1788
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1789
|
+
' LIKE @' +
|
|
1790
|
+
value +
|
|
1243
1791
|
')';
|
|
1244
|
-
params[
|
|
1245
|
-
break;
|
|
1792
|
+
params[value] = curValue[1];
|
|
1246
1793
|
} else {
|
|
1247
1794
|
if (curQuery) {
|
|
1248
1795
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1251,10 +1798,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1251
1798
|
const value = `param${++count.i}`;
|
|
1252
1799
|
curQuery +=
|
|
1253
1800
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1801
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1802
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1803
|
+
' WHERE `guid`=' +
|
|
1254
1804
|
ieTable +
|
|
1255
|
-
'.`guid`
|
|
1256
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1257
|
-
' WHERE `name`=@' +
|
|
1805
|
+
'.`guid` AND `name`=@' +
|
|
1258
1806
|
name +
|
|
1259
1807
|
' AND `string` LIKE @' +
|
|
1260
1808
|
value +
|
|
@@ -1265,34 +1813,33 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1265
1813
|
break;
|
|
1266
1814
|
case 'ilike':
|
|
1267
1815
|
case '!ilike':
|
|
1268
|
-
if (
|
|
1816
|
+
if (
|
|
1817
|
+
curValue[0] === 'cdate' ||
|
|
1818
|
+
curValue[0] === 'mdate' ||
|
|
1819
|
+
(this.nymph.tilmeld != null &&
|
|
1820
|
+
(curValue[0] === 'user' ||
|
|
1821
|
+
curValue[0] === 'group' ||
|
|
1822
|
+
curValue[0] === 'acUser' ||
|
|
1823
|
+
curValue[0] === 'acGroup' ||
|
|
1824
|
+
curValue[0] === 'acOther' ||
|
|
1825
|
+
curValue[0] === 'acRead' ||
|
|
1826
|
+
curValue[0] === 'acWrite' ||
|
|
1827
|
+
curValue[0] === 'acFull'))
|
|
1828
|
+
) {
|
|
1269
1829
|
if (curQuery) {
|
|
1270
1830
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1271
1831
|
}
|
|
1272
|
-
const
|
|
1273
|
-
curQuery +=
|
|
1274
|
-
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1275
|
-
'(' +
|
|
1276
|
-
ieTable +
|
|
1277
|
-
'.`cdate` LIKE @' +
|
|
1278
|
-
cdate +
|
|
1279
|
-
')';
|
|
1280
|
-
params[cdate] = curValue[1];
|
|
1281
|
-
break;
|
|
1282
|
-
} else if (curValue[0] === 'mdate') {
|
|
1283
|
-
if (curQuery) {
|
|
1284
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1285
|
-
}
|
|
1286
|
-
const mdate = `param${++count.i}`;
|
|
1832
|
+
const value = `param${++count.i}`;
|
|
1287
1833
|
curQuery +=
|
|
1288
1834
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1289
1835
|
'(' +
|
|
1290
1836
|
ieTable +
|
|
1291
|
-
'
|
|
1292
|
-
|
|
1837
|
+
'.' +
|
|
1838
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1839
|
+
' LIKE @' +
|
|
1840
|
+
value +
|
|
1293
1841
|
')';
|
|
1294
|
-
params[
|
|
1295
|
-
break;
|
|
1842
|
+
params[value] = curValue[1];
|
|
1296
1843
|
} else {
|
|
1297
1844
|
if (curQuery) {
|
|
1298
1845
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1301,48 +1848,48 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1301
1848
|
const value = `param${++count.i}`;
|
|
1302
1849
|
curQuery +=
|
|
1303
1850
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1851
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1852
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1853
|
+
' WHERE `guid`=' +
|
|
1304
1854
|
ieTable +
|
|
1305
|
-
'.`guid`
|
|
1306
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1307
|
-
' WHERE `name`=@' +
|
|
1855
|
+
'.`guid` AND `name`=@' +
|
|
1308
1856
|
name +
|
|
1309
1857
|
' AND LOWER(`string`) LIKE LOWER(@' +
|
|
1310
1858
|
value +
|
|
1311
1859
|
'))';
|
|
1312
|
-
params[name] = curValue[0];
|
|
1313
|
-
params[value] = curValue[1];
|
|
1314
|
-
}
|
|
1315
|
-
break;
|
|
1316
|
-
case 'gt':
|
|
1317
|
-
case '!gt':
|
|
1318
|
-
if (
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
break;
|
|
1332
|
-
} else if (curValue[0] === 'mdate') {
|
|
1860
|
+
params[name] = curValue[0];
|
|
1861
|
+
params[value] = curValue[1];
|
|
1862
|
+
}
|
|
1863
|
+
break;
|
|
1864
|
+
case 'gt':
|
|
1865
|
+
case '!gt':
|
|
1866
|
+
if (
|
|
1867
|
+
curValue[0] === 'cdate' ||
|
|
1868
|
+
curValue[0] === 'mdate' ||
|
|
1869
|
+
(this.nymph.tilmeld != null &&
|
|
1870
|
+
(curValue[0] === 'user' ||
|
|
1871
|
+
curValue[0] === 'group' ||
|
|
1872
|
+
curValue[0] === 'acUser' ||
|
|
1873
|
+
curValue[0] === 'acGroup' ||
|
|
1874
|
+
curValue[0] === 'acOther' ||
|
|
1875
|
+
curValue[0] === 'acRead' ||
|
|
1876
|
+
curValue[0] === 'acWrite' ||
|
|
1877
|
+
curValue[0] === 'acFull'))
|
|
1878
|
+
) {
|
|
1333
1879
|
if (curQuery) {
|
|
1334
1880
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1335
1881
|
}
|
|
1336
|
-
const
|
|
1882
|
+
const value = `param${++count.i}`;
|
|
1337
1883
|
curQuery +=
|
|
1338
1884
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1339
1885
|
ieTable +
|
|
1340
|
-
'
|
|
1341
|
-
|
|
1342
|
-
|
|
1886
|
+
'.' +
|
|
1887
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1888
|
+
'>@' +
|
|
1889
|
+
value;
|
|
1890
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1343
1891
|
? null
|
|
1344
1892
|
: Number(curValue[1]);
|
|
1345
|
-
break;
|
|
1346
1893
|
} else {
|
|
1347
1894
|
if (curQuery) {
|
|
1348
1895
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1351,10 +1898,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1351
1898
|
const value = `param${++count.i}`;
|
|
1352
1899
|
curQuery +=
|
|
1353
1900
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1901
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1902
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1903
|
+
' WHERE `guid`=' +
|
|
1354
1904
|
ieTable +
|
|
1355
|
-
'.`guid`
|
|
1356
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1357
|
-
' WHERE `name`=@' +
|
|
1905
|
+
'.`guid` AND `name`=@' +
|
|
1358
1906
|
name +
|
|
1359
1907
|
' AND `number`>@' +
|
|
1360
1908
|
value +
|
|
@@ -1367,34 +1915,33 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1367
1915
|
break;
|
|
1368
1916
|
case 'gte':
|
|
1369
1917
|
case '!gte':
|
|
1370
|
-
if (
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
break;
|
|
1384
|
-
} else if (curValue[0] === 'mdate') {
|
|
1918
|
+
if (
|
|
1919
|
+
curValue[0] === 'cdate' ||
|
|
1920
|
+
curValue[0] === 'mdate' ||
|
|
1921
|
+
(this.nymph.tilmeld != null &&
|
|
1922
|
+
(curValue[0] === 'user' ||
|
|
1923
|
+
curValue[0] === 'group' ||
|
|
1924
|
+
curValue[0] === 'acUser' ||
|
|
1925
|
+
curValue[0] === 'acGroup' ||
|
|
1926
|
+
curValue[0] === 'acOther' ||
|
|
1927
|
+
curValue[0] === 'acRead' ||
|
|
1928
|
+
curValue[0] === 'acWrite' ||
|
|
1929
|
+
curValue[0] === 'acFull'))
|
|
1930
|
+
) {
|
|
1385
1931
|
if (curQuery) {
|
|
1386
1932
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1387
1933
|
}
|
|
1388
|
-
const
|
|
1934
|
+
const value = `param${++count.i}`;
|
|
1389
1935
|
curQuery +=
|
|
1390
1936
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1391
1937
|
ieTable +
|
|
1392
|
-
'
|
|
1393
|
-
|
|
1394
|
-
|
|
1938
|
+
'.' +
|
|
1939
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1940
|
+
'>=@' +
|
|
1941
|
+
value;
|
|
1942
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1395
1943
|
? null
|
|
1396
1944
|
: Number(curValue[1]);
|
|
1397
|
-
break;
|
|
1398
1945
|
} else {
|
|
1399
1946
|
if (curQuery) {
|
|
1400
1947
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1403,10 +1950,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1403
1950
|
const value = `param${++count.i}`;
|
|
1404
1951
|
curQuery +=
|
|
1405
1952
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1953
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1954
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1955
|
+
' WHERE `guid`=' +
|
|
1406
1956
|
ieTable +
|
|
1407
|
-
'.`guid`
|
|
1408
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1409
|
-
' WHERE `name`=@' +
|
|
1957
|
+
'.`guid` AND `name`=@' +
|
|
1410
1958
|
name +
|
|
1411
1959
|
' AND `number`>=@' +
|
|
1412
1960
|
value +
|
|
@@ -1419,34 +1967,33 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1419
1967
|
break;
|
|
1420
1968
|
case 'lt':
|
|
1421
1969
|
case '!lt':
|
|
1422
|
-
if (
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
break;
|
|
1436
|
-
} else if (curValue[0] === 'mdate') {
|
|
1970
|
+
if (
|
|
1971
|
+
curValue[0] === 'cdate' ||
|
|
1972
|
+
curValue[0] === 'mdate' ||
|
|
1973
|
+
(this.nymph.tilmeld != null &&
|
|
1974
|
+
(curValue[0] === 'user' ||
|
|
1975
|
+
curValue[0] === 'group' ||
|
|
1976
|
+
curValue[0] === 'acUser' ||
|
|
1977
|
+
curValue[0] === 'acGroup' ||
|
|
1978
|
+
curValue[0] === 'acOther' ||
|
|
1979
|
+
curValue[0] === 'acRead' ||
|
|
1980
|
+
curValue[0] === 'acWrite' ||
|
|
1981
|
+
curValue[0] === 'acFull'))
|
|
1982
|
+
) {
|
|
1437
1983
|
if (curQuery) {
|
|
1438
1984
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1439
1985
|
}
|
|
1440
|
-
const
|
|
1986
|
+
const value = `param${++count.i}`;
|
|
1441
1987
|
curQuery +=
|
|
1442
1988
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1443
1989
|
ieTable +
|
|
1444
|
-
'
|
|
1445
|
-
|
|
1446
|
-
|
|
1990
|
+
'.' +
|
|
1991
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1992
|
+
'<@' +
|
|
1993
|
+
value;
|
|
1994
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1447
1995
|
? null
|
|
1448
1996
|
: Number(curValue[1]);
|
|
1449
|
-
break;
|
|
1450
1997
|
} else {
|
|
1451
1998
|
if (curQuery) {
|
|
1452
1999
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1455,10 +2002,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1455
2002
|
const value = `param${++count.i}`;
|
|
1456
2003
|
curQuery +=
|
|
1457
2004
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2005
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
2006
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
2007
|
+
' WHERE `guid`=' +
|
|
1458
2008
|
ieTable +
|
|
1459
|
-
'.`guid`
|
|
1460
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1461
|
-
' WHERE `name`=@' +
|
|
2009
|
+
'.`guid` AND `name`=@' +
|
|
1462
2010
|
name +
|
|
1463
2011
|
' AND `number`<@' +
|
|
1464
2012
|
value +
|
|
@@ -1471,34 +2019,33 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1471
2019
|
break;
|
|
1472
2020
|
case 'lte':
|
|
1473
2021
|
case '!lte':
|
|
1474
|
-
if (
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
break;
|
|
1488
|
-
} else if (curValue[0] === 'mdate') {
|
|
2022
|
+
if (
|
|
2023
|
+
curValue[0] === 'cdate' ||
|
|
2024
|
+
curValue[0] === 'mdate' ||
|
|
2025
|
+
(this.nymph.tilmeld != null &&
|
|
2026
|
+
(curValue[0] === 'user' ||
|
|
2027
|
+
curValue[0] === 'group' ||
|
|
2028
|
+
curValue[0] === 'acUser' ||
|
|
2029
|
+
curValue[0] === 'acGroup' ||
|
|
2030
|
+
curValue[0] === 'acOther' ||
|
|
2031
|
+
curValue[0] === 'acRead' ||
|
|
2032
|
+
curValue[0] === 'acWrite' ||
|
|
2033
|
+
curValue[0] === 'acFull'))
|
|
2034
|
+
) {
|
|
1489
2035
|
if (curQuery) {
|
|
1490
2036
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1491
2037
|
}
|
|
1492
|
-
const
|
|
2038
|
+
const value = `param${++count.i}`;
|
|
1493
2039
|
curQuery +=
|
|
1494
2040
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1495
2041
|
ieTable +
|
|
1496
|
-
'
|
|
1497
|
-
|
|
1498
|
-
|
|
2042
|
+
'.' +
|
|
2043
|
+
MySQLDriver.escape(curValue[0]) +
|
|
2044
|
+
'<=@' +
|
|
2045
|
+
value;
|
|
2046
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1499
2047
|
? null
|
|
1500
2048
|
: Number(curValue[1]);
|
|
1501
|
-
break;
|
|
1502
2049
|
} else {
|
|
1503
2050
|
if (curQuery) {
|
|
1504
2051
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1507,10 +2054,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1507
2054
|
const value = `param${++count.i}`;
|
|
1508
2055
|
curQuery +=
|
|
1509
2056
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2057
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
2058
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
2059
|
+
' WHERE `guid`=' +
|
|
1510
2060
|
ieTable +
|
|
1511
|
-
'.`guid`
|
|
1512
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1513
|
-
' WHERE `name`=@' +
|
|
2061
|
+
'.`guid` AND `name`=@' +
|
|
1514
2062
|
name +
|
|
1515
2063
|
' AND `number`<=@' +
|
|
1516
2064
|
value +
|
|
@@ -1534,32 +2082,66 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1534
2082
|
if (curQuery) {
|
|
1535
2083
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1536
2084
|
}
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
2085
|
+
if (
|
|
2086
|
+
this.nymph.tilmeld != null &&
|
|
2087
|
+
(curValue[0] === 'user' || curValue[0] === 'group')
|
|
2088
|
+
) {
|
|
2089
|
+
const guid = `param${++count.i}`;
|
|
2090
|
+
curQuery +=
|
|
2091
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2092
|
+
ieTable +
|
|
2093
|
+
'.' +
|
|
2094
|
+
MySQLDriver.escape(curValue[0]) +
|
|
2095
|
+
'=UNHEX(@' +
|
|
2096
|
+
guid +
|
|
2097
|
+
')';
|
|
2098
|
+
params[guid] = curQguid;
|
|
2099
|
+
} else if (
|
|
2100
|
+
this.nymph.tilmeld != null &&
|
|
2101
|
+
(curValue[0] === 'acRead' ||
|
|
2102
|
+
curValue[0] === 'acWrite' ||
|
|
2103
|
+
curValue[0] === 'acFull')
|
|
2104
|
+
) {
|
|
2105
|
+
const queryParam = `param${++count.i}`;
|
|
2106
|
+
curQuery +=
|
|
2107
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2108
|
+
'MATCH (' +
|
|
2109
|
+
ieTable +
|
|
2110
|
+
'.' +
|
|
2111
|
+
MySQLDriver.escape(curValue[0]) +
|
|
2112
|
+
') AGAINST (@' +
|
|
2113
|
+
queryParam +
|
|
2114
|
+
' IN BOOLEAN MODE)';
|
|
2115
|
+
params[queryParam] = '+' + curQguid;
|
|
2116
|
+
} else {
|
|
2117
|
+
const name = `param${++count.i}`;
|
|
2118
|
+
const guid = `param${++count.i}`;
|
|
2119
|
+
curQuery +=
|
|
2120
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2121
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
2122
|
+
MySQLDriver.escape(this.prefix + 'references_' + etype) +
|
|
2123
|
+
' WHERE `guid`=' +
|
|
2124
|
+
ieTable +
|
|
2125
|
+
'.`guid` AND `name`=@' +
|
|
2126
|
+
name +
|
|
2127
|
+
' AND `reference`=UNHEX(@' +
|
|
2128
|
+
guid +
|
|
2129
|
+
'))';
|
|
2130
|
+
params[name] = curValue[0];
|
|
2131
|
+
params[guid] = curQguid;
|
|
2132
|
+
}
|
|
1551
2133
|
break;
|
|
1552
2134
|
case 'selector':
|
|
1553
2135
|
case '!selector':
|
|
1554
|
-
const
|
|
1555
|
-
options,
|
|
2136
|
+
const innerquery = this.makeEntityQuery(
|
|
2137
|
+
{ ...options, sort: null, limit: undefined },
|
|
1556
2138
|
[curValue],
|
|
1557
2139
|
etype,
|
|
1558
2140
|
count,
|
|
1559
2141
|
params,
|
|
1560
2142
|
true,
|
|
1561
2143
|
tableSuffix,
|
|
1562
|
-
etypes
|
|
2144
|
+
etypes,
|
|
1563
2145
|
);
|
|
1564
2146
|
if (curQuery) {
|
|
1565
2147
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
@@ -1567,61 +2149,174 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1567
2149
|
curQuery +=
|
|
1568
2150
|
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1569
2151
|
'(' +
|
|
1570
|
-
|
|
2152
|
+
innerquery.query +
|
|
1571
2153
|
')';
|
|
1572
2154
|
break;
|
|
1573
2155
|
case 'qref':
|
|
1574
2156
|
case '!qref':
|
|
2157
|
+
const referenceTableSuffix = makeTableSuffix();
|
|
1575
2158
|
const [qrefOptions, ...qrefSelectors] = curValue[1] as [
|
|
1576
2159
|
Options,
|
|
1577
|
-
...FormattedSelector[]
|
|
2160
|
+
...FormattedSelector[],
|
|
1578
2161
|
];
|
|
1579
2162
|
const QrefEntityClass = qrefOptions.class as EntityConstructor;
|
|
1580
2163
|
etypes.push(QrefEntityClass.ETYPE);
|
|
1581
|
-
const qrefQuery = this.makeEntityQuery(
|
|
1582
|
-
{ ...qrefOptions, return: 'guid', class: QrefEntityClass },
|
|
1583
|
-
qrefSelectors,
|
|
1584
|
-
QrefEntityClass.ETYPE,
|
|
1585
|
-
count,
|
|
1586
|
-
params,
|
|
1587
|
-
false,
|
|
1588
|
-
makeTableSuffix(),
|
|
1589
|
-
etypes
|
|
1590
|
-
);
|
|
1591
2164
|
if (curQuery) {
|
|
1592
2165
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1593
2166
|
}
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
(
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
2167
|
+
if (
|
|
2168
|
+
this.nymph.tilmeld != null &&
|
|
2169
|
+
(curValue[0] === 'user' || curValue[0] === 'group')
|
|
2170
|
+
) {
|
|
2171
|
+
const qrefQuery = this.makeEntityQuery(
|
|
2172
|
+
{
|
|
2173
|
+
...qrefOptions,
|
|
2174
|
+
sort: qrefOptions.sort ?? null,
|
|
2175
|
+
return: 'guid',
|
|
2176
|
+
class: QrefEntityClass,
|
|
2177
|
+
},
|
|
2178
|
+
qrefSelectors,
|
|
2179
|
+
QrefEntityClass.ETYPE,
|
|
2180
|
+
count,
|
|
2181
|
+
params,
|
|
2182
|
+
false,
|
|
2183
|
+
makeTableSuffix(),
|
|
2184
|
+
etypes,
|
|
2185
|
+
'r' +
|
|
2186
|
+
referenceTableSuffix +
|
|
2187
|
+
'.' +
|
|
2188
|
+
MySQLDriver.escape(curValue[0]),
|
|
2189
|
+
);
|
|
2190
|
+
|
|
2191
|
+
curQuery +=
|
|
2192
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2193
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
2194
|
+
MySQLDriver.escape(this.prefix + 'entities_' + etype) +
|
|
2195
|
+
' r' +
|
|
2196
|
+
referenceTableSuffix +
|
|
2197
|
+
' WHERE r' +
|
|
2198
|
+
referenceTableSuffix +
|
|
2199
|
+
'.`guid`=' +
|
|
2200
|
+
ieTable +
|
|
2201
|
+
'.`guid` AND EXISTS (' +
|
|
2202
|
+
qrefQuery.query +
|
|
2203
|
+
'))';
|
|
2204
|
+
} else if (
|
|
2205
|
+
this.nymph.tilmeld != null &&
|
|
2206
|
+
(curValue[0] === 'acRead' ||
|
|
2207
|
+
curValue[0] === 'acWrite' ||
|
|
2208
|
+
curValue[0] === 'acFull')
|
|
2209
|
+
) {
|
|
2210
|
+
const qrefQuery = this.makeEntityQuery(
|
|
2211
|
+
{
|
|
2212
|
+
...qrefOptions,
|
|
2213
|
+
sort: qrefOptions.sort ?? null,
|
|
2214
|
+
return: 'guid',
|
|
2215
|
+
class: QrefEntityClass,
|
|
2216
|
+
},
|
|
2217
|
+
qrefSelectors,
|
|
2218
|
+
QrefEntityClass.ETYPE,
|
|
2219
|
+
count,
|
|
2220
|
+
params,
|
|
2221
|
+
false,
|
|
2222
|
+
makeTableSuffix(),
|
|
2223
|
+
etypes,
|
|
2224
|
+
undefined,
|
|
2225
|
+
(guid) =>
|
|
2226
|
+
ieTable +
|
|
2227
|
+
'.' +
|
|
2228
|
+
MySQLDriver.escape(curValue[0]) +
|
|
2229
|
+
" LIKE CONCAT('% ', LOWER(HEX(" +
|
|
2230
|
+
guid +
|
|
2231
|
+
")), ' %')",
|
|
2232
|
+
);
|
|
2233
|
+
|
|
2234
|
+
curQuery +=
|
|
2235
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2236
|
+
'EXISTS (' +
|
|
2237
|
+
qrefQuery.query +
|
|
2238
|
+
')';
|
|
2239
|
+
} else {
|
|
2240
|
+
const qrefQuery = this.makeEntityQuery(
|
|
2241
|
+
{
|
|
2242
|
+
...qrefOptions,
|
|
2243
|
+
sort: qrefOptions.sort ?? null,
|
|
2244
|
+
return: 'guid',
|
|
2245
|
+
class: QrefEntityClass,
|
|
2246
|
+
},
|
|
2247
|
+
qrefSelectors,
|
|
2248
|
+
QrefEntityClass.ETYPE,
|
|
2249
|
+
count,
|
|
2250
|
+
params,
|
|
2251
|
+
false,
|
|
2252
|
+
makeTableSuffix(),
|
|
2253
|
+
etypes,
|
|
2254
|
+
'r' + referenceTableSuffix + '.`reference`',
|
|
2255
|
+
);
|
|
2256
|
+
const qrefName = `param${++count.i}`;
|
|
2257
|
+
curQuery +=
|
|
2258
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
2259
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
2260
|
+
MySQLDriver.escape(this.prefix + 'references_' + etype) +
|
|
2261
|
+
' r' +
|
|
2262
|
+
referenceTableSuffix +
|
|
2263
|
+
' WHERE r' +
|
|
2264
|
+
referenceTableSuffix +
|
|
2265
|
+
'.`guid`=' +
|
|
2266
|
+
ieTable +
|
|
2267
|
+
'.`guid` AND r' +
|
|
2268
|
+
referenceTableSuffix +
|
|
2269
|
+
'.`name`=@' +
|
|
2270
|
+
qrefName +
|
|
2271
|
+
' AND EXISTS (' +
|
|
2272
|
+
qrefQuery.query +
|
|
2273
|
+
'))';
|
|
2274
|
+
params[qrefName] = curValue[0];
|
|
2275
|
+
}
|
|
1606
2276
|
break;
|
|
1607
2277
|
}
|
|
1608
2278
|
}
|
|
1609
2279
|
return curQuery;
|
|
1610
|
-
}
|
|
2280
|
+
},
|
|
1611
2281
|
);
|
|
1612
2282
|
|
|
1613
2283
|
let sortBy: string;
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
2284
|
+
let sortByInner: string;
|
|
2285
|
+
let sortJoin = '';
|
|
2286
|
+
let sortJoinInner = '';
|
|
2287
|
+
const order = options.reverse ? ' DESC' : '';
|
|
2288
|
+
if (sort == null) {
|
|
2289
|
+
sortBy = '';
|
|
2290
|
+
sortByInner = '';
|
|
2291
|
+
} else {
|
|
2292
|
+
switch (sort) {
|
|
2293
|
+
case 'mdate':
|
|
2294
|
+
sortBy = `ORDER BY ${eTable}.\`mdate\`${order}`;
|
|
2295
|
+
sortByInner = `ORDER BY ${ieTable}.\`mdate\`${order}`;
|
|
2296
|
+
break;
|
|
2297
|
+
case 'cdate':
|
|
2298
|
+
sortBy = `ORDER BY ${eTable}.\`cdate\`${order}`;
|
|
2299
|
+
sortByInner = `ORDER BY ${ieTable}.\`cdate\`${order}`;
|
|
2300
|
+
break;
|
|
2301
|
+
default:
|
|
2302
|
+
const name = `param${++count.i}`;
|
|
2303
|
+
sortJoin = `LEFT JOIN (
|
|
2304
|
+
SELECT \`guid\`, \`string\`, \`number\`
|
|
2305
|
+
FROM ${MySQLDriver.escape(this.prefix + 'data_' + etype)}
|
|
2306
|
+
WHERE \`name\`=@${name}
|
|
2307
|
+
ORDER BY \`number\`${order}, \`string\`${order}
|
|
2308
|
+
) ${sTable} ON ${eTable}.\`guid\`=${sTable}.\`guid\``;
|
|
2309
|
+
sortJoinInner = `LEFT JOIN (
|
|
2310
|
+
SELECT \`guid\`, \`string\`, \`number\`
|
|
2311
|
+
FROM ${MySQLDriver.escape(this.prefix + 'data_' + etype)}
|
|
2312
|
+
WHERE \`name\`=@${name}
|
|
2313
|
+
ORDER BY \`number\`${order}, \`string\`${order}
|
|
2314
|
+
) ${sTable} ON ${ieTable}.\`guid\`=${sTable}.\`guid\``;
|
|
2315
|
+
sortBy = `ORDER BY ${sTable}.\`number\`${order}, ${sTable}.\`string\`${order}`;
|
|
2316
|
+
sortByInner = sortBy;
|
|
2317
|
+
params[name] = sort;
|
|
2318
|
+
break;
|
|
2319
|
+
}
|
|
1625
2320
|
}
|
|
1626
2321
|
|
|
1627
2322
|
let query: string;
|
|
@@ -1632,31 +2327,36 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1632
2327
|
let limit = '';
|
|
1633
2328
|
if ('limit' in options) {
|
|
1634
2329
|
limit = ` LIMIT ${Math.floor(
|
|
1635
|
-
isNaN(Number(options.limit)) ? 0 : Number(options.limit)
|
|
2330
|
+
isNaN(Number(options.limit)) ? 0 : Number(options.limit),
|
|
1636
2331
|
)}`;
|
|
1637
2332
|
}
|
|
1638
2333
|
let offset = '';
|
|
1639
2334
|
if ('offset' in options) {
|
|
1640
2335
|
offset = ` OFFSET ${Math.floor(
|
|
1641
|
-
isNaN(Number(options.offset)) ? 0 : Number(options.offset)
|
|
2336
|
+
isNaN(Number(options.offset)) ? 0 : Number(options.offset),
|
|
1642
2337
|
)}`;
|
|
1643
2338
|
}
|
|
1644
2339
|
const whereClause = queryParts.join(') AND (');
|
|
2340
|
+
const guidClause = guidExplicitSelector
|
|
2341
|
+
? `${guidExplicitSelector(`${ieTable}.\`guid\``)} AND `
|
|
2342
|
+
: guidSelector
|
|
2343
|
+
? `${ieTable}.\`guid\`=${guidSelector} AND `
|
|
2344
|
+
: '';
|
|
1645
2345
|
if (options.return === 'count') {
|
|
1646
2346
|
if (limit || offset) {
|
|
1647
2347
|
query = `SELECT COUNT(${countTable}.\`guid\`) AS \`count\` FROM (
|
|
1648
2348
|
SELECT ${ieTable}.\`guid\` AS \`guid\`
|
|
1649
2349
|
FROM ${MySQLDriver.escape(
|
|
1650
|
-
`${this.prefix}entities_${etype}
|
|
2350
|
+
`${this.prefix}entities_${etype}`,
|
|
1651
2351
|
)} ${ieTable}
|
|
1652
|
-
WHERE (${whereClause})${limit}${offset}
|
|
2352
|
+
WHERE ${guidClause}(${whereClause})${limit}${offset}
|
|
1653
2353
|
) ${countTable}`;
|
|
1654
2354
|
} else {
|
|
1655
2355
|
query = `SELECT COUNT(${ieTable}.\`guid\`) AS \`count\`
|
|
1656
2356
|
FROM ${MySQLDriver.escape(
|
|
1657
|
-
`${this.prefix}entities_${etype}
|
|
2357
|
+
`${this.prefix}entities_${etype}`,
|
|
1658
2358
|
)} ${ieTable}
|
|
1659
|
-
WHERE (${whereClause})`;
|
|
2359
|
+
WHERE ${guidClause}(${whereClause})`;
|
|
1660
2360
|
}
|
|
1661
2361
|
} else if (options.return === 'guid') {
|
|
1662
2362
|
const guidColumn =
|
|
@@ -1665,38 +2365,47 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1665
2365
|
: `${ieTable}.\`guid\``;
|
|
1666
2366
|
query = `SELECT ${guidColumn} AS \`guid\`
|
|
1667
2367
|
FROM ${MySQLDriver.escape(
|
|
1668
|
-
`${this.prefix}entities_${etype}
|
|
2368
|
+
`${this.prefix}entities_${etype}`,
|
|
1669
2369
|
)} ${ieTable}
|
|
1670
|
-
|
|
1671
|
-
|
|
2370
|
+
${sortJoinInner}
|
|
2371
|
+
WHERE ${guidClause}(${whereClause})
|
|
2372
|
+
${sortByInner ? sortByInner + ', ' : 'ORDER BY '}${ieTable}.\`guid\`${limit}${offset}`;
|
|
1672
2373
|
} else {
|
|
1673
2374
|
query = `SELECT
|
|
1674
2375
|
LOWER(HEX(${eTable}.\`guid\`)) AS \`guid\`,
|
|
1675
2376
|
${eTable}.\`tags\`,
|
|
1676
2377
|
${eTable}.\`cdate\`,
|
|
1677
2378
|
${eTable}.\`mdate\`,
|
|
2379
|
+
LOWER(HEX(${eTable}.\`user\`)) AS \`user\`,
|
|
2380
|
+
LOWER(HEX(${eTable}.\`group\`)) AS \`group\`,
|
|
2381
|
+
${eTable}.\`acUser\`,
|
|
2382
|
+
${eTable}.\`acGroup\`,
|
|
2383
|
+
${eTable}.\`acOther\`,
|
|
2384
|
+
${eTable}.\`acRead\`,
|
|
2385
|
+
${eTable}.\`acWrite\`,
|
|
2386
|
+
${eTable}.\`acFull\`,
|
|
1678
2387
|
${dTable}.\`name\`,
|
|
1679
2388
|
${dTable}.\`value\`,
|
|
1680
|
-
${
|
|
1681
|
-
${
|
|
2389
|
+
${dTable}.\`json\`,
|
|
2390
|
+
${dTable}.\`string\`,
|
|
2391
|
+
${dTable}.\`number\`
|
|
1682
2392
|
FROM ${MySQLDriver.escape(
|
|
1683
|
-
`${this.prefix}entities_${etype}
|
|
2393
|
+
`${this.prefix}entities_${etype}`,
|
|
1684
2394
|
)} ${eTable}
|
|
1685
2395
|
LEFT JOIN ${MySQLDriver.escape(
|
|
1686
|
-
`${this.prefix}data_${etype}
|
|
2396
|
+
`${this.prefix}data_${etype}`,
|
|
1687
2397
|
)} ${dTable} ON ${eTable}.\`guid\`=${dTable}.\`guid\`
|
|
1688
|
-
|
|
1689
|
-
`${this.prefix}comparisons_${etype}`
|
|
1690
|
-
)} ${cTable} ON ${dTable}.\`guid\`=${cTable}.\`guid\` AND ${dTable}.\`name\`=${cTable}.\`name\`
|
|
2398
|
+
${sortJoin}
|
|
1691
2399
|
INNER JOIN (
|
|
1692
2400
|
SELECT ${ieTable}.\`guid\`
|
|
1693
2401
|
FROM ${MySQLDriver.escape(
|
|
1694
|
-
`${this.prefix}entities_${etype}
|
|
2402
|
+
`${this.prefix}entities_${etype}`,
|
|
1695
2403
|
)} ${ieTable}
|
|
1696
|
-
|
|
1697
|
-
|
|
2404
|
+
${sortJoinInner}
|
|
2405
|
+
WHERE ${guidClause}(${whereClause})
|
|
2406
|
+
${sortByInner}${limit}${offset}
|
|
1698
2407
|
) ${fTable} ON ${eTable}.\`guid\`=${fTable}.\`guid\`
|
|
1699
|
-
ORDER BY ${eTable}
|
|
2408
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}.\`guid\``;
|
|
1700
2409
|
}
|
|
1701
2410
|
}
|
|
1702
2411
|
} else {
|
|
@@ -1706,28 +2415,33 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1706
2415
|
let limit = '';
|
|
1707
2416
|
if ('limit' in options) {
|
|
1708
2417
|
limit = ` LIMIT ${Math.floor(
|
|
1709
|
-
isNaN(Number(options.limit)) ? 0 : Number(options.limit)
|
|
2418
|
+
isNaN(Number(options.limit)) ? 0 : Number(options.limit),
|
|
1710
2419
|
)}`;
|
|
1711
2420
|
}
|
|
1712
2421
|
let offset = '';
|
|
1713
2422
|
if ('offset' in options) {
|
|
1714
2423
|
offset = ` OFFSET ${Math.floor(
|
|
1715
|
-
isNaN(Number(options.offset)) ? 0 : Number(options.offset)
|
|
2424
|
+
isNaN(Number(options.offset)) ? 0 : Number(options.offset),
|
|
1716
2425
|
)}`;
|
|
1717
2426
|
}
|
|
2427
|
+
const guidClause = guidExplicitSelector
|
|
2428
|
+
? ` WHERE ${guidExplicitSelector(`${ieTable}.\`guid\``)}`
|
|
2429
|
+
: guidSelector
|
|
2430
|
+
? ` WHERE ${ieTable}.\`guid\`=${guidSelector}`
|
|
2431
|
+
: '';
|
|
1718
2432
|
if (options.return === 'count') {
|
|
1719
2433
|
if (limit || offset) {
|
|
1720
2434
|
query = `SELECT COUNT(${countTable}.\`guid\`) AS \`count\` FROM (
|
|
1721
2435
|
SELECT ${ieTable}.\`guid\` AS \`guid\`
|
|
1722
2436
|
FROM ${MySQLDriver.escape(
|
|
1723
|
-
`${this.prefix}entities_${etype}
|
|
1724
|
-
)} ${ieTable}${limit}${offset}
|
|
2437
|
+
`${this.prefix}entities_${etype}`,
|
|
2438
|
+
)} ${ieTable}${guidClause}${limit}${offset}
|
|
1725
2439
|
) ${countTable}`;
|
|
1726
2440
|
} else {
|
|
1727
2441
|
query = `SELECT COUNT(${ieTable}.\`guid\`) AS \`count\`
|
|
1728
2442
|
FROM ${MySQLDriver.escape(
|
|
1729
|
-
`${this.prefix}entities_${etype}
|
|
1730
|
-
)} ${ieTable}`;
|
|
2443
|
+
`${this.prefix}entities_${etype}`,
|
|
2444
|
+
)} ${ieTable}${guidClause}`;
|
|
1731
2445
|
}
|
|
1732
2446
|
} else if (options.return === 'guid') {
|
|
1733
2447
|
const guidColumn =
|
|
@@ -1736,9 +2450,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1736
2450
|
: `${ieTable}.\`guid\``;
|
|
1737
2451
|
query = `SELECT ${guidColumn} AS \`guid\`
|
|
1738
2452
|
FROM ${MySQLDriver.escape(
|
|
1739
|
-
`${this.prefix}entities_${etype}
|
|
2453
|
+
`${this.prefix}entities_${etype}`,
|
|
1740
2454
|
)} ${ieTable}
|
|
1741
|
-
|
|
2455
|
+
${sortJoinInner}
|
|
2456
|
+
${guidClause}
|
|
2457
|
+
${sortByInner ? sortByInner + ', ' : 'ORDER BY '}${ieTable}.\`guid\`${limit}${offset}`;
|
|
1742
2458
|
} else {
|
|
1743
2459
|
if (limit || offset) {
|
|
1744
2460
|
query = `SELECT
|
|
@@ -1746,47 +2462,64 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1746
2462
|
${eTable}.\`tags\`,
|
|
1747
2463
|
${eTable}.\`cdate\`,
|
|
1748
2464
|
${eTable}.\`mdate\`,
|
|
2465
|
+
LOWER(HEX(${eTable}.\`user\`)) AS \`user\`,
|
|
2466
|
+
LOWER(HEX(${eTable}.\`group\`)) AS \`group\`,
|
|
2467
|
+
${eTable}.\`acUser\`,
|
|
2468
|
+
${eTable}.\`acGroup\`,
|
|
2469
|
+
${eTable}.\`acOther\`,
|
|
2470
|
+
${eTable}.\`acRead\`,
|
|
2471
|
+
${eTable}.\`acWrite\`,
|
|
2472
|
+
${eTable}.\`acFull\`,
|
|
1749
2473
|
${dTable}.\`name\`,
|
|
1750
2474
|
${dTable}.\`value\`,
|
|
1751
|
-
${
|
|
1752
|
-
${
|
|
2475
|
+
${dTable}.\`json\`,
|
|
2476
|
+
${dTable}.\`string\`,
|
|
2477
|
+
${dTable}.\`number\`
|
|
1753
2478
|
FROM ${MySQLDriver.escape(
|
|
1754
|
-
`${this.prefix}entities_${etype}
|
|
2479
|
+
`${this.prefix}entities_${etype}`,
|
|
1755
2480
|
)} ${eTable}
|
|
1756
2481
|
LEFT JOIN ${MySQLDriver.escape(
|
|
1757
|
-
`${this.prefix}data_${etype}
|
|
2482
|
+
`${this.prefix}data_${etype}`,
|
|
1758
2483
|
)} ${dTable} ON ${eTable}.\`guid\`=${dTable}.\`guid\`
|
|
1759
|
-
|
|
1760
|
-
`${this.prefix}comparisons_${etype}`
|
|
1761
|
-
)} ${cTable} ON ${dTable}.\`guid\`=${cTable}.\`guid\` AND ${dTable}.\`name\`=${cTable}.\`name\`
|
|
2484
|
+
${sortJoin}
|
|
1762
2485
|
INNER JOIN (
|
|
1763
2486
|
SELECT ${ieTable}.\`guid\`
|
|
1764
2487
|
FROM ${MySQLDriver.escape(
|
|
1765
|
-
`${this.prefix}entities_${etype}
|
|
2488
|
+
`${this.prefix}entities_${etype}`,
|
|
1766
2489
|
)} ${ieTable}
|
|
1767
|
-
|
|
2490
|
+
${sortJoinInner}
|
|
2491
|
+
${guidClause}
|
|
2492
|
+
${sortByInner}${limit}${offset}
|
|
1768
2493
|
) ${fTable} ON ${eTable}.\`guid\`=${fTable}.\`guid\`
|
|
1769
|
-
ORDER BY ${eTable}
|
|
2494
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}.\`guid\``;
|
|
1770
2495
|
} else {
|
|
1771
2496
|
query = `SELECT
|
|
1772
2497
|
LOWER(HEX(${eTable}.\`guid\`)) AS \`guid\`,
|
|
1773
2498
|
${eTable}.\`tags\`,
|
|
1774
2499
|
${eTable}.\`cdate\`,
|
|
1775
2500
|
${eTable}.\`mdate\`,
|
|
2501
|
+
LOWER(HEX(${eTable}.\`user\`)) AS \`user\`,
|
|
2502
|
+
LOWER(HEX(${eTable}.\`group\`)) AS \`group\`,
|
|
2503
|
+
${eTable}.\`acUser\`,
|
|
2504
|
+
${eTable}.\`acGroup\`,
|
|
2505
|
+
${eTable}.\`acOther\`,
|
|
2506
|
+
${eTable}.\`acRead\`,
|
|
2507
|
+
${eTable}.\`acWrite\`,
|
|
2508
|
+
${eTable}.\`acFull\`,
|
|
1776
2509
|
${dTable}.\`name\`,
|
|
1777
2510
|
${dTable}.\`value\`,
|
|
1778
|
-
${
|
|
1779
|
-
${
|
|
2511
|
+
${dTable}.\`json\`,
|
|
2512
|
+
${dTable}.\`string\`,
|
|
2513
|
+
${dTable}.\`number\`
|
|
1780
2514
|
FROM ${MySQLDriver.escape(
|
|
1781
|
-
`${this.prefix}entities_${etype}
|
|
2515
|
+
`${this.prefix}entities_${etype}`,
|
|
1782
2516
|
)} ${eTable}
|
|
1783
2517
|
LEFT JOIN ${MySQLDriver.escape(
|
|
1784
|
-
`${this.prefix}data_${etype}
|
|
2518
|
+
`${this.prefix}data_${etype}`,
|
|
1785
2519
|
)} ${dTable} ON ${eTable}.\`guid\`=${dTable}.\`guid\`
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
ORDER BY ${eTable}.${sortBy}`;
|
|
2520
|
+
${sortJoin}
|
|
2521
|
+
${guidExplicitSelector ? `WHERE ${guidExplicitSelector(`${eTable}.\`guid\``)}` : guidSelector ? `WHERE ${eTable}.\`guid\`=${guidSelector}` : ''}
|
|
2522
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}.\`guid\``;
|
|
1790
2523
|
}
|
|
1791
2524
|
}
|
|
1792
2525
|
}
|
|
@@ -1806,38 +2539,18 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1806
2539
|
protected performQuery(
|
|
1807
2540
|
options: Options,
|
|
1808
2541
|
formattedSelectors: FormattedSelector[],
|
|
1809
|
-
etype: string
|
|
2542
|
+
etype: string,
|
|
1810
2543
|
): {
|
|
1811
2544
|
result: any;
|
|
1812
2545
|
} {
|
|
1813
2546
|
const { query, params, etypes } = this.makeEntityQuery(
|
|
1814
2547
|
options,
|
|
1815
2548
|
formattedSelectors,
|
|
1816
|
-
etype
|
|
1817
|
-
);
|
|
1818
|
-
const result = this.queryIter(query, { etypes, params }).then((val) =>
|
|
1819
|
-
val[Symbol.iterator]()
|
|
2549
|
+
etype,
|
|
1820
2550
|
);
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
};
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
protected performQuerySync(
|
|
1827
|
-
options: Options,
|
|
1828
|
-
formattedSelectors: FormattedSelector[],
|
|
1829
|
-
etype: string
|
|
1830
|
-
): {
|
|
1831
|
-
result: any;
|
|
1832
|
-
} {
|
|
1833
|
-
const { query, params, etypes } = this.makeEntityQuery(
|
|
1834
|
-
options,
|
|
1835
|
-
formattedSelectors,
|
|
1836
|
-
etype
|
|
2551
|
+
const result = this.queryArray(query, { etypes, params }).then((val) =>
|
|
2552
|
+
val[Symbol.iterator](),
|
|
1837
2553
|
);
|
|
1838
|
-
const result = (this.queryIterSync(query, { etypes, params }) || [])[
|
|
1839
|
-
Symbol.iterator
|
|
1840
|
-
]();
|
|
1841
2554
|
return {
|
|
1842
2555
|
result,
|
|
1843
2556
|
};
|
|
@@ -1851,20 +2564,26 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1851
2564
|
options: Options<T> & { return: 'guid' },
|
|
1852
2565
|
...selectors: Selector[]
|
|
1853
2566
|
): Promise<string[]>;
|
|
2567
|
+
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
2568
|
+
options: Options<T> & { return: 'object' },
|
|
2569
|
+
...selectors: Selector[]
|
|
2570
|
+
): Promise<EntityObjectType<T>[]>;
|
|
1854
2571
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1855
2572
|
options?: Options<T>,
|
|
1856
2573
|
...selectors: Selector[]
|
|
1857
|
-
): Promise<
|
|
2574
|
+
): Promise<EntityInstanceType<T>[]>;
|
|
1858
2575
|
public async getEntities<T extends EntityConstructor = EntityConstructor>(
|
|
1859
2576
|
options: Options<T> = {},
|
|
1860
2577
|
...selectors: Selector[]
|
|
1861
|
-
): Promise<
|
|
1862
|
-
|
|
2578
|
+
): Promise<
|
|
2579
|
+
EntityInstanceType<T>[] | EntityObjectType<T>[] | string[] | number
|
|
2580
|
+
> {
|
|
2581
|
+
const { result: resultPromise, process } = this.getEntitiesRowLike<T>(
|
|
1863
2582
|
// @ts-ignore: options is correct here.
|
|
1864
2583
|
options,
|
|
1865
2584
|
selectors,
|
|
1866
|
-
(options,
|
|
1867
|
-
this.performQuery(options,
|
|
2585
|
+
({ options, selectors, etype }) =>
|
|
2586
|
+
this.performQuery(options, selectors, etype),
|
|
1868
2587
|
() => {
|
|
1869
2588
|
const next: any = result.next();
|
|
1870
2589
|
return next.done ? null : next.value;
|
|
@@ -1873,9 +2592,23 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1873
2592
|
(row) => Number(row.count),
|
|
1874
2593
|
(row) => row.guid,
|
|
1875
2594
|
(row) => ({
|
|
1876
|
-
tags:
|
|
1877
|
-
|
|
1878
|
-
|
|
2595
|
+
tags:
|
|
2596
|
+
row.tags.length > 2
|
|
2597
|
+
? row.tags
|
|
2598
|
+
.slice(1, -1)
|
|
2599
|
+
.split(' ')
|
|
2600
|
+
.filter((tag: string) => tag)
|
|
2601
|
+
: [],
|
|
2602
|
+
cdate: isNaN(Number(row.cdate)) ? Date.now() : Number(row.cdate),
|
|
2603
|
+
mdate: isNaN(Number(row.mdate)) ? Date.now() : Number(row.mdate),
|
|
2604
|
+
user: row.user,
|
|
2605
|
+
group: row.group,
|
|
2606
|
+
acUser: row.acUser,
|
|
2607
|
+
acGroup: row.acGroup,
|
|
2608
|
+
acOther: row.acOther,
|
|
2609
|
+
acRead: row.acRead?.slice(1, -1).split(' ') ?? [],
|
|
2610
|
+
acWrite: row.acWrite?.slice(1, -1).split(' ') ?? [],
|
|
2611
|
+
acFull: row.acFull?.slice(1, -1).split(' ') ?? [],
|
|
1879
2612
|
}),
|
|
1880
2613
|
(row) => ({
|
|
1881
2614
|
name: row.name,
|
|
@@ -1883,9 +2616,11 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1883
2616
|
row.value === 'N'
|
|
1884
2617
|
? JSON.stringify(row.number)
|
|
1885
2618
|
: row.value === 'S'
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
2619
|
+
? JSON.stringify(row.string)
|
|
2620
|
+
: row.value === 'J'
|
|
2621
|
+
? JSON.stringify(row.json)
|
|
2622
|
+
: row.value,
|
|
2623
|
+
}),
|
|
1889
2624
|
);
|
|
1890
2625
|
|
|
1891
2626
|
const result = await resultPromise;
|
|
@@ -1896,231 +2631,374 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
1896
2631
|
return value;
|
|
1897
2632
|
}
|
|
1898
2633
|
|
|
1899
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1900
|
-
options: Options<T> & { return: 'count' },
|
|
1901
|
-
...selectors: Selector[]
|
|
1902
|
-
): number;
|
|
1903
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1904
|
-
options: Options<T> & { return: 'guid' },
|
|
1905
|
-
...selectors: Selector[]
|
|
1906
|
-
): string[];
|
|
1907
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1908
|
-
options?: Options<T>,
|
|
1909
|
-
...selectors: Selector[]
|
|
1910
|
-
): ReturnType<T['factorySync']>[];
|
|
1911
|
-
protected getEntitiesSync<T extends EntityConstructor = EntityConstructor>(
|
|
1912
|
-
options: Options<T> = {},
|
|
1913
|
-
...selectors: Selector[]
|
|
1914
|
-
): ReturnType<T['factorySync']>[] | string[] | number {
|
|
1915
|
-
const { result, process } = this.getEntitesRowLike<T>(
|
|
1916
|
-
// @ts-ignore: options is correct here.
|
|
1917
|
-
options,
|
|
1918
|
-
selectors,
|
|
1919
|
-
(options, formattedSelectors, etype) =>
|
|
1920
|
-
this.performQuerySync(options, formattedSelectors, etype),
|
|
1921
|
-
() => {
|
|
1922
|
-
const next: any = result.next();
|
|
1923
|
-
return next.done ? null : next.value;
|
|
1924
|
-
},
|
|
1925
|
-
() => undefined,
|
|
1926
|
-
(row) => Number(row.count),
|
|
1927
|
-
(row) => row.guid,
|
|
1928
|
-
(row) => ({
|
|
1929
|
-
tags: row.tags.length > 2 ? row.tags.slice(1, -1).split(',') : [],
|
|
1930
|
-
cdate: isNaN(Number(row.cdate)) ? null : Number(row.cdate),
|
|
1931
|
-
mdate: isNaN(Number(row.mdate)) ? null : Number(row.mdate),
|
|
1932
|
-
}),
|
|
1933
|
-
(row) => ({
|
|
1934
|
-
name: row.name,
|
|
1935
|
-
svalue:
|
|
1936
|
-
row.value === 'N'
|
|
1937
|
-
? JSON.stringify(row.number)
|
|
1938
|
-
: row.value === 'S'
|
|
1939
|
-
? JSON.stringify(row.string)
|
|
1940
|
-
: row.value,
|
|
1941
|
-
})
|
|
1942
|
-
);
|
|
1943
|
-
const value = process();
|
|
1944
|
-
if (value instanceof Error) {
|
|
1945
|
-
throw value;
|
|
1946
|
-
}
|
|
1947
|
-
return value;
|
|
1948
|
-
}
|
|
1949
|
-
|
|
1950
2634
|
public async getUID(name: string) {
|
|
1951
2635
|
if (name == null) {
|
|
1952
2636
|
throw new InvalidParametersError('Name not given for UID.');
|
|
1953
2637
|
}
|
|
1954
2638
|
const result = await this.queryGet(
|
|
1955
2639
|
`SELECT \`cur_uid\` FROM ${MySQLDriver.escape(
|
|
1956
|
-
`${this.prefix}uids
|
|
2640
|
+
`${this.prefix}uids`,
|
|
1957
2641
|
)} WHERE \`name\`=@name;`,
|
|
1958
2642
|
{
|
|
1959
2643
|
params: {
|
|
1960
2644
|
name: name,
|
|
1961
2645
|
},
|
|
1962
|
-
}
|
|
2646
|
+
},
|
|
1963
2647
|
);
|
|
1964
2648
|
return (result?.cur_uid as number | null) ?? null;
|
|
1965
2649
|
}
|
|
1966
2650
|
|
|
1967
|
-
public async
|
|
2651
|
+
public async importEntity(entity: {
|
|
2652
|
+
guid: string;
|
|
2653
|
+
cdate: number;
|
|
2654
|
+
mdate: number;
|
|
2655
|
+
tags: string[];
|
|
2656
|
+
sdata: SerializedEntityData;
|
|
2657
|
+
etype: string;
|
|
2658
|
+
}) {
|
|
2659
|
+
return await this.importEntityInternal(entity);
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
public async importEntityTokens(entity: {
|
|
2663
|
+
guid: string;
|
|
2664
|
+
cdate: number;
|
|
2665
|
+
mdate: number;
|
|
2666
|
+
tags: string[];
|
|
2667
|
+
sdata: SerializedEntityData;
|
|
2668
|
+
etype: string;
|
|
2669
|
+
}) {
|
|
2670
|
+
return await this.importEntityInternal(entity, { only: 'tokens' });
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
public async importEntityTilmeldAC(entity: {
|
|
2674
|
+
guid: string;
|
|
2675
|
+
cdate: number;
|
|
2676
|
+
mdate: number;
|
|
2677
|
+
tags: string[];
|
|
2678
|
+
sdata: SerializedEntityData;
|
|
2679
|
+
etype: string;
|
|
2680
|
+
}) {
|
|
2681
|
+
return await this.importEntityInternal(entity, { only: 'tilmeldAC' });
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
private async importEntityInternal(
|
|
2685
|
+
{
|
|
2686
|
+
guid,
|
|
2687
|
+
cdate,
|
|
2688
|
+
mdate,
|
|
2689
|
+
tags,
|
|
2690
|
+
sdata,
|
|
2691
|
+
etype,
|
|
2692
|
+
}: {
|
|
2693
|
+
guid: string;
|
|
2694
|
+
cdate: number;
|
|
2695
|
+
mdate: number;
|
|
2696
|
+
tags: string[];
|
|
2697
|
+
sdata: SerializedEntityData;
|
|
2698
|
+
etype: string;
|
|
2699
|
+
},
|
|
2700
|
+
{ only = undefined }: { only?: 'tokens' | 'tilmeldAC' } = {},
|
|
2701
|
+
) {
|
|
1968
2702
|
try {
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
`
|
|
1974
|
-
`${this.prefix}entities_${etype}
|
|
1975
|
-
)}
|
|
2703
|
+
let promises = [];
|
|
2704
|
+
if (only == null) {
|
|
2705
|
+
promises.push(
|
|
2706
|
+
this.queryRun(
|
|
2707
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
2708
|
+
`${this.prefix}entities_${etype}`,
|
|
2709
|
+
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
1976
2710
|
{
|
|
1977
2711
|
etypes: [etype],
|
|
1978
2712
|
params: {
|
|
1979
2713
|
guid,
|
|
1980
|
-
tags: ' ' + tags.join(' ') + ' ',
|
|
1981
|
-
cdate: isNaN(Number(JSON.parse(sdata.cdate)))
|
|
1982
|
-
? null
|
|
1983
|
-
: Number(JSON.parse(sdata.cdate)),
|
|
1984
|
-
mdate: isNaN(Number(JSON.parse(sdata.mdate)))
|
|
1985
|
-
? null
|
|
1986
|
-
: Number(JSON.parse(sdata.mdate)),
|
|
1987
2714
|
},
|
|
1988
|
-
}
|
|
1989
|
-
)
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
{
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
}
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2715
|
+
},
|
|
2716
|
+
),
|
|
2717
|
+
);
|
|
2718
|
+
promises.push(
|
|
2719
|
+
this.queryRun(
|
|
2720
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
2721
|
+
`${this.prefix}data_${etype}`,
|
|
2722
|
+
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
2723
|
+
{
|
|
2724
|
+
etypes: [etype],
|
|
2725
|
+
params: {
|
|
2726
|
+
guid,
|
|
2727
|
+
},
|
|
2728
|
+
},
|
|
2729
|
+
),
|
|
2730
|
+
);
|
|
2731
|
+
promises.push(
|
|
2732
|
+
this.queryRun(
|
|
2733
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
2734
|
+
`${this.prefix}references_${etype}`,
|
|
2735
|
+
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
2736
|
+
{
|
|
2737
|
+
etypes: [etype],
|
|
2738
|
+
params: {
|
|
2739
|
+
guid,
|
|
2740
|
+
},
|
|
2741
|
+
},
|
|
2742
|
+
),
|
|
2743
|
+
);
|
|
2744
|
+
}
|
|
2745
|
+
if (only == null || only === 'tokens') {
|
|
2746
|
+
promises.push(
|
|
2747
|
+
this.queryRun(
|
|
2748
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
2749
|
+
`${this.prefix}tokens_${etype}`,
|
|
2750
|
+
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
2751
|
+
{
|
|
2752
|
+
etypes: [etype],
|
|
2753
|
+
params: {
|
|
2754
|
+
guid,
|
|
2755
|
+
},
|
|
2756
|
+
},
|
|
2757
|
+
),
|
|
2758
|
+
);
|
|
2759
|
+
}
|
|
2760
|
+
if (only == null) {
|
|
2761
|
+
promises.push(
|
|
2762
|
+
this.queryRun(
|
|
2763
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
2764
|
+
`${this.prefix}uniques_${etype}`,
|
|
2765
|
+
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
2766
|
+
{
|
|
2767
|
+
etypes: [etype],
|
|
2768
|
+
params: {
|
|
2769
|
+
guid,
|
|
2770
|
+
},
|
|
2771
|
+
},
|
|
2772
|
+
),
|
|
2773
|
+
);
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
await Promise.all(promises);
|
|
2777
|
+
promises = [];
|
|
2778
|
+
|
|
2779
|
+
if (only == null) {
|
|
2780
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull } =
|
|
2781
|
+
this.removeAndReturnACValues(etype, {}, sdata);
|
|
2782
|
+
|
|
2783
|
+
await this.queryRun(
|
|
2784
|
+
`INSERT INTO ${MySQLDriver.escape(
|
|
2785
|
+
`${this.prefix}entities_${etype}`,
|
|
2786
|
+
)} (\`guid\`, \`tags\`, \`cdate\`, \`mdate\`, \`user\`, \`group\`, \`acUser\`, \`acGroup\`, \`acOther\`, \`acRead\`, \`acWrite\`, \`acFull\`) VALUES (UNHEX(@guid), @tags, @cdate, @mdate, ${user == null ? '@user' : 'UNHEX(@user)'}, ${group == null ? '@group' : 'UNHEX(@group)'}, @acUser, @acGroup, @acOther, @acRead, @acWrite, @acFull);`,
|
|
2787
|
+
{
|
|
2788
|
+
etypes: [etype],
|
|
2789
|
+
params: {
|
|
2790
|
+
guid,
|
|
2791
|
+
tags: ' ' + tags.join(' ') + ' ',
|
|
2792
|
+
cdate: isNaN(cdate) ? null : cdate,
|
|
2793
|
+
mdate: isNaN(mdate) ? null : mdate,
|
|
2794
|
+
user,
|
|
2795
|
+
group,
|
|
2796
|
+
acUser,
|
|
2797
|
+
acGroup,
|
|
2798
|
+
acOther,
|
|
2799
|
+
acRead: acRead && ' ' + acRead.join(' ') + ' ',
|
|
2800
|
+
acWrite: acWrite && ' ' + acWrite.join(' ') + ' ',
|
|
2801
|
+
acFull: acFull && ' ' + acFull.join(' ') + ' ',
|
|
2802
|
+
},
|
|
2803
|
+
},
|
|
2804
|
+
);
|
|
2805
|
+
|
|
2806
|
+
for (const name in sdata) {
|
|
2807
|
+
const value = sdata[name];
|
|
2808
|
+
const uvalue = JSON.parse(value);
|
|
2809
|
+
if (value === undefined) {
|
|
2810
|
+
continue;
|
|
2811
|
+
}
|
|
2812
|
+
const storageValue =
|
|
2813
|
+
typeof uvalue === 'number'
|
|
2814
|
+
? 'N'
|
|
2815
|
+
: typeof uvalue === 'string'
|
|
2043
2816
|
? 'S'
|
|
2044
|
-
:
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2817
|
+
: 'J';
|
|
2818
|
+
const jsonValue = storageValue === 'J' ? value : null;
|
|
2819
|
+
|
|
2820
|
+
promises.push(
|
|
2821
|
+
this.queryRun(
|
|
2822
|
+
`INSERT INTO ${MySQLDriver.escape(
|
|
2823
|
+
`${this.prefix}data_${etype}`,
|
|
2824
|
+
)} (\`guid\`, \`name\`, \`value\`, \`json\`, \`string\`, \`number\`, \`truthy\`) VALUES (UNHEX(@guid), @name, @storageValue, @jsonValue, @string, @number, @truthy);`,
|
|
2825
|
+
{
|
|
2826
|
+
etypes: [etype],
|
|
2827
|
+
params: {
|
|
2828
|
+
guid,
|
|
2829
|
+
name,
|
|
2830
|
+
storageValue,
|
|
2831
|
+
jsonValue,
|
|
2832
|
+
string: storageValue === 'J' ? null : `${uvalue}`,
|
|
2833
|
+
number: isNaN(Number(uvalue)) ? null : Number(uvalue),
|
|
2834
|
+
truthy: !!uvalue,
|
|
2835
|
+
},
|
|
2836
|
+
},
|
|
2837
|
+
),
|
|
2838
|
+
);
|
|
2839
|
+
|
|
2840
|
+
const references = this.findReferences(value);
|
|
2841
|
+
for (const reference of references) {
|
|
2061
2842
|
promises.push(
|
|
2062
2843
|
this.queryRun(
|
|
2063
2844
|
`INSERT INTO ${MySQLDriver.escape(
|
|
2064
|
-
`${this.prefix}
|
|
2065
|
-
)} (\`guid\`, \`name\`, \`
|
|
2845
|
+
`${this.prefix}references_${etype}`,
|
|
2846
|
+
)} (\`guid\`, \`name\`, \`reference\`) VALUES (UNHEX(@guid), @name, UNHEX(@reference));`,
|
|
2066
2847
|
{
|
|
2067
2848
|
etypes: [etype],
|
|
2068
2849
|
params: {
|
|
2069
2850
|
guid,
|
|
2070
2851
|
name,
|
|
2071
|
-
|
|
2072
|
-
string: `${uvalue}`,
|
|
2073
|
-
number: isNaN(Number(uvalue)) ? null : Number(uvalue),
|
|
2852
|
+
reference,
|
|
2074
2853
|
},
|
|
2075
|
-
}
|
|
2076
|
-
)
|
|
2854
|
+
},
|
|
2855
|
+
),
|
|
2077
2856
|
);
|
|
2078
|
-
|
|
2079
|
-
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
if (only === 'tilmeldAC') {
|
|
2862
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull } =
|
|
2863
|
+
this.removeAndReturnACValues(etype, {}, sdata);
|
|
2864
|
+
|
|
2865
|
+
promises.push(
|
|
2866
|
+
this.queryRun(
|
|
2867
|
+
`UPDATE ${MySQLDriver.escape(
|
|
2868
|
+
`${this.prefix}entities_${etype}`,
|
|
2869
|
+
)} SET \`user\`=${user == null ? '@user' : 'UNHEX(@user)'}, \`group\`=${group == null ? '@group' : 'UNHEX(@group)'}, \`acUser\`=@acUser, \`acGroup\`=@acGroup, \`acOther\`=@acOther, \`acRead\`=@acRead, \`acWrite\`=@acWrite, \`acFull\`=@acFull WHERE \`guid\`=UNHEX(@guid);`,
|
|
2870
|
+
{
|
|
2871
|
+
etypes: [etype],
|
|
2872
|
+
params: {
|
|
2873
|
+
user,
|
|
2874
|
+
group,
|
|
2875
|
+
acUser,
|
|
2876
|
+
acGroup,
|
|
2877
|
+
acOther,
|
|
2878
|
+
acRead: acRead && ' ' + acRead.join(' ') + ' ',
|
|
2879
|
+
acWrite: acWrite && ' ' + acWrite.join(' ') + ' ',
|
|
2880
|
+
acFull: acFull && ' ' + acFull.join(' ') + ' ',
|
|
2881
|
+
guid,
|
|
2882
|
+
},
|
|
2883
|
+
},
|
|
2884
|
+
),
|
|
2885
|
+
);
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
2889
|
+
|
|
2890
|
+
if (only == null || only === 'tokens') {
|
|
2891
|
+
for (let name in sdata) {
|
|
2892
|
+
let tokenString: string | null = null;
|
|
2893
|
+
try {
|
|
2894
|
+
tokenString = EntityClass.getFTSText(name, JSON.parse(sdata[name]));
|
|
2895
|
+
} catch (e: any) {
|
|
2896
|
+
// Ignore error.
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
if (tokenString != null) {
|
|
2900
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
2901
|
+
while (tokens.length) {
|
|
2902
|
+
const currentTokens = tokens.splice(0, 100);
|
|
2903
|
+
const params: { [k: string]: any } = {
|
|
2904
|
+
guid,
|
|
2905
|
+
name,
|
|
2906
|
+
};
|
|
2907
|
+
const values: string[] = [];
|
|
2908
|
+
|
|
2909
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
2910
|
+
const token = currentTokens[i];
|
|
2911
|
+
params['token' + i] = token.token;
|
|
2912
|
+
params['position' + i] = token.position;
|
|
2913
|
+
params['stem' + i] = token.stem;
|
|
2914
|
+
values.push(
|
|
2915
|
+
'(UNHEX(@guid), @name, @token' +
|
|
2916
|
+
i +
|
|
2917
|
+
', @position' +
|
|
2918
|
+
i +
|
|
2919
|
+
', @stem' +
|
|
2920
|
+
i +
|
|
2921
|
+
')',
|
|
2922
|
+
);
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2080
2925
|
promises.push(
|
|
2081
2926
|
this.queryRun(
|
|
2082
2927
|
`INSERT INTO ${MySQLDriver.escape(
|
|
2083
|
-
`${this.prefix}
|
|
2084
|
-
)} (\`guid\`, \`name\`, \`
|
|
2928
|
+
`${this.prefix}tokens_${etype}`,
|
|
2929
|
+
)} (\`guid\`, \`name\`, \`token\`, \`position\`, \`stem\`) VALUES ${values.join(', ')};`,
|
|
2085
2930
|
{
|
|
2086
2931
|
etypes: [etype],
|
|
2087
|
-
params
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
reference,
|
|
2091
|
-
},
|
|
2092
|
-
}
|
|
2093
|
-
)
|
|
2932
|
+
params,
|
|
2933
|
+
},
|
|
2934
|
+
),
|
|
2094
2935
|
);
|
|
2095
2936
|
}
|
|
2096
2937
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
if (only == null) {
|
|
2942
|
+
const uniques = await EntityClass.getUniques({
|
|
2943
|
+
guid,
|
|
2944
|
+
cdate,
|
|
2945
|
+
mdate,
|
|
2946
|
+
tags,
|
|
2947
|
+
data: {},
|
|
2948
|
+
sdata,
|
|
2949
|
+
});
|
|
2950
|
+
for (const unique of uniques) {
|
|
2951
|
+
promises.push(
|
|
2952
|
+
this.queryRun(
|
|
2953
|
+
`INSERT INTO ${MySQLDriver.escape(
|
|
2954
|
+
`${this.prefix}uniques_${etype}`,
|
|
2955
|
+
)} (\`guid\`, \`unique\`) VALUES (UNHEX(@guid), @unique);`,
|
|
2956
|
+
{
|
|
2957
|
+
etypes: [etype],
|
|
2958
|
+
params: {
|
|
2959
|
+
guid,
|
|
2960
|
+
unique,
|
|
2961
|
+
},
|
|
2108
2962
|
},
|
|
2109
|
-
|
|
2963
|
+
).catch((e: any) => {
|
|
2964
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2965
|
+
this.nymph.config.debugError(
|
|
2966
|
+
'mysql',
|
|
2967
|
+
`Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`,
|
|
2968
|
+
);
|
|
2969
|
+
}
|
|
2970
|
+
return e;
|
|
2971
|
+
}),
|
|
2110
2972
|
);
|
|
2111
|
-
},
|
|
2112
|
-
async () => {
|
|
2113
|
-
await this.internalTransaction('nymph-import');
|
|
2114
|
-
},
|
|
2115
|
-
async () => {
|
|
2116
|
-
await this.commit('nymph-import');
|
|
2117
2973
|
}
|
|
2118
|
-
|
|
2974
|
+
}
|
|
2119
2975
|
|
|
2120
|
-
|
|
2976
|
+
await Promise.all(promises);
|
|
2977
|
+
} catch (e: any) {
|
|
2978
|
+
this.nymph.config.debugError('mysql', `Import entity error: "${e}"`);
|
|
2979
|
+
throw e;
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2983
|
+
public async importUID({ name, value }: { name: string; value: number }) {
|
|
2984
|
+
try {
|
|
2985
|
+
await this.internalTransaction(`nymph-import-uid-${name}`);
|
|
2986
|
+
await this.queryRun(
|
|
2987
|
+
`INSERT INTO ${MySQLDriver.escape(
|
|
2988
|
+
`${this.prefix}uids`,
|
|
2989
|
+
)} (\`name\`, \`cur_uid\`) VALUES (@name, @value) ON DUPLICATE KEY UPDATE \`cur_uid\`=@value;`,
|
|
2990
|
+
{
|
|
2991
|
+
params: {
|
|
2992
|
+
name,
|
|
2993
|
+
value,
|
|
2994
|
+
},
|
|
2995
|
+
},
|
|
2996
|
+
);
|
|
2997
|
+
await this.commit(`nymph-import-uid-${name}`);
|
|
2121
2998
|
} catch (e: any) {
|
|
2122
|
-
|
|
2123
|
-
|
|
2999
|
+
this.nymph.config.debugError('mysql', `Import UID error: "${e}"`);
|
|
3000
|
+
await this.rollback(`nymph-import-uid-${name}`);
|
|
3001
|
+
throw e;
|
|
2124
3002
|
}
|
|
2125
3003
|
}
|
|
2126
3004
|
|
|
@@ -2129,55 +3007,57 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2129
3007
|
throw new InvalidParametersError('Name not given for UID.');
|
|
2130
3008
|
}
|
|
2131
3009
|
await this.internalTransaction('nymph-newuid');
|
|
3010
|
+
let curUid: number | null = null;
|
|
2132
3011
|
try {
|
|
2133
3012
|
const lock = await this.queryGet(
|
|
2134
3013
|
`SELECT GET_LOCK(${MySQLDriver.escapeValue(
|
|
2135
|
-
`${this.prefix}uids_${name}
|
|
2136
|
-
)}, 10) AS \`lock
|
|
3014
|
+
`${this.prefix}uids_${name}`,
|
|
3015
|
+
)}, 10) AS \`lock\`;`,
|
|
2137
3016
|
);
|
|
2138
3017
|
if (lock.lock !== 1) {
|
|
2139
3018
|
throw new QueryFailedError("Couldn't get lock for UID: " + name);
|
|
2140
3019
|
}
|
|
2141
|
-
let curUid: number | null = null;
|
|
2142
3020
|
await this.queryRun(
|
|
2143
3021
|
`INSERT INTO ${MySQLDriver.escape(
|
|
2144
|
-
`${this.prefix}uids
|
|
3022
|
+
`${this.prefix}uids`,
|
|
2145
3023
|
)} (\`name\`, \`cur_uid\`) VALUES (@name, 1) ON DUPLICATE KEY UPDATE \`cur_uid\`=\`cur_uid\`+1;`,
|
|
2146
3024
|
{
|
|
2147
3025
|
params: {
|
|
2148
3026
|
name,
|
|
2149
3027
|
},
|
|
2150
|
-
}
|
|
3028
|
+
},
|
|
2151
3029
|
);
|
|
2152
3030
|
const result = await this.queryGet(
|
|
2153
3031
|
`SELECT \`cur_uid\` FROM ${MySQLDriver.escape(
|
|
2154
|
-
`${this.prefix}uids
|
|
3032
|
+
`${this.prefix}uids`,
|
|
2155
3033
|
)} WHERE \`name\`=@name;`,
|
|
2156
3034
|
{
|
|
2157
3035
|
params: {
|
|
2158
3036
|
name,
|
|
2159
3037
|
},
|
|
2160
|
-
}
|
|
3038
|
+
},
|
|
2161
3039
|
);
|
|
2162
3040
|
await this.queryRun(
|
|
2163
3041
|
`SELECT RELEASE_LOCK(${MySQLDriver.escapeValue(
|
|
2164
|
-
`${this.prefix}uids_${name}
|
|
2165
|
-
)})
|
|
3042
|
+
`${this.prefix}uids_${name}`,
|
|
3043
|
+
)});`,
|
|
2166
3044
|
);
|
|
2167
|
-
await this.commit('nymph-newuid');
|
|
2168
3045
|
curUid = result.cur_uid ?? null;
|
|
2169
|
-
return curUid;
|
|
2170
3046
|
} catch (e: any) {
|
|
3047
|
+
this.nymph.config.debugError('mysql', `New UID error: "${e}"`);
|
|
2171
3048
|
if (e?.message !== "Couldn't get lock for UID: " + name) {
|
|
2172
3049
|
await this.queryRun(
|
|
2173
3050
|
`SELECT RELEASE_LOCK(${MySQLDriver.escapeValue(
|
|
2174
|
-
`${this.prefix}uids_${name}
|
|
2175
|
-
)})
|
|
3051
|
+
`${this.prefix}uids_${name}`,
|
|
3052
|
+
)});`,
|
|
2176
3053
|
);
|
|
2177
3054
|
}
|
|
2178
3055
|
await this.rollback('nymph-newuid');
|
|
2179
3056
|
throw e;
|
|
2180
3057
|
}
|
|
3058
|
+
|
|
3059
|
+
await this.commit('nymph-newuid');
|
|
3060
|
+
return curUid;
|
|
2181
3061
|
}
|
|
2182
3062
|
|
|
2183
3063
|
public async renameUID(oldName: string, newName: string) {
|
|
@@ -2186,14 +3066,14 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2186
3066
|
}
|
|
2187
3067
|
await this.queryRun(
|
|
2188
3068
|
`UPDATE ${MySQLDriver.escape(
|
|
2189
|
-
`${this.prefix}uids
|
|
3069
|
+
`${this.prefix}uids`,
|
|
2190
3070
|
)} SET \`name\`=@newName WHERE \`name\`=@oldName;`,
|
|
2191
3071
|
{
|
|
2192
3072
|
params: {
|
|
2193
3073
|
newName,
|
|
2194
3074
|
oldName,
|
|
2195
3075
|
},
|
|
2196
|
-
}
|
|
3076
|
+
},
|
|
2197
3077
|
);
|
|
2198
3078
|
return true;
|
|
2199
3079
|
}
|
|
@@ -2201,7 +3081,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2201
3081
|
public async rollback(name: string) {
|
|
2202
3082
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
2203
3083
|
throw new InvalidParametersError(
|
|
2204
|
-
'Transaction rollback attempted without a name.'
|
|
3084
|
+
'Transaction rollback attempted without a name.',
|
|
2205
3085
|
);
|
|
2206
3086
|
}
|
|
2207
3087
|
if (!this.transaction || this.transaction.count === 0) {
|
|
@@ -2226,12 +3106,15 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2226
3106
|
guid: string,
|
|
2227
3107
|
data: EntityData,
|
|
2228
3108
|
sdata: SerializedEntityData,
|
|
2229
|
-
|
|
3109
|
+
uniques: string[],
|
|
3110
|
+
etype: string,
|
|
2230
3111
|
) => {
|
|
3112
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
3113
|
+
|
|
2231
3114
|
const runInsertQuery = async (
|
|
2232
3115
|
name: string,
|
|
2233
3116
|
value: any,
|
|
2234
|
-
svalue: string
|
|
3117
|
+
svalue: string,
|
|
2235
3118
|
) => {
|
|
2236
3119
|
if (value === undefined) {
|
|
2237
3120
|
return;
|
|
@@ -2240,47 +3123,38 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2240
3123
|
typeof value === 'number'
|
|
2241
3124
|
? 'N'
|
|
2242
3125
|
: typeof value === 'string'
|
|
2243
|
-
|
|
2244
|
-
|
|
3126
|
+
? 'S'
|
|
3127
|
+
: 'J';
|
|
3128
|
+
const jsonValue = storageValue === 'J' ? svalue : null;
|
|
3129
|
+
|
|
2245
3130
|
const promises = [];
|
|
3131
|
+
|
|
2246
3132
|
promises.push(
|
|
2247
3133
|
this.queryRun(
|
|
2248
3134
|
`INSERT INTO ${MySQLDriver.escape(
|
|
2249
|
-
`${this.prefix}data_${etype}
|
|
2250
|
-
)} (\`guid\`, \`name\`, \`value\`) VALUES (UNHEX(@guid), @name, @storageValue);`,
|
|
3135
|
+
`${this.prefix}data_${etype}`,
|
|
3136
|
+
)} (\`guid\`, \`name\`, \`value\`, \`json\`, \`string\`, \`number\`, \`truthy\`) VALUES (UNHEX(@guid), @name, @storageValue, @jsonValue, @string, @number, @truthy);`,
|
|
2251
3137
|
{
|
|
2252
3138
|
etypes: [etype],
|
|
2253
3139
|
params: {
|
|
2254
3140
|
guid,
|
|
2255
3141
|
name,
|
|
2256
3142
|
storageValue,
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
)
|
|
2260
|
-
);
|
|
2261
|
-
promises.push(
|
|
2262
|
-
this.queryRun(
|
|
2263
|
-
`INSERT INTO ${MySQLDriver.escape(
|
|
2264
|
-
`${this.prefix}comparisons_${etype}`
|
|
2265
|
-
)} (\`guid\`, \`name\`, \`truthy\`, \`string\`, \`number\`) VALUES (UNHEX(@guid), @name, @truthy, @string, @number);`,
|
|
2266
|
-
{
|
|
2267
|
-
etypes: [etype],
|
|
2268
|
-
params: {
|
|
2269
|
-
guid,
|
|
2270
|
-
name,
|
|
2271
|
-
truthy: !!value,
|
|
2272
|
-
string: `${value}`,
|
|
3143
|
+
jsonValue,
|
|
3144
|
+
string: storageValue === 'J' ? null : `${value}`,
|
|
2273
3145
|
number: isNaN(Number(value)) ? null : Number(value),
|
|
3146
|
+
truthy: !!value,
|
|
2274
3147
|
},
|
|
2275
|
-
}
|
|
2276
|
-
)
|
|
3148
|
+
},
|
|
3149
|
+
),
|
|
2277
3150
|
);
|
|
3151
|
+
|
|
2278
3152
|
const references = this.findReferences(svalue);
|
|
2279
3153
|
for (const reference of references) {
|
|
2280
3154
|
promises.push(
|
|
2281
3155
|
this.queryRun(
|
|
2282
3156
|
`INSERT INTO ${MySQLDriver.escape(
|
|
2283
|
-
`${this.prefix}references_${etype}
|
|
3157
|
+
`${this.prefix}references_${etype}`,
|
|
2284
3158
|
)} (\`guid\`, \`name\`, \`reference\`) VALUES (UNHEX(@guid), @name, UNHEX(@reference));`,
|
|
2285
3159
|
{
|
|
2286
3160
|
etypes: [etype],
|
|
@@ -2289,12 +3163,85 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2289
3163
|
name,
|
|
2290
3164
|
reference,
|
|
2291
3165
|
},
|
|
2292
|
-
}
|
|
2293
|
-
)
|
|
3166
|
+
},
|
|
3167
|
+
),
|
|
2294
3168
|
);
|
|
2295
3169
|
}
|
|
3170
|
+
|
|
3171
|
+
let tokenString: string | null = null;
|
|
3172
|
+
try {
|
|
3173
|
+
tokenString = EntityClass.getFTSText(name, value);
|
|
3174
|
+
} catch (e: any) {
|
|
3175
|
+
// Ignore error.
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
if (tokenString != null) {
|
|
3179
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
3180
|
+
while (tokens.length) {
|
|
3181
|
+
const currentTokens = tokens.splice(0, 100);
|
|
3182
|
+
const params: { [k: string]: any } = {
|
|
3183
|
+
guid,
|
|
3184
|
+
name,
|
|
3185
|
+
};
|
|
3186
|
+
const values: string[] = [];
|
|
3187
|
+
|
|
3188
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
3189
|
+
const token = currentTokens[i];
|
|
3190
|
+
params['token' + i] = token.token;
|
|
3191
|
+
params['position' + i] = token.position;
|
|
3192
|
+
params['stem' + i] = token.stem;
|
|
3193
|
+
values.push(
|
|
3194
|
+
'(UNHEX(@guid), @name, @token' +
|
|
3195
|
+
i +
|
|
3196
|
+
', @position' +
|
|
3197
|
+
i +
|
|
3198
|
+
', @stem' +
|
|
3199
|
+
i +
|
|
3200
|
+
')',
|
|
3201
|
+
);
|
|
3202
|
+
}
|
|
3203
|
+
|
|
3204
|
+
promises.push(
|
|
3205
|
+
this.queryRun(
|
|
3206
|
+
`INSERT INTO ${MySQLDriver.escape(
|
|
3207
|
+
`${this.prefix}tokens_${etype}`,
|
|
3208
|
+
)} (\`guid\`, \`name\`, \`token\`, \`position\`, \`stem\`) VALUES ${values.join(', ')};`,
|
|
3209
|
+
{
|
|
3210
|
+
etypes: [etype],
|
|
3211
|
+
params,
|
|
3212
|
+
},
|
|
3213
|
+
),
|
|
3214
|
+
);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
|
|
2296
3218
|
await Promise.all(promises);
|
|
2297
3219
|
};
|
|
3220
|
+
|
|
3221
|
+
for (const unique of uniques) {
|
|
3222
|
+
try {
|
|
3223
|
+
await this.queryRun(
|
|
3224
|
+
`INSERT INTO ${MySQLDriver.escape(
|
|
3225
|
+
`${this.prefix}uniques_${etype}`,
|
|
3226
|
+
)} (\`guid\`, \`unique\`) VALUES (UNHEX(@guid), @unique);`,
|
|
3227
|
+
{
|
|
3228
|
+
etypes: [etype],
|
|
3229
|
+
params: {
|
|
3230
|
+
guid,
|
|
3231
|
+
unique,
|
|
3232
|
+
},
|
|
3233
|
+
},
|
|
3234
|
+
);
|
|
3235
|
+
} catch (e: any) {
|
|
3236
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
3237
|
+
this.nymph.config.debugError(
|
|
3238
|
+
'mysql',
|
|
3239
|
+
`Save entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`,
|
|
3240
|
+
);
|
|
3241
|
+
}
|
|
3242
|
+
throw e;
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
2298
3245
|
for (const name in data) {
|
|
2299
3246
|
await runInsertQuery(name, data[name], JSON.stringify(data[name]));
|
|
2300
3247
|
}
|
|
@@ -2302,109 +3249,173 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2302
3249
|
await runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
|
|
2303
3250
|
}
|
|
2304
3251
|
};
|
|
3252
|
+
let inTransaction = false;
|
|
2305
3253
|
try {
|
|
2306
3254
|
const result = await this.saveEntityRowLike(
|
|
2307
3255
|
entity,
|
|
2308
|
-
async (
|
|
3256
|
+
async ({ guid, tags, data, sdata, uniques, cdate, etype }) => {
|
|
3257
|
+
if (
|
|
3258
|
+
Object.keys(data).length === 0 &&
|
|
3259
|
+
Object.keys(sdata).length === 0
|
|
3260
|
+
) {
|
|
3261
|
+
return false;
|
|
3262
|
+
}
|
|
3263
|
+
let {
|
|
3264
|
+
user,
|
|
3265
|
+
group,
|
|
3266
|
+
acUser,
|
|
3267
|
+
acGroup,
|
|
3268
|
+
acOther,
|
|
3269
|
+
acRead,
|
|
3270
|
+
acWrite,
|
|
3271
|
+
acFull,
|
|
3272
|
+
} = this.removeAndReturnACValues(etype, data, sdata);
|
|
2309
3273
|
await this.queryRun(
|
|
2310
3274
|
`INSERT INTO ${MySQLDriver.escape(
|
|
2311
|
-
`${this.prefix}entities_${etype}
|
|
2312
|
-
)} (\`guid\`, \`tags\`, \`cdate\`, \`mdate\`) VALUES (UNHEX(@guid), @tags, @cdate, @cdate);`,
|
|
3275
|
+
`${this.prefix}entities_${etype}`,
|
|
3276
|
+
)} (\`guid\`, \`tags\`, \`cdate\`, \`mdate\`, \`user\`, \`group\`, \`acUser\`, \`acGroup\`, \`acOther\`, \`acRead\`, \`acWrite\`, \`acFull\`) VALUES (UNHEX(@guid), @tags, @cdate, @cdate, ${user == null ? '@user' : 'UNHEX(@user)'}, ${group == null ? '@group' : 'UNHEX(@group)'}, @acUser, @acGroup, @acOther, @acRead, @acWrite, @acFull);`,
|
|
2313
3277
|
{
|
|
2314
3278
|
etypes: [etype],
|
|
2315
3279
|
params: {
|
|
2316
3280
|
guid,
|
|
2317
3281
|
tags: ' ' + tags.join(' ') + ' ',
|
|
2318
3282
|
cdate,
|
|
3283
|
+
user,
|
|
3284
|
+
group,
|
|
3285
|
+
acUser,
|
|
3286
|
+
acGroup,
|
|
3287
|
+
acOther,
|
|
3288
|
+
acRead: acRead && ' ' + acRead.join(' ') + ' ',
|
|
3289
|
+
acWrite: acWrite && ' ' + acWrite.join(' ') + ' ',
|
|
3290
|
+
acFull: acFull && ' ' + acFull.join(' ') + ' ',
|
|
2319
3291
|
},
|
|
2320
|
-
}
|
|
3292
|
+
},
|
|
2321
3293
|
);
|
|
2322
|
-
await insertData(guid, data, sdata, etype);
|
|
3294
|
+
await insertData(guid, data, sdata, uniques, etype);
|
|
2323
3295
|
return true;
|
|
2324
3296
|
},
|
|
2325
|
-
async (entity, guid, tags, data, sdata, mdate, etype) => {
|
|
3297
|
+
async ({ entity, guid, tags, data, sdata, uniques, mdate, etype }) => {
|
|
3298
|
+
if (
|
|
3299
|
+
Object.keys(data).length === 0 &&
|
|
3300
|
+
Object.keys(sdata).length === 0
|
|
3301
|
+
) {
|
|
3302
|
+
return false;
|
|
3303
|
+
}
|
|
3304
|
+
let {
|
|
3305
|
+
user,
|
|
3306
|
+
group,
|
|
3307
|
+
acUser,
|
|
3308
|
+
acGroup,
|
|
3309
|
+
acOther,
|
|
3310
|
+
acRead,
|
|
3311
|
+
acWrite,
|
|
3312
|
+
acFull,
|
|
3313
|
+
} = this.removeAndReturnACValues(etype, data, sdata);
|
|
2326
3314
|
if (this.config.rowLocking) {
|
|
2327
3315
|
const promises = [];
|
|
2328
3316
|
promises.push(
|
|
2329
3317
|
this.queryRun(
|
|
2330
3318
|
`SELECT 1 FROM ${MySQLDriver.escape(
|
|
2331
|
-
`${this.prefix}entities_${etype}
|
|
3319
|
+
`${this.prefix}entities_${etype}`,
|
|
2332
3320
|
)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`,
|
|
2333
3321
|
{
|
|
2334
3322
|
etypes: [etype],
|
|
2335
3323
|
params: {
|
|
2336
3324
|
guid,
|
|
2337
3325
|
},
|
|
2338
|
-
}
|
|
2339
|
-
)
|
|
3326
|
+
},
|
|
3327
|
+
),
|
|
2340
3328
|
);
|
|
2341
3329
|
promises.push(
|
|
2342
3330
|
this.queryRun(
|
|
2343
3331
|
`SELECT 1 FROM ${MySQLDriver.escape(
|
|
2344
|
-
`${this.prefix}data_${etype}
|
|
3332
|
+
`${this.prefix}data_${etype}`,
|
|
2345
3333
|
)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`,
|
|
2346
3334
|
{
|
|
2347
3335
|
etypes: [etype],
|
|
2348
3336
|
params: {
|
|
2349
3337
|
guid,
|
|
2350
3338
|
},
|
|
2351
|
-
}
|
|
2352
|
-
)
|
|
3339
|
+
},
|
|
3340
|
+
),
|
|
2353
3341
|
);
|
|
2354
3342
|
promises.push(
|
|
2355
3343
|
this.queryRun(
|
|
2356
3344
|
`SELECT 1 FROM ${MySQLDriver.escape(
|
|
2357
|
-
`${this.prefix}
|
|
3345
|
+
`${this.prefix}references_${etype}`,
|
|
2358
3346
|
)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`,
|
|
2359
3347
|
{
|
|
2360
3348
|
etypes: [etype],
|
|
2361
3349
|
params: {
|
|
2362
3350
|
guid,
|
|
2363
3351
|
},
|
|
2364
|
-
}
|
|
2365
|
-
)
|
|
3352
|
+
},
|
|
3353
|
+
),
|
|
2366
3354
|
);
|
|
2367
3355
|
promises.push(
|
|
2368
3356
|
this.queryRun(
|
|
2369
3357
|
`SELECT 1 FROM ${MySQLDriver.escape(
|
|
2370
|
-
`${this.prefix}
|
|
3358
|
+
`${this.prefix}tokens_${etype}`,
|
|
2371
3359
|
)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`,
|
|
2372
3360
|
{
|
|
2373
3361
|
etypes: [etype],
|
|
2374
3362
|
params: {
|
|
2375
3363
|
guid,
|
|
2376
3364
|
},
|
|
2377
|
-
}
|
|
2378
|
-
)
|
|
3365
|
+
},
|
|
3366
|
+
),
|
|
3367
|
+
);
|
|
3368
|
+
promises.push(
|
|
3369
|
+
this.queryRun(
|
|
3370
|
+
`SELECT 1 FROM ${MySQLDriver.escape(
|
|
3371
|
+
`${this.prefix}uniques_${etype}`,
|
|
3372
|
+
)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`,
|
|
3373
|
+
{
|
|
3374
|
+
etypes: [etype],
|
|
3375
|
+
params: {
|
|
3376
|
+
guid,
|
|
3377
|
+
},
|
|
3378
|
+
},
|
|
3379
|
+
),
|
|
2379
3380
|
);
|
|
2380
3381
|
await Promise.all(promises);
|
|
2381
3382
|
}
|
|
2382
3383
|
if (this.config.tableLocking) {
|
|
2383
3384
|
await this.queryRun(
|
|
2384
3385
|
`LOCK TABLES ${MySQLDriver.escape(
|
|
2385
|
-
`${this.prefix}entities_${etype}
|
|
3386
|
+
`${this.prefix}entities_${etype}`,
|
|
2386
3387
|
)} WRITE, ${MySQLDriver.escape(
|
|
2387
|
-
`${this.prefix}data_${etype}
|
|
3388
|
+
`${this.prefix}data_${etype}`,
|
|
2388
3389
|
)} WRITE, ${MySQLDriver.escape(
|
|
2389
|
-
`${this.prefix}
|
|
3390
|
+
`${this.prefix}references_${etype}`,
|
|
2390
3391
|
)} WRITE, ${MySQLDriver.escape(
|
|
2391
|
-
`${this.prefix}
|
|
2392
|
-
)} WRITE
|
|
3392
|
+
`${this.prefix}tokens_${etype}`,
|
|
3393
|
+
)} WRITE, ${MySQLDriver.escape(
|
|
3394
|
+
`${this.prefix}uniques_${etype}`,
|
|
3395
|
+
)} WRITE;`,
|
|
2393
3396
|
);
|
|
2394
3397
|
}
|
|
2395
3398
|
const info = await this.queryRun(
|
|
2396
3399
|
`UPDATE ${MySQLDriver.escape(
|
|
2397
|
-
`${this.prefix}entities_${etype}
|
|
2398
|
-
)} SET \`tags\`=@tags, \`mdate\`=@mdate WHERE \`guid\`=UNHEX(@guid) AND \`mdate\` <= @emdate;`,
|
|
3400
|
+
`${this.prefix}entities_${etype}`,
|
|
3401
|
+
)} SET \`tags\`=@tags, \`mdate\`=@mdate, \`user\`=${user == null ? '@user' : 'UNHEX(@user)'}, \`group\`=${group == null ? '@group' : 'UNHEX(@group)'}, \`acUser\`=@acUser, \`acGroup\`=@acGroup, \`acOther\`=@acOther, \`acRead\`=@acRead, \`acWrite\`=@acWrite, \`acFull\`=@acFull WHERE \`guid\`=UNHEX(@guid) AND \`mdate\` <= @emdate;`,
|
|
2399
3402
|
{
|
|
2400
3403
|
etypes: [etype],
|
|
2401
3404
|
params: {
|
|
2402
3405
|
tags: ' ' + tags.join(' ') + ' ',
|
|
2403
3406
|
mdate,
|
|
3407
|
+
user,
|
|
3408
|
+
group,
|
|
3409
|
+
acUser,
|
|
3410
|
+
acGroup,
|
|
3411
|
+
acOther,
|
|
3412
|
+
acRead: acRead && ' ' + acRead.join(' ') + ' ',
|
|
3413
|
+
acWrite: acWrite && ' ' + acWrite.join(' ') + ' ',
|
|
3414
|
+
acFull: acFull && ' ' + acFull.join(' ') + ' ',
|
|
2404
3415
|
guid,
|
|
2405
3416
|
emdate: isNaN(Number(entity.mdate)) ? 0 : Number(entity.mdate),
|
|
2406
3417
|
},
|
|
2407
|
-
}
|
|
3418
|
+
},
|
|
2408
3419
|
);
|
|
2409
3420
|
let success = false;
|
|
2410
3421
|
if (info.changes === 1) {
|
|
@@ -2412,44 +3423,57 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2412
3423
|
promises.push(
|
|
2413
3424
|
this.queryRun(
|
|
2414
3425
|
`DELETE FROM ${MySQLDriver.escape(
|
|
2415
|
-
`${this.prefix}data_${etype}
|
|
3426
|
+
`${this.prefix}data_${etype}`,
|
|
2416
3427
|
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
2417
3428
|
{
|
|
2418
3429
|
etypes: [etype],
|
|
2419
3430
|
params: {
|
|
2420
3431
|
guid,
|
|
2421
3432
|
},
|
|
2422
|
-
}
|
|
2423
|
-
)
|
|
3433
|
+
},
|
|
3434
|
+
),
|
|
2424
3435
|
);
|
|
2425
3436
|
promises.push(
|
|
2426
3437
|
this.queryRun(
|
|
2427
3438
|
`DELETE FROM ${MySQLDriver.escape(
|
|
2428
|
-
`${this.prefix}
|
|
3439
|
+
`${this.prefix}references_${etype}`,
|
|
2429
3440
|
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
2430
3441
|
{
|
|
2431
3442
|
etypes: [etype],
|
|
2432
3443
|
params: {
|
|
2433
3444
|
guid,
|
|
2434
3445
|
},
|
|
2435
|
-
}
|
|
2436
|
-
)
|
|
3446
|
+
},
|
|
3447
|
+
),
|
|
2437
3448
|
);
|
|
2438
3449
|
promises.push(
|
|
2439
3450
|
this.queryRun(
|
|
2440
3451
|
`DELETE FROM ${MySQLDriver.escape(
|
|
2441
|
-
`${this.prefix}
|
|
3452
|
+
`${this.prefix}tokens_${etype}`,
|
|
2442
3453
|
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
2443
3454
|
{
|
|
2444
3455
|
etypes: [etype],
|
|
2445
3456
|
params: {
|
|
2446
3457
|
guid,
|
|
2447
3458
|
},
|
|
2448
|
-
}
|
|
2449
|
-
)
|
|
3459
|
+
},
|
|
3460
|
+
),
|
|
3461
|
+
);
|
|
3462
|
+
promises.push(
|
|
3463
|
+
this.queryRun(
|
|
3464
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
3465
|
+
`${this.prefix}uniques_${etype}`,
|
|
3466
|
+
)} WHERE \`guid\`=UNHEX(@guid);`,
|
|
3467
|
+
{
|
|
3468
|
+
etypes: [etype],
|
|
3469
|
+
params: {
|
|
3470
|
+
guid,
|
|
3471
|
+
},
|
|
3472
|
+
},
|
|
3473
|
+
),
|
|
2450
3474
|
);
|
|
2451
3475
|
await Promise.all(promises);
|
|
2452
|
-
await insertData(guid, data, sdata, etype);
|
|
3476
|
+
await insertData(guid, data, sdata, uniques, etype);
|
|
2453
3477
|
success = true;
|
|
2454
3478
|
}
|
|
2455
3479
|
if (this.config.tableLocking) {
|
|
@@ -2459,20 +3483,27 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2459
3483
|
},
|
|
2460
3484
|
async () => {
|
|
2461
3485
|
await this.internalTransaction('nymph-save');
|
|
3486
|
+
inTransaction = true;
|
|
2462
3487
|
},
|
|
2463
3488
|
async (success) => {
|
|
2464
|
-
if (
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
3489
|
+
if (inTransaction) {
|
|
3490
|
+
inTransaction = false;
|
|
3491
|
+
if (success) {
|
|
3492
|
+
await this.commit('nymph-save');
|
|
3493
|
+
} else {
|
|
3494
|
+
await this.rollback('nymph-save');
|
|
3495
|
+
}
|
|
2468
3496
|
}
|
|
2469
3497
|
return success;
|
|
2470
|
-
}
|
|
3498
|
+
},
|
|
2471
3499
|
);
|
|
2472
3500
|
|
|
2473
3501
|
return result;
|
|
2474
3502
|
} catch (e: any) {
|
|
2475
|
-
|
|
3503
|
+
this.nymph.config.debugError('mysql', `Save entity error: "${e}"`);
|
|
3504
|
+
if (inTransaction) {
|
|
3505
|
+
await this.rollback('nymph-save');
|
|
3506
|
+
}
|
|
2476
3507
|
throw e;
|
|
2477
3508
|
}
|
|
2478
3509
|
}
|
|
@@ -2483,22 +3514,22 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2483
3514
|
}
|
|
2484
3515
|
await this.queryRun(
|
|
2485
3516
|
`INSERT INTO ${MySQLDriver.escape(
|
|
2486
|
-
`${this.prefix}uids
|
|
3517
|
+
`${this.prefix}uids`,
|
|
2487
3518
|
)} (\`name\`, \`cur_uid\`) VALUES (@name, @curUid) ON DUPLICATE KEY UPDATE \`cur_uid\`=@curUid;`,
|
|
2488
3519
|
{
|
|
2489
3520
|
params: {
|
|
2490
3521
|
name,
|
|
2491
3522
|
curUid,
|
|
2492
3523
|
},
|
|
2493
|
-
}
|
|
3524
|
+
},
|
|
2494
3525
|
);
|
|
2495
3526
|
return true;
|
|
2496
3527
|
}
|
|
2497
3528
|
|
|
2498
|
-
|
|
3529
|
+
protected async internalTransaction(name: string) {
|
|
2499
3530
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
2500
3531
|
throw new InvalidParametersError(
|
|
2501
|
-
'Transaction start attempted without a name.'
|
|
3532
|
+
'Transaction start attempted without a name.',
|
|
2502
3533
|
);
|
|
2503
3534
|
}
|
|
2504
3535
|
|
|
@@ -2524,7 +3555,7 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2524
3555
|
}
|
|
2525
3556
|
|
|
2526
3557
|
public async startTransaction(name: string) {
|
|
2527
|
-
const inTransaction = this.inTransaction();
|
|
3558
|
+
const inTransaction = await this.inTransaction();
|
|
2528
3559
|
const transaction = await this.internalTransaction(name);
|
|
2529
3560
|
if (!inTransaction) {
|
|
2530
3561
|
this.transaction = null;
|
|
@@ -2535,4 +3566,152 @@ export default class MySQLDriver extends NymphDriver {
|
|
|
2535
3566
|
|
|
2536
3567
|
return nymph;
|
|
2537
3568
|
}
|
|
3569
|
+
|
|
3570
|
+
private async removeTilmeldOldRows(etype: string) {
|
|
3571
|
+
await this.internalTransaction('nymph-remove-tilmeld-rows');
|
|
3572
|
+
try {
|
|
3573
|
+
for (let name of [
|
|
3574
|
+
'user',
|
|
3575
|
+
'group',
|
|
3576
|
+
'acUser',
|
|
3577
|
+
'acGroup',
|
|
3578
|
+
'acOther',
|
|
3579
|
+
'acRead',
|
|
3580
|
+
'acWrite',
|
|
3581
|
+
'acFull',
|
|
3582
|
+
]) {
|
|
3583
|
+
await this.queryRun(
|
|
3584
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
3585
|
+
`${this.prefix}data_${etype}`,
|
|
3586
|
+
)} WHERE \`name\`=@name;`,
|
|
3587
|
+
{
|
|
3588
|
+
etypes: [etype],
|
|
3589
|
+
params: {
|
|
3590
|
+
name,
|
|
3591
|
+
},
|
|
3592
|
+
},
|
|
3593
|
+
);
|
|
3594
|
+
await this.queryRun(
|
|
3595
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
3596
|
+
`${this.prefix}references_${etype}`,
|
|
3597
|
+
)} WHERE \`name\`=@name;`,
|
|
3598
|
+
{
|
|
3599
|
+
etypes: [etype],
|
|
3600
|
+
params: {
|
|
3601
|
+
name,
|
|
3602
|
+
},
|
|
3603
|
+
},
|
|
3604
|
+
);
|
|
3605
|
+
await this.queryRun(
|
|
3606
|
+
`DELETE FROM ${MySQLDriver.escape(
|
|
3607
|
+
`${this.prefix}tokens_${etype}`,
|
|
3608
|
+
)} WHERE \`name\`=@name;`,
|
|
3609
|
+
{
|
|
3610
|
+
etypes: [etype],
|
|
3611
|
+
params: {
|
|
3612
|
+
name,
|
|
3613
|
+
},
|
|
3614
|
+
},
|
|
3615
|
+
);
|
|
3616
|
+
}
|
|
3617
|
+
} catch (e: any) {
|
|
3618
|
+
this.nymph.config.debugError(
|
|
3619
|
+
'mysql',
|
|
3620
|
+
`Remove tilmeld rows error: "${e}"`,
|
|
3621
|
+
);
|
|
3622
|
+
await this.rollback('nymph-remove-tilmeld-rows');
|
|
3623
|
+
throw e;
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
await this.commit('nymph-remove-tilmeld-rows');
|
|
3627
|
+
return true;
|
|
3628
|
+
}
|
|
3629
|
+
|
|
3630
|
+
public async needsMigration(): Promise<
|
|
3631
|
+
'json' | 'tokens' | 'tilmeldColumns' | false
|
|
3632
|
+
> {
|
|
3633
|
+
const table = await this.queryGet(
|
|
3634
|
+
'SELECT `table_name` AS `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=@db AND `table_name` LIKE @prefix LIMIT 1;',
|
|
3635
|
+
{
|
|
3636
|
+
params: {
|
|
3637
|
+
db: this.config.database,
|
|
3638
|
+
prefix: this.prefix + 'data_' + '%',
|
|
3639
|
+
},
|
|
3640
|
+
},
|
|
3641
|
+
);
|
|
3642
|
+
if (table?.table_name) {
|
|
3643
|
+
const result = await this.queryGet(
|
|
3644
|
+
"SELECT 1 AS `exists` FROM `information_schema`.`columns` WHERE `table_schema`=@db AND `table_name`=@table AND `column_name`='json';",
|
|
3645
|
+
{
|
|
3646
|
+
params: {
|
|
3647
|
+
db: this.config.database,
|
|
3648
|
+
table: table.table_name,
|
|
3649
|
+
},
|
|
3650
|
+
},
|
|
3651
|
+
);
|
|
3652
|
+
if (!result?.exists) {
|
|
3653
|
+
return 'json';
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
const table2 = await this.queryGet(
|
|
3657
|
+
'SELECT `table_name` AS `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=@db AND `table_name` LIKE @tokenTable LIMIT 1;',
|
|
3658
|
+
{
|
|
3659
|
+
params: {
|
|
3660
|
+
db: this.config.database,
|
|
3661
|
+
tokenTable: this.prefix + 'tokens_' + '%',
|
|
3662
|
+
},
|
|
3663
|
+
},
|
|
3664
|
+
);
|
|
3665
|
+
if (!table2 || !table2.table_name) {
|
|
3666
|
+
return 'tokens';
|
|
3667
|
+
}
|
|
3668
|
+
const table3 = await this.queryGet(
|
|
3669
|
+
'SELECT `table_name` AS `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=@db AND `table_name` LIKE @prefix LIMIT 1;',
|
|
3670
|
+
{
|
|
3671
|
+
params: {
|
|
3672
|
+
db: this.config.database,
|
|
3673
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
3674
|
+
},
|
|
3675
|
+
},
|
|
3676
|
+
);
|
|
3677
|
+
if (table3?.table_name) {
|
|
3678
|
+
const result = await this.queryGet(
|
|
3679
|
+
"SELECT 1 AS `exists` FROM `information_schema`.`columns` WHERE `table_schema`=@db AND `table_name`=@table AND `column_name`='user';",
|
|
3680
|
+
{
|
|
3681
|
+
params: {
|
|
3682
|
+
db: this.config.database,
|
|
3683
|
+
table: table3.table_name,
|
|
3684
|
+
},
|
|
3685
|
+
},
|
|
3686
|
+
);
|
|
3687
|
+
if (!result?.exists) {
|
|
3688
|
+
return 'tilmeldColumns';
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
return false;
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
public async liveMigration(
|
|
3695
|
+
migrationType: 'tokenTables' | 'tilmeldColumns' | 'tilmeldRemoveOldRows',
|
|
3696
|
+
) {
|
|
3697
|
+
if (migrationType === 'tokenTables') {
|
|
3698
|
+
const etypes = await this.getEtypes();
|
|
3699
|
+
|
|
3700
|
+
for (let etype of etypes) {
|
|
3701
|
+
await this.createTokensTable(etype);
|
|
3702
|
+
}
|
|
3703
|
+
} else if (migrationType === 'tilmeldColumns') {
|
|
3704
|
+
const etypes = await this.getEtypes();
|
|
3705
|
+
|
|
3706
|
+
for (let etype of etypes) {
|
|
3707
|
+
await this.addTilmeldColumnsAndIndexes(etype);
|
|
3708
|
+
}
|
|
3709
|
+
} else if (migrationType === 'tilmeldRemoveOldRows') {
|
|
3710
|
+
const etypes = await this.getEtypes();
|
|
3711
|
+
|
|
3712
|
+
for (let etype of etypes) {
|
|
3713
|
+
await this.removeTilmeldOldRows(etype);
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
2538
3717
|
}
|