From 0b5ec3eaed19a8fa31039a08ccb0683f3160da1f Mon Sep 17 00:00:00 2001 From: Serhii Filonenko Date: Tue, 4 Mar 2025 11:55:27 +0200 Subject: [PATCH 1/3] HCK-10157: enable dbt feature --- package.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c9cad59..37c2a78 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,13 @@ }, "nestedCollections": false, "disablePatternField": true, - "enableForwardEngineering": true, + "enableForwardEngineering": { + "jsonDocument": true, + "jsonSchema": true, + "excel": true, + "plugin": true, + "dbt": true + }, "disableMultipleTypes": false, "enableReverseEngineering": true, "enableComplexTypesNormalization": true, From 4dc15f308f9f6b8dd4cb562431436ac566b4c01b Mon Sep 17 00:00:00 2001 From: Serhii Filonenko Date: Tue, 4 Mar 2025 11:55:58 +0200 Subject: [PATCH 2/3] HCK-10157: add dbt provider --- esbuild.package.js | 1 + forward_engineering/dbtProvider.js | 49 +++++++++ .../helpers/constraintHelper.js | 102 ++++++++++++++++++ forward_engineering/types.ts | 29 +++++ 4 files changed, 181 insertions(+) create mode 100644 forward_engineering/dbtProvider.js create mode 100644 forward_engineering/types.ts diff --git a/esbuild.package.js b/esbuild.package.js index 19c1fd3..e6f7ca6 100644 --- a/esbuild.package.js +++ b/esbuild.package.js @@ -15,6 +15,7 @@ esbuild path.resolve(__dirname, 'api', 'fe.js'), path.resolve(__dirname, 'api', 're.js'), path.resolve(__dirname, 'forward_engineering', 'api.js'), + path.resolve(__dirname, 'forward_engineering', 'dbtProvider.js'), path.resolve(__dirname, 'reverse_engineering', 'api.js'), ], bundle: true, diff --git a/forward_engineering/dbtProvider.js b/forward_engineering/dbtProvider.js new file mode 100644 index 0000000..5aeaea9 --- /dev/null +++ b/forward_engineering/dbtProvider.js @@ -0,0 +1,49 @@ +/** + * @typedef {import('./types').ColumnDefinition} ColumnDefinition + * @typedef {import('./types').ConstraintDto} ConstraintDto + * @typedef {import('./types').JsonSchema} JsonSchema + */ + +const columnHelper = require('./helpers/columnHelper'); +const constraintHelper = require('./helpers/constraintHelper'); + +class DbtProvider { + /** + * @returns {DbtProvider} + */ + static createDbtProvider() { + return new DbtProvider(); + } + + /** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {string} + */ + decorateType({ columnDefinition }) { + const type = columnHelper.getTypeByProperty([], '')(columnDefinition); + const isComplexType = /^(array|struct)/i.test(type); + + return isComplexType ? type.replace(/<[\s\S]+>$/, '<>') : type; + } + + /** + * @param {{ jsonSchema: JsonSchema }} + * @returns {ConstraintDto[]} + */ + getCompositeKeyConstraints({ jsonSchema }) { + const compositePrimaryKeys = constraintHelper.getCompositePrimaryKeys({ jsonSchema }); + const compositeUniqueKeys = constraintHelper.getCompositeUniqueKeys({ jsonSchema }); + + return [...compositePrimaryKeys, ...compositeUniqueKeys]; + } + + /** + * @param {{ columnDefinition: ColumnDefinition; jsonSchema: JsonSchema }} + * @returns {ConstraintDto[]} + */ + getColumnConstraints({ columnDefinition, jsonSchema }) { + return constraintHelper.getColumnConstraints({ columnDefinition }); + } +} + +module.exports = DbtProvider; diff --git a/forward_engineering/helpers/constraintHelper.js b/forward_engineering/helpers/constraintHelper.js index 5e03433..c8d88d5 100644 --- a/forward_engineering/helpers/constraintHelper.js +++ b/forward_engineering/helpers/constraintHelper.js @@ -1,3 +1,9 @@ +/** + * @typedef {import('../types').ColumnDefinition} ColumnDefinition + * @typedef {import('../types').ConstraintDto} ConstraintDto + * @typedef {import('../types').JsonSchema} JsonSchema + */ + const findName = (keyId, properties) => { return Object.keys(properties).find(name => properties[name].GUID === keyId); }; @@ -91,8 +97,104 @@ const getCheckConstraint = jsonSchema => { return checkConstraint.filter(Boolean).join(',\n'); }; +/** + * @param {{ jsonSchema: JsonSchema }} + * @returns {ConstraintDto[]} + */ +const getCompositePrimaryKeys = ({ jsonSchema }) => { + if (!Array.isArray(jsonSchema.primaryKey)) { + return []; + } + + return jsonSchema.primaryKey + .filter(primaryKey => primaryKey.compositePrimaryKey?.length) + .map(primaryKey => ({ + keyType: 'PRIMARY KEY', + name: primaryKey.constraintName, + columns: getKeys(primaryKey.compositePrimaryKey, jsonSchema), + })); +}; + +/** + * @param {{ jsonSchema: JsonSchema }} + * @returns {ConstraintDto[]} + */ +const getCompositeUniqueKeys = ({ jsonSchema }) => { + if (!Array.isArray(jsonSchema.uniqueKey)) { + return []; + } + + return jsonSchema.uniqueKey + .filter(uniqueKey => uniqueKey.compositeUniqueKey?.length) + .map(uniqueKey => ({ + keyType: 'UNIQUE', + name: uniqueKey.constraintName, + columns: getKeys(uniqueKey.compositeUniqueKey, jsonSchema), + })); +}; + +/** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto} + */ +const getColumnPrimaryKeyConstraint = ({ columnDefinition }) => { + const isPrimaryKey = columnDefinition.primaryKey && !columnDefinition.compositePrimaryKey; + + if (!isPrimaryKey) { + return; + } + + return { + keyType: 'PRIMARY KEY', + }; +}; + +/** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto} + */ +const getColumnUniqueKeyConstraint = ({ columnDefinition }) => { + if (!columnDefinition.unique) { + return; + } + + return { + keyType: 'UNIQUE', + }; +}; + +/** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto} + */ +const getColumnCheckConstraint = ({ columnDefinition }) => { + if (!columnDefinition.check) { + return; + } + + return { + keyType: 'CHECK', + expression: columnDefinition.check, + }; +}; + +/** + * @param {{ columnDefinition: ColumnDefinition; jsonSchema: JsonSchema }} + * @returns {ConstraintDto[]} + */ +const getColumnConstraints = ({ columnDefinition, jsonSchema }) => { + const primaryKeyConstraint = getColumnPrimaryKeyConstraint({ columnDefinition }); + const uniqueKeyConstraint = getColumnUniqueKeyConstraint({ columnDefinition }); + const checkConstraint = getColumnCheckConstraint({ columnDefinition }); + + return [primaryKeyConstraint, uniqueKeyConstraint, checkConstraint].filter(Boolean); +}; + module.exports = { getConstraintOpts, getUniqueKeyStatement, getCheckConstraint, + getCompositeUniqueKeys, + getCompositePrimaryKeys, + getColumnConstraints, }; diff --git a/forward_engineering/types.ts b/forward_engineering/types.ts new file mode 100644 index 0000000..53bc7f8 --- /dev/null +++ b/forward_engineering/types.ts @@ -0,0 +1,29 @@ +export type ColumnDefinition = { + name: string; + type: string; + nullable: boolean; + isActivated: boolean; + length?: number; + precision?: number; + primaryKey?: boolean; + scale?: number; + timePrecision?: number; + unique?: boolean; + check?: string; + properties?: Record; +}; + +export type ConstraintDtoColumn = { + name: string; + isActivated: boolean; +}; + +export type KeyType = 'PRIMARY KEY' | 'UNIQUE' | 'CHECK'; + +export type ConstraintDto = { + keyType: KeyType; + name: string; + columns?: ConstraintDtoColumn[]; +}; + +export type JsonSchema = Record; From 4a6b760a665990c76fa17ea61a7b301321d897ad Mon Sep 17 00:00:00 2001 From: Serhii Filonenko Date: Wed, 5 Mar 2025 11:59:27 +0200 Subject: [PATCH 3/3] HCK-10157: fix return type --- forward_engineering/helpers/constraintHelper.js | 6 +++--- package-lock.json | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/forward_engineering/helpers/constraintHelper.js b/forward_engineering/helpers/constraintHelper.js index c8d88d5..bc55545 100644 --- a/forward_engineering/helpers/constraintHelper.js +++ b/forward_engineering/helpers/constraintHelper.js @@ -135,7 +135,7 @@ const getCompositeUniqueKeys = ({ jsonSchema }) => { /** * @param {{ columnDefinition: ColumnDefinition }} - * @returns {ConstraintDto} + * @returns {ConstraintDto | undefined} */ const getColumnPrimaryKeyConstraint = ({ columnDefinition }) => { const isPrimaryKey = columnDefinition.primaryKey && !columnDefinition.compositePrimaryKey; @@ -151,7 +151,7 @@ const getColumnPrimaryKeyConstraint = ({ columnDefinition }) => { /** * @param {{ columnDefinition: ColumnDefinition }} - * @returns {ConstraintDto} + * @returns {ConstraintDto | undefined} */ const getColumnUniqueKeyConstraint = ({ columnDefinition }) => { if (!columnDefinition.unique) { @@ -165,7 +165,7 @@ const getColumnUniqueKeyConstraint = ({ columnDefinition }) => { /** * @param {{ columnDefinition: ColumnDefinition }} - * @returns {ConstraintDto} + * @returns {ConstraintDto | undefined} */ const getColumnCheckConstraint = ({ columnDefinition }) => { if (!columnDefinition.check) { diff --git a/package-lock.json b/package-lock.json index 211dae9..195eb4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,13 @@ { "name": "Hive", - "version": "0.2.11", + "version": "0.2.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Hive", - "version": "0.2.11", + "version": "0.2.12", + "hasInstallScript": true, "dependencies": { "antlr4": "4.8.0", "async": "2.6.4",