@dbml/connector 11.0.0-alpha.2 → 11.0.0-alpha.4
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 +73 -0
- package/dist/index.js +52 -33
- package/dist/index.mjs +52 -33
- package/package.json +2 -2
- package/src/connectors/oracle/tables.ts +1 -1
- package/src/connectors/postgres/index.ts +54 -33
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { Client } from 'pg';
|
|
3
4
|
import { scanDirNames } from './testHelpers';
|
|
4
5
|
import { connector } from '../src/index';
|
|
5
6
|
|
|
@@ -44,4 +45,76 @@ describe('@dbml/connector', () => {
|
|
|
44
45
|
test.each(scanDirNames(__dirname, 'connectors'))('connectors/%s', async (dirName) => {
|
|
45
46
|
await runTest(path.join(__dirname, 'connectors', dirName));
|
|
46
47
|
}, 10000);
|
|
48
|
+
|
|
49
|
+
test('postgres preserves composite foreign key column order', async () => {
|
|
50
|
+
const testDir = path.join(__dirname, 'connectors', 'postgres');
|
|
51
|
+
const { connection } = JSON.parse(fs.readFileSync(path.join(testDir, 'connection.json'), 'utf-8'));
|
|
52
|
+
const schema = `dbml_fk_order_${Math.random().toString(16).slice(2)}`;
|
|
53
|
+
const client = new Client({ connectionString: connection });
|
|
54
|
+
|
|
55
|
+
await client.connect();
|
|
56
|
+
try {
|
|
57
|
+
await client.query(`CREATE SCHEMA "${schema}"`);
|
|
58
|
+
await client.query(`
|
|
59
|
+
CREATE TABLE "${schema}".parent (
|
|
60
|
+
zeta integer NOT NULL,
|
|
61
|
+
alpha integer NOT NULL,
|
|
62
|
+
PRIMARY KEY (zeta, alpha)
|
|
63
|
+
);
|
|
64
|
+
CREATE TABLE "${schema}".child (
|
|
65
|
+
id integer PRIMARY KEY,
|
|
66
|
+
a_zeta integer,
|
|
67
|
+
z_alpha integer,
|
|
68
|
+
CONSTRAINT child_parent_fk FOREIGN KEY (a_zeta, z_alpha)
|
|
69
|
+
REFERENCES "${schema}".parent (zeta, alpha)
|
|
70
|
+
);
|
|
71
|
+
`);
|
|
72
|
+
|
|
73
|
+
const schemaJson = await connector.fetchSchemaJson(`${connection}?schemas=${schema}`, 'postgres');
|
|
74
|
+
const ref = schemaJson.refs.find(({ name }) => name === 'child_parent_fk');
|
|
75
|
+
|
|
76
|
+
expect(ref?.endpoints[0].fieldNames).toEqual(['a_zeta', 'z_alpha']);
|
|
77
|
+
expect(ref?.endpoints[1].fieldNames).toEqual(['zeta', 'alpha']);
|
|
78
|
+
} finally {
|
|
79
|
+
await client.query(`DROP SCHEMA IF EXISTS "${schema}" CASCADE`);
|
|
80
|
+
await client.end();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('postgres keeps array column defaults that are not an ARRAY[...] list', async () => {
|
|
85
|
+
const testDir = path.join(__dirname, 'connectors', 'postgres');
|
|
86
|
+
const { connection } = JSON.parse(fs.readFileSync(path.join(testDir, 'connection.json'), 'utf-8'));
|
|
87
|
+
const schema = `dbml_array_default_${Math.random().toString(16).slice(2)}`;
|
|
88
|
+
const client = new Client({ connectionString: connection });
|
|
89
|
+
|
|
90
|
+
await client.connect();
|
|
91
|
+
try {
|
|
92
|
+
await client.query(`CREATE SCHEMA "${schema}"`);
|
|
93
|
+
await client.query(`
|
|
94
|
+
CREATE TABLE "${schema}".t (
|
|
95
|
+
literal_col varchar[] DEFAULT '{full_name,date_of_birth}',
|
|
96
|
+
empty_literal_col text[] DEFAULT '{}',
|
|
97
|
+
int_literal_col integer[] DEFAULT '{1,2}',
|
|
98
|
+
empty_array_col text[] DEFAULT ARRAY[]::text[],
|
|
99
|
+
function_col integer[] DEFAULT array_fill(0, ARRAY[3]),
|
|
100
|
+
array_col text[] DEFAULT ARRAY['a', 'b']
|
|
101
|
+
);
|
|
102
|
+
`);
|
|
103
|
+
|
|
104
|
+
const schemaJson = await connector.fetchSchemaJson(`${connection}?schemas=${schema}`, 'postgres');
|
|
105
|
+
const dbdefaults = Object.fromEntries(schemaJson.fields[`${schema}.t`].map(({ name, dbdefault }) => [name, dbdefault]));
|
|
106
|
+
|
|
107
|
+
expect(dbdefaults).toEqual({
|
|
108
|
+
literal_col: { type: 'string', value: '{full_name,date_of_birth}' },
|
|
109
|
+
empty_literal_col: { type: 'string', value: '{}' },
|
|
110
|
+
int_literal_col: { type: 'string', value: '{1,2}' },
|
|
111
|
+
empty_array_col: { type: 'expression', value: 'ARRAY[]::text[]' },
|
|
112
|
+
function_col: { type: 'expression', value: 'array_fill(0, ARRAY[3])' },
|
|
113
|
+
array_col: { type: 'expression', value: 'ARRAY[\'a\', \'b\']' },
|
|
114
|
+
});
|
|
115
|
+
} finally {
|
|
116
|
+
await client.query(`DROP SCHEMA IF EXISTS "${schema}" CASCADE`);
|
|
117
|
+
await client.end();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
47
120
|
});
|
package/dist/index.js
CHANGED
|
@@ -3484,7 +3484,7 @@ sSi6
|
|
|
3484
3484
|
ON obj.OBJECT_NAME = cols.TABLE_NAME
|
|
3485
3485
|
AND obj.OBJECT_TYPE = 'TABLE'
|
|
3486
3486
|
ORDER BY obj.CREATED, obj.OBJECT_ID, cols.COLUMN_ID
|
|
3487
|
-
`,[],Xr)).rows?.reduce((e,n)=>{let{table_name:r,table_comment:i}=n;e[r]||(e[r]={name:r,schemaName:``,note:i?{value:i}:{value:``}}),t[r]||(t[r]=[]);let a=ri(n);return t[r].push(a),e},{})||{};return{tables:Object.values(n),fields:t}}function ni(e){if(e==null)return`expression`;let t=e.trim();return/^'.*'$/.test(t)?`string`:/^[0-9]+$/.test(t)||/^[0-9]*\.[0-9]*$/.test(t)?`number`:`expression`}function ri(e){let{column_name:t,data_type:n,data_length:r,data_precision:i,data_scale:a,identity_increment:o,is_nullable:s,data_default:c,column_comment:l}=e,u=ni(c),d=c&&!o?ii(c,u):null;return{name:t,type:{type_name:mi(n,r,i,a),schemaName:null},dbdefault:d,not_null:!s,increment:!!o,note:l?{value:l}:{value:``}}}function ii(e,t){return e===null?null:t===`string`?{value:e.trim().slice(1,-1).replaceAll(`''`,`'`),type:t}:{value:e,type:t}}var ai=new Set([`char`,`varchar2`,`nchar`,`nvarchar2`,`raw`,`urowid`,`character varying`,`character`,`char varying`,`nchar varying`,`varchar`,`national character varying`,`national character`,`national char varying`,`national char`]),oi=new Set([`float`]),si=`timestamp with local time zone`,ci=`timestamp with time zone`,li=`timestamp`,ui=`interval year to month`,di=`interval day to second`,fi=new Set([`number`,`numeric`,`decimal`,`dec`]);function pi(e){let t=e.split(` `).filter(Boolean).join(` `).toLowerCase();switch(t){case`anydata`:return`AnyData`;case`anytype`:return`AnyType`;case`anydataset`:return`AnyDataSet`;case`xmltype`:return`XMLType`;case`uritype`:return`URIType`;case`sdo_geometry`:return`SDO_Geometry`;case`sdo_topo_geometry`:return`SDO_Topo_Geometry`;case`sdo_georaster`:return`SDO_GeoRaster`;default:return t}}function mi(e,t,n,r){let i=pi(e);return i===si?r===null?i:`timestamp (${r}) with local time zone`:i===ci?r===null?i:`timestamp (${r}) with time zone`:i===li?r===null?i:`timestamp (${r})`:i===ui?n===null?i:`interval year (${n}) to month`:i===di?n!==null&&r!==null?`interval day (${n}) to second (${r})`:n===null?r===null?i:`interval day to second (${r})`:`interval day (${n}) to second`:ai.has(i)?t?`${i}(${t})`:i:oi.has(i)?n===null?i:`${i}(${n})`:fi.has(i)?n!==null&&r!==null?`${i}(${n}, ${r})`:n===null?i:`${i}(${n})`:i}var hi=async(e,t,n)=>{let r=await(0,h.getConnection)({username:e,password:t,connectionString:n});try{return await r.execute(`SELECT 1 FROM DUAL`),r}catch(e){throw await r.close(),e instanceof Error?Error(`OracleSQL connection error: ${e.message}`):e}};async function gi(e){let{username:t,password:n,dbidentifier:r}=Zr(e),i=await hi(t,n,r),a=ti(i),o=Qr(i),s=ei(i),c=$r(i),l=await Promise.all([a,o,s,c]),{tables:u,fields:d}=l[0],{indexes:f,tableConstraints:p,checks:m}=l[1],h=l[2],g=l[3];return Object.keys(f).forEach(e=>{g[e]?g[e].push(...f[e]):g[e]=f[e]}),await i.close(),{tables:u,fields:d,refs:h,enums:[],indexes:g,tableConstraints:p,checks:m}}var _i=async e=>{let t=new g.Client(e);try{return await t.connect(),await t.query(`SELECT 1`),t}catch(e){throw await t.end(),e instanceof Error?Error(`PostgreSQL connection error: ${e}`):e}},vi=e=>e===`YES`,yi=(e,t,n,r,i)=>e===`ARRAY`?`${t.slice(1,t.length)}[]`:n?`${t}(${n})`:r&&i?`${t}(${r},${i})`:t,bi=(e,t,n)=>{if(e===`ARRAY`)return{type:n,value:`ARRAY[${t.slice(6,-1).split(`,`).map(e=>e.split(`::`)[0]).join(`, `)}]`};if(n===`string`){let n=t.split(`::`)[0];return{type:e===`json`||e===`jsonb`?`expression`:`string`,value:n.slice(1,-1)}}return{type:n,value:t}},xi=e=>{let{column_name:t,data_type:n,character_maximum_length:r,numeric_precision:i,numeric_scale:a,udt_schema:o,udt_name:s,identity_increment:c,is_nullable:l,column_default:u,default_type:d,column_comment:f}=e,p=u&&d!==`increment`?bi(n,u,d):null;return{name:t,type:n===`USER-DEFINED`?{type_name:s,schemaName:o}:{type_name:yi(n,s,r,i,a),schemaName:null},dbdefault:p,not_null:!vi(l),increment:!!c||d===`increment`,note:f?{value:f}:{value:``}}},Si=async(e,t)=>{let n={},r=`
|
|
3487
|
+
`,[],Xr)).rows?.reduce((e,n)=>{let{table_name:r,table_comment:i}=n;e[r]||(e[r]={name:r,schemaName:``,note:i?{value:i}:{value:``}}),t[r]||(t[r]=[]);let a=ri(n);return t[r].push(a),e},{})||{};return{tables:Object.values(n),fields:t}}function ni(e){if(e==null)return`expression`;let t=e.trim();return/^'.*'$/.test(t)?`string`:/^[0-9]+$/.test(t)||/^[0-9]*\.[0-9]*$/.test(t)?`number`:`expression`}function ri(e){let{column_name:t,data_type:n,data_length:r,data_precision:i,data_scale:a,identity_increment:o,is_nullable:s,data_default:c,column_comment:l}=e,u=ni(c),d=c&&!o?ii(c,u):null;return{name:t,type:{type_name:mi(n,r,i,a),schemaName:null},dbdefault:d,not_null:!s,increment:!!o,note:l?{value:l}:{value:``}}}function ii(e,t){return e===null?null:t===`string`?{value:e.trim().slice(1,-1).replaceAll(`''`,`'`),type:t}:{value:e,type:t}}var ai=new Set([`char`,`varchar2`,`nchar`,`nvarchar2`,`raw`,`urowid`,`character varying`,`character`,`char varying`,`nchar varying`,`varchar`,`national character varying`,`national character`,`national char varying`,`national char`]),oi=new Set([`float`]),si=`timestamp with local time zone`,ci=`timestamp with time zone`,li=`timestamp`,ui=`interval year to month`,di=`interval day to second`,fi=new Set([`number`,`numeric`,`decimal`,`dec`]);function pi(e){let t=e.split(` `).filter(Boolean).join(` `).toLowerCase();switch(t){case`anydata`:return`AnyData`;case`anytype`:return`AnyType`;case`anydataset`:return`AnyDataSet`;case`xmltype`:return`XMLType`;case`uritype`:return`URIType`;case`sdo_geometry`:return`SDO_Geometry`;case`sdo_topo_geometry`:return`SDO_Topo_Geometry`;case`sdo_georaster`:return`SDO_GeoRaster`;default:return t}}function mi(e,t,n,r){let i=pi(e);return i===si?r===null?i:`timestamp (${r}) with local time zone`:i===ci?r===null?i:`timestamp (${r}) with time zone`:i===li?r===null?i:`timestamp (${r})`:i===ui?n===null?i:`interval year (${n}) to month`:i===di?n!==null&&r!==null?`interval day (${n}) to second (${r})`:n===null?r===null?i:`interval day to second (${r})`:`interval day (${n}) to second`:ai.has(i)?t?`${i}(${t})`:i:oi.has(i)?n===null?i:`${i}(${n})`:fi.has(i)?n!==null&&r!==null?`${i}(${n}, ${r})`:n===null?i:`${i}(${n})`:i}var hi=async(e,t,n)=>{let r=await(0,h.getConnection)({username:e,password:t,connectionString:n});try{return await r.execute(`SELECT 1 FROM DUAL`),r}catch(e){throw await r.close(),e instanceof Error?Error(`OracleSQL connection error: ${e.message}`):e}};async function gi(e){let{username:t,password:n,dbidentifier:r}=Zr(e),i=await hi(t,n,r),a=ti(i),o=Qr(i),s=ei(i),c=$r(i),l=await Promise.all([a,o,s,c]),{tables:u,fields:d}=l[0],{indexes:f,tableConstraints:p,checks:m}=l[1],h=l[2],g=l[3];return Object.keys(f).forEach(e=>{g[e]?g[e].push(...f[e]):g[e]=f[e]}),await i.close(),{tables:u,fields:d,refs:h,enums:[],indexes:g,tableConstraints:p,checks:m}}var _i=async e=>{let t=new g.Client(e);try{return await t.connect(),await t.query(`SELECT 1`),t}catch(e){throw await t.end(),e instanceof Error?Error(`PostgreSQL connection error: ${e}`):e}},vi=e=>e===`YES`,yi=(e,t,n,r,i)=>e===`ARRAY`?`${t.slice(1,t.length)}[]`:n?`${t}(${n})`:r&&i?`${t}(${r},${i})`:t,bi=(e,t,n)=>{if(e===`ARRAY`&&t.startsWith(`ARRAY[`)&&!t.startsWith(`ARRAY[]`))return{type:n,value:`ARRAY[${t.slice(6,-1).split(`,`).map(e=>e.split(`::`)[0]).join(`, `)}]`};if(n===`string`){let n=t.split(`::`)[0];return{type:e===`json`||e===`jsonb`?`expression`:`string`,value:n.slice(1,-1)}}return{type:n,value:t}},xi=e=>{let{column_name:t,data_type:n,character_maximum_length:r,numeric_precision:i,numeric_scale:a,udt_schema:o,udt_name:s,identity_increment:c,is_nullable:l,column_default:u,default_type:d,column_comment:f}=e,p=u&&d!==`increment`?bi(n,u,d):null;return{name:t,type:n===`USER-DEFINED`?{type_name:s,schemaName:o}:{type_name:yi(n,s,r,i,a),schemaName:null},dbdefault:p,not_null:!vi(l),increment:!!c||d===`increment`,note:f?{value:f}:{value:``}}},Si=async(e,t)=>{let n={},r=`
|
|
3488
3488
|
WITH
|
|
3489
3489
|
comments AS (
|
|
3490
3490
|
SELECT DISTINCT ON (pc.relname, pn.nspname, pa.attname)
|
|
@@ -3560,40 +3560,59 @@ sSi6
|
|
|
3560
3560
|
;
|
|
3561
3561
|
`,i=(await e.query(r)).rows.reduce((e,t)=>{let{table_schema:r,table_name:i,table_comment:a}=t,o=`${r}.${i}`;e[o]||(e[o]={name:i,schemaName:r,note:a?{value:a}:{value:``}}),n[o]||(n[o]=[]);let s=xi(t);return n[o].push(s),e},{});return{tables:Object.values(i),fields:n}},Ci=async(e,t)=>{let n=[],r=`
|
|
3562
3562
|
SELECT
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
STRING_AGG(
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
STRING_AGG(
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3563
|
+
source_ns.nspname AS table_schema,
|
|
3564
|
+
source_table.relname AS table_name,
|
|
3565
|
+
constraint_row.conname AS fk_constraint_name,
|
|
3566
|
+
STRING_AGG(source_column.attname, ',' ORDER BY key_column.ordinality) AS column_names,
|
|
3567
|
+
target_ns.nspname AS foreign_table_schema,
|
|
3568
|
+
target_table.relname AS foreign_table_name,
|
|
3569
|
+
STRING_AGG(target_column.attname, ',' ORDER BY key_column.ordinality) AS foreign_column_names,
|
|
3570
|
+
CASE constraint_row.confdeltype
|
|
3571
|
+
WHEN 'a' THEN 'NO ACTION'
|
|
3572
|
+
WHEN 'r' THEN 'RESTRICT'
|
|
3573
|
+
WHEN 'c' THEN 'CASCADE'
|
|
3574
|
+
WHEN 'n' THEN 'SET NULL'
|
|
3575
|
+
WHEN 'd' THEN 'SET DEFAULT'
|
|
3576
|
+
END AS on_delete,
|
|
3577
|
+
CASE constraint_row.confupdtype
|
|
3578
|
+
WHEN 'a' THEN 'NO ACTION'
|
|
3579
|
+
WHEN 'r' THEN 'RESTRICT'
|
|
3580
|
+
WHEN 'c' THEN 'CASCADE'
|
|
3581
|
+
WHEN 'n' THEN 'SET NULL'
|
|
3582
|
+
WHEN 'd' THEN 'SET DEFAULT'
|
|
3583
|
+
END AS on_update
|
|
3584
|
+
FROM pg_constraint AS constraint_row
|
|
3585
|
+
JOIN pg_class AS source_table
|
|
3586
|
+
ON constraint_row.conrelid = source_table.oid
|
|
3587
|
+
JOIN pg_namespace AS source_ns
|
|
3588
|
+
ON source_table.relnamespace = source_ns.oid
|
|
3589
|
+
JOIN pg_class AS target_table
|
|
3590
|
+
ON constraint_row.confrelid = target_table.oid
|
|
3591
|
+
JOIN pg_namespace AS target_ns
|
|
3592
|
+
ON target_table.relnamespace = target_ns.oid
|
|
3593
|
+
JOIN LATERAL unnest(constraint_row.conkey, constraint_row.confkey)
|
|
3594
|
+
WITH ORDINALITY AS key_column(source_attnum, target_attnum, ordinality)
|
|
3595
|
+
ON TRUE
|
|
3596
|
+
JOIN pg_attribute AS source_column
|
|
3597
|
+
ON source_column.attrelid = source_table.oid
|
|
3598
|
+
AND source_column.attnum = key_column.source_attnum
|
|
3599
|
+
JOIN pg_attribute AS target_column
|
|
3600
|
+
ON target_column.attrelid = target_table.oid
|
|
3601
|
+
AND target_column.attnum = key_column.target_attnum
|
|
3602
|
+
WHERE constraint_row.contype = 'f'
|
|
3603
|
+
AND source_ns.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
3604
|
+
${j(`source_ns.nspname`,t)}
|
|
3585
3605
|
GROUP BY
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
rc.update_rule
|
|
3606
|
+
source_ns.nspname,
|
|
3607
|
+
source_table.relname,
|
|
3608
|
+
constraint_row.conname,
|
|
3609
|
+
target_ns.nspname,
|
|
3610
|
+
target_table.relname,
|
|
3611
|
+
constraint_row.confdeltype,
|
|
3612
|
+
constraint_row.confupdtype
|
|
3594
3613
|
ORDER BY
|
|
3595
|
-
|
|
3596
|
-
|
|
3614
|
+
source_ns.nspname,
|
|
3615
|
+
source_table.relname;
|
|
3597
3616
|
`;return(await e.query(r)).rows.forEach(e=>{let{table_schema:t,fk_constraint_name:r,table_name:i,column_names:a,foreign_table_schema:o,foreign_table_name:s,foreign_column_names:c,on_delete:l,on_update:u}=e,d={tableName:i,schemaName:t,fieldNames:a.split(`,`),relation:`0..*`},f={tableName:s,schemaName:o,fieldNames:c.split(`,`),relation:`0..1`};n.push({name:r,endpoints:[d,f],onDelete:l===`NO ACTION`?null:l,onUpdate:u===`NO ACTION`?null:u})}),n},wi=async(e,t)=>{let n=`
|
|
3598
3617
|
WITH user_tables AS (
|
|
3599
3618
|
SELECT
|
package/dist/index.mjs
CHANGED
|
@@ -9886,7 +9886,7 @@ var gi = async (e) => {
|
|
|
9886
9886
|
throw await t.end(), e instanceof Error ? Error(`PostgreSQL connection error: ${e}`) : e;
|
|
9887
9887
|
}
|
|
9888
9888
|
}, _i = (e) => e === "YES", vi = (e, t, n, r, i) => e === "ARRAY" ? `${t.slice(1, t.length)}[]` : n ? `${t}(${n})` : r && i ? `${t}(${r},${i})` : t, yi = (e, t, n) => {
|
|
9889
|
-
if (e === "ARRAY") return {
|
|
9889
|
+
if (e === "ARRAY" && t.startsWith("ARRAY[") && !t.startsWith("ARRAY[]")) return {
|
|
9890
9890
|
type: n,
|
|
9891
9891
|
value: `ARRAY[${t.slice(6, -1).split(",").map((e) => e.split("::")[0]).join(", ")}]`
|
|
9892
9892
|
};
|
|
@@ -10009,40 +10009,59 @@ var gi = async (e) => {
|
|
|
10009
10009
|
}, Si = async (e, t) => {
|
|
10010
10010
|
let n = [], r = `
|
|
10011
10011
|
SELECT
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
STRING_AGG(
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
STRING_AGG(
|
|
10019
|
-
|
|
10020
|
-
|
|
10021
|
-
|
|
10022
|
-
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
|
-
|
|
10028
|
-
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10012
|
+
source_ns.nspname AS table_schema,
|
|
10013
|
+
source_table.relname AS table_name,
|
|
10014
|
+
constraint_row.conname AS fk_constraint_name,
|
|
10015
|
+
STRING_AGG(source_column.attname, ',' ORDER BY key_column.ordinality) AS column_names,
|
|
10016
|
+
target_ns.nspname AS foreign_table_schema,
|
|
10017
|
+
target_table.relname AS foreign_table_name,
|
|
10018
|
+
STRING_AGG(target_column.attname, ',' ORDER BY key_column.ordinality) AS foreign_column_names,
|
|
10019
|
+
CASE constraint_row.confdeltype
|
|
10020
|
+
WHEN 'a' THEN 'NO ACTION'
|
|
10021
|
+
WHEN 'r' THEN 'RESTRICT'
|
|
10022
|
+
WHEN 'c' THEN 'CASCADE'
|
|
10023
|
+
WHEN 'n' THEN 'SET NULL'
|
|
10024
|
+
WHEN 'd' THEN 'SET DEFAULT'
|
|
10025
|
+
END AS on_delete,
|
|
10026
|
+
CASE constraint_row.confupdtype
|
|
10027
|
+
WHEN 'a' THEN 'NO ACTION'
|
|
10028
|
+
WHEN 'r' THEN 'RESTRICT'
|
|
10029
|
+
WHEN 'c' THEN 'CASCADE'
|
|
10030
|
+
WHEN 'n' THEN 'SET NULL'
|
|
10031
|
+
WHEN 'd' THEN 'SET DEFAULT'
|
|
10032
|
+
END AS on_update
|
|
10033
|
+
FROM pg_constraint AS constraint_row
|
|
10034
|
+
JOIN pg_class AS source_table
|
|
10035
|
+
ON constraint_row.conrelid = source_table.oid
|
|
10036
|
+
JOIN pg_namespace AS source_ns
|
|
10037
|
+
ON source_table.relnamespace = source_ns.oid
|
|
10038
|
+
JOIN pg_class AS target_table
|
|
10039
|
+
ON constraint_row.confrelid = target_table.oid
|
|
10040
|
+
JOIN pg_namespace AS target_ns
|
|
10041
|
+
ON target_table.relnamespace = target_ns.oid
|
|
10042
|
+
JOIN LATERAL unnest(constraint_row.conkey, constraint_row.confkey)
|
|
10043
|
+
WITH ORDINALITY AS key_column(source_attnum, target_attnum, ordinality)
|
|
10044
|
+
ON TRUE
|
|
10045
|
+
JOIN pg_attribute AS source_column
|
|
10046
|
+
ON source_column.attrelid = source_table.oid
|
|
10047
|
+
AND source_column.attnum = key_column.source_attnum
|
|
10048
|
+
JOIN pg_attribute AS target_column
|
|
10049
|
+
ON target_column.attrelid = target_table.oid
|
|
10050
|
+
AND target_column.attnum = key_column.target_attnum
|
|
10051
|
+
WHERE constraint_row.contype = 'f'
|
|
10052
|
+
AND source_ns.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
10053
|
+
${A("source_ns.nspname", t)}
|
|
10034
10054
|
GROUP BY
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
rc.update_rule
|
|
10055
|
+
source_ns.nspname,
|
|
10056
|
+
source_table.relname,
|
|
10057
|
+
constraint_row.conname,
|
|
10058
|
+
target_ns.nspname,
|
|
10059
|
+
target_table.relname,
|
|
10060
|
+
constraint_row.confdeltype,
|
|
10061
|
+
constraint_row.confupdtype
|
|
10043
10062
|
ORDER BY
|
|
10044
|
-
|
|
10045
|
-
|
|
10063
|
+
source_ns.nspname,
|
|
10064
|
+
source_table.relname;
|
|
10046
10065
|
`;
|
|
10047
10066
|
return (await e.query(r)).rows.forEach((e) => {
|
|
10048
10067
|
let { table_schema: t, fk_constraint_name: r, table_name: i, column_names: a, foreign_table_schema: o, foreign_table_name: s, foreign_column_names: c, on_delete: l, on_update: u } = e, d = {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@dbml/connector",
|
|
4
|
-
"version": "11.0.0-alpha.
|
|
4
|
+
"version": "11.0.0-alpha.4",
|
|
5
5
|
"description": "This package was created to fetch the schema JSON from many kind of databases.",
|
|
6
6
|
"author": "huy.phung.sw@gmail.com",
|
|
7
7
|
"license": "MIT",
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=18"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "40f71a2018dd2a5a9452cd4ba680ef08289fae3a"
|
|
43
43
|
}
|
|
@@ -135,7 +135,7 @@ function getDbdefault (columnDefault: string | null, defaultType: string): Defau
|
|
|
135
135
|
|
|
136
136
|
// Field type utils
|
|
137
137
|
|
|
138
|
-
// These datatypes are never qualified: data size, data scale and data precision
|
|
138
|
+
// These datatypes are never qualified: data size, data scale and data precision
|
|
139
139
|
// Ref: https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Data-Types.html
|
|
140
140
|
const UNQUALIFIED_DATA_TYPES = new Set([
|
|
141
141
|
// datetime
|
|
@@ -54,7 +54,9 @@ const getFieldType = (data_type: string, udt_name: string, character_maximum_len
|
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
const getDbdefault = (data_type: string, column_default: string, default_type: DefaultType): DefaultInfo => {
|
|
57
|
-
|
|
57
|
+
// Only a non-empty ARRAY[...] constructor is rewritten here. Other array defaults, such as
|
|
58
|
+
// '{a,b}'::text[], ARRAY[]::text[] or a function call, are handled below like any other default
|
|
59
|
+
if (data_type === 'ARRAY' && column_default.startsWith('ARRAY[') && !column_default.startsWith('ARRAY[]')) {
|
|
58
60
|
const values = column_default.slice(6, -1).split(',').map((value) => {
|
|
59
61
|
return value.split('::')[0];
|
|
60
62
|
});
|
|
@@ -228,40 +230,59 @@ const generateRawRefs = async (client: Client, schemas: string[]): Promise<Ref[]
|
|
|
228
230
|
|
|
229
231
|
const refsListSql = `
|
|
230
232
|
SELECT
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
STRING_AGG(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
STRING_AGG(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
233
|
+
source_ns.nspname AS table_schema,
|
|
234
|
+
source_table.relname AS table_name,
|
|
235
|
+
constraint_row.conname AS fk_constraint_name,
|
|
236
|
+
STRING_AGG(source_column.attname, ',' ORDER BY key_column.ordinality) AS column_names,
|
|
237
|
+
target_ns.nspname AS foreign_table_schema,
|
|
238
|
+
target_table.relname AS foreign_table_name,
|
|
239
|
+
STRING_AGG(target_column.attname, ',' ORDER BY key_column.ordinality) AS foreign_column_names,
|
|
240
|
+
CASE constraint_row.confdeltype
|
|
241
|
+
WHEN 'a' THEN 'NO ACTION'
|
|
242
|
+
WHEN 'r' THEN 'RESTRICT'
|
|
243
|
+
WHEN 'c' THEN 'CASCADE'
|
|
244
|
+
WHEN 'n' THEN 'SET NULL'
|
|
245
|
+
WHEN 'd' THEN 'SET DEFAULT'
|
|
246
|
+
END AS on_delete,
|
|
247
|
+
CASE constraint_row.confupdtype
|
|
248
|
+
WHEN 'a' THEN 'NO ACTION'
|
|
249
|
+
WHEN 'r' THEN 'RESTRICT'
|
|
250
|
+
WHEN 'c' THEN 'CASCADE'
|
|
251
|
+
WHEN 'n' THEN 'SET NULL'
|
|
252
|
+
WHEN 'd' THEN 'SET DEFAULT'
|
|
253
|
+
END AS on_update
|
|
254
|
+
FROM pg_constraint AS constraint_row
|
|
255
|
+
JOIN pg_class AS source_table
|
|
256
|
+
ON constraint_row.conrelid = source_table.oid
|
|
257
|
+
JOIN pg_namespace AS source_ns
|
|
258
|
+
ON source_table.relnamespace = source_ns.oid
|
|
259
|
+
JOIN pg_class AS target_table
|
|
260
|
+
ON constraint_row.confrelid = target_table.oid
|
|
261
|
+
JOIN pg_namespace AS target_ns
|
|
262
|
+
ON target_table.relnamespace = target_ns.oid
|
|
263
|
+
JOIN LATERAL unnest(constraint_row.conkey, constraint_row.confkey)
|
|
264
|
+
WITH ORDINALITY AS key_column(source_attnum, target_attnum, ordinality)
|
|
265
|
+
ON TRUE
|
|
266
|
+
JOIN pg_attribute AS source_column
|
|
267
|
+
ON source_column.attrelid = source_table.oid
|
|
268
|
+
AND source_column.attnum = key_column.source_attnum
|
|
269
|
+
JOIN pg_attribute AS target_column
|
|
270
|
+
ON target_column.attrelid = target_table.oid
|
|
271
|
+
AND target_column.attnum = key_column.target_attnum
|
|
272
|
+
WHERE constraint_row.contype = 'f'
|
|
273
|
+
AND source_ns.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
274
|
+
${buildSchemaQuery('source_ns.nspname', schemas)}
|
|
253
275
|
GROUP BY
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
rc.update_rule
|
|
276
|
+
source_ns.nspname,
|
|
277
|
+
source_table.relname,
|
|
278
|
+
constraint_row.conname,
|
|
279
|
+
target_ns.nspname,
|
|
280
|
+
target_table.relname,
|
|
281
|
+
constraint_row.confdeltype,
|
|
282
|
+
constraint_row.confupdtype
|
|
262
283
|
ORDER BY
|
|
263
|
-
|
|
264
|
-
|
|
284
|
+
source_ns.nspname,
|
|
285
|
+
source_table.relname;
|
|
265
286
|
`;
|
|
266
287
|
|
|
267
288
|
const refsQueryResult = await client.query(refsListSql);
|