@nymphjs/driver-postgresql 1.0.0-beta.9 → 1.0.0-beta.91
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 +401 -0
- package/README.md +1 -1
- package/dist/PostgreSQLDriver.d.ts +66 -20
- package/dist/PostgreSQLDriver.js +710 -542
- package/dist/PostgreSQLDriver.js.map +1 -1
- package/dist/PostgreSQLDriver.test.js +9 -12
- package/dist/PostgreSQLDriver.test.js.map +1 -1
- package/dist/conf/d.d.ts +26 -0
- package/dist/conf/d.js +1 -2
- 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 +2 -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 +11 -2
- package/package.json +22 -21
- package/src/PostgreSQLDriver.test.ts +5 -3
- package/src/PostgreSQLDriver.ts +1025 -873
- package/src/conf/defaults.ts +1 -1
- package/src/conf/index.ts +2 -2
- package/src/index.ts +2 -2
- package/tsconfig.json +5 -3
- package/typedoc.json +4 -0
- package/dist/runPostgresqlSync.js +0 -35
- package/src/runPostgresqlSync.js +0 -35
- package/src/testpostgresql.js +0 -59
package/dist/PostgreSQLDriver.js
CHANGED
|
@@ -1,26 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import pg from 'pg';
|
|
2
|
+
import format from 'pg-format';
|
|
3
|
+
import Cursor from 'pg-cursor';
|
|
4
|
+
import { NymphDriver, EntityUniqueConstraintError, InvalidParametersError, NotConfiguredError, QueryFailedError, UnableToConnectError, xor, } from '@nymphjs/nymph';
|
|
5
|
+
import { makeTableSuffix } from '@nymphjs/guid';
|
|
6
|
+
import { PostgreSQLDriverConfigDefaults as defaults, } from './conf/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* The PostgreSQL Nymph database driver.
|
|
9
|
+
*/
|
|
10
|
+
export default class PostgreSQLDriver extends NymphDriver {
|
|
11
|
+
config;
|
|
12
|
+
postgresqlConfig;
|
|
13
|
+
prefix;
|
|
14
|
+
connected = false;
|
|
15
|
+
// @ts-ignore: this is assigned in connect(), which is called by the constructor.
|
|
16
|
+
link;
|
|
17
|
+
transaction = null;
|
|
13
18
|
static escape(input) {
|
|
14
|
-
return
|
|
19
|
+
return format.ident(input);
|
|
15
20
|
}
|
|
16
21
|
static escapeValue(input) {
|
|
17
|
-
return
|
|
22
|
+
return format.literal(input);
|
|
23
|
+
}
|
|
24
|
+
static escapeNullSequences(input) {
|
|
25
|
+
// Postgres doesn't support null bytes in `text`, and it converts strings
|
|
26
|
+
// in JSON to `text`, so we need to escape the escape sequences for null
|
|
27
|
+
// bytes.
|
|
28
|
+
return (input
|
|
29
|
+
.replace(/\uFFFD/g, () => '\uFFFD\uFFFD')
|
|
30
|
+
// n so that if there's already an escape, it turns into \n
|
|
31
|
+
// - so that it won't match a \uFFFD that got turned into \uFFFD\uFFFD
|
|
32
|
+
.replace(/\\u0000/g, () => 'nu\uFFFD-')
|
|
33
|
+
.replace(/\\x00/g, () => 'nx\uFFFD-'));
|
|
34
|
+
}
|
|
35
|
+
static unescapeNullSequences(input) {
|
|
36
|
+
return input
|
|
37
|
+
.replace(/nu\uFFFD-/g, () => '\\u0000')
|
|
38
|
+
.replace(/nx\uFFFD-/g, () => '\\x00')
|
|
39
|
+
.replace(/\uFFFD\uFFFD/g, () => '\uFFFD');
|
|
40
|
+
}
|
|
41
|
+
static escapeNulls(input) {
|
|
42
|
+
// Postgres doesn't support null bytes in `text`.
|
|
43
|
+
return input
|
|
44
|
+
.replace(/\uFFFD/g, () => '\uFFFD\uFFFD')
|
|
45
|
+
.replace(/\x00/g, () => '-\uFFFD-');
|
|
46
|
+
}
|
|
47
|
+
static unescapeNulls(input) {
|
|
48
|
+
return input
|
|
49
|
+
.replace(/-\uFFFD-/g, () => '\x00')
|
|
50
|
+
.replace(/\uFFFD\uFFFD/g, () => '\uFFFD');
|
|
18
51
|
}
|
|
19
52
|
constructor(config, link, transaction) {
|
|
20
53
|
super();
|
|
21
|
-
this.
|
|
22
|
-
this.transaction = null;
|
|
23
|
-
this.config = { ...conf_1.PostgreSQLDriverConfigDefaults, ...config };
|
|
54
|
+
this.config = { ...defaults, ...config };
|
|
24
55
|
const { host, user, password, database, port, customPoolConfig } = this.config;
|
|
25
56
|
this.postgresqlConfig = customPoolConfig ?? {
|
|
26
57
|
host,
|
|
@@ -41,19 +72,40 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
41
72
|
this.connect();
|
|
42
73
|
}
|
|
43
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* This is used internally by Nymph. Don't call it yourself.
|
|
77
|
+
*
|
|
78
|
+
* @returns A clone of this instance.
|
|
79
|
+
*/
|
|
44
80
|
clone() {
|
|
45
81
|
return new PostgreSQLDriver(this.config, this.link, this.transaction ?? undefined);
|
|
46
82
|
}
|
|
47
|
-
getConnection() {
|
|
48
|
-
if (this.transaction != null &&
|
|
83
|
+
getConnection(outsideTransaction = false) {
|
|
84
|
+
if (this.transaction != null &&
|
|
85
|
+
this.transaction.connection != null &&
|
|
86
|
+
!outsideTransaction) {
|
|
49
87
|
return Promise.resolve(this.transaction.connection);
|
|
50
88
|
}
|
|
51
|
-
return new Promise((resolve, reject) => this.link.connect((err, client, done) => err
|
|
89
|
+
return new Promise((resolve, reject) => this.link.connect((err, client, done) => err
|
|
90
|
+
? reject(err)
|
|
91
|
+
: client
|
|
92
|
+
? resolve({ client, done })
|
|
93
|
+
: reject('No client returned from connect.')));
|
|
52
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Connect to the PostgreSQL database.
|
|
97
|
+
*
|
|
98
|
+
* @returns Whether this instance is connected to a PostgreSQL database.
|
|
99
|
+
*/
|
|
53
100
|
async connect() {
|
|
101
|
+
// If we think we're connected, try pinging the server.
|
|
54
102
|
try {
|
|
55
103
|
if (this.connected) {
|
|
56
|
-
const connection = await new Promise((resolve, reject) => this.link.connect((err, client, done) => err
|
|
104
|
+
const connection = await new Promise((resolve, reject) => this.link.connect((err, client, done) => err
|
|
105
|
+
? reject(err)
|
|
106
|
+
: client
|
|
107
|
+
? resolve({ client, done })
|
|
108
|
+
: reject('No client returned from connect.')));
|
|
57
109
|
await new Promise((resolve, reject) => connection.client.query('SELECT 1;', [], (err, res) => {
|
|
58
110
|
if (err) {
|
|
59
111
|
reject(err);
|
|
@@ -66,9 +118,10 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
66
118
|
catch (e) {
|
|
67
119
|
this.connected = false;
|
|
68
120
|
}
|
|
121
|
+
// Connecting, selecting database
|
|
69
122
|
if (!this.connected) {
|
|
70
123
|
try {
|
|
71
|
-
this.link = new
|
|
124
|
+
this.link = new pg.Pool(this.postgresqlConfig);
|
|
72
125
|
this.connected = true;
|
|
73
126
|
}
|
|
74
127
|
catch (e) {
|
|
@@ -76,15 +129,20 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
76
129
|
this.postgresqlConfig.user === 'nymph' &&
|
|
77
130
|
this.postgresqlConfig.password === 'password' &&
|
|
78
131
|
this.postgresqlConfig.database === 'nymph') {
|
|
79
|
-
throw new
|
|
132
|
+
throw new NotConfiguredError("It seems the config hasn't been set up correctly.");
|
|
80
133
|
}
|
|
81
134
|
else {
|
|
82
|
-
throw new
|
|
135
|
+
throw new UnableToConnectError('Could not connect: ' + e?.message);
|
|
83
136
|
}
|
|
84
137
|
}
|
|
85
138
|
}
|
|
86
139
|
return this.connected;
|
|
87
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Disconnect from the PostgreSQL database.
|
|
143
|
+
*
|
|
144
|
+
* @returns Whether this instance is connected to a PostgreSQL database.
|
|
145
|
+
*/
|
|
88
146
|
async disconnect() {
|
|
89
147
|
if (this.connected) {
|
|
90
148
|
await new Promise((resolve) => this.link.end(() => resolve(0)));
|
|
@@ -93,87 +151,121 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
93
151
|
return this.connected;
|
|
94
152
|
}
|
|
95
153
|
async inTransaction() {
|
|
154
|
+
if (this.transaction && this.transaction.count === 0) {
|
|
155
|
+
this.transaction = null;
|
|
156
|
+
}
|
|
96
157
|
return !!this.transaction;
|
|
97
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Check connection status.
|
|
161
|
+
*
|
|
162
|
+
* @returns Whether this instance is connected to a PostgreSQL database.
|
|
163
|
+
*/
|
|
98
164
|
isConnected() {
|
|
99
165
|
return this.connected;
|
|
100
166
|
}
|
|
101
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Create entity tables in the database.
|
|
169
|
+
*
|
|
170
|
+
* @param etype The entity type to create a table for. If this is blank, the default tables are created.
|
|
171
|
+
* @returns True on success, false on failure.
|
|
172
|
+
*/
|
|
173
|
+
async createTables(etype = null) {
|
|
174
|
+
const connection = await this.getConnection(true);
|
|
102
175
|
if (etype != null) {
|
|
103
|
-
|
|
176
|
+
// Create the entity table.
|
|
177
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} (
|
|
104
178
|
"guid" BYTEA NOT NULL,
|
|
105
179
|
"tags" TEXT[],
|
|
106
180
|
"cdate" DOUBLE PRECISION NOT NULL,
|
|
107
181
|
"mdate" DOUBLE PRECISION NOT NULL,
|
|
108
182
|
PRIMARY KEY ("guid")
|
|
109
|
-
) WITH ( OIDS=FALSE )
|
|
110
|
-
this.
|
|
111
|
-
this.
|
|
112
|
-
this.
|
|
113
|
-
this.
|
|
114
|
-
this.
|
|
115
|
-
this.
|
|
116
|
-
this.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
"name" TEXT NOT NULL,
|
|
120
|
-
"value" TEXT NOT NULL,
|
|
121
|
-
PRIMARY KEY ("guid", "name"),
|
|
122
|
-
FOREIGN KEY ("guid")
|
|
123
|
-
REFERENCES ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
|
|
124
|
-
) WITH ( OIDS=FALSE );`);
|
|
125
|
-
this.queryRunSync(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`);
|
|
126
|
-
this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid`)};`);
|
|
127
|
-
this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("guid");`);
|
|
128
|
-
this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name`)};`);
|
|
129
|
-
this.queryRunSync(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("name");`);
|
|
130
|
-
this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name__user`)};`);
|
|
131
|
-
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;`);
|
|
132
|
-
this.queryRunSync(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name__group`)};`);
|
|
133
|
-
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;`);
|
|
134
|
-
this.queryRunSync(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}comparisons_${etype}`)} (
|
|
183
|
+
) WITH ( OIDS=FALSE );`, { connection });
|
|
184
|
+
await this.queryRun(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`, { connection });
|
|
185
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_cdate`)};`, { connection });
|
|
186
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_cdate`)} ON ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} USING btree ("cdate");`, { connection });
|
|
187
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_mdate`)};`, { connection });
|
|
188
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_mdate`)} ON ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} USING btree ("mdate");`, { connection });
|
|
189
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_tags`)};`, { connection });
|
|
190
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}_id_tags`)} ON ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} USING gin ("tags");`, { connection });
|
|
191
|
+
// Create the data table.
|
|
192
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} (
|
|
135
193
|
"guid" BYTEA NOT NULL,
|
|
136
194
|
"name" TEXT NOT NULL,
|
|
137
|
-
"
|
|
195
|
+
"value" CHARACTER(1) NOT NULL,
|
|
196
|
+
"json" JSONB,
|
|
138
197
|
"string" TEXT,
|
|
139
198
|
"number" DOUBLE PRECISION,
|
|
199
|
+
"truthy" BOOLEAN,
|
|
140
200
|
PRIMARY KEY ("guid", "name"),
|
|
141
201
|
FOREIGN KEY ("guid")
|
|
142
202
|
REFERENCES ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
|
|
143
|
-
) WITH ( OIDS=FALSE )
|
|
144
|
-
this.
|
|
145
|
-
this.
|
|
146
|
-
this.
|
|
147
|
-
this.
|
|
148
|
-
this.
|
|
149
|
-
this.
|
|
150
|
-
this.
|
|
151
|
-
this.
|
|
152
|
-
this.
|
|
153
|
-
this.
|
|
203
|
+
) WITH ( OIDS=FALSE );`, { connection });
|
|
204
|
+
await this.queryRun(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`, { connection });
|
|
205
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid`)};`, { connection });
|
|
206
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("guid");`, { connection });
|
|
207
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name`)};`, { connection });
|
|
208
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("guid", "name");`, { connection });
|
|
209
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name__user`)};`, { connection });
|
|
210
|
+
await this.queryRun(`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;`, { connection });
|
|
211
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_guid_name__group`)};`, { connection });
|
|
212
|
+
await this.queryRun(`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;`, { connection });
|
|
213
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name`)};`, { connection });
|
|
214
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("name");`, { connection });
|
|
215
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name_string`)};`, { connection });
|
|
216
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name_string`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("name", LEFT("string", 512));`, { connection });
|
|
217
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name_number`)};`, { connection });
|
|
218
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name_number`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("name", "number");`, { connection });
|
|
219
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name_truthy`)};`, { connection });
|
|
220
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name_truthy`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("name") WHERE "truthy" = TRUE;`, { connection });
|
|
221
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name_falsy`)};`, { connection });
|
|
222
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_name_falsy`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING btree ("name") WHERE "truthy" <> TRUE;`, { connection });
|
|
223
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_string`)};`, { connection });
|
|
224
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_string`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING gin ("string" gin_trgm_ops);`, { connection });
|
|
225
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_json`)};`, { connection });
|
|
226
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}_id_json`)} ON ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} USING gin ("json");`, { connection });
|
|
227
|
+
// Create the references table.
|
|
228
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} (
|
|
154
229
|
"guid" BYTEA NOT NULL,
|
|
155
230
|
"name" TEXT NOT NULL,
|
|
156
231
|
"reference" BYTEA NOT NULL,
|
|
157
232
|
PRIMARY KEY ("guid", "name", "reference"),
|
|
158
233
|
FOREIGN KEY ("guid")
|
|
159
234
|
REFERENCES ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
|
|
160
|
-
) WITH ( OIDS=FALSE )
|
|
161
|
-
this.
|
|
162
|
-
this.
|
|
163
|
-
this.
|
|
164
|
-
this.
|
|
165
|
-
this.
|
|
166
|
-
this.
|
|
167
|
-
this.
|
|
235
|
+
) WITH ( OIDS=FALSE );`, { connection });
|
|
236
|
+
await this.queryRun(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`, { connection });
|
|
237
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_guid`)};`, { connection });
|
|
238
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} USING btree ("guid");`, { connection });
|
|
239
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_name`)};`, { connection });
|
|
240
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} USING btree ("name");`, { connection });
|
|
241
|
+
await this.queryRun(`DROP INDEX IF EXISTS ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_name_reference`)};`, { connection });
|
|
242
|
+
await this.queryRun(`CREATE INDEX ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}_id_name_reference`)} ON ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} USING btree ("name", "reference");`, { connection });
|
|
243
|
+
// Create the unique strings table.
|
|
244
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}uniques_${etype}`)} (
|
|
245
|
+
"guid" BYTEA NOT NULL,
|
|
246
|
+
"unique" TEXT NOT NULL UNIQUE,
|
|
247
|
+
PRIMARY KEY ("guid", "unique"),
|
|
248
|
+
FOREIGN KEY ("guid")
|
|
249
|
+
REFERENCES ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid") MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
|
|
250
|
+
) WITH ( OIDS=FALSE );`, { connection });
|
|
168
251
|
}
|
|
169
252
|
else {
|
|
170
|
-
|
|
253
|
+
// Add trigram extensions.
|
|
254
|
+
try {
|
|
255
|
+
await this.queryRun(`CREATE EXTENSION pg_trgm;`, { connection });
|
|
256
|
+
}
|
|
257
|
+
catch (e) {
|
|
258
|
+
// Ignore errors.
|
|
259
|
+
}
|
|
260
|
+
// Create the UID table.
|
|
261
|
+
await this.queryRun(`CREATE TABLE IF NOT EXISTS ${PostgreSQLDriver.escape(`${this.prefix}uids`)} (
|
|
171
262
|
"name" TEXT NOT NULL,
|
|
172
263
|
"cur_uid" BIGINT NOT NULL,
|
|
173
264
|
PRIMARY KEY ("name")
|
|
174
|
-
) WITH ( OIDS = FALSE )
|
|
175
|
-
this.
|
|
265
|
+
) WITH ( OIDS = FALSE );`, { connection });
|
|
266
|
+
await this.queryRun(`ALTER TABLE ${PostgreSQLDriver.escape(`${this.prefix}uids`)} OWNER TO ${PostgreSQLDriver.escape(this.config.user)};`, { connection });
|
|
176
267
|
}
|
|
268
|
+
connection.done();
|
|
177
269
|
return true;
|
|
178
270
|
}
|
|
179
271
|
translateQuery(origQuery, origParams) {
|
|
@@ -191,49 +283,32 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
191
283
|
}
|
|
192
284
|
async query(runQuery, query, etypes = []) {
|
|
193
285
|
try {
|
|
286
|
+
this.nymph.config.debugInfo('postgresql:query', query);
|
|
194
287
|
return await runQuery();
|
|
195
288
|
}
|
|
196
289
|
catch (e) {
|
|
197
290
|
const errorCode = e?.code;
|
|
198
|
-
if (errorCode === '42P01' && this.createTables()) {
|
|
291
|
+
if (errorCode === '42P01' && (await this.createTables())) {
|
|
292
|
+
// If the tables don't exist yet, create them.
|
|
199
293
|
for (let etype of etypes) {
|
|
200
|
-
this.createTables(etype);
|
|
294
|
+
await this.createTables(etype);
|
|
201
295
|
}
|
|
202
296
|
try {
|
|
203
297
|
return await runQuery();
|
|
204
298
|
}
|
|
205
299
|
catch (e2) {
|
|
206
|
-
throw new
|
|
300
|
+
throw new QueryFailedError('Query failed: ' + e2?.code + ' - ' + e2?.message, query);
|
|
207
301
|
}
|
|
208
302
|
}
|
|
209
|
-
else {
|
|
210
|
-
throw
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
querySync(runQuery, query, etypes = []) {
|
|
215
|
-
try {
|
|
216
|
-
return runQuery();
|
|
217
|
-
}
|
|
218
|
-
catch (e) {
|
|
219
|
-
const errorCode = e?.code;
|
|
220
|
-
if (errorCode === '42P01' && this.createTables()) {
|
|
221
|
-
for (let etype of etypes) {
|
|
222
|
-
this.createTables(etype);
|
|
223
|
-
}
|
|
224
|
-
try {
|
|
225
|
-
return runQuery();
|
|
226
|
-
}
|
|
227
|
-
catch (e2) {
|
|
228
|
-
throw new nymph_1.QueryFailedError('Query failed: ' + e2?.code + ' - ' + e2?.message, query);
|
|
229
|
-
}
|
|
303
|
+
else if (errorCode === '23505') {
|
|
304
|
+
throw new EntityUniqueConstraintError(`Unique constraint violation.`);
|
|
230
305
|
}
|
|
231
306
|
else {
|
|
232
|
-
throw e;
|
|
307
|
+
throw new QueryFailedError('Query failed: ' + e?.code + ' - ' + e?.message, query);
|
|
233
308
|
}
|
|
234
309
|
}
|
|
235
310
|
}
|
|
236
|
-
|
|
311
|
+
queryArray(query, { etypes = [], params = {}, } = {}) {
|
|
237
312
|
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
238
313
|
return this.query(async () => {
|
|
239
314
|
const results = await new Promise((resolve, reject) => {
|
|
@@ -249,32 +324,30 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
249
324
|
return results.rows;
|
|
250
325
|
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
251
326
|
}
|
|
252
|
-
|
|
327
|
+
async queryIter(query, { etypes = [], params = {}, } = {}) {
|
|
253
328
|
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
for (const name in err) {
|
|
277
|
-
e[name] = err[name];
|
|
329
|
+
const that = this;
|
|
330
|
+
return this.query(async function* () {
|
|
331
|
+
const transaction = !!that.transaction?.connection;
|
|
332
|
+
const connection = await that.getConnection();
|
|
333
|
+
const cursor = new Cursor(newQuery, newParams);
|
|
334
|
+
const iter = connection.client.query(cursor);
|
|
335
|
+
while (true) {
|
|
336
|
+
const rows = await iter.read(100);
|
|
337
|
+
if (!rows.length) {
|
|
338
|
+
await new Promise((resolve) => {
|
|
339
|
+
iter.close(() => {
|
|
340
|
+
if (!transaction) {
|
|
341
|
+
connection.done();
|
|
342
|
+
}
|
|
343
|
+
resolve();
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
for (let row of rows) {
|
|
349
|
+
yield row;
|
|
350
|
+
}
|
|
278
351
|
}
|
|
279
352
|
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
280
353
|
}
|
|
@@ -294,12 +367,13 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
294
367
|
return results.rows[0];
|
|
295
368
|
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
296
369
|
}
|
|
297
|
-
queryRun(query, { etypes = [], params = {}, } = {}) {
|
|
370
|
+
queryRun(query, { etypes = [], params = {}, connection, } = {}) {
|
|
298
371
|
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
299
372
|
return this.query(async () => {
|
|
300
373
|
const results = await new Promise((resolve, reject) => {
|
|
301
374
|
try {
|
|
302
|
-
(this.transaction?.connection?.client ??
|
|
375
|
+
((connection ?? this.transaction?.connection)?.client ??
|
|
376
|
+
this.link)
|
|
303
377
|
.query(newQuery, newParams)
|
|
304
378
|
.then((results) => resolve(results), (error) => reject(error));
|
|
305
379
|
}
|
|
@@ -310,39 +384,9 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
310
384
|
return { rowCount: results.rowCount ?? 0 };
|
|
311
385
|
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
312
386
|
}
|
|
313
|
-
queryRunSync(query, { etypes = [], params = {}, } = {}) {
|
|
314
|
-
const { query: newQuery, params: newParams } = this.translateQuery(query, params);
|
|
315
|
-
return this.querySync(() => {
|
|
316
|
-
const output = child_process_1.default.spawnSync(process.argv0, [__dirname + '/runPostgresqlSync.js'], {
|
|
317
|
-
input: JSON.stringify({
|
|
318
|
-
postgresqlConfig: this.postgresqlConfig,
|
|
319
|
-
query: newQuery,
|
|
320
|
-
params: newParams,
|
|
321
|
-
}),
|
|
322
|
-
timeout: 30000,
|
|
323
|
-
maxBuffer: 100 * 1024 * 1024,
|
|
324
|
-
encoding: 'utf8',
|
|
325
|
-
windowsHide: true,
|
|
326
|
-
});
|
|
327
|
-
try {
|
|
328
|
-
const results = JSON.parse(output.stdout);
|
|
329
|
-
return { rowCount: results.rowCount ?? 0 };
|
|
330
|
-
}
|
|
331
|
-
catch (e) {
|
|
332
|
-
}
|
|
333
|
-
if (output.status === 0) {
|
|
334
|
-
throw new Error('Unknown parse error.');
|
|
335
|
-
}
|
|
336
|
-
const err = JSON.parse(output.stderr);
|
|
337
|
-
const e = new Error(err.name);
|
|
338
|
-
for (const name in err) {
|
|
339
|
-
e[name] = err[name];
|
|
340
|
-
}
|
|
341
|
-
}, `${query} -- ${JSON.stringify(params)}`, etypes);
|
|
342
|
-
}
|
|
343
387
|
async commit(name) {
|
|
344
388
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
345
|
-
throw new
|
|
389
|
+
throw new InvalidParametersError('Transaction commit attempted without a name.');
|
|
346
390
|
}
|
|
347
391
|
if (!this.transaction || this.transaction.count === 0) {
|
|
348
392
|
this.transaction = null;
|
|
@@ -382,32 +426,34 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
382
426
|
guid,
|
|
383
427
|
},
|
|
384
428
|
});
|
|
385
|
-
await this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}
|
|
429
|
+
await this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
|
|
386
430
|
etypes: [etype],
|
|
387
431
|
params: {
|
|
388
432
|
guid,
|
|
389
433
|
},
|
|
390
434
|
});
|
|
391
|
-
await this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}
|
|
435
|
+
await this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
|
|
392
436
|
etypes: [etype],
|
|
393
437
|
params: {
|
|
394
438
|
guid,
|
|
395
439
|
},
|
|
396
440
|
});
|
|
397
|
-
await this.commit('nymph-delete');
|
|
398
|
-
if (this.nymph.config.cache) {
|
|
399
|
-
this.cleanCache(guid);
|
|
400
|
-
}
|
|
401
|
-
return true;
|
|
402
441
|
}
|
|
403
442
|
catch (e) {
|
|
443
|
+
this.nymph.config.debugError('postgresql', `Delete entity error: "${e}"`);
|
|
404
444
|
await this.rollback('nymph-delete');
|
|
405
445
|
throw e;
|
|
406
446
|
}
|
|
447
|
+
await this.commit('nymph-delete');
|
|
448
|
+
// Remove any cached versions of this entity.
|
|
449
|
+
if (this.nymph.config.cache) {
|
|
450
|
+
this.cleanCache(guid);
|
|
451
|
+
}
|
|
452
|
+
return true;
|
|
407
453
|
}
|
|
408
454
|
async deleteUID(name) {
|
|
409
455
|
if (!name) {
|
|
410
|
-
throw new
|
|
456
|
+
throw new InvalidParametersError('Name not given for UID');
|
|
411
457
|
}
|
|
412
458
|
await this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
413
459
|
params: {
|
|
@@ -416,79 +462,124 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
416
462
|
});
|
|
417
463
|
return true;
|
|
418
464
|
}
|
|
419
|
-
async
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
465
|
+
async *exportDataIterator() {
|
|
466
|
+
if (yield {
|
|
467
|
+
type: 'comment',
|
|
468
|
+
content: `#nex2
|
|
469
|
+
# Nymph Entity Exchange v2
|
|
470
|
+
# http://nymph.io
|
|
471
|
+
#
|
|
472
|
+
# Generation Time: ${new Date().toLocaleString()}
|
|
473
|
+
`,
|
|
474
|
+
}) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if (yield {
|
|
478
|
+
type: 'comment',
|
|
479
|
+
content: `
|
|
480
|
+
|
|
481
|
+
#
|
|
482
|
+
# UIDs
|
|
483
|
+
#
|
|
484
|
+
|
|
485
|
+
`,
|
|
486
|
+
}) {
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
// Export UIDs.
|
|
430
490
|
let uids = await this.queryIter(`SELECT * FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} ORDER BY "name";`);
|
|
431
|
-
for (const uid of uids) {
|
|
432
|
-
|
|
491
|
+
for await (const uid of uids) {
|
|
492
|
+
if (yield { type: 'uid', content: `<${uid.name}>[${uid.cur_uid}]\n` }) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (yield {
|
|
497
|
+
type: 'comment',
|
|
498
|
+
content: `
|
|
499
|
+
|
|
500
|
+
#
|
|
501
|
+
# Entities
|
|
502
|
+
#
|
|
503
|
+
|
|
504
|
+
`,
|
|
505
|
+
}) {
|
|
506
|
+
return;
|
|
433
507
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
508
|
+
// Get the etypes.
|
|
509
|
+
const tables = await this.queryArray('SELECT "table_name" AS "table_name" FROM "information_schema"."tables" WHERE "table_catalog"=@db AND "table_schema"=\'public\' AND "table_name" LIKE @prefix;', {
|
|
510
|
+
params: {
|
|
511
|
+
db: this.config.database,
|
|
512
|
+
prefix: this.prefix + 'entities_' + '%',
|
|
513
|
+
},
|
|
514
|
+
});
|
|
440
515
|
const etypes = [];
|
|
441
|
-
for (const
|
|
442
|
-
|
|
443
|
-
if (table.startsWith(this.prefix + 'entities_')) {
|
|
444
|
-
etypes.push(table.substr((this.prefix + 'entities_').length));
|
|
445
|
-
}
|
|
516
|
+
for (const table of tables) {
|
|
517
|
+
etypes.push(table.table_name.substr((this.prefix + 'entities_').length));
|
|
446
518
|
}
|
|
447
519
|
for (const etype of etypes) {
|
|
448
|
-
|
|
520
|
+
// Export entities.
|
|
521
|
+
const dataIterator = await this.queryIter(`SELECT encode(e."guid", 'hex') AS "guid", e."tags", e."cdate", e."mdate", d."name", d."value", d."json", d."string", d."number"
|
|
449
522
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} e
|
|
450
523
|
LEFT JOIN ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} d ON e."guid"=d."guid"
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
let datum = dataIterator.next();
|
|
524
|
+
ORDER BY e."guid";`);
|
|
525
|
+
let datum = await dataIterator.next();
|
|
454
526
|
while (!datum.done) {
|
|
455
527
|
const guid = datum.value.guid;
|
|
456
|
-
const tags = datum.value.tags.join(',');
|
|
528
|
+
const tags = datum.value.tags.filter((tag) => tag).join(',');
|
|
457
529
|
const cdate = datum.value.cdate;
|
|
458
530
|
const mdate = datum.value.mdate;
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
531
|
+
let currentEntityExport = [];
|
|
532
|
+
currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
|
|
533
|
+
currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
|
|
534
|
+
currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
|
|
535
|
+
if (datum.value.name != null) {
|
|
536
|
+
// This do will keep going and adding the data until the
|
|
537
|
+
// next entity is reached. $row will end on the next entity.
|
|
463
538
|
do {
|
|
464
|
-
const value = datum.value.
|
|
539
|
+
const value = datum.value.value === 'N'
|
|
465
540
|
? JSON.stringify(Number(datum.value.number))
|
|
466
|
-
: datum.value.
|
|
467
|
-
? JSON.stringify(datum.value.string)
|
|
468
|
-
: datum.value.
|
|
469
|
-
|
|
470
|
-
|
|
541
|
+
: datum.value.value === 'S'
|
|
542
|
+
? JSON.stringify(PostgreSQLDriver.unescapeNulls(datum.value.string))
|
|
543
|
+
: datum.value.value === 'J'
|
|
544
|
+
? PostgreSQLDriver.unescapeNullSequences(JSON.stringify(datum.value.json))
|
|
545
|
+
: datum.value.value;
|
|
546
|
+
currentEntityExport.push(`\t${datum.value.name}=${value}`);
|
|
547
|
+
datum = await dataIterator.next();
|
|
471
548
|
} while (!datum.done && datum.value.guid === guid);
|
|
472
549
|
}
|
|
473
550
|
else {
|
|
474
|
-
datum
|
|
551
|
+
// Make sure that datum is incremented :)
|
|
552
|
+
datum = await dataIterator.next();
|
|
553
|
+
}
|
|
554
|
+
currentEntityExport.push('');
|
|
555
|
+
if (yield { type: 'entity', content: currentEntityExport.join('\n') }) {
|
|
556
|
+
return;
|
|
475
557
|
}
|
|
476
558
|
}
|
|
477
559
|
}
|
|
478
|
-
return;
|
|
479
560
|
}
|
|
480
|
-
|
|
561
|
+
/**
|
|
562
|
+
* Generate the PostgreSQL query.
|
|
563
|
+
* @param options The options array.
|
|
564
|
+
* @param formattedSelectors The formatted selector array.
|
|
565
|
+
* @param etype
|
|
566
|
+
* @param count Used to track internal params.
|
|
567
|
+
* @param params Used to store internal params.
|
|
568
|
+
* @param subquery Whether only a subquery should be returned.
|
|
569
|
+
* @returns The SQL query.
|
|
570
|
+
*/
|
|
571
|
+
makeEntityQuery(options, formattedSelectors, etype, count = { i: 0 }, params = {}, subquery = false, tableSuffix = '', etypes = [], guidSelector = undefined) {
|
|
481
572
|
if (typeof options.class?.alterOptions === 'function') {
|
|
482
573
|
options = options.class.alterOptions(options);
|
|
483
574
|
}
|
|
484
575
|
const eTable = `e${tableSuffix}`;
|
|
485
576
|
const dTable = `d${tableSuffix}`;
|
|
486
|
-
const cTable = `c${tableSuffix}`;
|
|
487
577
|
const fTable = `f${tableSuffix}`;
|
|
488
578
|
const ieTable = `ie${tableSuffix}`;
|
|
489
579
|
const countTable = `count${tableSuffix}`;
|
|
580
|
+
const sTable = `s${tableSuffix}`;
|
|
490
581
|
const sort = options.sort ?? 'cdate';
|
|
491
|
-
const queryParts = this.iterateSelectorsForQuery(formattedSelectors, (key, value, typeIsOr, typeIsNot) => {
|
|
582
|
+
const queryParts = this.iterateSelectorsForQuery(formattedSelectors, ({ key, value, typeIsOr, typeIsNot }) => {
|
|
492
583
|
const clauseNot = key.startsWith('!');
|
|
493
584
|
let curQuery = '';
|
|
494
585
|
for (const curValue of value) {
|
|
@@ -501,7 +592,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
501
592
|
}
|
|
502
593
|
const guid = `param${++count.i}`;
|
|
503
594
|
curQuery +=
|
|
504
|
-
(
|
|
595
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
505
596
|
ieTable +
|
|
506
597
|
'."guid"=decode(@' +
|
|
507
598
|
guid +
|
|
@@ -517,7 +608,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
517
608
|
}
|
|
518
609
|
const tag = `param${++count.i}`;
|
|
519
610
|
curQuery +=
|
|
520
|
-
(
|
|
611
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
521
612
|
'@' +
|
|
522
613
|
tag +
|
|
523
614
|
' <@ ie."tags"';
|
|
@@ -532,12 +623,12 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
532
623
|
}
|
|
533
624
|
const name = `param${++count.i}`;
|
|
534
625
|
curQuery +=
|
|
535
|
-
|
|
536
|
-
'
|
|
537
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
538
|
-
'IN (SELECT "guid" FROM ' +
|
|
626
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
627
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
539
628
|
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
540
|
-
' WHERE "
|
|
629
|
+
' WHERE "guid"=' +
|
|
630
|
+
ieTable +
|
|
631
|
+
'."guid" AND "name"=@' +
|
|
541
632
|
name +
|
|
542
633
|
')';
|
|
543
634
|
params[name] = curVar;
|
|
@@ -551,7 +642,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
551
642
|
}
|
|
552
643
|
if (curVar === 'cdate') {
|
|
553
644
|
curQuery +=
|
|
554
|
-
(
|
|
645
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
555
646
|
'(' +
|
|
556
647
|
ieTable +
|
|
557
648
|
'."cdate" NOT NULL)';
|
|
@@ -559,7 +650,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
559
650
|
}
|
|
560
651
|
else if (curVar === 'mdate') {
|
|
561
652
|
curQuery +=
|
|
562
|
-
(
|
|
653
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
563
654
|
'(' +
|
|
564
655
|
ieTable +
|
|
565
656
|
'."mdate" NOT NULL)';
|
|
@@ -568,11 +659,12 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
568
659
|
else {
|
|
569
660
|
const name = `param${++count.i}`;
|
|
570
661
|
curQuery +=
|
|
571
|
-
(
|
|
662
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
663
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
664
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
665
|
+
' WHERE "guid"=' +
|
|
572
666
|
ieTable +
|
|
573
|
-
'."guid"
|
|
574
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
575
|
-
' WHERE "name"=@' +
|
|
667
|
+
'."guid" AND "name"=@' +
|
|
576
668
|
name +
|
|
577
669
|
' AND "truthy"=TRUE)';
|
|
578
670
|
params[name] = curVar;
|
|
@@ -587,7 +679,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
587
679
|
}
|
|
588
680
|
const cdate = `param${++count.i}`;
|
|
589
681
|
curQuery +=
|
|
590
|
-
(
|
|
682
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
591
683
|
ieTable +
|
|
592
684
|
'."cdate"=@' +
|
|
593
685
|
cdate;
|
|
@@ -602,7 +694,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
602
694
|
}
|
|
603
695
|
const mdate = `param${++count.i}`;
|
|
604
696
|
curQuery +=
|
|
605
|
-
(
|
|
697
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
606
698
|
ieTable +
|
|
607
699
|
'."mdate"=@' +
|
|
608
700
|
mdate;
|
|
@@ -618,11 +710,12 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
618
710
|
const name = `param${++count.i}`;
|
|
619
711
|
const value = `param${++count.i}`;
|
|
620
712
|
curQuery +=
|
|
621
|
-
(
|
|
713
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
714
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
715
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
716
|
+
' WHERE "guid"=' +
|
|
622
717
|
ieTable +
|
|
623
|
-
'."guid"
|
|
624
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
625
|
-
' WHERE "name"=@' +
|
|
718
|
+
'."guid" AND "name"=@' +
|
|
626
719
|
name +
|
|
627
720
|
' AND "number"=@' +
|
|
628
721
|
value +
|
|
@@ -637,17 +730,20 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
637
730
|
const name = `param${++count.i}`;
|
|
638
731
|
const value = `param${++count.i}`;
|
|
639
732
|
curQuery +=
|
|
640
|
-
(
|
|
733
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
734
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
735
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
736
|
+
' WHERE "guid"=' +
|
|
641
737
|
ieTable +
|
|
642
|
-
'."guid"
|
|
643
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
644
|
-
' WHERE "name"=@' +
|
|
738
|
+
'."guid" AND "name"=@' +
|
|
645
739
|
name +
|
|
646
|
-
' AND "string"
|
|
647
|
-
|
|
740
|
+
' AND "string"=' +
|
|
741
|
+
(curValue[1].length < 512
|
|
742
|
+
? 'LEFT(@' + value + ', 512)'
|
|
743
|
+
: '@' + value) +
|
|
648
744
|
')';
|
|
649
745
|
params[name] = curValue[0];
|
|
650
|
-
params[value] = curValue[1];
|
|
746
|
+
params[value] = PostgreSQLDriver.escapeNulls(curValue[1]);
|
|
651
747
|
}
|
|
652
748
|
else {
|
|
653
749
|
if (curQuery) {
|
|
@@ -664,17 +760,18 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
664
760
|
const name = `param${++count.i}`;
|
|
665
761
|
const value = `param${++count.i}`;
|
|
666
762
|
curQuery +=
|
|
667
|
-
(
|
|
668
|
-
|
|
669
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
763
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
764
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
670
765
|
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
671
|
-
' WHERE "
|
|
766
|
+
' WHERE "guid"=' +
|
|
767
|
+
ieTable +
|
|
768
|
+
'."guid" AND "name"=@' +
|
|
672
769
|
name +
|
|
673
|
-
' AND "
|
|
770
|
+
' AND "json"=@' +
|
|
674
771
|
value +
|
|
675
772
|
')';
|
|
676
773
|
params[name] = curValue[0];
|
|
677
|
-
params[value] = svalue;
|
|
774
|
+
params[value] = PostgreSQLDriver.escapeNullSequences(svalue);
|
|
678
775
|
}
|
|
679
776
|
break;
|
|
680
777
|
case 'contain':
|
|
@@ -685,9 +782,9 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
685
782
|
}
|
|
686
783
|
const cdate = `param${++count.i}`;
|
|
687
784
|
curQuery +=
|
|
688
|
-
(
|
|
785
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
689
786
|
ieTable +
|
|
690
|
-
'."cdate"
|
|
787
|
+
'."cdate"=@' +
|
|
691
788
|
cdate;
|
|
692
789
|
params[cdate] = isNaN(Number(curValue[1]))
|
|
693
790
|
? null
|
|
@@ -700,9 +797,9 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
700
797
|
}
|
|
701
798
|
const mdate = `param${++count.i}`;
|
|
702
799
|
curQuery +=
|
|
703
|
-
(
|
|
800
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
704
801
|
ieTable +
|
|
705
|
-
'."mdate"
|
|
802
|
+
'."mdate"=@' +
|
|
706
803
|
mdate;
|
|
707
804
|
params[mdate] = isNaN(Number(curValue[1]))
|
|
708
805
|
? null
|
|
@@ -714,55 +811,32 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
714
811
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
715
812
|
}
|
|
716
813
|
let svalue;
|
|
717
|
-
let stringValue;
|
|
718
814
|
if (curValue[1] instanceof Object &&
|
|
719
815
|
typeof curValue[1].toReference === 'function') {
|
|
720
816
|
svalue = JSON.stringify(curValue[1].toReference());
|
|
721
|
-
stringValue = `${curValue[1].toReference()}`;
|
|
722
817
|
}
|
|
723
|
-
else
|
|
818
|
+
else if (typeof curValue[1] === 'string' ||
|
|
819
|
+
typeof curValue[1] === 'number') {
|
|
724
820
|
svalue = JSON.stringify(curValue[1]);
|
|
725
|
-
stringValue = `${curValue[1]}`;
|
|
726
|
-
}
|
|
727
|
-
const name = `param${++count.i}`;
|
|
728
|
-
const value = `param${++count.i}`;
|
|
729
|
-
if (typeof curValue[1] === 'string') {
|
|
730
|
-
const stringParam = `param${++count.i}`;
|
|
731
|
-
curQuery +=
|
|
732
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
733
|
-
'(' +
|
|
734
|
-
ieTable +
|
|
735
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
736
|
-
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
737
|
-
' WHERE "name"=@' +
|
|
738
|
-
name +
|
|
739
|
-
' AND position(@' +
|
|
740
|
-
value +
|
|
741
|
-
' IN "value")>0) OR ' +
|
|
742
|
-
ieTable +
|
|
743
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
744
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
745
|
-
' WHERE "name"=@' +
|
|
746
|
-
name +
|
|
747
|
-
' AND "string"=@' +
|
|
748
|
-
stringParam +
|
|
749
|
-
'))';
|
|
750
|
-
params[stringParam] = stringValue;
|
|
751
821
|
}
|
|
752
822
|
else {
|
|
753
|
-
|
|
754
|
-
((0, nymph_1.xor)(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
755
|
-
ieTable +
|
|
756
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
757
|
-
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
758
|
-
' WHERE "name"=@' +
|
|
759
|
-
name +
|
|
760
|
-
' AND position(@' +
|
|
761
|
-
value +
|
|
762
|
-
' IN "value")>0)';
|
|
823
|
+
svalue = JSON.stringify([curValue[1]]);
|
|
763
824
|
}
|
|
825
|
+
const name = `param${++count.i}`;
|
|
826
|
+
const value = `param${++count.i}`;
|
|
827
|
+
curQuery +=
|
|
828
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
829
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
830
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
831
|
+
' WHERE "guid"=' +
|
|
832
|
+
ieTable +
|
|
833
|
+
'."guid" AND "name"=@' +
|
|
834
|
+
name +
|
|
835
|
+
' AND "json" @> @' +
|
|
836
|
+
value +
|
|
837
|
+
')';
|
|
764
838
|
params[name] = curValue[0];
|
|
765
|
-
params[value] = svalue;
|
|
839
|
+
params[value] = PostgreSQLDriver.escapeNullSequences(svalue);
|
|
766
840
|
}
|
|
767
841
|
break;
|
|
768
842
|
case 'match':
|
|
@@ -773,7 +847,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
773
847
|
}
|
|
774
848
|
const cdate = `param${++count.i}`;
|
|
775
849
|
curQuery +=
|
|
776
|
-
(
|
|
850
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
777
851
|
'(' +
|
|
778
852
|
ieTable +
|
|
779
853
|
'."cdate" ~ @' +
|
|
@@ -788,7 +862,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
788
862
|
}
|
|
789
863
|
const mdate = `param${++count.i}`;
|
|
790
864
|
curQuery +=
|
|
791
|
-
(
|
|
865
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
792
866
|
'(' +
|
|
793
867
|
ieTable +
|
|
794
868
|
'."mdate" ~ @' +
|
|
@@ -804,17 +878,18 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
804
878
|
const name = `param${++count.i}`;
|
|
805
879
|
const value = `param${++count.i}`;
|
|
806
880
|
curQuery +=
|
|
807
|
-
(
|
|
881
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
882
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
883
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
884
|
+
' WHERE "guid"=' +
|
|
808
885
|
ieTable +
|
|
809
|
-
'."guid"
|
|
810
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
811
|
-
' WHERE "name"=@' +
|
|
886
|
+
'."guid" AND "name"=@' +
|
|
812
887
|
name +
|
|
813
888
|
' AND "string" ~ @' +
|
|
814
889
|
value +
|
|
815
890
|
')';
|
|
816
891
|
params[name] = curValue[0];
|
|
817
|
-
params[value] = curValue[1];
|
|
892
|
+
params[value] = PostgreSQLDriver.escapeNulls(curValue[1]);
|
|
818
893
|
}
|
|
819
894
|
break;
|
|
820
895
|
case 'imatch':
|
|
@@ -825,7 +900,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
825
900
|
}
|
|
826
901
|
const cdate = `param${++count.i}`;
|
|
827
902
|
curQuery +=
|
|
828
|
-
(
|
|
903
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
829
904
|
'(' +
|
|
830
905
|
ieTable +
|
|
831
906
|
'."cdate" ~* @' +
|
|
@@ -840,7 +915,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
840
915
|
}
|
|
841
916
|
const mdate = `param${++count.i}`;
|
|
842
917
|
curQuery +=
|
|
843
|
-
(
|
|
918
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
844
919
|
'(' +
|
|
845
920
|
ieTable +
|
|
846
921
|
'."mdate" ~* @' +
|
|
@@ -856,17 +931,18 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
856
931
|
const name = `param${++count.i}`;
|
|
857
932
|
const value = `param${++count.i}`;
|
|
858
933
|
curQuery +=
|
|
859
|
-
(
|
|
934
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
935
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
936
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
937
|
+
' WHERE "guid"=' +
|
|
860
938
|
ieTable +
|
|
861
|
-
'."guid"
|
|
862
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
863
|
-
' WHERE "name"=@' +
|
|
939
|
+
'."guid" AND "name"=@' +
|
|
864
940
|
name +
|
|
865
941
|
' AND "string" ~* @' +
|
|
866
942
|
value +
|
|
867
943
|
')';
|
|
868
944
|
params[name] = curValue[0];
|
|
869
|
-
params[value] = curValue[1];
|
|
945
|
+
params[value] = PostgreSQLDriver.escapeNulls(curValue[1]);
|
|
870
946
|
}
|
|
871
947
|
break;
|
|
872
948
|
case 'like':
|
|
@@ -877,7 +953,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
877
953
|
}
|
|
878
954
|
const cdate = `param${++count.i}`;
|
|
879
955
|
curQuery +=
|
|
880
|
-
(
|
|
956
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
881
957
|
'(' +
|
|
882
958
|
ieTable +
|
|
883
959
|
'."cdate" LIKE @' +
|
|
@@ -892,7 +968,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
892
968
|
}
|
|
893
969
|
const mdate = `param${++count.i}`;
|
|
894
970
|
curQuery +=
|
|
895
|
-
(
|
|
971
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
896
972
|
'(' +
|
|
897
973
|
ieTable +
|
|
898
974
|
'."mdate" LIKE @' +
|
|
@@ -908,17 +984,18 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
908
984
|
const name = `param${++count.i}`;
|
|
909
985
|
const value = `param${++count.i}`;
|
|
910
986
|
curQuery +=
|
|
911
|
-
(
|
|
987
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
988
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
989
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
990
|
+
' WHERE "guid"=' +
|
|
912
991
|
ieTable +
|
|
913
|
-
'."guid"
|
|
914
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
915
|
-
' WHERE "name"=@' +
|
|
992
|
+
'."guid" AND "name"=@' +
|
|
916
993
|
name +
|
|
917
994
|
' AND "string" LIKE @' +
|
|
918
995
|
value +
|
|
919
996
|
')';
|
|
920
997
|
params[name] = curValue[0];
|
|
921
|
-
params[value] = curValue[1];
|
|
998
|
+
params[value] = PostgreSQLDriver.escapeNulls(curValue[1]);
|
|
922
999
|
}
|
|
923
1000
|
break;
|
|
924
1001
|
case 'ilike':
|
|
@@ -929,7 +1006,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
929
1006
|
}
|
|
930
1007
|
const cdate = `param${++count.i}`;
|
|
931
1008
|
curQuery +=
|
|
932
|
-
(
|
|
1009
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
933
1010
|
'(' +
|
|
934
1011
|
ieTable +
|
|
935
1012
|
'."cdate" ILIKE @' +
|
|
@@ -944,7 +1021,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
944
1021
|
}
|
|
945
1022
|
const mdate = `param${++count.i}`;
|
|
946
1023
|
curQuery +=
|
|
947
|
-
(
|
|
1024
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
948
1025
|
'(' +
|
|
949
1026
|
ieTable +
|
|
950
1027
|
'."mdate" ILIKE @' +
|
|
@@ -960,17 +1037,18 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
960
1037
|
const name = `param${++count.i}`;
|
|
961
1038
|
const value = `param${++count.i}`;
|
|
962
1039
|
curQuery +=
|
|
963
|
-
(
|
|
1040
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1041
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1042
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1043
|
+
' WHERE "guid"=' +
|
|
964
1044
|
ieTable +
|
|
965
|
-
'."guid"
|
|
966
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
967
|
-
' WHERE "name"=@' +
|
|
1045
|
+
'."guid" AND "name"=@' +
|
|
968
1046
|
name +
|
|
969
1047
|
' AND "string" ILIKE @' +
|
|
970
1048
|
value +
|
|
971
1049
|
')';
|
|
972
1050
|
params[name] = curValue[0];
|
|
973
|
-
params[value] = curValue[1];
|
|
1051
|
+
params[value] = PostgreSQLDriver.escapeNulls(curValue[1]);
|
|
974
1052
|
}
|
|
975
1053
|
break;
|
|
976
1054
|
case 'gt':
|
|
@@ -981,7 +1059,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
981
1059
|
}
|
|
982
1060
|
const cdate = `param${++count.i}`;
|
|
983
1061
|
curQuery +=
|
|
984
|
-
(
|
|
1062
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
985
1063
|
ieTable +
|
|
986
1064
|
'."cdate">@' +
|
|
987
1065
|
cdate;
|
|
@@ -996,7 +1074,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
996
1074
|
}
|
|
997
1075
|
const mdate = `param${++count.i}`;
|
|
998
1076
|
curQuery +=
|
|
999
|
-
(
|
|
1077
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1000
1078
|
ieTable +
|
|
1001
1079
|
'."mdate">@' +
|
|
1002
1080
|
mdate;
|
|
@@ -1012,11 +1090,12 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1012
1090
|
const name = `param${++count.i}`;
|
|
1013
1091
|
const value = `param${++count.i}`;
|
|
1014
1092
|
curQuery +=
|
|
1015
|
-
(
|
|
1093
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1094
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1095
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1096
|
+
' WHERE "guid"=' +
|
|
1016
1097
|
ieTable +
|
|
1017
|
-
'."guid"
|
|
1018
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1019
|
-
' WHERE "name"=@' +
|
|
1098
|
+
'."guid" AND "name"=@' +
|
|
1020
1099
|
name +
|
|
1021
1100
|
' AND "number">@' +
|
|
1022
1101
|
value +
|
|
@@ -1035,7 +1114,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1035
1114
|
}
|
|
1036
1115
|
const cdate = `param${++count.i}`;
|
|
1037
1116
|
curQuery +=
|
|
1038
|
-
(
|
|
1117
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1039
1118
|
ieTable +
|
|
1040
1119
|
'."cdate">=@' +
|
|
1041
1120
|
cdate;
|
|
@@ -1050,7 +1129,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1050
1129
|
}
|
|
1051
1130
|
const mdate = `param${++count.i}`;
|
|
1052
1131
|
curQuery +=
|
|
1053
|
-
(
|
|
1132
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1054
1133
|
ieTable +
|
|
1055
1134
|
'."mdate">=@' +
|
|
1056
1135
|
mdate;
|
|
@@ -1066,11 +1145,12 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1066
1145
|
const name = `param${++count.i}`;
|
|
1067
1146
|
const value = `param${++count.i}`;
|
|
1068
1147
|
curQuery +=
|
|
1069
|
-
(
|
|
1148
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1149
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1150
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1151
|
+
' WHERE "guid"=' +
|
|
1070
1152
|
ieTable +
|
|
1071
|
-
'."guid"
|
|
1072
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1073
|
-
' WHERE "name"=@' +
|
|
1153
|
+
'."guid" AND "name"=@' +
|
|
1074
1154
|
name +
|
|
1075
1155
|
' AND "number">=@' +
|
|
1076
1156
|
value +
|
|
@@ -1089,7 +1169,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1089
1169
|
}
|
|
1090
1170
|
const cdate = `param${++count.i}`;
|
|
1091
1171
|
curQuery +=
|
|
1092
|
-
(
|
|
1172
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1093
1173
|
ieTable +
|
|
1094
1174
|
'."cdate"<@' +
|
|
1095
1175
|
cdate;
|
|
@@ -1104,7 +1184,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1104
1184
|
}
|
|
1105
1185
|
const mdate = `param${++count.i}`;
|
|
1106
1186
|
curQuery +=
|
|
1107
|
-
(
|
|
1187
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1108
1188
|
ieTable +
|
|
1109
1189
|
'."mdate"<@' +
|
|
1110
1190
|
mdate;
|
|
@@ -1120,11 +1200,12 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1120
1200
|
const name = `param${++count.i}`;
|
|
1121
1201
|
const value = `param${++count.i}`;
|
|
1122
1202
|
curQuery +=
|
|
1123
|
-
(
|
|
1203
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1204
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1205
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1206
|
+
' WHERE "guid"=' +
|
|
1124
1207
|
ieTable +
|
|
1125
|
-
'."guid"
|
|
1126
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1127
|
-
' WHERE "name"=@' +
|
|
1208
|
+
'."guid" AND "name"=@' +
|
|
1128
1209
|
name +
|
|
1129
1210
|
' AND "number"<@' +
|
|
1130
1211
|
value +
|
|
@@ -1143,7 +1224,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1143
1224
|
}
|
|
1144
1225
|
const cdate = `param${++count.i}`;
|
|
1145
1226
|
curQuery +=
|
|
1146
|
-
(
|
|
1227
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1147
1228
|
ieTable +
|
|
1148
1229
|
'."cdate"<=@' +
|
|
1149
1230
|
cdate;
|
|
@@ -1158,7 +1239,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1158
1239
|
}
|
|
1159
1240
|
const mdate = `param${++count.i}`;
|
|
1160
1241
|
curQuery +=
|
|
1161
|
-
(
|
|
1242
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1162
1243
|
ieTable +
|
|
1163
1244
|
'."mdate"<=@' +
|
|
1164
1245
|
mdate;
|
|
@@ -1174,11 +1255,12 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1174
1255
|
const name = `param${++count.i}`;
|
|
1175
1256
|
const value = `param${++count.i}`;
|
|
1176
1257
|
curQuery +=
|
|
1177
|
-
(
|
|
1258
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1259
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1260
|
+
PostgreSQLDriver.escape(this.prefix + 'data_' + etype) +
|
|
1261
|
+
' WHERE "guid"=' +
|
|
1178
1262
|
ieTable +
|
|
1179
|
-
'."guid"
|
|
1180
|
-
PostgreSQLDriver.escape(this.prefix + 'comparisons_' + etype) +
|
|
1181
|
-
' WHERE "name"=@' +
|
|
1263
|
+
'."guid" AND "name"=@' +
|
|
1182
1264
|
name +
|
|
1183
1265
|
' AND "number"<=@' +
|
|
1184
1266
|
value +
|
|
@@ -1207,11 +1289,12 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1207
1289
|
const name = `param${++count.i}`;
|
|
1208
1290
|
const guid = `param${++count.i}`;
|
|
1209
1291
|
curQuery +=
|
|
1210
|
-
(
|
|
1211
|
-
|
|
1212
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1292
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1293
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1213
1294
|
PostgreSQLDriver.escape(this.prefix + 'references_' + etype) +
|
|
1214
|
-
' WHERE "
|
|
1295
|
+
' WHERE "guid"=' +
|
|
1296
|
+
ieTable +
|
|
1297
|
+
'."guid" AND "name"=@' +
|
|
1215
1298
|
name +
|
|
1216
1299
|
' AND "reference"=decode(@' +
|
|
1217
1300
|
guid +
|
|
@@ -1226,29 +1309,37 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1226
1309
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1227
1310
|
}
|
|
1228
1311
|
curQuery +=
|
|
1229
|
-
(
|
|
1312
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1230
1313
|
'(' +
|
|
1231
1314
|
subquery.query +
|
|
1232
1315
|
')';
|
|
1233
1316
|
break;
|
|
1234
1317
|
case 'qref':
|
|
1235
1318
|
case '!qref':
|
|
1319
|
+
const referenceTableSuffix = makeTableSuffix();
|
|
1236
1320
|
const [qrefOptions, ...qrefSelectors] = curValue[1];
|
|
1237
1321
|
const QrefEntityClass = qrefOptions.class;
|
|
1238
1322
|
etypes.push(QrefEntityClass.ETYPE);
|
|
1239
|
-
const qrefQuery = this.makeEntityQuery({ ...qrefOptions, return: 'guid', class: QrefEntityClass }, qrefSelectors, QrefEntityClass.ETYPE, count, params, false,
|
|
1323
|
+
const qrefQuery = this.makeEntityQuery({ ...qrefOptions, return: 'guid', class: QrefEntityClass }, qrefSelectors, QrefEntityClass.ETYPE, count, params, false, makeTableSuffix(), etypes, 'r' + referenceTableSuffix + '."reference"');
|
|
1240
1324
|
if (curQuery) {
|
|
1241
1325
|
curQuery += typeIsOr ? ' OR ' : ' AND ';
|
|
1242
1326
|
}
|
|
1243
1327
|
const qrefName = `param${++count.i}`;
|
|
1244
1328
|
curQuery +=
|
|
1245
|
-
(
|
|
1246
|
-
|
|
1247
|
-
'."guid" IN (SELECT "guid" FROM ' +
|
|
1329
|
+
(xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
|
|
1330
|
+
'EXISTS (SELECT "guid" FROM ' +
|
|
1248
1331
|
PostgreSQLDriver.escape(this.prefix + 'references_' + etype) +
|
|
1249
|
-
'
|
|
1332
|
+
' r' +
|
|
1333
|
+
referenceTableSuffix +
|
|
1334
|
+
' WHERE r' +
|
|
1335
|
+
referenceTableSuffix +
|
|
1336
|
+
'."guid"=' +
|
|
1337
|
+
ieTable +
|
|
1338
|
+
'."guid" AND r' +
|
|
1339
|
+
referenceTableSuffix +
|
|
1340
|
+
'."name"=@' +
|
|
1250
1341
|
qrefName +
|
|
1251
|
-
' AND
|
|
1342
|
+
' AND EXISTS (' +
|
|
1252
1343
|
qrefQuery.query +
|
|
1253
1344
|
'))';
|
|
1254
1345
|
params[qrefName] = curValue[0];
|
|
@@ -1258,18 +1349,38 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1258
1349
|
return curQuery;
|
|
1259
1350
|
});
|
|
1260
1351
|
let sortBy;
|
|
1352
|
+
let sortByInner;
|
|
1353
|
+
let sortJoin = '';
|
|
1354
|
+
let sortJoinInner = '';
|
|
1355
|
+
const order = options.reverse ? ' DESC' : '';
|
|
1261
1356
|
switch (sort) {
|
|
1262
1357
|
case 'mdate':
|
|
1263
|
-
sortBy =
|
|
1358
|
+
sortBy = `${eTable}."mdate"${order}`;
|
|
1359
|
+
sortByInner = `${ieTable}."mdate"${order}`;
|
|
1264
1360
|
break;
|
|
1265
1361
|
case 'cdate':
|
|
1362
|
+
sortBy = `${eTable}."cdate"${order}`;
|
|
1363
|
+
sortByInner = `${ieTable}."cdate"${order}`;
|
|
1364
|
+
break;
|
|
1266
1365
|
default:
|
|
1267
|
-
|
|
1366
|
+
const name = `param${++count.i}`;
|
|
1367
|
+
sortJoin = `LEFT JOIN (
|
|
1368
|
+
SELECT "guid", "string", "number"
|
|
1369
|
+
FROM ${PostgreSQLDriver.escape(this.prefix + 'data_' + etype)}
|
|
1370
|
+
WHERE "name"=@${name}
|
|
1371
|
+
ORDER BY "number"${order}, "string"${order}
|
|
1372
|
+
) ${sTable} ON ${eTable}."guid"=${sTable}."guid"`;
|
|
1373
|
+
sortJoinInner = `LEFT JOIN (
|
|
1374
|
+
SELECT "guid", "string", "number"
|
|
1375
|
+
FROM ${PostgreSQLDriver.escape(this.prefix + 'data_' + etype)}
|
|
1376
|
+
WHERE "name"=@${name}
|
|
1377
|
+
ORDER BY "number"${order}, "string"${order}
|
|
1378
|
+
) ${sTable} ON ${ieTable}."guid"=${sTable}."guid"`;
|
|
1379
|
+
sortBy = `${sTable}."number"${order}, ${sTable}."string"${order}`;
|
|
1380
|
+
sortByInner = sortBy;
|
|
1381
|
+
params[name] = sort;
|
|
1268
1382
|
break;
|
|
1269
1383
|
}
|
|
1270
|
-
if (options.reverse) {
|
|
1271
|
-
sortBy += ' DESC';
|
|
1272
|
-
}
|
|
1273
1384
|
let query;
|
|
1274
1385
|
if (queryParts.length) {
|
|
1275
1386
|
if (subquery) {
|
|
@@ -1285,18 +1396,21 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1285
1396
|
offset = ` OFFSET ${Math.floor(isNaN(Number(options.offset)) ? 0 : Number(options.offset))}`;
|
|
1286
1397
|
}
|
|
1287
1398
|
const whereClause = queryParts.join(') AND (');
|
|
1399
|
+
const guidClause = guidSelector
|
|
1400
|
+
? `${ieTable}."guid"=${guidSelector} AND `
|
|
1401
|
+
: '';
|
|
1288
1402
|
if (options.return === 'count') {
|
|
1289
1403
|
if (limit || offset) {
|
|
1290
1404
|
query = `SELECT COUNT(${countTable}."guid") AS "count" FROM (
|
|
1291
|
-
SELECT
|
|
1405
|
+
SELECT ${ieTable}."guid" AS "guid"
|
|
1292
1406
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1293
|
-
WHERE (${whereClause})${limit}${offset}
|
|
1407
|
+
WHERE ${guidClause}(${whereClause})${limit}${offset}
|
|
1294
1408
|
) ${countTable}`;
|
|
1295
1409
|
}
|
|
1296
1410
|
else {
|
|
1297
1411
|
query = `SELECT COUNT(${ieTable}."guid") AS "count"
|
|
1298
1412
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1299
|
-
WHERE (${whereClause})`;
|
|
1413
|
+
WHERE ${guidClause}(${whereClause})`;
|
|
1300
1414
|
}
|
|
1301
1415
|
}
|
|
1302
1416
|
else if (options.return === 'guid') {
|
|
@@ -1305,8 +1419,9 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1305
1419
|
: `${ieTable}."guid"`;
|
|
1306
1420
|
query = `SELECT ${guidColumn} AS "guid"
|
|
1307
1421
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1308
|
-
|
|
1309
|
-
|
|
1422
|
+
${sortJoinInner}
|
|
1423
|
+
WHERE ${guidClause}(${whereClause})
|
|
1424
|
+
ORDER BY ${sortByInner}, ${ieTable}."guid"${limit}${offset}`;
|
|
1310
1425
|
}
|
|
1311
1426
|
else {
|
|
1312
1427
|
query = `SELECT
|
|
@@ -1316,18 +1431,20 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1316
1431
|
${eTable}."mdate",
|
|
1317
1432
|
${dTable}."name",
|
|
1318
1433
|
${dTable}."value",
|
|
1319
|
-
${
|
|
1320
|
-
${
|
|
1434
|
+
${dTable}."json",
|
|
1435
|
+
${dTable}."string",
|
|
1436
|
+
${dTable}."number"
|
|
1321
1437
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
|
|
1322
1438
|
LEFT JOIN ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}."guid"=${dTable}."guid"
|
|
1323
|
-
|
|
1439
|
+
${sortJoin}
|
|
1324
1440
|
INNER JOIN (
|
|
1325
1441
|
SELECT ${ieTable}."guid"
|
|
1326
1442
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1327
|
-
|
|
1328
|
-
|
|
1443
|
+
${sortJoinInner}
|
|
1444
|
+
WHERE ${guidClause}(${whereClause})
|
|
1445
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1329
1446
|
) ${fTable} ON ${eTable}."guid"=${fTable}."guid"
|
|
1330
|
-
ORDER BY ${
|
|
1447
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1331
1448
|
}
|
|
1332
1449
|
}
|
|
1333
1450
|
}
|
|
@@ -1344,16 +1461,19 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1344
1461
|
if ('offset' in options) {
|
|
1345
1462
|
offset = ` OFFSET ${Math.floor(isNaN(Number(options.offset)) ? 0 : Number(options.offset))}`;
|
|
1346
1463
|
}
|
|
1464
|
+
const guidClause = guidSelector
|
|
1465
|
+
? ` WHERE ${ieTable}."guid"=${guidSelector}`
|
|
1466
|
+
: '';
|
|
1347
1467
|
if (options.return === 'count') {
|
|
1348
1468
|
if (limit || offset) {
|
|
1349
1469
|
query = `SELECT COUNT(${countTable}."guid") AS "count" FROM (
|
|
1350
|
-
SELECT
|
|
1351
|
-
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}${limit}${offset}
|
|
1470
|
+
SELECT ${ieTable}."guid" AS "guid"
|
|
1471
|
+
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}${guidClause}${limit}${offset}
|
|
1352
1472
|
) ${countTable}`;
|
|
1353
1473
|
}
|
|
1354
1474
|
else {
|
|
1355
1475
|
query = `SELECT COUNT(${ieTable}."guid") AS "count"
|
|
1356
|
-
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}`;
|
|
1476
|
+
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}${guidClause}`;
|
|
1357
1477
|
}
|
|
1358
1478
|
}
|
|
1359
1479
|
else if (options.return === 'guid') {
|
|
@@ -1362,7 +1482,9 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1362
1482
|
: `${ieTable}."guid"`;
|
|
1363
1483
|
query = `SELECT ${guidColumn} AS "guid"
|
|
1364
1484
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1365
|
-
|
|
1485
|
+
${sortJoinInner}
|
|
1486
|
+
${guidClause}
|
|
1487
|
+
ORDER BY ${sortByInner}, ${ieTable}."guid"${limit}${offset}`;
|
|
1366
1488
|
}
|
|
1367
1489
|
else {
|
|
1368
1490
|
if (limit || offset) {
|
|
@@ -1373,17 +1495,20 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1373
1495
|
${eTable}."mdate",
|
|
1374
1496
|
${dTable}."name",
|
|
1375
1497
|
${dTable}."value",
|
|
1376
|
-
${
|
|
1377
|
-
${
|
|
1498
|
+
${dTable}."json",
|
|
1499
|
+
${dTable}."string",
|
|
1500
|
+
${dTable}."number"
|
|
1378
1501
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
|
|
1379
1502
|
LEFT JOIN ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}."guid"=${dTable}."guid"
|
|
1380
|
-
|
|
1503
|
+
${sortJoin}
|
|
1381
1504
|
INNER JOIN (
|
|
1382
1505
|
SELECT ${ieTable}."guid"
|
|
1383
1506
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${ieTable}
|
|
1384
|
-
|
|
1507
|
+
${sortJoinInner}
|
|
1508
|
+
${guidClause}
|
|
1509
|
+
ORDER BY ${sortByInner}${limit}${offset}
|
|
1385
1510
|
) ${fTable} ON ${eTable}."guid"=${fTable}."guid"
|
|
1386
|
-
ORDER BY ${
|
|
1511
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1387
1512
|
}
|
|
1388
1513
|
else {
|
|
1389
1514
|
query = `SELECT
|
|
@@ -1393,12 +1518,14 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1393
1518
|
${eTable}."mdate",
|
|
1394
1519
|
${dTable}."name",
|
|
1395
1520
|
${dTable}."value",
|
|
1396
|
-
${
|
|
1397
|
-
${
|
|
1521
|
+
${dTable}."json",
|
|
1522
|
+
${dTable}."string",
|
|
1523
|
+
${dTable}."number"
|
|
1398
1524
|
FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ${eTable}
|
|
1399
1525
|
LEFT JOIN ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ${dTable} ON ${eTable}."guid"=${dTable}."guid"
|
|
1400
|
-
|
|
1401
|
-
|
|
1526
|
+
${sortJoin}
|
|
1527
|
+
${guidSelector ? `WHERE ${eTable}."guid"=${guidSelector}` : ''}
|
|
1528
|
+
ORDER BY ${sortBy}, ${eTable}."guid"`;
|
|
1402
1529
|
}
|
|
1403
1530
|
}
|
|
1404
1531
|
}
|
|
@@ -1414,24 +1541,19 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1414
1541
|
}
|
|
1415
1542
|
performQuery(options, formattedSelectors, etype) {
|
|
1416
1543
|
const { query, params, etypes } = this.makeEntityQuery(options, formattedSelectors, etype);
|
|
1417
|
-
const result = this.
|
|
1418
|
-
return {
|
|
1419
|
-
result,
|
|
1420
|
-
};
|
|
1421
|
-
}
|
|
1422
|
-
performQuerySync(options, formattedSelectors, etype) {
|
|
1423
|
-
const { query, params, etypes } = this.makeEntityQuery(options, formattedSelectors, etype);
|
|
1424
|
-
const result = (this.queryIterSync(query, { etypes, params }) || [])[Symbol.iterator]();
|
|
1544
|
+
const result = this.queryArray(query, { etypes, params }).then((val) => val[Symbol.iterator]());
|
|
1425
1545
|
return {
|
|
1426
1546
|
result,
|
|
1427
1547
|
};
|
|
1428
1548
|
}
|
|
1429
1549
|
async getEntities(options = {}, ...selectors) {
|
|
1430
|
-
const { result: resultPromise, process } = this.
|
|
1550
|
+
const { result: resultPromise, process } = this.getEntitiesRowLike(
|
|
1551
|
+
// @ts-ignore: options is correct here.
|
|
1552
|
+
options, selectors, ({ options, selectors, etype }) => this.performQuery(options, selectors, etype), () => {
|
|
1431
1553
|
const next = result.next();
|
|
1432
1554
|
return next.done ? null : next.value;
|
|
1433
1555
|
}, () => undefined, (row) => Number(row.count), (row) => row.guid, (row) => ({
|
|
1434
|
-
tags: row.tags,
|
|
1556
|
+
tags: row.tags.filter((tag) => tag),
|
|
1435
1557
|
cdate: isNaN(Number(row.cdate)) ? null : Number(row.cdate),
|
|
1436
1558
|
mdate: isNaN(Number(row.mdate)) ? null : Number(row.mdate),
|
|
1437
1559
|
}), (row) => ({
|
|
@@ -1439,8 +1561,10 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1439
1561
|
svalue: row.value === 'N'
|
|
1440
1562
|
? JSON.stringify(Number(row.number))
|
|
1441
1563
|
: row.value === 'S'
|
|
1442
|
-
? JSON.stringify(row.string)
|
|
1443
|
-
: row.value
|
|
1564
|
+
? JSON.stringify(PostgreSQLDriver.unescapeNulls(row.string))
|
|
1565
|
+
: row.value === 'J'
|
|
1566
|
+
? PostgreSQLDriver.unescapeNullSequences(JSON.stringify(row.json))
|
|
1567
|
+
: row.value,
|
|
1444
1568
|
}));
|
|
1445
1569
|
const result = await resultPromise;
|
|
1446
1570
|
const value = process();
|
|
@@ -1449,31 +1573,9 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1449
1573
|
}
|
|
1450
1574
|
return value;
|
|
1451
1575
|
}
|
|
1452
|
-
getEntitiesSync(options = {}, ...selectors) {
|
|
1453
|
-
const { result, process } = this.getEntitesRowLike(options, selectors, (options, formattedSelectors, etype) => this.performQuerySync(options, formattedSelectors, etype), () => {
|
|
1454
|
-
const next = result.next();
|
|
1455
|
-
return next.done ? null : next.value;
|
|
1456
|
-
}, () => undefined, (row) => Number(row.count), (row) => row.guid, (row) => ({
|
|
1457
|
-
tags: row.tags,
|
|
1458
|
-
cdate: isNaN(Number(row.cdate)) ? null : Number(row.cdate),
|
|
1459
|
-
mdate: isNaN(Number(row.mdate)) ? null : Number(row.mdate),
|
|
1460
|
-
}), (row) => ({
|
|
1461
|
-
name: row.name,
|
|
1462
|
-
svalue: row.value === 'N'
|
|
1463
|
-
? JSON.stringify(Number(row.number))
|
|
1464
|
-
: row.value === 'S'
|
|
1465
|
-
? JSON.stringify(row.string)
|
|
1466
|
-
: row.value,
|
|
1467
|
-
}));
|
|
1468
|
-
const value = process();
|
|
1469
|
-
if (value instanceof Error) {
|
|
1470
|
-
throw value;
|
|
1471
|
-
}
|
|
1472
|
-
return value;
|
|
1473
|
-
}
|
|
1474
1576
|
async getUID(name) {
|
|
1475
1577
|
if (name == null) {
|
|
1476
|
-
throw new
|
|
1578
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1477
1579
|
}
|
|
1478
1580
|
const result = await this.queryGet(`SELECT "cur_uid" FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
1479
1581
|
params: {
|
|
@@ -1482,129 +1584,143 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1482
1584
|
});
|
|
1483
1585
|
return result?.cur_uid == null ? null : Number(result.cur_uid);
|
|
1484
1586
|
}
|
|
1485
|
-
async
|
|
1587
|
+
async importEntity({ guid, cdate, mdate, tags, sdata, etype, }) {
|
|
1486
1588
|
try {
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1589
|
+
let promises = [];
|
|
1590
|
+
promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
|
|
1591
|
+
etypes: [etype],
|
|
1592
|
+
params: {
|
|
1593
|
+
guid,
|
|
1594
|
+
},
|
|
1595
|
+
}));
|
|
1596
|
+
promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
|
|
1597
|
+
etypes: [etype],
|
|
1598
|
+
params: {
|
|
1599
|
+
guid,
|
|
1600
|
+
},
|
|
1601
|
+
}));
|
|
1602
|
+
promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
|
|
1603
|
+
etypes: [etype],
|
|
1604
|
+
params: {
|
|
1605
|
+
guid,
|
|
1606
|
+
},
|
|
1607
|
+
}));
|
|
1608
|
+
promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
|
|
1609
|
+
etypes: [etype],
|
|
1610
|
+
params: {
|
|
1611
|
+
guid,
|
|
1612
|
+
},
|
|
1613
|
+
}));
|
|
1614
|
+
await Promise.all(promises);
|
|
1615
|
+
promises = [];
|
|
1616
|
+
await this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate") VALUES (decode(@guid, 'hex'), @tags, @cdate, @mdate);`, {
|
|
1617
|
+
etypes: [etype],
|
|
1618
|
+
params: {
|
|
1619
|
+
guid,
|
|
1620
|
+
tags,
|
|
1621
|
+
cdate: isNaN(cdate) ? null : cdate,
|
|
1622
|
+
mdate: isNaN(mdate) ? null : mdate,
|
|
1623
|
+
},
|
|
1624
|
+
});
|
|
1625
|
+
for (const name in sdata) {
|
|
1626
|
+
const value = sdata[name];
|
|
1627
|
+
const uvalue = JSON.parse(value);
|
|
1628
|
+
if (value === undefined) {
|
|
1629
|
+
continue;
|
|
1630
|
+
}
|
|
1631
|
+
const storageValue = typeof uvalue === 'number'
|
|
1632
|
+
? 'N'
|
|
1633
|
+
: typeof uvalue === 'string'
|
|
1634
|
+
? 'S'
|
|
1635
|
+
: 'J';
|
|
1636
|
+
const jsonValue = storageValue === 'J'
|
|
1637
|
+
? PostgreSQLDriver.escapeNullSequences(value)
|
|
1638
|
+
: null;
|
|
1639
|
+
promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (decode(@guid, 'hex'), @name, @storageValue, @jsonValue, @string, @number, @truthy);`, {
|
|
1495
1640
|
etypes: [etype],
|
|
1496
1641
|
params: {
|
|
1497
1642
|
guid,
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
mdate: isNaN(Number(JSON.parse(sdata.mdate)))
|
|
1643
|
+
name,
|
|
1644
|
+
storageValue,
|
|
1645
|
+
jsonValue,
|
|
1646
|
+
string: storageValue === 'J'
|
|
1503
1647
|
? null
|
|
1504
|
-
:
|
|
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,
|
|
1648
|
+
: PostgreSQLDriver.escapeNulls(`${uvalue}`),
|
|
1649
|
+
number: isNaN(Number(uvalue)) ? null : Number(uvalue),
|
|
1650
|
+
truthy: !!uvalue,
|
|
1524
1651
|
},
|
|
1525
1652
|
}));
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
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);`, {
|
|
1653
|
+
const references = this.findReferences(value);
|
|
1654
|
+
for (const reference of references) {
|
|
1655
|
+
promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} ("guid", "name", "reference") VALUES (decode(@guid, 'hex'), @name, decode(@reference, 'hex'));`, {
|
|
1550
1656
|
etypes: [etype],
|
|
1551
1657
|
params: {
|
|
1552
1658
|
guid,
|
|
1553
1659
|
name,
|
|
1554
|
-
|
|
1555
|
-
string: `${uvalue}`,
|
|
1556
|
-
number: isNaN(Number(uvalue)) ? null : Number(uvalue),
|
|
1660
|
+
reference,
|
|
1557
1661
|
},
|
|
1558
1662
|
}));
|
|
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
1663
|
}
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
await this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @curUid);`, {
|
|
1664
|
+
}
|
|
1665
|
+
const uniques = await this.nymph
|
|
1666
|
+
.getEntityClassByEtype(etype)
|
|
1667
|
+
.getUniques({ guid, cdate, mdate, tags, data: {}, sdata });
|
|
1668
|
+
for (const unique of uniques) {
|
|
1669
|
+
promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}uniques_${etype}`)} ("guid", "unique") VALUES (decode(@guid, 'hex'), @unique);`, {
|
|
1670
|
+
etypes: [etype],
|
|
1579
1671
|
params: {
|
|
1580
|
-
|
|
1581
|
-
|
|
1672
|
+
guid,
|
|
1673
|
+
unique,
|
|
1582
1674
|
},
|
|
1583
|
-
})
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1675
|
+
}).catch((e) => {
|
|
1676
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
1677
|
+
this.nymph.config.debugError('postgresql', `Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
|
|
1678
|
+
}
|
|
1679
|
+
return e;
|
|
1680
|
+
}));
|
|
1681
|
+
}
|
|
1682
|
+
await Promise.all(promises);
|
|
1683
|
+
}
|
|
1684
|
+
catch (e) {
|
|
1685
|
+
this.nymph.config.debugError('postgresql', `Import entity error: "${e}"`);
|
|
1686
|
+
throw e;
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
async importUID({ name, value }) {
|
|
1690
|
+
try {
|
|
1691
|
+
await this.internalTransaction(`nymph-import-uid-${name}`);
|
|
1692
|
+
await this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name;`, {
|
|
1693
|
+
params: {
|
|
1694
|
+
name,
|
|
1695
|
+
},
|
|
1588
1696
|
});
|
|
1589
|
-
|
|
1697
|
+
await this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @value);`, {
|
|
1698
|
+
params: {
|
|
1699
|
+
name,
|
|
1700
|
+
value,
|
|
1701
|
+
},
|
|
1702
|
+
});
|
|
1703
|
+
await this.commit(`nymph-import-uid-${name}`);
|
|
1590
1704
|
}
|
|
1591
1705
|
catch (e) {
|
|
1592
|
-
|
|
1593
|
-
|
|
1706
|
+
this.nymph.config.debugError('postgresql', `Import UID error: "${e}"`);
|
|
1707
|
+
await this.rollback(`nymph-import-uid-${name}`);
|
|
1708
|
+
throw e;
|
|
1594
1709
|
}
|
|
1595
1710
|
}
|
|
1596
1711
|
async newUID(name) {
|
|
1597
1712
|
if (name == null) {
|
|
1598
|
-
throw new
|
|
1713
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1599
1714
|
}
|
|
1600
1715
|
await this.internalTransaction('nymph-newuid');
|
|
1716
|
+
let curUid = undefined;
|
|
1601
1717
|
try {
|
|
1602
1718
|
const lock = await this.queryGet(`SELECT "cur_uid" FROM ${PostgreSQLDriver.escape(`${this.prefix}uids`)} WHERE "name"=@name FOR UPDATE;`, {
|
|
1603
1719
|
params: {
|
|
1604
1720
|
name,
|
|
1605
1721
|
},
|
|
1606
1722
|
});
|
|
1607
|
-
|
|
1723
|
+
curUid = lock?.cur_uid == null ? undefined : Number(lock.cur_uid);
|
|
1608
1724
|
if (curUid == null) {
|
|
1609
1725
|
curUid = 1;
|
|
1610
1726
|
await this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}uids`)} ("name", "cur_uid") VALUES (@name, @curUid);`, {
|
|
@@ -1623,17 +1739,18 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1623
1739
|
},
|
|
1624
1740
|
});
|
|
1625
1741
|
}
|
|
1626
|
-
await this.commit('nymph-newuid');
|
|
1627
|
-
return curUid;
|
|
1628
1742
|
}
|
|
1629
1743
|
catch (e) {
|
|
1744
|
+
this.nymph.config.debugError('postgresql', `New UID error: "${e}"`);
|
|
1630
1745
|
await this.rollback('nymph-newuid');
|
|
1631
1746
|
throw e;
|
|
1632
1747
|
}
|
|
1748
|
+
await this.commit('nymph-newuid');
|
|
1749
|
+
return curUid;
|
|
1633
1750
|
}
|
|
1634
1751
|
async renameUID(oldName, newName) {
|
|
1635
1752
|
if (oldName == null || newName == null) {
|
|
1636
|
-
throw new
|
|
1753
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1637
1754
|
}
|
|
1638
1755
|
await this.queryRun(`UPDATE ${PostgreSQLDriver.escape(`${this.prefix}uids`)} SET "name"=@newName WHERE "name"=@oldName;`, {
|
|
1639
1756
|
params: {
|
|
@@ -1645,7 +1762,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1645
1762
|
}
|
|
1646
1763
|
async rollback(name) {
|
|
1647
1764
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1648
|
-
throw new
|
|
1765
|
+
throw new InvalidParametersError('Transaction rollback attempted without a name.');
|
|
1649
1766
|
}
|
|
1650
1767
|
if (!this.transaction || this.transaction.count === 0) {
|
|
1651
1768
|
this.transaction = null;
|
|
@@ -1662,7 +1779,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1662
1779
|
return true;
|
|
1663
1780
|
}
|
|
1664
1781
|
async saveEntity(entity) {
|
|
1665
|
-
const insertData = async (guid, data, sdata, etype) => {
|
|
1782
|
+
const insertData = async (guid, data, sdata, uniques, etype) => {
|
|
1666
1783
|
const runInsertQuery = async (name, value, svalue) => {
|
|
1667
1784
|
if (value === undefined) {
|
|
1668
1785
|
return;
|
|
@@ -1671,24 +1788,23 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1671
1788
|
? 'N'
|
|
1672
1789
|
: typeof value === 'string'
|
|
1673
1790
|
? 'S'
|
|
1674
|
-
:
|
|
1791
|
+
: 'J';
|
|
1792
|
+
const jsonValue = storageValue === 'J'
|
|
1793
|
+
? PostgreSQLDriver.escapeNullSequences(svalue)
|
|
1794
|
+
: null;
|
|
1675
1795
|
const promises = [];
|
|
1676
|
-
promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value") VALUES (decode(@guid, 'hex'), @name, @storageValue);`, {
|
|
1796
|
+
promises.push(this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (decode(@guid, 'hex'), @name, @storageValue, @jsonValue, @string, @number, @truthy);`, {
|
|
1677
1797
|
etypes: [etype],
|
|
1678
1798
|
params: {
|
|
1679
1799
|
guid,
|
|
1680
1800
|
name,
|
|
1681
1801
|
storageValue,
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
params: {
|
|
1687
|
-
guid,
|
|
1688
|
-
name,
|
|
1689
|
-
truthy: !!value,
|
|
1690
|
-
string: `${value}`,
|
|
1802
|
+
jsonValue,
|
|
1803
|
+
string: storageValue === 'J'
|
|
1804
|
+
? null
|
|
1805
|
+
: PostgreSQLDriver.escapeNulls(`${value}`),
|
|
1691
1806
|
number: isNaN(Number(value)) ? null : Number(value),
|
|
1807
|
+
truthy: !!value,
|
|
1692
1808
|
},
|
|
1693
1809
|
}));
|
|
1694
1810
|
const references = this.findReferences(svalue);
|
|
@@ -1704,6 +1820,23 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1704
1820
|
}
|
|
1705
1821
|
await Promise.all(promises);
|
|
1706
1822
|
};
|
|
1823
|
+
for (const unique of uniques) {
|
|
1824
|
+
try {
|
|
1825
|
+
await this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}uniques_${etype}`)} ("guid", "unique") VALUES (decode(@guid, 'hex'), @unique);`, {
|
|
1826
|
+
etypes: [etype],
|
|
1827
|
+
params: {
|
|
1828
|
+
guid,
|
|
1829
|
+
unique,
|
|
1830
|
+
},
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
catch (e) {
|
|
1834
|
+
if (e instanceof EntityUniqueConstraintError) {
|
|
1835
|
+
this.nymph.config.debugError('postgresql', `Save entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
|
|
1836
|
+
}
|
|
1837
|
+
throw e;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1707
1840
|
for (const name in data) {
|
|
1708
1841
|
await runInsertQuery(name, data[name], JSON.stringify(data[name]));
|
|
1709
1842
|
}
|
|
@@ -1711,8 +1844,13 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1711
1844
|
await runInsertQuery(name, JSON.parse(sdata[name]), sdata[name]);
|
|
1712
1845
|
}
|
|
1713
1846
|
};
|
|
1847
|
+
let inTransaction = false;
|
|
1714
1848
|
try {
|
|
1715
|
-
const result = await this.saveEntityRowLike(entity, async (
|
|
1849
|
+
const result = await this.saveEntityRowLike(entity, async ({ guid, tags, data, sdata, uniques, cdate, etype }) => {
|
|
1850
|
+
if (Object.keys(data).length === 0 &&
|
|
1851
|
+
Object.keys(sdata).length === 0) {
|
|
1852
|
+
return false;
|
|
1853
|
+
}
|
|
1716
1854
|
await this.queryRun(`INSERT INTO ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate") VALUES (decode(@guid, 'hex'), @tags, @cdate, @cdate);`, {
|
|
1717
1855
|
etypes: [etype],
|
|
1718
1856
|
params: {
|
|
@@ -1721,9 +1859,13 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1721
1859
|
cdate,
|
|
1722
1860
|
},
|
|
1723
1861
|
});
|
|
1724
|
-
await insertData(guid, data, sdata, etype);
|
|
1862
|
+
await insertData(guid, data, sdata, uniques, etype);
|
|
1725
1863
|
return true;
|
|
1726
|
-
}, async (entity, guid, tags, data, sdata, mdate, etype) => {
|
|
1864
|
+
}, async ({ entity, guid, tags, data, sdata, uniques, mdate, etype }) => {
|
|
1865
|
+
if (Object.keys(data).length === 0 &&
|
|
1866
|
+
Object.keys(sdata).length === 0) {
|
|
1867
|
+
return false;
|
|
1868
|
+
}
|
|
1727
1869
|
const promises = [];
|
|
1728
1870
|
promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=decode(@guid, 'hex') FOR UPDATE;`, {
|
|
1729
1871
|
etypes: [etype],
|
|
@@ -1737,13 +1879,13 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1737
1879
|
guid,
|
|
1738
1880
|
},
|
|
1739
1881
|
}));
|
|
1740
|
-
promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}
|
|
1882
|
+
promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=decode(@guid, 'hex') FOR UPDATE;`, {
|
|
1741
1883
|
etypes: [etype],
|
|
1742
1884
|
params: {
|
|
1743
1885
|
guid,
|
|
1744
1886
|
},
|
|
1745
1887
|
}));
|
|
1746
|
-
promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}
|
|
1888
|
+
promises.push(this.queryRun(`SELECT 1 FROM ${PostgreSQLDriver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=decode(@guid, 'hex') FOR UPDATE;`, {
|
|
1747
1889
|
etypes: [etype],
|
|
1748
1890
|
params: {
|
|
1749
1891
|
guid,
|
|
@@ -1768,44 +1910,51 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1768
1910
|
guid,
|
|
1769
1911
|
},
|
|
1770
1912
|
}));
|
|
1771
|
-
promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}
|
|
1913
|
+
promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
|
|
1772
1914
|
etypes: [etype],
|
|
1773
1915
|
params: {
|
|
1774
1916
|
guid,
|
|
1775
1917
|
},
|
|
1776
1918
|
}));
|
|
1777
|
-
promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}
|
|
1919
|
+
promises.push(this.queryRun(`DELETE FROM ${PostgreSQLDriver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=decode(@guid, 'hex');`, {
|
|
1778
1920
|
etypes: [etype],
|
|
1779
1921
|
params: {
|
|
1780
1922
|
guid,
|
|
1781
1923
|
},
|
|
1782
1924
|
}));
|
|
1783
1925
|
await Promise.all(promises);
|
|
1784
|
-
await insertData(guid, data, sdata, etype);
|
|
1926
|
+
await insertData(guid, data, sdata, uniques, etype);
|
|
1785
1927
|
success = true;
|
|
1786
1928
|
}
|
|
1787
1929
|
return success;
|
|
1788
1930
|
}, async () => {
|
|
1789
1931
|
await this.internalTransaction('nymph-save');
|
|
1932
|
+
inTransaction = true;
|
|
1790
1933
|
}, async (success) => {
|
|
1791
|
-
if (
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1934
|
+
if (inTransaction) {
|
|
1935
|
+
inTransaction = false;
|
|
1936
|
+
if (success) {
|
|
1937
|
+
await this.commit('nymph-save');
|
|
1938
|
+
}
|
|
1939
|
+
else {
|
|
1940
|
+
await this.rollback('nymph-save');
|
|
1941
|
+
}
|
|
1796
1942
|
}
|
|
1797
1943
|
return success;
|
|
1798
1944
|
});
|
|
1799
1945
|
return result;
|
|
1800
1946
|
}
|
|
1801
1947
|
catch (e) {
|
|
1802
|
-
|
|
1948
|
+
this.nymph.config.debugError('postgresql', `Save entity error: "${e}"`);
|
|
1949
|
+
if (inTransaction) {
|
|
1950
|
+
await this.rollback('nymph-save');
|
|
1951
|
+
}
|
|
1803
1952
|
throw e;
|
|
1804
1953
|
}
|
|
1805
1954
|
}
|
|
1806
1955
|
async setUID(name, curUid) {
|
|
1807
1956
|
if (name == null) {
|
|
1808
|
-
throw new
|
|
1957
|
+
throw new InvalidParametersError('Name not given for UID.');
|
|
1809
1958
|
}
|
|
1810
1959
|
await this.internalTransaction('nymph-setuid');
|
|
1811
1960
|
try {
|
|
@@ -1821,23 +1970,25 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1821
1970
|
curUid,
|
|
1822
1971
|
},
|
|
1823
1972
|
});
|
|
1824
|
-
await this.commit('nymph-setuid');
|
|
1825
|
-
return true;
|
|
1826
1973
|
}
|
|
1827
1974
|
catch (e) {
|
|
1828
1975
|
await this.rollback('nymph-setuid');
|
|
1829
1976
|
throw e;
|
|
1830
1977
|
}
|
|
1978
|
+
await this.commit('nymph-setuid');
|
|
1979
|
+
return true;
|
|
1831
1980
|
}
|
|
1832
1981
|
async internalTransaction(name) {
|
|
1833
1982
|
if (name == null || typeof name !== 'string' || name.length === 0) {
|
|
1834
|
-
throw new
|
|
1983
|
+
throw new InvalidParametersError('Transaction start attempted without a name.');
|
|
1835
1984
|
}
|
|
1836
1985
|
if (!this.transaction || this.transaction.count === 0) {
|
|
1986
|
+
// Lock to one connection.
|
|
1837
1987
|
this.transaction = {
|
|
1838
1988
|
count: 0,
|
|
1839
1989
|
connection: await this.getConnection(),
|
|
1840
1990
|
};
|
|
1991
|
+
// We're not in a transaction yet, so start one.
|
|
1841
1992
|
await this.queryRun('BEGIN;');
|
|
1842
1993
|
}
|
|
1843
1994
|
await this.queryRun(`SAVEPOINT ${PostgreSQLDriver.escape(name)};`);
|
|
@@ -1845,7 +1996,7 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1845
1996
|
return this.transaction;
|
|
1846
1997
|
}
|
|
1847
1998
|
async startTransaction(name) {
|
|
1848
|
-
const inTransaction = this.inTransaction();
|
|
1999
|
+
const inTransaction = await this.inTransaction();
|
|
1849
2000
|
const transaction = await this.internalTransaction(name);
|
|
1850
2001
|
if (!inTransaction) {
|
|
1851
2002
|
this.transaction = null;
|
|
@@ -1854,6 +2005,23 @@ class PostgreSQLDriver extends nymph_1.NymphDriver {
|
|
|
1854
2005
|
nymph.driver.transaction = transaction;
|
|
1855
2006
|
return nymph;
|
|
1856
2007
|
}
|
|
2008
|
+
async needsMigration() {
|
|
2009
|
+
const table = await this.queryGet('SELECT "table_name" AS "table_name" FROM "information_schema"."tables" WHERE "table_catalog"=@db AND "table_schema"=\'public\' AND "table_name" LIKE @prefix LIMIT 1;', {
|
|
2010
|
+
params: {
|
|
2011
|
+
db: this.config.database,
|
|
2012
|
+
prefix: this.prefix + 'data_' + '%',
|
|
2013
|
+
},
|
|
2014
|
+
});
|
|
2015
|
+
if (table?.table_name) {
|
|
2016
|
+
const result = await this.queryGet('SELECT 1 AS "exists" FROM "information_schema"."columns" WHERE "table_catalog"=@db AND "table_schema"=\'public\' AND "table_name"=@table AND "column_name"=\'json\';', {
|
|
2017
|
+
params: {
|
|
2018
|
+
db: this.config.database,
|
|
2019
|
+
table: table.table_name,
|
|
2020
|
+
},
|
|
2021
|
+
});
|
|
2022
|
+
return !result?.exists;
|
|
2023
|
+
}
|
|
2024
|
+
return false;
|
|
2025
|
+
}
|
|
1857
2026
|
}
|
|
1858
|
-
exports.default = PostgreSQLDriver;
|
|
1859
2027
|
//# sourceMappingURL=PostgreSQLDriver.js.map
|