prostgles-server 3.0.131 → 3.0.133
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/dist/Prostgles.d.ts +6 -1
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +6 -2
- package/dist/Prostgles.js.map +1 -1
- package/dist/TableConfig/TableConfig.d.ts.map +1 -1
- package/dist/TableConfig/TableConfig.js +81 -147
- package/dist/TableConfig/TableConfig.js.map +1 -1
- package/dist/TableConfig/getColumnDefinitionQuery.d.ts +3 -19
- package/dist/TableConfig/getColumnDefinitionQuery.d.ts.map +1 -1
- package/dist/TableConfig/getColumnDefinitionQuery.js +5 -38
- package/dist/TableConfig/getColumnDefinitionQuery.js.map +1 -1
- package/dist/TableConfig/getConstraintDefinitionQueries.d.ts +27 -1
- package/dist/TableConfig/getConstraintDefinitionQueries.d.ts.map +1 -1
- package/dist/TableConfig/getConstraintDefinitionQueries.js +40 -6
- package/dist/TableConfig/getConstraintDefinitionQueries.js.map +1 -1
- package/dist/TableConfig/getFutureTableSchema.d.ts +15 -0
- package/dist/TableConfig/getFutureTableSchema.d.ts.map +1 -0
- package/dist/TableConfig/getFutureTableSchema.js +51 -0
- package/dist/TableConfig/getFutureTableSchema.js.map +1 -0
- package/dist/TableConfig/getTableColumnQueries.d.ts +16 -0
- package/dist/TableConfig/getTableColumnQueries.d.ts.map +1 -0
- package/dist/TableConfig/getTableColumnQueries.js +108 -0
- package/dist/TableConfig/getTableColumnQueries.js.map +1 -0
- package/lib/Prostgles.d.ts +6 -1
- package/lib/Prostgles.d.ts.map +1 -1
- package/lib/Prostgles.js +6 -2
- package/lib/Prostgles.ts +12 -3
- package/lib/TableConfig/TableConfig.d.ts.map +1 -1
- package/lib/TableConfig/TableConfig.js +81 -147
- package/lib/TableConfig/TableConfig.ts +94 -154
- package/lib/TableConfig/getColumnDefinitionQuery.d.ts +3 -19
- package/lib/TableConfig/getColumnDefinitionQuery.d.ts.map +1 -1
- package/lib/TableConfig/getColumnDefinitionQuery.js +5 -38
- package/lib/TableConfig/getColumnDefinitionQuery.ts +4 -46
- package/lib/TableConfig/getConstraintDefinitionQueries.d.ts +27 -1
- package/lib/TableConfig/getConstraintDefinitionQueries.d.ts.map +1 -1
- package/lib/TableConfig/getConstraintDefinitionQueries.js +40 -6
- package/lib/TableConfig/getConstraintDefinitionQueries.ts +64 -6
- package/lib/TableConfig/getFutureTableSchema.d.ts +15 -0
- package/lib/TableConfig/getFutureTableSchema.d.ts.map +1 -0
- package/lib/TableConfig/getFutureTableSchema.js +50 -0
- package/lib/TableConfig/getFutureTableSchema.ts +73 -0
- package/lib/TableConfig/getTableColumnQueries.d.ts +16 -0
- package/lib/TableConfig/getTableColumnQueries.d.ts.map +1 -0
- package/lib/TableConfig/getTableColumnQueries.js +107 -0
- package/lib/TableConfig/getTableColumnQueries.ts +130 -0
- package/package.json +1 -1
- package/tests/client/PID.txt +1 -1
- package/tests/config_test/index.ts +1 -2
- package/tests/config_test/init.sql +1 -8
- package/tests/server/DBoGenerated.d.ts +12 -2
- package/tests/server/index.js +5 -1
- package/tests/server/index.ts +5 -1
- package/tests/server/init.sql +1 -7
- package/tests/server/package-lock.json +1 -1
- package/tests/server/package.json +1 -1
|
@@ -4,8 +4,8 @@ exports.CONSTRAINT_TYPES = exports.parseI18N = void 0;
|
|
|
4
4
|
const prostgles_types_1 = require("prostgles-types");
|
|
5
5
|
const DboBuilder_1 = require("../DboBuilder");
|
|
6
6
|
const PubSubManager_1 = require("../PubSubManager/PubSubManager");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
7
|
+
const getTableColumnQueries_1 = require("./getTableColumnQueries");
|
|
8
|
+
const getFutureTableSchema_1 = require("./getFutureTableSchema");
|
|
9
9
|
const getConstraintDefinitionQueries_1 = require("./getConstraintDefinitionQueries");
|
|
10
10
|
const parseI18N = (params) => {
|
|
11
11
|
const { config, lang, defaultLang, defaultValue } = params;
|
|
@@ -127,7 +127,25 @@ class TableConfigurator {
|
|
|
127
127
|
return undefined;
|
|
128
128
|
};
|
|
129
129
|
async init() {
|
|
130
|
+
// if("2".length){
|
|
131
|
+
// throw await getFutureTableSchema({ db: this.db, columnDefs: ["id text primary key"], constraintDefs: [] });
|
|
132
|
+
// }
|
|
130
133
|
let queries = [];
|
|
134
|
+
const makeQuery = (q) => q.map(v => v.trim().endsWith(";") ? v : `${v};`).join("\n");
|
|
135
|
+
const runQueries = async (_queries = queries) => {
|
|
136
|
+
const q = makeQuery(queries);
|
|
137
|
+
if (!_queries.length)
|
|
138
|
+
return 0;
|
|
139
|
+
this.log(q);
|
|
140
|
+
(0, PubSubManager_1.log)(q);
|
|
141
|
+
await this.db.multi(q).catch(err => {
|
|
142
|
+
(0, PubSubManager_1.log)({ err, q });
|
|
143
|
+
return Promise.reject(err);
|
|
144
|
+
});
|
|
145
|
+
_queries = [];
|
|
146
|
+
queries = [];
|
|
147
|
+
return 1;
|
|
148
|
+
};
|
|
131
149
|
if (!this.config || !this.prostgles.pgp)
|
|
132
150
|
throw "config or pgp missing";
|
|
133
151
|
const MAX_IDENTIFIER_LENGTH = +(await this.db.one("SHOW max_identifier_length;")).max_identifier_length;
|
|
@@ -151,22 +169,22 @@ class TableConfigurator {
|
|
|
151
169
|
catch (e) {
|
|
152
170
|
}
|
|
153
171
|
if (!existingVersion || existingVersion < version) {
|
|
154
|
-
await onMigrate({ db: this.db, oldVersion: existingVersion, getConstraints: (table, col, types) => (0,
|
|
172
|
+
await onMigrate({ db: this.db, oldVersion: existingVersion, getConstraints: (table, col, types) => (0, getConstraintDefinitionQueries_1.getColConstraints)({ db: this.db, table, column: col, types }) });
|
|
155
173
|
}
|
|
156
174
|
}
|
|
157
175
|
/* Create lookup tables */
|
|
158
|
-
(0, prostgles_types_1.getKeys)(this.config).map(
|
|
176
|
+
(0, prostgles_types_1.getKeys)(this.config).map(tableNameRaw => {
|
|
159
177
|
const tableName = asName(tableNameRaw);
|
|
160
178
|
const tableConf = this.config[tableNameRaw];
|
|
161
|
-
const { dropIfExists = false, dropIfExistsCascade = false } = tableConf;
|
|
162
|
-
const isDropped = dropIfExists || dropIfExistsCascade;
|
|
163
|
-
if (dropIfExistsCascade) {
|
|
164
|
-
queries.push(`DROP TABLE IF EXISTS ${tableName} CASCADE;`);
|
|
165
|
-
}
|
|
166
|
-
else if (dropIfExists) {
|
|
167
|
-
queries.push(`DROP TABLE IF EXISTS ${tableName} ;`);
|
|
168
|
-
}
|
|
169
179
|
if ("isLookupTable" in tableConf && Object.keys(tableConf.isLookupTable?.values).length) {
|
|
180
|
+
const { dropIfExists = false, dropIfExistsCascade = false } = tableConf;
|
|
181
|
+
const isDropped = dropIfExists || dropIfExistsCascade;
|
|
182
|
+
if (dropIfExistsCascade) {
|
|
183
|
+
queries.push(`DROP TABLE IF EXISTS ${tableName} CASCADE;`);
|
|
184
|
+
}
|
|
185
|
+
else if (dropIfExists) {
|
|
186
|
+
queries.push(`DROP TABLE IF EXISTS ${tableName};`);
|
|
187
|
+
}
|
|
170
188
|
const rows = Object.keys(tableConf.isLookupTable?.values).map(id => ({ id, ...(tableConf.isLookupTable?.values[id]) }));
|
|
171
189
|
if (isDropped || !this.dbo?.[tableNameRaw]) {
|
|
172
190
|
const columnNames = Object.keys(rows[0]).filter(k => k !== "id");
|
|
@@ -178,129 +196,66 @@ class TableConfigurator {
|
|
|
178
196
|
const values = this.prostgles.pgp.helpers.values(row);
|
|
179
197
|
queries.push(this.prostgles.pgp.as.format(`INSERT INTO ${tableName} (${["id", ...columnNames].map(t => asName(t)).join(", ")}) ` + " VALUES ${values:raw} ;", { values }));
|
|
180
198
|
});
|
|
181
|
-
// this.log("Created lookup table " + tableName)
|
|
182
199
|
}
|
|
183
200
|
}
|
|
184
201
|
});
|
|
185
202
|
if (queries.length) {
|
|
186
|
-
|
|
187
|
-
if (this.prostgles.opts.DEBUG_MODE) {
|
|
188
|
-
this.log("TableConfig: \n", q);
|
|
189
|
-
}
|
|
190
|
-
await this.db.multi(q);
|
|
203
|
+
await runQueries(queries);
|
|
191
204
|
await this.prostgles.refreshDBO();
|
|
192
205
|
}
|
|
193
|
-
queries = [];
|
|
194
206
|
/* Create/Alter columns */
|
|
195
207
|
for await (const tableName of (0, prostgles_types_1.getKeys)(this.config)) {
|
|
196
208
|
const tableConf = this.config[tableName];
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
else if (!tableHandler) {
|
|
230
|
-
columnDefs.push(colDef);
|
|
231
|
-
colCreateLines.push(colDef);
|
|
232
|
-
/** Alter existing column */
|
|
233
|
-
}
|
|
234
|
-
else if (tableHandler && !tableHandler.columns?.find(c => colName === c.name)) {
|
|
235
|
-
columnDefs.push(colDef);
|
|
236
|
-
queries.push(`
|
|
237
|
-
ALTER TABLE ${asName(tableName)}
|
|
238
|
-
ADD COLUMN ${colDef};
|
|
239
|
-
`);
|
|
240
|
-
if ((0, prostgles_types_1.isObject)(colConf) && "references" in colConf && colConf.references) {
|
|
241
|
-
const { tableName: lookupTable } = colConf.references;
|
|
242
|
-
this.log(`TableConfigurator: ${tableName}(${colName})` + " referenced lookup table " + lookupTable);
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
this.log(`TableConfigurator: created/added column ${tableName}(${colName}) `);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
209
|
+
const tableHandler = this.dbo[tableName];
|
|
210
|
+
/** These have already been created */
|
|
211
|
+
if ("isLookupTable" in tableConf) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (tableName.startsWith("rec")) {
|
|
215
|
+
// eslint-disable-next-line no-debugger
|
|
216
|
+
debugger;
|
|
217
|
+
}
|
|
218
|
+
const ALTER_TABLE_Q = `ALTER TABLE ${asName(tableName)}`;
|
|
219
|
+
const coldef = await (0, getTableColumnQueries_1.getTableColumnQueries)({ db: this.db, tableConf: tableConf, tableHandler: tableHandler, tableName });
|
|
220
|
+
if (coldef) {
|
|
221
|
+
queries.push(coldef.fullQuery);
|
|
222
|
+
}
|
|
223
|
+
/** CONSTRAINTS */
|
|
224
|
+
const constraintDefs = (0, getConstraintDefinitionQueries_1.getConstraintDefinitionQueries)({ tableName, tableConf: tableConf });
|
|
225
|
+
if (coldef?.isCreate) {
|
|
226
|
+
queries.push(...constraintDefs?.map(c => c.alterQuery) ?? []);
|
|
227
|
+
}
|
|
228
|
+
else if (coldef) {
|
|
229
|
+
const fullSchema = await (0, getFutureTableSchema_1.getFutureTableSchema)({ db: this.db, tableName, columnDefs: coldef.columnDefs, constraintDefs });
|
|
230
|
+
const futureCons = fullSchema.constraints.map(nc => ({
|
|
231
|
+
...nc,
|
|
232
|
+
isNamed: constraintDefs?.some(c => c.name === nc.name)
|
|
233
|
+
}));
|
|
234
|
+
/** Run this first to ensure any dropped cols drop their constraints as well */
|
|
235
|
+
await runQueries(queries);
|
|
236
|
+
const currCons = await (0, getConstraintDefinitionQueries_1.getColConstraints)({ db: this.db, table: tableName });
|
|
237
|
+
/** Drop removed/modified */
|
|
238
|
+
currCons.forEach(c => {
|
|
239
|
+
if (!futureCons.some(nc => nc.definition === c.definition && (!nc.isNamed || nc.name === c.name))) {
|
|
240
|
+
queries.push(`${ALTER_TABLE_Q} DROP CONSTRAINT ${asName(c.name)};`);
|
|
248
241
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const randomTableName = `prostgles_constr_${v}`;
|
|
257
|
-
const columnDefsWithoutReferences = columnDefs.map(cdef => {
|
|
258
|
-
return cdef.slice(0, cdef.toLowerCase().indexOf(" references "));
|
|
259
|
-
});
|
|
260
|
-
await t.any(`CREATE TABLE ${randomTableName} ( \n${columnDefsWithoutReferences.join(",\n")}\n );\n` +
|
|
261
|
-
(constraintQueries ?? []).join("\n"));
|
|
262
|
-
newConstraints = await (0, getColumnDefinitionQuery_1.getColConstraints)({ db: t, table: randomTableName });
|
|
263
|
-
newCols = await (0, getColumnDefinitionQuery_1.getTableColumns)({ db: this.db, tableName });
|
|
264
|
-
return Promise.reject("Done");
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
catch (e) {
|
|
242
|
+
});
|
|
243
|
+
/** Add missing named constraints */
|
|
244
|
+
constraintDefs?.forEach(c => {
|
|
245
|
+
if (c.name) {
|
|
246
|
+
const fc = futureCons.find(nc => nc.name === c.name);
|
|
247
|
+
if (fc) {
|
|
248
|
+
queries.push(`${ALTER_TABLE_Q} ADD CONSTRAINT ${asName(c.name)} ${c.content};`);
|
|
268
249
|
}
|
|
269
|
-
const ALTER_TABLE_Q = `ALTER TABLE ${asName(tableName)}`;
|
|
270
|
-
const currConstraints = await (0, getColumnDefinitionQuery_1.getColConstraints)({ db: this.db, table: tableName });
|
|
271
|
-
currConstraints.forEach(c => {
|
|
272
|
-
if (!newConstraints.some(nc => nc.type === c.type && nc.definition === c.definition && nc.cols.sort().join() === c.cols.sort().join())) {
|
|
273
|
-
queries.unshift(`${ALTER_TABLE_Q} DROP CONSTRAINT ${asName(c.name)} CASCADE;`);
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
const currCols = await (0, getColumnDefinitionQuery_1.getTableColumns)({ db: this.db, tableName });
|
|
277
|
-
currCols.forEach(c => {
|
|
278
|
-
const newCol = newCols.find(nc => nc.column_name === c.column_name);
|
|
279
|
-
if (!newCol) {
|
|
280
|
-
queries.push(`${ALTER_TABLE_Q} DROP COLUMN ${asName(c.column_name)} CASCADE;`);
|
|
281
|
-
}
|
|
282
|
-
else if (newCol.nullable !== c.nullable) {
|
|
283
|
-
queries.push(`${ALTER_TABLE_Q} ALTER COLUMN ${asName(c.column_name)} ${newCol.nullable ? "SET" : "DROP"} NOT NULL;`);
|
|
284
|
-
}
|
|
285
|
-
else if (newCol.udt_name !== c.udt_name) {
|
|
286
|
-
queries.push(`${ALTER_TABLE_Q} ALTER COLUMN ${asName(c.column_name)} TYPE ${newCol.udt_name};`);
|
|
287
|
-
}
|
|
288
|
-
else if (newCol.column_default !== c.column_default) {
|
|
289
|
-
queries.push(`${ALTER_TABLE_Q} ALTER COLUMN ${asName(c.column_name)} ${newCol.column_default === null ? "DROP DEFAULT" : `SET DEFAULT ${newCol.column_default}`};`);
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
250
|
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this.log("TableConfigurator: Created table: \n" + queries.at(-1));
|
|
301
|
-
}
|
|
251
|
+
});
|
|
252
|
+
/** Add remaining missing constraints */
|
|
253
|
+
// currCons = await getColConstraints({ db: this.db, table: tableName });
|
|
254
|
+
futureCons.filter(nc => !currCons.some(c => c.definition === nc.definition))
|
|
255
|
+
.forEach(c => {
|
|
256
|
+
queries.push(`${ALTER_TABLE_Q} ADD ${c.definition};`);
|
|
257
|
+
});
|
|
302
258
|
}
|
|
303
|
-
queries.push(...constraintQueries ?? []);
|
|
304
259
|
if ("indexes" in tableConf && tableConf.indexes) {
|
|
305
260
|
/*
|
|
306
261
|
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
|
|
@@ -314,7 +269,7 @@ class TableConfigurator {
|
|
|
314
269
|
(0, prostgles_types_1.getKeys)(tableConf.indexes).map(indexName => {
|
|
315
270
|
const { replace, unique, concurrently, using, columns, where = "" } = tableConf.indexes[indexName];
|
|
316
271
|
if (replace || typeof replace !== "boolean" && tableConf.replaceUniqueIndexes) {
|
|
317
|
-
queries.push(`DROP INDEX IF EXISTS ${asName(indexName)}
|
|
272
|
+
queries.push(`DROP INDEX IF EXISTS ${asName(indexName)};`);
|
|
318
273
|
}
|
|
319
274
|
queries.push([
|
|
320
275
|
"CREATE",
|
|
@@ -379,10 +334,10 @@ class TableConfigurator {
|
|
|
379
334
|
}
|
|
380
335
|
}
|
|
381
336
|
if (queries.length) {
|
|
382
|
-
const q = queries
|
|
383
|
-
this.log("TableConfig
|
|
337
|
+
const q = makeQuery(queries);
|
|
338
|
+
this.log("TableConfig >>>> ", q);
|
|
384
339
|
try {
|
|
385
|
-
await
|
|
340
|
+
await runQueries(queries);
|
|
386
341
|
if (migrations) {
|
|
387
342
|
await this.db.any(`INSERT INTO ${migrations.table}(id, table_config) VALUES (${(0, PubSubManager_1.asValue)(migrations.version)}, ${(0, PubSubManager_1.asValue)(this.config)}) ON CONFLICT DO NOTHING;`);
|
|
388
343
|
}
|
|
@@ -406,24 +361,3 @@ class TableConfigurator {
|
|
|
406
361
|
};
|
|
407
362
|
}
|
|
408
363
|
exports.default = TableConfigurator;
|
|
409
|
-
async function columnExists(args) {
|
|
410
|
-
const { db, tableName, colName } = args;
|
|
411
|
-
return Boolean((await db.oneOrNone(`
|
|
412
|
-
SELECT column_name, table_name
|
|
413
|
-
FROM information_schema.columns
|
|
414
|
-
WHERE table_name=${(0, PubSubManager_1.asValue)(tableName)} and column_name=${(0, PubSubManager_1.asValue)(colName)}
|
|
415
|
-
LIMIT 1;
|
|
416
|
-
`))?.column_name);
|
|
417
|
-
}
|
|
418
|
-
function getTableConstraings(db, tableName) {
|
|
419
|
-
return db.any(`
|
|
420
|
-
SELECT con.*, pg_get_constraintdef(con.oid)
|
|
421
|
-
FROM pg_catalog.pg_constraint con
|
|
422
|
-
INNER JOIN pg_catalog.pg_class rel
|
|
423
|
-
ON rel.oid = con.conrelid
|
|
424
|
-
INNER JOIN pg_catalog.pg_namespace nsp
|
|
425
|
-
ON nsp.oid = connamespace
|
|
426
|
-
WHERE 1=1
|
|
427
|
-
AND nsp.nspname = current_schema
|
|
428
|
-
AND rel.relname = ` + "${tableName}", { tableName });
|
|
429
|
-
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { getKeys, asName as _asName, AnyObject, TableInfo, ALLOWED_EXTENSION, ALLOWED_CONTENT_TYPE, isObject, JSONB, ColumnInfo } from "prostgles-types";
|
|
1
|
+
import { getKeys, asName as _asName, AnyObject, TableInfo, ALLOWED_EXTENSION, ALLOWED_CONTENT_TYPE, isObject, JSONB, ColumnInfo, asName } from "prostgles-types";
|
|
2
2
|
import { isPlainObject, JoinInfo } from "../DboBuilder";
|
|
3
3
|
import { DB, DBHandlerServer, Prostgles } from "../Prostgles";
|
|
4
|
-
import { asValue } from "../PubSubManager/PubSubManager";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { getConstraintDefinitionQueries } from "./getConstraintDefinitionQueries";
|
|
4
|
+
import { asValue, log } from "../PubSubManager/PubSubManager";
|
|
5
|
+
import { getTableColumnQueries } from "./getTableColumnQueries";
|
|
6
|
+
import { getFutureTableSchema } from "./getFutureTableSchema";
|
|
7
|
+
import { ColConstraint, ConstraintDef, getColConstraints, getConstraintDefinitionQueries } from "./getConstraintDefinitionQueries";
|
|
8
8
|
|
|
9
9
|
type ColExtraInfo = {
|
|
10
10
|
min?: string | number;
|
|
@@ -417,7 +417,25 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
417
417
|
}
|
|
418
418
|
|
|
419
419
|
async init() {
|
|
420
|
+
// if("2".length){
|
|
421
|
+
// throw await getFutureTableSchema({ db: this.db, columnDefs: ["id text primary key"], constraintDefs: [] });
|
|
422
|
+
// }
|
|
420
423
|
let queries: string[] = [];
|
|
424
|
+
const makeQuery = (q: string[]) => q.map(v => v.trim().endsWith(";")? v : `${v};`).join("\n");
|
|
425
|
+
const runQueries = async (_queries = queries) => {
|
|
426
|
+
const q = makeQuery(queries);
|
|
427
|
+
if(!_queries.length) return 0;
|
|
428
|
+
this.log(q);
|
|
429
|
+
log(q);
|
|
430
|
+
await this.db.multi(q).catch(err => {
|
|
431
|
+
log({ err, q });
|
|
432
|
+
|
|
433
|
+
return Promise.reject(err);
|
|
434
|
+
});
|
|
435
|
+
_queries = [];
|
|
436
|
+
queries = [];
|
|
437
|
+
return 1;
|
|
438
|
+
}
|
|
421
439
|
|
|
422
440
|
if (!this.config || !this.prostgles.pgp) throw "config or pgp missing";
|
|
423
441
|
|
|
@@ -449,19 +467,20 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
449
467
|
}
|
|
450
468
|
|
|
451
469
|
/* Create lookup tables */
|
|
452
|
-
getKeys(this.config).map(
|
|
470
|
+
getKeys(this.config).map(tableNameRaw => {
|
|
453
471
|
const tableName = asName(tableNameRaw);
|
|
454
472
|
const tableConf = this.config![tableNameRaw];
|
|
455
|
-
const { dropIfExists = false, dropIfExistsCascade = false } = tableConf;
|
|
456
|
-
const isDropped = dropIfExists || dropIfExistsCascade;
|
|
457
|
-
|
|
458
|
-
if (dropIfExistsCascade) {
|
|
459
|
-
queries.push(`DROP TABLE IF EXISTS ${tableName} CASCADE;`);
|
|
460
|
-
} else if (dropIfExists) {
|
|
461
|
-
queries.push(`DROP TABLE IF EXISTS ${tableName} ;`);
|
|
462
|
-
}
|
|
463
473
|
|
|
464
474
|
if ("isLookupTable" in tableConf && Object.keys(tableConf.isLookupTable?.values).length) {
|
|
475
|
+
const { dropIfExists = false, dropIfExistsCascade = false } = tableConf;
|
|
476
|
+
const isDropped = dropIfExists || dropIfExistsCascade;
|
|
477
|
+
|
|
478
|
+
if (dropIfExistsCascade) {
|
|
479
|
+
queries.push(`DROP TABLE IF EXISTS ${tableName} CASCADE;`);
|
|
480
|
+
} else if (dropIfExists) {
|
|
481
|
+
queries.push(`DROP TABLE IF EXISTS ${tableName};`);
|
|
482
|
+
}
|
|
483
|
+
|
|
465
484
|
const rows = Object.keys(tableConf.isLookupTable?.values).map(id => ({ id, ...(tableConf.isLookupTable?.values[id]) }));
|
|
466
485
|
if (isDropped || !this.dbo?.[tableNameRaw]) {
|
|
467
486
|
const columnNames = Object.keys(rows[0]).filter(k => k !== "id");
|
|
@@ -476,137 +495,80 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
476
495
|
const values = this.prostgles.pgp!.helpers.values(row)
|
|
477
496
|
queries.push(this.prostgles.pgp!.as.format(`INSERT INTO ${tableName} (${["id", ...columnNames].map(t => asName(t)).join(", ")}) ` + " VALUES ${values:raw} ;", { values }))
|
|
478
497
|
});
|
|
479
|
-
// this.log("Created lookup table " + tableName)
|
|
480
498
|
}
|
|
481
499
|
}
|
|
482
500
|
});
|
|
483
501
|
|
|
484
|
-
if (queries.length) {
|
|
485
|
-
|
|
486
|
-
if(this.prostgles.opts.DEBUG_MODE){
|
|
487
|
-
this.log("TableConfig: \n", q);
|
|
488
|
-
}
|
|
489
|
-
await this.db.multi(q);
|
|
502
|
+
if (queries.length) {
|
|
503
|
+
await runQueries(queries);
|
|
490
504
|
await this.prostgles.refreshDBO()
|
|
491
505
|
}
|
|
492
|
-
queries = [];
|
|
493
506
|
|
|
494
507
|
/* Create/Alter columns */
|
|
495
508
|
for await (const tableName of getKeys(this.config)){
|
|
496
509
|
const tableConf = this.config![tableName];
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
if(hasJSONBValidation){
|
|
509
|
-
try {
|
|
510
|
-
await this.db.any(validate_jsonb_schema_sql);
|
|
511
|
-
} catch(err: any){
|
|
512
|
-
console.error("Could not install the jsonb validation function due to error: ", err);
|
|
513
|
-
throw err;
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const columns = getKeys(tableConf.columns).filter(c => {
|
|
518
|
-
const colDef = tableConf.columns![c];
|
|
519
|
-
/** Exclude NamedJoinColumn */
|
|
520
|
-
return typeof colDef === "string" || !("joinDef" in colDef)
|
|
521
|
-
});
|
|
522
|
-
|
|
523
|
-
const columnDefs: string[] = [];
|
|
524
|
-
for await(const colName of columns) {
|
|
525
|
-
const colConf = tableConf.columns![colName];
|
|
526
|
-
|
|
527
|
-
/* Add column to create statement */
|
|
528
|
-
const colDef = await getColumnDefinitionQuery({ colConf, column: colName, db: this.db, table: tableName });
|
|
529
|
-
if(!colDef){
|
|
530
|
-
// Column has only labels
|
|
531
|
-
} else if (!tableHandler) {
|
|
532
|
-
columnDefs.push(colDef);
|
|
533
|
-
colCreateLines.push(colDef);
|
|
534
|
-
|
|
535
|
-
/** Alter existing column */
|
|
536
|
-
} else if (tableHandler && !tableHandler.columns?.find(c => colName === c.name)) {
|
|
537
|
-
columnDefs.push(colDef);
|
|
510
|
+
const tableHandler = this.dbo[tableName];
|
|
511
|
+
|
|
512
|
+
/** These have already been created */
|
|
513
|
+
if("isLookupTable" in tableConf){
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if(tableName.startsWith("rec")){
|
|
518
|
+
// eslint-disable-next-line no-debugger
|
|
519
|
+
debugger;
|
|
520
|
+
}
|
|
538
521
|
|
|
539
|
-
|
|
540
|
-
ALTER TABLE ${asName(tableName)}
|
|
541
|
-
ADD COLUMN ${colDef};
|
|
542
|
-
`);
|
|
543
|
-
if(isObject(colConf) && "references" in colConf && colConf.references){
|
|
522
|
+
const ALTER_TABLE_Q = `ALTER TABLE ${asName(tableName)}`;
|
|
544
523
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
524
|
+
const coldef = await getTableColumnQueries({ db: this.db, tableConf: tableConf as any, tableHandler: tableHandler as any, tableName });
|
|
525
|
+
|
|
526
|
+
if(coldef){
|
|
527
|
+
queries.push(coldef.fullQuery);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/** CONSTRAINTS */
|
|
531
|
+
const constraintDefs = getConstraintDefinitionQueries({ tableName, tableConf: tableConf as any });
|
|
532
|
+
if(coldef?.isCreate){
|
|
533
|
+
queries.push(...constraintDefs?.map(c => c.alterQuery) ?? []);
|
|
534
|
+
|
|
535
|
+
} else if(coldef) {
|
|
536
|
+
const fullSchema = await getFutureTableSchema({ db: this.db, tableName, columnDefs: coldef.columnDefs, constraintDefs });
|
|
537
|
+
const futureCons = fullSchema.constraints.map(nc => ({
|
|
538
|
+
...nc,
|
|
539
|
+
isNamed: constraintDefs?.some(c => c.name === nc.name)
|
|
540
|
+
}));
|
|
541
|
+
|
|
542
|
+
/** Run this first to ensure any dropped cols drop their constraints as well */
|
|
543
|
+
await runQueries(queries);
|
|
544
|
+
const currCons = await getColConstraints({ db: this.db, table: tableName });
|
|
545
|
+
|
|
546
|
+
/** Drop removed/modified */
|
|
547
|
+
currCons.forEach(c => {
|
|
548
|
+
if(!futureCons.some(nc => nc.definition === c.definition && (!nc.isNamed || nc.name === c.name))){
|
|
549
|
+
queries.push(`${ALTER_TABLE_Q} DROP CONSTRAINT ${asName(c.name)};`)
|
|
551
550
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const randomTableName = `prostgles_constr_${v}`;
|
|
561
|
-
const columnDefsWithoutReferences = columnDefs.map(cdef => {
|
|
562
|
-
return cdef.slice(0, cdef.toLowerCase().indexOf(" references "));
|
|
563
|
-
});
|
|
564
|
-
await t.any(
|
|
565
|
-
`CREATE TABLE ${randomTableName} ( \n${columnDefsWithoutReferences.join(",\n")}\n );\n` +
|
|
566
|
-
(constraintQueries ?? []).join("\n")
|
|
567
|
-
);
|
|
568
|
-
newConstraints = await getColConstraints({ db: t, table: randomTableName });
|
|
569
|
-
newCols = await getTableColumns({ db: this.db, tableName });
|
|
570
|
-
return Promise.reject("Done");
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
} catch(e){
|
|
574
|
-
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
/** Add missing named constraints */
|
|
554
|
+
constraintDefs?.forEach(c => {
|
|
555
|
+
if(c.name){
|
|
556
|
+
const fc = futureCons.find(nc => nc.name === c.name);
|
|
557
|
+
if(fc){
|
|
558
|
+
queries.push(`${ALTER_TABLE_Q} ADD CONSTRAINT ${asName(c.name)} ${c.content};`);
|
|
575
559
|
}
|
|
576
|
-
const ALTER_TABLE_Q = `ALTER TABLE ${asName(tableName)}`;
|
|
577
|
-
const currConstraints = await getColConstraints({ db: this.db, table: tableName });
|
|
578
|
-
currConstraints.forEach(c => {
|
|
579
|
-
if(!newConstraints.some(nc => nc.type === c.type && nc.definition === c.definition && nc.cols.sort().join() === c.cols.sort().join())){
|
|
580
|
-
queries.unshift(`${ALTER_TABLE_Q} DROP CONSTRAINT ${asName(c.name)} CASCADE;`);
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
const currCols = await getTableColumns({ db: this.db, tableName });
|
|
585
|
-
currCols.forEach(c => {
|
|
586
|
-
const newCol = newCols.find(nc => nc.column_name === c.column_name);
|
|
587
|
-
if(!newCol){
|
|
588
|
-
queries.push(`${ALTER_TABLE_Q} DROP COLUMN ${asName(c.column_name)} CASCADE;`)
|
|
589
|
-
} else if(newCol.nullable !== c.nullable){
|
|
590
|
-
queries.push(`${ALTER_TABLE_Q} ALTER COLUMN ${asName(c.column_name)} ${newCol.nullable? "SET" : "DROP"} NOT NULL;`)
|
|
591
|
-
} else if(newCol.udt_name !== c.udt_name){
|
|
592
|
-
queries.push(`${ALTER_TABLE_Q} ALTER COLUMN ${asName(c.column_name)} TYPE ${newCol.udt_name};`)
|
|
593
|
-
} else if(newCol.column_default !== c.column_default){
|
|
594
|
-
queries.push(`${ALTER_TABLE_Q} ALTER COLUMN ${asName(c.column_name)} ${newCol.column_default === null? "DROP DEFAULT" : `SET DEFAULT ${newCol.column_default}`};`)
|
|
595
|
-
}
|
|
596
|
-
})
|
|
597
560
|
}
|
|
598
|
-
}
|
|
561
|
+
});
|
|
599
562
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
this.log("TableConfigurator: Created table: \n" + queries.at(-1))
|
|
607
|
-
}
|
|
563
|
+
/** Add remaining missing constraints */
|
|
564
|
+
// currCons = await getColConstraints({ db: this.db, table: tableName });
|
|
565
|
+
futureCons.filter(nc => !currCons.some(c =>c.definition === nc.definition))
|
|
566
|
+
.forEach(c => {
|
|
567
|
+
queries.push(`${ALTER_TABLE_Q} ADD ${c.definition};`)
|
|
568
|
+
});
|
|
608
569
|
}
|
|
609
|
-
|
|
570
|
+
|
|
571
|
+
|
|
610
572
|
if ("indexes" in tableConf && tableConf.indexes) {
|
|
611
573
|
/*
|
|
612
574
|
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
|
|
@@ -624,7 +586,7 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
624
586
|
using, columns, where = ""
|
|
625
587
|
} = tableConf.indexes![indexName];
|
|
626
588
|
if (replace || typeof replace !== "boolean" && tableConf.replaceUniqueIndexes) {
|
|
627
|
-
queries.push(`DROP INDEX IF EXISTS ${asName(indexName)}
|
|
589
|
+
queries.push(`DROP INDEX IF EXISTS ${asName(indexName)};`);
|
|
628
590
|
}
|
|
629
591
|
queries.push([
|
|
630
592
|
"CREATE",
|
|
@@ -702,11 +664,11 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
702
664
|
}
|
|
703
665
|
|
|
704
666
|
if (queries.length) {
|
|
705
|
-
const q = queries
|
|
706
|
-
this.log("TableConfig
|
|
667
|
+
const q = makeQuery(queries);
|
|
668
|
+
this.log("TableConfig >>>> ", q);
|
|
707
669
|
|
|
708
670
|
try {
|
|
709
|
-
await
|
|
671
|
+
await runQueries(queries);
|
|
710
672
|
if(migrations){
|
|
711
673
|
await this.db.any(`INSERT INTO ${migrations.table}(id, table_config) VALUES (${asValue(migrations.version)}, ${asValue(this.config)}) ON CONFLICT DO NOTHING;`)
|
|
712
674
|
}
|
|
@@ -732,25 +694,3 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
732
694
|
|
|
733
695
|
}
|
|
734
696
|
|
|
735
|
-
async function columnExists(args: { tableName: string; colName: string; db: DB }) {
|
|
736
|
-
const { db, tableName, colName } = args;
|
|
737
|
-
return Boolean((await db.oneOrNone(`
|
|
738
|
-
SELECT column_name, table_name
|
|
739
|
-
FROM information_schema.columns
|
|
740
|
-
WHERE table_name=${asValue(tableName)} and column_name=${asValue(colName)}
|
|
741
|
-
LIMIT 1;
|
|
742
|
-
`))?.column_name);
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
function getTableConstraings(db: DB, tableName: string): Promise<{ oid: number; conname: string; definition: string; }[]>{
|
|
746
|
-
return db.any(`
|
|
747
|
-
SELECT con.*, pg_get_constraintdef(con.oid)
|
|
748
|
-
FROM pg_catalog.pg_constraint con
|
|
749
|
-
INNER JOIN pg_catalog.pg_class rel
|
|
750
|
-
ON rel.oid = con.conrelid
|
|
751
|
-
INNER JOIN pg_catalog.pg_namespace nsp
|
|
752
|
-
ON nsp.oid = connamespace
|
|
753
|
-
WHERE 1=1
|
|
754
|
-
AND nsp.nspname = current_schema
|
|
755
|
-
AND rel.relname = ` + "${tableName}", { tableName })
|
|
756
|
-
}
|
|
@@ -11,22 +11,6 @@ type Args = {
|
|
|
11
11
|
* Column create statement for a given config
|
|
12
12
|
*/
|
|
13
13
|
export declare const getColumnDefinitionQuery: ({ colConf: colConfRaw, column, db, table }: Args) => Promise<string | undefined>;
|
|
14
|
-
export type ColConstraint = {
|
|
15
|
-
name: string;
|
|
16
|
-
table: string;
|
|
17
|
-
type: "c" | "p" | "u" | "f";
|
|
18
|
-
cols: Array<string>;
|
|
19
|
-
definition: string;
|
|
20
|
-
schema: string;
|
|
21
|
-
};
|
|
22
|
-
type ColConstraintsArgs = {
|
|
23
|
-
db: DB | pgPromise.ITask<{}>;
|
|
24
|
-
table?: string;
|
|
25
|
-
column?: string;
|
|
26
|
-
types?: ColConstraint["type"][];
|
|
27
|
-
};
|
|
28
|
-
export declare const getColConstraintsQuery: ({ column, table, types }: Omit<ColConstraintsArgs, "db">) => string;
|
|
29
|
-
export declare const getColConstraints: ({ db, column, table, types }: ColConstraintsArgs) => Promise<ColConstraint[]>;
|
|
30
14
|
export type ColumnMinimalInfo = {
|
|
31
15
|
table_name: string;
|
|
32
16
|
table_schema: string;
|
|
@@ -35,9 +19,9 @@ export type ColumnMinimalInfo = {
|
|
|
35
19
|
udt_name: string;
|
|
36
20
|
nullable: boolean;
|
|
37
21
|
};
|
|
38
|
-
export declare const getTableColumns: ({ db,
|
|
39
|
-
db: DB
|
|
40
|
-
|
|
22
|
+
export declare const getTableColumns: ({ db, table }: {
|
|
23
|
+
db: DB | pgPromise.ITask<{}>;
|
|
24
|
+
table: string;
|
|
41
25
|
}) => Promise<ColumnMinimalInfo[]>;
|
|
42
26
|
export {};
|
|
43
27
|
//# sourceMappingURL=getColumnDefinitionQuery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getColumnDefinitionQuery.d.ts","sourceRoot":"","sources":["getColumnDefinitionQuery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAGlC,OAAO,EAAmB,YAAY,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,SAAS,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"getColumnDefinitionQuery.d.ts","sourceRoot":"","sources":["getColumnDefinitionQuery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAGlC,OAAO,EAAmB,YAAY,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,SAAS,MAAM,YAAY,CAAC;AAGnC,KAAK,IAAI,GAAG;IACV,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,CAAC;IACtB,EAAE,EAAE,EAAE,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,+CAAsD,IAAI,KAAG,QAAQ,MAAM,GAAG,SAAS,CAiF3H,CAAA;AAGD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AACF,eAAO,MAAM,eAAe;QAAyB,EAAE,GAAG,UAAU,KAAK,CAAC,EAAE,CAAC;WAAS,MAAM;MAAK,QAAQ,iBAAiB,EAAE,CAS3H,CAAA"}
|