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