@dbml/connector 5.2.0 → 5.3.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.
Files changed (46) hide show
  1. package/__tests__/connector.test.ts +1 -1
  2. package/__tests__/connectors/mssql/out-files/schema.json +37 -253
  3. package/__tests__/connectors/mysql/expect-out-files/schema.json +1 -1
  4. package/__tests__/connectors/oracle/connection.json +4 -0
  5. package/__tests__/connectors/oracle/expect-out-files/schema.json +3866 -0
  6. package/dist/connectors/{bigqueryConnector.d.ts → bigquery/index.d.ts} +1 -1
  7. package/dist/connectors/{bigqueryConnector.js → bigquery/index.js} +2 -2
  8. package/dist/connectors/connector.js +13 -10
  9. package/dist/connectors/{mssqlConnector.d.ts → mssql/index.d.ts} +1 -1
  10. package/dist/connectors/{mssqlConnector.js → mssql/index.js} +1 -1
  11. package/dist/connectors/{mysqlConnector.d.ts → mysql/index.d.ts} +1 -1
  12. package/dist/connectors/oracle/constraints.d.ts +7 -0
  13. package/dist/connectors/oracle/constraints.js +112 -0
  14. package/dist/connectors/oracle/index.d.ts +3 -0
  15. package/dist/connectors/oracle/index.js +68 -0
  16. package/dist/connectors/oracle/indexes.d.ts +3 -0
  17. package/dist/connectors/oracle/indexes.js +65 -0
  18. package/dist/connectors/oracle/refs.d.ts +3 -0
  19. package/dist/connectors/oracle/refs.js +67 -0
  20. package/dist/connectors/oracle/tables.d.ts +7 -0
  21. package/dist/connectors/oracle/tables.js +280 -0
  22. package/dist/connectors/oracle/utils.d.ts +9 -0
  23. package/dist/connectors/oracle/utils.js +27 -0
  24. package/dist/connectors/{snowflakeConnector.d.ts → postgres/index.d.ts} +1 -1
  25. package/dist/connectors/{postgresConnector.js → postgres/index.js} +1 -1
  26. package/dist/connectors/{postgresConnector.d.ts → snowflake/index.d.ts} +1 -1
  27. package/dist/connectors/{snowflakeConnector.js → snowflake/index.js} +1 -1
  28. package/dist/connectors/types.d.ts +1 -1
  29. package/package.json +5 -3
  30. package/src/connectors/{bigqueryConnector.ts → bigquery/index.ts} +3 -3
  31. package/src/connectors/connector.ts +8 -5
  32. package/src/connectors/{mssqlConnector.ts → mssql/index.ts} +2 -2
  33. package/src/connectors/{mysqlConnector.ts → mysql/index.ts} +1 -1
  34. package/src/connectors/oracle/constraints.ts +113 -0
  35. package/src/connectors/oracle/index.ts +76 -0
  36. package/src/connectors/oracle/indexes.ts +71 -0
  37. package/src/connectors/oracle/refs.ts +73 -0
  38. package/src/connectors/oracle/tables.ts +305 -0
  39. package/src/connectors/oracle/utils.ts +23 -0
  40. package/src/connectors/{postgresConnector.ts → postgres/index.ts} +2 -2
  41. package/src/connectors/{snowflakeConnector.ts → snowflake/index.ts} +2 -2
  42. package/src/connectors/types.ts +1 -0
  43. package/__tests__/connectors/mysql/out-files/schema.json +0 -1430
  44. package/__tests__/connectors/postgres/out-files/schema.json +0 -1719
  45. package/test-output.log +0 -18
  46. /package/dist/connectors/{mysqlConnector.js → mysql/index.js} +0 -0
@@ -1,3 +1,3 @@
1
- import { DatabaseSchema } from './types';
1
+ import { DatabaseSchema } from '../types';
2
2
  declare function fetchSchemaJson(keyFilename: string): Promise<DatabaseSchema>;
3
3
  export { fetchSchemaJson };
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.fetchSchemaJson = fetchSchemaJson;
4
4
  const bigquery_1 = require("@google-cloud/bigquery");
5
- const credential_loader_1 = require("../utils/credential-loader");
6
- const helpers_1 = require("../utils/helpers");
5
+ const credential_loader_1 = require("../../utils/credential-loader");
6
+ const helpers_1 = require("../../utils/helpers");
7
7
  // BigQuery client authentication strategy:
8
8
  // 1. Start with environment/default authentication:
9
9
  // - GOOGLE_APPLICATION_CREDENTIALS env variable (service account key file)
@@ -1,23 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.fetchSchemaJson = void 0;
4
- const postgresConnector_1 = require("./postgresConnector");
5
- const mssqlConnector_1 = require("./mssqlConnector");
6
- const mysqlConnector_1 = require("./mysqlConnector");
7
- const snowflakeConnector_1 = require("./snowflakeConnector");
8
- const bigqueryConnector_1 = require("./bigqueryConnector");
4
+ const postgres_1 = require("./postgres");
5
+ const mssql_1 = require("./mssql");
6
+ const mysql_1 = require("./mysql");
7
+ const snowflake_1 = require("./snowflake");
8
+ const bigquery_1 = require("./bigquery");
9
+ const oracle_1 = require("./oracle");
9
10
  const fetchSchemaJson = async (connection, databaseType) => {
10
11
  switch (databaseType) {
11
12
  case 'postgres':
12
- return (0, postgresConnector_1.fetchSchemaJson)(connection);
13
+ return (0, postgres_1.fetchSchemaJson)(connection);
13
14
  case 'mssql':
14
- return (0, mssqlConnector_1.fetchSchemaJson)(connection);
15
+ return (0, mssql_1.fetchSchemaJson)(connection);
15
16
  case 'mysql':
16
- return (0, mysqlConnector_1.fetchSchemaJson)(connection);
17
+ return (0, mysql_1.fetchSchemaJson)(connection);
17
18
  case 'snowflake':
18
- return (0, snowflakeConnector_1.fetchSchemaJson)(connection);
19
+ return (0, snowflake_1.fetchSchemaJson)(connection);
19
20
  case 'bigquery':
20
- return (0, bigqueryConnector_1.fetchSchemaJson)(connection);
21
+ return (0, bigquery_1.fetchSchemaJson)(connection);
22
+ case 'oracle':
23
+ return (0, oracle_1.fetchSchemaJson)(connection);
21
24
  default:
22
25
  throw new Error(`Unsupported database type: ${databaseType}`);
23
26
  }
@@ -1,3 +1,3 @@
1
- import { DatabaseSchema } from './types';
1
+ import { DatabaseSchema } from '../types';
2
2
  declare const fetchSchemaJson: (connection: string) => Promise<DatabaseSchema>;
3
3
  export { fetchSchemaJson, };
@@ -10,7 +10,7 @@ exports.fetchSchemaJson = void 0;
10
10
  * - 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.
11
11
  * */
12
12
  const mssql_1 = __importDefault(require("mssql"));
13
- const parseSchema_1 = require("../utils/parseSchema");
13
+ const parseSchema_1 = require("../../utils/parseSchema");
14
14
  // https://learn.microsoft.com/en-us/sql/t-sql/data-types/date-and-time-types?view=sql-server-ver15
15
15
  const MSSQL_DATE_TYPES = [
16
16
  'date',
@@ -1,3 +1,3 @@
1
- import { DatabaseSchema } from './types';
1
+ import { DatabaseSchema } from '../types';
2
2
  declare function fetchSchemaJson(connection: string): Promise<DatabaseSchema>;
3
3
  export { fetchSchemaJson, };
@@ -0,0 +1,7 @@
1
+ import { Connection } from 'oracledb';
2
+ import { CheckConstraintDictionary, IndexesDictionary, TableConstraintsDictionary } from '../types';
3
+ export declare function generateConstraints(client: Connection): Promise<{
4
+ indexes: IndexesDictionary;
5
+ tableConstraints: TableConstraintsDictionary;
6
+ checks: CheckConstraintDictionary;
7
+ }>;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateConstraints = generateConstraints;
4
+ const utils_1 = require("./utils");
5
+ async function generateConstraints(client) {
6
+ const query = `
7
+ WITH all_constraints AS (
8
+ SELECT
9
+ c.CONSTRAINT_NAME,
10
+ c.TABLE_NAME,
11
+ c.CONSTRAINT_TYPE,
12
+ c.SEARCH_CONDITION_VC AS CHECK_EXPRESSION
13
+ FROM USER_CONSTRAINTS c
14
+ WHERE c.CONSTRAINT_TYPE IN ('P', 'U', 'C') -- P stands for primary key, U stands for unique and C stands for check
15
+ AND (c.CONSTRAINT_TYPE != 'C' OR UPPER(c.SEARCH_CONDITION_VC) NOT LIKE '%IS NOT NULL')
16
+ ),
17
+ constraint_columns AS (
18
+ SELECT
19
+ cc.CONSTRAINT_NAME,
20
+ LISTAGG(cc.COLUMN_NAME, '${utils_1.LIST_SEPARATOR}') WITHIN GROUP (ORDER BY cc.POSITION) AS COLUMNS,
21
+ COUNT(cc.COLUMN_NAME) AS COLUMN_COUNT
22
+ FROM USER_CONS_COLUMNS cc
23
+ GROUP BY cc.CONSTRAINT_NAME
24
+ )
25
+ SELECT
26
+ ac.CONSTRAINT_NAME AS "constraint_name",
27
+ ac.TABLE_NAME AS "table_name",
28
+ cc.COLUMNS AS "columns",
29
+ cc.COLUMN_COUNT AS "column_count",
30
+ ac.CHECK_EXPRESSION AS "check_expression",
31
+ ac.CONSTRAINT_TYPE AS "constraint_type"
32
+ FROM all_constraints ac
33
+ LEFT JOIN constraint_columns cc
34
+ ON ac.CONSTRAINT_NAME = cc.CONSTRAINT_NAME
35
+ LEFT JOIN USER_OBJECTS obj
36
+ ON obj.OBJECT_NAME = ac.TABLE_NAME
37
+ AND obj.OBJECT_TYPE = 'TABLE'
38
+ ORDER BY
39
+ obj.CREATED,
40
+ obj.OBJECT_ID,
41
+ ac.CONSTRAINT_NAME
42
+ `;
43
+ const indexes = {};
44
+ const tableConstraints = {};
45
+ const checks = {};
46
+ const res = await client.execute(query, [], utils_1.EXECUTE_OPTIONS);
47
+ res.rows?.forEach((row) => {
48
+ const { constraint_name, table_name, columns: columnsStr, column_count, check_expression, constraint_type } = row;
49
+ const tableName = table_name;
50
+ const constraintName = constraint_name || '';
51
+ const columns = (columnsStr || '').split(utils_1.LIST_SEPARATOR);
52
+ const columnCount = column_count || 1;
53
+ const constraintType = constraint_type;
54
+ const checkExpression = (check_expression || null);
55
+ // Table-level check constraints
56
+ if (constraintType === 'C' && checkExpression && columnCount > 1) {
57
+ if (!checks[tableName])
58
+ checks[tableName] = [];
59
+ const check = {
60
+ name: constraintName,
61
+ expression: checkExpression,
62
+ };
63
+ checks[tableName].push(check);
64
+ return;
65
+ }
66
+ // Column-level check constraints
67
+ if (constraintType === 'C' && checkExpression && columnCount === 1 && columns.length === 1) {
68
+ if (!tableConstraints[tableName])
69
+ tableConstraints[tableName] = {};
70
+ const column = columns[0];
71
+ if (!tableConstraints[tableName][column])
72
+ tableConstraints[tableName][column] = { checks: [] };
73
+ tableConstraints[tableName][column].checks.push({
74
+ name: constraintName,
75
+ expression: checkExpression,
76
+ });
77
+ }
78
+ // Column-level unique or primary indexes
79
+ if (['P', 'U'].includes(constraintType) && columnCount === 1 && columns.length === 1) {
80
+ if (!tableConstraints[tableName])
81
+ tableConstraints[tableName] = {};
82
+ const column = columns[0];
83
+ if (!tableConstraints[tableName][column])
84
+ tableConstraints[tableName][column] = { checks: [] };
85
+ tableConstraints[tableName][column].pk ||= constraintType === 'P';
86
+ tableConstraints[tableName][column].unique ||= constraintType === 'U';
87
+ }
88
+ // Table-level unique or primary indexes
89
+ if (['P', 'U'].includes(constraintType) && columnCount > 1) {
90
+ if (!tableConstraints[tableName])
91
+ tableConstraints[tableName] = {};
92
+ if (!indexes[tableName])
93
+ indexes[tableName] = [];
94
+ const index = {
95
+ name: constraintName,
96
+ type: '',
97
+ unique: true,
98
+ pk: constraintType === 'P',
99
+ columns: columns.map((c) => ({
100
+ type: 'column',
101
+ value: c,
102
+ })),
103
+ };
104
+ indexes[tableName].push(index);
105
+ }
106
+ });
107
+ return {
108
+ indexes,
109
+ tableConstraints,
110
+ checks,
111
+ };
112
+ }
@@ -0,0 +1,3 @@
1
+ import { DatabaseSchema } from '../types';
2
+ declare function fetchSchemaJson(connection: string): Promise<DatabaseSchema>;
3
+ export { fetchSchemaJson, };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchSchemaJson = fetchSchemaJson;
4
+ const oracledb_1 = require("oracledb");
5
+ const tables_1 = require("./tables");
6
+ const refs_1 = require("./refs");
7
+ const constraints_1 = require("./constraints");
8
+ const indexes_1 = require("./indexes");
9
+ const utils_1 = require("./utils");
10
+ const getValidatedClient = async (username, password, dbidentifier) => {
11
+ const client = await (0, oracledb_1.getConnection)({
12
+ username,
13
+ password,
14
+ connectionString: dbidentifier,
15
+ });
16
+ try {
17
+ await client.execute('SELECT 1 FROM DUAL');
18
+ return client;
19
+ }
20
+ catch (error) {
21
+ await client.close();
22
+ if (error instanceof Error) {
23
+ throw new Error(`OracleSQL connection error: ${error.message}`);
24
+ }
25
+ throw error;
26
+ }
27
+ };
28
+ // Expect an Easy Connect string format: username/password@[//]host[:port][/database]
29
+ // `username` and `password` are mandatory
30
+ // `port` and `database` (and the parts enclosed in `[]`) are optional
31
+ // Explanation of the format: https://www.orafaq.com/wiki/EZCONNECT
32
+ async function fetchSchemaJson(connection) {
33
+ const { username, password, dbidentifier } = (0, utils_1.processEasyConnectString)(connection);
34
+ const client = await getValidatedClient(username, password, dbidentifier);
35
+ const tablesAndFieldsRes = (0, tables_1.generateTablesAndFields)(client);
36
+ const constraintsRes = (0, constraints_1.generateConstraints)(client);
37
+ const refsRes = (0, refs_1.generateRawRefs)(client);
38
+ const indexesRes = (0, indexes_1.generateIndexes)(client);
39
+ const res = await Promise.all([
40
+ tablesAndFieldsRes,
41
+ constraintsRes,
42
+ refsRes,
43
+ indexesRes,
44
+ ]);
45
+ const { tables, fields } = res[0];
46
+ const { indexes: uniqueIndexes, tableConstraints, checks } = res[1];
47
+ const refs = res[2];
48
+ const indexes = res[3];
49
+ Object.keys(uniqueIndexes).forEach((key) => {
50
+ if (!indexes[key])
51
+ indexes[key] = uniqueIndexes[key];
52
+ else
53
+ indexes[key].push(...uniqueIndexes[key]);
54
+ });
55
+ await client.close();
56
+ return {
57
+ tables,
58
+ fields,
59
+ refs,
60
+ // As of oracle 19c, there's no native ENUM data type
61
+ // ENUM is introduced in oracle 23ai
62
+ enums: [],
63
+ indexes,
64
+ tableConstraints,
65
+ checks,
66
+ };
67
+ }
68
+ ;
@@ -0,0 +1,3 @@
1
+ import { Connection } from 'oracledb';
2
+ import { IndexesDictionary } from '../types';
3
+ export declare function generateIndexes(client: Connection): Promise<IndexesDictionary>;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateIndexes = generateIndexes;
4
+ const utils_1 = require("./utils");
5
+ async function generateIndexes(client) {
6
+ const query = `
7
+ SELECT
8
+ i.INDEX_NAME AS "index_name",
9
+ i.TABLE_NAME AS "table_name",
10
+ CASE
11
+ WHEN i.INDEX_TYPE LIKE '%NORMAL' THEN 'btree'
12
+ ELSE LOWER(REGEXP_REPLACE(i.INDEX_TYPE, '^FUNCTION-BASED ', ''))
13
+ END AS "index_type",
14
+ CASE WHEN i.UNIQUENESS = 'UNIQUE' THEN 1 ELSE 0 END AS "is_unique",
15
+ ic.COLUMN_NAME AS "column_name",
16
+ ic.COLUMN_POSITION AS "column_position",
17
+ ie.COLUMN_EXPRESSION AS "column_expression"
18
+ FROM USER_INDEXES i
19
+ LEFT JOIN USER_IND_COLUMNS ic
20
+ ON i.INDEX_NAME = ic.INDEX_NAME
21
+ LEFT JOIN USER_IND_EXPRESSIONS ie
22
+ ON i.INDEX_NAME = ie.INDEX_NAME
23
+ AND ic.COLUMN_POSITION = ie.COLUMN_POSITION
24
+ LEFT JOIN USER_OBJECTS obj
25
+ ON obj.OBJECT_NAME = i.TABLE_NAME
26
+ AND obj.OBJECT_TYPE = 'TABLE'
27
+ WHERE NOT EXISTS (
28
+ SELECT 1
29
+ FROM USER_CONSTRAINTS c
30
+ WHERE c.INDEX_NAME = i.INDEX_NAME
31
+ )
32
+ ORDER BY obj.CREATED, obj.OBJECT_ID, i.INDEX_NAME, ic.COLUMN_POSITION
33
+ `;
34
+ const res = await client.execute(query, [], utils_1.EXECUTE_OPTIONS);
35
+ const indexes = {};
36
+ const indexMap = {};
37
+ res.rows?.forEach((row) => {
38
+ const { index_name, table_name, index_type, is_unique, column_name, column_expression } = row;
39
+ const name = index_name;
40
+ const table = table_name;
41
+ const type = index_type;
42
+ const unique = !!is_unique;
43
+ if (column_expression) {
44
+ if (!indexMap[name]) {
45
+ indexMap[name] = { table, type, unique, columns: [] };
46
+ }
47
+ indexMap[name].columns.push({ type: 'expression', value: column_expression });
48
+ return;
49
+ }
50
+ if (column_name) {
51
+ if (!indexMap[name]) {
52
+ indexMap[name] = { table, type, unique, columns: [] };
53
+ }
54
+ indexMap[name].columns.push({ type: 'column', value: column_name });
55
+ return;
56
+ }
57
+ });
58
+ Object.entries(indexMap).forEach(([name, { table, type, unique, columns }]) => {
59
+ const index = { name, type, unique, columns };
60
+ if (!indexes[table])
61
+ indexes[table] = [];
62
+ indexes[table].push(index);
63
+ });
64
+ return indexes;
65
+ }
@@ -0,0 +1,3 @@
1
+ import { Connection } from 'oracledb';
2
+ import { Ref } from '../types';
3
+ export declare function generateRawRefs(client: Connection): Promise<Ref[]>;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateRawRefs = generateRawRefs;
4
+ const utils_1 = require("./utils");
5
+ async function generateRawRefs(client) {
6
+ const refs = [];
7
+ const refsListSql = `
8
+ SELECT
9
+ c.CONSTRAINT_NAME AS "fk_name",
10
+ c.TABLE_NAME AS "child_table",
11
+ LISTAGG(cc.COLUMN_NAME, '${utils_1.LIST_SEPARATOR}') WITHIN GROUP (ORDER BY cc.POSITION) AS "child_columns",
12
+ p.TABLE_NAME AS "parent_table",
13
+ LISTAGG(pc.COLUMN_NAME, '${utils_1.LIST_SEPARATOR}') WITHIN GROUP (ORDER BY pc.POSITION) AS "parent_columns",
14
+ c.DELETE_RULE AS "delete_rule"
15
+ FROM USER_CONSTRAINTS c
16
+ JOIN USER_CONSTRAINTS p
17
+ ON c.R_CONSTRAINT_NAME = p.CONSTRAINT_NAME
18
+ JOIN USER_CONS_COLUMNS cc
19
+ ON c.CONSTRAINT_NAME = cc.CONSTRAINT_NAME
20
+ JOIN USER_CONS_COLUMNS pc
21
+ ON p.CONSTRAINT_NAME = pc.CONSTRAINT_NAME
22
+ AND cc.POSITION = pc.POSITION
23
+ LEFT JOIN USER_OBJECTS obj_child
24
+ ON obj_child.OBJECT_NAME = c.TABLE_NAME
25
+ AND obj_child.OBJECT_TYPE = 'TABLE'
26
+ LEFT JOIN USER_OBJECTS obj_parent
27
+ ON obj_parent.OBJECT_NAME = p.TABLE_NAME
28
+ AND obj_parent.OBJECT_TYPE = 'TABLE'
29
+ WHERE c.CONSTRAINT_TYPE = 'R'
30
+ GROUP BY
31
+ c.CONSTRAINT_NAME,
32
+ c.TABLE_NAME,
33
+ p.TABLE_NAME,
34
+ c.DELETE_RULE,
35
+ obj_child.CREATED,
36
+ obj_child.OBJECT_ID,
37
+ obj_parent.CREATED,
38
+ obj_parent.OBJECT_ID
39
+ ORDER BY
40
+ obj_child.CREATED,
41
+ obj_child.OBJECT_ID,
42
+ c.CONSTRAINT_NAME
43
+ `;
44
+ const refsQueryResult = await client.execute(refsListSql, [], utils_1.EXECUTE_OPTIONS);
45
+ refsQueryResult.rows?.forEach((refRow) => {
46
+ const { fk_name, child_table, child_columns, parent_table, parent_columns, delete_rule } = refRow;
47
+ const ep1 = {
48
+ tableName: child_table,
49
+ schemaName: '',
50
+ fieldNames: child_columns.split(utils_1.LIST_SEPARATOR),
51
+ relation: '*',
52
+ };
53
+ const ep2 = {
54
+ tableName: parent_table,
55
+ schemaName: '',
56
+ fieldNames: parent_columns.split(utils_1.LIST_SEPARATOR),
57
+ relation: '1',
58
+ };
59
+ refs.push({
60
+ name: fk_name,
61
+ endpoints: [ep1, ep2],
62
+ onDelete: delete_rule === 'NO ACTION' ? null : delete_rule,
63
+ onUpdate: null,
64
+ });
65
+ });
66
+ return refs;
67
+ }
@@ -0,0 +1,7 @@
1
+ import { Connection } from 'oracledb';
2
+ import { FieldsDictionary, Table } from '../types';
3
+ export declare function generateTablesAndFields(client: Connection): Promise<{
4
+ tables: Table[];
5
+ fields: FieldsDictionary;
6
+ }>;
7
+ export declare function getFieldType(dataType: string, characterMaximumLength: number, numericPrecision: number | null, numericScale: number | null): string;