@dbml/connector 5.0.0 → 5.2.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.
@@ -1,7 +1,7 @@
1
- /* eslint-disable camelcase */
2
1
  import { Client } from 'pg';
3
2
  import { buildSchemaQuery, parseConnectionString } from '../utils/parseSchema';
4
3
  import {
4
+ CheckConstraintDictionary,
5
5
  DatabaseSchema,
6
6
  DefaultInfo,
7
7
  DefaultType,
@@ -96,13 +96,15 @@ const generateField = (row: Record<string, any>): Field => {
96
96
 
97
97
  const dbdefault = column_default && default_type !== 'increment' ? getDbdefault(data_type, column_default, default_type) : null;
98
98
 
99
- const fieldType = data_type === 'USER-DEFINED' ? {
100
- type_name: udt_name,
101
- schemaName: udt_schema,
102
- } : {
103
- type_name: getFieldType(data_type, udt_name, character_maximum_length, numeric_precision, numeric_scale),
104
- schemaName: null,
105
- };
99
+ const fieldType = data_type === 'USER-DEFINED'
100
+ ? {
101
+ type_name: udt_name,
102
+ schemaName: udt_schema,
103
+ }
104
+ : {
105
+ type_name: getFieldType(data_type, udt_name, character_maximum_length, numeric_precision, numeric_scale),
106
+ schemaName: null,
107
+ };
106
108
 
107
109
  return {
108
110
  name: column_name,
@@ -115,8 +117,8 @@ const generateField = (row: Record<string, any>): Field => {
115
117
  };
116
118
 
117
119
  const generateTablesAndFields = async (client: Client, schemas: string[]): Promise<{
118
- tables: Table[],
119
- fields: FieldsDictionary,
120
+ tables: Table[];
121
+ fields: FieldsDictionary;
120
122
  }> => {
121
123
  const fields: FieldsDictionary = {};
122
124
  const tablesAndFieldsSql = `
@@ -301,7 +303,7 @@ const generateRawRefs = async (client: Client, schemas: string[]): Promise<Ref[]
301
303
  return refs;
302
304
  };
303
305
 
304
- const generateIndexes = async (client: Client, schemas: string[]) => {
306
+ const generateIndexesAndConstraints = async (client: Client, schemas: string[]) => {
305
307
  const indexListSql = `
306
308
  WITH user_tables AS (
307
309
  SELECT
@@ -348,8 +350,8 @@ const generateIndexes = async (client: Client, schemas: string[]) => {
348
350
  ii.is_unique,
349
351
  ii.is_primary,
350
352
  ii.index_type,
351
- ii.columns,
352
- ii.expressions,
353
+ ii.columns AS index_columns,
354
+ ii.expressions AS index_expressions,
353
355
  ii.constraint_type -- Retained constraint type here
354
356
  FROM
355
357
  user_tables ut
@@ -364,43 +366,47 @@ const generateIndexes = async (client: Client, schemas: string[]) => {
364
366
  ;
365
367
  `;
366
368
  const indexListResult = await client.query(indexListSql);
367
- const { outOfLineConstraints, inlineConstraints } = indexListResult.rows.reduce((acc, row) => {
368
- const { constraint_type, columns } = row;
369
+ const { outOfLineIndexes, inlineIndexes } = indexListResult.rows.reduce((acc, row) => {
370
+ const { constraint_type, index_columns } = row;
369
371
 
370
- if (columns === 'null' || columns.trim() === '') return acc;
372
+ if (index_columns === 'null' || index_columns.trim() === '') return acc;
371
373
 
372
- const isSingleColumn = columns.split(',').length === 1;
373
- const isInlineConstraint = isSingleColumn && (constraint_type === 'PRIMARY KEY' || constraint_type === 'UNIQUE');
374
- if (isInlineConstraint) {
375
- acc.inlineConstraints.push(row);
374
+ const isSingleColumn = index_columns.split(',').length === 1;
375
+ const isInlineIndex = isSingleColumn && (constraint_type === 'PRIMARY KEY' || constraint_type === 'UNIQUE');
376
+ if (isInlineIndex) {
377
+ acc.inlineIndexes.push(row);
376
378
  } else {
377
- acc.outOfLineConstraints.push(row);
379
+ acc.outOfLineIndexes.push(row);
378
380
  }
379
381
  return acc;
380
- }, { outOfLineConstraints: [], inlineConstraints: [] });
382
+ }, { outOfLineIndexes: [], inlineIndexes: [] });
381
383
 
382
- const indexes = outOfLineConstraints.reduce((acc: IndexesDictionary, indexRow: Record<string, any>) => {
384
+ const indexes = outOfLineIndexes.reduce((acc: IndexesDictionary, indexRow: Record<string, any>) => {
383
385
  const {
384
386
  table_schema,
385
387
  table_name,
386
388
  index_name,
387
389
  index_type,
388
- columns,
389
- expressions,
390
+ index_columns,
391
+ index_expressions,
392
+ is_primary,
393
+ is_unique,
390
394
  } = indexRow;
391
- const indexColumns = columns.split(',').map((column: string) => {
395
+ const indexColumns = index_columns.split(',').map((column: string) => {
392
396
  return {
393
397
  type: 'column',
394
398
  value: column.trim(),
395
399
  };
396
400
  });
397
401
 
398
- const indexExpressions = expressions ? expressions.split(',').map((expression: string) => {
399
- return {
400
- type: 'expression',
401
- value: expression,
402
- };
403
- }) : [];
402
+ const indexExpressions = index_expressions
403
+ ? index_expressions.split(',').map((expression: string) => {
404
+ return {
405
+ type: 'expression',
406
+ value: expression,
407
+ };
408
+ })
409
+ : [];
404
410
 
405
411
  const index = {
406
412
  name: index_name,
@@ -409,6 +415,8 @@ const generateIndexes = async (client: Client, schemas: string[]) => {
409
415
  ...indexColumns,
410
416
  ...indexExpressions,
411
417
  ],
418
+ pk: !!is_primary,
419
+ unique: !is_primary && !!is_unique,
412
420
  };
413
421
 
414
422
  const key = `${table_schema}.${table_name}`;
@@ -421,32 +429,105 @@ const generateIndexes = async (client: Client, schemas: string[]) => {
421
429
  return acc;
422
430
  }, {});
423
431
 
424
- const tableConstraints = inlineConstraints.reduce((acc: TableConstraintsDictionary, row: Record<string, any>) => {
432
+ const tableConstraints: TableConstraintsDictionary = {};
433
+
434
+ inlineIndexes.forEach((row: Record<string, any>) => {
425
435
  const {
426
436
  table_schema,
427
437
  table_name,
428
- columns,
438
+ index_columns,
429
439
  constraint_type,
430
440
  } = row;
431
441
  const key = `${table_schema}.${table_name}`;
432
- if (!acc[key]) acc[key] = {};
442
+ if (!tableConstraints[key]) tableConstraints[key] = {};
433
443
 
434
- const columnNames = columns.split(',').map((column: string) => column.trim());
444
+ const columnNames = index_columns.split(',').map((column: string) => column.trim());
435
445
  columnNames.forEach((columnName: string) => {
436
- if (!acc[key][columnName]) acc[key][columnName] = {};
446
+ if (!tableConstraints[key][columnName]) tableConstraints[key][columnName] = { checks: [] };
437
447
  if (constraint_type === 'PRIMARY KEY') {
438
- acc[key][columnName].pk = true;
448
+ tableConstraints[key][columnName].pk = true;
439
449
  }
440
- if (constraint_type === 'UNIQUE' && !acc[key][columnName].pk) {
441
- acc[key][columnName].unique = true;
450
+ if (constraint_type === 'UNIQUE' && !tableConstraints[key][columnName].pk) {
451
+ tableConstraints[key][columnName].unique = true;
442
452
  }
443
453
  });
444
- return acc;
445
454
  }, {});
446
455
 
456
+ const checkListSql = `
457
+ SELECT
458
+ n.nspname AS table_schema,
459
+ c.relname AS table_name,
460
+ MAX(a.attname) AS column_name,
461
+ con.conname AS check_name,
462
+ pg_get_constraintdef(con.oid) AS check_definition,
463
+ CASE
464
+ WHEN COUNT(*) = 1 THEN TRUE
465
+ ELSE FALSE
466
+ END AS is_column_constraint
467
+ FROM
468
+ pg_catalog.pg_constraint AS con
469
+ JOIN
470
+ pg_catalog.pg_class AS c
471
+ ON con.conrelid = c.oid
472
+ LEFT JOIN
473
+ pg_catalog.pg_namespace AS n
474
+ ON c.relnamespace = n.oid
475
+ LEFT JOIN
476
+ pg_catalog.pg_attribute AS a
477
+ ON a.attrelid = c.oid AND a.attnum = ANY(con.conkey)
478
+ WHERE con.contype = 'c' -- 'c' for CHECK constraints
479
+ ${buildSchemaQuery('n.nspname', schemas)}
480
+ GROUP BY
481
+ con.conname,
482
+ n.nspname,
483
+ c.relname,
484
+ con.oid
485
+ `;
486
+ const checkListResult = await client.query(checkListSql);
487
+ const checks: CheckConstraintDictionary = {};
488
+ checkListResult.rows.forEach((row) => {
489
+ const {
490
+ table_schema,
491
+ table_name,
492
+ check_name,
493
+ check_definition,
494
+ column_name,
495
+ is_column_constraint,
496
+ } = row;
497
+ if (typeof table_schema !== 'string' || typeof table_name !== 'string' || typeof check_definition !== 'string') {
498
+ return;
499
+ }
500
+ if (!check_definition.match(/CHECK \(\(.*\)\)/)) {
501
+ return;
502
+ }
503
+ if (is_column_constraint && typeof column_name !== 'string') {
504
+ return;
505
+ }
506
+ const key = `${table_schema}.${table_name}`;
507
+ if (is_column_constraint) {
508
+ if (!tableConstraints[key]) tableConstraints[key] = {};
509
+ if (!tableConstraints[key][column_name]) tableConstraints[key][column_name] = { checks: [] };
510
+ tableConstraints[key][column_name].checks.push({
511
+ name: check_name || undefined,
512
+ // The check definition has the form: `CHECK ((expr))`
513
+ // The expression starts at 8 and ends at -2
514
+ expression: check_definition.slice(8, -2),
515
+ });
516
+ return;
517
+ }
518
+ if (!checks[key]) checks[key] = [];
519
+ checks[key].push({
520
+ name: check_name || undefined,
521
+ // The check definition has the form: `CHECK ((expr))`
522
+ // The expression starts at 8 and ends at -2
523
+ expression: check_definition.slice(8, -2),
524
+ });
525
+ });
526
+
447
527
  return {
448
528
  indexes,
449
529
  tableConstraints,
530
+ checks,
450
531
  };
451
532
  };
452
533
 
@@ -496,7 +577,7 @@ const fetchSchemaJson = async (connection: string): Promise<DatabaseSchema> => {
496
577
  const client = await getValidatedClient(connectionString);
497
578
 
498
579
  const tablesAndFieldsRes = generateTablesAndFields(client, schemas);
499
- const indexesRes = generateIndexes(client, schemas);
580
+ const indexesRes = generateIndexesAndConstraints(client, schemas);
500
581
  const refsRes = generateRawRefs(client, schemas);
501
582
  const enumsRes = generateRawEnums(client, schemas);
502
583
 
@@ -509,7 +590,7 @@ const fetchSchemaJson = async (connection: string): Promise<DatabaseSchema> => {
509
590
  client.end();
510
591
 
511
592
  const { tables, fields } = res[0];
512
- const { indexes, tableConstraints } = res[1];
593
+ const { indexes, tableConstraints, checks } = res[1];
513
594
  const refs = res[2];
514
595
  const enums = res[3];
515
596
 
@@ -520,9 +601,10 @@ const fetchSchemaJson = async (connection: string): Promise<DatabaseSchema> => {
520
601
  enums,
521
602
  indexes,
522
603
  tableConstraints,
604
+ checks,
523
605
  };
524
606
  };
525
607
 
526
608
  export {
527
- fetchSchemaJson
609
+ fetchSchemaJson,
528
610
  };
@@ -1,4 +1,3 @@
1
- /* eslint-disable camelcase */
2
1
  //
3
2
  // Description:
4
3
  // Snowflake info schema lacks reference direction for relationships.
@@ -43,12 +42,11 @@ const parseConnectionString = (connectionString: string): Record<string, string>
43
42
  let match;
44
43
 
45
44
  while ((match = regex.exec(connectionString)) !== null) {
46
- params[match[1].trim()] = match[2].trim();
45
+ params[match[1].trim()] = match[2].trim();
47
46
  }
48
47
 
49
48
  return params;
50
- }
51
-
49
+ };
52
50
 
53
51
  const connect = async (connection: Connection): Promise<void> => {
54
52
  return new Promise((resolve, reject) => {
@@ -61,13 +59,13 @@ const connect = async (connection: Connection): Promise<void> => {
61
59
  }
62
60
  });
63
61
  });
64
- }
62
+ };
65
63
 
66
64
  const executeQuery = (connection: Connection, sqlText: string): Promise<any[]> => {
67
65
  return new Promise((resolve, reject) => {
68
66
  console.log('Executing query...');
69
67
  connection.execute({
70
- sqlText: sqlText,
68
+ sqlText,
71
69
  complete: (err, stmt, rows) => {
72
70
  if (err) {
73
71
  reject(err);
@@ -77,14 +75,14 @@ const executeQuery = (connection: Connection, sqlText: string): Promise<any[]> =
77
75
  resolve(rows);
78
76
  }
79
77
  }
80
- }
78
+ },
81
79
  });
82
80
  });
83
- }
81
+ };
84
82
 
85
83
  const isLogLevel = (value: string): value is LogLevel => {
86
- return ['ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'].includes(value as LogLevel)
87
- }
84
+ return ['ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'].includes(value as LogLevel);
85
+ };
88
86
 
89
87
  const connectToSnowflake = async (config: Record<string, string>): Promise<Connection> => {
90
88
  const logLevel = isLogLevel(config.LOG_LEVEL) ? config.LOG_LEVEL : 'INFO';
@@ -197,8 +195,8 @@ const generateField = (row: Record<string, any>): Field => {
197
195
  };
198
196
 
199
197
  const generateTablesAndFields = async (conn: Connection, schemas: string[]): Promise<{
200
- tables: Table[],
201
- fields: FieldsDictionary,
198
+ tables: Table[];
199
+ fields: FieldsDictionary;
202
200
  }> => {
203
201
  const fields: FieldsDictionary = {};
204
202
  const schemaSql = schemas.length > 0 ? `AND c.table_schema IN (${schemas.map((schema) => `'${schema}'`).join(',')})` : '';
@@ -266,14 +264,18 @@ const generateTablesAndFields = async (conn: Connection, schemas: string[]): Pro
266
264
 
267
265
  const createConstraintKeysMap = (keys: Record<string, string>[], schemas: string[], constraintType: 'primary' | 'unique'): Record<string, ConstraintRow> => {
268
266
  return keys.reduce((acc: Record<string, ConstraintRow>, row: Record<string, string>) => {
269
- const { schema_name, table_name, column_name, constraint_name } = row;
267
+ const {
268
+ schema_name, table_name, column_name, constraint_name,
269
+ } = row;
270
270
  const selectedSchema = schemas.length > 0 ? schemas.includes(schema_name) : true;
271
- if (!selectedSchema) { return acc; }
271
+ if (!selectedSchema) {
272
+ return acc;
273
+ }
272
274
 
273
275
  const key = `${schema_name}.${table_name}.${constraint_name}`;
274
276
 
275
277
  if (acc[key]) {
276
- const columnNames = acc[key].columnNames;
278
+ const { columnNames } = acc[key];
277
279
  columnNames.push(column_name);
278
280
  return acc;
279
281
  }
@@ -291,8 +293,6 @@ const createConstraintKeysMap = (keys: Record<string, string>[], schemas: string
291
293
  }, {});
292
294
  };
293
295
  const generateIndexes = async (conn: Connection, databaseName: string, schemas: string[]) => {
294
-
295
-
296
296
  const getPrimaryKeysSql = `
297
297
  SHOW PRIMARY KEYS IN DATABASE ${databaseName};
298
298
  `;
@@ -309,7 +309,9 @@ const generateIndexes = async (conn: Connection, databaseName: string, schemas:
309
309
 
310
310
  const allConstraints: ConstraintRow[] = [Object.values(primaryKeysByConstraint), Object.values(uniqueKeysByConstraint)].flat();
311
311
  const { indexes, tableConstraints } = allConstraints.reduce((acc: GeneratedIndexes, row: ConstraintRow): GeneratedIndexes => {
312
- const { schemaName, tableName, constraintName, columnNames, type, primary, unique } = row;
312
+ const {
313
+ schemaName, tableName, constraintName, columnNames, type, primary, unique,
314
+ } = row;
313
315
  const key = `${schemaName}.${tableName}`;
314
316
 
315
317
  if (columnNames.length < 2) {
@@ -317,6 +319,7 @@ const generateIndexes = async (conn: Connection, databaseName: string, schemas:
317
319
  [columnNames[0]]: {
318
320
  pk: primary,
319
321
  unique,
322
+ checks: [],
320
323
  },
321
324
  };
322
325
  return acc;
@@ -340,7 +343,7 @@ const generateIndexes = async (conn: Connection, databaseName: string, schemas:
340
343
  }
341
344
 
342
345
  return acc;
343
- }, { indexes: {}, tableConstraints: {}});
346
+ }, { indexes: {}, tableConstraints: {} });
344
347
 
345
348
  return {
346
349
  indexes,
@@ -384,6 +387,8 @@ const fetchSchemaJson = async (connection: string): Promise<DatabaseSchema> => {
384
387
  enums: [],
385
388
  indexes,
386
389
  tableConstraints,
390
+ // Checks are not supported in snowflake
391
+ checks: {},
387
392
  };
388
393
  };
389
394
 
@@ -1,5 +1,3 @@
1
- import { columns } from "mssql";
2
-
3
1
  interface NoteInfo {
4
2
  value: string;
5
3
  }
@@ -9,11 +7,10 @@ interface TypeInfo {
9
7
  schemaName: string | null;
10
8
  }
11
9
 
12
-
13
10
  type DefaultType = 'string' | 'number' | 'boolean' | 'expression';
14
11
 
15
12
  interface DefaultInfo {
16
- type: DefaultType,
13
+ type: DefaultType;
17
14
  value: string;
18
15
  }
19
16
 
@@ -38,10 +35,20 @@ interface FieldsDictionary {
38
35
  [key: string]: Field[]; // Represents fields within tables, indexed by schemaName.tableName
39
36
  }
40
37
 
38
+ interface CheckConstraint {
39
+ name?: string;
40
+ expression: string;
41
+ }
42
+
43
+ interface CheckConstraintDictionary {
44
+ [tableName: string]: CheckConstraint[];
45
+ }
46
+
41
47
  interface TableConstraint {
42
48
  [fieldName: string]: {
43
49
  pk?: boolean;
44
50
  unique?: boolean;
51
+ checks: CheckConstraint[];
45
52
  };
46
53
  }
47
54
 
@@ -81,8 +88,8 @@ interface IndexColumn {
81
88
  interface Index {
82
89
  name: string;
83
90
  type: string;
84
- unique?: boolean,
85
- pk?: boolean,
91
+ unique?: boolean;
92
+ pk?: boolean;
86
93
  columns: IndexColumn[];
87
94
  }
88
95
 
@@ -97,68 +104,16 @@ interface DatabaseSchema {
97
104
  tableConstraints: TableConstraintsDictionary;
98
105
  refs: Ref[];
99
106
  indexes: IndexesDictionary; // Represents the indexes property
107
+ checks: CheckConstraintDictionary;
100
108
  }
101
109
 
102
110
  interface BigQueryCredentials {
103
- projectId?: string,
111
+ projectId?: string;
104
112
  credentials?: {
105
- clientEmail: string,
106
- privateKey: string,
107
- },
108
- datasets: string[],
109
- }
110
-
111
- // Currently, we parse the check constraints as enum values in mssql.
112
- // However, one check constraint can have multiple set of enum values.
113
- // So, we need to store the enum values in a dictionary.
114
- // Examples:
115
- // CREATE TABLE AddressInfo (
116
- // A1 UNIQUEIDENTIFIER NOT NULL,
117
- // A2 UNIQUEIDENTIFIER NOT NULL,
118
- // A3 UNIQUEIDENTIFIER NOT NULL,
119
- // A4 UNIQUEIDENTIFIER NOT NULL,
120
- // CONSTRAINT CK_Address_Valid CHECK (
121
- // A1 IN ('1111', '2222', '333') AND
122
- // A2 IN ('1111', '2222') AND
123
- // A3 IN ('2222', '1111') AND
124
- // A4 IN ('2222', '3333')
125
- // )
126
- // );
127
- // GO
128
- // In the above example, we have a check constraint CK_Address_Valid2 with 4 columns: A1, A2, A3, A4.
129
- // Each column has a different set of enum values. So, we need to store the enum values in a dictionary.
130
- // In the above example, the enum values dictionary will look like this:
131
- // [
132
- // {
133
- // columns : ['A1'],
134
- // enumValues: [
135
- // { name: '1111' },
136
- // { name: '2222' },
137
- // { name: '333' }
138
- // ],
139
- // constraint_name: 'CK_Address_Valid_A1'
140
- // },
141
- // {
142
- // columns : ['A2, A3'], => In this case, these two columns have the same set of enum values.
143
- // enumValues: [
144
- // { name: '1111' },
145
- // { name: '2222' }
146
- // ],
147
- // constraint_name: 'CK_Address_Valid_A2_A3'
148
- // },
149
- // {
150
- // columns : ['A4'],
151
- // enumValues: [
152
- // { name: '2222' },
153
- // { name: '3333' }
154
- // ],
155
- // constraint_name: 'CK_Address_Valid_A4'
156
- // }
157
- // ]
158
- interface EnumValuesDict {
159
- columns: string[],
160
- enumValues: EnumValue[],
161
- constraint_name: string,
113
+ clientEmail: string;
114
+ privateKey: string;
115
+ };
116
+ datasets: string[];
162
117
  }
163
118
 
164
119
  export {
@@ -180,5 +135,5 @@ export {
180
135
  IndexesDictionary,
181
136
  DatabaseSchema,
182
137
  BigQueryCredentials,
183
- EnumValuesDict,
138
+ CheckConstraintDictionary,
184
139
  };
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as connector from "./connectors/connector";
1
+ import * as connector from './connectors/connector';
2
2
 
3
3
  export {
4
4
  connector,
@@ -1,15 +1,16 @@
1
1
  import {
2
+ CheckConstraintDictionary,
2
3
  FieldsDictionary,
3
4
  IndexesDictionary,
4
5
  Table,
5
6
  TableConstraintsDictionary,
6
7
  } from '../connectors/types';
7
8
 
8
- export function getIntersection<T>(firstList: T[], secondList: T[]): T[] {
9
+ export function getIntersection<T> (firstList: T[], secondList: T[]): T[] {
9
10
  return firstList.filter((item) => secondList.includes(item));
10
11
  }
11
12
 
12
- export function getTableSchemaKey(schemaName: string, tableName: string) {
13
+ export function getTableSchemaKey (schemaName: string, tableName: string) {
13
14
  if (!tableName || !tableName.trim()) {
14
15
  throw new Error('Table name must be a non-empty string');
15
16
  }
@@ -17,15 +18,15 @@ export function getTableSchemaKey(schemaName: string, tableName: string) {
17
18
  return schemaName ? `${schemaName}.${tableName}` : `${tableName}`;
18
19
  }
19
20
 
20
- export function mergeTables(firstTableList: Table[], secondTable: Table[]): Table[] {
21
+ export function mergeTables (firstTableList: Table[], secondTable: Table[]): Table[] {
21
22
  return firstTableList.concat(secondTable);
22
23
  }
23
24
 
24
- export function mergeFieldDictionary(
25
+ export function mergeFieldDictionary (
25
26
  firstDict: FieldsDictionary,
26
- secondDict: FieldsDictionary
27
+ secondDict: FieldsDictionary,
27
28
  ): FieldsDictionary {
28
- const result: FieldsDictionary = Object.assign({}, firstDict);
29
+ const result: FieldsDictionary = { ...firstDict };
29
30
 
30
31
  Object.keys(secondDict).forEach((key) => {
31
32
  if (!result[key]) {
@@ -38,11 +39,11 @@ export function mergeFieldDictionary(
38
39
  return result;
39
40
  }
40
41
 
41
- export function mergeIndexDictionary(
42
+ export function mergeIndexDictionary (
42
43
  firstDict: IndexesDictionary,
43
- secondDict: IndexesDictionary
44
+ secondDict: IndexesDictionary,
44
45
  ): IndexesDictionary {
45
- const result: IndexesDictionary = Object.assign({}, firstDict);
46
+ const result: IndexesDictionary = { ...firstDict };
46
47
 
47
48
  Object.keys(secondDict).forEach((key) => {
48
49
  if (!result[key]) {
@@ -55,11 +56,11 @@ export function mergeIndexDictionary(
55
56
  return result;
56
57
  }
57
58
 
58
- export function mergeTableConstraintDictionary(
59
+ export function mergeTableConstraintDictionary (
59
60
  firstDict: TableConstraintsDictionary,
60
- secondDict: TableConstraintsDictionary
61
+ secondDict: TableConstraintsDictionary,
61
62
  ): TableConstraintsDictionary {
62
- const result: TableConstraintsDictionary = Object.assign({}, firstDict);
63
+ const result: TableConstraintsDictionary = { ...firstDict };
63
64
 
64
65
  Object.keys(secondDict).forEach((key) => {
65
66
  if (!result[key]) {
@@ -71,3 +72,20 @@ export function mergeTableConstraintDictionary(
71
72
 
72
73
  return result;
73
74
  }
75
+
76
+ export function mergeCheckConstraintDictionary (
77
+ firstDict: CheckConstraintDictionary,
78
+ secondDict: CheckConstraintDictionary,
79
+ ): CheckConstraintDictionary {
80
+ const result: CheckConstraintDictionary = { ...firstDict };
81
+
82
+ Object.keys(secondDict).forEach((key) => {
83
+ if (!result[key]) {
84
+ result[key] = [];
85
+ }
86
+
87
+ result[key] = result[key].concat(secondDict[key]);
88
+ });
89
+
90
+ return result;
91
+ }
@@ -14,6 +14,17 @@ const noSchemaResult = (connectionString: string) => ({
14
14
  schemas: [],
15
15
  });
16
16
 
17
+ // Inputs: schemas string -> Output: schema array string[]
18
+ // schema1, schema2 -> ['schema1', 'schema2']
19
+ // schema3,schema4 -> ['schema3", 'schema4']
20
+ // "schema5,gg", "schema6", schema7 -> ['schema5,gg', 'schema6', 'schema7']
21
+ // schema8 -> ['schema8']
22
+ export const parseSchema = (schemas: string | undefined): string[] => {
23
+ if (!schemas) return [];
24
+ const schemasWithDoubleQuotes = schemas.split(/,(?=(?:[^"]*(?:"[^"]*")*)*$)/).map((s) => s.trim());
25
+ return schemasWithDoubleQuotes.map((s) => s.replace(/"/g, ''));
26
+ };
27
+
17
28
  const parseOdbcSchema = (connectionString: string) => {
18
29
  const connectionParts = connectionString.split(';');
19
30
  const schemasPart = connectionParts.find((part) => haveSchemas(part));
@@ -47,14 +58,3 @@ export const buildSchemaQuery = (columnName: string, schemas: string[], prefix =
47
58
  if (schemas.length === 0) return '';
48
59
  return `${prefix} ${columnName} IN (${schemas.map((schema) => `'${schema}'`).join(', ')})`;
49
60
  };
50
-
51
- // Inputs: schemas string -> Output: schema array string[]
52
- // schema1, schema2 -> ['schema1', 'schema2']
53
- // schema3,schema4 -> ['schema3", 'schema4']
54
- // "schema5,gg", "schema6", schema7 -> ['schema5,gg', 'schema6', 'schema7']
55
- // schema8 -> ['schema8']
56
- export const parseSchema = (schemas: string | undefined): string[] => {
57
- if (!schemas) return [];
58
- const schemasWithDoubleQuotes = schemas.split(/,(?=(?:[^"]*(?:"[^"]*")*)*$)/).map((s) => s.trim());
59
- return schemasWithDoubleQuotes.map((s) => s.replace(/"/g, ''));
60
- };
@@ -0,0 +1,18 @@
1
+
2
+ > @dbml/connector@5.1.0 test
3
+ > jest
4
+
5
+ PASS __tests__/connector.test.ts
6
+ @dbml/connector
7
+ ✓ connectors/mssql (264 ms)
8
+ ✓ connectors/mysql (31 ms)
9
+ ✓ connectors/postgres (55 ms)
10
+
11
+ Test Suites: 1 passed, 1 total
12
+ Tests: 3 passed, 3 total
13
+ Snapshots: 0 total
14
+ Time: 1.208 s, estimated 2 s
15
+ Ran all test suites.
16
+ Jest did not exit one second after the test run has completed.
17
+
18
+ 'This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.