@andymic/pigeon 1.2.0 → 1.4.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/bin/pigeon.js CHANGED
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
- /*
3
- * Copyright (c) 2024 Andreas Michael
4
- * This software is under the Apache 2.0 License
5
- */
6
2
  import { cli, run } from "../src/cli.js";
3
+ import { PigeonError } from "../src/index.js";
7
4
  try {
8
- const { exitCode, message, error } = await run(cli.flags);
9
- if (message) {
10
- console.log(message);
5
+ const result = await run(cli.flags);
6
+ if (result instanceof PigeonError) {
7
+ if (result.message !== "")
8
+ console.log(result.message);
9
+ console.error(result.error);
10
+ process.exit(result.exitCode);
11
11
  }
12
- if (error) {
13
- console.error(error);
12
+ else {
13
+ console.log("Generation Completed Successfully");
14
+ process.exit(0);
14
15
  }
15
- process.exit(exitCode);
16
16
  }
17
17
  catch (error) {
18
18
  console.error(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andymic/pigeon",
3
- "version": "1.2.0",
3
+ "version": "1.4.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": [
@@ -32,8 +32,8 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "meow": "^13.2.0",
35
- "pg": "^8.14.1",
35
+ "pg": "^8.15.6",
36
36
  "prompt-sync": "^4.2.0"
37
37
  },
38
- "gitHead": "b163d7dac6444fad09fa7bf9bc2b812ed3f486ad"
38
+ "gitHead": "ec33791a735792a340bfa41c1f66e9a08534ffa6"
39
39
  }
package/src/cli.js CHANGED
@@ -1,12 +1,9 @@
1
- /*
2
- * Copyright (c) 2024 Andreas Michael
3
- * This software is under the Apache 2.0 License
4
- */
5
1
  import meow from "meow";
6
2
  import { createConfig } from "./config.js";
3
+ import { Database, deleteDir, enumsQuery, guided, PigeonError, queryDB, runGeneration } from "./index.js";
7
4
  import * as path from "node:path";
8
- import { deleteDir, guided, runPigeon } from "./index.js";
9
5
  import fs from "node:fs";
6
+ import { getRelationshipsAndTables, tableProcessing } from "./pgAdmin.js";
10
7
  export const cli = meow(`
11
8
  Usage
12
9
  $ pigeon [options]
@@ -17,12 +14,15 @@ export const cli = meow(`
17
14
  --force overwrites already existing files
18
15
  --output [path:String] output directory for the generated files.
19
16
  --config [path:String] path to .pigeon.json config file.
17
+ --pgAdmin [path:String] path to the pgAdmin ERD file.
18
+ --offline (only with pgAdmin) does not contact the database
20
19
 
21
20
  Examples
22
21
  $ pigeon --init
23
22
  $ pigeon --output C:/Users/User/Documents/Project
24
23
  $ pigeon --output ./generatedFiles --force
25
24
  $ pigeon --config ./customPigeonConfig.json
25
+ $ pigeon --pgAdmin C:/Users/User/Documents/Project/ERD.json --offline
26
26
 
27
27
  Exit Status
28
28
  Pigeon returns the following codes:
@@ -57,6 +57,13 @@ export const cli = meow(`
57
57
  type: "string",
58
58
  default: process.cwd(),
59
59
  },
60
+ pgAdmin: {
61
+ type: "string",
62
+ },
63
+ offline: {
64
+ type: "boolean",
65
+ default: false,
66
+ }
60
67
  },
61
68
  autoHelp: true,
62
69
  autoVersion: true,
@@ -67,16 +74,51 @@ export async function run(flags) {
67
74
  return createConfig(flags.cwd);
68
75
  if (flags.force)
69
76
  deleteDir(flags.output);
77
+ if (flags.pgAdmin) {
78
+ let enums;
79
+ let database;
80
+ if (!flags.offline) {
81
+ if (!fs.existsSync(path.join(process.cwd(), ".pigeon.json")))
82
+ return new PigeonError(1, "", new Error("The configuration file does not exist. Generate one using the \"pigeon --init\" command"));
83
+ const params = JSON.parse(fs.readFileSync(flags.config).toString());
84
+ database = new Database(params.host, params.port, params.database, params.username, params.password);
85
+ enums = await enumsQuery(database);
86
+ }
87
+ else {
88
+ enums = [];
89
+ database = new Database("localhost", "5432", "database", "username", "password");
90
+ }
91
+ if (enums instanceof PigeonError)
92
+ return enums;
93
+ if (!fs.existsSync(flags.pgAdmin))
94
+ return new PigeonError(1, "", new Error("The pgAdmin ERD file specified does not exist."));
95
+ const file = fs.readFileSync(flags.pgAdmin).toString();
96
+ let tables;
97
+ try {
98
+ tables = getRelationshipsAndTables(file).tables;
99
+ }
100
+ catch (e) {
101
+ return e;
102
+ }
103
+ const generationResult = runGeneration(flags.output, database, tableProcessing(tables), enums);
104
+ if (generationResult instanceof PigeonError)
105
+ return generationResult;
106
+ }
70
107
  if (flags.guided) {
71
108
  const params = guided();
72
- return await runPigeon(flags.output, params.host, params.port, params.db, params.user, params.pass);
109
+ const database = new Database(params.host, String(params.port), params.db, params.user, params.pass);
110
+ const result = await queryDB(database);
111
+ if (result instanceof PigeonError)
112
+ return result;
73
113
  }
74
114
  if (!fs.existsSync(path.join(process.cwd(), ".pigeon.json")))
75
- return {
76
- exitCode: 1,
77
- message: null,
78
- error: new Error("The configuration file does not exist. Generate one using the \"pigeon --init\" command"),
79
- };
115
+ return new PigeonError(1, "", new Error("The configuration file does not exist. Generate one using the \"pigeon --init\" command"));
80
116
  const params = JSON.parse(fs.readFileSync(flags.config).toString());
81
- return await runPigeon(flags.output, params.host, params.port, params.database, params.username, params.password);
117
+ const database = new Database(params.host, params.port, params.database, params.username, params.password);
118
+ const queryResult = await queryDB(database);
119
+ if (queryResult instanceof PigeonError)
120
+ return queryResult;
121
+ const generationResult = runGeneration(flags.output, database, queryResult.tables, queryResult.enums);
122
+ if (generationResult instanceof PigeonError)
123
+ return generationResult;
82
124
  }
package/src/config.js CHANGED
@@ -1,21 +1,9 @@
1
- /*
2
- * Copyright (c) 2024 Andreas Michael
3
- * This software is under the Apache 2.0 License
4
- */
1
+ import { PigeonError } from "./index.js";
5
2
  import fs from "node:fs";
6
3
  import * as path from "node:path";
7
4
  export function createConfig(dir) {
8
- if (fs.existsSync(path.join(dir, ".pigeon.json"))) {
9
- return {
10
- exitCode: 1,
11
- message: null,
12
- error: new Error("A Pigeon configuration file already exists."),
13
- };
14
- }
5
+ if (fs.existsSync(path.join(dir, ".pigeon.json")))
6
+ return new PigeonError(1, "", new Error("A Pigeon configuration file already exists."));
15
7
  fs.writeFileSync(path.join(dir, ".pigeon.json"), "{\n\t\"host\": \"localhost\",\n\t\"port\": 5432,\n\t\"database\": \"postgres\",\n\t\"username\": \"postgres\",\n\t\"password\": \"xxx\"\n}");
16
- return {
17
- exitCode: 0,
18
- message: "Configuration file successfully created!",
19
- error: null,
20
- };
8
+ return new PigeonError(0, "Configuration file successfully created!", null);
21
9
  }
package/src/index.js CHANGED
@@ -1,33 +1,108 @@
1
- /*
2
- * Copyright (c) 2024 Andreas Michael
3
- * This software is under the Apache 2.0 License
4
- */
5
- import { arrayMaker, getCombinations, nameBeautifier, queryMaker, runQuery, singularize, sleep, tabsInserter } from "./utils.js";
6
- import { types } from "./maps.js";
1
+ import { arrayMaker, consoleMessage, getCombinations, getType, nameBeautifier, queryMaker, runQuery, singularize, sleep, tabsInserter } from "./utils.js";
2
+ import prompt from "prompt-sync";
7
3
  import fs from "node:fs";
8
4
  import * as path from "node:path";
9
- import prompt from "prompt-sync";
5
+ export class PigeonError {
6
+ exitCode;
7
+ message;
8
+ error;
9
+ constructor(exitCode, message, error) {
10
+ this.exitCode = exitCode;
11
+ this.message = message;
12
+ this.error = error;
13
+ }
14
+ }
15
+ export class Database {
16
+ host;
17
+ port;
18
+ db;
19
+ user;
20
+ pass;
21
+ constructor(host, port, db, user, pass) {
22
+ this.host = host;
23
+ this.port = port;
24
+ this.db = db;
25
+ this.user = user;
26
+ this.pass = pass;
27
+ }
28
+ }
29
+ export class Table {
30
+ table_schema;
31
+ table_name;
32
+ columns = [];
33
+ primaryKey;
34
+ foreignKeys;
35
+ unique;
36
+ constructor(table_schema, table_name, columns, primaryKey, foreignKeys, unique) {
37
+ this.table_schema = table_schema;
38
+ this.table_name = table_name;
39
+ this.columns = columns;
40
+ this.primaryKey = primaryKey;
41
+ this.foreignKeys = foreignKeys;
42
+ this.unique = unique;
43
+ }
44
+ }
45
+ export class Enum {
46
+ name;
47
+ labels;
48
+ constructor(name, labels) {
49
+ this.name = name;
50
+ this.labels = labels;
51
+ }
52
+ }
53
+ export class ColumnQueryRow {
54
+ column_name;
55
+ ordinal_position;
56
+ column_default;
57
+ is_nullable;
58
+ data_type;
59
+ udt_name;
60
+ is_identity;
61
+ identity_generation;
62
+ constructor(column_name, ordinal_position, column_default, is_nullable, data_type, udt_name, is_identity, identity_generation) {
63
+ this.column_name = column_name;
64
+ this.ordinal_position = ordinal_position;
65
+ this.column_default = column_default;
66
+ this.is_nullable = is_nullable;
67
+ this.data_type = data_type;
68
+ this.udt_name = udt_name;
69
+ this.is_identity = is_identity;
70
+ this.identity_generation = identity_generation;
71
+ }
72
+ }
73
+ export class PrimaryKeyQueryRow {
74
+ column_name;
75
+ constructor(column_name) {
76
+ this.column_name = column_name;
77
+ }
78
+ }
79
+ export class ForeignKeyQueryRow {
80
+ local_schema;
81
+ local_table;
82
+ local_column;
83
+ foreign_schema;
84
+ foreign_table;
85
+ foreign_column;
86
+ constructor(local_schema, local_table, local_column, foreign_schema, foreign_table, foreign_column) {
87
+ this.local_schema = local_schema;
88
+ this.local_table = local_table;
89
+ this.local_column = local_column;
90
+ this.foreign_schema = foreign_schema;
91
+ this.foreign_table = foreign_table;
92
+ this.foreign_column = foreign_column;
93
+ }
94
+ }
95
+ export class UniqueQueryRow {
96
+ columns;
97
+ constructor(columns) {
98
+ this.columns = columns;
99
+ }
100
+ }
10
101
  function createDir(dirPath) {
11
102
  if (fs.existsSync(dirPath))
12
- return {
13
- exitCode: 1,
14
- message: null,
15
- error: new Error("Generation directory already exists. Add the --force flag if you want to overwrite it.")
16
- };
103
+ return new PigeonError(1, "", new Error("Generation directory already exists. Add the --force flag if you want to overwrite it."));
17
104
  else
18
- fs.mkdir(dirPath, (err) => {
19
- if (err)
20
- return {
21
- exitCode: 1,
22
- message: null,
23
- error: err
24
- };
25
- });
26
- return {
27
- exitCode: 0,
28
- message: null,
29
- error: null
30
- };
105
+ fs.mkdirSync(dirPath);
31
106
  }
32
107
  export function deleteDir(dirPath) {
33
108
  if (fs.existsSync(dirPath)) {
@@ -75,94 +150,71 @@ export function guided() {
75
150
  const pass = input("Database Password: ");
76
151
  return { host, port, db, user, pass };
77
152
  }
78
- export async function runPigeon(dir, host, port, db, user, pass) {
79
- const dirResult = createDir(dir);
80
- if (dirResult.exitCode !== 0)
81
- return dirResult;
82
- const tableQuery = await runQuery(`SELECT table_schema, table_name
83
- FROM information_schema.tables
84
- WHERE table_type = 'BASE TABLE'
85
- AND table_schema NOT IN
86
- ('pg_catalog', 'information_schema');`, [], host, port, db, user, pass);
87
- if (typeof tableQuery === "undefined")
88
- return {
89
- exitCode: 1,
90
- message: null,
91
- error: new Error("An SQL error has occurred.")
92
- };
93
- let schemas = [];
94
- for (const table of tableQuery.rows) {
95
- if (schemas.includes(table.table_schema))
96
- continue;
97
- schemas.push(table.table_schema);
98
- }
99
- for (const schema of schemas)
100
- createDir(path.join(dir, schema));
153
+ export async function enumsQuery(db) {
101
154
  const customTypeQuery = await runQuery(`SELECT t.oid, t.typname
102
155
  FROM pg_type t
103
156
  WHERE (t.typrelid = 0 OR t.typrelid IN (SELECT oid FROM pg_class WHERE relkind = 'c'))
104
157
  AND t.typelem = 0
105
158
  AND t.typnamespace NOT IN
106
- (SELECT oid FROM pg_namespace WHERE nspname IN ('pg_catalog', 'information_schema'));`, [], host, port, db, user, pass);
159
+ (SELECT oid FROM pg_namespace WHERE nspname IN ('pg_catalog', 'information_schema'));`, [], db);
107
160
  if (typeof customTypeQuery === "undefined")
108
- return {
109
- exitCode: 1,
110
- message: null,
111
- error: new Error("An SQL error has occurred.")
112
- };
113
- const customTypes = [];
161
+ return new PigeonError(1, "", new Error("An SQL error has occurred."));
162
+ const enums = [];
114
163
  for (const type of customTypeQuery.rows) {
115
164
  const enumQuery = await runQuery(`SELECT enumlabel
116
165
  FROM pg_enum
117
166
  WHERE enumtypid = $1::oid
118
- ORDER BY enumsortorder;`, [type.oid], host, port, db, user, pass);
167
+ ORDER BY enumsortorder;`, [type.oid], db);
119
168
  if (typeof enumQuery === "undefined")
120
- return {
121
- exitCode: 1,
122
- message: null,
123
- error: new Error("An SQL error has occurred.")
124
- };
169
+ return new PigeonError(1, "", new Error("An SQL error has occurred."));
125
170
  let labels = [];
126
171
  for (const enumLabel of enumQuery.rows)
127
172
  labels.push(enumLabel.enumlabel);
128
- customTypes.push({
129
- name: type.typname,
130
- labels: labels
131
- });
173
+ enums.push(new Enum(type.typname, labels));
132
174
  }
175
+ return enums;
176
+ }
177
+ export async function queryDB(db) {
178
+ const tableQuery = await runQuery(`SELECT table_schema, table_name
179
+ FROM information_schema.tables
180
+ WHERE table_type = 'BASE TABLE'
181
+ AND table_schema NOT IN
182
+ ('pg_catalog', 'information_schema');`, [], db);
183
+ if (typeof tableQuery === "undefined")
184
+ return new PigeonError(1, "", new Error("An SQL error has occurred."));
185
+ const enums = await enumsQuery(db);
186
+ if (enums instanceof PigeonError)
187
+ return enums;
188
+ const tables = [];
133
189
  for (const table of tableQuery.rows) {
134
- const columnQuery = await runQuery(`SELECT *
190
+ const columnQuery = await runQuery(`SELECT column_name,
191
+ ordinal_position,
192
+ column_default,
193
+ is_nullable,
194
+ data_type,
195
+ udt_name,
196
+ is_identity,
197
+ identity_generation
135
198
  FROM information_schema.columns
136
199
  WHERE table_name = $1::varchar
137
- AND table_schema = $2::varchar;`, [table.table_name, table.table_schema], host, port, db, user, pass);
200
+ AND table_schema = $2::varchar;`, [table.table_name, table.table_schema], db);
138
201
  if (typeof columnQuery === "undefined")
139
- return {
140
- exitCode: 1,
141
- message: null,
142
- error: new Error("An SQL error has occurred.")
143
- };
202
+ return new PigeonError(1, "", new Error("An SQL error has occurred."));
144
203
  const pKeyQuery = await runQuery(`SELECT ku.column_name
145
204
  FROM information_schema.table_constraints AS tc
146
205
  INNER JOIN information_schema.key_column_usage AS ku
147
206
  ON tc.constraint_type = 'PRIMARY KEY'
148
207
  AND tc.constraint_name = ku.constraint_name
149
208
  WHERE tc.table_schema = $1::varchar
150
- AND tc.table_name = $2::varchar;`, [table.table_schema, table.table_name], host, port, db, user, pass);
209
+ AND tc.table_name = $2::varchar;`, [table.table_schema, table.table_name], db);
151
210
  if (typeof pKeyQuery === "undefined")
152
- return {
153
- exitCode: 1,
154
- message: null,
155
- error: new Error("An SQL error has occurred.")
156
- };
157
- let pKeys = [];
158
- for (let pKey of pKeyQuery.rows)
159
- pKeys.push(pKey.column_name);
211
+ return new PigeonError(1, "", new Error("An SQL error has occurred."));
160
212
  const fKeyQuery = await runQuery(`SELECT kcu1.table_schema AS local_schema,
161
213
  kcu1.table_name AS local_table,
162
214
  kcu1.column_name AS local_column,
163
- kcu2.table_schema AS referenced_schema,
164
- kcu2.table_name AS referenced_table,
165
- kcu2.column_name AS referenced_column
215
+ kcu2.table_schema AS foreign_schema,
216
+ kcu2.table_name AS foreign_table,
217
+ kcu2.column_name AS foreign_column
166
218
  FROM information_schema.referential_constraints AS rc
167
219
  INNER JOIN information_schema.key_column_usage AS kcu1
168
220
  ON kcu1.constraint_catalog = rc.constraint_catalog
@@ -175,13 +227,9 @@ export async function runPigeon(dir, host, port, db, user, pass) {
175
227
  AND kcu2.constraint_name = rc.unique_constraint_name
176
228
  AND kcu2.ordinal_position = kcu1.ordinal_position
177
229
  WHERE kcu1.table_schema = $1::varchar
178
- AND kcu1.table_name = $2::varchar;`, [table.table_schema, table.table_name], host, port, db, user, pass);
230
+ AND kcu1.table_name = $2::varchar;`, [table.table_schema, table.table_name], db);
179
231
  if (typeof fKeyQuery === "undefined")
180
- return {
181
- exitCode: 1,
182
- message: null,
183
- error: new Error("An SQL error has occurred.")
184
- };
232
+ return new PigeonError(1, "", new Error("An SQL error has occurred."));
185
233
  const uniqueQuery = await runQuery(`SELECT array_agg(a.attname) AS columns
186
234
  FROM pg_constraint AS c
187
235
  CROSS JOIN LATERAL unnest(c.conkey) AS k(c)
@@ -190,61 +238,88 @@ export async function runPigeon(dir, host, port, db, user, pass) {
190
238
  AND c.connamespace = $1::regnamespace
191
239
  AND c.conrelid = $2::regclass
192
240
  GROUP BY c.conrelid;
193
- `, [table.table_schema, table.table_name], host, port, db, user, pass);
241
+ `, [table.table_schema, table.table_name], db);
194
242
  if (typeof uniqueQuery === "undefined")
195
- return {
196
- exitCode: 1,
197
- message: null,
198
- error: new Error("An SQL error has occurred.")
199
- };
243
+ return new PigeonError(1, "", new Error("An SQL error has occurred."));
200
244
  let uniques = [];
201
245
  if (uniqueQuery.rowCount > 0)
202
246
  uniques = uniqueQuery.rows[0].columns.slice(1, -1).split(",");
203
- let ts = clientMaker(0, host, port, db, user, pass);
247
+ tables.push(new Table(table.table_schema, table.table_name, columnQuery.rows, pKeyQuery.rows[0], fKeyQuery.rows, { columns: uniques }));
248
+ }
249
+ return {
250
+ tables: tables,
251
+ enums: enums
252
+ };
253
+ }
254
+ export function runGeneration(dir, db, tables, enums) {
255
+ if (!tables)
256
+ return new PigeonError(1, "", new Error("No tables were found."));
257
+ const dirResult = createDir(dir);
258
+ if (dirResult instanceof PigeonError)
259
+ return dirResult;
260
+ let schemas = [];
261
+ for (const table of tables) {
262
+ if (schemas.includes(table.table_schema))
263
+ continue;
264
+ schemas.push(table.table_schema);
265
+ }
266
+ for (const schema of schemas) {
267
+ const dirResult = createDir(path.join(dir, schema));
268
+ if (dirResult instanceof PigeonError)
269
+ return dirResult;
270
+ }
271
+ for (const table of tables) {
272
+ let ts = clientMaker(0, db);
204
273
  ts += "\n\n";
205
- for (const customType of customTypes) {
206
- for (const column of columnQuery.rows) {
207
- if (customType.name === column.udt_name) {
208
- const enumName = nameBeautifier(customType.name).replaceAll(" ", "");
209
- ts += "/**\n An Enum representing the " + nameBeautifier(customType.name).toLowerCase() + ".\n * @readonly\n * @enum {string}\n */\n";
210
- ts += "class " + enumName + " {\n";
211
- let longestLabel = 0;
212
- for (const label of customType.labels)
213
- if (label.length > longestLabel)
214
- longestLabel = label.length;
215
- for (const label of customType.labels)
216
- ts += "\tstatic " + label.toUpperCase().replaceAll(/[^a-zA-Z0-9$]/g, "_") + ": string" + " ".repeat(longestLabel - label.length + 1) + "= \"" + label + "\";\n";
217
- ts += "}\n\n";
274
+ if (enums) {
275
+ for (const cEnum of enums) {
276
+ for (const column of table.columns) {
277
+ if (cEnum.name === column.udt_name) {
278
+ const enumName = nameBeautifier(cEnum.name).replaceAll(" ", "");
279
+ ts += "/**\n An Enum representing the " + nameBeautifier(cEnum.name).toLowerCase() + ".\n * @readonly\n * @enum {string}\n */\n";
280
+ ts += "class " + enumName + " {\n";
281
+ let longestLabel = 0;
282
+ for (const label of cEnum.labels)
283
+ if (label.length > longestLabel)
284
+ longestLabel = label.length;
285
+ for (const label of cEnum.labels)
286
+ ts += "\tstatic " + label.toUpperCase().replaceAll(/[^a-zA-Z0-9$]/g, "_") + ": string" + " ".repeat(longestLabel - label.length + 1) + "= \"" + label + "\";\n";
287
+ ts += "}\n\n";
288
+ }
218
289
  }
219
290
  }
220
291
  }
221
- ts += createClass(table.table_name, columnQuery.rows, pKeys, fKeyQuery.rows);
292
+ ts += createClass(table.table_name, table.columns, table.primaryKey?.column_name, table.foreignKeys);
222
293
  ts += "\n\n";
223
- ts += createGetAll(table.table_schema, table.table_name, columnQuery.rows);
294
+ ts += createGetAll(table.table_schema, table.table_name, table.columns);
224
295
  ts += "\n\n";
225
- let keys = [...pKeys];
226
- for (const fKey of fKeyQuery.rows)
227
- keys.push(fKey.local_column.replaceAll(" ", ""));
228
- keys = keys.concat(uniques);
296
+ let keys = [];
297
+ if (table.primaryKey)
298
+ keys.push(table.primaryKey.column_name);
299
+ if (table.foreignKeys)
300
+ for (const fKey of table.foreignKeys)
301
+ keys.push(fKey.local_column.replaceAll(" ", ""));
302
+ if (table.unique)
303
+ keys = keys.concat(table.unique.columns);
229
304
  keys = [...new Set(keys)];
230
305
  for (const keyCombination of getCombinations(keys)) {
231
- ts += createGet(table.table_schema, table.table_name, columnQuery.rows, keyCombination);
306
+ ts += createGet(table.table_schema, table.table_name, table.columns, keyCombination);
232
307
  ts += "\n\n";
233
308
  }
234
309
  let nonDefaults = [];
235
310
  let softDefaults = [];
236
311
  let hardDefaults = [];
237
- for (const column of columnQuery.rows) {
312
+ for (const column of table.columns) {
238
313
  if (column.column_default === null && column.is_identity === "NO")
239
314
  nonDefaults.push(column);
240
- if ((column.column_default !== null && !column.column_default.includes("nextval")) || (column.is_identity === "YES" && column.identity_generation === "BY DEFAULT"))
315
+ else if ((column.column_default !== null && !column.column_default.includes("nextval")) || (column.is_identity === "YES" && column.identity_generation === "BY DEFAULT"))
241
316
  softDefaults.push(column);
242
- if ((column.column_default !== null && column.column_default.includes("nextval")) || (column.is_identity === "YES" && column.identity_generation === "ALWAYS"))
317
+ else if ((column.column_default !== null && column.column_default.includes("nextval")) || (column.is_identity === "YES" && column.identity_generation === "ALWAYS"))
243
318
  hardDefaults.push(column);
244
319
  }
245
- ts += createAdd(table.table_schema, table.table_name, nonDefaults, [], hardDefaults.concat(softDefaults), fKeyQuery.rows) + "\n\n";
320
+ ts += createAdd(table.table_schema, table.table_name, nonDefaults, [], hardDefaults.concat(softDefaults), table.foreignKeys) + "\n\n";
246
321
  for (const softCombination of getCombinations(softDefaults))
247
- ts += createAdd(table.table_schema, table.table_name, nonDefaults, softCombination, hardDefaults.concat(softDefaults.filter(n => !getCombinations(softDefaults).includes(n))), fKeyQuery.rows) + "\n\n";
322
+ ts += createAdd(table.table_schema, table.table_name, nonDefaults, softCombination, hardDefaults.concat(softDefaults.filter(n => !getCombinations(softDefaults).includes([n]))), table.foreignKeys) + "\n\n";
248
323
  ts = ts.slice(0, -2);
249
324
  const regex = /import ({?.*?}?) from "(.*?)";\n/g;
250
325
  let importObjects = [];
@@ -291,34 +366,29 @@ export async function runPigeon(dir, host, port, db, user, pass) {
291
366
  ts = importString + ts;
292
367
  fs.writeFileSync(path.join(dir, table.table_schema, table.table_name + ".ts"), ts);
293
368
  }
294
- return {
295
- exitCode: 0,
296
- message: "Generation Completed Successfully",
297
- error: null
298
- };
299
369
  }
300
- function createClass(tableName, columns, primaryKeys, foreignKeys) {
370
+ function createClass(tableName, columns, primaryKey, foreignKeys) {
301
371
  let text = "";
302
372
  text += "export class " + singularize(nameBeautifier(tableName)).replaceAll(" ", "") + " {\n";
303
373
  for (const column of columns) {
304
- let dataType = types.get(column.data_type);
305
- if (dataType === undefined)
306
- dataType = nameBeautifier(column.udt_name).replaceAll(" ", "");
307
- if (column.is_nullable == "YES")
374
+ let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
375
+ if (column.is_nullable === "YES")
308
376
  dataType += " | undefined";
309
377
  let isPrimaryKey = false;
310
- for (const pKey of primaryKeys)
311
- if (pKey === column.column_name)
312
- isPrimaryKey = true;
313
- let foreignKeyIndex = -1;
314
- for (let i = 0; i < foreignKeys.length; i++)
315
- if (foreignKeys[i].local_column === column.column_name)
316
- foreignKeyIndex = i;
378
+ if (column.column_name === primaryKey)
379
+ isPrimaryKey = true;
380
+ let foreignKeyIndex;
381
+ if (foreignKeys)
382
+ for (let i = 0; i < foreignKeys.length; i++)
383
+ if (foreignKeys[i].local_column === column.column_name)
384
+ foreignKeyIndex = i;
317
385
  text += "\t/**\n";
318
386
  if (isPrimaryKey)
319
387
  text += "\t * A primary key representing the " + nameBeautifier(column.column_name) + " for the " + nameBeautifier(tableName) + " table.\n";
320
- else if (foreignKeyIndex !== -1)
321
- text += "\t * A foreign key representing the " + nameBeautifier(column.column_name) + " for the " + nameBeautifier(tableName) + " table and referencing the " + nameBeautifier(foreignKeys[foreignKeyIndex].referenced_column) + " in the " + nameBeautifier(foreignKeys[foreignKeyIndex].referenced_table) + " table in the " + nameBeautifier(foreignKeys[foreignKeyIndex].referenced_schema) + " schema.\n";
388
+ else if (foreignKeys && foreignKeyIndex)
389
+ 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";
390
+ else if (column.column_name.toLowerCase().startsWith("is_"))
391
+ text += "\t * Indicates whether this record in the table " + nameBeautifier(tableName) + " is currently " + nameBeautifier(column.column_name.slice(3)).toLowerCase() + ".\n";
322
392
  else
323
393
  text += "\t * The " + nameBeautifier(column.column_name) + " for the " + nameBeautifier(tableName) + " table.\n";
324
394
  text += "\t * @type {" + dataType + "}\n";
@@ -330,9 +400,9 @@ function createClass(tableName, columns, primaryKeys, foreignKeys) {
330
400
  if (column.column_default)
331
401
  text += " = new Date()";
332
402
  else
333
- text += " = new Date(" + column.column_default.replace(' ', 'T') + ")";
403
+ text += " = new Date(" + column.column_default.replace(" ", "T") + ")";
334
404
  }
335
- else if (dataType === "number")
405
+ else if (dataType === "number" || dataType === "boolean")
336
406
  text += " = " + column.column_default;
337
407
  else
338
408
  text += " = \"" + column.column_default + "\"";
@@ -345,24 +415,23 @@ function createClass(tableName, columns, primaryKeys, foreignKeys) {
345
415
  text += "\t * Creates a new object for the " + nameBeautifier(tableName) + " table.\n";
346
416
  text += "\t * \n";
347
417
  for (const column of columns) {
348
- let dataType = types.get(column.data_type);
349
- if (dataType === undefined)
350
- dataType = nameBeautifier(column.udt_name).replaceAll(" ", "");
418
+ let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
351
419
  text += "\t * ";
352
420
  text += "@param {" + dataType;
353
- if (column.is_nullable == "YES")
421
+ if (column.is_nullable === "YES")
354
422
  text += " | undefined";
355
423
  text += "} " + column.column_name;
356
- text += " - The " + nameBeautifier(column.column_name) + " of the " + nameBeautifier(tableName) + " table. \n";
424
+ if (!column.column_name.toLowerCase().startsWith("is_"))
425
+ text += " - The " + nameBeautifier(column.column_name) + " of the " + nameBeautifier(tableName) + " table. \n";
426
+ else
427
+ text += " - Indicates whether this record in the table " + nameBeautifier(tableName) + " is currently " + nameBeautifier(column.column_name.slice(3)).toLowerCase() + ".\n";
357
428
  }
358
429
  text += "\t */\n";
359
430
  text += "\tconstructor(";
360
431
  for (const column of columns) {
361
- let dataType = types.get(column.data_type);
362
- if (dataType === undefined)
363
- dataType = nameBeautifier(column.udt_name).replaceAll(" ", "");
432
+ let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
364
433
  text += column.column_name + ": " + dataType;
365
- if (column.is_nullable == "YES")
434
+ if (column.is_nullable === "YES")
366
435
  text += " | undefined";
367
436
  text += ", ";
368
437
  }
@@ -374,14 +443,14 @@ function createClass(tableName, columns, primaryKeys, foreignKeys) {
374
443
  text += "}";
375
444
  return text;
376
445
  }
377
- export function clientMaker(baseTabs, host, port, db, user, pass) {
446
+ export function clientMaker(baseTabs, db) {
378
447
  let text = "";
379
448
  text += tabsInserter(baseTabs) + "const client = new Client({\n";
380
- text += tabsInserter(baseTabs + 1) + "host: \"" + host + "\",\n";
381
- text += tabsInserter(baseTabs + 1) + "port: " + port + ",\n";
382
- text += tabsInserter(baseTabs + 1) + "database: \"" + db + "\",\n";
383
- text += tabsInserter(baseTabs + 1) + "user: \"" + user + "\",\n";
384
- text += tabsInserter(baseTabs + 1) + "password: \"" + pass + "\"\n";
449
+ text += tabsInserter(baseTabs + 1) + "host: \"" + db.host + "\",\n";
450
+ text += tabsInserter(baseTabs + 1) + "port: " + db.port + ",\n";
451
+ text += tabsInserter(baseTabs + 1) + "database: \"" + db.db + "\",\n";
452
+ text += tabsInserter(baseTabs + 1) + "user: \"" + db.user + "\",\n";
453
+ text += tabsInserter(baseTabs + 1) + "password: \"" + db.pass + "\"\n";
385
454
  text += tabsInserter(baseTabs) + "});";
386
455
  return text;
387
456
  }
@@ -413,10 +482,12 @@ function createGet(tableSchema, tableName, columns, keys) {
413
482
  text = text.slice(0, -5) + ".\n";
414
483
  text += " *\n";
415
484
  for (const key of keys) {
416
- const column = columns.find(column => column.column_name == key);
417
- let dataType = types.get(column.data_type);
418
- if (dataType === undefined)
419
- dataType = nameBeautifier(column.udt_name).replaceAll(" ", "");
485
+ const column = columns.find(column => column.column_name === key);
486
+ if (!column) {
487
+ consoleMessage("WRN", `Key ${key} was not found in the columns of table ${tableName}.`);
488
+ continue;
489
+ }
490
+ let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
420
491
  text += " * ";
421
492
  text += "@param {" + dataType;
422
493
  text += "} " + column.column_name;
@@ -429,8 +500,14 @@ function createGet(tableSchema, tableName, columns, keys) {
429
500
  text += nameBeautifier(key).replaceAll(" ", "") + "And";
430
501
  text = text.slice(0, -3);
431
502
  text += "(";
432
- for (const key of keys)
433
- text += key + ": " + (types.get(columns.find(column => column.column_name == key).data_type) || nameBeautifier(columns.find(column => column.column_name == key).udt_name).replaceAll(" ", "")) + ", ";
503
+ for (const key of keys) {
504
+ const column = columns.find(column => column.column_name === key);
505
+ if (!column) {
506
+ consoleMessage("WRN", `Key ${key} was not found in the columns of table ${tableName}.`);
507
+ continue;
508
+ }
509
+ text += key + ": " + getType(column.data_type, column.udt_name) + ", ";
510
+ }
434
511
  text = text.slice(0, -2);
435
512
  text += "): Promise<" + className + "[]> {\n";
436
513
  text += "\tif (";
@@ -441,7 +518,12 @@ function createGet(tableSchema, tableName, columns, keys) {
441
518
  let query = "SELECT * FROM " + tableSchema + "." + tableName + " WHERE ";
442
519
  let parameters = "";
443
520
  for (let i = 0; i < keys.length; i++) {
444
- query += keys[i] + " = " + "$" + (i + 1) + "::" + (columns.find(column => column.column_name == keys[i]).data_type || columns.find(column => column.column_name == keys[i]).udt_name) + " AND ";
521
+ const column = columns.find(column => column.column_name === keys[i]);
522
+ if (!column) {
523
+ consoleMessage("WRN", `Key ${keys[i]} was not found in the columns of table ${tableName}.`);
524
+ continue;
525
+ }
526
+ query += keys[i] + " = " + "$" + (i + 1) + "::" + (column.data_type || column.udt_name) + " AND ";
445
527
  parameters += keys[i] + ", ";
446
528
  }
447
529
  query = query.slice(0, -5) + ";";
@@ -456,13 +538,15 @@ function createGet(tableSchema, tableName, columns, keys) {
456
538
  function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaults, foreignKeys) {
457
539
  let text = "";
458
540
  const className = singularize(nameBeautifier(tableName)).replaceAll(" ", "");
459
- for (const foreignKey of foreignKeys) {
460
- if ((tableSchema == foreignKey.referenced_schema) && (tableName == foreignKey.referenced_table))
461
- continue;
462
- text += "import {get" + nameBeautifier(foreignKey.referenced_table).replaceAll(" ", "") + "By" + nameBeautifier(foreignKey.referenced_column).replaceAll(" ", "") + "} from \".";
463
- if (tableSchema !== foreignKey.referenced_schema)
464
- text += "./" + foreignKey.referenced_schema;
465
- text += "/" + foreignKey.referenced_table + ".js\";\n";
541
+ if (foreignKeys) {
542
+ for (const foreignKey of foreignKeys) {
543
+ if ((tableSchema === foreignKey.foreign_schema) && (tableName === foreignKey.foreign_table))
544
+ continue;
545
+ text += "import {get" + nameBeautifier(foreignKey.foreign_table).replaceAll(" ", "") + "By" + nameBeautifier(foreignKey.foreign_column).replaceAll(" ", "") + "} from \".";
546
+ if (tableSchema !== foreignKey.foreign_schema)
547
+ text += "./" + foreignKey.foreign_schema;
548
+ text += "/" + foreignKey.foreign_table + ".js\";\n";
549
+ }
466
550
  }
467
551
  text += "/**\n";
468
552
  text += " * Adds the provided " + className + " object to the database.\n";
@@ -470,9 +554,7 @@ function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaul
470
554
  let columns = nonDefaults.concat(softDefaults);
471
555
  columns.sort((a, b) => a.ordinal_position - b.ordinal_position);
472
556
  for (const column of columns) {
473
- let dataType = types.get(column.data_type);
474
- if (dataType === undefined)
475
- dataType = nameBeautifier(column.udt_name).replaceAll(" ", "");
557
+ let dataType = getType(column.data_type, column.udt_name).replaceAll(" ", "");
476
558
  text += " * ";
477
559
  text += "@param {" + dataType;
478
560
  if (column.is_nullable === "YES")
@@ -481,7 +563,7 @@ function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaul
481
563
  text += " - The " + nameBeautifier(column.column_name) + " to be inserted into the " + nameBeautifier(tableName) + " table.\n";
482
564
  }
483
565
  text += " * @returns {Promise<" + className + ">} - A Promise object returning the inserted " + nameBeautifier(tableName) + ".\n";
484
- if (foreignKeys.length > 0) {
566
+ if (foreignKeys && foreignKeys.length > 0) {
485
567
  text += " * @throws string An exception in the case of the ";
486
568
  for (const foreignKey of foreignKeys)
487
569
  text += nameBeautifier(foreignKey.local_column) + " or the ";
@@ -498,9 +580,7 @@ function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaul
498
580
  }
499
581
  text += "(";
500
582
  for (const column of columns) {
501
- let dataType = types.get(column.data_type);
502
- if (dataType === undefined)
503
- dataType = nameBeautifier(column.udt_name).replaceAll(" ", "");
583
+ let dataType = getType(column.data_type, column.udt_name);
504
584
  text += column.column_name + ": " + dataType;
505
585
  if (column.is_nullable === "YES")
506
586
  text += " | undefined";
@@ -508,18 +588,25 @@ function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaul
508
588
  }
509
589
  text = text.slice(0, -2);
510
590
  text += "): Promise<" + className + "> {\n";
511
- for (const foreignKey of foreignKeys) {
512
- if (columns.find(column => column.column_name == foreignKey.local_column).is_nullable === "YES") {
513
- text += "\tif (" + foreignKey.local_column + ") {\n";
514
- text += "\t\tconst verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + " = await get" + nameBeautifier(foreignKey.referenced_table).replaceAll(" ", "") + "By" + nameBeautifier(foreignKey.referenced_column).replaceAll(" ", "") + "(" + foreignKey.local_column + ");\n";
515
- text += "\t\tif (verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + ".length === 0)\n";
516
- text += "\t\t\tthrow \"The " + nameBeautifier(foreignKey.local_column) + " provided does not exist.\";\n";
517
- text += "\t}\n\n";
518
- }
519
- else {
520
- text += "\tconst verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + " = await get" + nameBeautifier(foreignKey.referenced_table).replaceAll(" ", "") + "By" + nameBeautifier(foreignKey.referenced_column).replaceAll(" ", "") + "(" + foreignKey.local_column + ");\n";
521
- text += "\tif (verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + ".length === 0)\n";
522
- text += "\t\tthrow \"The " + nameBeautifier(foreignKey.local_column) + " provided does not exist.\";\n\n";
591
+ if (foreignKeys) {
592
+ for (const foreignKey of foreignKeys) {
593
+ const column = columns.find(column => column.column_name === foreignKey.local_column);
594
+ if (!column) {
595
+ consoleMessage("WRN", `Key ${foreignKey} was not found in the columns of table ${tableName}.`);
596
+ continue;
597
+ }
598
+ if (column.is_nullable === "YES") {
599
+ text += "\tif (" + foreignKey.local_column + ") {\n";
600
+ 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";
601
+ text += "\t\tif (verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + ".length === 0)\n";
602
+ text += "\t\t\tthrow \"The " + nameBeautifier(foreignKey.local_column) + " provided does not exist.\";\n";
603
+ text += "\t}\n\n";
604
+ }
605
+ else {
606
+ 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";
607
+ text += "\tif (verify" + nameBeautifier(foreignKey.local_column).replaceAll(" ", "") + ".length === 0)\n";
608
+ text += "\t\tthrow \"The " + nameBeautifier(foreignKey.local_column) + " provided does not exist.\";\n\n";
609
+ }
523
610
  }
524
611
  }
525
612
  let query = "INSERT INTO " + tableSchema + "." + tableName + " (";
@@ -529,9 +616,11 @@ function createAdd(tableSchema, tableName, nonDefaults, softDefaults, hardDefaul
529
616
  query += ") VALUES (";
530
617
  let parameters = "";
531
618
  for (let i = 0; i < columns.length; i++) {
532
- let dataType = columns[i].data_type;
533
- if (dataType === "USER-DEFINED")
534
- dataType = columns[i].udt_name;
619
+ let dataType = columns[i].udt_name;
620
+ if (dataType[0] === "_")
621
+ dataType = dataType.slice(1) + "[]";
622
+ else if (columns[i].data_type !== "USER-DEFINED")
623
+ dataType = columns[i].data_type;
535
624
  query += "$" + (i + 1) + "::" + dataType + ", ";
536
625
  parameters += columns[i].column_name + ", ";
537
626
  }
package/src/maps.js CHANGED
@@ -1,8 +1,4 @@
1
- /*
2
- * Copyright (c) 2024 Andreas Michael
3
- * This software is under the Apache 2.0 License
4
- */
5
- export const types = new Map([
1
+ export const jsTypes = new Map([
6
2
  ["bigint", "number"],
7
3
  ["int8", "number"],
8
4
  ["bigserial", "number"],
@@ -65,3 +61,62 @@ export const types = new Map([
65
61
  ["uuid", "string"],
66
62
  ["xml", "string"],
67
63
  ]);
64
+ export const udtTypes = new Map([
65
+ ["smallint", "int2"],
66
+ ["int2", "int2"],
67
+ ["integer", "int4"],
68
+ ["int", "int4"],
69
+ ["bigint", "int8"],
70
+ ["int8", "int8"],
71
+ ["real", "float4"],
72
+ ["float4", "float4"],
73
+ ["double precision", "float8"],
74
+ ["float8", "float8"],
75
+ ["numeric", "numeric"],
76
+ ["decimal", "numeric"],
77
+ ["money", "money"],
78
+ ["smallserial", "int2"],
79
+ ["serial", "int4"],
80
+ ["bigserial", "int8"],
81
+ ["character", "bpchar"],
82
+ ["char", "bpchar"],
83
+ ["character varying", "varchar"],
84
+ ["varchar", "varchar"],
85
+ ["text", "text"],
86
+ ["bytea", "bytea"],
87
+ ["bit", "bit"],
88
+ ["bit varying", "varbit"],
89
+ ["varbit", "varbit"],
90
+ ["boolean", "bool"],
91
+ ["bool", "bool"],
92
+ ["date", "date"],
93
+ ["time without time zone", "time"],
94
+ ["time", "time"],
95
+ ["time with time zone", "timetz"],
96
+ ["timetz", "timetz"],
97
+ ["timestamp without time zone", "timestamp"],
98
+ ["timestamp", "timestamp"],
99
+ ["timestamp with time zone", "timestamptz"],
100
+ ["timestamptz", "timestamptz"],
101
+ ["interval", "interval"],
102
+ ["box", "box"],
103
+ ["circle", "circle"],
104
+ ["line", "line"],
105
+ ["lseg", "lseg"],
106
+ ["path", "path"],
107
+ ["point", "point"],
108
+ ["polygon", "polygon"],
109
+ ["cidr", "cidr"],
110
+ ["inet", "inet"],
111
+ ["macaddr", "macaddr"],
112
+ ["macaddr8", "macaddr8"],
113
+ ["json", "json"],
114
+ ["jsonb", "jsonb"],
115
+ ["uuid", "uuid"],
116
+ ["tsquery", "tsquery"],
117
+ ["tsvector", "tsvector"],
118
+ ["pg_lsn", "pg_lsn"],
119
+ ["pg_snapshot", "pg_snapshot"],
120
+ ["txid_snapshot", "txid_snapshot"],
121
+ ["xml", "xml"],
122
+ ]);
package/src/pgAdmin.js ADDED
@@ -0,0 +1,117 @@
1
+ import { ColumnQueryRow, ForeignKeyQueryRow, PigeonError, PrimaryKeyQueryRow, Table, UniqueQueryRow } from "./index.js";
2
+ import { udtTypes } from "./maps.js";
3
+ function objectToArray(json) {
4
+ let arrayJSON = "";
5
+ let enteredObject = false;
6
+ let brackets = 0;
7
+ for (let i = 0; i < json.length; i++) {
8
+ if (json[i] === "{") {
9
+ if (!enteredObject) {
10
+ enteredObject = true;
11
+ arrayJSON += "[";
12
+ brackets++;
13
+ continue;
14
+ }
15
+ brackets++;
16
+ arrayJSON += json[i];
17
+ continue;
18
+ }
19
+ else if (json[i] === "}") {
20
+ brackets--;
21
+ if (brackets === 0)
22
+ return JSON.parse(arrayJSON.slice(0, -1) + "]");
23
+ arrayJSON += json[i];
24
+ if (brackets === 1)
25
+ arrayJSON += ",";
26
+ continue;
27
+ }
28
+ if (enteredObject && brackets !== 1)
29
+ arrayJSON += json[i];
30
+ }
31
+ }
32
+ export function getRelationshipsAndTables(json) {
33
+ if (!json.startsWith("{\"version\":"))
34
+ throw new PigeonError(1, "", new Error("The file specified is not an pgAdmin ERD file."));
35
+ let relationships = [];
36
+ let tables = [];
37
+ const relationshipsIndex = json.match(/"type":"diagram-links"/)?.index;
38
+ if (relationshipsIndex)
39
+ relationships = objectToArray(json.slice(relationshipsIndex));
40
+ const tablesIndex = json.match(/"type":"diagram-nodes"/)?.index;
41
+ if (tablesIndex)
42
+ tables = objectToArray(json.slice(tablesIndex));
43
+ return {
44
+ relationships: relationships,
45
+ tables: tables,
46
+ };
47
+ }
48
+ export function tableProcessing(tables) {
49
+ const pigeonTables = [];
50
+ for (const table of tables) {
51
+ const data = table.otherInfo.data;
52
+ const columns = [];
53
+ let ordinalPossition = 1;
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;
75
+ if (column.attnotnull)
76
+ isNullable = "NO";
77
+ else
78
+ isNullable = "YES";
79
+ let columnDefault;
80
+ if (column.defval !== "" && column.defval !== undefined)
81
+ columnDefault = column.defval;
82
+ else
83
+ columnDefault = null;
84
+ let identity;
85
+ if (column.colconstype === "i")
86
+ identity = "YES";
87
+ else
88
+ identity = "NO";
89
+ let identityGeneration = null;
90
+ if (identity === "YES") {
91
+ if (column.attidentity === "a")
92
+ identityGeneration = "ALWAYS";
93
+ if (column.attidentity === "b")
94
+ identityGeneration = "BY DEFAULT";
95
+ }
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));
107
+ }
108
+ }
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)));
115
+ }
116
+ return pigeonTables;
117
+ }
package/src/utils.js CHANGED
@@ -1,16 +1,13 @@
1
- /*
2
- * Copyright (c) 2024 Andreas Michael
3
- * This software is under the Apache 2.0 License
4
- */
5
1
  import pg from "pg";
2
+ import { jsTypes } from "./maps.js";
6
3
  const { Client } = pg;
7
- export async function runQuery(command, parameters, host, port, db, username, password) {
4
+ export async function runQuery(command, parameters, db) {
8
5
  const client = new Client({
9
- host: host,
10
- port: port,
11
- database: db,
12
- user: username,
13
- password: password,
6
+ host: db.host,
7
+ port: Number(db.port),
8
+ database: db.db,
9
+ user: db.user,
10
+ password: db.pass,
14
11
  });
15
12
  try {
16
13
  await client.connect();
@@ -149,3 +146,16 @@ export function getCombinations(valuesArray) {
149
146
  combinations.sort((a, b) => a.length - b.length);
150
147
  return combinations;
151
148
  }
149
+ export function getType(dataType, udtName) {
150
+ let isArray = false;
151
+ if (dataType === "ARRAY") {
152
+ dataType = udtName.slice(1);
153
+ isArray = true;
154
+ }
155
+ let foundDataType = jsTypes.get(dataType);
156
+ if (foundDataType === undefined)
157
+ foundDataType = nameBeautifier(udtName).replaceAll(" ", "");
158
+ if (isArray)
159
+ foundDataType += "[]";
160
+ return foundDataType;
161
+ }