@nymphjs/driver-postgresql 1.0.0-alpha.2

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.
@@ -0,0 +1,1876 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const child_process_1 = __importDefault(require("child_process"));
16
+ const pg_1 = require("pg");
17
+ const pg_format_1 = __importDefault(require("pg-format"));
18
+ const nanoid_1 = require("nanoid");
19
+ const nymph_1 = require("@nymphjs/nymph");
20
+ const conf_1 = require("./conf");
21
+ const makeTableSuffix = (0, nanoid_1.customAlphabet)('0123456789abcdefghijklmnopqrstuvwxyz', 20);
22
+ class PostgreSQLDriver extends nymph_1.NymphDriver {
23
+ constructor(config, link, transaction) {
24
+ super();
25
+ this.connected = false;
26
+ this.transaction = null;
27
+ this.config = Object.assign(Object.assign({}, conf_1.PostgreSQLDriverConfigDefaults), config);
28
+ const { host, user, password, database, port, customPoolConfig } = this.config;
29
+ this.postgresqlConfig = customPoolConfig !== null && customPoolConfig !== void 0 ? customPoolConfig : {
30
+ host,
31
+ user,
32
+ password,
33
+ database,
34
+ port,
35
+ };
36
+ this.prefix = this.config.prefix;
37
+ if (link != null) {
38
+ this.link = link;
39
+ this.connected = true;
40
+ }
41
+ if (transaction != null) {
42
+ this.transaction = transaction;
43
+ }
44
+ if (link == null) {
45
+ this.connect();
46
+ }
47
+ }
48
+ static escape(input) {
49
+ return pg_format_1.default.ident(input);
50
+ }
51
+ static escapeValue(input) {
52
+ return pg_format_1.default.literal(input);
53
+ }
54
+ getConnection() {
55
+ if (this.transaction != null && this.transaction.connection != null) {
56
+ return Promise.resolve(this.transaction.connection);
57
+ }
58
+ return new Promise((resolve, reject) => this.link.connect((err, client, done) => err ? reject(err) : resolve({ client, done })));
59
+ }
60
+ connect() {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ try {
63
+ if (this.connected) {
64
+ const connection = yield new Promise((resolve, reject) => this.link.connect((err, client, done) => err ? reject(err) : resolve({ client, done })));
65
+ yield new Promise((resolve, reject) => connection.client.query('SELECT 1;', [], (err, res) => {
66
+ if (err) {
67
+ reject(err);
68
+ }
69
+ resolve(0);
70
+ }));
71
+ connection.done();
72
+ }
73
+ }
74
+ catch (e) {
75
+ this.connected = false;
76
+ }
77
+ if (!this.connected) {
78
+ try {
79
+ this.link = new pg_1.Pool(this.postgresqlConfig);
80
+ this.connected = true;
81
+ }
82
+ catch (e) {
83
+ if (this.postgresqlConfig.host === 'localhost' &&
84
+ this.postgresqlConfig.user === 'nymph' &&
85
+ this.postgresqlConfig.password === 'password' &&
86
+ this.postgresqlConfig.database === 'nymph') {
87
+ throw new nymph_1.NotConfiguredError("It seems the config hasn't been set up correctly.");
88
+ }
89
+ else {
90
+ throw new nymph_1.UnableToConnectError('Could not connect: ' + (e === null || e === void 0 ? void 0 : e.message));
91
+ }
92
+ }
93
+ }
94
+ return this.connected;
95
+ });
96
+ }
97
+ disconnect() {
98
+ return __awaiter(this, void 0, void 0, function* () {
99
+ if (this.connected) {
100
+ yield new Promise((resolve) => this.link.end(() => resolve(0)));
101
+ this.connected = false;
102
+ }
103
+ return this.connected;
104
+ });
105
+ }
106
+ inTransaction() {
107
+ return __awaiter(this, void 0, void 0, function* () {
108
+ return !!this.transaction;
109
+ });
110
+ }
111
+ isConnected() {
112
+ return this.connected;
113
+ }
114
+ createTables(etype = null) {
115
+ if (etype != null) {
116
+ this.queryRunSync(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} (
117
+ "guid" BYTEA NOT NULL,
118
+ "tags" TEXT[],
119
+ "cdate" DOUBLE PRECISION NOT NULL,
120
+ "mdate" DOUBLE PRECISION NOT NULL,
121
+ PRIMARY KEY ("guid")
122
+ ) WITH ( OIDS=FALSE );`);
123
+ this.queryRunSync(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`);
124
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_cdate`)};`);
125
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_cdate`)} ON ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} USING btree ("cdate");`);
126
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_mdate`)};`);
127
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_mdate`)} ON ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} USING btree ("mdate");`);
128
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_tags`)};`);
129
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_tags`)} ON ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} USING gin ("tags");`);
130
+ this.queryRunSync(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} (
131
+ "guid" BYTEA NOT NULL,
132
+ "name" TEXT NOT NULL,
133
+ "value" TEXT NOT NULL,
134
+ PRIMARY KEY ("guid", "name"),
135
+ FOREIGN KEY ("guid")
136
+ REFERENCES ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
137
+ ) WITH ( OIDS=FALSE );`);
138
+ this.queryRunSync(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`);
139
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid`)};`);
140
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("guid");`);
141
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name`)};`);
142
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("name");`);
143
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name__user`)};`);
144
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name__user`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("guid") WHERE "name" = 'user'::text;`);
145
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name__group`)};`);
146
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name__group`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("guid") WHERE "name" = 'group'::text;`);
147
+ this.queryRunSync(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} (
148
+ "guid" BYTEA NOT NULL,
149
+ "name" TEXT NOT NULL,
150
+ "truthy" BOOLEAN,
151
+ "string" TEXT,
152
+ "number" DOUBLE PRECISION,
153
+ PRIMARY KEY ("guid", "name"),
154
+ FOREIGN KEY ("guid")
155
+ REFERENCES ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
156
+ ) WITH ( OIDS=FALSE );`);
157
+ this.queryRunSync(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`);
158
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}_id_guid`)};`);
159
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}_id_guid`)} ON ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} USING btree ("guid");`);
160
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}_id_name`)};`);
161
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}_id_name`)} ON ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} USING btree ("name");`);
162
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}_id_guid_name_truthy`)};`);
163
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}_id_guid_name_truthy`)} ON ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} USING btree ("guid", "name") WHERE "truthy" = TRUE;`);
164
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}_id_guid_name_falsy`)};`);
165
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}_id_guid_name_falsy`)} ON ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} USING btree ("guid", "name") WHERE "truthy" <> TRUE;`);
166
+ this.queryRunSync(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} (
167
+ "guid" BYTEA NOT NULL,
168
+ "name" TEXT NOT NULL,
169
+ "reference" BYTEA NOT NULL,
170
+ PRIMARY KEY ("guid", "name", "reference"),
171
+ FOREIGN KEY ("guid")
172
+ REFERENCES ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
173
+ ) WITH ( OIDS=FALSE );`);
174
+ this.queryRunSync(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`);
175
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_guid`)};`);
176
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} USING btree ("guid");`);
177
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_name`)};`);
178
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} USING btree ("name");`);
179
+ this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_reference`)};`);
180
+ this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_reference`)} ON ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} USING btree ("reference");`);
181
+ }
182
+ else {
183
+ this.queryRunSync(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}uids`)} (
184
+ "name" TEXT NOT NULL,
185
+ "cur_uid" BIGINT NOT NULL,
186
+ PRIMARY KEY ("name")
187
+ ) WITH ( OIDS = FALSE );`);
188
+ this.queryRunSync(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}uids`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`);
189
+ }
190
+ return true;
191
+ }
192
+ translateQuery(origQuery, origParams) {
193
+ const params = [];
194
+ let query = origQuery;
195
+ let paramRegex = /@[a-zA-Z0-9]+/;
196
+ let match;
197
+ let i = 1;
198
+ while ((match = query.match(paramRegex))) {
199
+ const param = match[0].substr(1);
200
+ params.push(origParams[param]);
201
+ query = query.replace(paramRegex, () => '$' + i++);
202
+ }
203
+ return { query, params };
204
+ }
205
+ query(runQuery, query, etypes = []) {
206
+ return __awaiter(this, void 0, void 0, function* () {
207
+ try {
208
+ return yield runQuery();
209
+ }
210
+ catch (e) {
211
+ const errorCode = e === null || e === void 0 ? void 0 : e.code;
212
+ if (errorCode === '42P01' && this.createTables()) {
213
+ for (let etype of etypes) {
214
+ this.createTables(etype);
215
+ }
216
+ try {
217
+ return yield runQuery();
218
+ }
219
+ catch (e2) {
220
+ throw new nymph_1.QueryFailedError('Query failed: ' + (e2 === null || e2 === void 0 ? void 0 : e2.code) + ' - ' + (e2 === null || e2 === void 0 ? void 0 : e2.message), query);
221
+ }
222
+ }
223
+ else {
224
+ throw e;
225
+ }
226
+ }
227
+ });
228
+ }
229
+ querySync(runQuery, query, etypes = []) {
230
+ try {
231
+ return runQuery();
232
+ }
233
+ catch (e) {
234
+ const errorCode = e === null || e === void 0 ? void 0 : e.code;
235
+ if (errorCode === '42P01' && this.createTables()) {
236
+ for (let etype of etypes) {
237
+ this.createTables(etype);
238
+ }
239
+ try {
240
+ return runQuery();
241
+ }
242
+ catch (e2) {
243
+ throw new nymph_1.QueryFailedError('Query failed: ' + (e2 === null || e2 === void 0 ? void 0 : e2.code) + ' - ' + (e2 === null || e2 === void 0 ? void 0 : e2.message), query);
244
+ }
245
+ }
246
+ else {
247
+ throw e;
248
+ }
249
+ }
250
+ }
251
+ queryIter(query, { etypes = [], params = {}, } = {}) {
252
+ const { query: newQuery, params: newParams } = this.translateQuery(query, params);
253
+ return this.query(() => __awaiter(this, void 0, void 0, function* () {
254
+ const results = yield new Promise((resolve, reject) => {
255
+ var _a, _b, _c;
256
+ try {
257
+ ((_c = (_b = (_a = this.transaction) === null || _a === void 0 ? void 0 : _a.connection) === null || _b === void 0 ? void 0 : _b.client) !== null && _c !== void 0 ? _c : this.link)
258
+ .query(newQuery, newParams)
259
+ .then((results) => resolve(results), (error) => reject(error));
260
+ }
261
+ catch (e) {
262
+ reject(e);
263
+ }
264
+ });
265
+ return results.rows;
266
+ }), `${query} -- ${JSON.stringify(params)}`, etypes);
267
+ }
268
+ queryIterSync(query, { etypes = [], params = {}, } = {}) {
269
+ const { query: newQuery, params: newParams } = this.translateQuery(query, params);
270
+ return this.querySync(() => {
271
+ const output = child_process_1.default.spawnSync(process.argv0, [__dirname + '/runPostgresqlSync.js'], {
272
+ input: JSON.stringify({
273
+ postgresqlConfig: this.postgresqlConfig,
274
+ query: newQuery,
275
+ params: newParams,
276
+ }),
277
+ timeout: 30000,
278
+ maxBuffer: 100 * 1024 * 1024,
279
+ encoding: 'utf8',
280
+ windowsHide: true,
281
+ });
282
+ try {
283
+ return JSON.parse(output.stdout).rows;
284
+ }
285
+ catch (e) {
286
+ }
287
+ if (output.status === 0) {
288
+ throw new Error('Unknown parse error.');
289
+ }
290
+ const err = JSON.parse(output.stderr);
291
+ const e = new Error(err.name);
292
+ for (const name in err) {
293
+ e[name] = err[name];
294
+ }
295
+ }, `${query} -- ${JSON.stringify(params)}`, etypes);
296
+ }
297
+ queryGet(query, { etypes = [], params = {}, } = {}) {
298
+ const { query: newQuery, params: newParams } = this.translateQuery(query, params);
299
+ return this.query(() => __awaiter(this, void 0, void 0, function* () {
300
+ const results = yield new Promise((resolve, reject) => {
301
+ var _a, _b, _c;
302
+ try {
303
+ ((_c = (_b = (_a = this.transaction) === null || _a === void 0 ? void 0 : _a.connection) === null || _b === void 0 ? void 0 : _b.client) !== null && _c !== void 0 ? _c : this.link)
304
+ .query(newQuery, newParams)
305
+ .then((results) => resolve(results), (error) => reject(error));
306
+ }
307
+ catch (e) {
308
+ reject(e);
309
+ }
310
+ });
311
+ return results.rows[0];
312
+ }), `${query} -- ${JSON.stringify(params)}`, etypes);
313
+ }
314
+ queryRun(query, { etypes = [], params = {}, } = {}) {
315
+ const { query: newQuery, params: newParams } = this.translateQuery(query, params);
316
+ return this.query(() => __awaiter(this, void 0, void 0, function* () {
317
+ var _a;
318
+ const results = yield new Promise((resolve, reject) => {
319
+ var _a, _b, _c;
320
+ try {
321
+ ((_c = (_b = (_a = this.transaction) === null || _a === void 0 ? void 0 : _a.connection) === null || _b === void 0 ? void 0 : _b.client) !== null && _c !== void 0 ? _c : this.link)
322
+ .query(newQuery, newParams)
323
+ .then((results) => resolve(results), (error) => reject(error));
324
+ }
325
+ catch (e) {
326
+ reject(e);
327
+ }
328
+ });
329
+ return { rowCount: (_a = results.rowCount) !== null && _a !== void 0 ? _a : 0 };
330
+ }), `${query} -- ${JSON.stringify(params)}`, etypes);
331
+ }
332
+ queryRunSync(query, { etypes = [], params = {}, } = {}) {
333
+ const { query: newQuery, params: newParams } = this.translateQuery(query, params);
334
+ return this.querySync(() => {
335
+ var _a;
336
+ const output = child_process_1.default.spawnSync(process.argv0, [__dirname + '/runPostgresqlSync.js'], {
337
+ input: JSON.stringify({
338
+ postgresqlConfig: this.postgresqlConfig,
339
+ query: newQuery,
340
+ params: newParams,
341
+ }),
342
+ timeout: 30000,
343
+ maxBuffer: 100 * 1024 * 1024,
344
+ encoding: 'utf8',
345
+ windowsHide: true,
346
+ });
347
+ try {
348
+ const results = JSON.parse(output.stdout);
349
+ return { rowCount: (_a = results.rowCount) !== null && _a !== void 0 ? _a : 0 };
350
+ }
351
+ catch (e) {
352
+ }
353
+ if (output.status === 0) {
354
+ throw new Error('Unknown parse error.');
355
+ }
356
+ const err = JSON.parse(output.stderr);
357
+ const e = new Error(err.name);
358
+ for (const name in err) {
359
+ e[name] = err[name];
360
+ }
361
+ }, `${query} -- ${JSON.stringify(params)}`, etypes);
362
+ }
363
+ commit(name) {
364
+ var _a;
365
+ return __awaiter(this, void 0, void 0, function* () {
366
+ if (name == null || typeof name !== 'string' || name.length === 0) {
367
+ throw new nymph_1.InvalidParametersError('Transaction commit attempted without a name.');
368
+ }
369
+ if (!this.transaction || this.transaction.count === 0) {
370
+ this.transaction = null;
371
+ return true;
372
+ }
373
+ yield this.queryRun(`RELEASE SAVEPOINT ${PostgreSQLDriver.escape(name)};`);
374
+ this.transaction.count--;
375
+ if (this.transaction.count === 0) {
376
+ yield this.queryRun('COMMIT;');
377
+ (_a = this.transaction.connection) === null || _a === void 0 ? void 0 : _a.done();
378
+ this.transaction.connection = null;
379
+ this.transaction = null;
380
+ }
381
+ return true;
382
+ });
383
+ }
384
+ deleteEntityByID(guid, className) {
385
+ return __awaiter(this, void 0, void 0, function* () {
386
+ let EntityClass;
387
+ if (typeof className === 'string' || className == null) {
388
+ const GetEntityClass = this.nymph.getEntityClass(className !== null && className !== void 0 ? className : 'Entity');
389
+ EntityClass = GetEntityClass;
390
+ }
391
+ else {
392
+ EntityClass = className;
393
+ }
394
+ const etype = EntityClass.ETYPE;
395
+ yield this.internalTransaction('nymph-delete');
396
+ try {
397
+ yield this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
398
+ etypes: [etype],
399
+ params: {
400
+ guid,
401
+ },
402
+ });
403
+ yield this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
404
+ etypes: [etype],
405
+ params: {
406
+ guid,
407
+ },
408
+ });
409
+ yield this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
410
+ etypes: [etype],
411
+ params: {
412
+ guid,
413
+ },
414
+ });
415
+ yield this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
416
+ etypes: [etype],
417
+ params: {
418
+ guid,
419
+ },
420
+ });
421
+ yield this.commit('nymph-delete');
422
+ if (this.nymph.config.cache) {
423
+ this.cleanCache(guid);
424
+ }
425
+ return true;
426
+ }
427
+ catch (e) {
428
+ yield this.rollback('nymph-delete');
429
+ throw e;
430
+ }
431
+ });
432
+ }
433
+ deleteUID(name) {
434
+ return __awaiter(this, void 0, void 0, function* () {
435
+ if (!name) {
436
+ throw new nymph_1.InvalidParametersError('Name not given for UID');
437
+ }
438
+ yield this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
439
+ params: {
440
+ name,
441
+ },
442
+ });
443
+ return true;
444
+ });
445
+ }
446
+ exportEntities(writeLine) {
447
+ return __awaiter(this, void 0, void 0, function* () {
448
+ writeLine('#nex2');
449
+ writeLine('# Nymph Entity Exchange v2');
450
+ writeLine('# http://nymph.io');
451
+ writeLine('#');
452
+ writeLine('# Generation Time: ' + new Date().toLocaleString());
453
+ writeLine('');
454
+ writeLine('#');
455
+ writeLine('# UIDs');
456
+ writeLine('#');
457
+ writeLine('');
458
+ let uids = yield this.queryIter(`SELECT * FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} ORDER BY "name";`);
459
+ for (const uid of uids) {
460
+ writeLine(`<${uid.name}>[${uid.cur_uid}]`);
461
+ }
462
+ writeLine('');
463
+ writeLine('#');
464
+ writeLine('# Entities');
465
+ writeLine('#');
466
+ writeLine('');
467
+ const tables = yield this.queryIter('SELECT relname FROM pg_stat_user_tables ORDER BY relname;');
468
+ const etypes = [];
469
+ for (const tableRow of tables) {
470
+ const table = tableRow.relname;
471
+ if (table.startsWith(this.prefix + 'entities_')) {
472
+ etypes.push(table.substr((this.prefix + 'entities_').length));
473
+ }
474
+ }
475
+ for (const etype of etypes) {
476
+ const dataIterator = (yield this.queryIter(`SELECT encode(e."guid", 'hex') as "guid", e."tags", e."cdate", e."mdate", d."name" AS "dname", d."value" AS "dvalue", c."string", c."number"
477
+ FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} e
478
+ LEFT JOIN ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} d ON e."guid"=d."guid"
479
+ INNER JOIN ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} c ON d."guid"=c."guid" AND d."name"=c."name"
480
+ ORDER BY e."guid";`))[Symbol.iterator]();
481
+ let datum = dataIterator.next();
482
+ while (!datum.done) {
483
+ const guid = datum.value.guid;
484
+ const tags = datum.value.tags.join(',');
485
+ const cdate = datum.value.cdate;
486
+ const mdate = datum.value.mdate;
487
+ writeLine(`{${guid}}<${etype}>[${tags}]`);
488
+ writeLine(`\tcdate=${JSON.stringify(cdate)}`);
489
+ writeLine(`\tmdate=${JSON.stringify(mdate)}`);
490
+ if (datum.value.dname != null) {
491
+ do {
492
+ const value = datum.value.dvalue === 'N'
493
+ ? JSON.stringify(Number(datum.value.number))
494
+ : datum.value.dvalue === 'S'
495
+ ? JSON.stringify(datum.value.string)
496
+ : datum.value.dvalue;
497
+ writeLine(`\t${datum.value.dname}=${value}`);
498
+ datum = dataIterator.next();
499
+ } while (!datum.done && datum.value.guid === guid);
500
+ }
501
+ else {
502
+ datum = dataIterator.next();
503
+ }
504
+ }
505
+ }
506
+ return;
507
+ });
508
+ }
509
+ makeEntityQuery(options, formattedSelectors, etype, count = { i: 0 }, params = {}, subquery = false, tableSuffix = '', etypes = []) {
510
+ var _a, _b;
511
+ if (typeof ((_a = options.class) === null || _a === void 0 ? void 0 : _a.alterOptions) === 'function') {
512
+ options = options.class.alterOptions(options);
513
+ }
514
+ const eTable = `e${tableSuffix}`;
515
+ const dTable = `d${tableSuffix}`;
516
+ const cTable = `c${tableSuffix}`;
517
+ const fTable = `f${tableSuffix}`;
518
+ const ieTable = `ie${tableSuffix}`;
519
+ const sort = (_b = options.sort) !== null && _b !== void 0 ? _b : 'cdate';
520
+ const queryParts = this.iterateSelectorsForQuery(formattedSelectors, (key, value, typeIsOr, typeIsNot) => {
521
+ const clauseNot = key.startsWith('!');
522
+ let curQuery = '';
523
+ for (const curValue of value) {
524
+ switch (key) {
525
+ case 'guid':
526
+ case '!guid':
527
+ for (const curGuid of curValue) {
528
+ if (curQuery) {
529
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
530
+ }
531
+ const guid = `param${++count.i}`;
532
+ curQuery +=
533
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
534
+ ieTable +
535
+ '."guid"=decode(@' +
536
+ guid +
537
+ ", 'hex')";
538
+ params[guid] = curGuid;
539
+ }
540
+ break;
541
+ case 'tag':
542
+ case '!tag':
543
+ for (const curTag of curValue) {
544
+ if (curQuery) {
545
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
546
+ }
547
+ const tag = `param${++count.i}`;
548
+ curQuery +=
549
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
550
+ '@' +
551
+ tag +
552
+ ' <@ ie."tags"';
553
+ params[tag] = [curTag];
554
+ }
555
+ break;
556
+ case 'defined':
557
+ case '!defined':
558
+ for (const curVar of curValue) {
559
+ if (curQuery) {
560
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
561
+ }
562
+ const name = `param${++count.i}`;
563
+ curQuery +=
564
+ ieTable +
565
+ '."guid" ' +
566
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
567
+ 'IN (SELECT "guid" FROM ' +
568
+ PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
569
+ ' WHERE "name"=@' +
570
+ name +
571
+ ')';
572
+ params[name] = curVar;
573
+ }
574
+ break;
575
+ case 'truthy':
576
+ case '!truthy':
577
+ for (const curVar of curValue) {
578
+ if (curQuery) {
579
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
580
+ }
581
+ if (curVar === 'cdate') {
582
+ curQuery +=
583
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
584
+ '(' +
585
+ ieTable +
586
+ '."cdate" NOT NULL)';
587
+ break;
588
+ }
589
+ else if (curVar === 'mdate') {
590
+ curQuery +=
591
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
592
+ '(' +
593
+ ieTable +
594
+ '."mdate" NOT NULL)';
595
+ break;
596
+ }
597
+ else {
598
+ const name = `param${++count.i}`;
599
+ curQuery +=
600
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
601
+ ieTable +
602
+ '."guid" IN (SELECT "guid" FROM ' +
603
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
604
+ ' WHERE "name"=@' +
605
+ name +
606
+ ' AND "truthy"=TRUE)';
607
+ params[name] = curVar;
608
+ }
609
+ }
610
+ break;
611
+ case 'equal':
612
+ case '!equal':
613
+ if (curValue[0] === 'cdate') {
614
+ if (curQuery) {
615
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
616
+ }
617
+ const cdate = `param${++count.i}`;
618
+ curQuery +=
619
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
620
+ ieTable +
621
+ '."cdate"=@' +
622
+ cdate;
623
+ params[cdate] = isNaN(Number(curValue[1]))
624
+ ? null
625
+ : Number(curValue[1]);
626
+ break;
627
+ }
628
+ else if (curValue[0] === 'mdate') {
629
+ if (curQuery) {
630
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
631
+ }
632
+ const mdate = `param${++count.i}`;
633
+ curQuery +=
634
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
635
+ ieTable +
636
+ '."mdate"=@' +
637
+ mdate;
638
+ params[mdate] = isNaN(Number(curValue[1]))
639
+ ? null
640
+ : Number(curValue[1]);
641
+ break;
642
+ }
643
+ else if (typeof curValue[1] === 'number') {
644
+ if (curQuery) {
645
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
646
+ }
647
+ const name = `param${++count.i}`;
648
+ const value = `param${++count.i}`;
649
+ curQuery +=
650
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
651
+ ieTable +
652
+ '."guid" IN (SELECT "guid" FROM ' +
653
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
654
+ ' WHERE "name"=@' +
655
+ name +
656
+ ' AND "number"=@' +
657
+ value +
658
+ ')';
659
+ params[name] = curValue[0];
660
+ params[value] = curValue[1];
661
+ }
662
+ else if (typeof curValue[1] === 'string') {
663
+ if (curQuery) {
664
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
665
+ }
666
+ const name = `param${++count.i}`;
667
+ const value = `param${++count.i}`;
668
+ curQuery +=
669
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
670
+ ieTable +
671
+ '."guid" IN (SELECT "guid" FROM ' +
672
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
673
+ ' WHERE "name"=@' +
674
+ name +
675
+ ' AND "string"=@' +
676
+ value +
677
+ ')';
678
+ params[name] = curValue[0];
679
+ params[value] = curValue[1];
680
+ }
681
+ else {
682
+ if (curQuery) {
683
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
684
+ }
685
+ let svalue;
686
+ if (curValue[1] instanceof Object &&
687
+ typeof curValue[1].toReference === 'function') {
688
+ svalue = JSON.stringify(curValue[1].toReference());
689
+ }
690
+ else {
691
+ svalue = JSON.stringify(curValue[1]);
692
+ }
693
+ const name = `param${++count.i}`;
694
+ const value = `param${++count.i}`;
695
+ curQuery +=
696
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
697
+ ieTable +
698
+ '."guid" IN (SELECT "guid" FROM ' +
699
+ PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
700
+ ' WHERE "name"=@' +
701
+ name +
702
+ ' AND "value"=@' +
703
+ value +
704
+ ')';
705
+ params[name] = curValue[0];
706
+ params[value] = svalue;
707
+ }
708
+ break;
709
+ case 'contain':
710
+ case '!contain':
711
+ if (curValue[0] === 'cdate') {
712
+ if (curQuery) {
713
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
714
+ }
715
+ const cdate = `param${++count.i}`;
716
+ curQuery +=
717
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
718
+ ieTable +
719
+ '."cdate"=' +
720
+ cdate;
721
+ params[cdate] = isNaN(Number(curValue[1]))
722
+ ? null
723
+ : Number(curValue[1]);
724
+ break;
725
+ }
726
+ else if (curValue[0] === 'mdate') {
727
+ if (curQuery) {
728
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
729
+ }
730
+ const mdate = `param${++count.i}`;
731
+ curQuery +=
732
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
733
+ ieTable +
734
+ '."mdate"=' +
735
+ mdate;
736
+ params[mdate] = isNaN(Number(curValue[1]))
737
+ ? null
738
+ : Number(curValue[1]);
739
+ break;
740
+ }
741
+ else {
742
+ if (curQuery) {
743
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
744
+ }
745
+ let svalue;
746
+ let stringValue;
747
+ if (curValue[1] instanceof Object &&
748
+ typeof curValue[1].toReference === 'function') {
749
+ svalue = JSON.stringify(curValue[1].toReference());
750
+ stringValue = `${curValue[1].toReference()}`;
751
+ }
752
+ else {
753
+ svalue = JSON.stringify(curValue[1]);
754
+ stringValue = `${curValue[1]}`;
755
+ }
756
+ const name = `param${++count.i}`;
757
+ const value = `param${++count.i}`;
758
+ if (typeof curValue[1] === 'string') {
759
+ const stringParam = `param${++count.i}`;
760
+ curQuery +=
761
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
762
+ '(' +
763
+ ieTable +
764
+ '."guid" IN (SELECT "guid" FROM ' +
765
+ PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
766
+ ' WHERE "name"=@' +
767
+ name +
768
+ ' AND position(@' +
769
+ value +
770
+ ' IN "value")>0) OR ' +
771
+ ieTable +
772
+ '."guid" IN (SELECT "guid" FROM ' +
773
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
774
+ ' WHERE "name"=@' +
775
+ name +
776
+ ' AND "string"=@' +
777
+ stringParam +
778
+ '))';
779
+ params[stringParam] = stringValue;
780
+ }
781
+ else {
782
+ curQuery +=
783
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
784
+ ieTable +
785
+ '."guid" IN (SELECT "guid" FROM ' +
786
+ PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
787
+ ' WHERE "name"=@' +
788
+ name +
789
+ ' AND position(@' +
790
+ value +
791
+ ' IN "value")>0)';
792
+ }
793
+ params[name] = curValue[0];
794
+ params[value] = svalue;
795
+ }
796
+ break;
797
+ case 'match':
798
+ case '!match':
799
+ if (curValue[0] === 'cdate') {
800
+ if (curQuery) {
801
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
802
+ }
803
+ const cdate = `param${++count.i}`;
804
+ curQuery +=
805
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
806
+ '(' +
807
+ ieTable +
808
+ '."cdate" ~ @' +
809
+ cdate +
810
+ ')';
811
+ params[cdate] = curValue[1];
812
+ break;
813
+ }
814
+ else if (curValue[0] === 'mdate') {
815
+ if (curQuery) {
816
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
817
+ }
818
+ const mdate = `param${++count.i}`;
819
+ curQuery +=
820
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
821
+ '(' +
822
+ ieTable +
823
+ '."mdate" ~ @' +
824
+ mdate +
825
+ ')';
826
+ params[mdate] = curValue[1];
827
+ break;
828
+ }
829
+ else {
830
+ if (curQuery) {
831
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
832
+ }
833
+ const name = `param${++count.i}`;
834
+ const value = `param${++count.i}`;
835
+ curQuery +=
836
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
837
+ ieTable +
838
+ '."guid" IN (SELECT "guid" FROM ' +
839
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
840
+ ' WHERE "name"=@' +
841
+ name +
842
+ ' AND "string" ~ @' +
843
+ value +
844
+ ')';
845
+ params[name] = curValue[0];
846
+ params[value] = curValue[1];
847
+ }
848
+ break;
849
+ case 'imatch':
850
+ case '!imatch':
851
+ if (curValue[0] === 'cdate') {
852
+ if (curQuery) {
853
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
854
+ }
855
+ const cdate = `param${++count.i}`;
856
+ curQuery +=
857
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
858
+ '(' +
859
+ ieTable +
860
+ '."cdate" ~* @' +
861
+ cdate +
862
+ ')';
863
+ params[cdate] = curValue[1];
864
+ break;
865
+ }
866
+ else if (curValue[0] === 'mdate') {
867
+ if (curQuery) {
868
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
869
+ }
870
+ const mdate = `param${++count.i}`;
871
+ curQuery +=
872
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
873
+ '(' +
874
+ ieTable +
875
+ '."mdate" ~* @' +
876
+ mdate +
877
+ ')';
878
+ params[mdate] = curValue[1];
879
+ break;
880
+ }
881
+ else {
882
+ if (curQuery) {
883
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
884
+ }
885
+ const name = `param${++count.i}`;
886
+ const value = `param${++count.i}`;
887
+ curQuery +=
888
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
889
+ ieTable +
890
+ '."guid" IN (SELECT "guid" FROM ' +
891
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
892
+ ' WHERE "name"=@' +
893
+ name +
894
+ ' AND "string" ~* @' +
895
+ value +
896
+ ')';
897
+ params[name] = curValue[0];
898
+ params[value] = curValue[1];
899
+ }
900
+ break;
901
+ case 'like':
902
+ case '!like':
903
+ if (curValue[0] === 'cdate') {
904
+ if (curQuery) {
905
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
906
+ }
907
+ const cdate = `param${++count.i}`;
908
+ curQuery +=
909
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
910
+ '(' +
911
+ ieTable +
912
+ '."cdate" LIKE @' +
913
+ cdate +
914
+ ')';
915
+ params[cdate] = curValue[1];
916
+ break;
917
+ }
918
+ else if (curValue[0] === 'mdate') {
919
+ if (curQuery) {
920
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
921
+ }
922
+ const mdate = `param${++count.i}`;
923
+ curQuery +=
924
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
925
+ '(' +
926
+ ieTable +
927
+ '."mdate" LIKE @' +
928
+ mdate +
929
+ ')';
930
+ params[mdate] = curValue[1];
931
+ break;
932
+ }
933
+ else {
934
+ if (curQuery) {
935
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
936
+ }
937
+ const name = `param${++count.i}`;
938
+ const value = `param${++count.i}`;
939
+ curQuery +=
940
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
941
+ ieTable +
942
+ '."guid" IN (SELECT "guid" FROM ' +
943
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
944
+ ' WHERE "name"=@' +
945
+ name +
946
+ ' AND "string" LIKE @' +
947
+ value +
948
+ ')';
949
+ params[name] = curValue[0];
950
+ params[value] = curValue[1];
951
+ }
952
+ break;
953
+ case 'ilike':
954
+ case '!ilike':
955
+ if (curValue[0] === 'cdate') {
956
+ if (curQuery) {
957
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
958
+ }
959
+ const cdate = `param${++count.i}`;
960
+ curQuery +=
961
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
962
+ '(' +
963
+ ieTable +
964
+ '."cdate" ILIKE @' +
965
+ cdate +
966
+ ')';
967
+ params[cdate] = curValue[1];
968
+ break;
969
+ }
970
+ else if (curValue[0] === 'mdate') {
971
+ if (curQuery) {
972
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
973
+ }
974
+ const mdate = `param${++count.i}`;
975
+ curQuery +=
976
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
977
+ '(' +
978
+ ieTable +
979
+ '."mdate" ILIKE @' +
980
+ mdate +
981
+ ')';
982
+ params[mdate] = curValue[1];
983
+ break;
984
+ }
985
+ else {
986
+ if (curQuery) {
987
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
988
+ }
989
+ const name = `param${++count.i}`;
990
+ const value = `param${++count.i}`;
991
+ curQuery +=
992
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
993
+ ieTable +
994
+ '."guid" IN (SELECT "guid" FROM ' +
995
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
996
+ ' WHERE "name"=@' +
997
+ name +
998
+ ' AND "string" ILIKE @' +
999
+ value +
1000
+ ')';
1001
+ params[name] = curValue[0];
1002
+ params[value] = curValue[1];
1003
+ }
1004
+ break;
1005
+ case 'gt':
1006
+ case '!gt':
1007
+ if (curValue[0] === 'cdate') {
1008
+ if (curQuery) {
1009
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1010
+ }
1011
+ const cdate = `param${++count.i}`;
1012
+ curQuery +=
1013
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1014
+ ieTable +
1015
+ '."cdate">@' +
1016
+ cdate;
1017
+ params[cdate] = isNaN(Number(curValue[1]))
1018
+ ? null
1019
+ : Number(curValue[1]);
1020
+ break;
1021
+ }
1022
+ else if (curValue[0] === 'mdate') {
1023
+ if (curQuery) {
1024
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1025
+ }
1026
+ const mdate = `param${++count.i}`;
1027
+ curQuery +=
1028
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1029
+ ieTable +
1030
+ '."mdate">@' +
1031
+ mdate;
1032
+ params[mdate] = isNaN(Number(curValue[1]))
1033
+ ? null
1034
+ : Number(curValue[1]);
1035
+ break;
1036
+ }
1037
+ else {
1038
+ if (curQuery) {
1039
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1040
+ }
1041
+ const name = `param${++count.i}`;
1042
+ const value = `param${++count.i}`;
1043
+ curQuery +=
1044
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1045
+ ieTable +
1046
+ '."guid" IN (SELECT "guid" FROM ' +
1047
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
1048
+ ' WHERE "name"=@' +
1049
+ name +
1050
+ ' AND "number">@' +
1051
+ value +
1052
+ ')';
1053
+ params[name] = curValue[0];
1054
+ params[value] = isNaN(Number(curValue[1]))
1055
+ ? null
1056
+ : Number(curValue[1]);
1057
+ }
1058
+ break;
1059
+ case 'gte':
1060
+ case '!gte':
1061
+ if (curValue[0] === 'cdate') {
1062
+ if (curQuery) {
1063
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1064
+ }
1065
+ const cdate = `param${++count.i}`;
1066
+ curQuery +=
1067
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1068
+ ieTable +
1069
+ '."cdate">=@' +
1070
+ cdate;
1071
+ params[cdate] = isNaN(Number(curValue[1]))
1072
+ ? null
1073
+ : Number(curValue[1]);
1074
+ break;
1075
+ }
1076
+ else if (curValue[0] === 'mdate') {
1077
+ if (curQuery) {
1078
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1079
+ }
1080
+ const mdate = `param${++count.i}`;
1081
+ curQuery +=
1082
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1083
+ ieTable +
1084
+ '."mdate">=@' +
1085
+ mdate;
1086
+ params[mdate] = isNaN(Number(curValue[1]))
1087
+ ? null
1088
+ : Number(curValue[1]);
1089
+ break;
1090
+ }
1091
+ else {
1092
+ if (curQuery) {
1093
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1094
+ }
1095
+ const name = `param${++count.i}`;
1096
+ const value = `param${++count.i}`;
1097
+ curQuery +=
1098
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1099
+ ieTable +
1100
+ '."guid" IN (SELECT "guid" FROM ' +
1101
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
1102
+ ' WHERE "name"=@' +
1103
+ name +
1104
+ ' AND "number">=@' +
1105
+ value +
1106
+ ')';
1107
+ params[name] = curValue[0];
1108
+ params[value] = isNaN(Number(curValue[1]))
1109
+ ? null
1110
+ : Number(curValue[1]);
1111
+ }
1112
+ break;
1113
+ case 'lt':
1114
+ case '!lt':
1115
+ if (curValue[0] === 'cdate') {
1116
+ if (curQuery) {
1117
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1118
+ }
1119
+ const cdate = `param${++count.i}`;
1120
+ curQuery +=
1121
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1122
+ ieTable +
1123
+ '."cdate"<@' +
1124
+ cdate;
1125
+ params[cdate] = isNaN(Number(curValue[1]))
1126
+ ? null
1127
+ : Number(curValue[1]);
1128
+ break;
1129
+ }
1130
+ else if (curValue[0] === 'mdate') {
1131
+ if (curQuery) {
1132
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1133
+ }
1134
+ const mdate = `param${++count.i}`;
1135
+ curQuery +=
1136
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1137
+ ieTable +
1138
+ '."mdate"<@' +
1139
+ mdate;
1140
+ params[mdate] = isNaN(Number(curValue[1]))
1141
+ ? null
1142
+ : Number(curValue[1]);
1143
+ break;
1144
+ }
1145
+ else {
1146
+ if (curQuery) {
1147
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1148
+ }
1149
+ const name = `param${++count.i}`;
1150
+ const value = `param${++count.i}`;
1151
+ curQuery +=
1152
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1153
+ ieTable +
1154
+ '."guid" IN (SELECT "guid" FROM ' +
1155
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
1156
+ ' WHERE "name"=@' +
1157
+ name +
1158
+ ' AND "number"<@' +
1159
+ value +
1160
+ ')';
1161
+ params[name] = curValue[0];
1162
+ params[value] = isNaN(Number(curValue[1]))
1163
+ ? null
1164
+ : Number(curValue[1]);
1165
+ }
1166
+ break;
1167
+ case 'lte':
1168
+ case '!lte':
1169
+ if (curValue[0] === 'cdate') {
1170
+ if (curQuery) {
1171
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1172
+ }
1173
+ const cdate = `param${++count.i}`;
1174
+ curQuery +=
1175
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1176
+ ieTable +
1177
+ '."cdate"<=@' +
1178
+ cdate;
1179
+ params[cdate] = isNaN(Number(curValue[1]))
1180
+ ? null
1181
+ : Number(curValue[1]);
1182
+ break;
1183
+ }
1184
+ else if (curValue[0] === 'mdate') {
1185
+ if (curQuery) {
1186
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1187
+ }
1188
+ const mdate = `param${++count.i}`;
1189
+ curQuery +=
1190
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1191
+ ieTable +
1192
+ '."mdate"<=@' +
1193
+ mdate;
1194
+ params[mdate] = isNaN(Number(curValue[1]))
1195
+ ? null
1196
+ : Number(curValue[1]);
1197
+ break;
1198
+ }
1199
+ else {
1200
+ if (curQuery) {
1201
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1202
+ }
1203
+ const name = `param${++count.i}`;
1204
+ const value = `param${++count.i}`;
1205
+ curQuery +=
1206
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1207
+ ieTable +
1208
+ '."guid" IN (SELECT "guid" FROM ' +
1209
+ PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
1210
+ ' WHERE "name"=@' +
1211
+ name +
1212
+ ' AND "number"<=@' +
1213
+ value +
1214
+ ')';
1215
+ params[name] = curValue[0];
1216
+ params[value] = isNaN(Number(curValue[1]))
1217
+ ? null
1218
+ : Number(curValue[1]);
1219
+ }
1220
+ break;
1221
+ case 'ref':
1222
+ case '!ref':
1223
+ let curQguid;
1224
+ if (typeof curValue[1] === 'string') {
1225
+ curQguid = curValue[1];
1226
+ }
1227
+ else if ('guid' in curValue[1]) {
1228
+ curQguid = curValue[1].guid;
1229
+ }
1230
+ else {
1231
+ curQguid = `${curValue[1]}`;
1232
+ }
1233
+ if (curQuery) {
1234
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1235
+ }
1236
+ const name = `param${++count.i}`;
1237
+ const guid = `param${++count.i}`;
1238
+ curQuery +=
1239
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1240
+ ieTable +
1241
+ '."guid" IN (SELECT "guid" FROM ' +
1242
+ PostgreSQLDriver.escape(this.prefix + 'references_' + etype) +
1243
+ ' WHERE "name"=@' +
1244
+ name +
1245
+ ' AND "reference"=decode(@' +
1246
+ guid +
1247
+ ", 'hex'))";
1248
+ params[name] = curValue[0];
1249
+ params[guid] = curQguid;
1250
+ break;
1251
+ case 'selector':
1252
+ case '!selector':
1253
+ const subquery = this.makeEntityQuery(options, [curValue], etype, count, params, true, tableSuffix, etypes);
1254
+ if (curQuery) {
1255
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1256
+ }
1257
+ curQuery +=
1258
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1259
+ '(' +
1260
+ subquery.query +
1261
+ ')';
1262
+ break;
1263
+ case 'qref':
1264
+ case '!qref':
1265
+ const [qrefOptions, ...qrefSelectors] = curValue[1];
1266
+ const QrefEntityClass = qrefOptions.class;
1267
+ etypes.push(QrefEntityClass.ETYPE);
1268
+ const qrefQuery = this.makeEntityQuery(Object.assign(Object.assign({}, qrefOptions), { return: 'guid', class: QrefEntityClass }), qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes);
1269
+ if (curQuery) {
1270
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
1271
+ }
1272
+ const qrefName = `param${++count.i}`;
1273
+ curQuery +=
1274
+ ((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
1275
+ ieTable +
1276
+ '."guid" IN (SELECT "guid" FROM ' +
1277
+ PostgreSQLDriver.escape(this.prefix + 'references_' + etype) +
1278
+ ' WHERE "name"=@' +
1279
+ qrefName +
1280
+ ' AND "reference" IN (' +
1281
+ qrefQuery.query +
1282
+ '))';
1283
+ params[qrefName] = curValue[0];
1284
+ break;
1285
+ }
1286
+ }
1287
+ return curQuery;
1288
+ });
1289
+ let sortBy;
1290
+ switch (sort) {
1291
+ case 'mdate':
1292
+ sortBy = '"mdate"';
1293
+ break;
1294
+ case 'cdate':
1295
+ default:
1296
+ sortBy = '"cdate"';
1297
+ break;
1298
+ }
1299
+ if (options.reverse) {
1300
+ sortBy += ' DESC';
1301
+ }
1302
+ let query;
1303
+ if (queryParts.length) {
1304
+ if (subquery) {
1305
+ query = '(' + queryParts.join(') AND (') + ')';
1306
+ }
1307
+ else {
1308
+ let limit = '';
1309
+ if ('limit' in options) {
1310
+ limit = ` LIMIT ${Math.floor(isNaN(Number(options.limit)) ? 0 : Number(options.limit))}`;
1311
+ }
1312
+ let offset = '';
1313
+ if ('offset' in options) {
1314
+ offset = ` OFFSET ${Math.floor(isNaN(Number(options.offset)) ? 0 : Number(options.offset))}`;
1315
+ }
1316
+ const whereClause = queryParts.join(') AND (');
1317
+ if (options.return === 'guid') {
1318
+ const guidColumn = tableSuffix === ''
1319
+ ? `encode(${ieTable}."guid", 'hex')`
1320
+ : `${ieTable}."guid"`;
1321
+ query = `SELECT ${guidColumn} as "guid"
1322
+ FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
1323
+ WHERE (${whereClause})
1324
+ ORDER BY ${ieTable}.${sortBy}${limit}${offset}`;
1325
+ }
1326
+ else {
1327
+ query = `SELECT
1328
+ encode(${eTable}."guid", 'hex') as "guid",
1329
+ ${eTable}."tags",
1330
+ ${eTable}."cdate",
1331
+ ${eTable}."mdate",
1332
+ ${dTable}."name",
1333
+ ${dTable}."value",
1334
+ ${cTable}."string",
1335
+ ${cTable}."number"
1336
+ FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
1337
+ LEFT JOIN ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}."guid"=${dTable}."guid"
1338
+ INNER JOIN ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} ${cTable} ON ${dTable}."guid"=${cTable}."guid" AND ${dTable}."name"=${cTable}."name"
1339
+ INNER JOIN (
1340
+ SELECT ${ieTable}."guid"
1341
+ FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
1342
+ WHERE (${whereClause})
1343
+ ORDER BY ${ieTable}.${sortBy}${limit}${offset}
1344
+ ) ${fTable} ON ${eTable}."guid"=${fTable}."guid"
1345
+ ORDER BY ${eTable}.${sortBy}`;
1346
+ }
1347
+ }
1348
+ }
1349
+ else {
1350
+ if (subquery) {
1351
+ query = '';
1352
+ }
1353
+ else {
1354
+ let limit = '';
1355
+ if ('limit' in options) {
1356
+ limit = ` LIMIT ${Math.floor(isNaN(Number(options.limit)) ? 0 : Number(options.limit))}`;
1357
+ }
1358
+ let offset = '';
1359
+ if ('offset' in options) {
1360
+ offset = ` OFFSET ${Math.floor(isNaN(Number(options.offset)) ? 0 : Number(options.offset))}`;
1361
+ }
1362
+ if (options.return === 'guid') {
1363
+ const guidColumn = tableSuffix === ''
1364
+ ? `encode(${ieTable}."guid", 'hex')`
1365
+ : `${ieTable}."guid"`;
1366
+ query = `SELECT ${guidColumn} as "guid"
1367
+ FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
1368
+ ORDER BY ${ieTable}.${sortBy}${limit}${offset}`;
1369
+ }
1370
+ else {
1371
+ if (limit || offset) {
1372
+ query = `SELECT
1373
+ encode(${eTable}."guid", 'hex') as "guid",
1374
+ ${eTable}."tags",
1375
+ ${eTable}."cdate",
1376
+ ${eTable}."mdate",
1377
+ ${dTable}."name",
1378
+ ${dTable}."value",
1379
+ ${cTable}."string",
1380
+ ${cTable}."number"
1381
+ FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
1382
+ LEFT JOIN ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}."guid"=${dTable}."guid"
1383
+ INNER JOIN ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} ${cTable} ON ${dTable}."guid"=${cTable}."guid" AND ${dTable}."name"=${cTable}."name"
1384
+ INNER JOIN (
1385
+ SELECT ${ieTable}."guid"
1386
+ FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
1387
+ ORDER BY ${ieTable}.${sortBy}${limit}${offset}
1388
+ ) ${fTable} ON ${eTable}."guid"=${fTable}."guid"
1389
+ ORDER BY ${eTable}.${sortBy}`;
1390
+ }
1391
+ else {
1392
+ query = `SELECT
1393
+ encode(${eTable}."guid", 'hex') as "guid",
1394
+ ${eTable}."tags",
1395
+ ${eTable}."cdate",
1396
+ ${eTable}."mdate",
1397
+ ${dTable}."name",
1398
+ ${dTable}."value",
1399
+ ${cTable}."string",
1400
+ ${cTable}."number"
1401
+ FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
1402
+ LEFT JOIN ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}."guid"=${dTable}."guid"
1403
+ INNER JOIN ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} ${cTable} ON ${dTable}."guid"=${cTable}."guid" AND ${dTable}."name"=${cTable}."name"
1404
+ ORDER BY ${eTable}.${sortBy}`;
1405
+ }
1406
+ }
1407
+ }
1408
+ }
1409
+ if (etypes.indexOf(etype) === -1) {
1410
+ etypes.push(etype);
1411
+ }
1412
+ return {
1413
+ query,
1414
+ params,
1415
+ etypes,
1416
+ };
1417
+ }
1418
+ performQuery(options, formattedSelectors, etype) {
1419
+ const { query, params, etypes } = this.makeEntityQuery(options, formattedSelectors, etype);
1420
+ const result = this.queryIter(query, { etypes, params }).then((val) => val[Symbol.iterator]());
1421
+ return {
1422
+ result,
1423
+ };
1424
+ }
1425
+ performQuerySync(options, formattedSelectors, etype) {
1426
+ const { query, params, etypes } = this.makeEntityQuery(options, formattedSelectors, etype);
1427
+ const result = this.queryIterSync(query, { etypes, params })[Symbol.iterator]();
1428
+ return {
1429
+ result,
1430
+ };
1431
+ }
1432
+ getEntities(options = {}, ...selectors) {
1433
+ return __awaiter(this, void 0, void 0, function* () {
1434
+ const { result: resultPromise, process } = this.getEntitesRowLike(options, selectors, (options, formattedSelectors, etype) => this.performQuery(options, formattedSelectors, etype), () => {
1435
+ const next = result.next();
1436
+ return next.done ? null : next.value;
1437
+ }, () => undefined, (row) => row.guid, (row) => ({
1438
+ tags: row.tags,
1439
+ cdate: isNaN(Number(row.cdate)) ? null : Number(row.cdate),
1440
+ mdate: isNaN(Number(row.mdate)) ? null : Number(row.mdate),
1441
+ }), (row) => ({
1442
+ name: row.name,
1443
+ svalue: row.value === 'N'
1444
+ ? JSON.stringify(Number(row.number))
1445
+ : row.value === 'S'
1446
+ ? JSON.stringify(row.string)
1447
+ : row.value,
1448
+ }));
1449
+ const result = yield resultPromise;
1450
+ return process();
1451
+ });
1452
+ }
1453
+ getEntitiesSync(options = {}, ...selectors) {
1454
+ const { result, process } = this.getEntitesRowLike(options, selectors, (options, formattedSelectors, etype) => this.performQuerySync(options, formattedSelectors, etype), () => {
1455
+ const next = result.next();
1456
+ return next.done ? null : next.value;
1457
+ }, () => undefined, (row) => row.guid, (row) => ({
1458
+ tags: row.tags,
1459
+ cdate: isNaN(Number(row.cdate)) ? null : Number(row.cdate),
1460
+ mdate: isNaN(Number(row.mdate)) ? null : Number(row.mdate),
1461
+ }), (row) => ({
1462
+ name: row.name,
1463
+ svalue: row.value === 'N'
1464
+ ? JSON.stringify(Number(row.number))
1465
+ : row.value === 'S'
1466
+ ? JSON.stringify(row.string)
1467
+ : row.value,
1468
+ }));
1469
+ return process();
1470
+ }
1471
+ getUID(name) {
1472
+ return __awaiter(this, void 0, void 0, function* () {
1473
+ if (name == null) {
1474
+ throw new nymph_1.InvalidParametersError('Name not given for UID.');
1475
+ }
1476
+ const result = yield this.queryGet(`SELECT "cur_uid" FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
1477
+ params: {
1478
+ name: name,
1479
+ },
1480
+ });
1481
+ return (result === null || result === void 0 ? void 0 : result.cur_uid) == null ? null : Number(result.cur_uid);
1482
+ });
1483
+ }
1484
+ import(filename) {
1485
+ return __awaiter(this, void 0, void 0, function* () {
1486
+ try {
1487
+ const result = yield this.importFromFile(filename, (guid, tags, sdata, etype) => __awaiter(this, void 0, void 0, function* () {
1488
+ yield this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
1489
+ etypes: [etype],
1490
+ params: {
1491
+ guid,
1492
+ },
1493
+ });
1494
+ yield this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate") VALUES (decode(@guid, 'hex'), @tags, @cdate, @mdate);`, {
1495
+ etypes: [etype],
1496
+ params: {
1497
+ guid,
1498
+ tags,
1499
+ cdate: isNaN(Number(JSON.parse(sdata.cdate)))
1500
+ ? null
1501
+ : Number(JSON.parse(sdata.cdate)),
1502
+ mdate: isNaN(Number(JSON.parse(sdata.mdate)))
1503
+ ? null
1504
+ : Number(JSON.parse(sdata.mdate)),
1505
+ },
1506
+ });
1507
+ const promises = [];
1508
+ promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
1509
+ etypes: [etype],
1510
+ params: {
1511
+ guid,
1512
+ },
1513
+ }));
1514
+ promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
1515
+ etypes: [etype],
1516
+ params: {
1517
+ guid,
1518
+ },
1519
+ }));
1520
+ promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
1521
+ etypes: [etype],
1522
+ params: {
1523
+ guid,
1524
+ },
1525
+ }));
1526
+ yield Promise.all(promises);
1527
+ delete sdata.cdate;
1528
+ delete sdata.mdate;
1529
+ for (const name in sdata) {
1530
+ const value = sdata[name];
1531
+ const uvalue = JSON.parse(value);
1532
+ if (value === undefined) {
1533
+ continue;
1534
+ }
1535
+ const storageValue = typeof uvalue === 'number'
1536
+ ? 'N'
1537
+ : typeof uvalue === 'string'
1538
+ ? 'S'
1539
+ : value;
1540
+ const promises = [];
1541
+ promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value") VALUES (decode(@guid, 'hex'), @name, @storageValue);`, {
1542
+ etypes: [etype],
1543
+ params: {
1544
+ guid,
1545
+ name,
1546
+ storageValue,
1547
+ },
1548
+ }));
1549
+ promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} ("guid", "name", "truthy", "string", "number") VALUES (decode(@guid, 'hex'), @name, @truthy, @string, @number);`, {
1550
+ etypes: [etype],
1551
+ params: {
1552
+ guid,
1553
+ name,
1554
+ truthy: !!uvalue,
1555
+ string: `${uvalue}`,
1556
+ number: isNaN(Number(uvalue)) ? null : Number(uvalue),
1557
+ },
1558
+ }));
1559
+ const references = this.findReferences(value);
1560
+ for (const reference of references) {
1561
+ promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} ("guid", "name", "reference") VALUES (decode(@guid, 'hex'), @name, decode(@reference, 'hex'));`, {
1562
+ etypes: [etype],
1563
+ params: {
1564
+ guid,
1565
+ name,
1566
+ reference,
1567
+ },
1568
+ }));
1569
+ }
1570
+ }
1571
+ yield Promise.all(promises);
1572
+ }), (name, curUid) => __awaiter(this, void 0, void 0, function* () {
1573
+ yield this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
1574
+ params: {
1575
+ name,
1576
+ },
1577
+ });
1578
+ yield this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @curUid);`, {
1579
+ params: {
1580
+ name,
1581
+ curUid,
1582
+ },
1583
+ });
1584
+ }), () => __awaiter(this, void 0, void 0, function* () {
1585
+ yield this.internalTransaction('nymph-import');
1586
+ }), () => __awaiter(this, void 0, void 0, function* () {
1587
+ yield this.commit('nymph-import');
1588
+ }));
1589
+ return result;
1590
+ }
1591
+ catch (e) {
1592
+ yield this.rollback('nymph-import');
1593
+ return false;
1594
+ }
1595
+ });
1596
+ }
1597
+ newUID(name) {
1598
+ return __awaiter(this, void 0, void 0, function* () {
1599
+ if (name == null) {
1600
+ throw new nymph_1.InvalidParametersError('Name not given for UID.');
1601
+ }
1602
+ yield this.internalTransaction('nymph-newuid');
1603
+ try {
1604
+ const lock = yield this.queryGet(`SELECT "cur_uid" FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name FOR UPDATE;`, {
1605
+ params: {
1606
+ name,
1607
+ },
1608
+ });
1609
+ let curUid = (lock === null || lock === void 0 ? void 0 : lock.cur_uid) == null ? undefined : Number(lock.cur_uid);
1610
+ if (curUid == null) {
1611
+ curUid = 1;
1612
+ yield this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @curUid);`, {
1613
+ params: {
1614
+ name,
1615
+ curUid,
1616
+ },
1617
+ });
1618
+ }
1619
+ else {
1620
+ curUid++;
1621
+ yield this.queryRun(`UPDATE ${PostgreSQLDriver.escape(`${this.prefix}uids`)} SET "cur_uid"=@curUid WHERE "name"=@name;`, {
1622
+ params: {
1623
+ name,
1624
+ curUid,
1625
+ },
1626
+ });
1627
+ }
1628
+ yield this.commit('nymph-newuid');
1629
+ return curUid;
1630
+ }
1631
+ catch (e) {
1632
+ yield this.rollback('nymph-newuid');
1633
+ throw e;
1634
+ }
1635
+ });
1636
+ }
1637
+ renameUID(oldName, newName) {
1638
+ return __awaiter(this, void 0, void 0, function* () {
1639
+ if (oldName == null || newName == null) {
1640
+ throw new nymph_1.InvalidParametersError('Name not given for UID.');
1641
+ }
1642
+ yield this.queryRun(`UPDATE ${PostgreSQLDriver.escape(`${this.prefix}uids`)} SET "name"=@newName WHERE "name"=@oldName;`, {
1643
+ params: {
1644
+ newName,
1645
+ oldName,
1646
+ },
1647
+ });
1648
+ return true;
1649
+ });
1650
+ }
1651
+ rollback(name) {
1652
+ var _a;
1653
+ return __awaiter(this, void 0, void 0, function* () {
1654
+ if (name == null || typeof name !== 'string' || name.length === 0) {
1655
+ throw new nymph_1.InvalidParametersError('Transaction rollback attempted without a name.');
1656
+ }
1657
+ if (!this.transaction || this.transaction.count === 0) {
1658
+ this.transaction = null;
1659
+ return true;
1660
+ }
1661
+ yield this.queryRun(`ROLLBACK TO SAVEPOINT ${PostgreSQLDriver.escape(name)};`);
1662
+ this.transaction.count--;
1663
+ if (this.transaction.count === 0) {
1664
+ yield this.queryRun('ROLLBACK;');
1665
+ (_a = this.transaction.connection) === null || _a === void 0 ? void 0 : _a.done();
1666
+ this.transaction.connection = null;
1667
+ this.transaction = null;
1668
+ }
1669
+ return true;
1670
+ });
1671
+ }
1672
+ saveEntity(entity) {
1673
+ return __awaiter(this, void 0, void 0, function* () {
1674
+ const insertData = (guid, data, sdata, etype) => __awaiter(this, void 0, void 0, function* () {
1675
+ const runInsertQuery = (name, value, svalue) => __awaiter(this, void 0, void 0, function* () {
1676
+ if (value === undefined) {
1677
+ return;
1678
+ }
1679
+ const storageValue = typeof value === 'number'
1680
+ ? 'N'
1681
+ : typeof value === 'string'
1682
+ ? 'S'
1683
+ : svalue;
1684
+ const promises = [];
1685
+ promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value") VALUES (decode(@guid, 'hex'), @name, @storageValue);`, {
1686
+ etypes: [etype],
1687
+ params: {
1688
+ guid,
1689
+ name,
1690
+ storageValue,
1691
+ },
1692
+ }));
1693
+ promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} ("guid", "name", "truthy", "string", "number") VALUES (decode(@guid, 'hex'), @name, @truthy, @string, @number);`, {
1694
+ etypes: [etype],
1695
+ params: {
1696
+ guid,
1697
+ name,
1698
+ truthy: !!value,
1699
+ string: `${value}`,
1700
+ number: isNaN(Number(value)) ? null : Number(value),
1701
+ },
1702
+ }));
1703
+ const references = this.findReferences(svalue);
1704
+ for (const reference of references) {
1705
+ promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} ("guid", "name", "reference") VALUES (decode(@guid, 'hex'), @name, decode(@reference, 'hex'));`, {
1706
+ etypes: [etype],
1707
+ params: {
1708
+ guid,
1709
+ name,
1710
+ reference,
1711
+ },
1712
+ }));
1713
+ }
1714
+ yield Promise.all(promises);
1715
+ });
1716
+ for (const name in data) {
1717
+ yield runInsertQuery(name, data[name], JSON.stringify(data[name]));
1718
+ }
1719
+ for (const name in sdata) {
1720
+ yield runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
1721
+ }
1722
+ });
1723
+ try {
1724
+ const result = yield this.saveEntityRowLike(entity, (_entity, guid, tags, data, sdata, cdate, etype) => __awaiter(this, void 0, void 0, function* () {
1725
+ yield this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate") VALUES (decode(@guid, 'hex'), @tags, @cdate, @cdate);`, {
1726
+ etypes: [etype],
1727
+ params: {
1728
+ guid,
1729
+ tags,
1730
+ cdate,
1731
+ },
1732
+ });
1733
+ yield insertData(guid, data, sdata, etype);
1734
+ return true;
1735
+ }), (entity, guid, tags, data, sdata, mdate, etype) => __awaiter(this, void 0, void 0, function* () {
1736
+ const promises = [];
1737
+ promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=decode(@guid, 'hex') FOR UPDATE;`, {
1738
+ etypes: [etype],
1739
+ params: {
1740
+ guid,
1741
+ },
1742
+ }));
1743
+ promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} WHERE "guid"=decode(@guid, 'hex') FOR UPDATE;`, {
1744
+ etypes: [etype],
1745
+ params: {
1746
+ guid,
1747
+ },
1748
+ }));
1749
+ promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} WHERE "guid"=decode(@guid, 'hex') FOR UPDATE;`, {
1750
+ etypes: [etype],
1751
+ params: {
1752
+ guid,
1753
+ },
1754
+ }));
1755
+ promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=decode(@guid, 'hex') FOR UPDATE;`, {
1756
+ etypes: [etype],
1757
+ params: {
1758
+ guid,
1759
+ },
1760
+ }));
1761
+ yield Promise.all(promises);
1762
+ const info = yield this.queryRun(`UPDATE ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} SET "tags"=@tags, "mdate"=@mdate WHERE "guid"=decode(@guid, 'hex') AND "mdate" <= @emdate;`, {
1763
+ etypes: [etype],
1764
+ params: {
1765
+ tags,
1766
+ mdate,
1767
+ guid,
1768
+ emdate: isNaN(Number(entity.mdate)) ? 0 : Number(entity.mdate),
1769
+ },
1770
+ });
1771
+ let success = false;
1772
+ if (info.rowCount === 1) {
1773
+ const promises = [];
1774
+ promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
1775
+ etypes: [etype],
1776
+ params: {
1777
+ guid,
1778
+ },
1779
+ }));
1780
+ promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
1781
+ etypes: [etype],
1782
+ params: {
1783
+ guid,
1784
+ },
1785
+ }));
1786
+ promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
1787
+ etypes: [etype],
1788
+ params: {
1789
+ guid,
1790
+ },
1791
+ }));
1792
+ yield Promise.all(promises);
1793
+ yield insertData(guid, data, sdata, etype);
1794
+ success = true;
1795
+ }
1796
+ return success;
1797
+ }), () => __awaiter(this, void 0, void 0, function* () {
1798
+ yield this.internalTransaction('nymph-save');
1799
+ }), (success) => __awaiter(this, void 0, void 0, function* () {
1800
+ if (success) {
1801
+ yield this.commit('nymph-save');
1802
+ }
1803
+ else {
1804
+ yield this.rollback('nymph-save');
1805
+ }
1806
+ return success;
1807
+ }));
1808
+ return result;
1809
+ }
1810
+ catch (e) {
1811
+ yield this.rollback('nymph-save');
1812
+ throw e;
1813
+ }
1814
+ });
1815
+ }
1816
+ setUID(name, curUid) {
1817
+ return __awaiter(this, void 0, void 0, function* () {
1818
+ if (name == null) {
1819
+ throw new nymph_1.InvalidParametersError('Name not given for UID.');
1820
+ }
1821
+ yield this.internalTransaction('nymph-setuid');
1822
+ try {
1823
+ yield this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
1824
+ params: {
1825
+ name,
1826
+ curUid,
1827
+ },
1828
+ });
1829
+ yield this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @curUid);`, {
1830
+ params: {
1831
+ name,
1832
+ curUid,
1833
+ },
1834
+ });
1835
+ yield this.commit('nymph-setuid');
1836
+ return true;
1837
+ }
1838
+ catch (e) {
1839
+ yield this.rollback('nymph-setuid');
1840
+ throw e;
1841
+ }
1842
+ });
1843
+ }
1844
+ internalTransaction(name) {
1845
+ return __awaiter(this, void 0, void 0, function* () {
1846
+ if (name == null || typeof name !== 'string' || name.length === 0) {
1847
+ throw new nymph_1.InvalidParametersError('Transaction start attempted without a name.');
1848
+ }
1849
+ if (!this.transaction || this.transaction.count === 0) {
1850
+ this.transaction = {
1851
+ count: 0,
1852
+ connection: yield this.getConnection(),
1853
+ };
1854
+ yield this.queryRun('BEGIN;');
1855
+ }
1856
+ yield this.queryRun(`SAVEPOINT ${PostgreSQLDriver.escape(name)};`);
1857
+ this.transaction.count++;
1858
+ return this.transaction;
1859
+ });
1860
+ }
1861
+ startTransaction(name) {
1862
+ return __awaiter(this, void 0, void 0, function* () {
1863
+ const inTransaction = this.inTransaction();
1864
+ const transaction = yield this.internalTransaction(name);
1865
+ if (!inTransaction) {
1866
+ this.transaction = null;
1867
+ }
1868
+ const nymph = this.nymph.clone();
1869
+ nymph.driver = new PostgreSQLDriver(this.config, this.link, transaction);
1870
+ nymph.driver.init(nymph);
1871
+ return nymph;
1872
+ });
1873
+ }
1874
+ }
1875
+ exports.default = PostgreSQLDriver;
1876
+ //# sourceMappingURL=PostgreSQLDriver.js.map