prostgles-server 3.0.129 → 3.0.131
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/TableConfig/TableConfig.d.ts +2 -2
- package/dist/TableConfig/TableConfig.d.ts.map +1 -1
- package/dist/TableConfig/TableConfig.js +65 -34
- package/dist/TableConfig/TableConfig.js.map +1 -1
- package/dist/TableConfig/getColumnDefinitionQuery.d.ts +22 -2
- package/dist/TableConfig/getColumnDefinitionQuery.d.ts.map +1 -1
- package/dist/TableConfig/getColumnDefinitionQuery.js +29 -13
- package/dist/TableConfig/getColumnDefinitionQuery.js.map +1 -1
- package/dist/TableConfig/getConstraintDefinitionQueries.d.ts +8 -0
- package/dist/TableConfig/getConstraintDefinitionQueries.d.ts.map +1 -0
- package/dist/TableConfig/getConstraintDefinitionQueries.js +32 -0
- package/dist/TableConfig/getConstraintDefinitionQueries.js.map +1 -0
- package/lib/TableConfig/TableConfig.d.ts +2 -2
- package/lib/TableConfig/TableConfig.d.ts.map +1 -1
- package/lib/TableConfig/TableConfig.js +65 -34
- package/lib/TableConfig/TableConfig.ts +97 -63
- package/lib/TableConfig/getColumnDefinitionQuery.d.ts +22 -2
- package/lib/TableConfig/getColumnDefinitionQuery.d.ts.map +1 -1
- package/lib/TableConfig/getColumnDefinitionQuery.js +29 -13
- package/lib/TableConfig/getColumnDefinitionQuery.ts +43 -14
- package/lib/TableConfig/getConstraintDefinitionQueries.d.ts +8 -0
- package/lib/TableConfig/getConstraintDefinitionQueries.d.ts.map +1 -0
- package/lib/TableConfig/getConstraintDefinitionQueries.js +31 -0
- package/lib/TableConfig/getConstraintDefinitionQueries.ts +37 -0
- package/package.json +1 -1
- package/tests/client/PID.txt +1 -1
- package/tests/server/package-lock.json +1 -1
|
@@ -6,6 +6,7 @@ const DboBuilder_1 = require("../DboBuilder");
|
|
|
6
6
|
const PubSubManager_1 = require("../PubSubManager/PubSubManager");
|
|
7
7
|
const validate_jsonb_schema_sql_1 = require("../JSONBValidation/validate_jsonb_schema_sql");
|
|
8
8
|
const getColumnDefinitionQuery_1 = require("./getColumnDefinitionQuery");
|
|
9
|
+
const getConstraintDefinitionQueries_1 = require("./getConstraintDefinitionQueries");
|
|
9
10
|
const parseI18N = (params) => {
|
|
10
11
|
const { config, lang, defaultLang, defaultValue } = params;
|
|
11
12
|
if (config) {
|
|
@@ -150,7 +151,7 @@ class TableConfigurator {
|
|
|
150
151
|
catch (e) {
|
|
151
152
|
}
|
|
152
153
|
if (!existingVersion || existingVersion < version) {
|
|
153
|
-
await onMigrate({ db: this.db, oldVersion: existingVersion, getConstraints: (table, col, types) => (0, getColumnDefinitionQuery_1.getColConstraints)(this.db, table, col, types) });
|
|
154
|
+
await onMigrate({ db: this.db, oldVersion: existingVersion, getConstraints: (table, col, types) => (0, getColumnDefinitionQuery_1.getColConstraints)({ db: this.db, table, column: col, types }) });
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
157
|
/* Create lookup tables */
|
|
@@ -170,9 +171,9 @@ class TableConfigurator {
|
|
|
170
171
|
if (isDropped || !this.dbo?.[tableNameRaw]) {
|
|
171
172
|
const columnNames = Object.keys(rows[0]).filter(k => k !== "id");
|
|
172
173
|
queries.push(`CREATE TABLE IF NOT EXISTS ${tableName} (
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
id TEXT PRIMARY KEY
|
|
175
|
+
${columnNames.length ? (", " + columnNames.map(k => asName(k) + " TEXT ").join(", ")) : ""}
|
|
176
|
+
);`);
|
|
176
177
|
rows.map(row => {
|
|
177
178
|
const values = this.prostgles.pgp.helpers.values(row);
|
|
178
179
|
queries.push(this.prostgles.pgp.as.format(`INSERT INTO ${tableName} (${["id", ...columnNames].map(t => asName(t)).join(", ")}) ` + " VALUES ${values:raw} ;", { values }));
|
|
@@ -190,9 +191,10 @@ class TableConfigurator {
|
|
|
190
191
|
await this.prostgles.refreshDBO();
|
|
191
192
|
}
|
|
192
193
|
queries = [];
|
|
193
|
-
/* Create columns */
|
|
194
|
+
/* Create/Alter columns */
|
|
194
195
|
for await (const tableName of (0, prostgles_types_1.getKeys)(this.config)) {
|
|
195
196
|
const tableConf = this.config[tableName];
|
|
197
|
+
const constraintQueries = (0, getConstraintDefinitionQueries_1.getConstraintDefinitionQueries)({ tableName, tableConf: tableConf });
|
|
196
198
|
if ("columns" in tableConf) {
|
|
197
199
|
const colCreateLines = [];
|
|
198
200
|
const tableHandler = this.dbo[tableName];
|
|
@@ -204,12 +206,7 @@ class TableConfigurator {
|
|
|
204
206
|
/** Must install validation function */
|
|
205
207
|
if (hasJSONBValidation) {
|
|
206
208
|
try {
|
|
207
|
-
|
|
208
|
-
/* prevent duplicate key value violates unique constraint "pg_namespace_nspname_index" Key (nspname)=(prostgles) already exists.*/
|
|
209
|
-
LOCK TABLE pg_catalog.pg_namespace IN SHARE ROW EXCLUSIVE MODE;
|
|
210
|
-
CREATE SCHEMA IF NOT EXISTS prostgles;\n
|
|
211
|
-
${validate_jsonb_schema_sql_1.validate_jsonb_schema_sql}`;
|
|
212
|
-
await this.db.any(fileContent);
|
|
209
|
+
await this.db.any(validate_jsonb_schema_sql_1.validate_jsonb_schema_sql);
|
|
213
210
|
}
|
|
214
211
|
catch (err) {
|
|
215
212
|
console.error("Could not install the jsonb validation function due to error: ", err);
|
|
@@ -218,23 +215,30 @@ class TableConfigurator {
|
|
|
218
215
|
}
|
|
219
216
|
const columns = (0, prostgles_types_1.getKeys)(tableConf.columns).filter(c => {
|
|
220
217
|
const colDef = tableConf.columns[c];
|
|
218
|
+
/** Exclude NamedJoinColumn */
|
|
221
219
|
return typeof colDef === "string" || !("joinDef" in colDef);
|
|
222
220
|
});
|
|
221
|
+
const columnDefs = [];
|
|
223
222
|
for await (const colName of columns) {
|
|
224
223
|
const colConf = tableConf.columns[colName];
|
|
225
|
-
/* Add
|
|
226
|
-
|
|
227
|
-
|
|
224
|
+
/* Add column to create statement */
|
|
225
|
+
const colDef = await (0, getColumnDefinitionQuery_1.getColumnDefinitionQuery)({ colConf, column: colName, db: this.db, table: tableName });
|
|
226
|
+
if (!colDef) {
|
|
227
|
+
// Column has only labels
|
|
228
|
+
}
|
|
229
|
+
else if (!tableHandler) {
|
|
230
|
+
columnDefs.push(colDef);
|
|
228
231
|
colCreateLines.push(colDef);
|
|
232
|
+
/** Alter existing column */
|
|
229
233
|
}
|
|
230
234
|
else if (tableHandler && !tableHandler.columns?.find(c => colName === c.name)) {
|
|
231
|
-
|
|
235
|
+
columnDefs.push(colDef);
|
|
232
236
|
queries.push(`
|
|
233
237
|
ALTER TABLE ${asName(tableName)}
|
|
234
238
|
ADD COLUMN ${colDef};
|
|
235
239
|
`);
|
|
236
240
|
if ((0, prostgles_types_1.isObject)(colConf) && "references" in colConf && colConf.references) {
|
|
237
|
-
const { tableName: lookupTable
|
|
241
|
+
const { tableName: lookupTable } = colConf.references;
|
|
238
242
|
this.log(`TableConfigurator: ${tableName}(${colName})` + " referenced lookup table " + lookupTable);
|
|
239
243
|
}
|
|
240
244
|
else {
|
|
@@ -242,6 +246,50 @@ class TableConfigurator {
|
|
|
242
246
|
}
|
|
243
247
|
}
|
|
244
248
|
}
|
|
249
|
+
/** Remove droped/altered constraints */
|
|
250
|
+
if (tableHandler && columnDefs.length) {
|
|
251
|
+
let newConstraints = [];
|
|
252
|
+
let newCols = [];
|
|
253
|
+
try {
|
|
254
|
+
await this.db.tx(async (t) => {
|
|
255
|
+
const { v } = await t.one("SELECT md5(random()::text) as v");
|
|
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) {
|
|
268
|
+
}
|
|
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
|
+
}
|
|
245
293
|
}
|
|
246
294
|
if (colCreateLines.length) {
|
|
247
295
|
queries.push([
|
|
@@ -252,24 +300,7 @@ class TableConfigurator {
|
|
|
252
300
|
this.log("TableConfigurator: Created table: \n" + queries.at(-1));
|
|
253
301
|
}
|
|
254
302
|
}
|
|
255
|
-
|
|
256
|
-
const constraints = await getTableConstraings(this.db, tableName);
|
|
257
|
-
const constraintNames = (0, prostgles_types_1.getKeys)(tableConf.constraints);
|
|
258
|
-
constraintNames.map(constraintName => {
|
|
259
|
-
const _cnstr = tableConf.constraints[constraintName];
|
|
260
|
-
const constraintDef = typeof _cnstr === "string" ? _cnstr : `${_cnstr.type} (${_cnstr.content})`;
|
|
261
|
-
const canDrop = (0, prostgles_types_1.isObject)(_cnstr) && _cnstr.dropIfExists;
|
|
262
|
-
/** Drop constraints with the same name */
|
|
263
|
-
const existingConstraint = constraints.some(c => c.conname === constraintName);
|
|
264
|
-
if (existingConstraint) {
|
|
265
|
-
if (canDrop)
|
|
266
|
-
queries.push(`ALTER TABLE ${asName(tableName)} DROP CONSTRAINT ${asName(constraintName)};`);
|
|
267
|
-
}
|
|
268
|
-
if (!existingConstraint || canDrop) {
|
|
269
|
-
queries.push(`ALTER TABLE ${asName(tableName)} ADD CONSTRAINT ${asName(constraintName)} ${constraintDef} ;`);
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
}
|
|
303
|
+
queries.push(...constraintQueries ?? []);
|
|
273
304
|
if ("indexes" in tableConf && tableConf.indexes) {
|
|
274
305
|
/*
|
|
275
306
|
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
|
|
@@ -3,8 +3,8 @@ import { isPlainObject, JoinInfo } from "../DboBuilder";
|
|
|
3
3
|
import { DB, DBHandlerServer, Prostgles } from "../Prostgles";
|
|
4
4
|
import { asValue } from "../PubSubManager/PubSubManager";
|
|
5
5
|
import { validate_jsonb_schema_sql } from "../JSONBValidation/validate_jsonb_schema_sql";
|
|
6
|
-
import { getColConstraints, getColumnDefinitionQuery } from "./getColumnDefinitionQuery";
|
|
7
|
-
import {
|
|
6
|
+
import { ColConstraint, ColumnMinimalInfo, getColConstraints, getColumnDefinitionQuery, getTableColumns } from "./getColumnDefinitionQuery";
|
|
7
|
+
import { getConstraintDefinitionQueries } from "./getConstraintDefinitionQueries";
|
|
8
8
|
|
|
9
9
|
type ColExtraInfo = {
|
|
10
10
|
min?: string | number;
|
|
@@ -208,33 +208,35 @@ type StrictUnionHelper<T, TAll> = T extends any ? T & Partial<Record<Exclude<Uni
|
|
|
208
208
|
export type StrictUnion<T> = StrictUnionHelper<T, T>
|
|
209
209
|
|
|
210
210
|
export const CONSTRAINT_TYPES = ["PRIMARY KEY", "UNIQUE", "CHECK"] as const; // "FOREIGN KEY",
|
|
211
|
-
type TableDefinition<LANG_IDS> = {
|
|
211
|
+
export type TableDefinition<LANG_IDS> = {
|
|
212
212
|
columns?: {
|
|
213
213
|
[column_name: string]: ColumnConfig<LANG_IDS>
|
|
214
214
|
},
|
|
215
|
-
constraints?:
|
|
216
|
-
|
|
217
|
-
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
215
|
+
constraints?:
|
|
216
|
+
| string[]
|
|
217
|
+
| {
|
|
218
|
+
[constraint_name: string]:
|
|
219
|
+
| string
|
|
220
|
+
| {
|
|
221
|
+
type: typeof CONSTRAINT_TYPES[number];
|
|
222
|
+
dropIfExists?: boolean;
|
|
223
|
+
/**
|
|
224
|
+
* E.g.:
|
|
225
|
+
* colname
|
|
226
|
+
* col1, col2
|
|
227
|
+
* col1 > col3
|
|
228
|
+
*/
|
|
229
|
+
content: string;
|
|
230
|
+
}
|
|
231
|
+
// & ({
|
|
232
|
+
// }
|
|
233
|
+
// | {
|
|
234
|
+
// type: "FOREIGN KEY",
|
|
235
|
+
// columns: string[];
|
|
236
|
+
// ftable: string;
|
|
237
|
+
// fcols: string[];
|
|
238
|
+
// }
|
|
239
|
+
// )
|
|
238
240
|
},
|
|
239
241
|
|
|
240
242
|
/**
|
|
@@ -442,7 +444,7 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
442
444
|
}
|
|
443
445
|
|
|
444
446
|
if(!existingVersion || existingVersion < version){
|
|
445
|
-
await onMigrate({ db: this.db, oldVersion: existingVersion, getConstraints: (table, col, types) => getColConstraints(this.db, table, col, types) })
|
|
447
|
+
await onMigrate({ db: this.db, oldVersion: existingVersion, getConstraints: (table, col, types) => getColConstraints({ db: this.db, table, column: col, types }) })
|
|
446
448
|
}
|
|
447
449
|
}
|
|
448
450
|
|
|
@@ -463,10 +465,12 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
463
465
|
const rows = Object.keys(tableConf.isLookupTable?.values).map(id => ({ id, ...(tableConf.isLookupTable?.values[id]) }));
|
|
464
466
|
if (isDropped || !this.dbo?.[tableNameRaw]) {
|
|
465
467
|
const columnNames = Object.keys(rows[0]).filter(k => k !== "id");
|
|
466
|
-
queries.push(
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
468
|
+
queries.push(
|
|
469
|
+
`CREATE TABLE IF NOT EXISTS ${tableName} (
|
|
470
|
+
id TEXT PRIMARY KEY
|
|
471
|
+
${columnNames.length? (", " + columnNames.map(k => asName(k) + " TEXT ").join(", ")) : ""}
|
|
472
|
+
);`
|
|
473
|
+
);
|
|
470
474
|
|
|
471
475
|
rows.map(row => {
|
|
472
476
|
const values = this.prostgles.pgp!.helpers.values(row)
|
|
@@ -487,9 +491,10 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
487
491
|
}
|
|
488
492
|
queries = [];
|
|
489
493
|
|
|
490
|
-
/* Create columns */
|
|
494
|
+
/* Create/Alter columns */
|
|
491
495
|
for await (const tableName of getKeys(this.config)){
|
|
492
496
|
const tableConf = this.config![tableName];
|
|
497
|
+
const constraintQueries = getConstraintDefinitionQueries({ tableName, tableConf: tableConf as any });
|
|
493
498
|
if ("columns" in tableConf) {
|
|
494
499
|
const colCreateLines: string[] = [];
|
|
495
500
|
const tableHandler = this.dbo[tableName];
|
|
@@ -502,13 +507,7 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
502
507
|
/** Must install validation function */
|
|
503
508
|
if(hasJSONBValidation){
|
|
504
509
|
try {
|
|
505
|
-
|
|
506
|
-
const fileContent = `
|
|
507
|
-
/* prevent duplicate key value violates unique constraint "pg_namespace_nspname_index" Key (nspname)=(prostgles) already exists.*/
|
|
508
|
-
LOCK TABLE pg_catalog.pg_namespace IN SHARE ROW EXCLUSIVE MODE;
|
|
509
|
-
CREATE SCHEMA IF NOT EXISTS prostgles;\n
|
|
510
|
-
${validate_jsonb_schema_sql}`;
|
|
511
|
-
await this.db.any(fileContent);
|
|
510
|
+
await this.db.any(validate_jsonb_schema_sql);
|
|
512
511
|
} catch(err: any){
|
|
513
512
|
console.error("Could not install the jsonb validation function due to error: ", err);
|
|
514
513
|
throw err;
|
|
@@ -517,34 +516,85 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
517
516
|
|
|
518
517
|
const columns = getKeys(tableConf.columns).filter(c => {
|
|
519
518
|
const colDef = tableConf.columns![c];
|
|
519
|
+
/** Exclude NamedJoinColumn */
|
|
520
520
|
return typeof colDef === "string" || !("joinDef" in colDef)
|
|
521
521
|
});
|
|
522
522
|
|
|
523
|
+
const columnDefs: string[] = [];
|
|
523
524
|
for await(const colName of columns) {
|
|
524
525
|
const colConf = tableConf.columns![colName];
|
|
525
526
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
if
|
|
529
|
-
|
|
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);
|
|
530
533
|
colCreateLines.push(colDef);
|
|
531
534
|
|
|
535
|
+
/** Alter existing column */
|
|
532
536
|
} else if (tableHandler && !tableHandler.columns?.find(c => colName === c.name)) {
|
|
533
|
-
|
|
537
|
+
columnDefs.push(colDef);
|
|
534
538
|
|
|
535
539
|
queries.push(`
|
|
536
540
|
ALTER TABLE ${asName(tableName)}
|
|
537
541
|
ADD COLUMN ${colDef};
|
|
538
542
|
`);
|
|
539
|
-
if
|
|
543
|
+
if(isObject(colConf) && "references" in colConf && colConf.references){
|
|
540
544
|
|
|
541
|
-
const { tableName: lookupTable
|
|
545
|
+
const { tableName: lookupTable } = colConf.references;
|
|
542
546
|
this.log(`TableConfigurator: ${tableName}(${colName})` + " referenced lookup table " + lookupTable);
|
|
543
547
|
} else {
|
|
544
548
|
this.log(`TableConfigurator: created/added column ${tableName}(${colName}) `)
|
|
545
549
|
}
|
|
546
550
|
}
|
|
547
551
|
}
|
|
552
|
+
|
|
553
|
+
/** Remove droped/altered constraints */
|
|
554
|
+
if(tableHandler && columnDefs.length){
|
|
555
|
+
let newConstraints: ColConstraint[] = [];
|
|
556
|
+
let newCols: ColumnMinimalInfo[] = [];
|
|
557
|
+
try {
|
|
558
|
+
await this.db.tx(async t => {
|
|
559
|
+
const { v } = await t.one("SELECT md5(random()::text) as v");
|
|
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
|
+
|
|
575
|
+
}
|
|
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
|
+
}
|
|
548
598
|
}
|
|
549
599
|
|
|
550
600
|
if (colCreateLines.length) {
|
|
@@ -556,23 +606,7 @@ export default class TableConfigurator<LANG_IDS = { en: 1 }> {
|
|
|
556
606
|
this.log("TableConfigurator: Created table: \n" + queries.at(-1))
|
|
557
607
|
}
|
|
558
608
|
}
|
|
559
|
-
|
|
560
|
-
const constraints = await getTableConstraings(this.db, tableName);
|
|
561
|
-
const constraintNames = getKeys(tableConf.constraints);
|
|
562
|
-
constraintNames.map(constraintName => {
|
|
563
|
-
const _cnstr = tableConf.constraints![constraintName];
|
|
564
|
-
const constraintDef = typeof _cnstr === "string"? _cnstr : `${_cnstr.type} (${_cnstr.content})`;
|
|
565
|
-
const canDrop = isObject(_cnstr) && _cnstr.dropIfExists;
|
|
566
|
-
/** Drop constraints with the same name */
|
|
567
|
-
const existingConstraint = constraints.some(c => c.conname === constraintName);
|
|
568
|
-
if(existingConstraint){
|
|
569
|
-
if(canDrop) queries.push(`ALTER TABLE ${asName(tableName)} DROP CONSTRAINT ${asName(constraintName)};`);
|
|
570
|
-
}
|
|
571
|
-
if(!existingConstraint || canDrop){
|
|
572
|
-
queries.push(`ALTER TABLE ${asName(tableName)} ADD CONSTRAINT ${asName(constraintName)} ${constraintDef} ;`);
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
}
|
|
609
|
+
queries.push(...constraintQueries ?? []);
|
|
576
610
|
if ("indexes" in tableConf && tableConf.indexes) {
|
|
577
611
|
/*
|
|
578
612
|
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DB } from "../Prostgles";
|
|
2
2
|
import { ColumnConfig } from "./TableConfig";
|
|
3
|
+
import pgPromise from "pg-promise";
|
|
3
4
|
type Args = {
|
|
4
5
|
column: string;
|
|
5
6
|
colConf: ColumnConfig;
|
|
@@ -9,7 +10,7 @@ type Args = {
|
|
|
9
10
|
/**
|
|
10
11
|
* Column create statement for a given config
|
|
11
12
|
*/
|
|
12
|
-
export declare const getColumnDefinitionQuery: ({ colConf, column, db, table }: Args) => Promise<string>;
|
|
13
|
+
export declare const getColumnDefinitionQuery: ({ colConf: colConfRaw, column, db, table }: Args) => Promise<string | undefined>;
|
|
13
14
|
export type ColConstraint = {
|
|
14
15
|
name: string;
|
|
15
16
|
table: string;
|
|
@@ -18,6 +19,25 @@ export type ColConstraint = {
|
|
|
18
19
|
definition: string;
|
|
19
20
|
schema: string;
|
|
20
21
|
};
|
|
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
|
+
export type ColumnMinimalInfo = {
|
|
31
|
+
table_name: string;
|
|
32
|
+
table_schema: string;
|
|
33
|
+
column_name: string;
|
|
34
|
+
column_default: string | null;
|
|
35
|
+
udt_name: string;
|
|
36
|
+
nullable: boolean;
|
|
37
|
+
};
|
|
38
|
+
export declare const getTableColumns: ({ db, tableName }: {
|
|
39
|
+
db: DB;
|
|
40
|
+
tableName: string;
|
|
41
|
+
}) => Promise<ColumnMinimalInfo[]>;
|
|
22
42
|
export {};
|
|
23
43
|
//# 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;
|
|
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;AAEnC,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;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC5B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAA;AACD,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;CACjC,CAAA;AACD,eAAO,MAAM,sBAAsB,6BAA8B,KAAK,kBAAkB,EAAE,IAAI,CAAC,WAyB9F,CAAA;AACD,eAAO,MAAM,iBAAiB,iCAAkC,kBAAkB,KAAI,QAAQ,aAAa,EAAE,CAG5G,CAAA;AACD,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;;eAA4C,MAAM;MAAK,QAAQ,iBAAiB,EAAE,CAS7G,CAAA"}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getColConstraints = exports.getColumnDefinitionQuery = void 0;
|
|
3
|
+
exports.getTableColumns = exports.getColConstraints = exports.getColConstraintsQuery = exports.getColumnDefinitionQuery = void 0;
|
|
4
4
|
const prostgles_types_1 = require("prostgles-types");
|
|
5
5
|
const PubSubManager_1 = require("../PubSubManager/PubSubManager");
|
|
6
6
|
const validate_jsonb_schema_sql_1 = require("../JSONBValidation/validate_jsonb_schema_sql");
|
|
7
7
|
/**
|
|
8
8
|
* Column create statement for a given config
|
|
9
9
|
*/
|
|
10
|
-
const getColumnDefinitionQuery = async ({ colConf, column, db, table }) => {
|
|
10
|
+
const getColumnDefinitionQuery = async ({ colConf: colConfRaw, column, db, table }) => {
|
|
11
|
+
const colConf = typeof colConfRaw === "string" ? { sqlDefinition: colConfRaw } : colConfRaw;
|
|
11
12
|
const colNameEsc = (0, prostgles_types_1.asName)(column);
|
|
12
13
|
const getColTypeDef = (colConf, pgType) => {
|
|
13
14
|
const { nullable, defaultValue } = colConf;
|
|
14
15
|
return `${pgType} ${!nullable ? " NOT NULL " : ""} ${defaultValue ? ` DEFAULT ${(0, PubSubManager_1.asValue)(defaultValue)} ` : ""}`;
|
|
15
16
|
};
|
|
16
|
-
const jsonbSchema = (
|
|
17
|
+
const jsonbSchema = ("jsonbSchema" in colConf && colConf.jsonbSchema) ? { jsonbSchema: colConf.jsonbSchema, jsonbSchemaType: undefined } :
|
|
17
18
|
("jsonbSchemaType" in colConf && colConf.jsonbSchemaType) ? { jsonbSchema: undefined, jsonbSchemaType: colConf.jsonbSchemaType } :
|
|
18
|
-
undefined
|
|
19
|
-
|
|
20
|
-
if ((0, prostgles_types_1.isObject)(colConf) && "references" in colConf && colConf.references) {
|
|
19
|
+
undefined;
|
|
20
|
+
if ("references" in colConf && colConf.references) {
|
|
21
21
|
const { tableName: lookupTable, columnName: lookupCol = "id" } = colConf.references;
|
|
22
22
|
return ` ${colNameEsc} ${getColTypeDef(colConf.references, "TEXT")} REFERENCES ${lookupTable} (${lookupCol}) `;
|
|
23
23
|
}
|
|
24
|
-
else if (
|
|
25
|
-
return ` ${colNameEsc} ${
|
|
24
|
+
else if ("sqlDefinition" in colConf && colConf.sqlDefinition) {
|
|
25
|
+
return ` ${colNameEsc} ${colConf.sqlDefinition} `;
|
|
26
26
|
}
|
|
27
|
-
else if (
|
|
27
|
+
else if ("isText" in colConf && colConf.isText) {
|
|
28
28
|
let checks = "";
|
|
29
29
|
const colChecks = [];
|
|
30
30
|
if (colConf.lowerCased) {
|
|
@@ -62,7 +62,7 @@ const getColumnDefinitionQuery = async ({ colConf, column, db, table }) => {
|
|
|
62
62
|
const namePreffix = 'prostgles_jsonb_';
|
|
63
63
|
const { val: nameEnding } = await db.one("SELECT MD5( ${table} || ${column} || ${schema}) as val", { table: table, column, schema: jsonbSchemaStr });
|
|
64
64
|
const constraintName = namePreffix + nameEnding;
|
|
65
|
-
const colConstraints = await (0, exports.getColConstraints)(db, table, column);
|
|
65
|
+
const colConstraints = await (0, exports.getColConstraints)({ db, table, column });
|
|
66
66
|
const existingNonMatchingConstraints = colConstraints.filter(c => c.name.startsWith(namePreffix) && c.name !== constraintName);
|
|
67
67
|
for await (const oldCons of existingNonMatchingConstraints) {
|
|
68
68
|
await db.any(`ALTER TABLE ${(0, prostgles_types_1.asName)(table)} DROP CONSTRAINT ${(0, prostgles_types_1.asName)(oldCons.name)};`);
|
|
@@ -77,11 +77,12 @@ const getColumnDefinitionQuery = async ({ colConf, column, db, table }) => {
|
|
|
77
77
|
return ` ${colNameEsc} ${type} ${colConf.nullable ? "" : "NOT NULL"} ${"defaultValue" in colConf ? ` DEFAULT ${(0, PubSubManager_1.asValue)(colConf.defaultValue)}` : ""} CHECK(${checks})`;
|
|
78
78
|
}
|
|
79
79
|
else {
|
|
80
|
-
|
|
80
|
+
return undefined;
|
|
81
|
+
// throw "Unknown column config: " + JSON.stringify(colConf);
|
|
81
82
|
}
|
|
82
83
|
};
|
|
83
84
|
exports.getColumnDefinitionQuery = getColumnDefinitionQuery;
|
|
84
|
-
const
|
|
85
|
+
const getColConstraintsQuery = ({ column, table, types }) => {
|
|
85
86
|
let query = `
|
|
86
87
|
SELECT *
|
|
87
88
|
FROM (
|
|
@@ -108,6 +109,21 @@ const getColConstraints = (db, table, column, types) => {
|
|
|
108
109
|
query += `\nAND cols @> ARRAY[${(0, PubSubManager_1.asValue)(column)}]`;
|
|
109
110
|
if (types?.length)
|
|
110
111
|
query += `\nAND type IN (${types.map(v => (0, PubSubManager_1.asValue)(v)).join(", ")})`;
|
|
111
|
-
return
|
|
112
|
+
return query;
|
|
113
|
+
};
|
|
114
|
+
exports.getColConstraintsQuery = getColConstraintsQuery;
|
|
115
|
+
const getColConstraints = ({ db, column, table, types }) => {
|
|
116
|
+
return db.manyOrNone((0, exports.getColConstraintsQuery)({ column, table, types }));
|
|
112
117
|
};
|
|
113
118
|
exports.getColConstraints = getColConstraints;
|
|
119
|
+
const getTableColumns = ({ db, tableName }) => {
|
|
120
|
+
return db.manyOrNone(`
|
|
121
|
+
SELECT table_name,
|
|
122
|
+
table_schema, column_name,
|
|
123
|
+
column_default, udt_name,
|
|
124
|
+
is_nullable = 'YES' as nullable
|
|
125
|
+
FROM information_schema.columns
|
|
126
|
+
WHERE table_name = $1
|
|
127
|
+
`, [tableName]);
|
|
128
|
+
};
|
|
129
|
+
exports.getTableColumns = getTableColumns;
|