@dbml/connector 3.7.4 → 3.8.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.
- package/__tests__/connector.test.ts +2 -2
- package/__tests__/connectors/postgres/expect-out-files/schema.json +208 -0
- package/dist/connectors/bigqueryConnector.d.ts +3 -0
- package/dist/connectors/bigqueryConnector.js +276 -0
- package/dist/connectors/connector.d.ts +1 -1
- package/dist/connectors/connector.js +9 -3
- package/dist/connectors/mssqlConnector.d.ts +1 -1
- package/dist/connectors/mssqlConnector.js +100 -70
- package/dist/connectors/postgresConnector.d.ts +1 -1
- package/dist/connectors/postgresConnector.js +28 -20
- package/dist/connectors/snowflakeConnector.d.ts +3 -0
- package/dist/connectors/snowflakeConnector.js +292 -0
- package/dist/connectors/types.d.ts +11 -1
- package/dist/utils/credential-loader.d.ts +3 -0
- package/dist/utils/credential-loader.js +53 -0
- package/dist/utils/helpers.d.ts +7 -0
- package/dist/utils/helpers.js +50 -0
- package/dist/utils/parseSchema.d.ts +10 -0
- package/dist/utils/parseSchema.js +59 -0
- package/package.json +5 -3
- package/src/connectors/bigqueryConnector.ts +389 -0
- package/src/connectors/connector.ts +9 -3
- package/src/connectors/mssqlConnector.ts +107 -77
- package/src/connectors/postgresConnector.ts +29 -21
- package/src/connectors/snowflakeConnector.ts +370 -0
- package/src/connectors/types.ts +12 -0
- package/src/ddl_samples/bigquery.sql +71 -0
- package/src/ddl_samples/snowflake.sql +131 -0
- package/src/utils/credential-loader.ts +64 -0
- package/src/utils/helpers.ts +73 -0
- package/src/utils/parseSchema.ts +60 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
1
|
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
3
|
import { scanDirNames } from '../jestHelpers.ts';
|
|
4
4
|
import { connector } from '../src/index.ts';
|
|
5
5
|
|
|
6
6
|
describe('@dbml/connector', () => {
|
|
7
|
-
const runTest = async (dirName) => {
|
|
7
|
+
const runTest = async (dirName: string) => {
|
|
8
8
|
process.chdir(dirName);
|
|
9
9
|
|
|
10
10
|
const connectionRaw = fs.readFileSync(path.join(dirName, './connection.json'), 'utf-8');
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"tables": [
|
|
3
|
+
{
|
|
4
|
+
"name": "table1",
|
|
5
|
+
"schemaName": "dbml_test",
|
|
6
|
+
"note": {
|
|
7
|
+
"value": ""
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "table3",
|
|
12
|
+
"schemaName": "dbml_test",
|
|
13
|
+
"note": {
|
|
14
|
+
"value": ""
|
|
15
|
+
}
|
|
16
|
+
},
|
|
3
17
|
{
|
|
4
18
|
"name": "all_default_values",
|
|
5
19
|
"schemaName": "public",
|
|
@@ -49,6 +63,20 @@
|
|
|
49
63
|
"value": ""
|
|
50
64
|
}
|
|
51
65
|
},
|
|
66
|
+
{
|
|
67
|
+
"name": "table1",
|
|
68
|
+
"schemaName": "public",
|
|
69
|
+
"note": {
|
|
70
|
+
"value": ""
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "table2",
|
|
75
|
+
"schemaName": "public",
|
|
76
|
+
"note": {
|
|
77
|
+
"value": ""
|
|
78
|
+
}
|
|
79
|
+
},
|
|
52
80
|
{
|
|
53
81
|
"name": "table_with_comments",
|
|
54
82
|
"schemaName": "public",
|
|
@@ -72,6 +100,62 @@
|
|
|
72
100
|
}
|
|
73
101
|
],
|
|
74
102
|
"fields": {
|
|
103
|
+
"dbml_test.table1": [
|
|
104
|
+
{
|
|
105
|
+
"name": "id",
|
|
106
|
+
"type": {
|
|
107
|
+
"type_name": "int4",
|
|
108
|
+
"schemaName": null
|
|
109
|
+
},
|
|
110
|
+
"dbdefault": null,
|
|
111
|
+
"not_null": true,
|
|
112
|
+
"increment": true,
|
|
113
|
+
"note": {
|
|
114
|
+
"value": ""
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"name": "status",
|
|
119
|
+
"type": {
|
|
120
|
+
"type_name": "enum_type1",
|
|
121
|
+
"schemaName": "dbml_test"
|
|
122
|
+
},
|
|
123
|
+
"dbdefault": null,
|
|
124
|
+
"not_null": false,
|
|
125
|
+
"increment": false,
|
|
126
|
+
"note": {
|
|
127
|
+
"value": ""
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
"dbml_test.table3": [
|
|
132
|
+
{
|
|
133
|
+
"name": "id",
|
|
134
|
+
"type": {
|
|
135
|
+
"type_name": "int4",
|
|
136
|
+
"schemaName": null
|
|
137
|
+
},
|
|
138
|
+
"dbdefault": null,
|
|
139
|
+
"not_null": true,
|
|
140
|
+
"increment": true,
|
|
141
|
+
"note": {
|
|
142
|
+
"value": ""
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"name": "status",
|
|
147
|
+
"type": {
|
|
148
|
+
"type_name": "enum_type3",
|
|
149
|
+
"schemaName": "dbml_test"
|
|
150
|
+
},
|
|
151
|
+
"dbdefault": null,
|
|
152
|
+
"not_null": false,
|
|
153
|
+
"increment": false,
|
|
154
|
+
"note": {
|
|
155
|
+
"value": ""
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
],
|
|
75
159
|
"public.all_default_values": [
|
|
76
160
|
{
|
|
77
161
|
"name": "id",
|
|
@@ -843,6 +927,62 @@
|
|
|
843
927
|
}
|
|
844
928
|
}
|
|
845
929
|
],
|
|
930
|
+
"public.table1": [
|
|
931
|
+
{
|
|
932
|
+
"name": "id",
|
|
933
|
+
"type": {
|
|
934
|
+
"type_name": "int4",
|
|
935
|
+
"schemaName": null
|
|
936
|
+
},
|
|
937
|
+
"dbdefault": null,
|
|
938
|
+
"not_null": true,
|
|
939
|
+
"increment": true,
|
|
940
|
+
"note": {
|
|
941
|
+
"value": ""
|
|
942
|
+
}
|
|
943
|
+
},
|
|
944
|
+
{
|
|
945
|
+
"name": "status",
|
|
946
|
+
"type": {
|
|
947
|
+
"type_name": "enum_type1",
|
|
948
|
+
"schemaName": "public"
|
|
949
|
+
},
|
|
950
|
+
"dbdefault": null,
|
|
951
|
+
"not_null": false,
|
|
952
|
+
"increment": false,
|
|
953
|
+
"note": {
|
|
954
|
+
"value": ""
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
],
|
|
958
|
+
"public.table2": [
|
|
959
|
+
{
|
|
960
|
+
"name": "id",
|
|
961
|
+
"type": {
|
|
962
|
+
"type_name": "int4",
|
|
963
|
+
"schemaName": null
|
|
964
|
+
},
|
|
965
|
+
"dbdefault": null,
|
|
966
|
+
"not_null": true,
|
|
967
|
+
"increment": true,
|
|
968
|
+
"note": {
|
|
969
|
+
"value": ""
|
|
970
|
+
}
|
|
971
|
+
},
|
|
972
|
+
{
|
|
973
|
+
"name": "status",
|
|
974
|
+
"type": {
|
|
975
|
+
"type_name": "enum_type2",
|
|
976
|
+
"schemaName": "public"
|
|
977
|
+
},
|
|
978
|
+
"dbdefault": null,
|
|
979
|
+
"not_null": false,
|
|
980
|
+
"increment": false,
|
|
981
|
+
"note": {
|
|
982
|
+
"value": ""
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
],
|
|
846
986
|
"public.table_with_comments": [
|
|
847
987
|
{
|
|
848
988
|
"name": "id",
|
|
@@ -1229,6 +1369,54 @@
|
|
|
1229
1369
|
}
|
|
1230
1370
|
],
|
|
1231
1371
|
"enums": [
|
|
1372
|
+
{
|
|
1373
|
+
"name": "enum_type1",
|
|
1374
|
+
"schemaName": "dbml_test",
|
|
1375
|
+
"values": [
|
|
1376
|
+
{
|
|
1377
|
+
"name": "value1"
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
"name": "value2"
|
|
1381
|
+
}
|
|
1382
|
+
]
|
|
1383
|
+
},
|
|
1384
|
+
{
|
|
1385
|
+
"name": "enum_type3",
|
|
1386
|
+
"schemaName": "dbml_test",
|
|
1387
|
+
"values": [
|
|
1388
|
+
{
|
|
1389
|
+
"name": "value4"
|
|
1390
|
+
},
|
|
1391
|
+
{
|
|
1392
|
+
"name": "value5"
|
|
1393
|
+
}
|
|
1394
|
+
]
|
|
1395
|
+
},
|
|
1396
|
+
{
|
|
1397
|
+
"name": "enum_type1",
|
|
1398
|
+
"schemaName": "public",
|
|
1399
|
+
"values": [
|
|
1400
|
+
{
|
|
1401
|
+
"name": "value1"
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
"name": "value2"
|
|
1405
|
+
}
|
|
1406
|
+
]
|
|
1407
|
+
},
|
|
1408
|
+
{
|
|
1409
|
+
"name": "enum_type2",
|
|
1410
|
+
"schemaName": "public",
|
|
1411
|
+
"values": [
|
|
1412
|
+
{
|
|
1413
|
+
"name": "value1"
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
"name": "value3"
|
|
1417
|
+
}
|
|
1418
|
+
]
|
|
1419
|
+
},
|
|
1232
1420
|
{
|
|
1233
1421
|
"name": "gender_type",
|
|
1234
1422
|
"schemaName": "public",
|
|
@@ -1386,6 +1574,26 @@
|
|
|
1386
1574
|
"pk": true
|
|
1387
1575
|
}
|
|
1388
1576
|
},
|
|
1577
|
+
"public.table1": {
|
|
1578
|
+
"id": {
|
|
1579
|
+
"pk": true
|
|
1580
|
+
}
|
|
1581
|
+
},
|
|
1582
|
+
"dbml_test.table1": {
|
|
1583
|
+
"id": {
|
|
1584
|
+
"pk": true
|
|
1585
|
+
}
|
|
1586
|
+
},
|
|
1587
|
+
"public.table2": {
|
|
1588
|
+
"id": {
|
|
1589
|
+
"pk": true
|
|
1590
|
+
}
|
|
1591
|
+
},
|
|
1592
|
+
"dbml_test.table3": {
|
|
1593
|
+
"id": {
|
|
1594
|
+
"pk": true
|
|
1595
|
+
}
|
|
1596
|
+
},
|
|
1389
1597
|
"public.table_with_comments": {
|
|
1390
1598
|
"id": {
|
|
1391
1599
|
"pk": true
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchSchemaJson = fetchSchemaJson;
|
|
4
|
+
const bigquery_1 = require("@google-cloud/bigquery");
|
|
5
|
+
const credential_loader_1 = require("../utils/credential-loader");
|
|
6
|
+
const helpers_1 = require("../utils/helpers");
|
|
7
|
+
async function connectBigQuery(credential) {
|
|
8
|
+
const client = new bigquery_1.BigQuery({
|
|
9
|
+
projectId: credential.projectId,
|
|
10
|
+
credentials: {
|
|
11
|
+
private_key: credential.credentials.privateKey,
|
|
12
|
+
client_email: credential.credentials.clientEmail,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
try {
|
|
16
|
+
const query = `SELECT CURRENT_DATE() as today`;
|
|
17
|
+
await client.query(query);
|
|
18
|
+
return client;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error instanceof Error) {
|
|
22
|
+
throw new Error(`BigQuery connection error: ${error.message}`);
|
|
23
|
+
}
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function getDbDefault(columnDefault, defaultValueType) {
|
|
28
|
+
if (defaultValueType === null) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
if (defaultValueType === 'string') {
|
|
32
|
+
// bigquery store the double qoutes and quotes at the end and the beginning of the string: "string" or 'string'
|
|
33
|
+
return { value: columnDefault.slice(1, -1).replaceAll("'", "\'"), type: defaultValueType };
|
|
34
|
+
}
|
|
35
|
+
return { value: columnDefault, type: defaultValueType };
|
|
36
|
+
}
|
|
37
|
+
function generateField(row) {
|
|
38
|
+
const { columnName, isNullable, dataType, columnDefault, columnDefaultType, columnDescription, } = row;
|
|
39
|
+
const fieldDefaultValue = getDbDefault(columnDefault, columnDefaultType);
|
|
40
|
+
const field = {
|
|
41
|
+
name: columnName,
|
|
42
|
+
not_null: isNullable === 'NO',
|
|
43
|
+
type: {
|
|
44
|
+
type_name: dataType,
|
|
45
|
+
schemaName: null,
|
|
46
|
+
},
|
|
47
|
+
note: {
|
|
48
|
+
value: columnDescription || '',
|
|
49
|
+
},
|
|
50
|
+
dbdefault: fieldDefaultValue,
|
|
51
|
+
increment: false, // bigquery does not support native auto-increment
|
|
52
|
+
};
|
|
53
|
+
return field;
|
|
54
|
+
}
|
|
55
|
+
async function generateTablesAndFields(client, projectId, datasetId) {
|
|
56
|
+
const tableName = `${projectId}.${datasetId}`;
|
|
57
|
+
const query = `
|
|
58
|
+
with
|
|
59
|
+
table_comments as (
|
|
60
|
+
select table_schema, table_name, option_value as description
|
|
61
|
+
from ${tableName}.INFORMATION_SCHEMA.TABLE_OPTIONS
|
|
62
|
+
where option_name = 'description'
|
|
63
|
+
),
|
|
64
|
+
column_comments as (
|
|
65
|
+
select column_name, table_schema, table_name, description
|
|
66
|
+
from ${tableName}.INFORMATION_SCHEMA.COLUMN_FIELD_PATHS
|
|
67
|
+
where column_name = field_path
|
|
68
|
+
)
|
|
69
|
+
select
|
|
70
|
+
t.table_schema as tableSchema,
|
|
71
|
+
t.table_name as tableName,
|
|
72
|
+
(select description from table_comments tc where tc.table_name = t.table_name and tc.table_schema = t.table_schema) as tableDescription,
|
|
73
|
+
(
|
|
74
|
+
select description
|
|
75
|
+
from column_comments cc
|
|
76
|
+
where cc.table_name = c.table_name and cc.table_schema = c.table_schema and cc.column_name = c.column_name
|
|
77
|
+
) as columnDescription,
|
|
78
|
+
c.column_name as columnName,
|
|
79
|
+
c.is_nullable as isNullable,
|
|
80
|
+
c.data_type as dataType,
|
|
81
|
+
c.column_default as columnDefault,
|
|
82
|
+
CASE
|
|
83
|
+
WHEN SAFE_CAST(c.column_default AS FLOAT64) IS NOT NULL THEN 'number'
|
|
84
|
+
WHEN SAFE_CAST(c.column_default AS BOOLEAN) IS NOT NULL THEN 'boolean'
|
|
85
|
+
-- string value is enclosed in single quotes, double quotes
|
|
86
|
+
WHEN REGEXP_CONTAINS(c.column_default, r"^['\\"].*['\\"]$") THEN 'string'
|
|
87
|
+
WHEN c.column_default = "NULL" THEN NULL
|
|
88
|
+
ELSE 'expression'
|
|
89
|
+
END AS columnDefaultType
|
|
90
|
+
from ${tableName}.INFORMATION_SCHEMA.TABLES t
|
|
91
|
+
join ${tableName}.INFORMATION_SCHEMA.COLUMNS c
|
|
92
|
+
on
|
|
93
|
+
t.table_schema = c.table_schema
|
|
94
|
+
and t.table_name = c.table_name
|
|
95
|
+
where t.table_type = 'BASE TABLE'
|
|
96
|
+
order by t.table_name, c.ordinal_position;
|
|
97
|
+
`;
|
|
98
|
+
const [queryResult] = await client.query({
|
|
99
|
+
query,
|
|
100
|
+
params: {
|
|
101
|
+
// stringRegex: STRING_REGEX,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
const tableMap = {};
|
|
105
|
+
const fieldMap = {};
|
|
106
|
+
queryResult.forEach((row) => {
|
|
107
|
+
const { tableSchema, tableName, tableComment } = row;
|
|
108
|
+
const key = (0, helpers_1.getTableSchemaKey)(tableSchema, tableName);
|
|
109
|
+
if (!tableMap[key]) {
|
|
110
|
+
tableMap[key] = {
|
|
111
|
+
name: tableName,
|
|
112
|
+
note: { value: tableComment || '' },
|
|
113
|
+
schemaName: tableSchema,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (!fieldMap[key]) {
|
|
117
|
+
fieldMap[key] = [];
|
|
118
|
+
}
|
|
119
|
+
const field = generateField(row);
|
|
120
|
+
fieldMap[key].push(field);
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
tables: Object.values(tableMap),
|
|
124
|
+
fieldMap,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function generateIndexes(client, projectId, datasetId) {
|
|
128
|
+
const tableName = `${projectId}.${datasetId}`;
|
|
129
|
+
const query = `
|
|
130
|
+
select
|
|
131
|
+
s.index_schema as indexSchema,
|
|
132
|
+
s.table_name as tableName,
|
|
133
|
+
s.index_name as indexName,
|
|
134
|
+
string_agg(sc.index_column_name, ', ') as indexColumnNames
|
|
135
|
+
from ${tableName}.INFORMATION_SCHEMA.SEARCH_INDEXES s
|
|
136
|
+
join ${tableName}.INFORMATION_SCHEMA.SEARCH_INDEX_COLUMNS sc
|
|
137
|
+
on
|
|
138
|
+
s.index_schema = sc.index_schema
|
|
139
|
+
and s.table_name = sc.table_name
|
|
140
|
+
and s.index_name = sc.index_name
|
|
141
|
+
where sc.index_column_name = sc.index_field_path
|
|
142
|
+
group by s.index_schema, s.table_name, s.index_name
|
|
143
|
+
order by s.table_name, s.index_name;
|
|
144
|
+
`;
|
|
145
|
+
const [queryResult] = await client.query(query);
|
|
146
|
+
const indexMap = {};
|
|
147
|
+
queryResult.forEach((row) => {
|
|
148
|
+
const { indexSchema, tableName, indexName, indexColumnNames } = row;
|
|
149
|
+
const indexColumns = indexColumnNames.split(', ').map((column) => {
|
|
150
|
+
return {
|
|
151
|
+
type: 'column',
|
|
152
|
+
value: column,
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
const index = {
|
|
156
|
+
name: indexName,
|
|
157
|
+
type: '',
|
|
158
|
+
columns: [...indexColumns],
|
|
159
|
+
};
|
|
160
|
+
const key = (0, helpers_1.getTableSchemaKey)(indexSchema, tableName);
|
|
161
|
+
if (indexMap[key]) {
|
|
162
|
+
indexMap[key].push(index);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
indexMap[key] = [index];
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return indexMap;
|
|
169
|
+
}
|
|
170
|
+
async function generateTableConstraints(client, projectId, datasetId) {
|
|
171
|
+
const tableName = `${projectId}.${datasetId}`;
|
|
172
|
+
const query = `
|
|
173
|
+
select
|
|
174
|
+
tc.table_schema as tableSchema,
|
|
175
|
+
tc.table_name as tableName,
|
|
176
|
+
tc.constraint_name as constraintName,
|
|
177
|
+
string_agg(kcu.column_name, ', ') as columnNames,
|
|
178
|
+
count(kcu.column_name) as columnCount,
|
|
179
|
+
from ${tableName}.INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
|
|
180
|
+
join ${tableName}.INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
|
|
181
|
+
on
|
|
182
|
+
tc.table_schema = kcu.table_schema
|
|
183
|
+
and tc.table_name = kcu.table_name
|
|
184
|
+
and tc.constraint_name = kcu.constraint_name
|
|
185
|
+
where tc.constraint_type = 'PRIMARY KEY'
|
|
186
|
+
group by tc.table_schema, tc.table_name, tc.constraint_name
|
|
187
|
+
order by tc.table_name, tc.constraint_name;
|
|
188
|
+
`;
|
|
189
|
+
const [queryResult] = await client.query(query);
|
|
190
|
+
const inlinePrimaryKeyList = queryResult.filter((row) => row.columnCount && row.columnCount === 1);
|
|
191
|
+
const compositePrimaryKeyList = queryResult.filter((row) => row.columnCount && row.columnCount > 1);
|
|
192
|
+
const inlinePrimaryKeyMap = {};
|
|
193
|
+
inlinePrimaryKeyList.forEach((inlineKey) => {
|
|
194
|
+
const { tableSchema, tableName, columnNames } = inlineKey;
|
|
195
|
+
const key = (0, helpers_1.getTableSchemaKey)(tableSchema, tableName);
|
|
196
|
+
if (!inlinePrimaryKeyMap[key]) {
|
|
197
|
+
inlinePrimaryKeyMap[key] = {};
|
|
198
|
+
}
|
|
199
|
+
if (!inlinePrimaryKeyMap[key][columnNames]) {
|
|
200
|
+
inlinePrimaryKeyMap[key][columnNames] = {};
|
|
201
|
+
}
|
|
202
|
+
inlinePrimaryKeyMap[key][columnNames].pk = true;
|
|
203
|
+
});
|
|
204
|
+
const compositePrimaryKeyMap = {};
|
|
205
|
+
compositePrimaryKeyList.forEach((compositeKey) => {
|
|
206
|
+
const { tableSchema, tableName, constraintName, columnNames } = compositeKey;
|
|
207
|
+
const indexColumns = columnNames.split(', ').map((column) => {
|
|
208
|
+
return {
|
|
209
|
+
type: 'column',
|
|
210
|
+
value: column,
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
const index = {
|
|
214
|
+
name: constraintName,
|
|
215
|
+
type: '',
|
|
216
|
+
columns: [...indexColumns],
|
|
217
|
+
pk: true,
|
|
218
|
+
};
|
|
219
|
+
const key = (0, helpers_1.getTableSchemaKey)(tableSchema, tableName);
|
|
220
|
+
if (compositePrimaryKeyMap[key]) {
|
|
221
|
+
compositePrimaryKeyMap[key].push(index);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
compositePrimaryKeyMap[key] = [index];
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
return {
|
|
228
|
+
inlinePrimaryKeyMap,
|
|
229
|
+
compositePrimaryKeyMap,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
async function validateDatasetIdList(client, datasetIdList) {
|
|
233
|
+
const [datasets] = await client.getDatasets();
|
|
234
|
+
const rawDatasetIdList = datasets.map((dataset) => dataset.id).filter((id) => id);
|
|
235
|
+
// If user does not specify which datasets to be fetched, we will fetch all datasets
|
|
236
|
+
if (datasetIdList.length === 0) {
|
|
237
|
+
return rawDatasetIdList;
|
|
238
|
+
}
|
|
239
|
+
return (0, helpers_1.getIntersection)(datasetIdList, rawDatasetIdList);
|
|
240
|
+
}
|
|
241
|
+
async function fetchSchemaJsonByDataset(client, projectId, datasetId) {
|
|
242
|
+
const res = await Promise.all([
|
|
243
|
+
generateTablesAndFields(client, projectId, datasetId),
|
|
244
|
+
generateIndexes(client, projectId, datasetId),
|
|
245
|
+
generateTableConstraints(client, projectId, datasetId),
|
|
246
|
+
]);
|
|
247
|
+
const { tables, fieldMap } = res[0];
|
|
248
|
+
const indexMap = res[1];
|
|
249
|
+
const { inlinePrimaryKeyMap, compositePrimaryKeyMap } = res[2];
|
|
250
|
+
return {
|
|
251
|
+
tables,
|
|
252
|
+
fields: fieldMap,
|
|
253
|
+
refs: [],
|
|
254
|
+
enums: [],
|
|
255
|
+
indexes: (0, helpers_1.mergeIndexDictionary)(indexMap, compositePrimaryKeyMap),
|
|
256
|
+
tableConstraints: inlinePrimaryKeyMap,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
async function fetchSchemaJson(keyFilename) {
|
|
260
|
+
const rawCredential = await (0, credential_loader_1.loadCredentialFromFile)(keyFilename);
|
|
261
|
+
const credentialJson = (0, credential_loader_1.parseBigQueryCredential)(rawCredential);
|
|
262
|
+
const client = await connectBigQuery(credentialJson);
|
|
263
|
+
const projectId = await client.getProjectId();
|
|
264
|
+
const datasetIdList = await validateDatasetIdList(client, credentialJson.datasets);
|
|
265
|
+
const querySchemaPromises = datasetIdList.map((dataset) => fetchSchemaJsonByDataset(client, projectId, dataset));
|
|
266
|
+
const databaseSchemaRes = await Promise.all(querySchemaPromises);
|
|
267
|
+
const res = databaseSchemaRes.reduce((acc, dbSchema) => {
|
|
268
|
+
const { tables, fields, indexes, tableConstraints } = dbSchema;
|
|
269
|
+
acc.tables = (0, helpers_1.mergeTables)(acc.tables, tables);
|
|
270
|
+
acc.fields = (0, helpers_1.mergeFieldDictionary)(acc.fields, fields);
|
|
271
|
+
acc.indexes = (0, helpers_1.mergeIndexDictionary)(acc.indexes, indexes);
|
|
272
|
+
acc.tableConstraints = (0, helpers_1.mergeTableConstraintDictionary)(acc.tableConstraints, tableConstraints);
|
|
273
|
+
return acc;
|
|
274
|
+
}, { tables: [], fields: {}, tableConstraints: {}, indexes: {}, refs: [], enums: [] });
|
|
275
|
+
return res;
|
|
276
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { DatabaseSchema } from './types';
|
|
2
|
-
declare const fetchSchemaJson: (connection: string,
|
|
2
|
+
declare const fetchSchemaJson: (connection: string, databaseType: string) => Promise<DatabaseSchema>;
|
|
3
3
|
export { fetchSchemaJson, };
|
|
@@ -4,16 +4,22 @@ exports.fetchSchemaJson = void 0;
|
|
|
4
4
|
const postgresConnector_1 = require("./postgresConnector");
|
|
5
5
|
const mssqlConnector_1 = require("./mssqlConnector");
|
|
6
6
|
const mysqlConnector_1 = require("./mysqlConnector");
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const snowflakeConnector_1 = require("./snowflakeConnector");
|
|
8
|
+
const bigqueryConnector_1 = require("./bigqueryConnector");
|
|
9
|
+
const fetchSchemaJson = async (connection, databaseType) => {
|
|
10
|
+
switch (databaseType) {
|
|
9
11
|
case 'postgres':
|
|
10
12
|
return (0, postgresConnector_1.fetchSchemaJson)(connection);
|
|
11
13
|
case 'mssql':
|
|
12
14
|
return (0, mssqlConnector_1.fetchSchemaJson)(connection);
|
|
13
15
|
case 'mysql':
|
|
14
16
|
return (0, mysqlConnector_1.fetchSchemaJson)(connection);
|
|
17
|
+
case 'snowflake':
|
|
18
|
+
return (0, snowflakeConnector_1.fetchSchemaJson)(connection);
|
|
19
|
+
case 'bigquery':
|
|
20
|
+
return (0, bigqueryConnector_1.fetchSchemaJson)(connection);
|
|
15
21
|
default:
|
|
16
|
-
throw new Error(`Unsupported
|
|
22
|
+
throw new Error(`Unsupported database type: ${databaseType}`);
|
|
17
23
|
}
|
|
18
24
|
};
|
|
19
25
|
exports.fetchSchemaJson = fetchSchemaJson;
|