From 004eed4a2eb94b87b34c54c858c5435d27a4c250 Mon Sep 17 00:00:00 2001 From: Serhii Filonenko Date: Tue, 4 Mar 2025 17:10:49 +0200 Subject: [PATCH 1/2] HCK-10160: add dbt provider --- esbuild.package.js | 1 + forward_engineering/dbtProvider.js | 76 +++++++++++++++++++ forward_engineering/ddlProvider.js | 6 +- .../helpers/columnDefinitionHelper.js | 4 +- forward_engineering/helpers/keyHelper.js | 66 +++++++++++++++- forward_engineering/types.d.ts | 33 ++++++++ 6 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 forward_engineering/dbtProvider.js create mode 100644 forward_engineering/types.d.ts diff --git a/esbuild.package.js b/esbuild.package.js index d473476..aff4f18 100644 --- a/esbuild.package.js +++ b/esbuild.package.js @@ -13,6 +13,7 @@ esbuild entryPoints: [ path.resolve(__dirname, 'forward_engineering', 'api.js'), path.resolve(__dirname, 'forward_engineering', 'ddlProvider.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..5e58caf --- /dev/null +++ b/forward_engineering/dbtProvider.js @@ -0,0 +1,76 @@ +/** + * @typedef {import('./types').AppInstance} AppInstance + * @typedef {import('./types').ColumnDefinition} ColumnDefinition + * @typedef {import('./types').JsonSchema} JsonSchema + * @typedef {import('./types').ConstraintDto} ConstraintDto + */ +const { toLower, toUpper, identity } = require('lodash'); + +const types = require('./configs/types'); +const defaultTypes = require('./configs/defaultTypes'); +const getKeyHelper = require('./helpers/keyHelper'); +const getColumnDefinitionHelper = require('./helpers/columnDefinitionHelper'); + +class DbtProvider { + /** + * @returns {DbtProvider} + */ + static createDbtProvider() { + return new DbtProvider(); + } + + /** + * @param {string} type + * @returns {string | undefined} + */ + getDefaultType(type) { + return defaultTypes[type]; + } + + /** + * @returns {Record} + */ + getTypesDescriptors() { + return types; + } + + /** + * @param {string} type + * @returns {boolean} + */ + hasType(type) { + return Object.keys(types).map(toLower).includes(toLower(type)); + } + + /** + * @param {{ type: string; columnDefinition: ColumnDefinition }} + * @returns {string} + */ + decorateType({ type, columnDefinition }) { + const columnDefinitionHelper = getColumnDefinitionHelper(identity); + + return columnDefinitionHelper.decorateType(toUpper(type), columnDefinition); + } + + /** + * @param {{ jsonSchema: JsonSchema }} + * @returns {ConstraintDto[]} + */ + getCompositeKeyConstraints({ jsonSchema }) { + const keyHelper = getKeyHelper(identity); + + return keyHelper.getCompositeKeyConstraints({ jsonSchema }); + } + + /** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto[]} + */ + getColumnConstraints({ columnDefinition }) { + const keyHelper = getKeyHelper(identity); + + return keyHelper.getColumnConstraints({ columnDefinition }); + } +} + +module.exports = DbtProvider; diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index 3e957b1..073961d 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -1,3 +1,4 @@ +const _ = require('lodash'); const defaultTypes = require('./configs/defaultTypes'); const types = require('./configs/types'); const templates = require('./configs/templates'); @@ -6,7 +7,6 @@ const dropStatementProxy = require('./helpers/dropStatementProxy'); const { joinActivatedAndDeactivatedStatements } = require('./utils/joinActivatedAndDeactivatedStatements'); module.exports = (baseProvider, options, app) => { - const _ = app.require('lodash'); const { tab, commentIfDeactivated, @@ -19,7 +19,7 @@ module.exports = (baseProvider, options, app) => { } = app.require('@hackolade/ddl-fe-utils').general; const { assignTemplates, compareGroupItems } = app.require('@hackolade/ddl-fe-utils'); const { decorateDefault, decorateType, canBeNational, getSign, createGeneratedColumn, canHaveAutoIncrement } = - require('./helpers/columnDefinitionHelper')(_, wrap); + require('./helpers/columnDefinitionHelper')(wrap); const { getTableName, getTableOptions, getPartitions, getViewData, getCharacteristics, escapeQuotes } = require('./helpers/general')(_, wrap); const { generateConstraintsString, foreignKeysToString, foreignActiveKeysToString, createKeyConstraint } = @@ -31,7 +31,7 @@ module.exports = (baseProvider, options, app) => { assignTemplates, escapeQuotes, }); - const keyHelper = require('./helpers/keyHelper')(_, clean); + const keyHelper = require('./helpers/keyHelper')(clean); const { processIndexKeyName } = require('./helpers/indexHelper')(wrap); const additionalOptions = getAdditionalOptions(options.additionalOptions); diff --git a/forward_engineering/helpers/columnDefinitionHelper.js b/forward_engineering/helpers/columnDefinitionHelper.js index 07f35ae..a71af0b 100644 --- a/forward_engineering/helpers/columnDefinitionHelper.js +++ b/forward_engineering/helpers/columnDefinitionHelper.js @@ -1,4 +1,6 @@ -module.exports = (_, wrap) => { +const _ = require('lodash'); + +module.exports = wrap => { const addLength = (type, length) => { return `${type}(${length})`; }; diff --git a/forward_engineering/helpers/keyHelper.js b/forward_engineering/helpers/keyHelper.js index 3330cd1..fbb1ea7 100644 --- a/forward_engineering/helpers/keyHelper.js +++ b/forward_engineering/helpers/keyHelper.js @@ -1,4 +1,12 @@ -module.exports = (_, clean) => { +/** + * @typedef {import('../types').ColumnDefinition} ColumnDefinition + * @typedef {import('../types').JsonSchema} JsonSchema + * @typedef {import('../types').ConstraintDto} ConstraintDto + */ + +const _ = require('lodash'); + +module.exports = clean => { const mapProperties = (jsonSchema, iteratee) => { return Object.entries(jsonSchema.properties).map(iteratee); }; @@ -166,11 +174,67 @@ module.exports = (_, clean) => { ]; }; + /** + * @param {{ jsonSchema: JsonSchema }} + * @returns {ConstraintDto[]} + */ + const getCompositeKeyConstraints = ({ jsonSchema }) => { + const compositePrimaryKeys = getCompositePrimaryKeys(jsonSchema); + const compositeUniqueKeys = getCompositeUniqueKeys(jsonSchema); + + return [...compositePrimaryKeys, ...compositeUniqueKeys]; + }; + + /** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto | undefined} + */ + const getPrimaryKeyConstraint = ({ columnDefinition }) => { + if (!isPrimaryKey(columnDefinition)) { + return; + } + + return hydratePrimaryKeyOptions(columnDefinition.primaryKeyOptions ?? {}, '', columnDefinition.isActivated); + }; + + /** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto[]} + */ + const getUniqueKeyConstraints = ({ columnDefinition }) => { + if (!isUniqueKey(columnDefinition)) { + return []; + } + + if (isInlineUnique(columnDefinition)) { + const constraint = hydrateUniqueOptions({}, '', columnDefinition.isActivated); + + return [constraint]; + } + + return columnDefinition.uniqueKeyOptions.map(uniqueKeyOption => { + return hydrateUniqueOptions(uniqueKeyOption, '', columnDefinition.isActivated); + }); + }; + + /** + * @param {{ columnDefinition: ColumnDefinition }} + * @returns {ConstraintDto[]} + */ + const getColumnConstraints = ({ columnDefinition }) => { + const primaryKeyConstraint = getPrimaryKeyConstraint({ columnDefinition }); + const uniqueKeyConstraints = getUniqueKeyConstraints({ columnDefinition }); + + return [primaryKeyConstraint, ...uniqueKeyConstraints].filter(Boolean); + }; + return { getTableKeyConstraints, isInlineUnique, isInlinePrimaryKey, hydratePrimaryKeyOptions, hydrateUniqueOptions, + getColumnConstraints, + getCompositeKeyConstraints, }; }; diff --git a/forward_engineering/types.d.ts b/forward_engineering/types.d.ts new file mode 100644 index 0000000..80afdad --- /dev/null +++ b/forward_engineering/types.d.ts @@ -0,0 +1,33 @@ +export type ColumnDefinition = { + name: string; + type: string; + isActivated: boolean; + length?: number; + precision?: number; + primaryKey?: boolean; + scale?: number; + timePrecision?: number; + unique?: boolean; + primaryKeyOptions?: { GUID: string; constraintName: string }; + uniqueKeyOptions?: Array<{ GUID: string; constraintName: string }>; +}; + +export type AppInstance = { + require: (packageName: string) => unknown; + general: object; +} + +export type ConstraintDtoColumn = { + name: string; + isActivated: boolean; +}; + +export type KeyType = 'PRIMARY KEY' | 'UNIQUE'; + +export type ConstraintDto = { + keyType: KeyType; + name: string; + columns?: ConstraintDtoColumn[]; +}; + +export type JsonSchema = Record; From c25ab2ef8028a6f42509cd2ce294caa9e4c28c3d Mon Sep 17 00:00:00 2001 From: Serhii Filonenko Date: Tue, 4 Mar 2025 17:11:02 +0200 Subject: [PATCH 2/2] HCK-10160: enable dbt feature --- package.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 789c834..bc0507f 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,13 @@ "nestedCollections": false, "disablePatternField": true, "disableMultipleTypes": true, - "enableForwardEngineering": true, + "enableForwardEngineering": { + "jsonDocument": true, + "jsonSchema": true, + "excel": true, + "plugin": true, + "dbt": true + }, "disableReverseEngineering": false, "disableChoices": true, "enableJsonType": true,