@andymic/pigeon 1.4.2 → 1.5.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andymic/pigeon",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "author": "Andreas Michael <ateasm03@gmail.com>",
5
5
  "description": "Pigeon is a TypeScript-based tool for generating TypeScript classes and methods from PostgreSQL database schemas.",
6
6
  "keywords": [
@@ -35,5 +35,5 @@
35
35
  "pg": "^8.15.6",
36
36
  "prompt-sync": "^4.2.0"
37
37
  },
38
- "gitHead": "04b72fd9eb0dde3a4005146b38d899b9655f0d83"
38
+ "gitHead": "06042d8920b14ccabf82d19113131bf977950d46"
39
39
  }
package/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { arrayMaker, consoleMessage, getCombinations, getType, nameBeautifier, queryMaker, runQuery, singularize, sleep, tabsInserter } from "./utils.js";
1
+ import { arrayMaker, getCombinations, getJSType, getPGType, nameBeautifier, queryMaker, runQuery, singularize, sleep, tabsInserter } from "./utils.js";
2
2
  import prompt from "prompt-sync";
3
3
  import fs from "node:fs";
4
4
  import * as path from "node:path";
@@ -27,20 +27,46 @@ export class Database {
27
27
  this.pass = pass;
28
28
  }
29
29
  }
30
+ export class Column {
31
+ name;
32
+ position;
33
+ defaultValue;
34
+ isNullable;
35
+ jsType;
36
+ pgType;
37
+ isIdentity;
38
+ identityGeneration;
39
+ isPrimary;
40
+ isUnique;
41
+ isForeign;
42
+ foreignSchema;
43
+ foreignTable;
44
+ foreignColumn;
45
+ constructor(name, position, defaultValue, isNullable, jsType, pgType, isIdentity, identityGeneration, isPrimary, isUnique, isForeign, foreignSchema, foreignTable, foreignColumn) {
46
+ this.name = name;
47
+ this.position = position;
48
+ this.defaultValue = defaultValue;
49
+ this.isNullable = isNullable;
50
+ this.jsType = jsType;
51
+ this.pgType = pgType;
52
+ this.isIdentity = isIdentity;
53
+ this.identityGeneration = identityGeneration;
54
+ this.isPrimary = isPrimary;
55
+ this.isUnique = isUnique;
56
+ this.isForeign = isForeign;
57
+ this.foreignSchema = foreignSchema;
58
+ this.foreignTable = foreignTable;
59
+ this.foreignColumn = foreignColumn;
60
+ }
61
+ }
30
62
  export class Table {
31
- table_schema;
32
- table_name;
63
+ name;
64
+ schema;
33
65
  columns = [];
34
- primaryKey;
35
- foreignKeys;
36
- unique;
37
- constructor(table_schema, table_name, columns, primaryKey, foreignKeys, unique) {
38
- this.table_schema = table_schema;
39
- this.table_name = table_name;
66
+ constructor(name, schema, columns) {
67
+ this.name = name;
68
+ this.schema = schema;
40
69
  this.columns = columns;
41
- this.primaryKey = primaryKey;
42
- this.foreignKeys = foreignKeys;
43
- this.unique = unique;
44
70
  }
45
71
  }
46
72
  export class Enum {
@@ -51,54 +77,6 @@ export class Enum {
51
77
  this.labels = labels;
52
78
  }
53
79
  }
54
- export class ColumnQueryRow {
55
- column_name;
56
- ordinal_position;
57
- column_default;
58
- is_nullable;
59
- data_type;
60
- udt_name;
61
- is_identity;
62
- identity_generation;
63
- constructor(column_name, ordinal_position, column_default, is_nullable, data_type, udt_name, is_identity, identity_generation) {
64
- this.column_name = column_name;
65
- this.ordinal_position = ordinal_position;
66
- this.column_default = column_default;
67
- this.is_nullable = is_nullable;
68
- this.data_type = data_type;
69
- this.udt_name = udt_name;
70
- this.is_identity = is_identity;
71
- this.identity_generation = identity_generation;
72
- }
73
- }
74
- export class PrimaryKeyQueryRow {
75
- column_name;
76
- constructor(column_name) {
77
- this.column_name = column_name;
78
- }
79
- }
80
- export class ForeignKeyQueryRow {
81
- local_schema;
82
- local_table;
83
- local_column;
84
- foreign_schema;
85
- foreign_table;
86
- foreign_column;
87
- constructor(local_schema, local_table, local_column, foreign_schema, foreign_table, foreign_column) {
88
- this.local_schema = local_schema;
89
- this.local_table = local_table;
90
- this.local_column = local_column;
91
- this.foreign_schema = foreign_schema;
92
- this.foreign_table = foreign_table;
93
- this.foreign_column = foreign_column;
94
- }
95
- }
96
- export class UniqueQueryRow {
97
- columns;
98
- constructor(columns) {
99
- this.columns = columns;
100
- }
101
- }
102
80
  function createDir(dirPath) {
103
81
  if (fs.existsSync(dirPath))
104
82
  return new PigeonError(1, "", new Error("Generation directory already exists. Add the --force flag if you want to overwrite it."));
@@ -210,6 +188,10 @@ export async function queryDB(db) {
210
188
  AND tc.table_name = $2::varchar;`, [table.table_schema, table.table_name], db);
211
189
  if (typeof pKeyQuery === "undefined")
212
190
  return new PigeonError(1, "", new Error("An SQL error has occurred."));
191
+ for (const pKey of pKeyQuery.rows)
192
+ for (const column of columnQuery.rows)
193
+ if (pKey.column_name === column.column_name)
194
+ column.isPrimary = true;
213
195
  const fKeyQuery = await runQuery(`SELECT kcu1.table_schema AS local_schema,
214
196
  kcu1.table_name AS local_table,
215
197
  kcu1.column_name AS local_column,
@@ -231,6 +213,16 @@ export async function queryDB(db) {
231
213
  AND kcu1.table_name = $2::varchar;`, [table.table_schema, table.table_name], db);
232
214
  if (typeof fKeyQuery === "undefined")
233
215
  return new PigeonError(1, "", new Error("An SQL error has occurred."));
216
+ for (const fKey of fKeyQuery.rows) {
217
+ for (const column of columnQuery.rows) {
218
+ if (fKey.local_schema === table.table_schema && fKey.local_table === table.table_name && fKey.local_column === column.column_name) {
219
+ column.isForeign = true;
220
+ column.foreignSchema = fKey.foreign_schema;
221
+ column.foreignTable = fKey.foreign_table;
222
+ column.foreignColumn = fKey.foreign_column;
223
+ }
224
+ }
225
+ }
234
226
  const uniqueQuery = await runQuery(`SELECT array_agg(a.attname) AS columns
235
227
  FROM pg_constraint AS c
236
228
  CROSS JOIN LATERAL unnest(c.conkey) AS k(c)
@@ -245,7 +237,15 @@ export async function queryDB(db) {
245
237
  let uniques = [];
246
238
  if (uniqueQuery.rowCount > 0)
247
239
  uniques = uniqueQuery.rows[0].columns.slice(1, -1).split(",");
248
- tables.push(new Table(table.table_schema, table.table_name, columnQuery.rows, pKeyQuery.rows[0], fKeyQuery.rows, { columns: uniques }));
240
+ for (const unique of uniques)
241
+ for (const column of columnQuery.rows)
242
+ if (unique === column.column_name)
243
+ column.isUnique = true;
244
+ const columns = [];
245
+ for (const column of columnQuery.rows) {
246
+ columns.push(new Column(column.column_name, column.ordinal_position, column.column_default, column.is_nullable === "YES", getJSType(column.data_type, column.udt_name, column.is_nullable === "YES"), getPGType(column.data_type, column.udt_name), column.is_identity === "YES", column.identity_generation, column.isPrimary || false, column.isUnique || false, column.isForeign || false, column.foreignSchema, column.foreignTable, column.foreignColumn));
247
+ }
248
+ tables.push(new Table(table.table_name, table.table_schema, columns));
249
249
  }
250
250
  return {
251
251
  tables: tables,
@@ -253,16 +253,16 @@ export async function queryDB(db) {
253
253
  };
254
254
  }
255
255
  export function runGeneration(dir, db, tables, enums) {
256
- if (!tables)
256
+ if (tables.length === 0)
257
257
  return new PigeonError(1, "", new Error("No tables were found."));
258
258
  const dirResult = createDir(dir);
259
259
  if (dirResult instanceof PigeonError)
260
260
  return dirResult;
261
261
  let schemas = [];
262
262
  for (const table of tables) {
263
- if (schemas.includes(table.table_schema))
263
+ if (schemas.includes(table.schema))
264
264
  continue;
265
- schemas.push(table.table_schema);
265
+ schemas.push(table.schema);
266
266
  }
267
267
  for (const schema of schemas) {
268
268
  const dirResult = createDir(path.join(dir, schema));
@@ -275,7 +275,7 @@ export function runGeneration(dir, db, tables, enums) {
275
275
  if (enums) {
276
276
  for (const cEnum of enums) {
277
277
  for (const column of table.columns) {
278
- if (cEnum.name === column.udt_name) {
278
+ if (column.pgType.includes(cEnum.name)) {
279
279
  const enumName = nameBeautifier(cEnum.name).replaceAll(" ", "");
280
280
  ts += "/**\n An Enum representing the " + nameBeautifier(cEnum.name).toLowerCase() + ".\n * @readonly\n * @enum {string}\n */\n";
281
281
  ts += "class " + enumName + " {\n";
@@ -290,37 +290,32 @@ export function runGeneration(dir, db, tables, enums) {
290
290
  }
291
291
  }
292
292
  }
293
- ts += createClass(table.table_name, table.columns, table.primaryKey?.column_name, table.foreignKeys);
293
+ ts += createClass(table.name, table.columns);
294
294
  ts += "\n\n";
295
- ts += createGetAll(table.table_schema, table.table_name, table.columns);
295
+ ts += createGetAll(table.schema, table.name, table.columns);
296
296
  ts += "\n\n";
297
297
  let keys = [];
298
- if (table.primaryKey)
299
- keys.push(table.primaryKey.column_name);
300
- if (table.foreignKeys)
301
- for (const fKey of table.foreignKeys)
302
- keys.push(fKey.local_column.replaceAll(" ", ""));
303
- if (table.unique)
304
- keys = keys.concat(table.unique.columns);
305
- keys = [...new Set(keys)];
298
+ for (const column of table.columns)
299
+ if (column.isPrimary || column.isForeign || column.isUnique)
300
+ keys.push(column);
306
301
  for (const keyCombination of getCombinations(keys)) {
307
- ts += createGet(table.table_schema, table.table_name, table.columns, keyCombination);
302
+ ts += createGet(table.schema, table.name, table.columns, keyCombination);
308
303
  ts += "\n\n";
309
304
  }
310
305
  let nonDefaults = [];
311
306
  let softDefaults = [];
312
307
  let hardDefaults = [];
313
308
  for (const column of table.columns) {
314
- if (column.column_default === null && column.is_identity === "NO")
309
+ if (column.defaultValue === null && !column.isIdentity)
315
310
  nonDefaults.push(column);
316
- else if ((column.column_default !== null && !column.column_default.includes("nextval")) || (column.is_identity === "YES" && column.identity_generation === "BY DEFAULT"))
311
+ else if ((column.defaultValue !== null && !column.defaultValue.includes("nextval")) || (column.isIdentity && column.identityGeneration === "BY DEFAULT"))
317
312
  softDefaults.push(column);
318
- else if ((column.column_default !== null && column.column_default.includes("nextval")) || (column.is_identity === "YES" && column.identity_generation === "ALWAYS"))
313
+ else if ((column.defaultValue !== null && column.defaultValue.includes("nextval")) || (column.isIdentity && column.identityGeneration === "ALWAYS"))
319
314
  hardDefaults.push(column);
320
315
  }
321
- ts += createAdd(table.table_schema, table.table_name, nonDefaults, [], hardDefaults.concat(softDefaults), table.foreignKeys) + "\n\n";
316
+ ts += createAdd(table.schema, table.name, nonDefaults, [], hardDefaults.concat(softDefaults)) + "\n\n";
322
317
  for (const softCombination of getCombinations(softDefaults))
323
- ts += createAdd(table.table_schema, table.table_name, nonDefaults, softCombination, hardDefaults.concat(softDefaults.filter(n => !getCombinations(softDefaults).includes([n]))), table.foreignKeys) + "\n\n";
318
+ ts += createAdd(table.schema, table.name, nonDefaults, softCombination, hardDefaults.concat(softDefaults.filter(n => !getCombinations(softDefaults).includes([n])))) + "\n\n";
324
319
  ts = ts.slice(0, -2);
325
320
  const regex = /import ({?.*?}?) from "(.*?)";\n/g;
326
321
  let importObjects = [];
@@ -365,47 +360,36 @@ export function runGeneration(dir, db, tables, enums) {
365
360
  importString += "import pg from \"pg\";\n\n";
366
361
  importString += "const {Client} = pg;\n\n";
367
362
  ts = importString + ts;
368
- fs.writeFileSync(path.join(dir, table.table_schema, table.table_name + ".ts"), ts);
363
+ fs.writeFileSync(path.join(dir, table.schema, table.name + ".ts"), ts);
369
364
  }
370
365
  }
371
- function createClass(tableName, columns, primaryKey, foreignKeys) {
366
+ function createClass(tableName, columns) {
372
367
  let text = "";
373
368
  text += "export class " + singularize(nameBeautifier(tableName)).replaceAll(" ", "") + " {\n";
374
369
  for (const column of columns) {
375
- let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
376
- if (column.is_nullable === "YES")
377
- dataType += " | undefined";
378
- let isPrimaryKey = false;
379
- if (column.column_name === primaryKey)
380
- isPrimaryKey = true;
381
- let foreignKeyIndex;
382
- if (foreignKeys)
383
- for (let i = 0; i < foreignKeys.length; i++)
384
- if (foreignKeys[i].local_column === column.column_name)
385
- foreignKeyIndex = i;
386
370
  text += "\t/**\n";
387
- if (isPrimaryKey)
388
- text += "\t * A primary key representing the " + nameBeautifier(column.column_name) + " for the " + nameBeautifier(tableName) + " table.\n";
389
- else if (foreignKeys && foreignKeyIndex)
390
- text += "\t * A foreign key representing the " + nameBeautifier(column.column_name) + " for the " + nameBeautifier(tableName) + " table and referencing the " + nameBeautifier(foreignKeys[foreignKeyIndex].foreign_column) + " in the " + nameBeautifier(foreignKeys[foreignKeyIndex].foreign_table) + " table in the " + nameBeautifier(foreignKeys[foreignKeyIndex].foreign_schema) + " schema.\n";
391
- else if (column.column_name.toLowerCase().startsWith("is_"))
392
- text += "\t * Indicates whether this record in the table " + nameBeautifier(tableName) + " is currently " + nameBeautifier(column.column_name.slice(3)).toLowerCase() + ".\n";
371
+ if (column.isPrimary)
372
+ text += "\t * A primary key representing the " + nameBeautifier(column.name) + " for the " + nameBeautifier(tableName) + " table.\n";
373
+ else if (column.isForeign && column.foreignColumn && column.foreignTable && column.foreignSchema)
374
+ text += "\t * A foreign key representing the " + nameBeautifier(column.name) + " for the " + nameBeautifier(tableName) + " table and referencing the " + nameBeautifier(column.foreignColumn) + " in the " + nameBeautifier(column.foreignTable) + " table in the " + nameBeautifier(column.foreignSchema) + " schema.\n";
375
+ else if (column.name.toLowerCase().startsWith("is_"))
376
+ text += "\t * Indicates whether this record in the table " + nameBeautifier(tableName) + " is currently " + nameBeautifier(column.name.slice(3)).toLowerCase() + ".\n";
393
377
  else
394
- text += "\t * The " + nameBeautifier(column.column_name) + " for the " + nameBeautifier(tableName) + " table.\n";
395
- text += "\t * @type {" + dataType + "}\n";
378
+ text += "\t * The " + nameBeautifier(column.name) + " for the " + nameBeautifier(tableName) + " table.\n";
379
+ text += "\t * @type {" + column.jsType + "}\n";
396
380
  text += "\t */\n";
397
- text += "\t" + column.column_name + ": " + dataType;
398
- if (column.column_default !== null) {
399
- let columnDefault = column.column_default.split("::")[0];
400
- let type = column.column_default.split("::")[1];
381
+ text += "\t" + column.name + ": " + column.jsType;
382
+ if (column.defaultValue !== null) {
383
+ let columnDefault = column.defaultValue.split("::")[0];
384
+ let type = column.defaultValue.split("::")[1];
401
385
  if (!columnDefault.includes("nextval")) {
402
- if (dataType === "Date") {
386
+ if (column.jsType === "Date") {
403
387
  if (columnDefault.toLowerCase() === "now()")
404
388
  text += " = new Date()";
405
389
  else
406
390
  text += " = new Date(" + columnDefault.replace(" ", "T") + ")";
407
391
  }
408
- else if (dataType === "number" || dataType === "boolean")
392
+ else if (column.jsType.includes("number") || column.jsType.includes("boolean"))
409
393
  text += " = " + columnDefault;
410
394
  else if (type) {
411
395
  if (jsTypes.get(type) === "string")
@@ -419,7 +403,7 @@ function createClass(tableName, columns, primaryKey, foreignKeys) {
419
403
  }
420
404
  }
421
405
  else
422
- text += " = \"" + column.column_default + "\"";
406
+ text += " = \"" + column.defaultValue + "\"";
423
407
  }
424
408
  }
425
409
  text += ";\n";
@@ -429,30 +413,20 @@ function createClass(tableName, columns, primaryKey, foreignKeys) {
429
413
  text += "\t * Creates a new object for the " + nameBeautifier(tableName) + " table.\n";
430
414
  text += "\t * \n";
431
415
  for (const column of columns) {
432
- let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
433
- text += "\t * ";
434
- text += "@param {" + dataType;
435
- if (column.is_nullable === "YES")
436
- text += " | undefined";
437
- text += "} " + column.column_name;
438
- if (!column.column_name.toLowerCase().startsWith("is_"))
439
- text += " - The " + nameBeautifier(column.column_name) + " of the " + nameBeautifier(tableName) + " table. \n";
416
+ text += "\t * @param {" + column.jsType + "} " + column.name;
417
+ if (!column.name.toLowerCase().startsWith("is_"))
418
+ text += " - The " + nameBeautifier(column.name) + " of the " + nameBeautifier(tableName) + " table. \n";
440
419
  else
441
- text += " - Indicates whether this record in the table " + nameBeautifier(tableName) + " is currently " + nameBeautifier(column.column_name.slice(3)).toLowerCase() + ".\n";
420
+ text += " - Indicates whether this record in the table " + nameBeautifier(tableName) + " is currently " + nameBeautifier(column.name.slice(3)).toLowerCase() + ".\n";
442
421
  }
443
422
  text += "\t */\n";
444
423
  text += "\tconstructor(";
445
- for (const column of columns) {
446
- let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
447
- text += column.column_name + ": " + dataType;
448
- if (column.is_nullable === "YES")
449
- text += " | undefined";
450
- text += ", ";
451
- }
424
+ for (const column of columns)
425
+ text += column.name + ": " + column.jsType + ", ";
452
426
  text = text.slice(0, -2);
453
427
  text += ") {\n";
454
428
  for (const column of columns)
455
- text += "\t\tthis." + column.column_name + " = " + column.column_name + ";\n";
429
+ text += "\t\tthis." + column.name + " = " + column.name + ";\n";
456
430
  text += "\t}\n";
457
431
  text += "}";
458
432
  return text;
@@ -492,53 +466,32 @@ function createGet(tableSchema, tableName, columns, keys) {
492
466
  text += "/**\n";
493
467
  text += " * Gets " + className + " objects from the database by ";
494
468
  for (const key of keys)
495
- text += key + " and ";
469
+ text += key.name + " and ";
496
470
  text = text.slice(0, -5) + ".\n";
497
471
  text += " *\n";
498
- for (const key of keys) {
499
- const column = columns.find(column => column.column_name === key);
500
- if (!column) {
501
- consoleMessage("WRN", `Key ${key} was not found in the columns of table ${tableName}.`);
502
- continue;
503
- }
504
- let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
505
- text += " * ";
506
- text += "@param {" + dataType;
507
- text += "} " + column.column_name;
508
- text += " - The " + nameBeautifier(column.column_name) + " of the " + nameBeautifier(tableName) + " table.\n";
509
- }
472
+ for (const key of keys)
473
+ text += " * @param {" + key.jsType + "} " + key.name + " - The " + nameBeautifier(key.name) + " of the " + nameBeautifier(tableName) + " table.\n";
510
474
  text += " * @returns {Promise<" + className + "[]>} - A Promise object returning an array of " + nameBeautifier(tableName) + ".\n";
511
475
  text += " */\n";
512
476
  text += "export async function get" + nameBeautifier(tableName).replaceAll(" ", "") + "By";
513
477
  for (const key of keys)
514
- text += nameBeautifier(key).replaceAll(" ", "") + "And";
478
+ text += nameBeautifier(key.name).replaceAll(" ", "") + "And";
515
479
  text = text.slice(0, -3);
516
480
  text += "(";
517
- for (const key of keys) {
518
- const column = columns.find(column => column.column_name === key);
519
- if (!column) {
520
- consoleMessage("WRN", `Key ${key} was not found in the columns of table ${tableName}.`);
521
- continue;
522
- }
523
- text += key + ": " + getType(column.data_type, column.udt_name) + ", ";
524
- }
481
+ for (const key of keys)
482
+ text += key.name + ": " + key.jsType + ", ";
525
483
  text = text.slice(0, -2);
526
484
  text += "): Promise<" + className + "[]> {\n";
527
485
  text += "\tif (";
528
486
  for (const key of keys)
529
- text += key + " === undefined || ";
487
+ text += key.name + " === undefined || ";
530
488
  text = text.slice(0, -4);
531
489
  text += ")\n" + "\t\tthrow \"Missing Parameters\";\n\n";
532
490
  let query = "SELECT * FROM " + tableSchema + "." + tableName + " WHERE ";
533
491
  let parameters = "";
534
492
  for (let i = 0; i < keys.length; i++) {
535
- const column = columns.find(column => column.column_name === keys[i]);
536
- if (!column) {
537
- consoleMessage("WRN", `Key ${keys[i]} was not found in the columns of table ${tableName}.`);
538
- continue;
539
- }
540
- query += keys[i] + " = " + "$" + (i + 1) + "::" + (column.data_type || column.udt_name) + " AND ";
541
- parameters += keys[i] + ", ";
493
+ query += keys[i].name + " = " + "$" + (i + 1) + "::" + keys[i].pgType + " AND ";
494
+ parameters += keys[i].name + ", ";
542
495
  }
543
496
  query = query.slice(0, -5) + ";";
544
497
  parameters = parameters.slice(0, -2);
@@ -549,38 +502,34 @@ function createGet(tableSchema, tableName, columns, keys) {
549
502
  text += "}";
550
503
  return text;
551
504
  }
552
- function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaults, foreignKeys) {
505
+ function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaults) {
553
506
  let text = "";
554
507
  const className = singularize(nameBeautifier(tableName)).replaceAll(" ", "");
555
- if (foreignKeys) {
556
- for (const foreignKey of foreignKeys) {
557
- if ((tableSchema === foreignKey.foreign_schema) && (tableName === foreignKey.foreign_table))
508
+ let hasForeign = false;
509
+ for (const column of nonDefaults.concat(softDefaults).concat(hardDefaults).sort((a, b) => a.position - b.position)) {
510
+ if (column.isForeign && column.foreignColumn && column.foreignTable && column.foreignSchema) {
511
+ hasForeign = true;
512
+ if ((tableSchema === column.foreignSchema) && (tableName === column.foreignTable))
558
513
  continue;
559
- text += "import {get" + nameBeautifier(foreignKey.foreign_table).replaceAll(" ", "") + "By" + nameBeautifier(foreignKey.foreign_column).replaceAll(" ", "") + "} from \".";
560
- if (tableSchema !== foreignKey.foreign_schema)
561
- text += "./" + foreignKey.foreign_schema;
562
- text += "/" + foreignKey.foreign_table + ".js\";\n";
514
+ text += "import {get" + nameBeautifier(column.foreignTable).replaceAll(" ", "") + "By" + nameBeautifier(column.foreignColumn).replaceAll(" ", "") + "} from \".";
515
+ if (tableSchema !== column.foreignSchema)
516
+ text += "./" + column.foreignSchema;
517
+ text += "/" + column.foreignTable + ".js\";\n";
563
518
  }
564
519
  }
565
520
  text += "/**\n";
566
521
  text += " * Adds the provided " + className + " object to the database.\n";
567
522
  text += " *\n";
568
523
  let columns = nonDefaults.concat(softDefaults);
569
- columns.sort((a, b) => a.ordinal_position - b.ordinal_position);
570
- for (const column of columns) {
571
- let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
572
- text += " * ";
573
- text += "@param {" + dataType;
574
- if (column.is_nullable === "YES")
575
- text += " | undefined";
576
- text += "} " + column.column_name;
577
- text += " - The " + nameBeautifier(column.column_name) + " to be inserted into the " + nameBeautifier(tableName) + " table.\n";
578
- }
524
+ columns.sort((a, b) => a.position - b.position);
525
+ for (const column of columns)
526
+ text += " * @param {" + column.jsType + "} " + column.name + " - The " + nameBeautifier(column.name) + " to be inserted into the " + nameBeautifier(tableName) + " table.\n";
579
527
  text += " * @returns {Promise<" + className + ">} - A Promise object returning the inserted " + nameBeautifier(tableName) + ".\n";
580
- if (foreignKeys && foreignKeys.length > 0) {
528
+ if (hasForeign) {
581
529
  text += " * @throws string An exception in the case of the ";
582
- for (const foreignKey of foreignKeys)
583
- text += nameBeautifier(foreignKey.local_column) + " or the ";
530
+ for (const column of columns)
531
+ if (column.isForeign)
532
+ text += nameBeautifier(column.name) + " or the ";
584
533
  text = text.slice(0, -8);
585
534
  text += " not existing in their table.\n";
586
535
  }
@@ -589,54 +538,42 @@ function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaul
589
538
  if (softDefaults.length > 0) {
590
539
  text += "With";
591
540
  for (const softDefault of softDefaults)
592
- text += nameBeautifier(softDefault.column_name).replaceAll(" ", "") + "And";
541
+ text += nameBeautifier(softDefault.name).replaceAll(" ", "") + "And";
593
542
  text = text.slice(0, -3);
594
543
  }
595
544
  text += "(";
596
- for (const column of columns) {
597
- let dataType = getType(column.data_type, column.udt_name);
598
- text += column.column_name + ": " + dataType;
599
- if (column.is_nullable === "YES")
600
- text += " | undefined";
601
- text += ", ";
602
- }
545
+ for (const column of columns)
546
+ text += column.name + ": " + column.jsType + ", ";
603
547
  text = text.slice(0, -2);
604
548
  text += "): Promise<" + className + "> {\n";
605
- if (foreignKeys) {
606
- for (const foreignKey of foreignKeys) {
607
- const column = columns.find(column => column.column_name === foreignKey.local_column);
608
- if (!column) {
609
- consoleMessage("WRN", `Key ${foreignKey} was not found in the columns of table ${tableName}.`);
610
- continue;
611
- }
612
- if (column.is_nullable === "YES") {
613
- text += "\tif (" + foreignKey.local_column + ") {\n";
614
- text += "\t\tconst verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + " = await get" + nameBeautifier(foreignKey.foreign_table).replaceAll(" ", "") + "By" + nameBeautifier(foreignKey.foreign_column).replaceAll(" ", "") + "(" + foreignKey.local_column + ");\n";
615
- text += "\t\tif (verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + ".length === 0)\n";
616
- text += "\t\t\tthrow \"The " + nameBeautifier(foreignKey.local_column) + " provided does not exist.\";\n";
617
- text += "\t}\n\n";
618
- }
619
- else {
620
- text += "\tconst verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + " = await get" + nameBeautifier(foreignKey.foreign_table).replaceAll(" ", "") + "By" + nameBeautifier(foreignKey.foreign_column).replaceAll(" ", "") + "(" + foreignKey.local_column + ");\n";
621
- text += "\tif (verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + ".length === 0)\n";
622
- text += "\t\tthrow \"The " + nameBeautifier(foreignKey.local_column) + " provided does not exist.\";\n\n";
549
+ if (hasForeign) {
550
+ for (const column of columns) {
551
+ if (column.isForeign && column.foreignColumn && column.foreignTable && column.foreignSchema) {
552
+ const name = nameBeautifier(column.name).replaceAll(" ", "");
553
+ if (column.isNullable) {
554
+ text += "\tif (" + column.name + ") {\n";
555
+ text += "\t\tconst verify" + name + " = await get" + nameBeautifier(column.foreignTable).replaceAll(" ", "") + "By" + nameBeautifier(column.foreignColumn).replaceAll(" ", "") + "(" + column.name + ");\n";
556
+ text += "\t\tif (verify" + name + ".length === 0)\n";
557
+ text += "\t\t\tthrow \"The " + nameBeautifier(column.name) + " provided does not exist.\";\n";
558
+ text += "\t}\n\n";
559
+ }
560
+ else {
561
+ text += "\tconst verify" + name + " = await get" + nameBeautifier(column.foreignTable).replaceAll(" ", "") + "By" + nameBeautifier(column.foreignColumn).replaceAll(" ", "") + "(" + column.name + ");\n";
562
+ text += "\tif (verify" + name + ".length === 0)\n";
563
+ text += "\t\tthrow \"The " + nameBeautifier(column.name) + " provided does not exist.\";\n\n";
564
+ }
623
565
  }
624
566
  }
625
567
  }
626
568
  let query = "INSERT INTO " + tableSchema + "." + tableName + " (";
627
569
  for (const column of columns)
628
- query += column.column_name + ", ";
570
+ query += column.name + ", ";
629
571
  query = query.slice(0, -2);
630
572
  query += ") VALUES (";
631
573
  let parameters = "";
632
574
  for (let i = 0; i < columns.length; i++) {
633
- let dataType = columns[i].udt_name;
634
- if (dataType[0] === "_")
635
- dataType = dataType.slice(1) + "[]";
636
- else if (columns[i].data_type !== "USER-DEFINED")
637
- dataType = columns[i].data_type;
638
- query += "$" + (i + 1) + "::" + dataType + ", ";
639
- parameters += columns[i].column_name + ", ";
575
+ query += "$" + (i + 1) + "::" + columns[i].pgType + ", ";
576
+ parameters += columns[i].name + ", ";
640
577
  }
641
578
  query = query.slice(0, -2);
642
579
  parameters = parameters.slice(0, -2);
@@ -646,9 +583,9 @@ function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaul
646
583
  text += "\treturn new " + className + "(\n";
647
584
  columns = columns.concat(hardDefaults);
648
585
  columns = [...new Set(columns)];
649
- columns.sort((a, b) => a.ordinal_position - b.ordinal_position);
586
+ columns.sort((a, b) => a.position - b.position);
650
587
  for (const column of columns)
651
- text += "\t\tinsertQuery.rows[0]." + column.column_name + ",\n";
588
+ text += "\t\tinsertQuery.rows[0]." + column.name + ",\n";
652
589
  text = text.slice(0, -2);
653
590
  text += "\n";
654
591
  text += "\t);\n";
package/src/maps.js CHANGED
@@ -1,64 +1,64 @@
1
1
  export const jsTypes = new Map([
2
- ["bigint", "number"],
3
- ["int8", "number"],
4
- ["bigserial", "number"],
5
- ["serial8", "number"],
6
- ["bit", "Array"],
7
- ["bit varying", "Array"],
8
- ["varbit", "Array"],
9
- ["boolean", "boolean"],
10
- ["bool", "boolean"],
11
- ["box", ""],
12
- ["bytea", "Array"],
13
- ["character", "string"],
14
- ["char", "string"],
15
- ["character varying", "string"],
16
- ["varchar", "string"],
17
- ["cidr", "string"],
18
- ["circle", ""],
19
- ["date", "Date"],
20
- ["double precision", "number"],
21
- ["float8", "number"],
22
- ["inet", "string"],
2
+ ["smallint", "number"],
3
+ ["int2", "number"],
23
4
  ["integer", "number"],
24
5
  ["int", "number"],
25
- ["int4", "number"],
26
- ["interval", ""],
27
- ["json", "string"],
28
- ["jsonb", "Array"],
29
- ["line", ""],
30
- ["lseg", ""],
31
- ["macaddr", "string"],
32
- ["macaddr8", "string"],
33
- ["money", "number"],
34
- ["numeric", "number"],
35
- ["decimal", "number"],
36
- ["path", ""],
37
- ["pg_lsn", "number"],
38
- ["pg_snapshot", ""],
39
- ["point", ""],
40
- ["polygon", ""],
6
+ ["bigint", "string"],
7
+ ["int8", "string"],
41
8
  ["real", "number"],
42
9
  ["float4", "number"],
43
- ["smallint", "number"],
44
- ["int2", "number"],
10
+ ["double precision", "number"],
11
+ ["float8", "string"],
12
+ ["numeric", "string"],
13
+ ["decimal", "string"],
14
+ ["money", "string"],
45
15
  ["smallserial", "number"],
46
16
  ["serial2", "number"],
47
17
  ["serial", "number"],
48
- ["string4", "number"],
18
+ ["serial4", "number"],
19
+ ["bigserial", "string"],
20
+ ["serial8", "string"],
21
+ ["character", "string"],
22
+ ["char", "string"],
23
+ ["character varying", "string"],
24
+ ["varchar", "string"],
49
25
  ["text", "string"],
50
- ["time", ""],
51
- ["time without time zone", ""],
52
- ["time with time zone", ""],
53
- ["timetz", ""],
54
- ["timestamp", "Date"],
26
+ ["name", "string"],
27
+ ["bytea", "Buffer"],
28
+ ["bit", "string"],
29
+ ["bit varying", "string"],
30
+ ["varbit", "string"],
31
+ ["boolean", "boolean"],
32
+ ["bool", "boolean"],
33
+ ["date", "Date"],
34
+ ["time without time zone", "string"],
35
+ ["time", "string"],
36
+ ["time with time zone", "string"],
37
+ ["timetz", "string"],
55
38
  ["timestamp without time zone", "Date"],
39
+ ["timestamp", "Date"],
56
40
  ["timestamp with time zone", "Date"],
57
41
  ["timestamptz", "Date"],
58
- ["tsquery", ""],
59
- ["tsvector", ""],
60
- ["txid_snapshot", ""],
42
+ ["interval", "object"],
43
+ ["box", "object"],
44
+ ["circle", "object"],
45
+ ["line", "object"],
46
+ ["lseg", "object"],
47
+ ["path", "object"],
48
+ ["point", "object"],
49
+ ["polygon", "object"],
50
+ ["cidr", "string"],
51
+ ["inet", "string"],
52
+ ["macaddr", "string"],
53
+ ["macaddr8", "string"],
54
+ ["json", "object"],
55
+ ["jsonb", "object"],
61
56
  ["uuid", "string"],
57
+ ["tsquery", "string"],
58
+ ["tsvector", "string"],
59
+ ["pg_lsn", "string"],
60
+ ["pg_snapshot", "string"],
61
+ ["txid_snapshot", "string"],
62
62
  ["xml", "string"],
63
63
  ]);
64
64
  export const udtTypes = new Map([
@@ -83,6 +83,7 @@ export const udtTypes = new Map([
83
83
  ["character varying", "varchar"],
84
84
  ["varchar", "varchar"],
85
85
  ["text", "text"],
86
+ ["name", "name"],
86
87
  ["bytea", "bytea"],
87
88
  ["bit", "bit"],
88
89
  ["bit varying", "varbit"],
package/src/pgAdmin.js CHANGED
@@ -1,5 +1,5 @@
1
- import { ColumnQueryRow, ForeignKeyQueryRow, PigeonError, PrimaryKeyQueryRow, Table, UniqueQueryRow } from "./index.js";
2
- import { udtTypes } from "./maps.js";
1
+ import { Column, PigeonError, Table, } from "./index.js";
2
+ import { getJSType, getPGType, getTypesByDataType } from "./utils.js";
3
3
  function objectToArray(json) {
4
4
  let arrayJSON = "";
5
5
  let enteredObject = false;
@@ -52,66 +52,57 @@ export function tableProcessing(tables) {
52
52
  const columns = [];
53
53
  let ordinalPossition = 1;
54
54
  for (const column of data.columns) {
55
- let dataType = column.cltype;
56
- let udtType;
57
- udtType = udtTypes.get(dataType);
58
- if (!udtType) {
59
- if (dataType.endsWith("[]")) {
60
- udtType = "_" + udtTypes.get(dataType.slice(0, -2));
61
- dataType = "ARRAY";
62
- }
63
- else {
64
- udtType = dataType;
65
- dataType = "USER-DEFINED";
66
- }
67
- }
68
- if (dataType === "smallserial" || dataType === "serial" || dataType === "bigserial") {
69
- dataType = dataType.replace("serial", "int");
70
- if (dataType === "int")
71
- dataType = "integer";
72
- column.defval = "nextval('" + data.name + "_" + column.name + "_seq'::regclass)";
73
- }
74
- let isNullable;
55
+ const types = getTypesByDataType(column.cltype);
56
+ let isNullable = true;
75
57
  if (column.attnotnull)
76
- isNullable = "NO";
77
- else
78
- isNullable = "YES";
58
+ isNullable = false;
59
+ const jsType = getJSType(types.dataType, types.udtName, isNullable);
60
+ const pgType = getPGType(types.dataType);
61
+ if (column.cltype.contains("serial"))
62
+ column.defval = "nextval('" + data.name + "_" + column.name + "_seq'::regclass)";
79
63
  let columnDefault;
80
64
  if (column.defval !== "" && column.defval !== undefined)
81
65
  columnDefault = column.defval;
82
66
  else
83
67
  columnDefault = null;
84
- let identity;
68
+ let identity = false;
85
69
  if (column.colconstype === "i")
86
- identity = "YES";
87
- else
88
- identity = "NO";
70
+ identity = true;
89
71
  let identityGeneration = null;
90
- if (identity === "YES") {
72
+ if (identity) {
91
73
  if (column.attidentity === "a")
92
74
  identityGeneration = "ALWAYS";
93
75
  if (column.attidentity === "b")
94
76
  identityGeneration = "BY DEFAULT";
95
77
  }
96
- columns.push(new ColumnQueryRow(column.name, ordinalPossition, columnDefault, isNullable, dataType, udtType, identity, identityGeneration));
97
- ordinalPossition++;
98
- }
99
- let primaryKey = undefined;
100
- if (data.primary_key[0]?.columns[0]?.column)
101
- primaryKey = new PrimaryKeyQueryRow(data.primary_key[0].columns[0].column);
102
- const foreignKeys = [];
103
- for (const foreignKey of data.foreign_key) {
104
- for (const column of foreignKey.columns) {
105
- const match = column.references_table_name.match(/(?:\((.*?)\))? ?(.*)/);
106
- foreignKeys.push(new ForeignKeyQueryRow(data.schema, data.name, column.local_column, match[1] || data.schema, match[2], column.referenced));
78
+ let isPrimary = false;
79
+ if (column.name === data.primary_key[0].columns[0].column)
80
+ isPrimary = true;
81
+ let isForeign = false;
82
+ let foreignSchema = undefined;
83
+ let foreignTable = undefined;
84
+ let foreignColumn = undefined;
85
+ for (const foreignKey of data.foreign_key) {
86
+ for (const foreignKeyColumn of foreignKey.columns) {
87
+ if (foreignKeyColumn.local_column === column.name) {
88
+ isForeign = true;
89
+ const match = foreignKeyColumn.references_table_name.match(/(?:\((.*?)\))? ?(.*)/);
90
+ foreignSchema = match[1] || data.schema;
91
+ foreignTable = match[2];
92
+ foreignColumn = foreignKeyColumn.referenced;
93
+ }
94
+ }
107
95
  }
96
+ let isUnique = false;
97
+ if (data.unique_constraint)
98
+ for (const uniqueConstraint of data.unique_constraint)
99
+ for (const uniqueColumn of uniqueConstraint.columns)
100
+ if (uniqueColumn.column === column.name)
101
+ isUnique = true;
102
+ columns.push(new Column(column.name, ordinalPossition, columnDefault, isNullable, jsType, pgType, identity, identityGeneration, isPrimary, isUnique, isForeign, foreignSchema, foreignTable, foreignColumn));
103
+ ordinalPossition++;
108
104
  }
109
- const uniqueConstraints = [];
110
- if (data.unique_constraint)
111
- for (const uniqueConstraint of data.unique_constraint)
112
- for (const column of uniqueConstraint.columns)
113
- uniqueConstraints.push(column.column);
114
- pigeonTables.push(new Table(data.schema, data.name, columns, primaryKey, foreignKeys, new UniqueQueryRow(uniqueConstraints)));
105
+ pigeonTables.push(new Table(data.name, data.schema, columns));
115
106
  }
116
107
  return pigeonTables;
117
108
  }
package/src/utils.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import pg from "pg";
2
- import { jsTypes } from "./maps.js";
2
+ import { jsTypes, udtTypes } from "./maps.js";
3
3
  const { Client } = pg;
4
4
  export async function runQuery(command, parameters, db) {
5
5
  const client = new Client({
@@ -114,7 +114,7 @@ export function arrayMaker(baseTabs, variableName, className, columns) {
114
114
  array += tabsInserter(baseTabs) + "for (const row of " + variableName + "Query.rows)\n";
115
115
  array += tabsInserter(baseTabs + 1) + variableName + ".push(new " + className + "(\n";
116
116
  for (const column of columns)
117
- array += tabsInserter(baseTabs + 2) + "row." + column.column_name + ",\n";
117
+ array += tabsInserter(baseTabs + 2) + "row." + column.name + ",\n";
118
118
  array = array.slice(0, -2) + "\n";
119
119
  array += tabsInserter(baseTabs + 1) + "));";
120
120
  return array;
@@ -146,7 +146,10 @@ export function getCombinations(valuesArray) {
146
146
  combinations.sort((a, b) => a.length - b.length);
147
147
  return combinations;
148
148
  }
149
- export function getType(dataType, udtName) {
149
+ export function getJSType(dataType, udtName, isNullable) {
150
+ dataType = dataType.replace("serial", "int");
151
+ if (dataType === "int")
152
+ dataType = "integer";
150
153
  let isArray = false;
151
154
  if (dataType === "ARRAY") {
152
155
  dataType = udtName.slice(1);
@@ -157,5 +160,40 @@ export function getType(dataType, udtName) {
157
160
  foundDataType = nameBeautifier(udtName).replaceAll(" ", "");
158
161
  if (isArray)
159
162
  foundDataType += "[]";
163
+ if (isNullable)
164
+ foundDataType += " | undefined";
160
165
  return foundDataType;
161
166
  }
167
+ export function getTypesByDataType(dataType) {
168
+ let udtName;
169
+ udtName = udtTypes.get(dataType);
170
+ if (!udtName) {
171
+ if (dataType.endsWith("[]")) {
172
+ udtName = "_" + udtTypes.get(dataType.slice(0, -2));
173
+ dataType = "ARRAY";
174
+ }
175
+ else {
176
+ udtName = dataType;
177
+ dataType = "USER-DEFINED";
178
+ }
179
+ }
180
+ return {
181
+ dataType: dataType,
182
+ udtName: udtName
183
+ };
184
+ }
185
+ export function getPGType(dataType, udtName) {
186
+ if (!udtName) {
187
+ const types = getTypesByDataType(dataType);
188
+ udtName = types.udtName;
189
+ }
190
+ dataType = dataType.replace("serial", "int");
191
+ if (dataType === "int")
192
+ dataType = "integer";
193
+ let pgType = udtName;
194
+ if (dataType.endsWith("[]"))
195
+ pgType = pgType.slice(1) + "[]";
196
+ else if (dataType !== "USER-DEFINED")
197
+ pgType = dataType;
198
+ return pgType;
199
+ }