@dbml/connector 5.1.0 → 5.3.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.
Files changed (58) hide show
  1. package/__tests__/connector.test.ts +1 -1
  2. package/__tests__/connectors/mssql/expect-out-files/schema.json +98 -7
  3. package/__tests__/connectors/mssql/out-files/schema.json +2165 -0
  4. package/__tests__/connectors/mysql/expect-out-files/schema.json +99 -9
  5. package/__tests__/connectors/mysql/out-files/schema.json +1520 -0
  6. package/__tests__/connectors/oracle/connection.json +4 -0
  7. package/__tests__/connectors/oracle/expect-out-files/schema.json +3866 -0
  8. package/__tests__/connectors/oracle/out-files/schema.json +3866 -0
  9. package/__tests__/connectors/postgres/expect-out-files/schema.json +119 -8
  10. package/__tests__/connectors/postgres/out-files/schema.json +1830 -0
  11. package/dist/connectors/{bigqueryConnector.d.ts → bigquery/index.d.ts} +1 -1
  12. package/dist/connectors/{bigqueryConnector.js → bigquery/index.js} +3 -4
  13. package/dist/connectors/connector.js +13 -10
  14. package/dist/connectors/{snowflakeConnector.d.ts → mssql/index.d.ts} +1 -1
  15. package/dist/connectors/{mssqlConnector.js → mssql/index.js} +13 -10
  16. package/dist/connectors/{mysqlConnector.d.ts → mysql/index.d.ts} +1 -1
  17. package/dist/connectors/{mysqlConnector.js → mysql/index.js} +1 -1
  18. package/dist/connectors/oracle/constraints.d.ts +7 -0
  19. package/dist/connectors/oracle/constraints.js +112 -0
  20. package/dist/connectors/oracle/index.d.ts +3 -0
  21. package/dist/connectors/oracle/index.js +68 -0
  22. package/dist/connectors/oracle/indexes.d.ts +3 -0
  23. package/dist/connectors/oracle/indexes.js +65 -0
  24. package/dist/connectors/oracle/refs.d.ts +3 -0
  25. package/dist/connectors/oracle/refs.js +67 -0
  26. package/dist/connectors/oracle/tables.d.ts +7 -0
  27. package/dist/connectors/oracle/tables.js +280 -0
  28. package/dist/connectors/oracle/utils.d.ts +9 -0
  29. package/dist/connectors/oracle/utils.js +27 -0
  30. package/dist/connectors/{postgresConnector.d.ts → postgres/index.d.ts} +1 -1
  31. package/dist/connectors/{postgresConnector.js → postgres/index.js} +21 -16
  32. package/dist/connectors/{mssqlConnector.d.ts → snowflake/index.d.ts} +1 -1
  33. package/dist/connectors/{snowflakeConnector.js → snowflake/index.js} +1 -2
  34. package/dist/connectors/types.d.ts +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +17 -7
  37. package/dist/utils/parseSchema.d.ts +1 -1
  38. package/dist/utils/parseSchema.js +13 -13
  39. package/eslint.config.ts +70 -0
  40. package/jest.config.ts +2 -2
  41. package/package.json +17 -6
  42. package/src/connectors/{bigqueryConnector.ts → bigquery/index.ts} +4 -5
  43. package/src/connectors/connector.ts +8 -5
  44. package/src/connectors/{mssqlConnector.ts → mssql/index.ts} +20 -15
  45. package/src/connectors/{mysqlConnector.ts → mysql/index.ts} +3 -3
  46. package/src/connectors/oracle/constraints.ts +113 -0
  47. package/src/connectors/oracle/index.ts +76 -0
  48. package/src/connectors/oracle/indexes.ts +71 -0
  49. package/src/connectors/oracle/refs.ts +73 -0
  50. package/src/connectors/oracle/tables.ts +305 -0
  51. package/src/connectors/oracle/utils.ts +23 -0
  52. package/src/connectors/{postgresConnector.ts → postgres/index.ts} +25 -18
  53. package/src/connectors/{snowflakeConnector.ts → snowflake/index.ts} +7 -6
  54. package/src/connectors/types.ts +14 -13
  55. package/src/index.ts +1 -1
  56. package/src/utils/parseSchema.ts +11 -11
  57. package/tsconfig.json +1 -1
  58. package/.eslintrc.json +0 -24
@@ -0,0 +1,305 @@
1
+ import { Connection } from 'oracledb';
2
+ import { DefaultInfo, DefaultType, Field, FieldsDictionary, Table } from '../types';
3
+ import { EXECUTE_OPTIONS } from './utils';
4
+
5
+ export async function generateTablesAndFields (client: Connection): Promise<{
6
+ tables: Table[];
7
+ fields: FieldsDictionary;
8
+ }> {
9
+ const fields: FieldsDictionary = {};
10
+ // Note: DATA_DEFAULT is LONG type which doesn't support SQL string operations
11
+ // The oracledb driver fetches LONG as string, so we detect default type in JavaScript
12
+ const tablesAndFieldsSql = `
13
+ SELECT
14
+ cols.TABLE_NAME AS "table_name",
15
+ cols.COLUMN_NAME AS "column_name",
16
+ cols.COLUMN_ID AS "column_id",
17
+ cols.DATA_TYPE AS "data_type",
18
+ cols.DATA_LENGTH AS "data_length",
19
+ cols.DATA_PRECISION AS "data_precision",
20
+ cols.DATA_SCALE AS "data_scale",
21
+ CASE WHEN cols.IDENTITY_COLUMN = 'YES' THEN 1 ELSE 0 END AS "identity_increment",
22
+ CASE WHEN cols.NULLABLE = 'Y' THEN 1 ELSE 0 END AS "is_nullable",
23
+ cols.DATA_DEFAULT AS "data_default",
24
+ tcoms.COMMENTS AS "table_comment",
25
+ ccoms.COMMENTS AS "column_comment",
26
+ obj.CREATED AS "table_created"
27
+ FROM USER_TAB_COLUMNS cols
28
+ LEFT JOIN USER_COL_COMMENTS ccoms
29
+ ON ccoms.COLUMN_NAME = cols.COLUMN_NAME
30
+ AND ccoms.TABLE_NAME = cols.TABLE_NAME
31
+ LEFT JOIN USER_TAB_COMMENTS tcoms
32
+ ON tcoms.TABLE_NAME = cols.TABLE_NAME
33
+ LEFT JOIN USER_OBJECTS obj
34
+ ON obj.OBJECT_NAME = cols.TABLE_NAME
35
+ AND obj.OBJECT_TYPE = 'TABLE'
36
+ ORDER BY obj.CREATED, obj.OBJECT_ID, cols.COLUMN_ID
37
+ `;
38
+
39
+ const tablesAndFieldsResult = await client.execute(tablesAndFieldsSql, [], EXECUTE_OPTIONS);
40
+ const tableMap = tablesAndFieldsResult.rows?.reduce((acc: Record<string, Table>, row) => {
41
+ const { table_name, table_comment } = row as any;
42
+ if (!acc[table_name]) {
43
+ acc[table_name] = {
44
+ name: table_name,
45
+ schemaName: '',
46
+ note: table_comment ? { value: table_comment } : { value: '' },
47
+ };
48
+ }
49
+
50
+ if (!fields[table_name]) fields[table_name] = [];
51
+ const field = generateField(row as any);
52
+ fields[table_name].push(field);
53
+
54
+ return acc;
55
+ }, {} as Record<string, Table>) || {};
56
+
57
+ return {
58
+ tables: Object.values(tableMap),
59
+ fields,
60
+ };
61
+ }
62
+
63
+ // Field utils
64
+
65
+ function getDefaultType (columnDefault: string | null | undefined): string {
66
+ if (columnDefault === null || columnDefault === undefined) {
67
+ return 'expression';
68
+ }
69
+ const trimmed = columnDefault.trim();
70
+ // String defaults are wrapped in single quotes: 'value'
71
+ // Example: `'string'`, `'string with quotes'''`
72
+ if (/^'.*'$/.test(trimmed)) {
73
+ return 'string';
74
+ }
75
+ // Number defaults are integers or non-scientific floats
76
+ // Example: `123`, `0.12`, `.12`, `12.`
77
+ if (/^[0-9]+$/.test(trimmed) || /^[0-9]*\.[0-9]*$/.test(trimmed)) {
78
+ return 'number';
79
+ }
80
+ // Example: Strings that are not enclosed in `'` or do not contain only numbers and `.`
81
+ // * CURRENT_TIMESTAMP
82
+ // * SYSDATE
83
+ // * "number-column" + 2
84
+ return 'expression';
85
+ }
86
+
87
+ function generateField (row: Record<string, any>): Field {
88
+ const {
89
+ column_name,
90
+ data_type,
91
+ data_length,
92
+ data_precision,
93
+ data_scale,
94
+ identity_increment,
95
+ is_nullable,
96
+ data_default,
97
+ column_comment,
98
+ } = row;
99
+
100
+ const defaultType = getDefaultType(data_default);
101
+ const dbdefault = data_default && !identity_increment ? getDbdefault(data_default, defaultType) : null;
102
+
103
+ const fieldType = {
104
+ type_name: getFieldType(data_type, data_length, data_precision, data_scale),
105
+ schemaName: null,
106
+ };
107
+
108
+ return {
109
+ name: column_name,
110
+ type: fieldType,
111
+ dbdefault,
112
+ not_null: !is_nullable,
113
+ increment: !!identity_increment,
114
+ note: column_comment ? { value: column_comment } : { value: '' },
115
+ };
116
+ }
117
+
118
+ // Field default utils
119
+
120
+ function getDbdefault (columnDefault: string | null, defaultType: string): DefaultInfo | null {
121
+ if (columnDefault === null) {
122
+ return null;
123
+ }
124
+ if (defaultType === 'string') {
125
+ const trimmed = columnDefault.trim();
126
+ return {
127
+ value: trimmed.slice(1, -1) // slice off single quotes at the start and end of the value
128
+ .replaceAll('\'\'', '\''), // escape sequences are preserved: in oracle, double single quotes = escape a single quote
129
+ type: defaultType,
130
+ };
131
+ }
132
+
133
+ return { value: columnDefault, type: defaultType as DefaultType };
134
+ }
135
+
136
+ // Field type utils
137
+
138
+ // These datatypes are never qualified: data size, data scale and data precision are all ignore.
139
+ // Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
140
+ const UNQUALIFIED_DATA_TYPES = new Set([
141
+ // datetime
142
+ 'date',
143
+ // number
144
+ 'binary_float',
145
+ 'binary_double',
146
+ // long and raw
147
+ 'long',
148
+ 'long raw',
149
+ // large object
150
+ 'blob',
151
+ 'clob',
152
+ 'nclob',
153
+ 'bfile',
154
+ // rowid
155
+ 'rowid',
156
+ // ansi supported
157
+ 'integer',
158
+ 'int',
159
+ 'smallint',
160
+ 'double precision',
161
+ 'real',
162
+ // any
163
+ 'AnyData',
164
+ 'AnyType',
165
+ 'AnyDataSet',
166
+ // xml
167
+ 'XMLType',
168
+ 'URIType',
169
+ // spatial
170
+ 'SDO_Geometry',
171
+ 'SDO_Topo_Geometry',
172
+ 'SDO_GeoRaster',
173
+ ]);
174
+
175
+ // These datatypes can be and only be qualified with data size
176
+ // For simplicity the data size in bytes is assumed
177
+ // Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
178
+ const SIZED_DATA_TYPES = new Set([
179
+ // character
180
+ 'char',
181
+ 'varchar2',
182
+ 'nchar',
183
+ 'nvarchar2',
184
+ // long and raw
185
+ 'raw',
186
+ // rowid
187
+ 'urowid',
188
+ // ansi supported
189
+ 'character varying',
190
+ 'character',
191
+ 'char varying',
192
+ 'nchar varying',
193
+ 'varchar',
194
+ 'national character varying',
195
+ 'national character',
196
+ 'national char varying',
197
+ 'national char',
198
+ ]);
199
+
200
+ // These datatypes can be and only be qualified with precision
201
+ // For datetime, these are the types that only have 1 precision
202
+ // Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
203
+ const PRECISION_DATA_TYPES = new Set([
204
+ // number
205
+ 'float',
206
+ ]);
207
+
208
+ // This datatype can be qualified with a fractional second precision
209
+ const TIMESTAMP_WITH_LOCAL_TIME_ZONE_DATA_TYPE = 'timestamp with local time zone';
210
+ // This datatype can be qualified with a second precision
211
+ const TIMESTAMP_WITH_TIME_ZONE_DATA_TYPE = 'timestamp with time zone';
212
+ // This datatype can be qualified with a second precision
213
+ const TIMESTAMP_DATA_TYPE = 'timestamp';
214
+ // This datatype can be qualified with a year precision
215
+ const INTERVAL_YEAR_DATA_TYPE = 'interval year to month';
216
+ // This datatype can be qualified with a day precision and a fraction second precision
217
+ const INTERVAL_DAY_DATA_TYPE = 'interval day to second';
218
+
219
+ // These datatypes can be and only be qualified with precision and scale
220
+ // For datetime, these are the types that can have 2 precisions
221
+ // Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
222
+ const PRECISION_SCALED_DATA_TYPES = new Set([
223
+ // number
224
+ 'number',
225
+ // ansi supported
226
+ 'numeric',
227
+ 'decimal',
228
+ 'dec',
229
+ ]);
230
+
231
+ // Format the field type to a standard string for aesthetic when exporting to DBML (`ANYDATA`, `anydata` are all normalized to `AnyData`)
232
+ // Some types contain multiple words with arbitrary spaces, for example, `TIMESTAMP (6) WITH LOCAL TIME ZONE`, we should normalize this to allow processing to be uniform, for example when checking for equality
233
+ function normalizeFieldType (dataType: string): string {
234
+ const normalizedDataType = dataType.split(' ').filter(Boolean).join(' ').toLowerCase();
235
+ switch (normalizedDataType) {
236
+ case 'anydata':
237
+ return 'AnyData';
238
+ case 'anytype':
239
+ return 'AnyType';
240
+ case 'anydataset':
241
+ return 'AnyDataSet';
242
+ case 'xmltype':
243
+ return 'XMLType';
244
+ case 'uritype':
245
+ return 'URIType';
246
+ case 'sdo_geometry':
247
+ return 'SDO_Geometry';
248
+ case 'sdo_topo_geometry':
249
+ return 'SDO_Topo_Geometry';
250
+ case 'sdo_georaster':
251
+ return 'SDO_GeoRaster';
252
+ default:
253
+ return normalizedDataType;
254
+ }
255
+ }
256
+
257
+ export function getFieldType (dataType: string, characterMaximumLength: number, numericPrecision: number | null, numericScale: number | null): string {
258
+ const normalizedDataType = normalizeFieldType(dataType);
259
+ if (normalizedDataType === TIMESTAMP_WITH_LOCAL_TIME_ZONE_DATA_TYPE) {
260
+ if (numericScale !== null) return `timestamp (${numericScale}) with local time zone`;
261
+ return normalizedDataType;
262
+ }
263
+ if (normalizedDataType === TIMESTAMP_WITH_TIME_ZONE_DATA_TYPE) {
264
+ if (numericScale !== null) return `timestamp (${numericScale}) with time zone`;
265
+ return normalizedDataType;
266
+ }
267
+ if (normalizedDataType === TIMESTAMP_DATA_TYPE) {
268
+ if (numericScale !== null) return `timestamp (${numericScale})`;
269
+ return normalizedDataType;
270
+ }
271
+ if (normalizedDataType === INTERVAL_YEAR_DATA_TYPE) {
272
+ if (numericPrecision !== null) return `interval year (${numericPrecision}) to month`;
273
+ return normalizedDataType;
274
+ }
275
+ if (normalizedDataType === INTERVAL_DAY_DATA_TYPE) {
276
+ if (numericPrecision !== null && numericScale !== null) return `interval day (${numericPrecision}) to second (${numericScale})`;
277
+ if (numericPrecision !== null) return `interval day (${numericPrecision}) to second`;
278
+ if (numericScale !== null) return `interval day to second (${numericScale})`;
279
+ return normalizedDataType;
280
+ }
281
+
282
+ if (SIZED_DATA_TYPES.has(normalizedDataType)) {
283
+ if (characterMaximumLength) return `${normalizedDataType}(${characterMaximumLength})`;
284
+ return normalizedDataType;
285
+ }
286
+
287
+ if (PRECISION_DATA_TYPES.has(normalizedDataType)) {
288
+ if (numericPrecision !== null) return `${normalizedDataType}(${numericPrecision})`;
289
+ return normalizedDataType;
290
+ }
291
+
292
+ if (PRECISION_SCALED_DATA_TYPES.has(normalizedDataType)) {
293
+ if (numericPrecision !== null && numericScale !== null) return `${normalizedDataType}(${numericPrecision}, ${numericScale})`;
294
+ if (numericPrecision !== null) return `${normalizedDataType}(${numericPrecision})`;
295
+ // There's no situation where numericScale is not null but numericPrecision is null
296
+ return normalizedDataType;
297
+ }
298
+
299
+ // This is not needed since we return `normalizedDataType` either if the condition holds true or not
300
+ // if (UNQUALIFIED_DATA_TYPES.has(normalizedDataType)) {
301
+ // return normalizedDataType;
302
+ // }
303
+
304
+ return normalizedDataType;
305
+ };
@@ -0,0 +1,23 @@
1
+ import oracledb from 'oracledb';
2
+
3
+ export const LIST_SEPARATOR = '@@@@@@@@'; // Used to join multiple fields into a string field to simulate array column types
4
+
5
+ export const EXECUTE_OPTIONS = { outFormat: oracledb.OUT_FORMAT_OBJECT };
6
+
7
+ // Expect an Easy Connect string format: username/password@[//]host[:port][/database]
8
+ // Explanation of the format: https://www.orafaq.com/wiki/EZCONNECT
9
+ export function processEasyConnectString (connection: string): { username: string; password: string; dbidentifier: string } {
10
+ // Capturing group `username`: a string without the characters `/` `@` `:`
11
+ // Capturing group `password`: a string without the characters `/` `@` `:`
12
+ // Capturing group `dbidentifier`: a string containing the `host[:port][/database]` part
13
+ const matches = connection.match(/^(?<username>[^/@:]+)\/(?<password>[^/@:]+)@(\/\/)?(?<dbidentifier>.+)$/);
14
+ const { username, password, dbidentifier } = matches?.groups || {};
15
+ if (!username || !password || !dbidentifier) {
16
+ throw new Error('Invalid Easy Connect string. Expect a string of format \'username/password@[//]host[:port][/database]\'');
17
+ }
18
+ return {
19
+ username,
20
+ password,
21
+ dbidentifier,
22
+ };
23
+ }
@@ -1,6 +1,5 @@
1
- /* eslint-disable camelcase */
2
1
  import { Client } from 'pg';
3
- import { buildSchemaQuery, parseConnectionString } from '../utils/parseSchema';
2
+ import { buildSchemaQuery, parseConnectionString } from '../../utils/parseSchema';
4
3
  import {
5
4
  CheckConstraintDictionary,
6
5
  DatabaseSchema,
@@ -14,7 +13,7 @@ import {
14
13
  RefEndpoint,
15
14
  Table,
16
15
  TableConstraintsDictionary,
17
- } from './types';
16
+ } from '../types';
18
17
 
19
18
  const getValidatedClient = async (connection: string): Promise<Client> => {
20
19
  const client = new Client(connection);
@@ -97,13 +96,15 @@ const generateField = (row: Record<string, any>): Field => {
97
96
 
98
97
  const dbdefault = column_default && default_type !== 'increment' ? getDbdefault(data_type, column_default, default_type) : null;
99
98
 
100
- const fieldType = data_type === 'USER-DEFINED' ? {
101
- type_name: udt_name,
102
- schemaName: udt_schema,
103
- } : {
104
- type_name: getFieldType(data_type, udt_name, character_maximum_length, numeric_precision, numeric_scale),
105
- schemaName: null,
106
- };
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
+ };
107
108
 
108
109
  return {
109
110
  name: column_name,
@@ -116,8 +117,8 @@ const generateField = (row: Record<string, any>): Field => {
116
117
  };
117
118
 
118
119
  const generateTablesAndFields = async (client: Client, schemas: string[]): Promise<{
119
- tables: Table[],
120
- fields: FieldsDictionary,
120
+ tables: Table[];
121
+ fields: FieldsDictionary;
121
122
  }> => {
122
123
  const fields: FieldsDictionary = {};
123
124
  const tablesAndFieldsSql = `
@@ -388,6 +389,8 @@ const generateIndexesAndConstraints = async (client: Client, schemas: string[])
388
389
  index_type,
389
390
  index_columns,
390
391
  index_expressions,
392
+ is_primary,
393
+ is_unique,
391
394
  } = indexRow;
392
395
  const indexColumns = index_columns.split(',').map((column: string) => {
393
396
  return {
@@ -396,12 +399,14 @@ const generateIndexesAndConstraints = async (client: Client, schemas: string[])
396
399
  };
397
400
  });
398
401
 
399
- const indexExpressions = index_expressions ? index_expressions.split(',').map((expression: string) => {
400
- return {
401
- type: 'expression',
402
- value: expression,
403
- };
404
- }) : [];
402
+ const indexExpressions = index_expressions
403
+ ? index_expressions.split(',').map((expression: string) => {
404
+ return {
405
+ type: 'expression',
406
+ value: expression,
407
+ };
408
+ })
409
+ : [];
405
410
 
406
411
  const index = {
407
412
  name: index_name,
@@ -410,6 +415,8 @@ const generateIndexesAndConstraints = async (client: Client, schemas: string[])
410
415
  ...indexColumns,
411
416
  ...indexExpressions,
412
417
  ],
418
+ pk: !!is_primary,
419
+ unique: !is_primary && !!is_unique,
413
420
  };
414
421
 
415
422
  const key = `${table_schema}.${table_name}`;
@@ -1,4 +1,3 @@
1
- /* eslint-disable camelcase */
2
1
  //
3
2
  // Description:
4
3
  // Snowflake info schema lacks reference direction for relationships.
@@ -9,7 +8,7 @@
9
8
 
10
9
  import snowflake from 'snowflake-sdk';
11
10
  import type { Connection, LogLevel, ConnectionOptions } from 'snowflake-sdk';
12
- import { parseSchema } from '../utils/parseSchema';
11
+ import { parseSchema } from '../../utils/parseSchema';
13
12
  import {
14
13
  DatabaseSchema,
15
14
  DefaultInfo,
@@ -20,7 +19,7 @@ import {
20
19
  IndexesDictionary,
21
20
  Table,
22
21
  TableConstraintsDictionary,
23
- } from './types';
22
+ } from '../types';
24
23
 
25
24
  type ConstraintRow = {
26
25
  schemaName: string;
@@ -196,8 +195,8 @@ const generateField = (row: Record<string, any>): Field => {
196
195
  };
197
196
 
198
197
  const generateTablesAndFields = async (conn: Connection, schemas: string[]): Promise<{
199
- tables: Table[],
200
- fields: FieldsDictionary,
198
+ tables: Table[];
199
+ fields: FieldsDictionary;
201
200
  }> => {
202
201
  const fields: FieldsDictionary = {};
203
202
  const schemaSql = schemas.length > 0 ? `AND c.table_schema IN (${schemas.map((schema) => `'${schema}'`).join(',')})` : '';
@@ -269,7 +268,9 @@ const createConstraintKeysMap = (keys: Record<string, string>[], schemas: string
269
268
  schema_name, table_name, column_name, constraint_name,
270
269
  } = row;
271
270
  const selectedSchema = schemas.length > 0 ? schemas.includes(schema_name) : true;
272
- if (!selectedSchema) { return acc; }
271
+ if (!selectedSchema) {
272
+ return acc;
273
+ }
273
274
 
274
275
  const key = `${schema_name}.${table_name}.${constraint_name}`;
275
276
 
@@ -10,7 +10,7 @@ interface TypeInfo {
10
10
  type DefaultType = 'string' | 'number' | 'boolean' | 'expression';
11
11
 
12
12
  interface DefaultInfo {
13
- type: DefaultType,
13
+ type: DefaultType;
14
14
  value: string;
15
15
  }
16
16
 
@@ -45,12 +45,12 @@ interface CheckConstraintDictionary {
45
45
  }
46
46
 
47
47
  interface TableConstraint {
48
- [fieldName: string]: {
49
- pk?: boolean;
50
- unique?: boolean;
51
- checks: CheckConstraint[];
48
+ [fieldName: string]: {
49
+ pk?: boolean;
50
+ unique?: boolean;
51
+ checks: CheckConstraint[];
52
52
  };
53
- }
53
+ }
54
54
 
55
55
  interface TableConstraintsDictionary {
56
56
  [tableIdentifier: string]: TableConstraint; // Represents constraints within tables, indexed by schemaName.tableName
@@ -88,8 +88,8 @@ interface IndexColumn {
88
88
  interface Index {
89
89
  name: string;
90
90
  type: string;
91
- unique?: boolean,
92
- pk?: boolean,
91
+ unique?: boolean;
92
+ pk?: boolean;
93
93
  columns: IndexColumn[];
94
94
  }
95
95
 
@@ -108,12 +108,12 @@ interface DatabaseSchema {
108
108
  }
109
109
 
110
110
  interface BigQueryCredentials {
111
- projectId?: string,
111
+ projectId?: string;
112
112
  credentials?: {
113
- clientEmail: string,
114
- privateKey: string,
115
- },
116
- datasets: string[],
113
+ clientEmail: string;
114
+ privateKey: string;
115
+ };
116
+ datasets: string[];
117
117
  }
118
118
 
119
119
  export {
@@ -135,5 +135,6 @@ export {
135
135
  IndexesDictionary,
136
136
  DatabaseSchema,
137
137
  BigQueryCredentials,
138
+ CheckConstraint,
138
139
  CheckConstraintDictionary,
139
140
  };
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,
@@ -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
- };
package/tsconfig.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "esModuleInterop": true,
10
10
  "skipLibCheck": true,
11
11
  "forceConsistentCasingInFileNames": true,
12
- "declaration": true, // Generates .d.ts files
12
+ "declaration": true // Generates .d.ts files
13
13
  },
14
14
  "include": ["./src"],
15
15
  "exclude": ["node_modules", "**/*.test.ts"]
package/.eslintrc.json DELETED
@@ -1,24 +0,0 @@
1
- {
2
- "extends": [
3
- "plugin:@typescript-eslint/recommended"
4
- ],
5
- "parser": "@typescript-eslint/parser",
6
- "parserOptions": {
7
- "sourceType": "module",
8
- "ecmaVersion": 2020,
9
- "project": "./tsconfig.json"
10
- },
11
- "settings": {
12
- "import/resolver": {
13
- "typescript": {
14
- "alwaysTryTypes": true,
15
- "project": "packages/*/{ts,js}config.json"
16
- }
17
- }
18
- },
19
- "plugins": ["@typescript-eslint"],
20
- "ignorePatterns": ["**/*.test.ts"],
21
- "rules": {
22
- "@typescript-eslint/no-explicit-any": "off"
23
- }
24
- }