@nymphjs/driver-mysql 1.0.0-beta.13 → 1.0.0-beta.131
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 +612 -0
- package/README.md +5 -3
- package/dist/MySQLDriver.d.ts +109 -24
- package/dist/MySQLDriver.js +1655 -768
- 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 +36 -25
- package/src/MySQLDriver.test.ts +16 -5
- package/src/MySQLDriver.ts +2323 -1082
- 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/dist/MySQLDriver.js
CHANGED
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import mysql from 'mysql2';
|
|
2
|
+
import SqlString from 'sqlstring';
|
|
3
|
+
import { NymphDriver, EntityConflictError, EntityInvalidDataError, EntityUniqueConstraintError, InvalidParametersError, NotConfiguredError, QueryFailedError, UnableToConnectError, xor, } from '@nymphjs/nymph';
|
|
4
|
+
import { makeTableSuffix } from '@nymphjs/guid';
|
|
5
|
+
import { MySQLDriverConfigDefaults as defaults, } from './conf/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* The MySQL Nymph database driver.
|
|
8
|
+
*/
|
|
9
|
+
export default class MySQLDriver extends NymphDriver {
|
|
10
|
+
config;
|
|
11
|
+
mysqlConfig;
|
|
12
|
+
prefix;
|
|
13
|
+
connected = false;
|
|
14
|
+
// @ts-ignore: this is assigned in connect(), which is called by the constructor.
|
|
15
|
+
link;
|
|
16
|
+
transaction = null;
|
|
13
17
|
static escape(input) {
|
|
14
|
-
return
|
|
18
|
+
return SqlString.escapeId(input, true);
|
|
15
19
|
}
|
|
16
20
|
static escapeValue(input) {
|
|
17
21
|
return mysql.escape(input);
|
|
18
22
|
}
|
|
19
23
|
constructor(config, link, transaction) {
|
|
20
24
|
super();
|
|
21
|
-
this.
|
|
22
|
-
this.transaction = null;
|
|
23
|
-
this.config = { ...conf_1.MySQLDriverConfigDefaults, ...config };
|
|
25
|
+
this.config = { ...defaults, ...config };
|
|
24
26
|
const { host, user, password, database, port, customPoolConfig } = this.config;
|
|
25
27
|
this.mysqlConfig = customPoolConfig ?? {
|
|
26
28
|
host,
|
|
@@ -41,6 +43,11 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
41
43
|
this.connect();
|
|
42
44
|
}
|
|
43
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* This is used internally by Nymph. Don't call it yourself.
|
|
48
|
+
*
|
|
49
|
+
* @returns A clone of this instance.
|
|
50
|
+
*/
|
|
44
51
|
clone() {
|
|
45
52
|
return new MySQLDriver(this.config, this.link, this.transaction ?? undefined);
|
|
46
53
|
}
|
|
@@ -50,22 +57,29 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
50
57
|
}
|
|
51
58
|
return new Promise((resolve, reject) => this.link.getConnection((err, con) => (err ? reject(err) : resolve(con))));
|
|
52
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Connect to the MySQL database.
|
|
62
|
+
*
|
|
63
|
+
* @returns Whether this instance is connected to a MySQL database.
|
|
64
|
+
*/
|
|
53
65
|
async connect() {
|
|
66
|
+
// If we think we're connected, try pinging the server.
|
|
54
67
|
try {
|
|
55
68
|
if (this.connected) {
|
|
56
69
|
const connection = await new Promise((resolve, reject) => this.link.getConnection((err, con) => err ? reject(err) : resolve(con)));
|
|
57
|
-
await new Promise((resolve) => connection.ping(() => {
|
|
58
|
-
resolve(0);
|
|
59
|
-
}));
|
|
60
70
|
connection.release();
|
|
61
71
|
}
|
|
62
72
|
}
|
|
63
73
|
catch (e) {
|
|
64
74
|
this.connected = false;
|
|
65
75
|
}
|
|
76
|
+
// Connecting, selecting database
|
|
66
77
|
if (!this.connected) {
|
|
67
78
|
try {
|
|
68
|
-
this.link = mysql.createPool(
|
|
79
|
+
this.link = mysql.createPool({
|
|
80
|
+
...this.mysqlConfig,
|
|
81
|
+
charset: 'utf8mb4_bin',
|
|
82
|
+
});
|
|
69
83
|
this.connected = true;
|
|
70
84
|
}
|
|
71
85
|
catch (e) {
|
|
@@ -73,15 +87,20 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
73
87
|
this.mysqlConfig.user === 'nymph' &&
|
|
74
88
|
this.mysqlConfig.password === 'password' &&
|
|
75
89
|
this.mysqlConfig.database === 'nymph') {
|
|
76
|
-
throw new
|
|
90
|
+
throw new NotConfiguredError("It seems the config hasn't been set up correctly.");
|
|
77
91
|
}
|
|
78
92
|
else {
|
|
79
|
-
throw new
|
|
93
|
+
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
80
94
|
}
|
|
81
95
|
}
|
|
82
96
|
}
|
|
83
97
|
return this.connected;
|
|
84
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Disconnect from the MySQL database.
|
|
101
|
+
*
|
|
102
|
+
* @returns Whether this instance is connected to a MySQL database.
|
|
103
|
+
*/
|
|
85
104
|
async disconnect() {
|
|
86
105
|
if (this.connected) {
|
|
87
106
|
await new Promise((resolve) => this.link.end(() => resolve(0)));
|
|
@@ -90,68 +109,173 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
90
109
|
return this.connected;
|
|
91
110
|
}
|
|
92
111
|
async inTransaction() {
|
|
112
|
+
if (this.transaction && this.transaction.count === 0) {
|
|
113
|
+
this.transaction = null;
|
|
114
|
+
}
|
|
93
115
|
return !!this.transaction;
|
|
94
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Check connection status.
|
|
119
|
+
*
|
|
120
|
+
* @returns Whether this instance is connected to a MySQL database.
|
|
121
|
+
*/
|
|
95
122
|
isConnected() {
|
|
96
123
|
return this.connected;
|
|
97
124
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
let foreignKeyDataComparisonsTableGuid = '';
|
|
102
|
-
let foreignKeyReferencesTableGuid = '';
|
|
103
|
-
if (this.config.foreignKeys) {
|
|
104
|
-
foreignKeyDataTableGuid = ` REFERENCES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)}(\`guid\`) ON DELETE CASCADE`;
|
|
105
|
-
foreignKeyDataComparisonsTableGuid = ` REFERENCES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)}(\`guid\`) ON DELETE CASCADE`;
|
|
106
|
-
foreignKeyReferencesTableGuid = ` REFERENCES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)}(\`guid\`) ON DELETE CASCADE`;
|
|
107
|
-
}
|
|
108
|
-
if (etype != null) {
|
|
109
|
-
this.queryRunSync(`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (
|
|
125
|
+
async createEntitiesTable(etype) {
|
|
126
|
+
// Create the entity table.
|
|
127
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (
|
|
110
128
|
\`guid\` BINARY(12) NOT NULL,
|
|
111
129
|
\`tags\` LONGTEXT,
|
|
112
130
|
\`cdate\` DOUBLE PRECISION NOT NULL,
|
|
113
131
|
\`mdate\` DOUBLE PRECISION NOT NULL,
|
|
132
|
+
\`user\` BINARY(12),
|
|
133
|
+
\`group\` BINARY(12),
|
|
134
|
+
\`acUser\` TINYINT UNSIGNED,
|
|
135
|
+
\`acGroup\` TINYINT UNSIGNED,
|
|
136
|
+
\`acOther\` TINYINT UNSIGNED,
|
|
137
|
+
\`acRead\` LONGTEXT,
|
|
138
|
+
\`acWrite\` LONGTEXT,
|
|
139
|
+
\`acFull\` LONGTEXT,
|
|
114
140
|
PRIMARY KEY (\`guid\`),
|
|
141
|
+
INDEX \`id_guid\` USING HASH (\`guid\`),
|
|
115
142
|
INDEX \`id_cdate\` USING BTREE (\`cdate\`),
|
|
116
143
|
INDEX \`id_mdate\` USING BTREE (\`mdate\`),
|
|
117
|
-
FULLTEXT \`id_tags\` (\`tags\`)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
\`
|
|
122
|
-
\`
|
|
123
|
-
\`
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
INDEX \`id_name_value\` USING BTREE (\`name\`(255), \`value\`(512))
|
|
144
|
+
FULLTEXT \`id_tags\` (\`tags\`),
|
|
145
|
+
INDEX \`id_user_acUser\` USING BTREE (\`user\`, \`acUser\`),
|
|
146
|
+
INDEX \`id_group_acGroup\` USING BTREE (\`group\`, \`acGroup\`),
|
|
147
|
+
INDEX \`id_acUser\` USING BTREE (\`acUser\`),
|
|
148
|
+
INDEX \`id_acGroup\` USING BTREE (\`acGroup\`),
|
|
149
|
+
INDEX \`id_acOther\` USING BTREE (\`acOther\`),
|
|
150
|
+
FULLTEXT \`id_acRead\` (\`acRead\`),
|
|
151
|
+
FULLTEXT \`id_acWrite\` (\`acWrite\`),
|
|
152
|
+
FULLTEXT \`id_acFull\` (\`acFull\`)
|
|
127
153
|
) ENGINE ${this.config.engine}
|
|
128
|
-
CHARACTER SET
|
|
129
|
-
|
|
130
|
-
|
|
154
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`);
|
|
155
|
+
}
|
|
156
|
+
async addTilmeldColumnsAndIndexes(etype) {
|
|
157
|
+
await this.queryRun(`ALTER TABLE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN \`user\` BINARY(12);`);
|
|
158
|
+
await this.queryRun(`ALTER TABLE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN \`group\` BINARY(12);`);
|
|
159
|
+
await this.queryRun(`ALTER TABLE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN \`acUser\` TINYINT UNSIGNED;`);
|
|
160
|
+
await this.queryRun(`ALTER TABLE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN \`acGroup\` TINYINT UNSIGNED;`);
|
|
161
|
+
await this.queryRun(`ALTER TABLE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN \`acOther\` TINYINT UNSIGNED;`);
|
|
162
|
+
await this.queryRun(`ALTER TABLE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN \`acRead\` LONGTEXT;`);
|
|
163
|
+
await this.queryRun(`ALTER TABLE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN \`acWrite\` LONGTEXT;`);
|
|
164
|
+
await this.queryRun(`ALTER TABLE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ADD COLUMN \`acFull\` LONGTEXT;`);
|
|
165
|
+
await this.createEntitiesTilmeldIndexes(etype);
|
|
166
|
+
}
|
|
167
|
+
async createEntitiesTilmeldIndexes(etype) {
|
|
168
|
+
await this.queryRun(`CREATE INDEX \`id_user_acUser\` ON ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`user\`, \`acUser\`) USING BTREE;`);
|
|
169
|
+
await this.queryRun(`CREATE INDEX \`id_group_acGroup\` ON ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`group\`, \`acGroup\`) USING BTREE;`);
|
|
170
|
+
await this.queryRun(`CREATE INDEX \`id_acUser\` ON ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`acUser\`) USING BTREE;`);
|
|
171
|
+
await this.queryRun(`CREATE INDEX \`id_acGroup\` ON ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`acGroup\`) USING BTREE;`);
|
|
172
|
+
await this.queryRun(`CREATE INDEX \`id_acOther\` ON ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`acOther\`) USING BTREE;`);
|
|
173
|
+
await this.queryRun(`CREATE FULLTEXT INDEX \`id_acRead\` ON ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`acRead\`);`);
|
|
174
|
+
await this.queryRun(`CREATE FULLTEXT INDEX \`id_acWrite\` ON ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`acWrite\`);`);
|
|
175
|
+
await this.queryRun(`CREATE FULLTEXT INDEX \`id_acFull\` ON ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`acFull\`);`);
|
|
176
|
+
}
|
|
177
|
+
async createDataTable(etype) {
|
|
178
|
+
let foreignKey = '';
|
|
179
|
+
if (this.config.foreignKeys) {
|
|
180
|
+
foreignKey = ` REFERENCES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)}(\`guid\`) ON DELETE CASCADE`;
|
|
181
|
+
}
|
|
182
|
+
// Create the data table.
|
|
183
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (
|
|
184
|
+
\`guid\` BINARY(12) NOT NULL${foreignKey},
|
|
131
185
|
\`name\` TEXT NOT NULL,
|
|
132
|
-
\`
|
|
186
|
+
\`value\` CHAR(1) NOT NULL,
|
|
187
|
+
\`json\` JSON,
|
|
133
188
|
\`string\` LONGTEXT,
|
|
134
189
|
\`number\` DOUBLE,
|
|
190
|
+
\`truthy\` BOOLEAN,
|
|
135
191
|
PRIMARY KEY (\`guid\`, \`name\`(255)),
|
|
136
|
-
INDEX \`
|
|
192
|
+
INDEX \`id_name_guid\` USING BTREE (\`name\`(255), \`guid\`),
|
|
193
|
+
INDEX \`id_name_string_guid\` USING BTREE (\`name\`(255), \`string\`(500), \`guid\`),
|
|
194
|
+
INDEX \`id_name_number_guid\` USING BTREE (\`name\`(255), \`number\`, \`guid\`),
|
|
195
|
+
INDEX \`id_name_truthy_guid\` USING BTREE (\`name\`(255), \`truthy\`, \`guid\`),
|
|
196
|
+
INDEX \`id_name_json_guid\` USING BTREE (\`name\`(255), (CAST(\`json\` AS CHAR(500)) COLLATE utf8mb4_bin), \`guid\`)
|
|
137
197
|
) ENGINE ${this.config.engine}
|
|
138
|
-
CHARACTER SET
|
|
139
|
-
|
|
140
|
-
|
|
198
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`);
|
|
199
|
+
}
|
|
200
|
+
async createReferencesTable(etype) {
|
|
201
|
+
let foreignKey = '';
|
|
202
|
+
if (this.config.foreignKeys) {
|
|
203
|
+
foreignKey = ` REFERENCES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)}(\`guid\`) ON DELETE CASCADE`;
|
|
204
|
+
}
|
|
205
|
+
// Create the references table.
|
|
206
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(`${this.prefix}references_${etype}`)} (
|
|
207
|
+
\`guid\` BINARY(12) NOT NULL${foreignKey},
|
|
141
208
|
\`name\` TEXT NOT NULL,
|
|
142
209
|
\`reference\` BINARY(12) NOT NULL,
|
|
143
210
|
PRIMARY KEY (\`guid\`, \`name\`(255), \`reference\`),
|
|
144
|
-
INDEX \`
|
|
211
|
+
INDEX \`id_name_reference_guid\` USING HASH (\`name\`(255), \`reference\`, \`guid\`)
|
|
212
|
+
) ENGINE ${this.config.engine}
|
|
213
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`);
|
|
214
|
+
}
|
|
215
|
+
async createTokensTable(etype) {
|
|
216
|
+
let foreignKey = '';
|
|
217
|
+
if (this.config.foreignKeys) {
|
|
218
|
+
foreignKey = ` REFERENCES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)}(\`guid\`) ON DELETE CASCADE`;
|
|
219
|
+
}
|
|
220
|
+
// Create the tokens table.
|
|
221
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} (
|
|
222
|
+
\`guid\` BINARY(12) NOT NULL${foreignKey},
|
|
223
|
+
\`name\` TEXT NOT NULL,
|
|
224
|
+
\`token\` INT NOT NULL,
|
|
225
|
+
\`position\` INT UNSIGNED NOT NULL,
|
|
226
|
+
\`stem\` BOOLEAN NOT NULL,
|
|
227
|
+
PRIMARY KEY (\`guid\`, \`name\`(255), \`token\`, \`position\`),
|
|
228
|
+
INDEX \`id_name_token_guid\` USING btree (\`name\`(255), \`token\`, \`guid\`)
|
|
229
|
+
) ENGINE ${this.config.engine}
|
|
230
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`);
|
|
231
|
+
}
|
|
232
|
+
async createUniquesTable(etype) {
|
|
233
|
+
let foreignKey = '';
|
|
234
|
+
if (this.config.foreignKeys) {
|
|
235
|
+
foreignKey = ` REFERENCES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)}(\`guid\`) ON DELETE CASCADE`;
|
|
236
|
+
}
|
|
237
|
+
// Create the unique strings table.
|
|
238
|
+
// 255 key is max length for charset UTF8.
|
|
239
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(`${this.prefix}uniques_${etype}`)} (
|
|
240
|
+
\`guid\` BINARY(12) NOT NULL${foreignKey},
|
|
241
|
+
\`unique\` TEXT NOT NULL,
|
|
242
|
+
PRIMARY KEY (\`guid\`, \`unique\`(255)),
|
|
243
|
+
INDEX \`id_guid\` USING HASH (\`guid\`),
|
|
244
|
+
CONSTRAINT \`uc_unique\` UNIQUE (\`unique\`(255))
|
|
145
245
|
) ENGINE ${this.config.engine}
|
|
146
|
-
CHARACTER SET
|
|
246
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Create entity tables in the database.
|
|
250
|
+
*
|
|
251
|
+
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
252
|
+
* @returns True on success, false on failure.
|
|
253
|
+
*/
|
|
254
|
+
async createTables(etype = null) {
|
|
255
|
+
await this.queryRun('SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";');
|
|
256
|
+
if (etype != null) {
|
|
257
|
+
await this.createEntitiesTable(etype);
|
|
258
|
+
await this.createDataTable(etype);
|
|
259
|
+
await this.createReferencesTable(etype);
|
|
260
|
+
await this.createTokensTable(etype);
|
|
261
|
+
await this.createUniquesTable(etype);
|
|
147
262
|
}
|
|
148
263
|
else {
|
|
149
|
-
|
|
264
|
+
// Create the UID table.
|
|
265
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${MySQLDriver.escape(`${this.prefix}uids`)} (
|
|
150
266
|
\`name\` TEXT NOT NULL,
|
|
151
267
|
\`cur_uid\` BIGINT(20) UNSIGNED NOT NULL,
|
|
152
268
|
PRIMARY KEY (\`name\`(100))
|
|
153
269
|
) ENGINE ${this.config.engine}
|
|
154
|
-
CHARACTER SET
|
|
270
|
+
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;`);
|
|
271
|
+
}
|
|
272
|
+
if (this.transaction &&
|
|
273
|
+
this.transaction.count > 0 &&
|
|
274
|
+
this.config.transactions) {
|
|
275
|
+
this.transaction.count = 0;
|
|
276
|
+
this.transaction.connection?.release();
|
|
277
|
+
this.transaction.connection = null;
|
|
278
|
+
this.transaction = null;
|
|
155
279
|
}
|
|
156
280
|
return true;
|
|
157
281
|
}
|
|
@@ -169,190 +293,128 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
169
293
|
}
|
|
170
294
|
async query(runQuery, query, etypes = []) {
|
|
171
295
|
try {
|
|
296
|
+
this.nymph.config.debugInfo('mysql:query', query);
|
|
172
297
|
return await runQuery();
|
|
173
298
|
}
|
|
174
299
|
catch (e) {
|
|
175
300
|
const errorCode = e?.errno;
|
|
176
|
-
if (errorCode === 1146 && this.createTables()) {
|
|
301
|
+
if (errorCode === 1146 && (await this.createTables())) {
|
|
302
|
+
// If the tables don't exist yet, create them.
|
|
177
303
|
for (let etype of etypes) {
|
|
178
|
-
this.createTables(etype);
|
|
304
|
+
await this.createTables(etype);
|
|
179
305
|
}
|
|
180
306
|
try {
|
|
181
307
|
return await runQuery();
|
|
182
308
|
}
|
|
183
309
|
catch (e2) {
|
|
184
|
-
throw new
|
|
310
|
+
throw new QueryFailedError('Query failed: ' + e2?.errno + ' - ' + e2?.message, query, e2?.errno);
|
|
185
311
|
}
|
|
186
312
|
}
|
|
187
|
-
else if (errorCode ===
|
|
188
|
-
|
|
189
|
-
throw new nymph_1.QueryFailedError('Query failed: ' + e?.errno + ' - ' + e?.message, query);
|
|
190
|
-
}
|
|
191
|
-
try {
|
|
192
|
-
return await runQuery();
|
|
193
|
-
}
|
|
194
|
-
catch (e2) {
|
|
195
|
-
throw new nymph_1.QueryFailedError('Query failed: ' + e2?.errno + ' - ' + e2?.message, query);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
throw e;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
querySync(runQuery, query, etypes = []) {
|
|
204
|
-
try {
|
|
205
|
-
return runQuery();
|
|
206
|
-
}
|
|
207
|
-
catch (e) {
|
|
208
|
-
const errorCode = e?.errno;
|
|
209
|
-
if (errorCode === 1146 && this.createTables()) {
|
|
210
|
-
for (let etype of etypes) {
|
|
211
|
-
this.createTables(etype);
|
|
212
|
-
}
|
|
213
|
-
try {
|
|
214
|
-
return runQuery();
|
|
215
|
-
}
|
|
216
|
-
catch (e2) {
|
|
217
|
-
throw new nymph_1.QueryFailedError('Query failed: ' + e2?.errno + ' - ' + e2?.message, query);
|
|
218
|
-
}
|
|
313
|
+
else if (errorCode === 1062) {
|
|
314
|
+
throw new EntityUniqueConstraintError(`Unique constraint violation.`);
|
|
219
315
|
}
|
|
220
316
|
else if (errorCode === 2006) {
|
|
221
|
-
|
|
222
|
-
|
|
317
|
+
// If the MySQL server disconnected, reconnect to it.
|
|
318
|
+
if (!(await this.connect())) {
|
|
319
|
+
throw new QueryFailedError('Query failed: ' + e?.errno + ' - ' + e?.message, query, e?.errno);
|
|
223
320
|
}
|
|
224
321
|
try {
|
|
225
|
-
return runQuery();
|
|
322
|
+
return await runQuery();
|
|
226
323
|
}
|
|
227
324
|
catch (e2) {
|
|
228
|
-
throw new
|
|
325
|
+
throw new QueryFailedError('Query failed: ' + e2?.errno + ' - ' + e2?.message, query, e2?.errno);
|
|
229
326
|
}
|
|
230
327
|
}
|
|
231
328
|
else {
|
|
232
|
-
throw e;
|
|
329
|
+
throw new QueryFailedError('Query failed: ' + e?.errno + ' - ' + e?.message, query, e?.errno);
|
|
233
330
|
}
|
|
234
331
|
}
|
|
235
332
|
}
|
|
236
|
-
|
|
333
|
+
queryArray(query, { etypes = [], params = {}, } = {}) {
|
|
237
334
|
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
238
335
|
return this.query(async () => {
|
|
239
|
-
const results = await new Promise((resolve, reject) => {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
reject(e);
|
|
336
|
+
const results = await new Promise(async (resolve, reject) => {
|
|
337
|
+
// Only do one query at a time in transations.
|
|
338
|
+
let myResolve = () => { };
|
|
339
|
+
const myPromise = new Promise((resolve) => {
|
|
340
|
+
myResolve = resolve;
|
|
341
|
+
});
|
|
342
|
+
if (this.transaction) {
|
|
343
|
+
const latestPromise = this.transaction.latestPromise;
|
|
344
|
+
this.transaction.latestPromise = myPromise;
|
|
345
|
+
await latestPromise;
|
|
250
346
|
}
|
|
347
|
+
(this.transaction?.connection ?? this.link).query(newQuery, newParams, (error, results) => {
|
|
348
|
+
if (error) {
|
|
349
|
+
reject(error);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
resolve(results);
|
|
353
|
+
}
|
|
354
|
+
myResolve();
|
|
355
|
+
});
|
|
251
356
|
});
|
|
252
357
|
return results;
|
|
253
358
|
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
254
359
|
}
|
|
255
|
-
queryIterSync(query, { etypes = [], params = {}, } = {}) {
|
|
256
|
-
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
257
|
-
return this.querySync(() => {
|
|
258
|
-
const output = child_process_1.default.spawnSync(process.argv0, [__dirname + '/runMysqlSync.js'], {
|
|
259
|
-
input: JSON.stringify({
|
|
260
|
-
mysqlConfig: this.mysqlConfig,
|
|
261
|
-
query: newQuery,
|
|
262
|
-
params: newParams,
|
|
263
|
-
}),
|
|
264
|
-
timeout: 30000,
|
|
265
|
-
maxBuffer: 100 * 1024 * 1024,
|
|
266
|
-
encoding: 'utf8',
|
|
267
|
-
windowsHide: true,
|
|
268
|
-
});
|
|
269
|
-
try {
|
|
270
|
-
const { results } = JSON.parse(output.stdout);
|
|
271
|
-
return results;
|
|
272
|
-
}
|
|
273
|
-
catch (e) {
|
|
274
|
-
}
|
|
275
|
-
if (output.status === 0) {
|
|
276
|
-
throw new Error('Unknown parse error.');
|
|
277
|
-
}
|
|
278
|
-
const err = JSON.parse(output.stderr);
|
|
279
|
-
const e = new Error(err.name);
|
|
280
|
-
for (const name in err) {
|
|
281
|
-
e[name] = err[name];
|
|
282
|
-
}
|
|
283
|
-
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
284
|
-
}
|
|
285
360
|
queryGet(query, { etypes = [], params = {}, } = {}) {
|
|
286
361
|
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
287
362
|
return this.query(async () => {
|
|
288
|
-
const results = await new Promise((resolve, reject) => {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
reject(e);
|
|
363
|
+
const results = await new Promise(async (resolve, reject) => {
|
|
364
|
+
// Only do one query at a time in transations.
|
|
365
|
+
let myResolve = () => { };
|
|
366
|
+
const myPromise = new Promise((resolve) => {
|
|
367
|
+
myResolve = resolve;
|
|
368
|
+
});
|
|
369
|
+
if (this.transaction) {
|
|
370
|
+
const latestPromise = this.transaction.latestPromise;
|
|
371
|
+
this.transaction.latestPromise = myPromise;
|
|
372
|
+
await latestPromise;
|
|
299
373
|
}
|
|
374
|
+
(this.transaction?.connection ?? this.link).query(newQuery, newParams, (error, results) => {
|
|
375
|
+
if (error) {
|
|
376
|
+
reject(error);
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
resolve(results);
|
|
380
|
+
}
|
|
381
|
+
myResolve();
|
|
382
|
+
});
|
|
300
383
|
});
|
|
301
384
|
return results[0];
|
|
302
385
|
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
303
386
|
}
|
|
304
|
-
queryRun(query, { etypes = [], params = {}, } = {}) {
|
|
387
|
+
queryRun(query, { etypes = [], params = {}, transaction, } = {}) {
|
|
305
388
|
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
306
389
|
return this.query(async () => {
|
|
307
|
-
const results = await new Promise((resolve, reject) => {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
390
|
+
const results = await new Promise(async (resolve, reject) => {
|
|
391
|
+
// Only do one query at a time in transations.
|
|
392
|
+
let myResolve = () => { };
|
|
393
|
+
const myPromise = new Promise((resolve) => {
|
|
394
|
+
myResolve = resolve;
|
|
395
|
+
});
|
|
396
|
+
const trans = transaction ?? this.transaction;
|
|
397
|
+
if (trans) {
|
|
398
|
+
const latestPromise = trans.latestPromise;
|
|
399
|
+
trans.latestPromise = myPromise;
|
|
400
|
+
await latestPromise;
|
|
318
401
|
}
|
|
402
|
+
(trans?.connection ?? this.link).query(newQuery, newParams, (error, results) => {
|
|
403
|
+
if (error) {
|
|
404
|
+
reject(error);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
resolve(results);
|
|
408
|
+
}
|
|
409
|
+
myResolve();
|
|
410
|
+
});
|
|
319
411
|
});
|
|
320
412
|
return { changes: results.changedRows ?? 0 };
|
|
321
413
|
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
322
414
|
}
|
|
323
|
-
queryRunSync(query, { etypes = [], params = {}, } = {}) {
|
|
324
|
-
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
325
|
-
return this.querySync(() => {
|
|
326
|
-
const output = child_process_1.default.spawnSync(process.argv0, [__dirname + '/runMysqlSync.js'], {
|
|
327
|
-
input: JSON.stringify({
|
|
328
|
-
mysqlConfig: this.mysqlConfig,
|
|
329
|
-
query: newQuery,
|
|
330
|
-
params: newParams,
|
|
331
|
-
}),
|
|
332
|
-
timeout: 30000,
|
|
333
|
-
maxBuffer: 100 * 1024 * 1024,
|
|
334
|
-
encoding: 'utf8',
|
|
335
|
-
windowsHide: true,
|
|
336
|
-
});
|
|
337
|
-
try {
|
|
338
|
-
const { results } = JSON.parse(output.stdout);
|
|
339
|
-
return { changes: results.changedRows ?? 0 };
|
|
340
|
-
}
|
|
341
|
-
catch (e) {
|
|
342
|
-
}
|
|
343
|
-
if (output.status === 0) {
|
|
344
|
-
throw new Error('Unknown parse error.');
|
|
345
|
-
}
|
|
346
|
-
const err = JSON.parse(output.stderr);
|
|
347
|
-
const e = new Error(err.name);
|
|
348
|
-
for (const name in err) {
|
|
349
|
-
e[name] = err[name];
|
|
350
|
-
}
|
|
351
|
-
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
352
|
-
}
|
|
353
415
|
async commit(name) {
|
|
354
416
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
355
|
-
throw new
|
|
417
|
+
throw new InvalidParametersError('Transaction commit attempted without a name.');
|
|
356
418
|
}
|
|
357
419
|
if (!this.transaction || this.transaction.count === 0) {
|
|
358
420
|
this.transaction = null;
|
|
@@ -394,32 +456,40 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
394
456
|
guid,
|
|
395
457
|
},
|
|
396
458
|
});
|
|
397
|
-
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}
|
|
459
|
+
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
398
460
|
etypes: [etype],
|
|
399
461
|
params: {
|
|
400
462
|
guid,
|
|
401
463
|
},
|
|
402
464
|
});
|
|
403
|
-
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}
|
|
465
|
+
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
466
|
+
etypes: [etype],
|
|
467
|
+
params: {
|
|
468
|
+
guid,
|
|
469
|
+
},
|
|
470
|
+
});
|
|
471
|
+
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}uniques_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
404
472
|
etypes: [etype],
|
|
405
473
|
params: {
|
|
406
474
|
guid,
|
|
407
475
|
},
|
|
408
476
|
});
|
|
409
|
-
await this.commit('nymph-delete');
|
|
410
|
-
if (this.nymph.config.cache) {
|
|
411
|
-
this.cleanCache(guid);
|
|
412
|
-
}
|
|
413
|
-
return true;
|
|
414
477
|
}
|
|
415
478
|
catch (e) {
|
|
479
|
+
this.nymph.config.debugError('mysql', `Delete entity error: "${e}"`);
|
|
416
480
|
await this.rollback('nymph-delete');
|
|
417
481
|
throw e;
|
|
418
482
|
}
|
|
483
|
+
await this.commit('nymph-delete');
|
|
484
|
+
// Remove any cached versions of this entity.
|
|
485
|
+
if (this.nymph.config.cache) {
|
|
486
|
+
this.cleanCache(guid);
|
|
487
|
+
}
|
|
488
|
+
return true;
|
|
419
489
|
}
|
|
420
490
|
async deleteUID(name) {
|
|
421
491
|
if (!name) {
|
|
422
|
-
throw new
|
|
492
|
+
throw new InvalidParametersError('Name not given for UID');
|
|
423
493
|
}
|
|
424
494
|
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}uids`)} WHERE \`name\`=@name;`, {
|
|
425
495
|
params: {
|
|
@@ -428,79 +498,243 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
428
498
|
});
|
|
429
499
|
return true;
|
|
430
500
|
}
|
|
431
|
-
async
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
501
|
+
async getIndexes(etype) {
|
|
502
|
+
const indexes = [];
|
|
503
|
+
for (let [scope, suffix] of [
|
|
504
|
+
['data', '_string_guid'],
|
|
505
|
+
['references', '_reference_guid'],
|
|
506
|
+
['tokens', '_token_guid'],
|
|
507
|
+
]) {
|
|
508
|
+
const indexDefinitions = await this.queryArray(`SHOW INDEXES FROM ${MySQLDriver.escape(`${this.prefix}${scope}_${etype}`)} WHERE \`Key_name\` LIKE @pattern AND \`Seq_in_index\`=1;`, {
|
|
509
|
+
params: {
|
|
510
|
+
pattern: `${this.prefix}${scope}_${etype}_id_custom_%${suffix}`,
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
for (const indexDefinition of indexDefinitions) {
|
|
514
|
+
indexes.push({
|
|
515
|
+
scope,
|
|
516
|
+
name: indexDefinition.Key_name.substring(`${this.prefix}${scope}_${etype}_id_custom_`.length, indexDefinition.Key_name.length - suffix.length),
|
|
517
|
+
property: (indexDefinition.Expression.match(/\s*\(?\s*`?name`?\s*=\s*(?:\w*)\\*'(.*?)\\*'/) ?? [])[1] ?? '',
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return indexes;
|
|
522
|
+
}
|
|
523
|
+
async addIndex(etype, definition) {
|
|
524
|
+
this.checkIndexName(definition.name);
|
|
525
|
+
await this.deleteIndex(etype, definition.scope, definition.name);
|
|
526
|
+
if (definition.scope === 'data') {
|
|
527
|
+
await this.queryRun(`CREATE INDEX ${MySQLDriver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_string_guid`)} USING btree ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`string\`(500), \`guid\`);`);
|
|
528
|
+
await this.queryRun(`CREATE INDEX ${MySQLDriver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_number_guid`)} USING btree ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`number\`, \`guid\`);`);
|
|
529
|
+
await this.queryRun(`CREATE INDEX ${MySQLDriver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_truthy_guid`)} USING btree ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`truthy\`, \`guid\`);`);
|
|
530
|
+
await this.queryRun(`CREATE INDEX ${MySQLDriver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_json_guid`)} USING btree ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), (CAST(\`json\` AS CHAR(500)) COLLATE utf8mb4_bin), \`guid\`);`);
|
|
531
|
+
}
|
|
532
|
+
else if (definition.scope === 'references') {
|
|
533
|
+
await this.queryRun(`CREATE INDEX ${MySQLDriver.escape(`${this.prefix}references_${etype}_id_custom_${definition.name}_reference_guid`)} USING btree ON ${MySQLDriver.escape(`${this.prefix}references_${etype}`)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`reference\`, \`guid\`);`);
|
|
534
|
+
}
|
|
535
|
+
else if (definition.scope === 'tokens') {
|
|
536
|
+
await this.queryRun(`CREATE INDEX ${MySQLDriver.escape(`${this.prefix}tokens_${etype}_id_custom_${definition.name}_token_guid`)} USING btree ON ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} (((\`name\` = ${MySQLDriver.escapeValue(definition.property)})), \`token\`, \`guid\`);`);
|
|
537
|
+
}
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
async deleteIndex(etype, scope, name) {
|
|
541
|
+
this.checkIndexName(name);
|
|
542
|
+
try {
|
|
543
|
+
if (scope === 'data') {
|
|
544
|
+
await this.queryRun(`DROP INDEX ${MySQLDriver.escape(`${this.prefix}data_${etype}_id_custom_${name}_string_guid`)} ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)};`);
|
|
545
|
+
await this.queryRun(`DROP INDEX ${MySQLDriver.escape(`${this.prefix}data_${etype}_id_custom_${name}_number_guid`)} ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)};`);
|
|
546
|
+
await this.queryRun(`DROP INDEX ${MySQLDriver.escape(`${this.prefix}data_${etype}_id_custom_${name}_truthy_guid`)} ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)};`);
|
|
547
|
+
await this.queryRun(`DROP INDEX ${MySQLDriver.escape(`${this.prefix}data_${etype}_id_custom_${name}_json_guid`)} ON ${MySQLDriver.escape(`${this.prefix}data_${etype}`)};`);
|
|
548
|
+
}
|
|
549
|
+
else if (scope === 'references') {
|
|
550
|
+
await this.queryRun(`DROP INDEX ${MySQLDriver.escape(`${this.prefix}references_${etype}_id_custom_${name}_reference_guid`)} ON ${MySQLDriver.escape(`${this.prefix}references_${etype}`)};`);
|
|
551
|
+
}
|
|
552
|
+
else if (scope === 'tokens') {
|
|
553
|
+
await this.queryRun(`DROP INDEX ${MySQLDriver.escape(`${this.prefix}tokens_${etype}_id_custom_${name}_token_guid`)} ON ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)};`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
catch (e) {
|
|
557
|
+
if (e?.errorCode !== 1091) {
|
|
558
|
+
throw e;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
async getEtypes() {
|
|
564
|
+
const tables = await this.queryArray('SELECT `table_name` AS `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=@db AND `table_name` LIKE @prefix;', {
|
|
565
|
+
params: {
|
|
566
|
+
db: this.config.database,
|
|
567
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
568
|
+
},
|
|
569
|
+
});
|
|
452
570
|
const etypes = [];
|
|
453
|
-
for (const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
571
|
+
for (const table of tables) {
|
|
572
|
+
etypes.push(table.table_name.substr((this.prefix + 'entities_').length));
|
|
573
|
+
}
|
|
574
|
+
return etypes;
|
|
575
|
+
}
|
|
576
|
+
async *exportDataIterator() {
|
|
577
|
+
if (yield {
|
|
578
|
+
type: 'comment',
|
|
579
|
+
content: `#nex2
|
|
580
|
+
# Nymph Entity Exchange v2
|
|
581
|
+
# http://nymph.io
|
|
582
|
+
#
|
|
583
|
+
# Generation Time: ${new Date().toLocaleString()}
|
|
584
|
+
`,
|
|
585
|
+
}) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (yield {
|
|
589
|
+
type: 'comment',
|
|
590
|
+
content: `
|
|
591
|
+
|
|
592
|
+
#
|
|
593
|
+
# UIDs
|
|
594
|
+
#
|
|
595
|
+
|
|
596
|
+
`,
|
|
597
|
+
}) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
// Export UIDs.
|
|
601
|
+
let uids = await this.queryArray(`SELECT * FROM ${MySQLDriver.escape(`${this.prefix}uids`)} ORDER BY \`name\`;`);
|
|
602
|
+
for (const uid of uids) {
|
|
603
|
+
if (yield { type: 'uid', content: `<${uid.name}>[${uid.cur_uid}]\n` }) {
|
|
604
|
+
return;
|
|
457
605
|
}
|
|
458
606
|
}
|
|
607
|
+
if (yield {
|
|
608
|
+
type: 'comment',
|
|
609
|
+
content: `
|
|
610
|
+
|
|
611
|
+
#
|
|
612
|
+
# Entities
|
|
613
|
+
#
|
|
614
|
+
|
|
615
|
+
`,
|
|
616
|
+
}) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
// Get the etypes.
|
|
620
|
+
const etypes = await this.getEtypes();
|
|
459
621
|
for (const etype of etypes) {
|
|
460
|
-
|
|
622
|
+
// Export entities.
|
|
623
|
+
const entityIterator = this.exportEntityInternal(etype);
|
|
624
|
+
for await (let content of entityIterator) {
|
|
625
|
+
yield { type: 'entity', content };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
async exportEntity(etype, guid) {
|
|
630
|
+
const entityIterator = this.exportEntityInternal(etype, guid);
|
|
631
|
+
let exportContent = '';
|
|
632
|
+
for await (let content of entityIterator) {
|
|
633
|
+
exportContent += content;
|
|
634
|
+
}
|
|
635
|
+
return exportContent;
|
|
636
|
+
}
|
|
637
|
+
async *exportEntityInternal(etype, guid) {
|
|
638
|
+
// Export entities.
|
|
639
|
+
const dataIterator = (await this.queryArray(`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\`
|
|
461
640
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} e
|
|
462
|
-
LEFT JOIN ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} d ON e.\`guid\`=d.\`guid
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
641
|
+
LEFT JOIN ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} d ON e.\`guid\`=d.\`guid\`${guid == null ? '' : ` WHERE e.\`guid\`=UNHEX(@guid)`}
|
|
642
|
+
ORDER BY e.\`guid\`, d.\`name\`;`, guid == null ? undefined : { params: { guid } }))[Symbol.iterator]();
|
|
643
|
+
let datum = dataIterator.next();
|
|
644
|
+
while (!datum.done) {
|
|
645
|
+
const guid = datum.value.guid;
|
|
646
|
+
const tags = datum.value.tags
|
|
647
|
+
.slice(1, -1)
|
|
648
|
+
.split(' ')
|
|
649
|
+
.filter((tag) => tag)
|
|
650
|
+
.join(',');
|
|
651
|
+
const cdate = datum.value.cdate;
|
|
652
|
+
const mdate = datum.value.mdate;
|
|
653
|
+
const user = datum.value.user;
|
|
654
|
+
const group = datum.value.group;
|
|
655
|
+
const acUser = datum.value.acUser;
|
|
656
|
+
const acGroup = datum.value.acGroup;
|
|
657
|
+
const acOther = datum.value.acOther;
|
|
658
|
+
const acRead = datum.value.acRead?.slice(1, -1).split(' ');
|
|
659
|
+
const acWrite = datum.value.acWrite?.slice(1, -1).split(' ');
|
|
660
|
+
const acFull = datum.value.acFull?.slice(1, -1).split(' ');
|
|
661
|
+
let currentEntityExport = [];
|
|
662
|
+
currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
|
|
663
|
+
currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
|
|
664
|
+
currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
|
|
665
|
+
if (this.nymph.tilmeld != null) {
|
|
666
|
+
if (user != null) {
|
|
667
|
+
currentEntityExport.push(`\tuser=${JSON.stringify(['nymph_entity_reference', user, 'User'])}`);
|
|
484
668
|
}
|
|
485
|
-
|
|
486
|
-
|
|
669
|
+
if (group != null) {
|
|
670
|
+
currentEntityExport.push(`\tgroup=${JSON.stringify(['nymph_entity_reference', group, 'Group'])}`);
|
|
671
|
+
}
|
|
672
|
+
if (acUser != null) {
|
|
673
|
+
currentEntityExport.push(`\tacUser=${JSON.stringify(acUser)}`);
|
|
674
|
+
}
|
|
675
|
+
if (acGroup != null) {
|
|
676
|
+
currentEntityExport.push(`\tacGroup=${JSON.stringify(acGroup)}`);
|
|
677
|
+
}
|
|
678
|
+
if (acOther != null) {
|
|
679
|
+
currentEntityExport.push(`\tacOther=${JSON.stringify(acOther)}`);
|
|
680
|
+
}
|
|
681
|
+
if (acRead != null) {
|
|
682
|
+
currentEntityExport.push(`\tacRead=${JSON.stringify(acRead)}`);
|
|
683
|
+
}
|
|
684
|
+
if (acWrite != null) {
|
|
685
|
+
currentEntityExport.push(`\tacWrite=${JSON.stringify(acWrite)}`);
|
|
686
|
+
}
|
|
687
|
+
if (acFull != null) {
|
|
688
|
+
currentEntityExport.push(`\tacFull=${JSON.stringify(acFull)}`);
|
|
487
689
|
}
|
|
488
690
|
}
|
|
691
|
+
if (datum.value.name != null) {
|
|
692
|
+
// This do will keep going and adding the data until the
|
|
693
|
+
// next entity is reached. $row will end on the next entity.
|
|
694
|
+
do {
|
|
695
|
+
const value = datum.value.value === 'N'
|
|
696
|
+
? JSON.stringify(datum.value.number)
|
|
697
|
+
: datum.value.value === 'S'
|
|
698
|
+
? JSON.stringify(datum.value.string)
|
|
699
|
+
: datum.value.value === 'J'
|
|
700
|
+
? JSON.stringify(datum.value.json)
|
|
701
|
+
: datum.value.value;
|
|
702
|
+
currentEntityExport.push(`\t${datum.value.name}=${value}`);
|
|
703
|
+
datum = dataIterator.next();
|
|
704
|
+
} while (!datum.done && datum.value.guid === guid);
|
|
705
|
+
}
|
|
706
|
+
else {
|
|
707
|
+
// Make sure that datum is incremented :)
|
|
708
|
+
datum = dataIterator.next();
|
|
709
|
+
}
|
|
710
|
+
currentEntityExport.push('');
|
|
711
|
+
if (yield currentEntityExport.join('\n')) {
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
489
714
|
}
|
|
490
|
-
return;
|
|
491
715
|
}
|
|
492
|
-
|
|
716
|
+
/**
|
|
717
|
+
* Generate the MySQL query.
|
|
718
|
+
* @param options The options array.
|
|
719
|
+
* @param formattedSelectors The formatted selector array.
|
|
720
|
+
* @param etype
|
|
721
|
+
* @param count Used to track internal params.
|
|
722
|
+
* @param params Used to store internal params.
|
|
723
|
+
* @param subquery Whether only a subquery should be returned.
|
|
724
|
+
* @returns The SQL query.
|
|
725
|
+
*/
|
|
726
|
+
makeEntityQuery(options, formattedSelectors, etype, count = { i: 0 }, params = {}, subquery = false, tableSuffix = '', etypes = [], guidSelector = undefined, guidExplicitSelector = undefined) {
|
|
493
727
|
if (typeof options.class?.alterOptions === 'function') {
|
|
494
728
|
options = options.class.alterOptions(options);
|
|
495
729
|
}
|
|
496
730
|
const eTable = `e${tableSuffix}`;
|
|
497
731
|
const dTable = `d${tableSuffix}`;
|
|
498
|
-
const cTable = `c${tableSuffix}`;
|
|
499
732
|
const fTable = `f${tableSuffix}`;
|
|
500
733
|
const ieTable = `ie${tableSuffix}`;
|
|
501
734
|
const countTable = `count${tableSuffix}`;
|
|
502
|
-
const
|
|
503
|
-
const
|
|
735
|
+
const sTable = `s${tableSuffix}`;
|
|
736
|
+
const sort = options.sort === undefined ? 'cdate' : options.sort;
|
|
737
|
+
const queryParts = this.iterateSelectorsForQuery(formattedSelectors, ({ key, value, typeIsOr, typeIsNot }) => {
|
|
504
738
|
const clauseNot = key.startsWith('!');
|
|
505
739
|
let curQuery = '';
|
|
506
740
|
for (const curValue of value) {
|
|
@@ -513,7 +747,7 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
513
747
|
}
|
|
514
748
|
const guid = `param${++count.i}`;
|
|
515
749
|
curQuery +=
|
|
516
|
-
(
|
|
750
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
517
751
|
ieTable +
|
|
518
752
|
'.`guid`=UNHEX(@' +
|
|
519
753
|
guid +
|
|
@@ -523,7 +757,7 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
523
757
|
break;
|
|
524
758
|
case 'tag':
|
|
525
759
|
case '!tag':
|
|
526
|
-
if (
|
|
760
|
+
if (xor(typeIsNot, clauseNot)) {
|
|
527
761
|
if (typeIsOr) {
|
|
528
762
|
for (const curTag of curValue) {
|
|
529
763
|
if (curQuery) {
|
|
@@ -564,17 +798,38 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
564
798
|
if (curQuery) {
|
|
565
799
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
566
800
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
801
|
+
if (curVar === 'cdate' ||
|
|
802
|
+
curVar === 'mdate' ||
|
|
803
|
+
(this.nymph.tilmeld != null &&
|
|
804
|
+
(curVar === 'user' ||
|
|
805
|
+
curVar === 'group' ||
|
|
806
|
+
curVar === 'acUser' ||
|
|
807
|
+
curVar === 'acGroup' ||
|
|
808
|
+
curVar === 'acOther' ||
|
|
809
|
+
curVar === 'acRead' ||
|
|
810
|
+
curVar === 'acWrite' ||
|
|
811
|
+
curVar === 'acFull'))) {
|
|
812
|
+
curQuery +=
|
|
813
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
814
|
+
'(' +
|
|
815
|
+
ieTable +
|
|
816
|
+
'.' +
|
|
817
|
+
MySQLDriver.escape(curVar) +
|
|
818
|
+
' IS NOT NULL)';
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
const name = `param${++count.i}`;
|
|
822
|
+
curQuery +=
|
|
823
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
824
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
825
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
826
|
+
' WHERE `guid`=' +
|
|
827
|
+
ieTable +
|
|
828
|
+
'.`guid` AND `name`=@' +
|
|
829
|
+
name +
|
|
830
|
+
')';
|
|
831
|
+
params[name] = curVar;
|
|
832
|
+
}
|
|
578
833
|
}
|
|
579
834
|
break;
|
|
580
835
|
case 'truthy':
|
|
@@ -583,30 +838,34 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
583
838
|
if (curQuery) {
|
|
584
839
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
585
840
|
}
|
|
586
|
-
if (curVar === 'cdate'
|
|
841
|
+
if (curVar === 'cdate' ||
|
|
842
|
+
curVar === 'mdate' ||
|
|
843
|
+
(this.nymph.tilmeld != null &&
|
|
844
|
+
(curVar === 'user' ||
|
|
845
|
+
curVar === 'group' ||
|
|
846
|
+
curVar === 'acUser' ||
|
|
847
|
+
curVar === 'acGroup' ||
|
|
848
|
+
curVar === 'acOther' ||
|
|
849
|
+
curVar === 'acRead' ||
|
|
850
|
+
curVar === 'acWrite' ||
|
|
851
|
+
curVar === 'acFull'))) {
|
|
587
852
|
curQuery +=
|
|
588
|
-
(
|
|
853
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
589
854
|
'(' +
|
|
590
855
|
ieTable +
|
|
591
|
-
'
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
else if (curVar === 'mdate') {
|
|
595
|
-
curQuery +=
|
|
596
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
597
|
-
'(' +
|
|
598
|
-
ieTable +
|
|
599
|
-
'.`mdate` NOT NULL)';
|
|
600
|
-
break;
|
|
856
|
+
'.' +
|
|
857
|
+
MySQLDriver.escape(curVar) +
|
|
858
|
+
' IS NOT NULL)';
|
|
601
859
|
}
|
|
602
860
|
else {
|
|
603
861
|
const name = `param${++count.i}`;
|
|
604
862
|
curQuery +=
|
|
605
|
-
(
|
|
863
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
864
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
865
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
866
|
+
' WHERE `guid`=' +
|
|
606
867
|
ieTable +
|
|
607
|
-
'.`guid`
|
|
608
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
609
|
-
' WHERE `name`=@' +
|
|
868
|
+
'.`guid` AND `name`=@' +
|
|
610
869
|
name +
|
|
611
870
|
' AND `truthy`=TRUE)';
|
|
612
871
|
params[name] = curVar;
|
|
@@ -615,35 +874,61 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
615
874
|
break;
|
|
616
875
|
case 'equal':
|
|
617
876
|
case '!equal':
|
|
618
|
-
if (curValue[0] === 'cdate'
|
|
877
|
+
if (curValue[0] === 'cdate' ||
|
|
878
|
+
curValue[0] === 'mdate' ||
|
|
879
|
+
(this.nymph.tilmeld != null &&
|
|
880
|
+
(curValue[0] === 'acUser' ||
|
|
881
|
+
curValue[0] === 'acGroup' ||
|
|
882
|
+
curValue[0] === 'acOther'))) {
|
|
619
883
|
if (curQuery) {
|
|
620
884
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
621
885
|
}
|
|
622
|
-
const
|
|
886
|
+
const value = `param${++count.i}`;
|
|
623
887
|
curQuery +=
|
|
624
|
-
(
|
|
888
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
625
889
|
ieTable +
|
|
626
|
-
'
|
|
627
|
-
|
|
628
|
-
|
|
890
|
+
'.' +
|
|
891
|
+
MySQLDriver.escape(curValue[0]) +
|
|
892
|
+
'=@' +
|
|
893
|
+
value;
|
|
894
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
629
895
|
? null
|
|
630
896
|
: Number(curValue[1]);
|
|
631
|
-
break;
|
|
632
897
|
}
|
|
633
|
-
else if (
|
|
898
|
+
else if (this.nymph.tilmeld != null &&
|
|
899
|
+
(curValue[0] === 'user' || curValue[0] === 'group')) {
|
|
634
900
|
if (curQuery) {
|
|
635
901
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
636
902
|
}
|
|
637
|
-
const
|
|
903
|
+
const value = `param${++count.i}`;
|
|
638
904
|
curQuery +=
|
|
639
|
-
(
|
|
905
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
640
906
|
ieTable +
|
|
641
|
-
'
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
907
|
+
'.' +
|
|
908
|
+
MySQLDriver.escape(curValue[0]) +
|
|
909
|
+
'=UNHEX(@' +
|
|
910
|
+
value +
|
|
911
|
+
')';
|
|
912
|
+
params[value] = `${curValue[1]}`;
|
|
913
|
+
}
|
|
914
|
+
else if (this.nymph.tilmeld != null &&
|
|
915
|
+
(curValue[0] === 'acRead' ||
|
|
916
|
+
curValue[0] === 'acWrite' ||
|
|
917
|
+
curValue[0] === 'acFull')) {
|
|
918
|
+
if (curQuery) {
|
|
919
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
920
|
+
}
|
|
921
|
+
const value = `param${++count.i}`;
|
|
922
|
+
curQuery +=
|
|
923
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
924
|
+
ieTable +
|
|
925
|
+
'.' +
|
|
926
|
+
MySQLDriver.escape(curValue[0]) +
|
|
927
|
+
'=@' +
|
|
928
|
+
value;
|
|
929
|
+
params[value] = Array.isArray(curValue[1])
|
|
930
|
+
? ' ' + curValue[1].join(' ') + ' '
|
|
931
|
+
: '';
|
|
647
932
|
}
|
|
648
933
|
else if (typeof curValue[1] === 'number') {
|
|
649
934
|
if (curQuery) {
|
|
@@ -652,11 +937,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
652
937
|
const name = `param${++count.i}`;
|
|
653
938
|
const value = `param${++count.i}`;
|
|
654
939
|
curQuery +=
|
|
655
|
-
(
|
|
940
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
941
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
942
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
943
|
+
' WHERE `guid`=' +
|
|
656
944
|
ieTable +
|
|
657
|
-
'.`guid`
|
|
658
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
659
|
-
' WHERE `name`=@' +
|
|
945
|
+
'.`guid` AND `name`=@' +
|
|
660
946
|
name +
|
|
661
947
|
' AND `number`=@' +
|
|
662
948
|
value +
|
|
@@ -671,11 +957,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
671
957
|
const name = `param${++count.i}`;
|
|
672
958
|
const value = `param${++count.i}`;
|
|
673
959
|
curQuery +=
|
|
674
|
-
(
|
|
960
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
961
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
962
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
963
|
+
' WHERE `guid`=' +
|
|
675
964
|
ieTable +
|
|
676
|
-
'.`guid`
|
|
677
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
678
|
-
' WHERE `name`=@' +
|
|
965
|
+
'.`guid` AND `name`=@' +
|
|
679
966
|
name +
|
|
680
967
|
' AND `string`=@' +
|
|
681
968
|
value +
|
|
@@ -697,139 +984,284 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
697
984
|
}
|
|
698
985
|
const name = `param${++count.i}`;
|
|
699
986
|
const value = `param${++count.i}`;
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
987
|
+
if (svalue.length < 500) {
|
|
988
|
+
curQuery +=
|
|
989
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
990
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
991
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
992
|
+
' WHERE `guid`=' +
|
|
993
|
+
ieTable +
|
|
994
|
+
'.`guid` AND `name`=@' +
|
|
995
|
+
name +
|
|
996
|
+
' AND (CAST(`json` AS CHAR(500)) COLLATE utf8mb4_bin)=CAST(CAST(@' +
|
|
997
|
+
value +
|
|
998
|
+
' AS JSON) AS CHAR(500)))';
|
|
999
|
+
}
|
|
1000
|
+
else {
|
|
1001
|
+
curQuery +=
|
|
1002
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1003
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1004
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1005
|
+
' WHERE `guid`=' +
|
|
1006
|
+
ieTable +
|
|
1007
|
+
'.`guid` AND `name`=@' +
|
|
1008
|
+
name +
|
|
1009
|
+
' AND `json`=CAST(@' +
|
|
1010
|
+
value +
|
|
1011
|
+
' AS JSON))';
|
|
1012
|
+
}
|
|
710
1013
|
params[name] = curValue[0];
|
|
711
1014
|
params[value] = svalue;
|
|
712
1015
|
}
|
|
713
1016
|
break;
|
|
714
1017
|
case 'contain':
|
|
715
1018
|
case '!contain':
|
|
716
|
-
if (curValue[0] === 'cdate'
|
|
1019
|
+
if (curValue[0] === 'cdate' ||
|
|
1020
|
+
curValue[0] === 'mdate' ||
|
|
1021
|
+
(this.nymph.tilmeld != null &&
|
|
1022
|
+
(curValue[0] === 'acUser' ||
|
|
1023
|
+
curValue[0] === 'acGroup' ||
|
|
1024
|
+
curValue[0] === 'acOther'))) {
|
|
717
1025
|
if (curQuery) {
|
|
718
1026
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
719
1027
|
}
|
|
720
|
-
const
|
|
1028
|
+
const value = `param${++count.i}`;
|
|
721
1029
|
curQuery +=
|
|
722
|
-
(
|
|
1030
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
723
1031
|
ieTable +
|
|
724
|
-
'
|
|
725
|
-
|
|
726
|
-
|
|
1032
|
+
'.' +
|
|
1033
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1034
|
+
'=@' +
|
|
1035
|
+
value;
|
|
1036
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
727
1037
|
? null
|
|
728
1038
|
: Number(curValue[1]);
|
|
729
|
-
break;
|
|
730
1039
|
}
|
|
731
|
-
else if (
|
|
1040
|
+
else if (this.nymph.tilmeld != null &&
|
|
1041
|
+
(curValue[0] === 'user' || curValue[0] === 'group')) {
|
|
732
1042
|
if (curQuery) {
|
|
733
1043
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
734
1044
|
}
|
|
735
|
-
const
|
|
1045
|
+
const value = `param${++count.i}`;
|
|
736
1046
|
curQuery +=
|
|
737
|
-
(
|
|
1047
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
738
1048
|
ieTable +
|
|
739
|
-
'
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
1049
|
+
'.' +
|
|
1050
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1051
|
+
'=UNHEX(@' +
|
|
1052
|
+
value +
|
|
1053
|
+
')';
|
|
1054
|
+
params[value] = `${curValue[1]}`;
|
|
1055
|
+
}
|
|
1056
|
+
else if (this.nymph.tilmeld != null &&
|
|
1057
|
+
(curValue[0] === 'acRead' ||
|
|
1058
|
+
curValue[0] === 'acWrite' ||
|
|
1059
|
+
curValue[0] === 'acFull')) {
|
|
1060
|
+
if (curQuery) {
|
|
1061
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1062
|
+
}
|
|
1063
|
+
const queryParam = `param${++count.i}`;
|
|
1064
|
+
curQuery +=
|
|
1065
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1066
|
+
'MATCH (' +
|
|
1067
|
+
ieTable +
|
|
1068
|
+
'.' +
|
|
1069
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1070
|
+
') AGAINST (@' +
|
|
1071
|
+
queryParam +
|
|
1072
|
+
' IN BOOLEAN MODE)';
|
|
1073
|
+
params[queryParam] = '+' + curValue[1];
|
|
745
1074
|
}
|
|
746
1075
|
else {
|
|
747
1076
|
if (curQuery) {
|
|
748
1077
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
749
1078
|
}
|
|
750
1079
|
let svalue;
|
|
751
|
-
let stringValue;
|
|
752
1080
|
if (curValue[1] instanceof Object &&
|
|
753
1081
|
typeof curValue[1].toReference === 'function') {
|
|
754
1082
|
svalue = JSON.stringify(curValue[1].toReference());
|
|
755
|
-
stringValue = `${curValue[1].toReference()}`;
|
|
756
1083
|
}
|
|
757
1084
|
else {
|
|
758
1085
|
svalue = JSON.stringify(curValue[1]);
|
|
759
|
-
stringValue = `${curValue[1]}`;
|
|
760
1086
|
}
|
|
761
1087
|
const name = `param${++count.i}`;
|
|
762
1088
|
const value = `param${++count.i}`;
|
|
763
|
-
|
|
764
|
-
|
|
1089
|
+
curQuery +=
|
|
1090
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1091
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1092
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1093
|
+
' WHERE `guid`=' +
|
|
1094
|
+
ieTable +
|
|
1095
|
+
'.`guid` AND `name`=@' +
|
|
1096
|
+
name +
|
|
1097
|
+
' AND JSON_CONTAINS(`json`, @' +
|
|
1098
|
+
value +
|
|
1099
|
+
'))';
|
|
1100
|
+
params[name] = curValue[0];
|
|
1101
|
+
params[value] = svalue;
|
|
1102
|
+
}
|
|
1103
|
+
break;
|
|
1104
|
+
case 'search':
|
|
1105
|
+
case '!search':
|
|
1106
|
+
if (curValue[0] === 'cdate' ||
|
|
1107
|
+
curValue[0] === 'mdate' ||
|
|
1108
|
+
(this.nymph.tilmeld != null &&
|
|
1109
|
+
(curValue[0] === 'user' ||
|
|
1110
|
+
curValue[0] === 'group' ||
|
|
1111
|
+
curValue[0] === 'acUser' ||
|
|
1112
|
+
curValue[0] === 'acGroup' ||
|
|
1113
|
+
curValue[0] === 'acOther' ||
|
|
1114
|
+
curValue[0] === 'acRead' ||
|
|
1115
|
+
curValue[0] === 'acWrite' ||
|
|
1116
|
+
curValue[0] === 'acFull'))) {
|
|
1117
|
+
if (curQuery) {
|
|
1118
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1119
|
+
}
|
|
1120
|
+
curQuery +=
|
|
1121
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(FALSE)';
|
|
1122
|
+
}
|
|
1123
|
+
else {
|
|
1124
|
+
if (curQuery) {
|
|
1125
|
+
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1126
|
+
}
|
|
1127
|
+
const parsedFTSQuery = this.tokenizer.parseSearchQuery(curValue[1]);
|
|
1128
|
+
if (!parsedFTSQuery.length) {
|
|
765
1129
|
curQuery +=
|
|
766
|
-
(
|
|
767
|
-
|
|
1130
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(FALSE)';
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
const name = `param${++count.i}`;
|
|
1134
|
+
const queryPartToken = (term) => {
|
|
1135
|
+
const value = `param${++count.i}`;
|
|
1136
|
+
params[value] = term.token;
|
|
1137
|
+
return ('EXISTS (SELECT `guid` FROM ' +
|
|
1138
|
+
MySQLDriver.escape(this.prefix + 'tokens_' + etype) +
|
|
1139
|
+
' WHERE `guid`=' +
|
|
768
1140
|
ieTable +
|
|
769
|
-
'.`guid`
|
|
770
|
-
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
771
|
-
' WHERE `name`=@' +
|
|
1141
|
+
'.`guid` AND `name`=@' +
|
|
772
1142
|
name +
|
|
773
|
-
' AND
|
|
1143
|
+
' AND `token`=@' +
|
|
774
1144
|
value +
|
|
775
|
-
'
|
|
1145
|
+
(term.nostemmed ? ' AND `stem`=FALSE' : '') +
|
|
1146
|
+
')');
|
|
1147
|
+
};
|
|
1148
|
+
const queryPartSeries = (series) => {
|
|
1149
|
+
const tokenTableSuffix = makeTableSuffix();
|
|
1150
|
+
const tokenParts = series.tokens.map((token, i) => {
|
|
1151
|
+
const value = `param${++count.i}`;
|
|
1152
|
+
params[value] = token.token;
|
|
1153
|
+
return {
|
|
1154
|
+
fromClause: i === 0
|
|
1155
|
+
? 'FROM ' +
|
|
1156
|
+
MySQLDriver.escape(this.prefix + 'tokens_' + etype) +
|
|
1157
|
+
' t' +
|
|
1158
|
+
tokenTableSuffix +
|
|
1159
|
+
'0'
|
|
1160
|
+
: 'JOIN ' +
|
|
1161
|
+
MySQLDriver.escape(this.prefix + 'tokens_' + etype) +
|
|
1162
|
+
' t' +
|
|
1163
|
+
tokenTableSuffix +
|
|
1164
|
+
i +
|
|
1165
|
+
' ON t' +
|
|
1166
|
+
tokenTableSuffix +
|
|
1167
|
+
i +
|
|
1168
|
+
'.`guid` = t' +
|
|
1169
|
+
tokenTableSuffix +
|
|
1170
|
+
'0.`guid` AND t' +
|
|
1171
|
+
tokenTableSuffix +
|
|
1172
|
+
i +
|
|
1173
|
+
'.`name` = t' +
|
|
1174
|
+
tokenTableSuffix +
|
|
1175
|
+
'0.`name` AND t' +
|
|
1176
|
+
tokenTableSuffix +
|
|
1177
|
+
i +
|
|
1178
|
+
'.`position` = t' +
|
|
1179
|
+
tokenTableSuffix +
|
|
1180
|
+
'0.`position` + ' +
|
|
1181
|
+
i,
|
|
1182
|
+
whereClause: 't' +
|
|
1183
|
+
tokenTableSuffix +
|
|
1184
|
+
i +
|
|
1185
|
+
'.`token`=@' +
|
|
1186
|
+
value +
|
|
1187
|
+
(token.nostemmed
|
|
1188
|
+
? ' AND t' + tokenTableSuffix + i + '.`stem`=FALSE'
|
|
1189
|
+
: ''),
|
|
1190
|
+
};
|
|
1191
|
+
});
|
|
1192
|
+
return ('EXISTS (SELECT t' +
|
|
1193
|
+
tokenTableSuffix +
|
|
1194
|
+
'0.`guid` ' +
|
|
1195
|
+
tokenParts.map((part) => part.fromClause).join(' ') +
|
|
1196
|
+
' WHERE t' +
|
|
1197
|
+
tokenTableSuffix +
|
|
1198
|
+
'0.`guid`=' +
|
|
776
1199
|
ieTable +
|
|
777
|
-
'.`guid`
|
|
778
|
-
|
|
779
|
-
'
|
|
1200
|
+
'.`guid` AND t' +
|
|
1201
|
+
tokenTableSuffix +
|
|
1202
|
+
'0.`name`=@' +
|
|
780
1203
|
name +
|
|
781
|
-
' AND
|
|
782
|
-
|
|
783
|
-
'))
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1204
|
+
' AND ' +
|
|
1205
|
+
tokenParts.map((part) => part.whereClause).join(' AND ') +
|
|
1206
|
+
')');
|
|
1207
|
+
};
|
|
1208
|
+
const queryPartTerm = (term) => {
|
|
1209
|
+
if (term.type === 'series') {
|
|
1210
|
+
return queryPartSeries(term);
|
|
1211
|
+
}
|
|
1212
|
+
else if (term.type === 'not') {
|
|
1213
|
+
return 'NOT ' + queryPartTerm(term.operand);
|
|
1214
|
+
}
|
|
1215
|
+
else if (term.type === 'or') {
|
|
1216
|
+
let queryParts = [];
|
|
1217
|
+
for (let operand of term.operands) {
|
|
1218
|
+
queryParts.push(queryPartTerm(operand));
|
|
1219
|
+
}
|
|
1220
|
+
return '(' + queryParts.join(' OR ') + ')';
|
|
1221
|
+
}
|
|
1222
|
+
return queryPartToken(term);
|
|
1223
|
+
};
|
|
1224
|
+
// Run through the query and add terms.
|
|
1225
|
+
let termStrings = [];
|
|
1226
|
+
for (let term of parsedFTSQuery) {
|
|
1227
|
+
termStrings.push(queryPartTerm(term));
|
|
1228
|
+
}
|
|
787
1229
|
curQuery +=
|
|
788
|
-
(
|
|
789
|
-
|
|
790
|
-
'
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
name +
|
|
794
|
-
' AND INSTR(`value`, @' +
|
|
795
|
-
value +
|
|
796
|
-
'))';
|
|
1230
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1231
|
+
'(' +
|
|
1232
|
+
termStrings.join(' AND ') +
|
|
1233
|
+
')';
|
|
1234
|
+
params[name] = curValue[0];
|
|
797
1235
|
}
|
|
798
|
-
params[name] = curValue[0];
|
|
799
|
-
params[value] = svalue;
|
|
800
1236
|
}
|
|
801
1237
|
break;
|
|
802
1238
|
case 'match':
|
|
803
1239
|
case '!match':
|
|
804
|
-
if (curValue[0] === 'cdate'
|
|
1240
|
+
if (curValue[0] === 'cdate' ||
|
|
1241
|
+
curValue[0] === 'mdate' ||
|
|
1242
|
+
(this.nymph.tilmeld != null &&
|
|
1243
|
+
(curValue[0] === 'user' ||
|
|
1244
|
+
curValue[0] === 'group' ||
|
|
1245
|
+
curValue[0] === 'acUser' ||
|
|
1246
|
+
curValue[0] === 'acGroup' ||
|
|
1247
|
+
curValue[0] === 'acOther' ||
|
|
1248
|
+
curValue[0] === 'acRead' ||
|
|
1249
|
+
curValue[0] === 'acWrite' ||
|
|
1250
|
+
curValue[0] === 'acFull'))) {
|
|
805
1251
|
if (curQuery) {
|
|
806
1252
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
807
1253
|
}
|
|
808
|
-
const
|
|
809
|
-
curQuery +=
|
|
810
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
811
|
-
'(' +
|
|
812
|
-
ieTable +
|
|
813
|
-
'.`cdate` REGEXP @' +
|
|
814
|
-
cdate +
|
|
815
|
-
')';
|
|
816
|
-
params[cdate] = curValue[1];
|
|
817
|
-
break;
|
|
818
|
-
}
|
|
819
|
-
else if (curValue[0] === 'mdate') {
|
|
820
|
-
if (curQuery) {
|
|
821
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
822
|
-
}
|
|
823
|
-
const mdate = `param${++count.i}`;
|
|
1254
|
+
const value = `param${++count.i}`;
|
|
824
1255
|
curQuery +=
|
|
825
|
-
(
|
|
1256
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
826
1257
|
'(' +
|
|
827
1258
|
ieTable +
|
|
828
|
-
'
|
|
829
|
-
|
|
1259
|
+
'.' +
|
|
1260
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1261
|
+
' REGEXP @' +
|
|
1262
|
+
value +
|
|
830
1263
|
')';
|
|
831
|
-
params[
|
|
832
|
-
break;
|
|
1264
|
+
params[value] = curValue[1];
|
|
833
1265
|
}
|
|
834
1266
|
else {
|
|
835
1267
|
if (curQuery) {
|
|
@@ -838,11 +1270,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
838
1270
|
const name = `param${++count.i}`;
|
|
839
1271
|
const value = `param${++count.i}`;
|
|
840
1272
|
curQuery +=
|
|
841
|
-
(
|
|
1273
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1274
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1275
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1276
|
+
' WHERE `guid`=' +
|
|
842
1277
|
ieTable +
|
|
843
|
-
'.`guid`
|
|
844
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
845
|
-
' WHERE `name`=@' +
|
|
1278
|
+
'.`guid` AND `name`=@' +
|
|
846
1279
|
name +
|
|
847
1280
|
' AND `string` REGEXP @' +
|
|
848
1281
|
value +
|
|
@@ -853,35 +1286,31 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
853
1286
|
break;
|
|
854
1287
|
case 'imatch':
|
|
855
1288
|
case '!imatch':
|
|
856
|
-
if (curValue[0] === 'cdate'
|
|
1289
|
+
if (curValue[0] === 'cdate' ||
|
|
1290
|
+
curValue[0] === 'mdate' ||
|
|
1291
|
+
(this.nymph.tilmeld != null &&
|
|
1292
|
+
(curValue[0] === 'user' ||
|
|
1293
|
+
curValue[0] === 'group' ||
|
|
1294
|
+
curValue[0] === 'acUser' ||
|
|
1295
|
+
curValue[0] === 'acGroup' ||
|
|
1296
|
+
curValue[0] === 'acOther' ||
|
|
1297
|
+
curValue[0] === 'acRead' ||
|
|
1298
|
+
curValue[0] === 'acWrite' ||
|
|
1299
|
+
curValue[0] === 'acFull'))) {
|
|
857
1300
|
if (curQuery) {
|
|
858
1301
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
859
1302
|
}
|
|
860
|
-
const
|
|
861
|
-
curQuery +=
|
|
862
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
863
|
-
'(' +
|
|
864
|
-
ieTable +
|
|
865
|
-
'.`cdate` REGEXP @' +
|
|
866
|
-
cdate +
|
|
867
|
-
')';
|
|
868
|
-
params[cdate] = curValue[1];
|
|
869
|
-
break;
|
|
870
|
-
}
|
|
871
|
-
else if (curValue[0] === 'mdate') {
|
|
872
|
-
if (curQuery) {
|
|
873
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
874
|
-
}
|
|
875
|
-
const mdate = `param${++count.i}`;
|
|
1303
|
+
const value = `param${++count.i}`;
|
|
876
1304
|
curQuery +=
|
|
877
|
-
(
|
|
1305
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
878
1306
|
'(' +
|
|
879
1307
|
ieTable +
|
|
880
|
-
'
|
|
881
|
-
|
|
1308
|
+
'.' +
|
|
1309
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1310
|
+
' REGEXP @' +
|
|
1311
|
+
value +
|
|
882
1312
|
')';
|
|
883
|
-
params[
|
|
884
|
-
break;
|
|
1313
|
+
params[value] = curValue[1];
|
|
885
1314
|
}
|
|
886
1315
|
else {
|
|
887
1316
|
if (curQuery) {
|
|
@@ -890,11 +1319,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
890
1319
|
const name = `param${++count.i}`;
|
|
891
1320
|
const value = `param${++count.i}`;
|
|
892
1321
|
curQuery +=
|
|
893
|
-
(
|
|
1322
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1323
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1324
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1325
|
+
' WHERE `guid`=' +
|
|
894
1326
|
ieTable +
|
|
895
|
-
'.`guid`
|
|
896
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
897
|
-
' WHERE `name`=@' +
|
|
1327
|
+
'.`guid` AND `name`=@' +
|
|
898
1328
|
name +
|
|
899
1329
|
' AND LOWER(`string`) REGEXP LOWER(@' +
|
|
900
1330
|
value +
|
|
@@ -905,35 +1335,31 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
905
1335
|
break;
|
|
906
1336
|
case 'like':
|
|
907
1337
|
case '!like':
|
|
908
|
-
if (curValue[0] === 'cdate'
|
|
1338
|
+
if (curValue[0] === 'cdate' ||
|
|
1339
|
+
curValue[0] === 'mdate' ||
|
|
1340
|
+
(this.nymph.tilmeld != null &&
|
|
1341
|
+
(curValue[0] === 'user' ||
|
|
1342
|
+
curValue[0] === 'group' ||
|
|
1343
|
+
curValue[0] === 'acUser' ||
|
|
1344
|
+
curValue[0] === 'acGroup' ||
|
|
1345
|
+
curValue[0] === 'acOther' ||
|
|
1346
|
+
curValue[0] === 'acRead' ||
|
|
1347
|
+
curValue[0] === 'acWrite' ||
|
|
1348
|
+
curValue[0] === 'acFull'))) {
|
|
909
1349
|
if (curQuery) {
|
|
910
1350
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
911
1351
|
}
|
|
912
|
-
const
|
|
913
|
-
curQuery +=
|
|
914
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
915
|
-
'(' +
|
|
916
|
-
ieTable +
|
|
917
|
-
'.`cdate` LIKE @' +
|
|
918
|
-
cdate +
|
|
919
|
-
')';
|
|
920
|
-
params[cdate] = curValue[1];
|
|
921
|
-
break;
|
|
922
|
-
}
|
|
923
|
-
else if (curValue[0] === 'mdate') {
|
|
924
|
-
if (curQuery) {
|
|
925
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
926
|
-
}
|
|
927
|
-
const mdate = `param${++count.i}`;
|
|
1352
|
+
const value = `param${++count.i}`;
|
|
928
1353
|
curQuery +=
|
|
929
|
-
(
|
|
1354
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
930
1355
|
'(' +
|
|
931
1356
|
ieTable +
|
|
932
|
-
'
|
|
933
|
-
|
|
1357
|
+
'.' +
|
|
1358
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1359
|
+
' LIKE @' +
|
|
1360
|
+
value +
|
|
934
1361
|
')';
|
|
935
|
-
params[
|
|
936
|
-
break;
|
|
1362
|
+
params[value] = curValue[1];
|
|
937
1363
|
}
|
|
938
1364
|
else {
|
|
939
1365
|
if (curQuery) {
|
|
@@ -942,11 +1368,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
942
1368
|
const name = `param${++count.i}`;
|
|
943
1369
|
const value = `param${++count.i}`;
|
|
944
1370
|
curQuery +=
|
|
945
|
-
(
|
|
1371
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1372
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1373
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1374
|
+
' WHERE `guid`=' +
|
|
946
1375
|
ieTable +
|
|
947
|
-
'.`guid`
|
|
948
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
949
|
-
' WHERE `name`=@' +
|
|
1376
|
+
'.`guid` AND `name`=@' +
|
|
950
1377
|
name +
|
|
951
1378
|
' AND `string` LIKE @' +
|
|
952
1379
|
value +
|
|
@@ -957,35 +1384,31 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
957
1384
|
break;
|
|
958
1385
|
case 'ilike':
|
|
959
1386
|
case '!ilike':
|
|
960
|
-
if (curValue[0] === 'cdate'
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
'
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
')';
|
|
972
|
-
params[cdate] = curValue[1];
|
|
973
|
-
break;
|
|
974
|
-
}
|
|
975
|
-
else if (curValue[0] === 'mdate') {
|
|
1387
|
+
if (curValue[0] === 'cdate' ||
|
|
1388
|
+
curValue[0] === 'mdate' ||
|
|
1389
|
+
(this.nymph.tilmeld != null &&
|
|
1390
|
+
(curValue[0] === 'user' ||
|
|
1391
|
+
curValue[0] === 'group' ||
|
|
1392
|
+
curValue[0] === 'acUser' ||
|
|
1393
|
+
curValue[0] === 'acGroup' ||
|
|
1394
|
+
curValue[0] === 'acOther' ||
|
|
1395
|
+
curValue[0] === 'acRead' ||
|
|
1396
|
+
curValue[0] === 'acWrite' ||
|
|
1397
|
+
curValue[0] === 'acFull'))) {
|
|
976
1398
|
if (curQuery) {
|
|
977
1399
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
978
1400
|
}
|
|
979
|
-
const
|
|
1401
|
+
const value = `param${++count.i}`;
|
|
980
1402
|
curQuery +=
|
|
981
|
-
(
|
|
1403
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
982
1404
|
'(' +
|
|
983
1405
|
ieTable +
|
|
984
|
-
'
|
|
985
|
-
|
|
1406
|
+
'.' +
|
|
1407
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1408
|
+
' LIKE @' +
|
|
1409
|
+
value +
|
|
986
1410
|
')';
|
|
987
|
-
params[
|
|
988
|
-
break;
|
|
1411
|
+
params[value] = curValue[1];
|
|
989
1412
|
}
|
|
990
1413
|
else {
|
|
991
1414
|
if (curQuery) {
|
|
@@ -994,11 +1417,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
994
1417
|
const name = `param${++count.i}`;
|
|
995
1418
|
const value = `param${++count.i}`;
|
|
996
1419
|
curQuery +=
|
|
997
|
-
(
|
|
1420
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1421
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1422
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1423
|
+
' WHERE `guid`=' +
|
|
998
1424
|
ieTable +
|
|
999
|
-
'.`guid`
|
|
1000
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1001
|
-
' WHERE `name`=@' +
|
|
1425
|
+
'.`guid` AND `name`=@' +
|
|
1002
1426
|
name +
|
|
1003
1427
|
' AND LOWER(`string`) LIKE LOWER(@' +
|
|
1004
1428
|
value +
|
|
@@ -1009,35 +1433,31 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1009
1433
|
break;
|
|
1010
1434
|
case 'gt':
|
|
1011
1435
|
case '!gt':
|
|
1012
|
-
if (curValue[0] === 'cdate'
|
|
1436
|
+
if (curValue[0] === 'cdate' ||
|
|
1437
|
+
curValue[0] === 'mdate' ||
|
|
1438
|
+
(this.nymph.tilmeld != null &&
|
|
1439
|
+
(curValue[0] === 'user' ||
|
|
1440
|
+
curValue[0] === 'group' ||
|
|
1441
|
+
curValue[0] === 'acUser' ||
|
|
1442
|
+
curValue[0] === 'acGroup' ||
|
|
1443
|
+
curValue[0] === 'acOther' ||
|
|
1444
|
+
curValue[0] === 'acRead' ||
|
|
1445
|
+
curValue[0] === 'acWrite' ||
|
|
1446
|
+
curValue[0] === 'acFull'))) {
|
|
1013
1447
|
if (curQuery) {
|
|
1014
1448
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1015
1449
|
}
|
|
1016
|
-
const
|
|
1017
|
-
curQuery +=
|
|
1018
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1019
|
-
ieTable +
|
|
1020
|
-
'.`cdate`>@' +
|
|
1021
|
-
cdate;
|
|
1022
|
-
params[cdate] = isNaN(Number(curValue[1]))
|
|
1023
|
-
? null
|
|
1024
|
-
: Number(curValue[1]);
|
|
1025
|
-
break;
|
|
1026
|
-
}
|
|
1027
|
-
else if (curValue[0] === 'mdate') {
|
|
1028
|
-
if (curQuery) {
|
|
1029
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1030
|
-
}
|
|
1031
|
-
const mdate = `param${++count.i}`;
|
|
1450
|
+
const value = `param${++count.i}`;
|
|
1032
1451
|
curQuery +=
|
|
1033
|
-
(
|
|
1452
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1034
1453
|
ieTable +
|
|
1035
|
-
'
|
|
1036
|
-
|
|
1037
|
-
|
|
1454
|
+
'.' +
|
|
1455
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1456
|
+
'>@' +
|
|
1457
|
+
value;
|
|
1458
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1038
1459
|
? null
|
|
1039
1460
|
: Number(curValue[1]);
|
|
1040
|
-
break;
|
|
1041
1461
|
}
|
|
1042
1462
|
else {
|
|
1043
1463
|
if (curQuery) {
|
|
@@ -1046,11 +1466,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1046
1466
|
const name = `param${++count.i}`;
|
|
1047
1467
|
const value = `param${++count.i}`;
|
|
1048
1468
|
curQuery +=
|
|
1049
|
-
(
|
|
1469
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1470
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1471
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1472
|
+
' WHERE `guid`=' +
|
|
1050
1473
|
ieTable +
|
|
1051
|
-
'.`guid`
|
|
1052
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1053
|
-
' WHERE `name`=@' +
|
|
1474
|
+
'.`guid` AND `name`=@' +
|
|
1054
1475
|
name +
|
|
1055
1476
|
' AND `number`>@' +
|
|
1056
1477
|
value +
|
|
@@ -1063,35 +1484,31 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1063
1484
|
break;
|
|
1064
1485
|
case 'gte':
|
|
1065
1486
|
case '!gte':
|
|
1066
|
-
if (curValue[0] === 'cdate'
|
|
1487
|
+
if (curValue[0] === 'cdate' ||
|
|
1488
|
+
curValue[0] === 'mdate' ||
|
|
1489
|
+
(this.nymph.tilmeld != null &&
|
|
1490
|
+
(curValue[0] === 'user' ||
|
|
1491
|
+
curValue[0] === 'group' ||
|
|
1492
|
+
curValue[0] === 'acUser' ||
|
|
1493
|
+
curValue[0] === 'acGroup' ||
|
|
1494
|
+
curValue[0] === 'acOther' ||
|
|
1495
|
+
curValue[0] === 'acRead' ||
|
|
1496
|
+
curValue[0] === 'acWrite' ||
|
|
1497
|
+
curValue[0] === 'acFull'))) {
|
|
1067
1498
|
if (curQuery) {
|
|
1068
1499
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1069
1500
|
}
|
|
1070
|
-
const
|
|
1071
|
-
curQuery +=
|
|
1072
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1073
|
-
ieTable +
|
|
1074
|
-
'.`cdate`>=@' +
|
|
1075
|
-
cdate;
|
|
1076
|
-
params[cdate] = isNaN(Number(curValue[1]))
|
|
1077
|
-
? null
|
|
1078
|
-
: Number(curValue[1]);
|
|
1079
|
-
break;
|
|
1080
|
-
}
|
|
1081
|
-
else if (curValue[0] === 'mdate') {
|
|
1082
|
-
if (curQuery) {
|
|
1083
|
-
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1084
|
-
}
|
|
1085
|
-
const mdate = `param${++count.i}`;
|
|
1501
|
+
const value = `param${++count.i}`;
|
|
1086
1502
|
curQuery +=
|
|
1087
|
-
(
|
|
1503
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1088
1504
|
ieTable +
|
|
1089
|
-
'
|
|
1090
|
-
|
|
1091
|
-
|
|
1505
|
+
'.' +
|
|
1506
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1507
|
+
'>=@' +
|
|
1508
|
+
value;
|
|
1509
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1092
1510
|
? null
|
|
1093
1511
|
: Number(curValue[1]);
|
|
1094
|
-
break;
|
|
1095
1512
|
}
|
|
1096
1513
|
else {
|
|
1097
1514
|
if (curQuery) {
|
|
@@ -1100,11 +1517,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1100
1517
|
const name = `param${++count.i}`;
|
|
1101
1518
|
const value = `param${++count.i}`;
|
|
1102
1519
|
curQuery +=
|
|
1103
|
-
(
|
|
1520
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1521
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1522
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1523
|
+
' WHERE `guid`=' +
|
|
1104
1524
|
ieTable +
|
|
1105
|
-
'.`guid`
|
|
1106
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1107
|
-
' WHERE `name`=@' +
|
|
1525
|
+
'.`guid` AND `name`=@' +
|
|
1108
1526
|
name +
|
|
1109
1527
|
' AND `number`>=@' +
|
|
1110
1528
|
value +
|
|
@@ -1115,37 +1533,33 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1115
1533
|
: Number(curValue[1]);
|
|
1116
1534
|
}
|
|
1117
1535
|
break;
|
|
1118
|
-
case 'lt':
|
|
1119
|
-
case '!lt':
|
|
1120
|
-
if (curValue[0] === 'cdate'
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
'
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
? null
|
|
1132
|
-
: Number(curValue[1]);
|
|
1133
|
-
break;
|
|
1134
|
-
}
|
|
1135
|
-
else if (curValue[0] === 'mdate') {
|
|
1536
|
+
case 'lt':
|
|
1537
|
+
case '!lt':
|
|
1538
|
+
if (curValue[0] === 'cdate' ||
|
|
1539
|
+
curValue[0] === 'mdate' ||
|
|
1540
|
+
(this.nymph.tilmeld != null &&
|
|
1541
|
+
(curValue[0] === 'user' ||
|
|
1542
|
+
curValue[0] === 'group' ||
|
|
1543
|
+
curValue[0] === 'acUser' ||
|
|
1544
|
+
curValue[0] === 'acGroup' ||
|
|
1545
|
+
curValue[0] === 'acOther' ||
|
|
1546
|
+
curValue[0] === 'acRead' ||
|
|
1547
|
+
curValue[0] === 'acWrite' ||
|
|
1548
|
+
curValue[0] === 'acFull'))) {
|
|
1136
1549
|
if (curQuery) {
|
|
1137
1550
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1138
1551
|
}
|
|
1139
|
-
const
|
|
1552
|
+
const value = `param${++count.i}`;
|
|
1140
1553
|
curQuery +=
|
|
1141
|
-
(
|
|
1554
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1142
1555
|
ieTable +
|
|
1143
|
-
'
|
|
1144
|
-
|
|
1145
|
-
|
|
1556
|
+
'.' +
|
|
1557
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1558
|
+
'<@' +
|
|
1559
|
+
value;
|
|
1560
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1146
1561
|
? null
|
|
1147
1562
|
: Number(curValue[1]);
|
|
1148
|
-
break;
|
|
1149
1563
|
}
|
|
1150
1564
|
else {
|
|
1151
1565
|
if (curQuery) {
|
|
@@ -1154,11 +1568,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1154
1568
|
const name = `param${++count.i}`;
|
|
1155
1569
|
const value = `param${++count.i}`;
|
|
1156
1570
|
curQuery +=
|
|
1157
|
-
(
|
|
1571
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1572
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1573
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1574
|
+
' WHERE `guid`=' +
|
|
1158
1575
|
ieTable +
|
|
1159
|
-
'.`guid`
|
|
1160
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1161
|
-
' WHERE `name`=@' +
|
|
1576
|
+
'.`guid` AND `name`=@' +
|
|
1162
1577
|
name +
|
|
1163
1578
|
' AND `number`<@' +
|
|
1164
1579
|
value +
|
|
@@ -1171,35 +1586,31 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1171
1586
|
break;
|
|
1172
1587
|
case 'lte':
|
|
1173
1588
|
case '!lte':
|
|
1174
|
-
if (curValue[0] === 'cdate'
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
'
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
? null
|
|
1186
|
-
: Number(curValue[1]);
|
|
1187
|
-
break;
|
|
1188
|
-
}
|
|
1189
|
-
else if (curValue[0] === 'mdate') {
|
|
1589
|
+
if (curValue[0] === 'cdate' ||
|
|
1590
|
+
curValue[0] === 'mdate' ||
|
|
1591
|
+
(this.nymph.tilmeld != null &&
|
|
1592
|
+
(curValue[0] === 'user' ||
|
|
1593
|
+
curValue[0] === 'group' ||
|
|
1594
|
+
curValue[0] === 'acUser' ||
|
|
1595
|
+
curValue[0] === 'acGroup' ||
|
|
1596
|
+
curValue[0] === 'acOther' ||
|
|
1597
|
+
curValue[0] === 'acRead' ||
|
|
1598
|
+
curValue[0] === 'acWrite' ||
|
|
1599
|
+
curValue[0] === 'acFull'))) {
|
|
1190
1600
|
if (curQuery) {
|
|
1191
1601
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1192
1602
|
}
|
|
1193
|
-
const
|
|
1603
|
+
const value = `param${++count.i}`;
|
|
1194
1604
|
curQuery +=
|
|
1195
|
-
(
|
|
1605
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1196
1606
|
ieTable +
|
|
1197
|
-
'
|
|
1198
|
-
|
|
1199
|
-
|
|
1607
|
+
'.' +
|
|
1608
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1609
|
+
'<=@' +
|
|
1610
|
+
value;
|
|
1611
|
+
params[value] = isNaN(Number(curValue[1]))
|
|
1200
1612
|
? null
|
|
1201
1613
|
: Number(curValue[1]);
|
|
1202
|
-
break;
|
|
1203
1614
|
}
|
|
1204
1615
|
else {
|
|
1205
1616
|
if (curQuery) {
|
|
@@ -1208,11 +1619,12 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1208
1619
|
const name = `param${++count.i}`;
|
|
1209
1620
|
const value = `param${++count.i}`;
|
|
1210
1621
|
curQuery +=
|
|
1211
|
-
(
|
|
1622
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1623
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1624
|
+
MySQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1625
|
+
' WHERE `guid`=' +
|
|
1212
1626
|
ieTable +
|
|
1213
|
-
'.`guid`
|
|
1214
|
-
MySQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1215
|
-
' WHERE `name`=@' +
|
|
1627
|
+
'.`guid` AND `name`=@' +
|
|
1216
1628
|
name +
|
|
1217
1629
|
' AND `number`<=@' +
|
|
1218
1630
|
value +
|
|
@@ -1238,71 +1650,190 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1238
1650
|
if (curQuery) {
|
|
1239
1651
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1240
1652
|
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1653
|
+
if (this.nymph.tilmeld != null &&
|
|
1654
|
+
(curValue[0] === 'user' || curValue[0] === 'group')) {
|
|
1655
|
+
const guid = `param${++count.i}`;
|
|
1656
|
+
curQuery +=
|
|
1657
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1658
|
+
ieTable +
|
|
1659
|
+
'.' +
|
|
1660
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1661
|
+
'=UNHEX(@' +
|
|
1662
|
+
guid +
|
|
1663
|
+
')';
|
|
1664
|
+
params[guid] = curQguid;
|
|
1665
|
+
}
|
|
1666
|
+
else if (this.nymph.tilmeld != null &&
|
|
1667
|
+
(curValue[0] === 'acRead' ||
|
|
1668
|
+
curValue[0] === 'acWrite' ||
|
|
1669
|
+
curValue[0] === 'acFull')) {
|
|
1670
|
+
const queryParam = `param${++count.i}`;
|
|
1671
|
+
curQuery +=
|
|
1672
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1673
|
+
'MATCH (' +
|
|
1674
|
+
ieTable +
|
|
1675
|
+
'.' +
|
|
1676
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1677
|
+
') AGAINST (@' +
|
|
1678
|
+
queryParam +
|
|
1679
|
+
' IN BOOLEAN MODE)';
|
|
1680
|
+
params[queryParam] = '+' + curQguid;
|
|
1681
|
+
}
|
|
1682
|
+
else {
|
|
1683
|
+
const name = `param${++count.i}`;
|
|
1684
|
+
const guid = `param${++count.i}`;
|
|
1685
|
+
curQuery +=
|
|
1686
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1687
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1688
|
+
MySQLDriver.escape(this.prefix + 'references_' + etype) +
|
|
1689
|
+
' WHERE `guid`=' +
|
|
1690
|
+
ieTable +
|
|
1691
|
+
'.`guid` AND `name`=@' +
|
|
1692
|
+
name +
|
|
1693
|
+
' AND `reference`=UNHEX(@' +
|
|
1694
|
+
guid +
|
|
1695
|
+
'))';
|
|
1696
|
+
params[name] = curValue[0];
|
|
1697
|
+
params[guid] = curQguid;
|
|
1698
|
+
}
|
|
1255
1699
|
break;
|
|
1256
1700
|
case 'selector':
|
|
1257
1701
|
case '!selector':
|
|
1258
|
-
const
|
|
1702
|
+
const innerquery = this.makeEntityQuery({ ...options, sort: null, limit: undefined }, [curValue], etype, count, params, true, tableSuffix, etypes);
|
|
1259
1703
|
if (curQuery) {
|
|
1260
1704
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1261
1705
|
}
|
|
1262
1706
|
curQuery +=
|
|
1263
|
-
(
|
|
1707
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1264
1708
|
'(' +
|
|
1265
|
-
|
|
1709
|
+
innerquery.query +
|
|
1266
1710
|
')';
|
|
1267
1711
|
break;
|
|
1268
1712
|
case 'qref':
|
|
1269
1713
|
case '!qref':
|
|
1714
|
+
const referenceTableSuffix = makeTableSuffix();
|
|
1270
1715
|
const [qrefOptions, ...qrefSelectors] = curValue[1];
|
|
1271
1716
|
const QrefEntityClass = qrefOptions.class;
|
|
1272
1717
|
etypes.push(QrefEntityClass.ETYPE);
|
|
1273
|
-
const qrefQuery = this.makeEntityQuery({ ...qrefOptions, return: 'guid', class: QrefEntityClass }, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, (0, guid_1.makeTableSuffix)(), etypes);
|
|
1274
1718
|
if (curQuery) {
|
|
1275
1719
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1276
1720
|
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1721
|
+
if (this.nymph.tilmeld != null &&
|
|
1722
|
+
(curValue[0] === 'user' || curValue[0] === 'group')) {
|
|
1723
|
+
const qrefQuery = this.makeEntityQuery({
|
|
1724
|
+
...qrefOptions,
|
|
1725
|
+
sort: qrefOptions.sort ?? null,
|
|
1726
|
+
return: 'guid',
|
|
1727
|
+
class: QrefEntityClass,
|
|
1728
|
+
}, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes, 'r' +
|
|
1729
|
+
referenceTableSuffix +
|
|
1730
|
+
'.' +
|
|
1731
|
+
MySQLDriver.escape(curValue[0]));
|
|
1732
|
+
curQuery +=
|
|
1733
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1734
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1735
|
+
MySQLDriver.escape(this.prefix + 'entities_' + etype) +
|
|
1736
|
+
' r' +
|
|
1737
|
+
referenceTableSuffix +
|
|
1738
|
+
' WHERE r' +
|
|
1739
|
+
referenceTableSuffix +
|
|
1740
|
+
'.`guid`=' +
|
|
1741
|
+
ieTable +
|
|
1742
|
+
'.`guid` AND EXISTS (' +
|
|
1743
|
+
qrefQuery.query +
|
|
1744
|
+
'))';
|
|
1745
|
+
}
|
|
1746
|
+
else if (this.nymph.tilmeld != null &&
|
|
1747
|
+
(curValue[0] === 'acRead' ||
|
|
1748
|
+
curValue[0] === 'acWrite' ||
|
|
1749
|
+
curValue[0] === 'acFull')) {
|
|
1750
|
+
const qrefQuery = this.makeEntityQuery({
|
|
1751
|
+
...qrefOptions,
|
|
1752
|
+
sort: qrefOptions.sort ?? null,
|
|
1753
|
+
return: 'guid',
|
|
1754
|
+
class: QrefEntityClass,
|
|
1755
|
+
}, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes, undefined, (guid) => ieTable +
|
|
1756
|
+
'.' +
|
|
1757
|
+
MySQLDriver.escape(curValue[0]) +
|
|
1758
|
+
" LIKE CONCAT('% ', LOWER(HEX(" +
|
|
1759
|
+
guid +
|
|
1760
|
+
")), ' %')");
|
|
1761
|
+
curQuery +=
|
|
1762
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1763
|
+
'EXISTS (' +
|
|
1764
|
+
qrefQuery.query +
|
|
1765
|
+
')';
|
|
1766
|
+
}
|
|
1767
|
+
else {
|
|
1768
|
+
const qrefQuery = this.makeEntityQuery({
|
|
1769
|
+
...qrefOptions,
|
|
1770
|
+
sort: qrefOptions.sort ?? null,
|
|
1771
|
+
return: 'guid',
|
|
1772
|
+
class: QrefEntityClass,
|
|
1773
|
+
}, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes, 'r' + referenceTableSuffix + '.`reference`');
|
|
1774
|
+
const qrefName = `param${++count.i}`;
|
|
1775
|
+
curQuery +=
|
|
1776
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1777
|
+
'EXISTS (SELECT `guid` FROM ' +
|
|
1778
|
+
MySQLDriver.escape(this.prefix + 'references_' + etype) +
|
|
1779
|
+
' r' +
|
|
1780
|
+
referenceTableSuffix +
|
|
1781
|
+
' WHERE r' +
|
|
1782
|
+
referenceTableSuffix +
|
|
1783
|
+
'.`guid`=' +
|
|
1784
|
+
ieTable +
|
|
1785
|
+
'.`guid` AND r' +
|
|
1786
|
+
referenceTableSuffix +
|
|
1787
|
+
'.`name`=@' +
|
|
1788
|
+
qrefName +
|
|
1789
|
+
' AND EXISTS (' +
|
|
1790
|
+
qrefQuery.query +
|
|
1791
|
+
'))';
|
|
1792
|
+
params[qrefName] = curValue[0];
|
|
1793
|
+
}
|
|
1289
1794
|
break;
|
|
1290
1795
|
}
|
|
1291
1796
|
}
|
|
1292
1797
|
return curQuery;
|
|
1293
1798
|
});
|
|
1294
1799
|
let sortBy;
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1800
|
+
let sortByInner;
|
|
1801
|
+
let sortJoin = '';
|
|
1802
|
+
let sortJoinInner = '';
|
|
1803
|
+
const order = options.reverse ? ' DESC' : '';
|
|
1804
|
+
if (sort == null) {
|
|
1805
|
+
sortBy = '';
|
|
1806
|
+
sortByInner = '';
|
|
1807
|
+
}
|
|
1808
|
+
else {
|
|
1809
|
+
switch (sort) {
|
|
1810
|
+
case 'mdate':
|
|
1811
|
+
sortBy = `ORDER BY ${eTable}.\`mdate\`${order}`;
|
|
1812
|
+
sortByInner = `ORDER BY ${ieTable}.\`mdate\`${order}`;
|
|
1813
|
+
break;
|
|
1814
|
+
case 'cdate':
|
|
1815
|
+
sortBy = `ORDER BY ${eTable}.\`cdate\`${order}`;
|
|
1816
|
+
sortByInner = `ORDER BY ${ieTable}.\`cdate\`${order}`;
|
|
1817
|
+
break;
|
|
1818
|
+
default:
|
|
1819
|
+
const name = `param${++count.i}`;
|
|
1820
|
+
sortJoin = `LEFT JOIN (
|
|
1821
|
+
SELECT \`guid\`, \`string\`, \`number\`
|
|
1822
|
+
FROM ${MySQLDriver.escape(this.prefix + 'data_' + etype)}
|
|
1823
|
+
WHERE \`name\`=@${name}
|
|
1824
|
+
ORDER BY \`number\`${order}, \`string\`${order}
|
|
1825
|
+
) ${sTable} ON ${eTable}.\`guid\`=${sTable}.\`guid\``;
|
|
1826
|
+
sortJoinInner = `LEFT JOIN (
|
|
1827
|
+
SELECT \`guid\`, \`string\`, \`number\`
|
|
1828
|
+
FROM ${MySQLDriver.escape(this.prefix + 'data_' + etype)}
|
|
1829
|
+
WHERE \`name\`=@${name}
|
|
1830
|
+
ORDER BY \`number\`${order}, \`string\`${order}
|
|
1831
|
+
) ${sTable} ON ${ieTable}.\`guid\`=${sTable}.\`guid\``;
|
|
1832
|
+
sortBy = `ORDER BY ${sTable}.\`number\`${order}, ${sTable}.\`string\`${order}`;
|
|
1833
|
+
sortByInner = sortBy;
|
|
1834
|
+
params[name] = sort;
|
|
1835
|
+
break;
|
|
1836
|
+
}
|
|
1306
1837
|
}
|
|
1307
1838
|
let query;
|
|
1308
1839
|
if (queryParts.length) {
|
|
@@ -1319,18 +1850,23 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1319
1850
|
offset = ` OFFSET ${Math.floor(isNaN(Number(options.offset)) ? 0 : Number(options.offset))}`;
|
|
1320
1851
|
}
|
|
1321
1852
|
const whereClause = queryParts.join(') AND (');
|
|
1853
|
+
const guidClause = guidExplicitSelector
|
|
1854
|
+
? `${guidExplicitSelector(`${ieTable}.\`guid\``)} AND `
|
|
1855
|
+
: guidSelector
|
|
1856
|
+
? `${ieTable}.\`guid\`=${guidSelector} AND `
|
|
1857
|
+
: '';
|
|
1322
1858
|
if (options.return === 'count') {
|
|
1323
1859
|
if (limit || offset) {
|
|
1324
1860
|
query = `SELECT COUNT(${countTable}.\`guid\`) AS \`count\` FROM (
|
|
1325
1861
|
SELECT ${ieTable}.\`guid\` AS \`guid\`
|
|
1326
1862
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1327
|
-
WHERE (${whereClause})${limit}${offset}
|
|
1863
|
+
WHERE ${guidClause}(${whereClause})${limit}${offset}
|
|
1328
1864
|
) ${countTable}`;
|
|
1329
1865
|
}
|
|
1330
1866
|
else {
|
|
1331
1867
|
query = `SELECT COUNT(${ieTable}.\`guid\`) AS \`count\`
|
|
1332
1868
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1333
|
-
WHERE (${whereClause})`;
|
|
1869
|
+
WHERE ${guidClause}(${whereClause})`;
|
|
1334
1870
|
}
|
|
1335
1871
|
}
|
|
1336
1872
|
else if (options.return === 'guid') {
|
|
@@ -1339,8 +1875,9 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1339
1875
|
: `${ieTable}.\`guid\``;
|
|
1340
1876
|
query = `SELECT ${guidColumn} AS \`guid\`
|
|
1341
1877
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1342
|
-
|
|
1343
|
-
|
|
1878
|
+
${sortJoinInner}
|
|
1879
|
+
WHERE ${guidClause}(${whereClause})
|
|
1880
|
+
${sortByInner ? sortByInner + ', ' : 'ORDER BY '}${ieTable}.\`guid\`${limit}${offset}`;
|
|
1344
1881
|
}
|
|
1345
1882
|
else {
|
|
1346
1883
|
query = `SELECT
|
|
@@ -1348,20 +1885,30 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1348
1885
|
${eTable}.\`tags\`,
|
|
1349
1886
|
${eTable}.\`cdate\`,
|
|
1350
1887
|
${eTable}.\`mdate\`,
|
|
1888
|
+
LOWER(HEX(${eTable}.\`user\`)) AS \`user\`,
|
|
1889
|
+
LOWER(HEX(${eTable}.\`group\`)) AS \`group\`,
|
|
1890
|
+
${eTable}.\`acUser\`,
|
|
1891
|
+
${eTable}.\`acGroup\`,
|
|
1892
|
+
${eTable}.\`acOther\`,
|
|
1893
|
+
${eTable}.\`acRead\`,
|
|
1894
|
+
${eTable}.\`acWrite\`,
|
|
1895
|
+
${eTable}.\`acFull\`,
|
|
1351
1896
|
${dTable}.\`name\`,
|
|
1352
1897
|
${dTable}.\`value\`,
|
|
1353
|
-
${
|
|
1354
|
-
${
|
|
1898
|
+
${dTable}.\`json\`,
|
|
1899
|
+
${dTable}.\`string\`,
|
|
1900
|
+
${dTable}.\`number\`
|
|
1355
1901
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
|
|
1356
1902
|
LEFT JOIN ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}.\`guid\`=${dTable}.\`guid\`
|
|
1357
|
-
|
|
1903
|
+
${sortJoin}
|
|
1358
1904
|
INNER JOIN (
|
|
1359
1905
|
SELECT ${ieTable}.\`guid\`
|
|
1360
1906
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1361
|
-
|
|
1362
|
-
|
|
1907
|
+
${sortJoinInner}
|
|
1908
|
+
WHERE ${guidClause}(${whereClause})
|
|
1909
|
+
${sortByInner}${limit}${offset}
|
|
1363
1910
|
) ${fTable} ON ${eTable}.\`guid\`=${fTable}.\`guid\`
|
|
1364
|
-
ORDER BY ${eTable}
|
|
1911
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}.\`guid\``;
|
|
1365
1912
|
}
|
|
1366
1913
|
}
|
|
1367
1914
|
}
|
|
@@ -1378,16 +1925,21 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1378
1925
|
if ('offset' in options) {
|
|
1379
1926
|
offset = ` OFFSET ${Math.floor(isNaN(Number(options.offset)) ? 0 : Number(options.offset))}`;
|
|
1380
1927
|
}
|
|
1928
|
+
const guidClause = guidExplicitSelector
|
|
1929
|
+
? ` WHERE ${guidExplicitSelector(`${ieTable}.\`guid\``)}`
|
|
1930
|
+
: guidSelector
|
|
1931
|
+
? ` WHERE ${ieTable}.\`guid\`=${guidSelector}`
|
|
1932
|
+
: '';
|
|
1381
1933
|
if (options.return === 'count') {
|
|
1382
1934
|
if (limit || offset) {
|
|
1383
1935
|
query = `SELECT COUNT(${countTable}.\`guid\`) AS \`count\` FROM (
|
|
1384
1936
|
SELECT ${ieTable}.\`guid\` AS \`guid\`
|
|
1385
|
-
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}${limit}${offset}
|
|
1937
|
+
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}${guidClause}${limit}${offset}
|
|
1386
1938
|
) ${countTable}`;
|
|
1387
1939
|
}
|
|
1388
1940
|
else {
|
|
1389
1941
|
query = `SELECT COUNT(${ieTable}.\`guid\`) AS \`count\`
|
|
1390
|
-
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}`;
|
|
1942
|
+
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}${guidClause}`;
|
|
1391
1943
|
}
|
|
1392
1944
|
}
|
|
1393
1945
|
else if (options.return === 'guid') {
|
|
@@ -1396,7 +1948,9 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1396
1948
|
: `${ieTable}.\`guid\``;
|
|
1397
1949
|
query = `SELECT ${guidColumn} AS \`guid\`
|
|
1398
1950
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1399
|
-
|
|
1951
|
+
${sortJoinInner}
|
|
1952
|
+
${guidClause}
|
|
1953
|
+
${sortByInner ? sortByInner + ', ' : 'ORDER BY '}${ieTable}.\`guid\`${limit}${offset}`;
|
|
1400
1954
|
}
|
|
1401
1955
|
else {
|
|
1402
1956
|
if (limit || offset) {
|
|
@@ -1405,19 +1959,30 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1405
1959
|
${eTable}.\`tags\`,
|
|
1406
1960
|
${eTable}.\`cdate\`,
|
|
1407
1961
|
${eTable}.\`mdate\`,
|
|
1962
|
+
LOWER(HEX(${eTable}.\`user\`)) AS \`user\`,
|
|
1963
|
+
LOWER(HEX(${eTable}.\`group\`)) AS \`group\`,
|
|
1964
|
+
${eTable}.\`acUser\`,
|
|
1965
|
+
${eTable}.\`acGroup\`,
|
|
1966
|
+
${eTable}.\`acOther\`,
|
|
1967
|
+
${eTable}.\`acRead\`,
|
|
1968
|
+
${eTable}.\`acWrite\`,
|
|
1969
|
+
${eTable}.\`acFull\`,
|
|
1408
1970
|
${dTable}.\`name\`,
|
|
1409
1971
|
${dTable}.\`value\`,
|
|
1410
|
-
${
|
|
1411
|
-
${
|
|
1972
|
+
${dTable}.\`json\`,
|
|
1973
|
+
${dTable}.\`string\`,
|
|
1974
|
+
${dTable}.\`number\`
|
|
1412
1975
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
|
|
1413
1976
|
LEFT JOIN ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}.\`guid\`=${dTable}.\`guid\`
|
|
1414
|
-
|
|
1977
|
+
${sortJoin}
|
|
1415
1978
|
INNER JOIN (
|
|
1416
1979
|
SELECT ${ieTable}.\`guid\`
|
|
1417
1980
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1418
|
-
|
|
1981
|
+
${sortJoinInner}
|
|
1982
|
+
${guidClause}
|
|
1983
|
+
${sortByInner}${limit}${offset}
|
|
1419
1984
|
) ${fTable} ON ${eTable}.\`guid\`=${fTable}.\`guid\`
|
|
1420
|
-
ORDER BY ${eTable}
|
|
1985
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}.\`guid\``;
|
|
1421
1986
|
}
|
|
1422
1987
|
else {
|
|
1423
1988
|
query = `SELECT
|
|
@@ -1425,14 +1990,24 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1425
1990
|
${eTable}.\`tags\`,
|
|
1426
1991
|
${eTable}.\`cdate\`,
|
|
1427
1992
|
${eTable}.\`mdate\`,
|
|
1993
|
+
LOWER(HEX(${eTable}.\`user\`)) AS \`user\`,
|
|
1994
|
+
LOWER(HEX(${eTable}.\`group\`)) AS \`group\`,
|
|
1995
|
+
${eTable}.\`acUser\`,
|
|
1996
|
+
${eTable}.\`acGroup\`,
|
|
1997
|
+
${eTable}.\`acOther\`,
|
|
1998
|
+
${eTable}.\`acRead\`,
|
|
1999
|
+
${eTable}.\`acWrite\`,
|
|
2000
|
+
${eTable}.\`acFull\`,
|
|
1428
2001
|
${dTable}.\`name\`,
|
|
1429
2002
|
${dTable}.\`value\`,
|
|
1430
|
-
${
|
|
1431
|
-
${
|
|
2003
|
+
${dTable}.\`json\`,
|
|
2004
|
+
${dTable}.\`string\`,
|
|
2005
|
+
${dTable}.\`number\`
|
|
1432
2006
|
FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
|
|
1433
2007
|
LEFT JOIN ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}.\`guid\`=${dTable}.\`guid\`
|
|
1434
|
-
|
|
1435
|
-
|
|
2008
|
+
${sortJoin}
|
|
2009
|
+
${guidExplicitSelector ? `WHERE ${guidExplicitSelector(`${eTable}.\`guid\``)}` : guidSelector ? `WHERE ${eTable}.\`guid\`=${guidSelector}` : ''}
|
|
2010
|
+
${sortBy ? sortBy + ', ' : 'ORDER BY '}${eTable}.\`guid\``;
|
|
1436
2011
|
}
|
|
1437
2012
|
}
|
|
1438
2013
|
}
|
|
@@ -1448,33 +2023,43 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1448
2023
|
}
|
|
1449
2024
|
performQuery(options, formattedSelectors, etype) {
|
|
1450
2025
|
const { query, params, etypes } = this.makeEntityQuery(options, formattedSelectors, etype);
|
|
1451
|
-
const result = this.
|
|
1452
|
-
return {
|
|
1453
|
-
result,
|
|
1454
|
-
};
|
|
1455
|
-
}
|
|
1456
|
-
performQuerySync(options, formattedSelectors, etype) {
|
|
1457
|
-
const { query, params, etypes } = this.makeEntityQuery(options, formattedSelectors, etype);
|
|
1458
|
-
const result = (this.queryIterSync(query, { etypes, params }) || [])[Symbol.iterator]();
|
|
2026
|
+
const result = this.queryArray(query, { etypes, params }).then((val) => val[Symbol.iterator]());
|
|
1459
2027
|
return {
|
|
1460
2028
|
result,
|
|
1461
2029
|
};
|
|
1462
2030
|
}
|
|
1463
2031
|
async getEntities(options = {}, ...selectors) {
|
|
1464
|
-
const { result: resultPromise, process } = this.
|
|
2032
|
+
const { result: resultPromise, process } = this.getEntitiesRowLike(
|
|
2033
|
+
// @ts-ignore: options is correct here.
|
|
2034
|
+
options, selectors, ({ options, selectors, etype }) => this.performQuery(options, selectors, etype), () => {
|
|
1465
2035
|
const next = result.next();
|
|
1466
2036
|
return next.done ? null : next.value;
|
|
1467
2037
|
}, () => undefined, (row) => Number(row.count), (row) => row.guid, (row) => ({
|
|
1468
|
-
tags: row.tags.length > 2
|
|
1469
|
-
|
|
1470
|
-
|
|
2038
|
+
tags: row.tags.length > 2
|
|
2039
|
+
? row.tags
|
|
2040
|
+
.slice(1, -1)
|
|
2041
|
+
.split(' ')
|
|
2042
|
+
.filter((tag) => tag)
|
|
2043
|
+
: [],
|
|
2044
|
+
cdate: isNaN(Number(row.cdate)) ? Date.now() : Number(row.cdate),
|
|
2045
|
+
mdate: isNaN(Number(row.mdate)) ? Date.now() : Number(row.mdate),
|
|
2046
|
+
user: row.user,
|
|
2047
|
+
group: row.group,
|
|
2048
|
+
acUser: row.acUser,
|
|
2049
|
+
acGroup: row.acGroup,
|
|
2050
|
+
acOther: row.acOther,
|
|
2051
|
+
acRead: row.acRead?.slice(1, -1).split(' ') ?? [],
|
|
2052
|
+
acWrite: row.acWrite?.slice(1, -1).split(' ') ?? [],
|
|
2053
|
+
acFull: row.acFull?.slice(1, -1).split(' ') ?? [],
|
|
1471
2054
|
}), (row) => ({
|
|
1472
2055
|
name: row.name,
|
|
1473
2056
|
svalue: row.value === 'N'
|
|
1474
2057
|
? JSON.stringify(row.number)
|
|
1475
2058
|
: row.value === 'S'
|
|
1476
2059
|
? JSON.stringify(row.string)
|
|
1477
|
-
: row.value
|
|
2060
|
+
: row.value === 'J'
|
|
2061
|
+
? JSON.stringify(row.json)
|
|
2062
|
+
: row.value,
|
|
1478
2063
|
}));
|
|
1479
2064
|
const result = await resultPromise;
|
|
1480
2065
|
const value = process();
|
|
@@ -1483,31 +2068,9 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1483
2068
|
}
|
|
1484
2069
|
return value;
|
|
1485
2070
|
}
|
|
1486
|
-
getEntitiesSync(options = {}, ...selectors) {
|
|
1487
|
-
const { result, process } = this.getEntitesRowLike(options, selectors, (options, formattedSelectors, etype) => this.performQuerySync(options, formattedSelectors, etype), () => {
|
|
1488
|
-
const next = result.next();
|
|
1489
|
-
return next.done ? null : next.value;
|
|
1490
|
-
}, () => undefined, (row) => Number(row.count), (row) => row.guid, (row) => ({
|
|
1491
|
-
tags: row.tags.length > 2 ? row.tags.slice(1, -1).split(',') : [],
|
|
1492
|
-
cdate: isNaN(Number(row.cdate)) ? null : Number(row.cdate),
|
|
1493
|
-
mdate: isNaN(Number(row.mdate)) ? null : Number(row.mdate),
|
|
1494
|
-
}), (row) => ({
|
|
1495
|
-
name: row.name,
|
|
1496
|
-
svalue: row.value === 'N'
|
|
1497
|
-
? JSON.stringify(row.number)
|
|
1498
|
-
: row.value === 'S'
|
|
1499
|
-
? JSON.stringify(row.string)
|
|
1500
|
-
: row.value,
|
|
1501
|
-
}));
|
|
1502
|
-
const value = process();
|
|
1503
|
-
if (value instanceof Error) {
|
|
1504
|
-
throw value;
|
|
1505
|
-
}
|
|
1506
|
-
return value;
|
|
1507
|
-
}
|
|
1508
2071
|
async getUID(name) {
|
|
1509
2072
|
if (name == null) {
|
|
1510
|
-
throw new
|
|
2073
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1511
2074
|
}
|
|
1512
2075
|
const result = await this.queryGet(`SELECT \`cur_uid\` FROM ${MySQLDriver.escape(`${this.prefix}uids`)} WHERE \`name\`=@name;`, {
|
|
1513
2076
|
params: {
|
|
@@ -1516,44 +2079,75 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1516
2079
|
});
|
|
1517
2080
|
return result?.cur_uid ?? null;
|
|
1518
2081
|
}
|
|
1519
|
-
async
|
|
2082
|
+
async importEntity(entity) {
|
|
2083
|
+
return await this.importEntityInternal(entity);
|
|
2084
|
+
}
|
|
2085
|
+
async importEntityTokens(entity) {
|
|
2086
|
+
return await this.importEntityInternal(entity, { only: 'tokens' });
|
|
2087
|
+
}
|
|
2088
|
+
async importEntityTilmeldAC(entity) {
|
|
2089
|
+
return await this.importEntityInternal(entity, { only: 'tilmeldAC' });
|
|
2090
|
+
}
|
|
2091
|
+
async importEntityInternal({ guid, cdate, mdate, tags, sdata, etype, }, { only = undefined } = {}) {
|
|
1520
2092
|
try {
|
|
1521
|
-
|
|
1522
|
-
|
|
2093
|
+
let promises = [];
|
|
2094
|
+
if (only == null) {
|
|
2095
|
+
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
1523
2096
|
etypes: [etype],
|
|
1524
2097
|
params: {
|
|
1525
2098
|
guid,
|
|
1526
|
-
tags: ' ' + tags.join(' ') + ' ',
|
|
1527
|
-
cdate: isNaN(Number(JSON.parse(sdata.cdate)))
|
|
1528
|
-
? null
|
|
1529
|
-
: Number(JSON.parse(sdata.cdate)),
|
|
1530
|
-
mdate: isNaN(Number(JSON.parse(sdata.mdate)))
|
|
1531
|
-
? null
|
|
1532
|
-
: Number(JSON.parse(sdata.mdate)),
|
|
1533
2099
|
},
|
|
1534
|
-
});
|
|
1535
|
-
const promises = [];
|
|
2100
|
+
}));
|
|
1536
2101
|
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
1537
2102
|
etypes: [etype],
|
|
1538
2103
|
params: {
|
|
1539
2104
|
guid,
|
|
1540
2105
|
},
|
|
1541
2106
|
}));
|
|
1542
|
-
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}
|
|
2107
|
+
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
1543
2108
|
etypes: [etype],
|
|
1544
2109
|
params: {
|
|
1545
2110
|
guid,
|
|
1546
2111
|
},
|
|
1547
2112
|
}));
|
|
1548
|
-
|
|
2113
|
+
}
|
|
2114
|
+
if (only == null || only === 'tokens') {
|
|
2115
|
+
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
1549
2116
|
etypes: [etype],
|
|
1550
2117
|
params: {
|
|
1551
2118
|
guid,
|
|
1552
2119
|
},
|
|
1553
2120
|
}));
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
2121
|
+
}
|
|
2122
|
+
if (only == null) {
|
|
2123
|
+
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}uniques_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
2124
|
+
etypes: [etype],
|
|
2125
|
+
params: {
|
|
2126
|
+
guid,
|
|
2127
|
+
},
|
|
2128
|
+
}));
|
|
2129
|
+
}
|
|
2130
|
+
await Promise.all(promises);
|
|
2131
|
+
promises = [];
|
|
2132
|
+
if (only == null) {
|
|
2133
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull } = this.removeAndReturnACValues(etype, {}, sdata);
|
|
2134
|
+
await this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`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);`, {
|
|
2135
|
+
etypes: [etype],
|
|
2136
|
+
params: {
|
|
2137
|
+
guid,
|
|
2138
|
+
tags: ' ' + tags.join(' ') + ' ',
|
|
2139
|
+
cdate: isNaN(cdate) ? null : cdate,
|
|
2140
|
+
mdate: isNaN(mdate) ? null : mdate,
|
|
2141
|
+
user,
|
|
2142
|
+
group,
|
|
2143
|
+
acUser,
|
|
2144
|
+
acGroup,
|
|
2145
|
+
acOther,
|
|
2146
|
+
acRead: acRead && ' ' + acRead.join(' ') + ' ',
|
|
2147
|
+
acWrite: acWrite && ' ' + acWrite.join(' ') + ' ',
|
|
2148
|
+
acFull: acFull && ' ' + acFull.join(' ') + ' ',
|
|
2149
|
+
},
|
|
2150
|
+
});
|
|
1557
2151
|
for (const name in sdata) {
|
|
1558
2152
|
const value = sdata[name];
|
|
1559
2153
|
const uvalue = JSON.parse(value);
|
|
@@ -1564,24 +2158,18 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1564
2158
|
? 'N'
|
|
1565
2159
|
: typeof uvalue === 'string'
|
|
1566
2160
|
? 'S'
|
|
1567
|
-
:
|
|
1568
|
-
const
|
|
1569
|
-
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (\`guid\`, \`name\`, \`value\`) VALUES (UNHEX(@guid), @name, @storageValue);`, {
|
|
2161
|
+
: 'J';
|
|
2162
|
+
const jsonValue = storageValue === 'J' ? value : null;
|
|
2163
|
+
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (\`guid\`, \`name\`, \`value\`, \`json\`, \`string\`, \`number\`, \`truthy\`) VALUES (UNHEX(@guid), @name, @storageValue, @jsonValue, @string, @number, @truthy);`, {
|
|
1570
2164
|
etypes: [etype],
|
|
1571
2165
|
params: {
|
|
1572
2166
|
guid,
|
|
1573
2167
|
name,
|
|
1574
2168
|
storageValue,
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}comparisons_${etype}`)} (\`guid\`, \`name\`, \`truthy\`, \`string\`, \`number\`) VALUES (UNHEX(@guid), @name, @truthy, @string, @number);`, {
|
|
1578
|
-
etypes: [etype],
|
|
1579
|
-
params: {
|
|
1580
|
-
guid,
|
|
1581
|
-
name,
|
|
1582
|
-
truthy: !!uvalue,
|
|
1583
|
-
string: `${uvalue}`,
|
|
2169
|
+
jsonValue,
|
|
2170
|
+
string: storageValue === 'J' ? null : `${uvalue}`,
|
|
1584
2171
|
number: isNaN(Number(uvalue)) ? null : Number(uvalue),
|
|
2172
|
+
truthy: !!uvalue,
|
|
1585
2173
|
},
|
|
1586
2174
|
}));
|
|
1587
2175
|
const references = this.findReferences(value);
|
|
@@ -1596,37 +2184,123 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1596
2184
|
}));
|
|
1597
2185
|
}
|
|
1598
2186
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
2187
|
+
}
|
|
2188
|
+
if (only === 'tilmeldAC') {
|
|
2189
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull } = this.removeAndReturnACValues(etype, {}, sdata);
|
|
2190
|
+
promises.push(this.queryRun(`UPDATE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} 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);`, {
|
|
2191
|
+
etypes: [etype],
|
|
1602
2192
|
params: {
|
|
1603
|
-
|
|
1604
|
-
|
|
2193
|
+
user,
|
|
2194
|
+
group,
|
|
2195
|
+
acUser,
|
|
2196
|
+
acGroup,
|
|
2197
|
+
acOther,
|
|
2198
|
+
acRead: acRead && ' ' + acRead.join(' ') + ' ',
|
|
2199
|
+
acWrite: acWrite && ' ' + acWrite.join(' ') + ' ',
|
|
2200
|
+
acFull: acFull && ' ' + acFull.join(' ') + ' ',
|
|
2201
|
+
guid,
|
|
1605
2202
|
},
|
|
2203
|
+
}));
|
|
2204
|
+
}
|
|
2205
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
2206
|
+
if (only == null || only === 'tokens') {
|
|
2207
|
+
for (let name in sdata) {
|
|
2208
|
+
let tokenString = null;
|
|
2209
|
+
try {
|
|
2210
|
+
tokenString = EntityClass.getFTSText(name, JSON.parse(sdata[name]));
|
|
2211
|
+
}
|
|
2212
|
+
catch (e) {
|
|
2213
|
+
// Ignore error.
|
|
2214
|
+
}
|
|
2215
|
+
if (tokenString != null) {
|
|
2216
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
2217
|
+
while (tokens.length) {
|
|
2218
|
+
const currentTokens = tokens.splice(0, 100);
|
|
2219
|
+
const params = {
|
|
2220
|
+
guid,
|
|
2221
|
+
name,
|
|
2222
|
+
};
|
|
2223
|
+
const values = [];
|
|
2224
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
2225
|
+
const token = currentTokens[i];
|
|
2226
|
+
params['token' + i] = token.token;
|
|
2227
|
+
params['position' + i] = token.position;
|
|
2228
|
+
params['stem' + i] = token.stem;
|
|
2229
|
+
values.push('(UNHEX(@guid), @name, @token' +
|
|
2230
|
+
i +
|
|
2231
|
+
', @position' +
|
|
2232
|
+
i +
|
|
2233
|
+
', @stem' +
|
|
2234
|
+
i +
|
|
2235
|
+
')');
|
|
2236
|
+
}
|
|
2237
|
+
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} (\`guid\`, \`name\`, \`token\`, \`position\`, \`stem\`) VALUES ${values.join(', ')};`, {
|
|
2238
|
+
etypes: [etype],
|
|
2239
|
+
params,
|
|
2240
|
+
}));
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
if (only == null) {
|
|
2246
|
+
const uniques = await EntityClass.getUniques({
|
|
2247
|
+
guid,
|
|
2248
|
+
cdate,
|
|
2249
|
+
mdate,
|
|
2250
|
+
tags,
|
|
2251
|
+
data: {},
|
|
2252
|
+
sdata,
|
|
1606
2253
|
});
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
2254
|
+
for (const unique of uniques) {
|
|
2255
|
+
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}uniques_${etype}`)} (\`guid\`, \`unique\`) VALUES (UNHEX(@guid), @unique);`, {
|
|
2256
|
+
etypes: [etype],
|
|
2257
|
+
params: {
|
|
2258
|
+
guid,
|
|
2259
|
+
unique,
|
|
2260
|
+
},
|
|
2261
|
+
}).catch((e) => {
|
|
2262
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2263
|
+
this.nymph.config.debugError('mysql', `Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
|
|
2264
|
+
}
|
|
2265
|
+
return e;
|
|
2266
|
+
}));
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
await Promise.all(promises);
|
|
2270
|
+
}
|
|
2271
|
+
catch (e) {
|
|
2272
|
+
this.nymph.config.debugError('mysql', `Import entity error: "${e}"`);
|
|
2273
|
+
throw e;
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
async importUID({ name, value }) {
|
|
2277
|
+
try {
|
|
2278
|
+
await this.internalTransaction(`nymph-import-uid-${name}`);
|
|
2279
|
+
await this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}uids`)} (\`name\`, \`cur_uid\`) VALUES (@name, @value) ON DUPLICATE KEY UPDATE \`cur_uid\`=@value;`, {
|
|
2280
|
+
params: {
|
|
2281
|
+
name,
|
|
2282
|
+
value,
|
|
2283
|
+
},
|
|
1611
2284
|
});
|
|
1612
|
-
|
|
2285
|
+
await this.commit(`nymph-import-uid-${name}`);
|
|
1613
2286
|
}
|
|
1614
2287
|
catch (e) {
|
|
1615
|
-
|
|
1616
|
-
|
|
2288
|
+
this.nymph.config.debugError('mysql', `Import UID error: "${e}"`);
|
|
2289
|
+
await this.rollback(`nymph-import-uid-${name}`);
|
|
2290
|
+
throw e;
|
|
1617
2291
|
}
|
|
1618
2292
|
}
|
|
1619
2293
|
async newUID(name) {
|
|
1620
2294
|
if (name == null) {
|
|
1621
|
-
throw new
|
|
2295
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1622
2296
|
}
|
|
1623
2297
|
await this.internalTransaction('nymph-newuid');
|
|
2298
|
+
let curUid = null;
|
|
1624
2299
|
try {
|
|
1625
2300
|
const lock = await this.queryGet(`SELECT GET_LOCK(${MySQLDriver.escapeValue(`${this.prefix}uids_${name}`)}, 10) AS \`lock\`;`);
|
|
1626
2301
|
if (lock.lock !== 1) {
|
|
1627
|
-
throw new
|
|
2302
|
+
throw new QueryFailedError("Couldn't get lock for UID: " + name);
|
|
1628
2303
|
}
|
|
1629
|
-
let curUid = null;
|
|
1630
2304
|
await this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}uids`)} (\`name\`, \`cur_uid\`) VALUES (@name, 1) ON DUPLICATE KEY UPDATE \`cur_uid\`=\`cur_uid\`+1;`, {
|
|
1631
2305
|
params: {
|
|
1632
2306
|
name,
|
|
@@ -1638,21 +2312,22 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1638
2312
|
},
|
|
1639
2313
|
});
|
|
1640
2314
|
await this.queryRun(`SELECT RELEASE_LOCK(${MySQLDriver.escapeValue(`${this.prefix}uids_${name}`)});`);
|
|
1641
|
-
await this.commit('nymph-newuid');
|
|
1642
2315
|
curUid = result.cur_uid ?? null;
|
|
1643
|
-
return curUid;
|
|
1644
2316
|
}
|
|
1645
2317
|
catch (e) {
|
|
2318
|
+
this.nymph.config.debugError('mysql', `New UID error: "${e}"`);
|
|
1646
2319
|
if (e?.message !== "Couldn't get lock for UID: " + name) {
|
|
1647
2320
|
await this.queryRun(`SELECT RELEASE_LOCK(${MySQLDriver.escapeValue(`${this.prefix}uids_${name}`)});`);
|
|
1648
2321
|
}
|
|
1649
2322
|
await this.rollback('nymph-newuid');
|
|
1650
2323
|
throw e;
|
|
1651
2324
|
}
|
|
2325
|
+
await this.commit('nymph-newuid');
|
|
2326
|
+
return curUid;
|
|
1652
2327
|
}
|
|
1653
2328
|
async renameUID(oldName, newName) {
|
|
1654
2329
|
if (oldName == null || newName == null) {
|
|
1655
|
-
throw new
|
|
2330
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1656
2331
|
}
|
|
1657
2332
|
await this.queryRun(`UPDATE ${MySQLDriver.escape(`${this.prefix}uids`)} SET \`name\`=@newName WHERE \`name\`=@oldName;`, {
|
|
1658
2333
|
params: {
|
|
@@ -1664,7 +2339,7 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1664
2339
|
}
|
|
1665
2340
|
async rollback(name) {
|
|
1666
2341
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1667
|
-
throw new
|
|
2342
|
+
throw new InvalidParametersError('Transaction rollback attempted without a name.');
|
|
1668
2343
|
}
|
|
1669
2344
|
if (!this.transaction || this.transaction.count === 0) {
|
|
1670
2345
|
this.transaction = null;
|
|
@@ -1683,7 +2358,8 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1683
2358
|
return true;
|
|
1684
2359
|
}
|
|
1685
2360
|
async saveEntity(entity) {
|
|
1686
|
-
const insertData = async (guid, data, sdata, etype) => {
|
|
2361
|
+
const insertData = async (guid, data, sdata, uniques, etype) => {
|
|
2362
|
+
const EntityClass = this.nymph.getEntityClassByEtype(etype);
|
|
1687
2363
|
const runInsertQuery = async (name, value, svalue) => {
|
|
1688
2364
|
if (value === undefined) {
|
|
1689
2365
|
return;
|
|
@@ -1692,24 +2368,19 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1692
2368
|
? 'N'
|
|
1693
2369
|
: typeof value === 'string'
|
|
1694
2370
|
? 'S'
|
|
1695
|
-
:
|
|
2371
|
+
: 'J';
|
|
2372
|
+
const jsonValue = storageValue === 'J' ? svalue : null;
|
|
1696
2373
|
const promises = [];
|
|
1697
|
-
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (\`guid\`, \`name\`, \`value\`) VALUES (UNHEX(@guid), @name, @storageValue);`, {
|
|
2374
|
+
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} (\`guid\`, \`name\`, \`value\`, \`json\`, \`string\`, \`number\`, \`truthy\`) VALUES (UNHEX(@guid), @name, @storageValue, @jsonValue, @string, @number, @truthy);`, {
|
|
1698
2375
|
etypes: [etype],
|
|
1699
2376
|
params: {
|
|
1700
2377
|
guid,
|
|
1701
2378
|
name,
|
|
1702
2379
|
storageValue,
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}comparisons_${etype}`)} (\`guid\`, \`name\`, \`truthy\`, \`string\`, \`number\`) VALUES (UNHEX(@guid), @name, @truthy, @string, @number);`, {
|
|
1706
|
-
etypes: [etype],
|
|
1707
|
-
params: {
|
|
1708
|
-
guid,
|
|
1709
|
-
name,
|
|
1710
|
-
truthy: !!value,
|
|
1711
|
-
string: `${value}`,
|
|
2380
|
+
jsonValue,
|
|
2381
|
+
string: storageValue === 'J' ? null : `${value}`,
|
|
1712
2382
|
number: isNaN(Number(value)) ? null : Number(value),
|
|
2383
|
+
truthy: !!value,
|
|
1713
2384
|
},
|
|
1714
2385
|
}));
|
|
1715
2386
|
const references = this.findReferences(svalue);
|
|
@@ -1723,8 +2394,60 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1723
2394
|
},
|
|
1724
2395
|
}));
|
|
1725
2396
|
}
|
|
2397
|
+
let tokenString = null;
|
|
2398
|
+
try {
|
|
2399
|
+
tokenString = EntityClass.getFTSText(name, value);
|
|
2400
|
+
}
|
|
2401
|
+
catch (e) {
|
|
2402
|
+
// Ignore error.
|
|
2403
|
+
}
|
|
2404
|
+
if (tokenString != null) {
|
|
2405
|
+
const tokens = this.tokenizer.tokenize(tokenString);
|
|
2406
|
+
while (tokens.length) {
|
|
2407
|
+
const currentTokens = tokens.splice(0, 100);
|
|
2408
|
+
const params = {
|
|
2409
|
+
guid,
|
|
2410
|
+
name,
|
|
2411
|
+
};
|
|
2412
|
+
const values = [];
|
|
2413
|
+
for (let i = 0; i < currentTokens.length; i++) {
|
|
2414
|
+
const token = currentTokens[i];
|
|
2415
|
+
params['token' + i] = token.token;
|
|
2416
|
+
params['position' + i] = token.position;
|
|
2417
|
+
params['stem' + i] = token.stem;
|
|
2418
|
+
values.push('(UNHEX(@guid), @name, @token' +
|
|
2419
|
+
i +
|
|
2420
|
+
', @position' +
|
|
2421
|
+
i +
|
|
2422
|
+
', @stem' +
|
|
2423
|
+
i +
|
|
2424
|
+
')');
|
|
2425
|
+
}
|
|
2426
|
+
promises.push(this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} (\`guid\`, \`name\`, \`token\`, \`position\`, \`stem\`) VALUES ${values.join(', ')};`, {
|
|
2427
|
+
etypes: [etype],
|
|
2428
|
+
params,
|
|
2429
|
+
}));
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
1726
2432
|
await Promise.all(promises);
|
|
1727
2433
|
};
|
|
2434
|
+
for (const unique of uniques) {
|
|
2435
|
+
try {
|
|
2436
|
+
await this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}uniques_${etype}`)} (\`guid\`, \`unique\`) VALUES (UNHEX(@guid), @unique);`, {
|
|
2437
|
+
etypes: [etype],
|
|
2438
|
+
params: {
|
|
2439
|
+
guid,
|
|
2440
|
+
unique,
|
|
2441
|
+
},
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
catch (e) {
|
|
2445
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
2446
|
+
this.nymph.config.debugError('mysql', `Save entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
|
|
2447
|
+
}
|
|
2448
|
+
throw e;
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
1728
2451
|
for (const name in data) {
|
|
1729
2452
|
await runInsertQuery(name, data[name], JSON.stringify(data[name]));
|
|
1730
2453
|
}
|
|
@@ -1732,19 +2455,42 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1732
2455
|
await runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
|
|
1733
2456
|
}
|
|
1734
2457
|
};
|
|
2458
|
+
let inTransaction = false;
|
|
1735
2459
|
try {
|
|
1736
|
-
const result = await this.saveEntityRowLike(entity, async (
|
|
1737
|
-
|
|
2460
|
+
const result = await this.saveEntityRowLike(entity, async ({ guid, tags, data, sdata, uniques, cdate, etype }) => {
|
|
2461
|
+
if (Object.keys(data).length === 0 &&
|
|
2462
|
+
Object.keys(sdata).length === 0) {
|
|
2463
|
+
throw new EntityInvalidDataError('Entity contains no data.');
|
|
2464
|
+
}
|
|
2465
|
+
let processedData = this.removeAndReturnACValues(etype, { ...data }, { ...sdata });
|
|
2466
|
+
({ data, sdata } = processedData);
|
|
2467
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull, } = processedData;
|
|
2468
|
+
await this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} (\`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);`, {
|
|
1738
2469
|
etypes: [etype],
|
|
1739
2470
|
params: {
|
|
1740
2471
|
guid,
|
|
1741
2472
|
tags: ' ' + tags.join(' ') + ' ',
|
|
1742
2473
|
cdate,
|
|
2474
|
+
user,
|
|
2475
|
+
group,
|
|
2476
|
+
acUser,
|
|
2477
|
+
acGroup,
|
|
2478
|
+
acOther,
|
|
2479
|
+
acRead: acRead && ' ' + acRead.join(' ') + ' ',
|
|
2480
|
+
acWrite: acWrite && ' ' + acWrite.join(' ') + ' ',
|
|
2481
|
+
acFull: acFull && ' ' + acFull.join(' ') + ' ',
|
|
1743
2482
|
},
|
|
1744
2483
|
});
|
|
1745
|
-
await insertData(guid, data, sdata, etype);
|
|
2484
|
+
await insertData(guid, data, sdata, uniques, etype);
|
|
1746
2485
|
return true;
|
|
1747
|
-
}, async (entity, guid, tags, data, sdata, mdate, etype) => {
|
|
2486
|
+
}, async ({ entity, guid, tags, data, sdata, uniques, mdate, etype }) => {
|
|
2487
|
+
if (Object.keys(data).length === 0 &&
|
|
2488
|
+
Object.keys(sdata).length === 0) {
|
|
2489
|
+
throw new EntityInvalidDataError('Entity contains no data.');
|
|
2490
|
+
}
|
|
2491
|
+
let processedData = this.removeAndReturnACValues(etype, { ...data }, { ...sdata });
|
|
2492
|
+
({ data, sdata } = processedData);
|
|
2493
|
+
let { user, group, acUser, acGroup, acOther, acRead, acWrite, acFull, } = processedData;
|
|
1748
2494
|
if (this.config.rowLocking) {
|
|
1749
2495
|
const promises = [];
|
|
1750
2496
|
promises.push(this.queryRun(`SELECT 1 FROM ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`, {
|
|
@@ -1759,13 +2505,19 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1759
2505
|
guid,
|
|
1760
2506
|
},
|
|
1761
2507
|
}));
|
|
1762
|
-
promises.push(this.queryRun(`SELECT 1 FROM ${MySQLDriver.escape(`${this.prefix}
|
|
2508
|
+
promises.push(this.queryRun(`SELECT 1 FROM ${MySQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`, {
|
|
1763
2509
|
etypes: [etype],
|
|
1764
2510
|
params: {
|
|
1765
2511
|
guid,
|
|
1766
2512
|
},
|
|
1767
2513
|
}));
|
|
1768
|
-
promises.push(this.queryRun(`SELECT 1 FROM ${MySQLDriver.escape(`${this.prefix}
|
|
2514
|
+
promises.push(this.queryRun(`SELECT 1 FROM ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`, {
|
|
2515
|
+
etypes: [etype],
|
|
2516
|
+
params: {
|
|
2517
|
+
guid,
|
|
2518
|
+
},
|
|
2519
|
+
}));
|
|
2520
|
+
promises.push(this.queryRun(`SELECT 1 FROM ${MySQLDriver.escape(`${this.prefix}uniques_${etype}`)} WHERE \`guid\`=UNHEX(@guid) GROUP BY 1 FOR UPDATE;`, {
|
|
1769
2521
|
etypes: [etype],
|
|
1770
2522
|
params: {
|
|
1771
2523
|
guid,
|
|
@@ -1774,13 +2526,21 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1774
2526
|
await Promise.all(promises);
|
|
1775
2527
|
}
|
|
1776
2528
|
if (this.config.tableLocking) {
|
|
1777
|
-
await this.queryRun(`LOCK TABLES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} WRITE, ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} WRITE, ${MySQLDriver.escape(`${this.prefix}
|
|
2529
|
+
await this.queryRun(`LOCK TABLES ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} WRITE, ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} WRITE, ${MySQLDriver.escape(`${this.prefix}references_${etype}`)} WRITE, ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} WRITE, ${MySQLDriver.escape(`${this.prefix}uniques_${etype}`)} WRITE;`);
|
|
1778
2530
|
}
|
|
1779
|
-
const info = await this.queryRun(`UPDATE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} SET \`tags\`=@tags, \`mdate\`=@mdate WHERE \`guid\`=UNHEX(@guid) AND \`mdate\` <= @emdate;`, {
|
|
2531
|
+
const info = await this.queryRun(`UPDATE ${MySQLDriver.escape(`${this.prefix}entities_${etype}`)} 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;`, {
|
|
1780
2532
|
etypes: [etype],
|
|
1781
2533
|
params: {
|
|
1782
2534
|
tags: ' ' + tags.join(' ') + ' ',
|
|
1783
2535
|
mdate,
|
|
2536
|
+
user,
|
|
2537
|
+
group,
|
|
2538
|
+
acUser,
|
|
2539
|
+
acGroup,
|
|
2540
|
+
acOther,
|
|
2541
|
+
acRead: acRead && ' ' + acRead.join(' ') + ' ',
|
|
2542
|
+
acWrite: acWrite && ' ' + acWrite.join(' ') + ' ',
|
|
2543
|
+
acFull: acFull && ' ' + acFull.join(' ') + ' ',
|
|
1784
2544
|
guid,
|
|
1785
2545
|
emdate: isNaN(Number(entity.mdate)) ? 0 : Number(entity.mdate),
|
|
1786
2546
|
},
|
|
@@ -1794,47 +2554,63 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1794
2554
|
guid,
|
|
1795
2555
|
},
|
|
1796
2556
|
}));
|
|
1797
|
-
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}
|
|
2557
|
+
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
1798
2558
|
etypes: [etype],
|
|
1799
2559
|
params: {
|
|
1800
2560
|
guid,
|
|
1801
2561
|
},
|
|
1802
2562
|
}));
|
|
1803
|
-
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}
|
|
2563
|
+
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
2564
|
+
etypes: [etype],
|
|
2565
|
+
params: {
|
|
2566
|
+
guid,
|
|
2567
|
+
},
|
|
2568
|
+
}));
|
|
2569
|
+
promises.push(this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}uniques_${etype}`)} WHERE \`guid\`=UNHEX(@guid);`, {
|
|
1804
2570
|
etypes: [etype],
|
|
1805
2571
|
params: {
|
|
1806
2572
|
guid,
|
|
1807
2573
|
},
|
|
1808
2574
|
}));
|
|
1809
2575
|
await Promise.all(promises);
|
|
1810
|
-
await insertData(guid, data, sdata, etype);
|
|
2576
|
+
await insertData(guid, data, sdata, uniques, etype);
|
|
1811
2577
|
success = true;
|
|
1812
2578
|
}
|
|
1813
2579
|
if (this.config.tableLocking) {
|
|
1814
2580
|
await this.queryRun('UNLOCK TABLES;');
|
|
1815
2581
|
}
|
|
2582
|
+
if (!success && info.changes === 0) {
|
|
2583
|
+
throw new EntityConflictError("Entity either doesn't exist or is newer in the DB.");
|
|
2584
|
+
}
|
|
1816
2585
|
return success;
|
|
1817
2586
|
}, async () => {
|
|
1818
2587
|
await this.internalTransaction('nymph-save');
|
|
2588
|
+
inTransaction = true;
|
|
1819
2589
|
}, async (success) => {
|
|
1820
|
-
if (
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
2590
|
+
if (inTransaction) {
|
|
2591
|
+
inTransaction = false;
|
|
2592
|
+
if (success) {
|
|
2593
|
+
success = await this.commit('nymph-save');
|
|
2594
|
+
}
|
|
2595
|
+
else {
|
|
2596
|
+
await this.rollback('nymph-save');
|
|
2597
|
+
}
|
|
1825
2598
|
}
|
|
1826
2599
|
return success;
|
|
1827
2600
|
});
|
|
1828
2601
|
return result;
|
|
1829
2602
|
}
|
|
1830
2603
|
catch (e) {
|
|
1831
|
-
|
|
2604
|
+
this.nymph.config.debugError('mysql', `Save entity error: "${e}"`);
|
|
2605
|
+
if (inTransaction) {
|
|
2606
|
+
await this.rollback('nymph-save');
|
|
2607
|
+
}
|
|
1832
2608
|
throw e;
|
|
1833
2609
|
}
|
|
1834
2610
|
}
|
|
1835
2611
|
async setUID(name, curUid) {
|
|
1836
2612
|
if (name == null) {
|
|
1837
|
-
throw new
|
|
2613
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1838
2614
|
}
|
|
1839
2615
|
await this.queryRun(`INSERT INTO ${MySQLDriver.escape(`${this.prefix}uids`)} (\`name\`, \`cur_uid\`) VALUES (@name, @curUid) ON DUPLICATE KEY UPDATE \`cur_uid\`=@curUid;`, {
|
|
1840
2616
|
params: {
|
|
@@ -1844,35 +2620,146 @@ class MySQLDriver extends nymph_1.NymphDriver {
|
|
|
1844
2620
|
});
|
|
1845
2621
|
return true;
|
|
1846
2622
|
}
|
|
1847
|
-
async internalTransaction(name) {
|
|
2623
|
+
async internalTransaction(name, setOnSelf = true) {
|
|
1848
2624
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1849
|
-
throw new
|
|
2625
|
+
throw new InvalidParametersError('Transaction start attempted without a name.');
|
|
1850
2626
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
2627
|
+
let transaction = this.transaction;
|
|
2628
|
+
if (!transaction) {
|
|
2629
|
+
// Lock to one connection.
|
|
2630
|
+
transaction = {
|
|
1853
2631
|
count: 0,
|
|
1854
2632
|
connection: await this.getConnection(),
|
|
2633
|
+
latestPromise: Promise.resolve(),
|
|
1855
2634
|
};
|
|
1856
|
-
if (
|
|
1857
|
-
|
|
2635
|
+
if (setOnSelf) {
|
|
2636
|
+
this.transaction = transaction;
|
|
1858
2637
|
}
|
|
1859
2638
|
}
|
|
2639
|
+
if (this.config.transactions && transaction.count === 0) {
|
|
2640
|
+
// We're not in a transaction yet, so start one.
|
|
2641
|
+
await this.queryRun('START TRANSACTION;', { transaction });
|
|
2642
|
+
}
|
|
2643
|
+
transaction.count++;
|
|
1860
2644
|
if (this.config.transactions) {
|
|
1861
|
-
await this.queryRun(`SAVEPOINT ${MySQLDriver.escape(name)}
|
|
2645
|
+
await this.queryRun(`SAVEPOINT ${MySQLDriver.escape(name)};`, {
|
|
2646
|
+
transaction,
|
|
2647
|
+
});
|
|
1862
2648
|
}
|
|
1863
|
-
|
|
1864
|
-
return this.transaction;
|
|
2649
|
+
return transaction;
|
|
1865
2650
|
}
|
|
1866
2651
|
async startTransaction(name) {
|
|
1867
|
-
const
|
|
1868
|
-
const transaction = await this.internalTransaction(name);
|
|
1869
|
-
if (!inTransaction) {
|
|
1870
|
-
this.transaction = null;
|
|
1871
|
-
}
|
|
2652
|
+
const transaction = await this.internalTransaction(name, false);
|
|
1872
2653
|
const nymph = this.nymph.clone();
|
|
1873
2654
|
nymph.driver.transaction = transaction;
|
|
1874
2655
|
return nymph;
|
|
1875
2656
|
}
|
|
2657
|
+
async removeTilmeldOldRows(etype) {
|
|
2658
|
+
await this.internalTransaction('nymph-remove-tilmeld-rows');
|
|
2659
|
+
try {
|
|
2660
|
+
for (let name of [
|
|
2661
|
+
'user',
|
|
2662
|
+
'group',
|
|
2663
|
+
'acUser',
|
|
2664
|
+
'acGroup',
|
|
2665
|
+
'acOther',
|
|
2666
|
+
'acRead',
|
|
2667
|
+
'acWrite',
|
|
2668
|
+
'acFull',
|
|
2669
|
+
]) {
|
|
2670
|
+
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}data_${etype}`)} WHERE \`name\`=@name;`, {
|
|
2671
|
+
etypes: [etype],
|
|
2672
|
+
params: {
|
|
2673
|
+
name,
|
|
2674
|
+
},
|
|
2675
|
+
});
|
|
2676
|
+
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE \`name\`=@name;`, {
|
|
2677
|
+
etypes: [etype],
|
|
2678
|
+
params: {
|
|
2679
|
+
name,
|
|
2680
|
+
},
|
|
2681
|
+
});
|
|
2682
|
+
await this.queryRun(`DELETE FROM ${MySQLDriver.escape(`${this.prefix}tokens_${etype}`)} WHERE \`name\`=@name;`, {
|
|
2683
|
+
etypes: [etype],
|
|
2684
|
+
params: {
|
|
2685
|
+
name,
|
|
2686
|
+
},
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
catch (e) {
|
|
2691
|
+
this.nymph.config.debugError('mysql', `Remove tilmeld rows error: "${e}"`);
|
|
2692
|
+
await this.rollback('nymph-remove-tilmeld-rows');
|
|
2693
|
+
throw e;
|
|
2694
|
+
}
|
|
2695
|
+
await this.commit('nymph-remove-tilmeld-rows');
|
|
2696
|
+
return true;
|
|
2697
|
+
}
|
|
2698
|
+
async needsMigration() {
|
|
2699
|
+
const table = await this.queryGet('SELECT `table_name` AS `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=@db AND `table_name` LIKE @prefix LIMIT 1;', {
|
|
2700
|
+
params: {
|
|
2701
|
+
db: this.config.database,
|
|
2702
|
+
prefix: this.prefix + 'data_' + '%',
|
|
2703
|
+
},
|
|
2704
|
+
});
|
|
2705
|
+
if (table?.table_name) {
|
|
2706
|
+
const result = await this.queryGet("SELECT 1 AS `exists` FROM `information_schema`.`columns` WHERE `table_schema`=@db AND `table_name`=@table AND `column_name`='json';", {
|
|
2707
|
+
params: {
|
|
2708
|
+
db: this.config.database,
|
|
2709
|
+
table: table.table_name,
|
|
2710
|
+
},
|
|
2711
|
+
});
|
|
2712
|
+
if (!result?.exists) {
|
|
2713
|
+
return 'json';
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
const table2 = await this.queryGet('SELECT `table_name` AS `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=@db AND `table_name` LIKE @tokenTable LIMIT 1;', {
|
|
2717
|
+
params: {
|
|
2718
|
+
db: this.config.database,
|
|
2719
|
+
tokenTable: this.prefix + 'tokens_' + '%',
|
|
2720
|
+
},
|
|
2721
|
+
});
|
|
2722
|
+
if (!table2 || !table2.table_name) {
|
|
2723
|
+
return 'tokens';
|
|
2724
|
+
}
|
|
2725
|
+
const table3 = await this.queryGet('SELECT `table_name` AS `table_name` FROM `information_schema`.`tables` WHERE `table_schema`=@db AND `table_name` LIKE @prefix LIMIT 1;', {
|
|
2726
|
+
params: {
|
|
2727
|
+
db: this.config.database,
|
|
2728
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
2729
|
+
},
|
|
2730
|
+
});
|
|
2731
|
+
if (table3?.table_name) {
|
|
2732
|
+
const result = await this.queryGet("SELECT 1 AS `exists` FROM `information_schema`.`columns` WHERE `table_schema`=@db AND `table_name`=@table AND `column_name`='user';", {
|
|
2733
|
+
params: {
|
|
2734
|
+
db: this.config.database,
|
|
2735
|
+
table: table3.table_name,
|
|
2736
|
+
},
|
|
2737
|
+
});
|
|
2738
|
+
if (!result?.exists) {
|
|
2739
|
+
return 'tilmeldColumns';
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
return false;
|
|
2743
|
+
}
|
|
2744
|
+
async liveMigration(migrationType) {
|
|
2745
|
+
if (migrationType === 'tokenTables') {
|
|
2746
|
+
const etypes = await this.getEtypes();
|
|
2747
|
+
for (let etype of etypes) {
|
|
2748
|
+
await this.createTokensTable(etype);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
else if (migrationType === 'tilmeldColumns') {
|
|
2752
|
+
const etypes = await this.getEtypes();
|
|
2753
|
+
for (let etype of etypes) {
|
|
2754
|
+
await this.addTilmeldColumnsAndIndexes(etype);
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
else if (migrationType === 'tilmeldRemoveOldRows') {
|
|
2758
|
+
const etypes = await this.getEtypes();
|
|
2759
|
+
for (let etype of etypes) {
|
|
2760
|
+
await this.removeTilmeldOldRows(etype);
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
1876
2764
|
}
|
|
1877
|
-
exports.default = MySQLDriver;
|
|
1878
2765
|
//# sourceMappingURL=MySQLDriver.js.map
|