@dbml/connector 5.0.0 → 5.1.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.
@@ -40,7 +40,7 @@ const executeQuery = (connection, sqlText) => {
40
40
  return new Promise((resolve, reject) => {
41
41
  console.log('Executing query...');
42
42
  connection.execute({
43
- sqlText: sqlText,
43
+ sqlText,
44
44
  complete: (err, stmt, rows) => {
45
45
  if (err) {
46
46
  reject(err);
@@ -51,7 +51,7 @@ const executeQuery = (connection, sqlText) => {
51
51
  resolve(rows);
52
52
  }
53
53
  }
54
- }
54
+ },
55
55
  });
56
56
  });
57
57
  };
@@ -203,14 +203,14 @@ const generateTablesAndFields = async (conn, schemas) => {
203
203
  };
204
204
  const createConstraintKeysMap = (keys, schemas, constraintType) => {
205
205
  return keys.reduce((acc, row) => {
206
- const { schema_name, table_name, column_name, constraint_name } = row;
206
+ const { schema_name, table_name, column_name, constraint_name, } = row;
207
207
  const selectedSchema = schemas.length > 0 ? schemas.includes(schema_name) : true;
208
208
  if (!selectedSchema) {
209
209
  return acc;
210
210
  }
211
211
  const key = `${schema_name}.${table_name}.${constraint_name}`;
212
212
  if (acc[key]) {
213
- const columnNames = acc[key].columnNames;
213
+ const { columnNames } = acc[key];
214
214
  columnNames.push(column_name);
215
215
  return acc;
216
216
  }
@@ -238,13 +238,14 @@ const generateIndexes = async (conn, databaseName, schemas) => {
238
238
  const uniqueKeysByConstraint = createConstraintKeysMap(uniqueKeys, schemas, 'unique');
239
239
  const allConstraints = [Object.values(primaryKeysByConstraint), Object.values(uniqueKeysByConstraint)].flat();
240
240
  const { indexes, tableConstraints } = allConstraints.reduce((acc, row) => {
241
- const { schemaName, tableName, constraintName, columnNames, type, primary, unique } = row;
241
+ const { schemaName, tableName, constraintName, columnNames, type, primary, unique, } = row;
242
242
  const key = `${schemaName}.${tableName}`;
243
243
  if (columnNames.length < 2) {
244
244
  acc.tableConstraints[key] = {
245
245
  [columnNames[0]]: {
246
246
  pk: primary,
247
247
  unique,
248
+ checks: [],
248
249
  },
249
250
  };
250
251
  return acc;
@@ -304,6 +305,8 @@ const fetchSchemaJson = async (connection) => {
304
305
  enums: [],
305
306
  indexes,
306
307
  tableConstraints,
308
+ // Checks are not supported in snowflake
309
+ checks: {},
307
310
  };
308
311
  };
309
312
  exports.fetchSchemaJson = fetchSchemaJson;
@@ -28,10 +28,18 @@ interface Table {
28
28
  interface FieldsDictionary {
29
29
  [key: string]: Field[];
30
30
  }
31
+ interface CheckConstraint {
32
+ name?: string;
33
+ expression: string;
34
+ }
35
+ interface CheckConstraintDictionary {
36
+ [tableName: string]: CheckConstraint[];
37
+ }
31
38
  interface TableConstraint {
32
39
  [fieldName: string]: {
33
40
  pk?: boolean;
34
41
  unique?: boolean;
42
+ checks: CheckConstraint[];
35
43
  };
36
44
  }
37
45
  interface TableConstraintsDictionary {
@@ -78,6 +86,7 @@ interface DatabaseSchema {
78
86
  tableConstraints: TableConstraintsDictionary;
79
87
  refs: Ref[];
80
88
  indexes: IndexesDictionary;
89
+ checks: CheckConstraintDictionary;
81
90
  }
82
91
  interface BigQueryCredentials {
83
92
  projectId?: string;
@@ -87,9 +96,4 @@ interface BigQueryCredentials {
87
96
  };
88
97
  datasets: string[];
89
98
  }
90
- interface EnumValuesDict {
91
- columns: string[];
92
- enumValues: EnumValue[];
93
- constraint_name: string;
94
- }
95
- export { NoteInfo, TypeInfo, DefaultType, DefaultInfo, Field, Table, FieldsDictionary, TableConstraint, TableConstraintsDictionary, RefEndpoint, Ref, EnumValue, Enum, IndexColumn, Index, IndexesDictionary, DatabaseSchema, BigQueryCredentials, EnumValuesDict, };
99
+ export { NoteInfo, TypeInfo, DefaultType, DefaultInfo, Field, Table, FieldsDictionary, TableConstraint, TableConstraintsDictionary, RefEndpoint, Ref, EnumValue, Enum, IndexColumn, Index, IndexesDictionary, DatabaseSchema, BigQueryCredentials, CheckConstraintDictionary, };
@@ -1,7 +1,8 @@
1
- import { FieldsDictionary, IndexesDictionary, Table, TableConstraintsDictionary } from '../connectors/types';
1
+ import { CheckConstraintDictionary, FieldsDictionary, IndexesDictionary, Table, TableConstraintsDictionary } from '../connectors/types';
2
2
  export declare function getIntersection<T>(firstList: T[], secondList: T[]): T[];
3
3
  export declare function getTableSchemaKey(schemaName: string, tableName: string): string;
4
4
  export declare function mergeTables(firstTableList: Table[], secondTable: Table[]): Table[];
5
5
  export declare function mergeFieldDictionary(firstDict: FieldsDictionary, secondDict: FieldsDictionary): FieldsDictionary;
6
6
  export declare function mergeIndexDictionary(firstDict: IndexesDictionary, secondDict: IndexesDictionary): IndexesDictionary;
7
7
  export declare function mergeTableConstraintDictionary(firstDict: TableConstraintsDictionary, secondDict: TableConstraintsDictionary): TableConstraintsDictionary;
8
+ export declare function mergeCheckConstraintDictionary(firstDict: CheckConstraintDictionary, secondDict: CheckConstraintDictionary): CheckConstraintDictionary;
@@ -6,6 +6,7 @@ exports.mergeTables = mergeTables;
6
6
  exports.mergeFieldDictionary = mergeFieldDictionary;
7
7
  exports.mergeIndexDictionary = mergeIndexDictionary;
8
8
  exports.mergeTableConstraintDictionary = mergeTableConstraintDictionary;
9
+ exports.mergeCheckConstraintDictionary = mergeCheckConstraintDictionary;
9
10
  function getIntersection(firstList, secondList) {
10
11
  return firstList.filter((item) => secondList.includes(item));
11
12
  }
@@ -19,7 +20,7 @@ function mergeTables(firstTableList, secondTable) {
19
20
  return firstTableList.concat(secondTable);
20
21
  }
21
22
  function mergeFieldDictionary(firstDict, secondDict) {
22
- const result = Object.assign({}, firstDict);
23
+ const result = { ...firstDict };
23
24
  Object.keys(secondDict).forEach((key) => {
24
25
  if (!result[key]) {
25
26
  result[key] = [];
@@ -29,7 +30,7 @@ function mergeFieldDictionary(firstDict, secondDict) {
29
30
  return result;
30
31
  }
31
32
  function mergeIndexDictionary(firstDict, secondDict) {
32
- const result = Object.assign({}, firstDict);
33
+ const result = { ...firstDict };
33
34
  Object.keys(secondDict).forEach((key) => {
34
35
  if (!result[key]) {
35
36
  result[key] = [];
@@ -39,7 +40,7 @@ function mergeIndexDictionary(firstDict, secondDict) {
39
40
  return result;
40
41
  }
41
42
  function mergeTableConstraintDictionary(firstDict, secondDict) {
42
- const result = Object.assign({}, firstDict);
43
+ const result = { ...firstDict };
43
44
  Object.keys(secondDict).forEach((key) => {
44
45
  if (!result[key]) {
45
46
  result[key] = {};
@@ -48,3 +49,13 @@ function mergeTableConstraintDictionary(firstDict, secondDict) {
48
49
  });
49
50
  return result;
50
51
  }
52
+ function mergeCheckConstraintDictionary(firstDict, secondDict) {
53
+ const result = { ...firstDict };
54
+ Object.keys(secondDict).forEach((key) => {
55
+ if (!result[key]) {
56
+ result[key] = [];
57
+ }
58
+ result[key] = result[key].concat(secondDict[key]);
59
+ });
60
+ return result;
61
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbml/connector",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
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",
@@ -44,5 +44,5 @@
44
44
  "engines": {
45
45
  "node": ">=18"
46
46
  },
47
- "gitHead": "a2d029e9c3c78ab0956312495165ec3115b5bc00"
47
+ "gitHead": "376dca507512a3fe549f630e6f22d7d339939183"
48
48
  }
@@ -297,7 +297,7 @@ async function generateTableConstraints (
297
297
  }
298
298
 
299
299
  if (!inlinePrimaryKeyMap[key][columnNames]) {
300
- inlinePrimaryKeyMap[key][columnNames] = {};
300
+ inlinePrimaryKeyMap[key][columnNames] = { checks: [] };
301
301
  }
302
302
 
303
303
  inlinePrimaryKeyMap[key][columnNames].pk = true;
@@ -372,6 +372,8 @@ async function fetchSchemaJsonByDataset (
372
372
  enums: [],
373
373
  indexes: mergeIndexDictionary(indexMap, compositePrimaryKeyMap),
374
374
  tableConstraints: inlinePrimaryKeyMap,
375
+ // Checks are not supported in BigQuery
376
+ checks: {},
375
377
  };
376
378
  }
377
379
 
@@ -401,7 +403,7 @@ async function fetchSchemaJson (keyFilename: string): Promise<DatabaseSchema> {
401
403
  return acc;
402
404
  },
403
405
  {
404
- tables: [], fields: {}, tableConstraints: {}, indexes: {}, refs: [], enums: [],
406
+ tables: [], fields: {}, tableConstraints: {}, indexes: {}, refs: [], enums: [], checks: {},
405
407
  },
406
408
  );
407
409
 
@@ -1,11 +1,16 @@
1
1
  /* eslint-disable camelcase */
2
+ /* TDD 72
3
+ * - In MSSQL, there's no notion of ENUM.
4
+ * - MSSQL connector used to extract ENUMS from CHECK constraints, for example: `CHECK ([col]=value1 OR [col]=value2)` would be translated to an enum with 2 values, `value1` and `value2`.
5
+ * - Since DBML 4.0.0, we have supported CHECK constraints, so we no longer extract ENUMS out from CHECK constraints but rather keep them as CHECK constraints.
6
+ * */
2
7
  import sql from 'mssql';
3
8
  import { buildSchemaQuery, parseConnectionString } from '../utils/parseSchema';
4
9
  import {
10
+ CheckConstraintDictionary,
5
11
  DatabaseSchema,
6
12
  DefaultInfo,
7
13
  DefaultType,
8
- Enum,
9
14
  Field,
10
15
  FieldsDictionary,
11
16
  IndexesDictionary,
@@ -13,7 +18,6 @@ import {
13
18
  RefEndpoint,
14
19
  Table,
15
20
  TableConstraintsDictionary,
16
- EnumValuesDict,
17
21
  } from './types';
18
22
 
19
23
  // https://learn.microsoft.com/en-us/sql/t-sql/data-types/date-and-time-types?view=sql-server-ver15
@@ -111,66 +115,6 @@ const getDbdefault = (data_type: string, column_default: string, default_type: D
111
115
  };
112
116
  };
113
117
 
114
- const getEnumValues = (definition: string, constraint_name: string): EnumValuesDict[] => {
115
- // Use the example below to understand the regex:
116
- // ([quantity]>(0))
117
- // ([unit_price]>(0))
118
- // ([status]='cancelled' OR [status]='delivered' OR [status]='shipped' OR [status]='processing' OR [status]='pending')
119
- // ([total_amount]>(0))
120
- // ([price]>(0))
121
- // ([stock_quantity]>=(0))
122
- // ([age_start]<=[age_end])
123
- // ([age_start]<=[age_end])
124
- // ([gender]='Other' OR [gender]='Female' OR [gender]='Male')
125
- // ([date_of_birth]<=dateadd(year,(-13),getdate()))
126
- // ([email] like '%_@_%._%')
127
- if (!definition) return [];
128
- const values = definition.match(/\[([^\]]+)\]='([^']+)'/g); // Extracting the enum values when the definition contains ]='
129
- if (!values) return [];
130
-
131
- const colMap: { [key: string]: string[] } = {};
132
- values.forEach((value) => {
133
- const [columnName, enumValue] = value.split("]='");
134
- const cleanColumnName = columnName.slice(1); // Remove the leading '['
135
- const cleanEnumValue = enumValue.slice(0, -1); // Remove the trailing "'"
136
- if (!colMap[cleanColumnName]) {
137
- colMap[cleanColumnName] = [cleanEnumValue];
138
- } else {
139
- colMap[cleanColumnName].push(cleanEnumValue);
140
- }
141
- });
142
-
143
- const arraysEqual = (a: string[], b: string[]): boolean => {
144
- if (a.length !== b.length) return false;
145
- const sortedA = [...a].sort();
146
- const sortedB = [...b].sort();
147
- return sortedA.every((value, index) => value === sortedB[index]);
148
- };
149
-
150
- // Please check the comments of the EnumValuesDict type in types.ts to understand the structure
151
- const result: EnumValuesDict[] = [];
152
- const processedKeys = new Set<string>();
153
-
154
- Object.keys(colMap).forEach((key) => {
155
- if (processedKeys.has(key)) return;
156
-
157
- const mergedColumns = [key];
158
- const colValues = colMap[key];
159
-
160
- Object.keys(colMap).forEach((innerKey) => {
161
- if (key !== innerKey && arraysEqual(colValues, colMap[innerKey])) {
162
- mergedColumns.push(innerKey);
163
- processedKeys.add(innerKey);
164
- }
165
- });
166
- const enumValues = colValues.map((value) => ({ name: value }));
167
- result.push({ columns: mergedColumns, enumValues, constraint_name: `${constraint_name}_${mergedColumns.join('_')}` });
168
- processedKeys.add(key);
169
- });
170
-
171
- return result;
172
- };
173
-
174
118
  const generateField = (row: Record<string, any>): Field => {
175
119
  const {
176
120
  column_name,
@@ -202,15 +146,11 @@ const generateField = (row: Record<string, any>): Field => {
202
146
  };
203
147
  };
204
148
 
205
- const generateTablesFieldsAndEnums = async (client: sql.ConnectionPool, schemas: string[]): Promise<{
149
+ const generateTablesFields = async (client: sql.ConnectionPool, schemas: string[]): Promise<{
206
150
  tables: Table[],
207
151
  fields: FieldsDictionary,
208
- enums: Enum[],
209
152
  }> => {
210
- const checkConstraintDefinitionDedup: { [key: string]: EnumValuesDict[] } = {};
211
-
212
153
  const fields: FieldsDictionary = {};
213
- const enums: Enum[] = [];
214
154
  const tablesAndFieldsSql = `
215
155
  WITH tables_and_fields AS (
216
156
  SELECT
@@ -249,35 +189,6 @@ const generateTablesFieldsAndEnums = async (client: sql.ConnectionPool, schemas:
249
189
  AND ep.name like '%description%'
250
190
  WHERE
251
191
  t.type = 'U' -- User-defined tables
252
- ),
253
- constraints_with_nulls AS (
254
- SELECT
255
- tf.*,
256
- cc.name AS check_constraint_name,
257
- CASE
258
- WHEN cc.definition LIKE '%[' + tf.column_name + ']%=''%' THEN cc.definition
259
- ELSE NULL
260
- END AS check_constraint_definition
261
- FROM
262
- tables_and_fields AS tf
263
- LEFT JOIN sys.check_constraints cc
264
- ON cc.parent_object_id = OBJECT_ID(tf.table_schema + '.' + tf.table_name)
265
- AND cc.definition LIKE '%' + tf.column_name + '%' -- Ensure the constraint references the column
266
- ),
267
- constraints_with_row_number AS (
268
- SELECT
269
- *,
270
- ROW_NUMBER() OVER (
271
- PARTITION BY table_schema, table_name, column_name
272
- ORDER BY
273
- CASE
274
- WHEN check_constraint_definition IS NOT NULL THEN 1
275
- ELSE 2
276
- END,
277
- check_constraint_name
278
- ) AS rn
279
- FROM
280
- constraints_with_nulls
281
192
  )
282
193
  SELECT
283
194
  table_schema,
@@ -292,17 +203,15 @@ const generateTablesFieldsAndEnums = async (client: sql.ConnectionPool, schemas:
292
203
  column_default,
293
204
  table_comment,
294
205
  column_comment,
295
- check_constraint_name,
296
- check_constraint_definition,
297
206
  CASE
298
207
  WHEN column_default LIKE '((%))' THEN 'number'
299
208
  WHEN column_default LIKE '(''%'')' THEN 'string'
300
209
  ELSE 'expression'
301
210
  END AS default_type
302
211
  FROM
303
- constraints_with_row_number
212
+ tables_and_fields
304
213
  WHERE
305
- rn = 1
214
+ 1 = 1
306
215
  ${buildSchemaQuery('table_schema', schemas)}
307
216
  ORDER BY
308
217
  table_schema,
@@ -317,8 +226,6 @@ const generateTablesFieldsAndEnums = async (client: sql.ConnectionPool, schemas:
317
226
  table_schema,
318
227
  table_name,
319
228
  table_comment,
320
- check_constraint_name,
321
- check_constraint_definition,
322
229
  } = row;
323
230
  const key = `${table_schema}.${table_name}`;
324
231
 
@@ -332,30 +239,6 @@ const generateTablesFieldsAndEnums = async (client: sql.ConnectionPool, schemas:
332
239
 
333
240
  if (!fields[key]) fields[key] = [];
334
241
  const field = generateField(row);
335
-
336
- if (check_constraint_definition && !checkConstraintDefinitionDedup[check_constraint_name]) {
337
- const enumValuesByColumns = getEnumValues(check_constraint_definition, check_constraint_name);
338
- enumValuesByColumns.forEach((item) => {
339
- enums.push({
340
- name: item.constraint_name,
341
- schemaName: table_schema,
342
- values: item.enumValues,
343
- });
344
- });
345
- checkConstraintDefinitionDedup[check_constraint_name] = enumValuesByColumns;
346
- }
347
-
348
- if (checkConstraintDefinitionDedup[check_constraint_name]) {
349
- const enumValuesByColumns = checkConstraintDefinitionDedup[check_constraint_name];
350
- const columnEnumValues = enumValuesByColumns.find((item) => item.columns.includes(field.name));
351
- if (columnEnumValues) {
352
- field.type = {
353
- type_name: columnEnumValues.constraint_name,
354
- schemaName: table_schema,
355
- };
356
- }
357
- }
358
-
359
242
  fields[key].push(field);
360
243
 
361
244
  return acc;
@@ -364,7 +247,6 @@ const generateTablesFieldsAndEnums = async (client: sql.ConnectionPool, schemas:
364
247
  return {
365
248
  tables: Object.values(tables),
366
249
  fields,
367
- enums,
368
250
  };
369
251
  };
370
252
 
@@ -461,7 +343,7 @@ const generateRefs = async (client: sql.ConnectionPool, schemas: string[]): Prom
461
343
  return refs;
462
344
  };
463
345
 
464
- const generateIndexes = async (client: sql.ConnectionPool, schemas: string[]) => {
346
+ const generateIndexesAndConstraints = async (client: sql.ConnectionPool, schemas: string[]) => {
465
347
  const indexListSql = `
466
348
  WITH user_tables AS (
467
349
  SELECT
@@ -537,19 +419,19 @@ const generateIndexes = async (client: sql.ConnectionPool, schemas: string[]) =>
537
419
  ii.index_name;
538
420
  `;
539
421
  const indexListResult = await client.query(indexListSql);
540
- const { outOfLineConstraints, inlineConstraints } = indexListResult.recordset.reduce((acc, row) => {
422
+ const { outOfLineIndexes, inlineIndexes } = indexListResult.recordset.reduce((acc, row) => {
541
423
  const { constraint_type, columns } = row;
542
424
 
543
425
  if (columns === 'null' || columns.trim() === '') return acc;
544
426
  if (constraint_type === 'PRIMARY KEY' || constraint_type === 'UNIQUE') {
545
- acc.inlineConstraints.push(row);
427
+ acc.inlineIndexes.push(row);
546
428
  } else {
547
- acc.outOfLineConstraints.push(row);
429
+ acc.outOfLineIndexes.push(row);
548
430
  }
549
431
  return acc;
550
- }, { outOfLineConstraints: [], inlineConstraints: [] });
432
+ }, { inlineIndexes: [], outOfLineIndexes: [] });
551
433
 
552
- const indexes = outOfLineConstraints.reduce((acc: IndexesDictionary, indexRow: Record<string, any>) => {
434
+ const indexes = outOfLineIndexes.reduce((acc: IndexesDictionary, indexRow: Record<string, any>) => {
553
435
  const {
554
436
  table_schema,
555
437
  table_name,
@@ -591,7 +473,9 @@ const generateIndexes = async (client: sql.ConnectionPool, schemas: string[]) =>
591
473
  return acc;
592
474
  }, {});
593
475
 
594
- const tableConstraints = inlineConstraints.reduce((acc: TableConstraintsDictionary, row: Record<string, any>) => {
476
+ const tableConstraints: TableConstraintsDictionary = {};
477
+
478
+ inlineIndexes.forEach((row: Record<string, any>) => {
595
479
  const {
596
480
  table_schema,
597
481
  table_name,
@@ -599,24 +483,64 @@ const generateIndexes = async (client: sql.ConnectionPool, schemas: string[]) =>
599
483
  constraint_type,
600
484
  } = row;
601
485
  const key = `${table_schema}.${table_name}`;
602
- if (!acc[key]) acc[key] = {};
486
+ if (!tableConstraints[key]) tableConstraints[key] = {};
603
487
 
604
488
  const columnNames = columns.split(',').map((column: string) => column.trim());
605
489
  columnNames.forEach((columnName: string) => {
606
- if (!acc[key][columnName]) acc[key][columnName] = {};
490
+ if (!tableConstraints[key][columnName]) tableConstraints[key][columnName] = { checks: [] };
607
491
  if (constraint_type === 'PRIMARY KEY') {
608
- acc[key][columnName].pk = true;
492
+ tableConstraints[key][columnName].pk = true;
609
493
  }
610
- if (constraint_type === 'UNIQUE' && !acc[key][columnName].pk) {
611
- acc[key][columnName].unique = true;
494
+ if (constraint_type === 'UNIQUE' && !tableConstraints[key][columnName].pk) {
495
+ tableConstraints[key][columnName].unique = true;
612
496
  }
613
497
  });
614
- return acc;
615
- }, {});
498
+ });
499
+
500
+ const checkListSql = `
501
+ SELECT
502
+ OBJECT_SCHEMA_NAME(cc.parent_object_id) AS table_schema,
503
+ OBJECT_NAME(cc.parent_object_id) AS table_name,
504
+ c.name AS column_name,
505
+ cc.name AS check_name,
506
+ cc.definition AS check_expression
507
+ FROM
508
+ sys.check_constraints cc
509
+ LEFT JOIN
510
+ sys.columns c ON cc.parent_object_id = c.object_id AND cc.parent_column_id = c.column_id
511
+ WHERE 1 = 1
512
+ ${buildSchemaQuery('OBJECT_SCHEMA_NAME(cc.parent_object_id)', schemas)}
513
+ `;
514
+
515
+ const checkListResult = await client.query(checkListSql);
516
+ const checks: CheckConstraintDictionary = {};
517
+ checkListResult.recordset.forEach((row) => {
518
+ const {
519
+ table_schema,
520
+ table_name,
521
+ column_name,
522
+ check_name,
523
+ check_expression,
524
+ } = row;
525
+ const key = `${table_schema}.${table_name}`;
526
+ if (column_name) {
527
+ if (!tableConstraints[key]) tableConstraints[key] = {};
528
+ if (!tableConstraints[key][column_name]) tableConstraints[key][column_name] = { checks: [] };
529
+ // The check definition has the form: `(expr)`
530
+ // The expression starts at 1 and ends at -1
531
+ tableConstraints[key][column_name].checks.push({ name: check_name, expression: check_expression.slice(1, -1) });
532
+ return;
533
+ }
534
+ if (!checks[key]) checks[key] = [];
535
+ // The check definition has the form: `(expr)`
536
+ // The expression starts at 1 and ends at -1
537
+ checks[key].push({ name: check_name, expression: check_expression.slice(1, -1) });
538
+ });
616
539
 
617
540
  return {
618
541
  indexes,
619
542
  tableConstraints,
543
+ checks,
620
544
  };
621
545
  };
622
546
 
@@ -624,28 +548,29 @@ const fetchSchemaJson = async (connection: string): Promise<DatabaseSchema> => {
624
548
  const { connectionString, schemas } = parseConnectionString(connection, 'odbc');
625
549
  const client = await getValidatedClient(connectionString);
626
550
 
627
- const tablesFieldsAndEnumsRes = generateTablesFieldsAndEnums(client, schemas);
628
- const indexesRes = generateIndexes(client, schemas);
551
+ const tablesRes = generateTablesFields(client, schemas);
552
+ const indexesAndConstraintsRes = generateIndexesAndConstraints(client, schemas);
629
553
  const refsRes = generateRefs(client, schemas);
630
554
 
631
555
  const res = await Promise.all([
632
- tablesFieldsAndEnumsRes,
633
- indexesRes,
556
+ tablesRes,
557
+ indexesAndConstraintsRes,
634
558
  refsRes,
635
559
  ]);
636
- client.close();
637
560
 
638
- const { tables, fields, enums } = res[0];
639
- const { indexes, tableConstraints } = res[1];
561
+ const { tables, fields } = res[0];
562
+ const { indexes, tableConstraints, checks } = res[1];
640
563
  const refs = res[2];
641
564
 
642
565
  return {
643
566
  tables,
644
567
  fields,
645
- enums,
568
+ // MSSQL doesn't support the notion of enums
569
+ enums: [],
646
570
  refs,
647
571
  indexes,
648
572
  tableConstraints,
573
+ checks,
649
574
  };
650
575
  };
651
576