@dbml/connector 3.8.0 → 3.8.1

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.
@@ -1,10 +1,10 @@
1
- import path from 'path';
2
1
  import fs from 'fs';
2
+ import path from 'path';
3
3
  import { scanDirNames } from '../jestHelpers.ts';
4
4
  import { connector } from '../src/index.ts';
5
5
 
6
6
  describe('@dbml/connector', () => {
7
- const runTest = async (dirName) => {
7
+ const runTest = async (dirName: string) => {
8
8
  process.chdir(dirName);
9
9
 
10
10
  const connectionRaw = fs.readFileSync(path.join(dirName, './connection.json'), 'utf-8');
@@ -1,5 +1,19 @@
1
1
  {
2
2
  "tables": [
3
+ {
4
+ "name": "table1",
5
+ "schemaName": "dbml_test",
6
+ "note": {
7
+ "value": ""
8
+ }
9
+ },
10
+ {
11
+ "name": "table3",
12
+ "schemaName": "dbml_test",
13
+ "note": {
14
+ "value": ""
15
+ }
16
+ },
3
17
  {
4
18
  "name": "all_default_values",
5
19
  "schemaName": "public",
@@ -49,6 +63,20 @@
49
63
  "value": ""
50
64
  }
51
65
  },
66
+ {
67
+ "name": "table1",
68
+ "schemaName": "public",
69
+ "note": {
70
+ "value": ""
71
+ }
72
+ },
73
+ {
74
+ "name": "table2",
75
+ "schemaName": "public",
76
+ "note": {
77
+ "value": ""
78
+ }
79
+ },
52
80
  {
53
81
  "name": "table_with_comments",
54
82
  "schemaName": "public",
@@ -72,6 +100,62 @@
72
100
  }
73
101
  ],
74
102
  "fields": {
103
+ "dbml_test.table1": [
104
+ {
105
+ "name": "id",
106
+ "type": {
107
+ "type_name": "int4",
108
+ "schemaName": null
109
+ },
110
+ "dbdefault": null,
111
+ "not_null": true,
112
+ "increment": true,
113
+ "note": {
114
+ "value": ""
115
+ }
116
+ },
117
+ {
118
+ "name": "status",
119
+ "type": {
120
+ "type_name": "enum_type1",
121
+ "schemaName": "dbml_test"
122
+ },
123
+ "dbdefault": null,
124
+ "not_null": false,
125
+ "increment": false,
126
+ "note": {
127
+ "value": ""
128
+ }
129
+ }
130
+ ],
131
+ "dbml_test.table3": [
132
+ {
133
+ "name": "id",
134
+ "type": {
135
+ "type_name": "int4",
136
+ "schemaName": null
137
+ },
138
+ "dbdefault": null,
139
+ "not_null": true,
140
+ "increment": true,
141
+ "note": {
142
+ "value": ""
143
+ }
144
+ },
145
+ {
146
+ "name": "status",
147
+ "type": {
148
+ "type_name": "enum_type3",
149
+ "schemaName": "dbml_test"
150
+ },
151
+ "dbdefault": null,
152
+ "not_null": false,
153
+ "increment": false,
154
+ "note": {
155
+ "value": ""
156
+ }
157
+ }
158
+ ],
75
159
  "public.all_default_values": [
76
160
  {
77
161
  "name": "id",
@@ -843,6 +927,62 @@
843
927
  }
844
928
  }
845
929
  ],
930
+ "public.table1": [
931
+ {
932
+ "name": "id",
933
+ "type": {
934
+ "type_name": "int4",
935
+ "schemaName": null
936
+ },
937
+ "dbdefault": null,
938
+ "not_null": true,
939
+ "increment": true,
940
+ "note": {
941
+ "value": ""
942
+ }
943
+ },
944
+ {
945
+ "name": "status",
946
+ "type": {
947
+ "type_name": "enum_type1",
948
+ "schemaName": "public"
949
+ },
950
+ "dbdefault": null,
951
+ "not_null": false,
952
+ "increment": false,
953
+ "note": {
954
+ "value": ""
955
+ }
956
+ }
957
+ ],
958
+ "public.table2": [
959
+ {
960
+ "name": "id",
961
+ "type": {
962
+ "type_name": "int4",
963
+ "schemaName": null
964
+ },
965
+ "dbdefault": null,
966
+ "not_null": true,
967
+ "increment": true,
968
+ "note": {
969
+ "value": ""
970
+ }
971
+ },
972
+ {
973
+ "name": "status",
974
+ "type": {
975
+ "type_name": "enum_type2",
976
+ "schemaName": "public"
977
+ },
978
+ "dbdefault": null,
979
+ "not_null": false,
980
+ "increment": false,
981
+ "note": {
982
+ "value": ""
983
+ }
984
+ }
985
+ ],
846
986
  "public.table_with_comments": [
847
987
  {
848
988
  "name": "id",
@@ -1229,6 +1369,54 @@
1229
1369
  }
1230
1370
  ],
1231
1371
  "enums": [
1372
+ {
1373
+ "name": "enum_type1",
1374
+ "schemaName": "dbml_test",
1375
+ "values": [
1376
+ {
1377
+ "name": "value1"
1378
+ },
1379
+ {
1380
+ "name": "value2"
1381
+ }
1382
+ ]
1383
+ },
1384
+ {
1385
+ "name": "enum_type3",
1386
+ "schemaName": "dbml_test",
1387
+ "values": [
1388
+ {
1389
+ "name": "value4"
1390
+ },
1391
+ {
1392
+ "name": "value5"
1393
+ }
1394
+ ]
1395
+ },
1396
+ {
1397
+ "name": "enum_type1",
1398
+ "schemaName": "public",
1399
+ "values": [
1400
+ {
1401
+ "name": "value1"
1402
+ },
1403
+ {
1404
+ "name": "value2"
1405
+ }
1406
+ ]
1407
+ },
1408
+ {
1409
+ "name": "enum_type2",
1410
+ "schemaName": "public",
1411
+ "values": [
1412
+ {
1413
+ "name": "value1"
1414
+ },
1415
+ {
1416
+ "name": "value3"
1417
+ }
1418
+ ]
1419
+ },
1232
1420
  {
1233
1421
  "name": "gender_type",
1234
1422
  "schemaName": "public",
@@ -1386,6 +1574,26 @@
1386
1574
  "pk": true
1387
1575
  }
1388
1576
  },
1577
+ "public.table1": {
1578
+ "id": {
1579
+ "pk": true
1580
+ }
1581
+ },
1582
+ "dbml_test.table1": {
1583
+ "id": {
1584
+ "pk": true
1585
+ }
1586
+ },
1587
+ "public.table2": {
1588
+ "id": {
1589
+ "pk": true
1590
+ }
1591
+ },
1592
+ "dbml_test.table3": {
1593
+ "id": {
1594
+ "pk": true
1595
+ }
1596
+ },
1389
1597
  "public.table_with_comments": {
1390
1598
  "id": {
1391
1599
  "pk": true
@@ -1,3 +1,3 @@
1
1
  import { DatabaseSchema } from './types';
2
2
  declare const fetchSchemaJson: (connection: string) => Promise<DatabaseSchema>;
3
- export { fetchSchemaJson, };
3
+ export { fetchSchemaJson };
@@ -106,71 +106,99 @@ const generateTablesFieldsAndEnums = async (client, schemas) => {
106
106
  const fields = {};
107
107
  const enums = [];
108
108
  const tablesAndFieldsSql = `
109
- WITH tables_and_fields AS (
109
+ WITH tables_and_fields AS (
110
+ SELECT
111
+ s.name AS table_schema,
112
+ t.name AS table_name,
113
+ c.name AS column_name,
114
+ ty.name AS data_type,
115
+ c.max_length AS character_maximum_length,
116
+ c.precision AS numeric_precision,
117
+ c.scale AS numeric_scale,
118
+ c.is_identity AS identity_increment,
119
+ CASE
120
+ WHEN c.is_nullable = 1 THEN 'YES'
121
+ ELSE 'NO'
122
+ END AS is_nullable,
123
+ CASE
124
+ WHEN c.default_object_id = 0 THEN NULL
125
+ ELSE OBJECT_DEFINITION(c.default_object_id)
126
+ END AS column_default,
127
+ -- Fetching table comments
128
+ p.value AS table_comment,
129
+ ep.value AS column_comment
130
+ FROM
131
+ sys.tables t
132
+ JOIN sys.schemas s ON t.schema_id = s.schema_id
133
+ JOIN sys.columns c ON t.object_id = c.object_id
134
+ JOIN sys.types ty ON c.user_type_id = ty.user_type_id
135
+ LEFT JOIN sys.extended_properties p ON p.major_id = t.object_id
136
+ AND p.name = 'MS_Description'
137
+ AND p.minor_id = 0 -- Ensure minor_id is 0 for table comments
138
+ LEFT JOIN sys.extended_properties ep ON ep.major_id = c.object_id
139
+ AND ep.minor_id = c.column_id
140
+ AND ep.name = 'MS_Description'
141
+ WHERE
142
+ t.type = 'U' -- User-defined tables
143
+ ),
144
+ constraints_with_nulls AS (
145
+ SELECT
146
+ tf.*,
147
+ cc.name AS check_constraint_name,
148
+ CASE
149
+ WHEN cc.definition LIKE '%[' + tf.column_name + ']%=''%' THEN cc.definition
150
+ ELSE NULL
151
+ END AS check_constraint_definition
152
+ FROM
153
+ tables_and_fields AS tf
154
+ LEFT JOIN sys.check_constraints cc
155
+ ON cc.parent_object_id = OBJECT_ID(tf.table_schema + '.' + tf.table_name)
156
+ AND cc.definition LIKE '%' + tf.column_name + '%' -- Ensure the constraint references the column
157
+ ),
158
+ constraints_with_row_number AS (
159
+ SELECT
160
+ *,
161
+ ROW_NUMBER() OVER (
162
+ PARTITION BY table_schema, table_name, column_name
163
+ ORDER BY
164
+ CASE
165
+ WHEN check_constraint_definition IS NOT NULL THEN 1
166
+ ELSE 2
167
+ END,
168
+ check_constraint_name
169
+ ) AS rn
170
+ FROM
171
+ constraints_with_nulls
172
+ )
110
173
  SELECT
111
- s.name AS table_schema,
112
- t.name AS table_name,
113
- c.name AS column_name,
114
- ty.name AS data_type,
115
- c.max_length AS character_maximum_length,
116
- c.precision AS numeric_precision,
117
- c.scale AS numeric_scale,
118
- c.is_identity AS identity_increment,
174
+ table_schema,
175
+ table_name,
176
+ column_name,
177
+ data_type,
178
+ character_maximum_length,
179
+ numeric_precision,
180
+ numeric_scale,
181
+ identity_increment,
182
+ is_nullable,
183
+ column_default,
184
+ table_comment,
185
+ column_comment,
186
+ check_constraint_name,
187
+ check_constraint_definition,
119
188
  CASE
120
- WHEN c.is_nullable = 1 THEN 'YES'
121
- ELSE 'NO'
122
- END AS is_nullable,
123
- CASE
124
- WHEN c.default_object_id = 0 THEN NULL
125
- ELSE OBJECT_DEFINITION(c.default_object_id)
126
- END AS column_default,
127
- -- Fetching table comments
128
- p.value AS table_comment,
129
- ep.value AS column_comment
189
+ WHEN column_default LIKE '((%))' THEN 'number'
190
+ WHEN column_default LIKE '(''%'')' THEN 'string'
191
+ ELSE 'expression'
192
+ END AS default_type
130
193
  FROM
131
- sys.tables t
132
- JOIN sys.schemas s ON t.schema_id = s.schema_id
133
- JOIN sys.columns c ON t.object_id = c.object_id
134
- JOIN sys.types ty ON c.user_type_id = ty.user_type_id
135
- LEFT JOIN sys.extended_properties p ON p.major_id = t.object_id
136
- AND p.name = 'MS_Description'
137
- AND p.minor_id = 0 -- Ensure minor_id is 0 for table comments
138
- LEFT JOIN sys.extended_properties ep ON ep.major_id = c.object_id
139
- AND ep.minor_id = c.column_id
140
- AND ep.name = 'MS_Description'
194
+ constraints_with_row_number
141
195
  WHERE
142
- t.type = 'U' -- User-defined tables
143
- )
144
- SELECT
145
- tf.table_schema,
146
- tf.table_name,
147
- tf.column_name,
148
- tf.data_type,
149
- tf.character_maximum_length,
150
- tf.numeric_precision,
151
- tf.numeric_scale,
152
- tf.identity_increment,
153
- tf.is_nullable,
154
- tf.column_default,
155
- tf.table_comment,
156
- tf.column_comment,
157
- cc.name AS check_constraint_name, -- Adding CHECK constraint name
158
- cc.definition AS check_constraint_definition, -- Adding CHECK constraint definition
159
- CASE
160
- WHEN tf.column_default LIKE '((%))' THEN 'number'
161
- WHEN tf.column_default LIKE '(''%'')' THEN 'string'
162
- ELSE 'expression'
163
- END AS default_type
164
- FROM
165
- tables_and_fields AS tf
166
- LEFT JOIN sys.check_constraints cc
167
- ON cc.parent_object_id = OBJECT_ID(tf.table_schema + '.' + tf.table_name)
168
- AND cc.definition LIKE '%' + tf.column_name + '%' -- Ensure the constraint references the column
169
- ${(0, parseSchema_1.buildSchemaQuery)('tf.table_schema', schemas, 'WHERE')}
170
- ORDER BY
171
- tf.table_schema,
172
- tf.table_name,
173
- tf.column_name;
196
+ rn = 1
197
+ ${(0, parseSchema_1.buildSchemaQuery)('table_schema', schemas, 'WHERE')}
198
+ ORDER BY
199
+ table_schema,
200
+ table_name,
201
+ column_name;
174
202
  `;
175
203
  const tablesAndFieldsResult = await client.query(tablesAndFieldsSql);
176
204
  const tables = tablesAndFieldsResult.recordset.reduce((acc, row) => {
@@ -1,3 +1,3 @@
1
1
  import { DatabaseSchema } from './types';
2
2
  declare const fetchSchemaJson: (connection: string) => Promise<DatabaseSchema>;
3
- export { fetchSchemaJson, };
3
+ export { fetchSchemaJson };
@@ -83,7 +83,7 @@ const generateTablesAndFields = async (client, schemas) => {
83
83
  const fields = {};
84
84
  const tablesAndFieldsSql = `
85
85
  WITH comments AS (
86
- SELECT
86
+ SELECT DISTINCT ON (pc.relname, pn.nspname, pa.attname)
87
87
  pc.relname AS table_name,
88
88
  pn.nspname AS table_schema,
89
89
  pa.attname AS column_name,
@@ -113,6 +113,7 @@ const generateTablesAndFields = async (client, schemas) => {
113
113
  c.identity_increment,
114
114
  c.is_nullable,
115
115
  c.column_default,
116
+ c.ordinal_position,
116
117
  CASE
117
118
  WHEN c.column_default IS NULL THEN NULL
118
119
  WHEN c.column_default LIKE 'nextval(%' THEN 'increment'
@@ -121,8 +122,8 @@ const generateTablesAndFields = async (client, schemas) => {
121
122
  WHEN c.column_default ~ '^-?[0-9]+(.[0-9]+)?$' THEN 'number'
122
123
  ELSE 'expression'
123
124
  END AS default_type,
124
- (SELECT description FROM comments WHERE table_name = t.table_name AND table_schema = t.table_schema AND column_name IS NULL) AS table_comment,
125
- (SELECT description FROM comments WHERE table_name = t.table_name AND table_schema = t.table_schema AND column_name = c.column_name) AS column_comment
125
+ (SELECT description FROM comments WHERE table_name = t.table_name AND table_schema = t.table_schema AND column_name IS NULL LIMIT 1) AS table_comment,
126
+ (SELECT description FROM comments WHERE table_name = t.table_name AND table_schema = t.table_schema AND column_name = c.column_name LIMIT 1) AS column_comment
126
127
  FROM
127
128
  information_schema.columns c
128
129
  JOIN
@@ -355,7 +356,7 @@ const generateIndexes = async (client, schemas) => {
355
356
  };
356
357
  const generateRawEnums = async (client, schemas) => {
357
358
  const enumListSql = `
358
- SELECT
359
+ SELECT DISTINCT
359
360
  n.nspname AS schema_name,
360
361
  t.typname AS enum_type,
361
362
  e.enumlabel AS enum_value,
@@ -376,14 +377,15 @@ const generateRawEnums = async (client, schemas) => {
376
377
  const enumListResult = await client.query(enumListSql);
377
378
  const enums = enumListResult.rows.reduce((acc, row) => {
378
379
  const { schema_name, enum_type, enum_value } = row;
379
- if (!acc[enum_type]) {
380
- acc[enum_type] = {
380
+ const key = `${schema_name}.${enum_type}`;
381
+ if (!acc[key]) {
382
+ acc[key] = {
381
383
  name: enum_type,
382
384
  schemaName: schema_name,
383
385
  values: [],
384
386
  };
385
387
  }
386
- acc[enum_type].values.push({
388
+ acc[key].values.push({
387
389
  name: enum_value,
388
390
  });
389
391
  return acc;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbml/connector",
3
- "version": "3.8.0",
3
+ "version": "3.8.1",
4
4
  "description": "This package was created to fetch the schema JSON from many kind of databases.",
5
5
  "author": "huy.phung.sw@gmail.com",
6
6
  "license": "MIT",
@@ -40,5 +40,5 @@
40
40
  "engines": {
41
41
  "node": ">=18"
42
42
  },
43
- "gitHead": "f106540bc455695c8a4c91ed63aa8fabc8ce645a"
43
+ "gitHead": "40a25ded1488372f082739f6d43e45f2ad918e7e"
44
44
  }
@@ -1,20 +1,20 @@
1
1
  /* eslint-disable camelcase */
2
2
  import sql from 'mssql';
3
+ import { buildSchemaQuery, parseConnectionString } from '../utils/parseSchema';
3
4
  import {
4
- Field,
5
+ DatabaseSchema,
6
+ DefaultInfo,
5
7
  DefaultType,
6
- FieldsDictionary,
7
8
  Enum,
9
+ EnumValue,
10
+ Field,
11
+ FieldsDictionary,
12
+ IndexesDictionary,
8
13
  Ref,
9
14
  RefEndpoint,
10
15
  Table,
11
- IndexesDictionary,
12
- EnumValue,
13
16
  TableConstraintsDictionary,
14
- DatabaseSchema,
15
- DefaultInfo,
16
17
  } from './types';
17
- import { buildSchemaQuery, parseConnectionString } from '../utils/parseSchema';
18
18
 
19
19
  const MSSQL_DATE_TYPES = [
20
20
  'date',
@@ -141,71 +141,99 @@ const generateTablesFieldsAndEnums = async (client: sql.ConnectionPool, schemas:
141
141
  const fields: FieldsDictionary = {};
142
142
  const enums: Enum[] = [];
143
143
  const tablesAndFieldsSql = `
144
- WITH tables_and_fields AS (
144
+ WITH tables_and_fields AS (
145
+ SELECT
146
+ s.name AS table_schema,
147
+ t.name AS table_name,
148
+ c.name AS column_name,
149
+ ty.name AS data_type,
150
+ c.max_length AS character_maximum_length,
151
+ c.precision AS numeric_precision,
152
+ c.scale AS numeric_scale,
153
+ c.is_identity AS identity_increment,
154
+ CASE
155
+ WHEN c.is_nullable = 1 THEN 'YES'
156
+ ELSE 'NO'
157
+ END AS is_nullable,
158
+ CASE
159
+ WHEN c.default_object_id = 0 THEN NULL
160
+ ELSE OBJECT_DEFINITION(c.default_object_id)
161
+ END AS column_default,
162
+ -- Fetching table comments
163
+ p.value AS table_comment,
164
+ ep.value AS column_comment
165
+ FROM
166
+ sys.tables t
167
+ JOIN sys.schemas s ON t.schema_id = s.schema_id
168
+ JOIN sys.columns c ON t.object_id = c.object_id
169
+ JOIN sys.types ty ON c.user_type_id = ty.user_type_id
170
+ LEFT JOIN sys.extended_properties p ON p.major_id = t.object_id
171
+ AND p.name = 'MS_Description'
172
+ AND p.minor_id = 0 -- Ensure minor_id is 0 for table comments
173
+ LEFT JOIN sys.extended_properties ep ON ep.major_id = c.object_id
174
+ AND ep.minor_id = c.column_id
175
+ AND ep.name = 'MS_Description'
176
+ WHERE
177
+ t.type = 'U' -- User-defined tables
178
+ ),
179
+ constraints_with_nulls AS (
180
+ SELECT
181
+ tf.*,
182
+ cc.name AS check_constraint_name,
183
+ CASE
184
+ WHEN cc.definition LIKE '%[' + tf.column_name + ']%=''%' THEN cc.definition
185
+ ELSE NULL
186
+ END AS check_constraint_definition
187
+ FROM
188
+ tables_and_fields AS tf
189
+ LEFT JOIN sys.check_constraints cc
190
+ ON cc.parent_object_id = OBJECT_ID(tf.table_schema + '.' + tf.table_name)
191
+ AND cc.definition LIKE '%' + tf.column_name + '%' -- Ensure the constraint references the column
192
+ ),
193
+ constraints_with_row_number AS (
194
+ SELECT
195
+ *,
196
+ ROW_NUMBER() OVER (
197
+ PARTITION BY table_schema, table_name, column_name
198
+ ORDER BY
199
+ CASE
200
+ WHEN check_constraint_definition IS NOT NULL THEN 1
201
+ ELSE 2
202
+ END,
203
+ check_constraint_name
204
+ ) AS rn
205
+ FROM
206
+ constraints_with_nulls
207
+ )
145
208
  SELECT
146
- s.name AS table_schema,
147
- t.name AS table_name,
148
- c.name AS column_name,
149
- ty.name AS data_type,
150
- c.max_length AS character_maximum_length,
151
- c.precision AS numeric_precision,
152
- c.scale AS numeric_scale,
153
- c.is_identity AS identity_increment,
154
- CASE
155
- WHEN c.is_nullable = 1 THEN 'YES'
156
- ELSE 'NO'
157
- END AS is_nullable,
209
+ table_schema,
210
+ table_name,
211
+ column_name,
212
+ data_type,
213
+ character_maximum_length,
214
+ numeric_precision,
215
+ numeric_scale,
216
+ identity_increment,
217
+ is_nullable,
218
+ column_default,
219
+ table_comment,
220
+ column_comment,
221
+ check_constraint_name,
222
+ check_constraint_definition,
158
223
  CASE
159
- WHEN c.default_object_id = 0 THEN NULL
160
- ELSE OBJECT_DEFINITION(c.default_object_id)
161
- END AS column_default,
162
- -- Fetching table comments
163
- p.value AS table_comment,
164
- ep.value AS column_comment
224
+ WHEN column_default LIKE '((%))' THEN 'number'
225
+ WHEN column_default LIKE '(''%'')' THEN 'string'
226
+ ELSE 'expression'
227
+ END AS default_type
165
228
  FROM
166
- sys.tables t
167
- JOIN sys.schemas s ON t.schema_id = s.schema_id
168
- JOIN sys.columns c ON t.object_id = c.object_id
169
- JOIN sys.types ty ON c.user_type_id = ty.user_type_id
170
- LEFT JOIN sys.extended_properties p ON p.major_id = t.object_id
171
- AND p.name = 'MS_Description'
172
- AND p.minor_id = 0 -- Ensure minor_id is 0 for table comments
173
- LEFT JOIN sys.extended_properties ep ON ep.major_id = c.object_id
174
- AND ep.minor_id = c.column_id
175
- AND ep.name = 'MS_Description'
229
+ constraints_with_row_number
176
230
  WHERE
177
- t.type = 'U' -- User-defined tables
178
- )
179
- SELECT
180
- tf.table_schema,
181
- tf.table_name,
182
- tf.column_name,
183
- tf.data_type,
184
- tf.character_maximum_length,
185
- tf.numeric_precision,
186
- tf.numeric_scale,
187
- tf.identity_increment,
188
- tf.is_nullable,
189
- tf.column_default,
190
- tf.table_comment,
191
- tf.column_comment,
192
- cc.name AS check_constraint_name, -- Adding CHECK constraint name
193
- cc.definition AS check_constraint_definition, -- Adding CHECK constraint definition
194
- CASE
195
- WHEN tf.column_default LIKE '((%))' THEN 'number'
196
- WHEN tf.column_default LIKE '(''%'')' THEN 'string'
197
- ELSE 'expression'
198
- END AS default_type
199
- FROM
200
- tables_and_fields AS tf
201
- LEFT JOIN sys.check_constraints cc
202
- ON cc.parent_object_id = OBJECT_ID(tf.table_schema + '.' + tf.table_name)
203
- AND cc.definition LIKE '%' + tf.column_name + '%' -- Ensure the constraint references the column
204
- ${buildSchemaQuery('tf.table_schema', schemas, 'WHERE')}
205
- ORDER BY
206
- tf.table_schema,
207
- tf.table_name,
208
- tf.column_name;
231
+ rn = 1
232
+ ${buildSchemaQuery('table_schema', schemas, 'WHERE')}
233
+ ORDER BY
234
+ table_schema,
235
+ table_name,
236
+ column_name;
209
237
  `;
210
238
 
211
239
  const tablesAndFieldsResult = await client.query(tablesAndFieldsSql);
@@ -521,5 +549,5 @@ const fetchSchemaJson = async (connection: string): Promise<DatabaseSchema> => {
521
549
  };
522
550
 
523
551
  export {
524
- fetchSchemaJson,
552
+ fetchSchemaJson
525
553
  };
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable camelcase */
2
2
  import { Client } from 'pg';
3
+ import { buildSchemaQuery, parseConnectionString } from '../utils/parseSchema';
3
4
  import {
4
5
  DatabaseSchema,
5
6
  DefaultInfo,
@@ -13,7 +14,6 @@ import {
13
14
  Table,
14
15
  TableConstraintsDictionary,
15
16
  } from './types';
16
- import { parseConnectionString, buildSchemaQuery } from '../utils/parseSchema';
17
17
 
18
18
  const getValidatedClient = async (connection: string): Promise<Client> => {
19
19
  const client = new Client(connection);
@@ -121,7 +121,7 @@ const generateTablesAndFields = async (client: Client, schemas: string[]): Promi
121
121
  const fields: FieldsDictionary = {};
122
122
  const tablesAndFieldsSql = `
123
123
  WITH comments AS (
124
- SELECT
124
+ SELECT DISTINCT ON (pc.relname, pn.nspname, pa.attname)
125
125
  pc.relname AS table_name,
126
126
  pn.nspname AS table_schema,
127
127
  pa.attname AS column_name,
@@ -151,6 +151,7 @@ const generateTablesAndFields = async (client: Client, schemas: string[]): Promi
151
151
  c.identity_increment,
152
152
  c.is_nullable,
153
153
  c.column_default,
154
+ c.ordinal_position,
154
155
  CASE
155
156
  WHEN c.column_default IS NULL THEN NULL
156
157
  WHEN c.column_default LIKE 'nextval(%' THEN 'increment'
@@ -159,8 +160,8 @@ const generateTablesAndFields = async (client: Client, schemas: string[]): Promi
159
160
  WHEN c.column_default ~ '^-?[0-9]+(.[0-9]+)?$' THEN 'number'
160
161
  ELSE 'expression'
161
162
  END AS default_type,
162
- (SELECT description FROM comments WHERE table_name = t.table_name AND table_schema = t.table_schema AND column_name IS NULL) AS table_comment,
163
- (SELECT description FROM comments WHERE table_name = t.table_name AND table_schema = t.table_schema AND column_name = c.column_name) AS column_comment
163
+ (SELECT description FROM comments WHERE table_name = t.table_name AND table_schema = t.table_schema AND column_name IS NULL LIMIT 1) AS table_comment,
164
+ (SELECT description FROM comments WHERE table_name = t.table_name AND table_schema = t.table_schema AND column_name = c.column_name LIMIT 1) AS column_comment
164
165
  FROM
165
166
  information_schema.columns c
166
167
  JOIN
@@ -433,7 +434,7 @@ const generateIndexes = async (client: Client, schemas: string[]) => {
433
434
 
434
435
  const generateRawEnums = async (client: Client, schemas: string[]): Promise<Enum[]> => {
435
436
  const enumListSql = `
436
- SELECT
437
+ SELECT DISTINCT
437
438
  n.nspname AS schema_name,
438
439
  t.typname AS enum_type,
439
440
  e.enumlabel AS enum_value,
@@ -454,15 +455,16 @@ const generateRawEnums = async (client: Client, schemas: string[]): Promise<Enum
454
455
  const enumListResult = await client.query(enumListSql);
455
456
  const enums = enumListResult.rows.reduce((acc, row) => {
456
457
  const { schema_name, enum_type, enum_value } = row;
458
+ const key = `${schema_name}.${enum_type}`;
457
459
 
458
- if (!acc[enum_type]) {
459
- acc[enum_type] = {
460
+ if (!acc[key]) {
461
+ acc[key] = {
460
462
  name: enum_type,
461
463
  schemaName: schema_name,
462
464
  values: [],
463
465
  };
464
466
  }
465
- acc[enum_type].values.push({
467
+ acc[key].values.push({
466
468
  name: enum_value,
467
469
  });
468
470
  return acc;
@@ -504,5 +506,5 @@ const fetchSchemaJson = async (connection: string): Promise<DatabaseSchema> => {
504
506
  };
505
507
 
506
508
  export {
507
- fetchSchemaJson,
509
+ fetchSchemaJson
508
510
  };