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