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.
Files changed (56) hide show
  1. package/dist/Prostgles.d.ts +6 -1
  2. package/dist/Prostgles.d.ts.map +1 -1
  3. package/dist/Prostgles.js +6 -2
  4. package/dist/Prostgles.js.map +1 -1
  5. package/dist/TableConfig/TableConfig.d.ts.map +1 -1
  6. package/dist/TableConfig/TableConfig.js +81 -147
  7. package/dist/TableConfig/TableConfig.js.map +1 -1
  8. package/dist/TableConfig/getColumnDefinitionQuery.d.ts +3 -19
  9. package/dist/TableConfig/getColumnDefinitionQuery.d.ts.map +1 -1
  10. package/dist/TableConfig/getColumnDefinitionQuery.js +5 -38
  11. package/dist/TableConfig/getColumnDefinitionQuery.js.map +1 -1
  12. package/dist/TableConfig/getConstraintDefinitionQueries.d.ts +27 -1
  13. package/dist/TableConfig/getConstraintDefinitionQueries.d.ts.map +1 -1
  14. package/dist/TableConfig/getConstraintDefinitionQueries.js +40 -6
  15. package/dist/TableConfig/getConstraintDefinitionQueries.js.map +1 -1
  16. package/dist/TableConfig/getFutureTableSchema.d.ts +15 -0
  17. package/dist/TableConfig/getFutureTableSchema.d.ts.map +1 -0
  18. package/dist/TableConfig/getFutureTableSchema.js +51 -0
  19. package/dist/TableConfig/getFutureTableSchema.js.map +1 -0
  20. package/dist/TableConfig/getTableColumnQueries.d.ts +16 -0
  21. package/dist/TableConfig/getTableColumnQueries.d.ts.map +1 -0
  22. package/dist/TableConfig/getTableColumnQueries.js +108 -0
  23. package/dist/TableConfig/getTableColumnQueries.js.map +1 -0
  24. package/lib/Prostgles.d.ts +6 -1
  25. package/lib/Prostgles.d.ts.map +1 -1
  26. package/lib/Prostgles.js +6 -2
  27. package/lib/Prostgles.ts +12 -3
  28. package/lib/TableConfig/TableConfig.d.ts.map +1 -1
  29. package/lib/TableConfig/TableConfig.js +81 -147
  30. package/lib/TableConfig/TableConfig.ts +94 -154
  31. package/lib/TableConfig/getColumnDefinitionQuery.d.ts +3 -19
  32. package/lib/TableConfig/getColumnDefinitionQuery.d.ts.map +1 -1
  33. package/lib/TableConfig/getColumnDefinitionQuery.js +5 -38
  34. package/lib/TableConfig/getColumnDefinitionQuery.ts +4 -46
  35. package/lib/TableConfig/getConstraintDefinitionQueries.d.ts +27 -1
  36. package/lib/TableConfig/getConstraintDefinitionQueries.d.ts.map +1 -1
  37. package/lib/TableConfig/getConstraintDefinitionQueries.js +40 -6
  38. package/lib/TableConfig/getConstraintDefinitionQueries.ts +64 -6
  39. package/lib/TableConfig/getFutureTableSchema.d.ts +15 -0
  40. package/lib/TableConfig/getFutureTableSchema.d.ts.map +1 -0
  41. package/lib/TableConfig/getFutureTableSchema.js +50 -0
  42. package/lib/TableConfig/getFutureTableSchema.ts +73 -0
  43. package/lib/TableConfig/getTableColumnQueries.d.ts +16 -0
  44. package/lib/TableConfig/getTableColumnQueries.d.ts.map +1 -0
  45. package/lib/TableConfig/getTableColumnQueries.js +107 -0
  46. package/lib/TableConfig/getTableColumnQueries.ts +130 -0
  47. package/package.json +1 -1
  48. package/tests/client/PID.txt +1 -1
  49. package/tests/config_test/index.ts +1 -2
  50. package/tests/config_test/init.sql +1 -8
  51. package/tests/server/DBoGenerated.d.ts +12 -2
  52. package/tests/server/index.js +5 -1
  53. package/tests/server/index.ts +5 -1
  54. package/tests/server/init.sql +1 -7
  55. package/tests/server/package-lock.json +1 -1
  56. 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 validate_jsonb_schema_sql_1 = require("../JSONBValidation/validate_jsonb_schema_sql");
8
- const getColumnDefinitionQuery_1 = require("./getColumnDefinitionQuery");
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, getColumnDefinitionQuery_1.getColConstraints)({ db: this.db, table, column: col, types }) });
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(async (tableNameRaw) => {
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
- const q = queries.join("\n");
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 constraintQueries = (0, getConstraintDefinitionQueries_1.getConstraintDefinitionQueries)({ tableName, tableConf: tableConf });
198
- if ("columns" in tableConf) {
199
- const colCreateLines = [];
200
- const tableHandler = this.dbo[tableName];
201
- if (tableConf.columns) {
202
- const hasJSONBValidation = (0, prostgles_types_1.getKeys)(tableConf.columns).some(c => {
203
- const cConf = tableConf.columns?.[c];
204
- return cConf && (0, prostgles_types_1.isObject)(cConf) && (cConf.jsonbSchema || cConf.jsonbSchemaType);
205
- });
206
- /** Must install validation function */
207
- if (hasJSONBValidation) {
208
- try {
209
- await this.db.any(validate_jsonb_schema_sql_1.validate_jsonb_schema_sql);
210
- }
211
- catch (err) {
212
- console.error("Could not install the jsonb validation function due to error: ", err);
213
- throw err;
214
- }
215
- }
216
- const columns = (0, prostgles_types_1.getKeys)(tableConf.columns).filter(c => {
217
- const colDef = tableConf.columns[c];
218
- /** Exclude NamedJoinColumn */
219
- return typeof colDef === "string" || !("joinDef" in colDef);
220
- });
221
- const columnDefs = [];
222
- for await (const colName of columns) {
223
- const colConf = tableConf.columns[colName];
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);
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
- /** 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) {
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
- if (colCreateLines.length) {
295
- queries.push([
296
- `CREATE TABLE ${asName(tableName)} (`,
297
- colCreateLines.join(", \n"),
298
- `);`
299
- ].join("\n"));
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.join("\n");
383
- this.log("TableConfig: \n", q);
337
+ const q = makeQuery(queries);
338
+ this.log("TableConfig >>>> ", q);
384
339
  try {
385
- await this.db.multi(q);
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 { validate_jsonb_schema_sql } from "../JSONBValidation/validate_jsonb_schema_sql";
6
- import { ColConstraint, ColumnMinimalInfo, getColConstraints, getColumnDefinitionQuery, getTableColumns } from "./getColumnDefinitionQuery";
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(async tableNameRaw => {
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
- const q = queries.join("\n");
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 constraintQueries = getConstraintDefinitionQueries({ tableName, tableConf: tableConf as any });
498
- if ("columns" in tableConf) {
499
- const colCreateLines: string[] = [];
500
- const tableHandler = this.dbo[tableName];
501
- if (tableConf.columns) {
502
- const hasJSONBValidation = getKeys(tableConf.columns).some(c => {
503
- const cConf = tableConf.columns?.[c];
504
- return cConf && isObject(cConf) && (cConf.jsonbSchema || cConf.jsonbSchemaType)
505
- });
506
-
507
- /** Must install validation function */
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
- queries.push(`
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
- const { tableName: lookupTable } = colConf.references;
546
- this.log(`TableConfigurator: ${tableName}(${colName})` + " referenced lookup table " + lookupTable);
547
- } else {
548
- this.log(`TableConfigurator: created/added column ${tableName}(${colName}) `)
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
- /** 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
-
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
- if (colCreateLines.length) {
601
- queries.push([
602
- `CREATE TABLE ${asName(tableName)} (`,
603
- colCreateLines.join(", \n"),
604
- `);`
605
- ].join("\n"))
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
- queries.push(...constraintQueries ?? []);
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.join("\n");
706
- this.log("TableConfig: \n", q);
667
+ const q = makeQuery(queries);
668
+ this.log("TableConfig >>>> ", q);
707
669
 
708
670
  try {
709
- await this.db.multi(q);
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, tableName }: {
39
- db: DB;
40
- tableName: string;
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;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
+ {"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"}