@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.
- package/__tests__/connector.test.ts +1 -1
- package/__tests__/connectors/mssql/expect-out-files/schema.json +98 -7
- package/__tests__/connectors/mssql/out-files/schema.json +2165 -0
- package/__tests__/connectors/mysql/expect-out-files/schema.json +99 -9
- package/__tests__/connectors/mysql/out-files/schema.json +1520 -0
- package/__tests__/connectors/oracle/connection.json +4 -0
- package/__tests__/connectors/oracle/expect-out-files/schema.json +3866 -0
- package/__tests__/connectors/oracle/out-files/schema.json +3866 -0
- package/__tests__/connectors/postgres/expect-out-files/schema.json +119 -8
- package/__tests__/connectors/postgres/out-files/schema.json +1830 -0
- package/dist/connectors/{bigqueryConnector.d.ts → bigquery/index.d.ts} +1 -1
- package/dist/connectors/{bigqueryConnector.js → bigquery/index.js} +3 -4
- package/dist/connectors/connector.js +13 -10
- package/dist/connectors/{snowflakeConnector.d.ts → mssql/index.d.ts} +1 -1
- package/dist/connectors/{mssqlConnector.js → mssql/index.js} +13 -10
- package/dist/connectors/{mysqlConnector.d.ts → mysql/index.d.ts} +1 -1
- package/dist/connectors/{mysqlConnector.js → mysql/index.js} +1 -1
- package/dist/connectors/oracle/constraints.d.ts +7 -0
- package/dist/connectors/oracle/constraints.js +112 -0
- package/dist/connectors/oracle/index.d.ts +3 -0
- package/dist/connectors/oracle/index.js +68 -0
- package/dist/connectors/oracle/indexes.d.ts +3 -0
- package/dist/connectors/oracle/indexes.js +65 -0
- package/dist/connectors/oracle/refs.d.ts +3 -0
- package/dist/connectors/oracle/refs.js +67 -0
- package/dist/connectors/oracle/tables.d.ts +7 -0
- package/dist/connectors/oracle/tables.js +280 -0
- package/dist/connectors/oracle/utils.d.ts +9 -0
- package/dist/connectors/oracle/utils.js +27 -0
- package/dist/connectors/{postgresConnector.d.ts → postgres/index.d.ts} +1 -1
- package/dist/connectors/{postgresConnector.js → postgres/index.js} +21 -16
- package/dist/connectors/{mssqlConnector.d.ts → snowflake/index.d.ts} +1 -1
- package/dist/connectors/{snowflakeConnector.js → snowflake/index.js} +1 -2
- package/dist/connectors/types.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -7
- package/dist/utils/parseSchema.d.ts +1 -1
- package/dist/utils/parseSchema.js +13 -13
- package/eslint.config.ts +70 -0
- package/jest.config.ts +2 -2
- package/package.json +17 -6
- package/src/connectors/{bigqueryConnector.ts → bigquery/index.ts} +4 -5
- package/src/connectors/connector.ts +8 -5
- package/src/connectors/{mssqlConnector.ts → mssql/index.ts} +20 -15
- package/src/connectors/{mysqlConnector.ts → mysql/index.ts} +3 -3
- package/src/connectors/oracle/constraints.ts +113 -0
- package/src/connectors/oracle/index.ts +76 -0
- package/src/connectors/oracle/indexes.ts +71 -0
- package/src/connectors/oracle/refs.ts +73 -0
- package/src/connectors/oracle/tables.ts +305 -0
- package/src/connectors/oracle/utils.ts +23 -0
- package/src/connectors/{postgresConnector.ts → postgres/index.ts} +25 -18
- package/src/connectors/{snowflakeConnector.ts → snowflake/index.ts} +7 -6
- package/src/connectors/types.ts +14 -13
- package/src/index.ts +1 -1
- package/src/utils/parseSchema.ts +11 -11
- package/tsconfig.json +1 -1
- package/.eslintrc.json +0 -24
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateTablesAndFields = generateTablesAndFields;
|
|
4
|
+
exports.getFieldType = getFieldType;
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
async function generateTablesAndFields(client) {
|
|
7
|
+
const fields = {};
|
|
8
|
+
// Note: DATA_DEFAULT is LONG type which doesn't support SQL string operations
|
|
9
|
+
// The oracledb driver fetches LONG as string, so we detect default type in JavaScript
|
|
10
|
+
const tablesAndFieldsSql = `
|
|
11
|
+
SELECT
|
|
12
|
+
cols.TABLE_NAME AS "table_name",
|
|
13
|
+
cols.COLUMN_NAME AS "column_name",
|
|
14
|
+
cols.COLUMN_ID AS "column_id",
|
|
15
|
+
cols.DATA_TYPE AS "data_type",
|
|
16
|
+
cols.DATA_LENGTH AS "data_length",
|
|
17
|
+
cols.DATA_PRECISION AS "data_precision",
|
|
18
|
+
cols.DATA_SCALE AS "data_scale",
|
|
19
|
+
CASE WHEN cols.IDENTITY_COLUMN = 'YES' THEN 1 ELSE 0 END AS "identity_increment",
|
|
20
|
+
CASE WHEN cols.NULLABLE = 'Y' THEN 1 ELSE 0 END AS "is_nullable",
|
|
21
|
+
cols.DATA_DEFAULT AS "data_default",
|
|
22
|
+
tcoms.COMMENTS AS "table_comment",
|
|
23
|
+
ccoms.COMMENTS AS "column_comment",
|
|
24
|
+
obj.CREATED AS "table_created"
|
|
25
|
+
FROM USER_TAB_COLUMNS cols
|
|
26
|
+
LEFT JOIN USER_COL_COMMENTS ccoms
|
|
27
|
+
ON ccoms.COLUMN_NAME = cols.COLUMN_NAME
|
|
28
|
+
AND ccoms.TABLE_NAME = cols.TABLE_NAME
|
|
29
|
+
LEFT JOIN USER_TAB_COMMENTS tcoms
|
|
30
|
+
ON tcoms.TABLE_NAME = cols.TABLE_NAME
|
|
31
|
+
LEFT JOIN USER_OBJECTS obj
|
|
32
|
+
ON obj.OBJECT_NAME = cols.TABLE_NAME
|
|
33
|
+
AND obj.OBJECT_TYPE = 'TABLE'
|
|
34
|
+
ORDER BY obj.CREATED, obj.OBJECT_ID, cols.COLUMN_ID
|
|
35
|
+
`;
|
|
36
|
+
const tablesAndFieldsResult = await client.execute(tablesAndFieldsSql, [], utils_1.EXECUTE_OPTIONS);
|
|
37
|
+
const tableMap = tablesAndFieldsResult.rows?.reduce((acc, row) => {
|
|
38
|
+
const { table_name, table_comment } = row;
|
|
39
|
+
if (!acc[table_name]) {
|
|
40
|
+
acc[table_name] = {
|
|
41
|
+
name: table_name,
|
|
42
|
+
schemaName: '',
|
|
43
|
+
note: table_comment ? { value: table_comment } : { value: '' },
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (!fields[table_name])
|
|
47
|
+
fields[table_name] = [];
|
|
48
|
+
const field = generateField(row);
|
|
49
|
+
fields[table_name].push(field);
|
|
50
|
+
return acc;
|
|
51
|
+
}, {}) || {};
|
|
52
|
+
return {
|
|
53
|
+
tables: Object.values(tableMap),
|
|
54
|
+
fields,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Field utils
|
|
58
|
+
function getDefaultType(columnDefault) {
|
|
59
|
+
if (columnDefault === null || columnDefault === undefined) {
|
|
60
|
+
return 'expression';
|
|
61
|
+
}
|
|
62
|
+
const trimmed = columnDefault.trim();
|
|
63
|
+
// String defaults are wrapped in single quotes: 'value'
|
|
64
|
+
// Example: `'string'`, `'string with quotes'''`
|
|
65
|
+
if (/^'.*'$/.test(trimmed)) {
|
|
66
|
+
return 'string';
|
|
67
|
+
}
|
|
68
|
+
// Number defaults are integers or non-scientific floats
|
|
69
|
+
// Example: `123`, `0.12`, `.12`, `12.`
|
|
70
|
+
if (/^[0-9]+$/.test(trimmed) || /^[0-9]*\.[0-9]*$/.test(trimmed)) {
|
|
71
|
+
return 'number';
|
|
72
|
+
}
|
|
73
|
+
// Example: Strings that are not enclosed in `'` or do not contain only numbers and `.`
|
|
74
|
+
// * CURRENT_TIMESTAMP
|
|
75
|
+
// * SYSDATE
|
|
76
|
+
// * "number-column" + 2
|
|
77
|
+
return 'expression';
|
|
78
|
+
}
|
|
79
|
+
function generateField(row) {
|
|
80
|
+
const { column_name, data_type, data_length, data_precision, data_scale, identity_increment, is_nullable, data_default, column_comment, } = row;
|
|
81
|
+
const defaultType = getDefaultType(data_default);
|
|
82
|
+
const dbdefault = data_default && !identity_increment ? getDbdefault(data_default, defaultType) : null;
|
|
83
|
+
const fieldType = {
|
|
84
|
+
type_name: getFieldType(data_type, data_length, data_precision, data_scale),
|
|
85
|
+
schemaName: null,
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
name: column_name,
|
|
89
|
+
type: fieldType,
|
|
90
|
+
dbdefault,
|
|
91
|
+
not_null: !is_nullable,
|
|
92
|
+
increment: !!identity_increment,
|
|
93
|
+
note: column_comment ? { value: column_comment } : { value: '' },
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Field default utils
|
|
97
|
+
function getDbdefault(columnDefault, defaultType) {
|
|
98
|
+
if (columnDefault === null) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (defaultType === 'string') {
|
|
102
|
+
const trimmed = columnDefault.trim();
|
|
103
|
+
return {
|
|
104
|
+
value: trimmed.slice(1, -1) // slice off single quotes at the start and end of the value
|
|
105
|
+
.replaceAll('\'\'', '\''), // escape sequences are preserved: in oracle, double single quotes = escape a single quote
|
|
106
|
+
type: defaultType,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return { value: columnDefault, type: defaultType };
|
|
110
|
+
}
|
|
111
|
+
// Field type utils
|
|
112
|
+
// These datatypes are never qualified: data size, data scale and data precision are all ignore.
|
|
113
|
+
// Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
|
|
114
|
+
const UNQUALIFIED_DATA_TYPES = new Set([
|
|
115
|
+
// datetime
|
|
116
|
+
'date',
|
|
117
|
+
// number
|
|
118
|
+
'binary_float',
|
|
119
|
+
'binary_double',
|
|
120
|
+
// long and raw
|
|
121
|
+
'long',
|
|
122
|
+
'long raw',
|
|
123
|
+
// large object
|
|
124
|
+
'blob',
|
|
125
|
+
'clob',
|
|
126
|
+
'nclob',
|
|
127
|
+
'bfile',
|
|
128
|
+
// rowid
|
|
129
|
+
'rowid',
|
|
130
|
+
// ansi supported
|
|
131
|
+
'integer',
|
|
132
|
+
'int',
|
|
133
|
+
'smallint',
|
|
134
|
+
'double precision',
|
|
135
|
+
'real',
|
|
136
|
+
// any
|
|
137
|
+
'AnyData',
|
|
138
|
+
'AnyType',
|
|
139
|
+
'AnyDataSet',
|
|
140
|
+
// xml
|
|
141
|
+
'XMLType',
|
|
142
|
+
'URIType',
|
|
143
|
+
// spatial
|
|
144
|
+
'SDO_Geometry',
|
|
145
|
+
'SDO_Topo_Geometry',
|
|
146
|
+
'SDO_GeoRaster',
|
|
147
|
+
]);
|
|
148
|
+
// These datatypes can be and only be qualified with data size
|
|
149
|
+
// For simplicity the data size in bytes is assumed
|
|
150
|
+
// Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
|
|
151
|
+
const SIZED_DATA_TYPES = new Set([
|
|
152
|
+
// character
|
|
153
|
+
'char',
|
|
154
|
+
'varchar2',
|
|
155
|
+
'nchar',
|
|
156
|
+
'nvarchar2',
|
|
157
|
+
// long and raw
|
|
158
|
+
'raw',
|
|
159
|
+
// rowid
|
|
160
|
+
'urowid',
|
|
161
|
+
// ansi supported
|
|
162
|
+
'character varying',
|
|
163
|
+
'character',
|
|
164
|
+
'char varying',
|
|
165
|
+
'nchar varying',
|
|
166
|
+
'varchar',
|
|
167
|
+
'national character varying',
|
|
168
|
+
'national character',
|
|
169
|
+
'national char varying',
|
|
170
|
+
'national char',
|
|
171
|
+
]);
|
|
172
|
+
// These datatypes can be and only be qualified with precision
|
|
173
|
+
// For datetime, these are the types that only have 1 precision
|
|
174
|
+
// Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
|
|
175
|
+
const PRECISION_DATA_TYPES = new Set([
|
|
176
|
+
// number
|
|
177
|
+
'float',
|
|
178
|
+
]);
|
|
179
|
+
// This datatype can be qualified with a fractional second precision
|
|
180
|
+
const TIMESTAMP_WITH_LOCAL_TIME_ZONE_DATA_TYPE = 'timestamp with local time zone';
|
|
181
|
+
// This datatype can be qualified with a second precision
|
|
182
|
+
const TIMESTAMP_WITH_TIME_ZONE_DATA_TYPE = 'timestamp with time zone';
|
|
183
|
+
// This datatype can be qualified with a second precision
|
|
184
|
+
const TIMESTAMP_DATA_TYPE = 'timestamp';
|
|
185
|
+
// This datatype can be qualified with a year precision
|
|
186
|
+
const INTERVAL_YEAR_DATA_TYPE = 'interval year to month';
|
|
187
|
+
// This datatype can be qualified with a day precision and a fraction second precision
|
|
188
|
+
const INTERVAL_DAY_DATA_TYPE = 'interval day to second';
|
|
189
|
+
// These datatypes can be and only be qualified with precision and scale
|
|
190
|
+
// For datetime, these are the types that can have 2 precisions
|
|
191
|
+
// Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
|
|
192
|
+
const PRECISION_SCALED_DATA_TYPES = new Set([
|
|
193
|
+
// number
|
|
194
|
+
'number',
|
|
195
|
+
// ansi supported
|
|
196
|
+
'numeric',
|
|
197
|
+
'decimal',
|
|
198
|
+
'dec',
|
|
199
|
+
]);
|
|
200
|
+
// Format the field type to a standard string for aesthetic when exporting to DBML (`ANYDATA`, `anydata` are all normalized to `AnyData`)
|
|
201
|
+
// 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
|
|
202
|
+
function normalizeFieldType(dataType) {
|
|
203
|
+
const normalizedDataType = dataType.split(' ').filter(Boolean).join(' ').toLowerCase();
|
|
204
|
+
switch (normalizedDataType) {
|
|
205
|
+
case 'anydata':
|
|
206
|
+
return 'AnyData';
|
|
207
|
+
case 'anytype':
|
|
208
|
+
return 'AnyType';
|
|
209
|
+
case 'anydataset':
|
|
210
|
+
return 'AnyDataSet';
|
|
211
|
+
case 'xmltype':
|
|
212
|
+
return 'XMLType';
|
|
213
|
+
case 'uritype':
|
|
214
|
+
return 'URIType';
|
|
215
|
+
case 'sdo_geometry':
|
|
216
|
+
return 'SDO_Geometry';
|
|
217
|
+
case 'sdo_topo_geometry':
|
|
218
|
+
return 'SDO_Topo_Geometry';
|
|
219
|
+
case 'sdo_georaster':
|
|
220
|
+
return 'SDO_GeoRaster';
|
|
221
|
+
default:
|
|
222
|
+
return normalizedDataType;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function getFieldType(dataType, characterMaximumLength, numericPrecision, numericScale) {
|
|
226
|
+
const normalizedDataType = normalizeFieldType(dataType);
|
|
227
|
+
if (normalizedDataType === TIMESTAMP_WITH_LOCAL_TIME_ZONE_DATA_TYPE) {
|
|
228
|
+
if (numericScale !== null)
|
|
229
|
+
return `timestamp (${numericScale}) with local time zone`;
|
|
230
|
+
return normalizedDataType;
|
|
231
|
+
}
|
|
232
|
+
if (normalizedDataType === TIMESTAMP_WITH_TIME_ZONE_DATA_TYPE) {
|
|
233
|
+
if (numericScale !== null)
|
|
234
|
+
return `timestamp (${numericScale}) with time zone`;
|
|
235
|
+
return normalizedDataType;
|
|
236
|
+
}
|
|
237
|
+
if (normalizedDataType === TIMESTAMP_DATA_TYPE) {
|
|
238
|
+
if (numericScale !== null)
|
|
239
|
+
return `timestamp (${numericScale})`;
|
|
240
|
+
return normalizedDataType;
|
|
241
|
+
}
|
|
242
|
+
if (normalizedDataType === INTERVAL_YEAR_DATA_TYPE) {
|
|
243
|
+
if (numericPrecision !== null)
|
|
244
|
+
return `interval year (${numericPrecision}) to month`;
|
|
245
|
+
return normalizedDataType;
|
|
246
|
+
}
|
|
247
|
+
if (normalizedDataType === INTERVAL_DAY_DATA_TYPE) {
|
|
248
|
+
if (numericPrecision !== null && numericScale !== null)
|
|
249
|
+
return `interval day (${numericPrecision}) to second (${numericScale})`;
|
|
250
|
+
if (numericPrecision !== null)
|
|
251
|
+
return `interval day (${numericPrecision}) to second`;
|
|
252
|
+
if (numericScale !== null)
|
|
253
|
+
return `interval day to second (${numericScale})`;
|
|
254
|
+
return normalizedDataType;
|
|
255
|
+
}
|
|
256
|
+
if (SIZED_DATA_TYPES.has(normalizedDataType)) {
|
|
257
|
+
if (characterMaximumLength)
|
|
258
|
+
return `${normalizedDataType}(${characterMaximumLength})`;
|
|
259
|
+
return normalizedDataType;
|
|
260
|
+
}
|
|
261
|
+
if (PRECISION_DATA_TYPES.has(normalizedDataType)) {
|
|
262
|
+
if (numericPrecision !== null)
|
|
263
|
+
return `${normalizedDataType}(${numericPrecision})`;
|
|
264
|
+
return normalizedDataType;
|
|
265
|
+
}
|
|
266
|
+
if (PRECISION_SCALED_DATA_TYPES.has(normalizedDataType)) {
|
|
267
|
+
if (numericPrecision !== null && numericScale !== null)
|
|
268
|
+
return `${normalizedDataType}(${numericPrecision}, ${numericScale})`;
|
|
269
|
+
if (numericPrecision !== null)
|
|
270
|
+
return `${normalizedDataType}(${numericPrecision})`;
|
|
271
|
+
// There's no situation where numericScale is not null but numericPrecision is null
|
|
272
|
+
return normalizedDataType;
|
|
273
|
+
}
|
|
274
|
+
// This is not needed since we return `normalizedDataType` either if the condition holds true or not
|
|
275
|
+
// if (UNQUALIFIED_DATA_TYPES.has(normalizedDataType)) {
|
|
276
|
+
// return normalizedDataType;
|
|
277
|
+
// }
|
|
278
|
+
return normalizedDataType;
|
|
279
|
+
}
|
|
280
|
+
;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EXECUTE_OPTIONS = exports.LIST_SEPARATOR = void 0;
|
|
7
|
+
exports.processEasyConnectString = processEasyConnectString;
|
|
8
|
+
const oracledb_1 = __importDefault(require("oracledb"));
|
|
9
|
+
exports.LIST_SEPARATOR = '@@@@@@@@'; // Used to join multiple fields into a string field to simulate array column types
|
|
10
|
+
exports.EXECUTE_OPTIONS = { outFormat: oracledb_1.default.OUT_FORMAT_OBJECT };
|
|
11
|
+
// Expect an Easy Connect string format: username/password@[//]host[:port][/database]
|
|
12
|
+
// Explanation of the format: https://www.orafaq.com/wiki/EZCONNECT
|
|
13
|
+
function processEasyConnectString(connection) {
|
|
14
|
+
// Capturing group `username`: a string without the characters `/` `@` `:`
|
|
15
|
+
// Capturing group `password`: a string without the characters `/` `@` `:`
|
|
16
|
+
// Capturing group `dbidentifier`: a string containing the `host[:port][/database]` part
|
|
17
|
+
const matches = connection.match(/^(?<username>[^/@:]+)\/(?<password>[^/@:]+)@(\/\/)?(?<dbidentifier>.+)$/);
|
|
18
|
+
const { username, password, dbidentifier } = matches?.groups || {};
|
|
19
|
+
if (!username || !password || !dbidentifier) {
|
|
20
|
+
throw new Error('Invalid Easy Connect string. Expect a string of format \'username/password@[//]host[:port][/database]\'');
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
username,
|
|
24
|
+
password,
|
|
25
|
+
dbidentifier,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.fetchSchemaJson = void 0;
|
|
4
|
-
/* eslint-disable camelcase */
|
|
5
4
|
const pg_1 = require("pg");
|
|
6
|
-
const parseSchema_1 = require("
|
|
5
|
+
const parseSchema_1 = require("../../utils/parseSchema");
|
|
7
6
|
const getValidatedClient = async (connection) => {
|
|
8
7
|
const client = new pg_1.Client(connection);
|
|
9
8
|
try {
|
|
@@ -63,13 +62,15 @@ const getDbdefault = (data_type, column_default, default_type) => {
|
|
|
63
62
|
const generateField = (row) => {
|
|
64
63
|
const { column_name, data_type, character_maximum_length, numeric_precision, numeric_scale, udt_schema, udt_name, identity_increment, is_nullable, column_default, default_type, column_comment, } = row;
|
|
65
64
|
const dbdefault = column_default && default_type !== 'increment' ? getDbdefault(data_type, column_default, default_type) : null;
|
|
66
|
-
const fieldType = data_type === 'USER-DEFINED'
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
const fieldType = data_type === 'USER-DEFINED'
|
|
66
|
+
? {
|
|
67
|
+
type_name: udt_name,
|
|
68
|
+
schemaName: udt_schema,
|
|
69
|
+
}
|
|
70
|
+
: {
|
|
71
|
+
type_name: getFieldType(data_type, udt_name, character_maximum_length, numeric_precision, numeric_scale),
|
|
72
|
+
schemaName: null,
|
|
73
|
+
};
|
|
73
74
|
return {
|
|
74
75
|
name: column_name,
|
|
75
76
|
type: fieldType,
|
|
@@ -319,19 +320,21 @@ const generateIndexesAndConstraints = async (client, schemas) => {
|
|
|
319
320
|
return acc;
|
|
320
321
|
}, { outOfLineIndexes: [], inlineIndexes: [] });
|
|
321
322
|
const indexes = outOfLineIndexes.reduce((acc, indexRow) => {
|
|
322
|
-
const { table_schema, table_name, index_name, index_type, index_columns, index_expressions, } = indexRow;
|
|
323
|
+
const { table_schema, table_name, index_name, index_type, index_columns, index_expressions, is_primary, is_unique, } = indexRow;
|
|
323
324
|
const indexColumns = index_columns.split(',').map((column) => {
|
|
324
325
|
return {
|
|
325
326
|
type: 'column',
|
|
326
327
|
value: column.trim(),
|
|
327
328
|
};
|
|
328
329
|
});
|
|
329
|
-
const indexExpressions = index_expressions
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
330
|
+
const indexExpressions = index_expressions
|
|
331
|
+
? index_expressions.split(',').map((expression) => {
|
|
332
|
+
return {
|
|
333
|
+
type: 'expression',
|
|
334
|
+
value: expression,
|
|
335
|
+
};
|
|
336
|
+
})
|
|
337
|
+
: [];
|
|
335
338
|
const index = {
|
|
336
339
|
name: index_name,
|
|
337
340
|
type: index_type,
|
|
@@ -339,6 +342,8 @@ const generateIndexesAndConstraints = async (client, schemas) => {
|
|
|
339
342
|
...indexColumns,
|
|
340
343
|
...indexExpressions,
|
|
341
344
|
],
|
|
345
|
+
pk: !!is_primary,
|
|
346
|
+
unique: !is_primary && !!is_unique,
|
|
342
347
|
};
|
|
343
348
|
const key = `${table_schema}.${table_name}`;
|
|
344
349
|
if (acc[key]) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/* eslint-disable camelcase */
|
|
3
2
|
//
|
|
4
3
|
// Description:
|
|
5
4
|
// Snowflake info schema lacks reference direction for relationships.
|
|
@@ -13,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
13
|
exports.fetchSchemaJson = void 0;
|
|
15
14
|
const snowflake_sdk_1 = __importDefault(require("snowflake-sdk"));
|
|
16
|
-
const parseSchema_1 = require("
|
|
15
|
+
const parseSchema_1 = require("../../utils/parseSchema");
|
|
17
16
|
const parseConnectionString = (connectionString) => {
|
|
18
17
|
const params = {};
|
|
19
18
|
const regex = /([^;=]+)=([^;]*)/g;
|
|
@@ -96,4 +96,4 @@ interface BigQueryCredentials {
|
|
|
96
96
|
};
|
|
97
97
|
datasets: string[];
|
|
98
98
|
}
|
|
99
|
-
export { NoteInfo, TypeInfo, DefaultType, DefaultInfo, Field, Table, FieldsDictionary, TableConstraint, TableConstraintsDictionary, RefEndpoint, Ref, EnumValue, Enum, IndexColumn, Index, IndexesDictionary, DatabaseSchema, BigQueryCredentials, CheckConstraintDictionary, };
|
|
99
|
+
export { NoteInfo, TypeInfo, DefaultType, DefaultInfo, Field, Table, FieldsDictionary, TableConstraint, TableConstraintsDictionary, RefEndpoint, Ref, EnumValue, Enum, IndexColumn, Index, IndexesDictionary, DatabaseSchema, BigQueryCredentials, CheckConstraint, CheckConstraintDictionary, };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import * as connector from
|
|
1
|
+
import * as connector from './connectors/connector';
|
|
2
2
|
export { connector, };
|
package/dist/index.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
36
|
exports.connector = void 0;
|
|
27
37
|
const connector = __importStar(require("./connectors/connector"));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const parseSchema: (schemas: string | undefined) => string[];
|
|
1
2
|
export declare const parseJdbcSchema: (connectionString: string) => {
|
|
2
3
|
connectionString: string;
|
|
3
4
|
schemas: string[];
|
|
@@ -7,4 +8,3 @@ export declare const parseConnectionString: (connectionString: string, connectio
|
|
|
7
8
|
schemas: string[];
|
|
8
9
|
};
|
|
9
10
|
export declare const buildSchemaQuery: (columnName: string, schemas: string[], prefix?: string) => string;
|
|
10
|
-
export declare const parseSchema: (schemas: string | undefined) => string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.buildSchemaQuery = exports.parseConnectionString = exports.parseJdbcSchema = exports.parseSchema = void 0;
|
|
4
4
|
// You cannot use the "=" inside database's schema name. It will be treated as a delimiter.
|
|
5
5
|
const SCHEMAS_DELIMITER = 'schemas=';
|
|
6
6
|
const haveSchemas = (str) => {
|
|
@@ -13,6 +13,18 @@ const noSchemaResult = (connectionString) => ({
|
|
|
13
13
|
connectionString,
|
|
14
14
|
schemas: [],
|
|
15
15
|
});
|
|
16
|
+
// Inputs: schemas string -> Output: schema array string[]
|
|
17
|
+
// schema1, schema2 -> ['schema1', 'schema2']
|
|
18
|
+
// schema3,schema4 -> ['schema3", 'schema4']
|
|
19
|
+
// "schema5,gg", "schema6", schema7 -> ['schema5,gg', 'schema6', 'schema7']
|
|
20
|
+
// schema8 -> ['schema8']
|
|
21
|
+
const parseSchema = (schemas) => {
|
|
22
|
+
if (!schemas)
|
|
23
|
+
return [];
|
|
24
|
+
const schemasWithDoubleQuotes = schemas.split(/,(?=(?:[^"]*(?:"[^"]*")*)*$)/).map((s) => s.trim());
|
|
25
|
+
return schemasWithDoubleQuotes.map((s) => s.replace(/"/g, ''));
|
|
26
|
+
};
|
|
27
|
+
exports.parseSchema = parseSchema;
|
|
16
28
|
const parseOdbcSchema = (connectionString) => {
|
|
17
29
|
const connectionParts = connectionString.split(';');
|
|
18
30
|
const schemasPart = connectionParts.find((part) => haveSchemas(part));
|
|
@@ -45,15 +57,3 @@ const buildSchemaQuery = (columnName, schemas, prefix = 'AND') => {
|
|
|
45
57
|
return `${prefix} ${columnName} IN (${schemas.map((schema) => `'${schema}'`).join(', ')})`;
|
|
46
58
|
};
|
|
47
59
|
exports.buildSchemaQuery = buildSchemaQuery;
|
|
48
|
-
// Inputs: schemas string -> Output: schema array string[]
|
|
49
|
-
// schema1, schema2 -> ['schema1', 'schema2']
|
|
50
|
-
// schema3,schema4 -> ['schema3", 'schema4']
|
|
51
|
-
// "schema5,gg", "schema6", schema7 -> ['schema5,gg', 'schema6', 'schema7']
|
|
52
|
-
// schema8 -> ['schema8']
|
|
53
|
-
const parseSchema = (schemas) => {
|
|
54
|
-
if (!schemas)
|
|
55
|
-
return [];
|
|
56
|
-
const schemasWithDoubleQuotes = schemas.split(/,(?=(?:[^"]*(?:"[^"]*")*)*$)/).map((s) => s.trim());
|
|
57
|
-
return schemasWithDoubleQuotes.map((s) => s.replace(/"/g, ''));
|
|
58
|
-
};
|
|
59
|
-
exports.parseSchema = parseSchema;
|
package/eslint.config.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import eslint from '@eslint/js';
|
|
2
|
+
import { defineConfig } from 'eslint/config';
|
|
3
|
+
import tseslint from 'typescript-eslint';
|
|
4
|
+
import tsparser from '@typescript-eslint/parser';
|
|
5
|
+
import stylistic from '@stylistic/eslint-plugin';
|
|
6
|
+
|
|
7
|
+
export default defineConfig(
|
|
8
|
+
eslint.configs.recommended,
|
|
9
|
+
tseslint.configs.recommended,
|
|
10
|
+
stylistic.configs.customize({
|
|
11
|
+
indent: 2,
|
|
12
|
+
semi: true,
|
|
13
|
+
arrowParens: true,
|
|
14
|
+
braceStyle: '1tbs',
|
|
15
|
+
}),
|
|
16
|
+
[
|
|
17
|
+
{
|
|
18
|
+
ignores: [
|
|
19
|
+
'node_modules/*',
|
|
20
|
+
'dist/*',
|
|
21
|
+
'eslint.config.ts',
|
|
22
|
+
'jestHelpers.ts',
|
|
23
|
+
'jest.config.ts',
|
|
24
|
+
'**/*.test.ts',
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
files: ['**/*.ts'],
|
|
29
|
+
languageOptions: {
|
|
30
|
+
parser: tsparser,
|
|
31
|
+
parserOptions: {
|
|
32
|
+
sourceType: 'module',
|
|
33
|
+
ecmaVersion: 2020,
|
|
34
|
+
project: './tsconfig.json',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
plugins: {
|
|
38
|
+
'@stylistic': stylistic,
|
|
39
|
+
},
|
|
40
|
+
rules: {
|
|
41
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
42
|
+
'no-use-before-define': 'off',
|
|
43
|
+
'no-continue': 'off',
|
|
44
|
+
'no-useless-escape': 'warn',
|
|
45
|
+
'@stylistic/space-before-function-paren': ['error', 'always'],
|
|
46
|
+
'@typescript-eslint/no-unused-vars': [
|
|
47
|
+
'warn',
|
|
48
|
+
{
|
|
49
|
+
argsIgnorePattern: '^_',
|
|
50
|
+
varsIgnorePattern: '^_',
|
|
51
|
+
caughtErrorsIgnorePattern: '^_',
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
'consistent-return': 'off',
|
|
55
|
+
'@typescript-eslint/consistent-return': ['error'],
|
|
56
|
+
'@stylistic/quotes': ['error', 'single', { 'avoidEscape': true }],
|
|
57
|
+
'@stylistic/max-statements-per-line': 'off',
|
|
58
|
+
'@stylistic/operator-linebreak': ['error', 'before', { overrides: { '=': 'after' } }],
|
|
59
|
+
},
|
|
60
|
+
settings: {
|
|
61
|
+
'import/resolver': {
|
|
62
|
+
typescript: {
|
|
63
|
+
alwaysTryTypes: true,
|
|
64
|
+
project: 'packages/*/{ts,js}config.json',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
);
|
package/jest.config.ts
CHANGED
|
@@ -2,9 +2,9 @@ module.exports = {
|
|
|
2
2
|
preset: 'ts-jest',
|
|
3
3
|
testEnvironment: 'node',
|
|
4
4
|
transform: {
|
|
5
|
-
|
|
5
|
+
'^.+\\.[tj]sx?$': 'babel-jest',
|
|
6
6
|
},
|
|
7
7
|
moduleNameMapper: {
|
|
8
|
-
|
|
8
|
+
'\\.(css|less|scss)$': 'identity-obj-proxy',
|
|
9
9
|
},
|
|
10
10
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package",
|
|
2
3
|
"name": "@dbml/connector",
|
|
3
|
-
"version": "5.
|
|
4
|
+
"version": "5.3.0",
|
|
4
5
|
"description": "This package was created to fetch the schema JSON from many kind of databases.",
|
|
5
6
|
"author": "huy.phung.sw@gmail.com",
|
|
6
7
|
"license": "MIT",
|
|
@@ -15,34 +16,44 @@
|
|
|
15
16
|
"@babel/preset-env": "^7.21.4",
|
|
16
17
|
"@babel/preset-typescript": "^7.24.7",
|
|
17
18
|
"@babel/runtime": "^7.21.0",
|
|
19
|
+
"@stylistic/eslint-plugin": "^5.5.0",
|
|
18
20
|
"@types/jest": "^29.5.12",
|
|
19
21
|
"@types/lodash": "^4.17.16",
|
|
20
22
|
"@types/mssql": "^9.1.5",
|
|
21
23
|
"@types/node": "^22.2.0",
|
|
24
|
+
"@types/oracledb": "^6.10.0",
|
|
22
25
|
"@types/pg": "^8.11.6",
|
|
26
|
+
"@typescript-eslint/eslint-plugin": "^8.46.3",
|
|
27
|
+
"@typescript-eslint/parser": "^8.46.3",
|
|
23
28
|
"babel-jest": "^29.5.0",
|
|
29
|
+
"eslint": "^9.39.1",
|
|
24
30
|
"jest": "^29.7.0",
|
|
25
31
|
"ts-jest": "^29.2.4",
|
|
26
32
|
"ts-node": "^10.9.2",
|
|
27
|
-
"typescript": "^5.
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"typescript-eslint": "^8.46.3"
|
|
28
35
|
},
|
|
29
36
|
"scripts": {
|
|
30
37
|
"build": "tsc",
|
|
31
38
|
"start": "node dist/index.js",
|
|
32
|
-
"test": "jest"
|
|
39
|
+
"test": "jest",
|
|
40
|
+
"lint": "eslint .",
|
|
41
|
+
"lint:fix": "eslint --fix ."
|
|
33
42
|
},
|
|
34
43
|
"dependencies": {
|
|
35
44
|
"@google-cloud/bigquery": "^7.9.0",
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
37
|
-
"@typescript-eslint/parser": "^8.
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^8.46.3",
|
|
46
|
+
"@typescript-eslint/parser": "^8.46.3",
|
|
47
|
+
"eslint": "^9.39.1",
|
|
38
48
|
"lodash": "^4.17.21",
|
|
39
49
|
"mssql": "^11.0.1",
|
|
40
50
|
"mysql2": "^3.11.0",
|
|
51
|
+
"oracledb": "^6.10.0",
|
|
41
52
|
"pg": "^8.12.0",
|
|
42
53
|
"snowflake-sdk": "^2.0.3"
|
|
43
54
|
},
|
|
44
55
|
"engines": {
|
|
45
56
|
"node": ">=18"
|
|
46
57
|
},
|
|
47
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "c8e67b627584b81d18c16a6f2983a92d75a326d9"
|
|
48
59
|
}
|