From b84f5a192954f893e5bd894fe3315c188a475aa0 Mon Sep 17 00:00:00 2001 From: chulanovskyi-bs <56116665+chulanovskyi-bs@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:16:07 +0300 Subject: [PATCH] HCK-8102: `dynamic iceberg` table statements (#151) * fix: normalized dependencies for 'external', 'iceberg', 'dynamic' and 'transient' table options * fix: pass 'iceberg', 'dynamic' and 'transient' table options to script properly * chore: refactored approach of adding space at the beginning of the statement * fix: pass missing parameters to a template --- forward_engineering/configs/templates.js | 31 +++- forward_engineering/ddlProvider.js | 171 ++++++++++-------- .../alterScriptHelpers/commonScript.js | 7 +- .../helpers/columnDefinitionHelper.js | 7 +- forward_engineering/helpers/tableHelper.js | 40 ++-- forward_engineering/helpers/tagHelper.js | 3 +- forward_engineering/utils/preSpace.js | 3 + .../entity_level/entityLevelConfig.json | 64 +++++-- 8 files changed, 207 insertions(+), 119 deletions(-) create mode 100644 forward_engineering/utils/preSpace.js diff --git a/forward_engineering/configs/templates.js b/forward_engineering/configs/templates.js index c8973481..fefdd3d1 100644 --- a/forward_engineering/configs/templates.js +++ b/forward_engineering/configs/templates.js @@ -1,16 +1,19 @@ module.exports = { createDatabase: 'CREATE DATABASE IF NOT EXISTS ${name};\nUSE DATABASE ${name};\n', + createSchema: 'CREATE${transient} SCHEMA IF NOT EXISTS ${name}${managed_access}${data_retention}${comment};\nUSE SCHEMA ${name};\n', dropSchema: 'DROP SCHEMA IF EXISTS ${name};\n', + createTable: - 'CREATE${temporary}${transient} TABLE IF NOT EXISTS\n' + + 'CREATE${orReplace}${temporary}${transient} TABLE${tableIfNotExists}\n' + '\t${name} (\n' + '\t\t${column_definitions}' + '${out_of_line_constraints}\n' + '\t)${tableOptions};\n', + createDynamicTable: - 'CREATE${orReplace}${transient} DYNAMIC${iceberg} TABLE${tableIfNotExists}\n' + + 'CREATE${orReplace}${transient}${dynamic}${iceberg} TABLE${tableIfNotExists}\n' + '\t${name}\n' + '${column_definitions}' + '${targetLag}' + @@ -27,30 +30,44 @@ module.exports = { '${comment}' + '${tagsStatement}' + '${selectStatement};\n', + createLikeTable: 'CREATE TABLE IF NOT EXISTS ${name} LIKE ${source_table}${tableOptions};\n', + createCloneTable: 'CREATE TABLE IF NOT EXISTS ${name} CLONE ${source_table}${tableOptions};\n', + createAsSelect: 'CREATE TABLE IF NOT EXISTS ${name} AS ${selectStatement}${tableOptions};\n', + createExternalTable: 'CREATE EXTERNAL TABLE IF NOT EXISTS \n' + '\t${name} (\n' + '\t\t${column_definitions}${out_of_line_constraints}\n' + '\t)${tableOptions};\n', + columnDefinition: '${name} ${type}${collation}${default}${identity}${autoincrement}${not_nul}${inline_constraint}${comment}${tag}', + externalColumnDefinition: '${name} ${type} as ${expression}${comment}', + createTableForeignKey: '${constraint}FOREIGN KEY (${columns}) REFERENCES ${primary_table} (${primary_columns})', + alterTableForeignKey: 'ALTER TABLE IF EXISTS ${table_name} ADD ${constraint}FOREIGN KEY (${columns}) REFERENCES ${primary_table} (${primary_columns});', + createView: 'CREATE${secure}${materialized} VIEW IF NOT EXISTS ${name} (\n' + '\t${column_list}\n' + ')\n${copy_grants}${comment}${tag}${clustering}AS ${select_statement};\n', + createUDF: 'CREATE${orReplace} FUNCTION ${name}(${arguments})\n\tRETURNS ${returnType}${notNull}\n\tLANGUAGE ${language}${parameters}${comment}\n\tAS ${body};\n', + createProcedure: 'CREATE${orReplace} PROCEDURE ${name}(${arguments})\n\tRETURNS ${returnType}${notNull}\n\tLANGUAGE ${language}${parameters}${comment}\n\tAS ${body};\n', + createSequence: 'CREATE SEQUENCE IF NOT EXISTS ${name} START ${start} INCREMENT ${increment}${comment};\n', + createFileFormat: 'CREATE FILE FORMAT IF NOT EXISTS ${name}${options}${comment};\n', + createStage: 'CREATE${temporary} STAGE IF NOT EXISTS ${name} ${url}${storageIntegration}${credentials}${encryption};\n', @@ -61,12 +78,16 @@ module.exports = { alterSchemaScript: 'ALTER SCHEMA IF EXISTS ${name} ', alterTableScript: 'ALTER${dynamic} TABLE IF EXISTS ${name} ', alterEntityRename: 'RENAME TO ${name};\n', + + alterViewScript: 'ALTER VIEW IF EXISTS ${name} ', + alterMaterializedViewScript: 'ALTER MATERIALIZED VIEW ${name} ', + setPropertySchema: 'SET ${property};\n', unsetPropertySchema: 'UNSET ${property};\n', - manageAccessSchema: '${access} MANAGED ACCESS;\n', setPropertyTable: 'SET ${property};\n', - alterViewScript: 'ALTER VIEW IF EXISTS ${name} ', - alterMaterializedViewScript: 'ALTER MATERIALIZED VIEW ${name} ', + + manageAccessSchema: '${access} MANAGED ACCESS;\n', + createTag: 'CREATE${orReplace} TAG${ifNotExist} ${name}${allowedValues}${comment};\n', dropTag: 'DROP TAG IF EXISTS ${name};\n', alterTag: 'ALTER TAG${ifExists} ${name} ${option}${optionValue};\n', diff --git a/forward_engineering/ddlProvider.js b/forward_engineering/ddlProvider.js index 9ecacf82..f62feb95 100644 --- a/forward_engineering/ddlProvider.js +++ b/forward_engineering/ddlProvider.js @@ -19,6 +19,7 @@ const { } = require('./helpers/alterScriptHelpers/common'); const { escapeString } = require('./utils/escapeString'); const { joinActivatedAndDeactivatedStatements } = require('./utils/joinActivatedAndDeactivatedStatements'); +const { preSpace } = require('./utils/preSpace'); const DEFAULT_SNOWFLAKE_SEQUENCE_START = 1; const DEFAULT_SNOWFLAKE_SEQUENCE_INCREMENT = 1; @@ -29,7 +30,7 @@ module.exports = (baseProvider, options, app) => { const scriptFormat = options?.targetScriptOptions?.keyword || FORMATS.SNOWSIGHT; const keyHelper = require('./helpers/keyHelper')(app); - const { getFileFormat, getCopyOptions, addOptions, getAtOrBefore, mergeKeys, getDynamicTableProps } = + const { getFileFormat, getCopyOptions, addOptions, getAtOrBefore, mergeKeys, getTableExtraProps } = require('./helpers/tableHelper')(app); const getFormatTypeOptions = require('./helpers/getFormatTypeOptions')(app); const { getStageCopyOptions } = require('./helpers/getStageCopyOptions')(app); @@ -99,11 +100,11 @@ module.exports = (baseProvider, options, app) => { return input; } - const getOrReplaceStatement = isEnabled => (isEnabled ? ' OR REPLACE' : ''); + const getOrReplaceStatement = isEnabled => preSpace(isEnabled && 'OR REPLACE'); const getBodyStatement = body => (body ? `\n\t${insertNewlinesAtEdges(escapeString(scriptFormat, body))}` : ''); const getCommentsStatement = text => (text ? `\n\tCOMMENT = '${text}'` : ''); const getNotNullStatement = isEnabled => (isEnabled ? '\n\tNOT NULL' : ''); - const getIfNotExistStatement = ifNotExist => (ifNotExist ? ' IF NOT EXISTS' : ''); + const getIfNotExistStatement = ifNotExist => preSpace(ifNotExist && 'IF NOT EXISTS'); return { createSchema({ @@ -122,7 +123,7 @@ module.exports = (baseProvider, options, app) => { tags, schemaTags, }) { - const transientStatement = transient ? ' TRANSIENT' : ''; + const transientStatement = preSpace(transient && 'TRANSIENT'); const dataRetentionStatement = !isNaN(dataRetention) && dataRetention ? `\n\tDATA_RETENTION_TIME_IN_DAYS=${dataRetention}` : ''; const managedAccessStatement = managedAccess ? '\n\tWITH MANAGED ACCESS' : ''; @@ -138,6 +139,8 @@ module.exports = (baseProvider, options, app) => { comment: commentStatement, }); + const joinPackages = packages => packages.map(({ packageName }) => `'${packageName}'`).join(', '); + const getParameters = payload => { if (!payload) { return; @@ -153,8 +156,7 @@ module.exports = (baseProvider, options, app) => { const handlerStatement = handler ? `\n\tHANDLER = '${handler}'` : ''; - const joinPackages = () => packages.map(({ packageName }) => `'${packageName}'`).join(', '); - const packagesStatement = packages ? `\n\tPACKAGES = (${joinPackages()})` : ''; + const packagesStatement = packages ? `\n\tPACKAGES = (${joinPackages(packages)})` : ''; return `${runtimeVersionStatement}${handlerStatement}${packagesStatement}`; }; @@ -220,7 +222,7 @@ module.exports = (baseProvider, options, app) => { const stagesStatements = stages.map(stage => assignTemplates(templates.createStage, { name: getFullName(currentSchemaName, getName(isCaseSensitive, stage.name)), - temporary: stage.temporary ? ' TEMPORARY' : '', + temporary: preSpace(stage.temporary && 'TEMPORARY'), url: stage.url ? `\n\tURL=${stage.url}` : '', storageIntegration: stage.storageIntegration ? `\n\tSTORAGE_INTEGRATION=${stage.storageIntegration}` @@ -275,35 +277,39 @@ module.exports = (baseProvider, options, app) => { createTable(tableData, isActivated) { const schemaName = _.get(tableData, 'schemaData.schemaName'); - const temporary = tableData.temporary ? ' TEMPORARY' : ''; - const transient = tableData.transient && !tableData.temporary ? ' TRANSIENT' : ''; - const orReplace = tableData.orReplace ? ' OR REPLACE' : ''; - const tableIfNotExists = tableData.tableIfNotExists ? ' IF NOT EXISTS' : ''; - const clusterKeys = !_.isEmpty(tableData.clusteringKey) - ? ' CLUSTER BY (' + - (isActivated - ? foreignKeysToString(tableData.isCaseSensitive, tableData.clusteringKey) - : foreignActiveKeysToString(tableData.isCaseSensitive, tableData.clusteringKey)) + - ')' - : ''; - const partitionKeys = !_.isEmpty(tableData.partitioningKey) - ? ' PARTITION BY (' + - (isActivated - ? foreignKeysToString( - tableData.isCaseSensitive, - tableData.partitioningKey.map(key => ({ - name: `${getName(tableData.isCaseSensitive, key.name)}`, - isActivated: key.isActivated, - })), - ) - : mergeKeys(tableData.partitioningKey)) + - ')' - : ''; - const comment = tableData.comment ? ` COMMENT=${escapeString(scriptFormat, tableData.comment)}` : ''; - const copyGrants = tableData.copyGrants ? ` COPY GRANTS` : ''; - const dataRetentionTime = tableData.dataRetentionTime - ? ` DATA_RETENTION_TIME_IN_DAYS=${tableData.dataRetentionTime}` - : ''; + const temporary = preSpace(tableData.temporary && 'TEMPORARY'); + const transient = preSpace(tableData.transient && !tableData.temporary && 'TRANSIENT'); + const orReplace = preSpace(tableData.orReplace && 'OR REPLACE'); + const tableIfNotExists = preSpace(tableData.tableIfNotExists && 'IF NOT EXISTS'); + + const clusterKeys = preSpace( + !_.isEmpty(tableData.clusteringKey) && + 'CLUSTER BY (' + + (isActivated + ? foreignKeysToString(tableData.isCaseSensitive, tableData.clusteringKey) + : foreignActiveKeysToString(tableData.isCaseSensitive, tableData.clusteringKey)) + + ')', + ); + const partitionKeys = preSpace( + !_.isEmpty(tableData.partitioningKey) && + 'PARTITION BY (' + + (isActivated + ? foreignKeysToString( + tableData.isCaseSensitive, + tableData.partitioningKey.map(key => ({ + name: `${getName(tableData.isCaseSensitive, key.name)}`, + isActivated: key.isActivated, + })), + ) + : mergeKeys(tableData.partitioningKey)) + + ')', + ); + + const comment = preSpace(tableData.comment && `COMMENT=${escapeString(scriptFormat, tableData.comment)}`); + const copyGrants = preSpace(tableData.copyGrants && 'COPY GRANTS'); + const dataRetentionTime = preSpace( + tableData.dataRetentionTime && `DATA_RETENTION_TIME_IN_DAYS=${tableData.dataRetentionTime}`, + ); const stageFileFormat = tableData.fileFormat ? tab( 'STAGE_FILE_FORMAT = ' + @@ -327,9 +333,8 @@ module.exports = (baseProvider, options, app) => { isCaseSensitive: tableData.isCaseSensitive, }); - if (tableData.dynamic) { - const dynamicTableOptions = getDynamicTableProps({ - iceberg: tableData.iceberg, + if (tableData.dynamic || tableData.iceberg) { + const tableExtraOptions = getTableExtraProps({ tableData, tagsStatement, clusterKeys, @@ -344,7 +349,7 @@ module.exports = (baseProvider, options, app) => { tableIfNotExists, name: tableData.fullName, transient, - ...dynamicTableOptions, + ...tableExtraOptions, }); } else if (tableData.selectStatement) { return assignTemplates(templates.createAsSelect, { @@ -365,18 +370,19 @@ module.exports = (baseProvider, options, app) => { tableOptions: addOptions([clusterKeys, copyGrants, tagsStatement]), }); } else if (tableData.external) { - const location = tableData.externalOptions.location - ? ' WITH LOCATION=' + tableData.externalOptions.location - : ''; - const refreshOnCreate = tableData.externalOptions.REFRESH_ON_CREATE - ? ' REFRESH_ON_CREATE=' + tableData.externalOptions.REFRESH_ON_CREATE - : ''; - const autoRefresh = tableData.externalOptions.AUTO_REFRESH - ? ' AUTO_REFRESH=' + tableData.externalOptions.AUTO_REFRESH - : ''; - const pattern = tableData.externalOptions.PATTERN - ? ' PATTERN=' + tableData.externalOptions.PATTERN - : ''; + const location = preSpace( + tableData.externalOptions.location && 'WITH LOCATION=' + tableData.externalOptions.location, + ); + const refreshOnCreate = preSpace( + tableData.externalOptions.REFRESH_ON_CREATE && + 'REFRESH_ON_CREATE=' + tableData.externalOptions.REFRESH_ON_CREATE, + ); + const autoRefresh = preSpace( + tableData.externalOptions.AUTO_REFRESH && 'AUTO_REFRESH=' + tableData.externalOptions.AUTO_REFRESH, + ); + const pattern = preSpace( + tableData.externalOptions.PATTERN && 'PATTERN=' + tableData.externalOptions.PATTERN, + ); return assignTemplates(templates.createExternalTable, { name: tableData.fullName, @@ -408,6 +414,8 @@ module.exports = (baseProvider, options, app) => { name: tableData.fullName, temporary, transient, + tableIfNotExists, + orReplace, tableOptions: addOptions( [clusterKeys, stageFileFormat, copyOptions, dataRetentionTime, copyGrants, tagsStatement], comment, @@ -427,21 +435,22 @@ module.exports = (baseProvider, options, app) => { name: columnDefinition.name, type: decorateType(columnDefinition.type, columnDefinition), collation: getCollation(columnDefinition.type, columnDefinition.collation), - default: !_.isUndefined(columnDefinition.default) - ? ' DEFAULT ' + - getDefault({ - scriptFormat, - type: columnDefinition.type, - defaultValue: columnDefinition.default, - }) - : '', + default: preSpace( + !_.isUndefined(columnDefinition.default) && + 'DEFAULT ' + + getDefault({ + scriptFormat, + type: columnDefinition.type, + defaultValue: columnDefinition.default, + }), + ), autoincrement: getAutoIncrement(columnDefinition.type, 'AUTOINCREMENT', columnDefinition.autoincrement), identity: getAutoIncrement(columnDefinition.type, 'IDENTITY', columnDefinition.identity), - not_nul: !columnDefinition.nullable ? ' NOT NULL' : '', + not_nul: preSpace(!columnDefinition.nullable && 'NOT NULL'), inline_constraint: getInlineConstraint(columnDefinition), - comment: columnDefinition.comment - ? ` COMMENT ${escapeString(scriptFormat, columnDefinition.comment)}` - : '', + comment: preSpace( + columnDefinition.comment && `COMMENT ${escapeString(scriptFormat, columnDefinition.comment)}`, + ), tag: getTagStatement({ tags: columnDefinition.columnTags, isCaseSensitive: columnDefinition.isCaseSensitive, @@ -555,8 +564,8 @@ module.exports = (baseProvider, options, app) => { : undefined; return assignTemplates(templates.createView, { - secure: viewData.secure ? ' SECURE' : '', - materialized: viewData.materialized ? ' MATERIALIZED' : '', + secure: preSpace(viewData.secure && 'SECURE'), + materialized: preSpace(viewData.materialized && 'MATERIALIZED'), name: getFullName(schemaName, viewData.name), column_list: viewColumnsToString(columnList, isActivated), copy_grants: viewData.copyGrants ? 'COPY GRANTS\n' : '', @@ -685,9 +694,10 @@ module.exports = (baseProvider, options, app) => { name: sequence.name || undefined, start: sequence.sequenceStart || DEFAULT_SNOWFLAKE_SEQUENCE_START, increment: sequence.sequenceIncrement || DEFAULT_SNOWFLAKE_SEQUENCE_INCREMENT, - comment: sequence.sequenceComments - ? ` COMMENT=${escapeString(scriptFormat, sequence.sequenceComments)}` - : '', + comment: preSpace( + sequence.sequenceComments && + `COMMENT=${escapeString(scriptFormat, sequence.sequenceComments)}`, + ), }), ) .filter(sequence => sequence.name) @@ -701,9 +711,10 @@ module.exports = (baseProvider, options, app) => { formatTypeOptions: clean( getFormatTypeOptions(fileFormat.fileFormat, fileFormat.formatTypeOptions), ), - comment: fileFormat.fileFormatComments - ? ` COMMENT=${escapeString(scriptFormat, fileFormat.fileFormatComments)}` - : '', + comment: preSpace( + fileFormat.fileFormatComments && + `COMMENT=${escapeString(scriptFormat, fileFormat.fileFormatComments)}`, + ), }), ) .filter(fileFormat => fileFormat.name) @@ -822,8 +833,10 @@ module.exports = (baseProvider, options, app) => { transient: firstTab.transient, external: firstTab.external, dynamic: firstTab.dynamic, - dynamicTableProps: { - iceberg: firstTab.iceberg, + iceberg: firstTab.iceberg, + orReplace: firstTab.orReplace, + tableIfNotExists: firstTab.tableIfNotExists, + tableExtraProps: { warehouse: firstTab.warehouse, targetLag: firstTab.targetLag, refreshMode: firstTab.refreshMode, @@ -1106,7 +1119,7 @@ module.exports = (baseProvider, options, app) => { }; createAndPushStatement(isNameChanged, { - ifExists: ' IF EXISTS', + ifExists: preSpace('IF EXISTS'), name: oldName, option: 'RENAME TO ', optionValue: getName(isCaseSensitive, tag.name), @@ -1118,27 +1131,27 @@ module.exports = (baseProvider, options, app) => { }); createAndPushStatement(!isAllowedValuesDropped && !_.isEmpty(droppedAllowedValues), { - ifExists: ' IF EXISTS', + ifExists: preSpace('IF EXISTS'), name: newName, option: 'DROP', optionValue: getTagAllowedValues({ allowedValues: droppedAllowedValues }), }); createAndPushStatement(!_.isEmpty(newAllowedValues), { - ifExists: ' IF EXISTS', + ifExists: preSpace('IF EXISTS'), name: newName, option: 'ADD', optionValue: getTagAllowedValues({ allowedValues: newAllowedValues }), }); createAndPushStatement(isCommentDropped, { - ifExists: ' IF EXISTS', + ifExists: preSpace('IF EXISTS'), name: newName, option: 'UNSET COMMENT', }); createAndPushStatement(isCommentChanged, { - ifExists: ' IF EXISTS', + ifExists: preSpace('IF EXISTS'), name: newName, option: 'SET COMMENT = ', optionValue: toString(tag.description), diff --git a/forward_engineering/helpers/alterScriptHelpers/commonScript.js b/forward_engineering/helpers/alterScriptHelpers/commonScript.js index 767d011d..f2e67515 100644 --- a/forward_engineering/helpers/alterScriptHelpers/commonScript.js +++ b/forward_engineering/helpers/alterScriptHelpers/commonScript.js @@ -1,5 +1,6 @@ const _ = require('lodash'); const { escapeString } = require('../../utils/escapeString'); +const { preSpace } = require('../../utils/preSpace'); module.exports = ({ getName, getFullName, templates, assignTemplates, tab }) => { const getSchemaFullName = (database, schemaName, isCaseSensitive) => { @@ -20,7 +21,7 @@ module.exports = ({ getName, getFullName, templates, assignTemplates, tab }) => const tableName = getName(isCaseSensitive, newName); const tableFullName = getFullName(schemaFullName, tableName); - return assignTemplates(template, { dynamic: dynamic ? ' DYNAMIC' : '', name: tableFullName }); + return assignTemplates(template, { dynamic: preSpace(dynamic && 'DYNAMIC'), name: tableFullName }); }; const getAlterSchemaName = ({ script, data }) => { @@ -76,7 +77,7 @@ module.exports = ({ getName, getFullName, templates, assignTemplates, tab }) => const value = getValue({ key, data, propValue }, 'setProperty'); const statement = `${mapKeyToKeyword[key]} = ${value}`; - return Boolean(index) ? tab(statement) : statement; + return index ? tab(statement) : statement; }); if (!_.isEmpty(setPropertyData)) { @@ -99,7 +100,7 @@ module.exports = ({ getName, getFullName, templates, assignTemplates, tab }) => const unsetPropertyData = unsetProperty.map((key, index) => { key = mapKeyToKeyword[key]; - return Boolean(index) ? `${key}` : `${key}`; + return `${key}`; }); if (!_.isEmpty(unsetPropertyData)) { diff --git a/forward_engineering/helpers/columnDefinitionHelper.js b/forward_engineering/helpers/columnDefinitionHelper.js index 19ca7329..372f0cb9 100644 --- a/forward_engineering/helpers/columnDefinitionHelper.js +++ b/forward_engineering/helpers/columnDefinitionHelper.js @@ -1,6 +1,7 @@ const templates = require('../configs/templates'); const _ = require('lodash'); const { escapeString } = require('../utils/escapeString'); +const { preSpace } = require('../utils/preSpace'); module.exports = app => { const assignTemplates = app.require('@hackolade/ddl-fe-utils').assignTemplates; @@ -113,7 +114,7 @@ module.exports = app => { }; const getUnique = columnDefinition => { - return columnDefinition.unique && !columnDefinition.compositeUniqueKey ? ' UNIQUE' : ''; + return preSpace(columnDefinition.unique && !columnDefinition.compositeUniqueKey && 'UNIQUE'); }; const getPrimaryKey = columnDefinition => { @@ -121,7 +122,7 @@ module.exports = app => { return ''; } - return ' PRIMARY KEY'; + return preSpace('PRIMARY KEY'); }; const getInlineConstraint = columnDefinition => { @@ -135,7 +136,7 @@ module.exports = app => { expression: columnDefinition.expression ? `(${columnDefinition.expression})` : `(value:${columnDefinition.name}::${columnDefinition.type})`, - comment: columnDefinition.comment ? ` COMMENT ${escapeString(columnDefinition.comment)}` : '', + comment: preSpace(columnDefinition.comment && `COMMENT ${escapeString(columnDefinition.comment)}`), }); return { statement: externalColumnStatement, isActivated: columnDefinition.isActivated }; diff --git a/forward_engineering/helpers/tableHelper.js b/forward_engineering/helpers/tableHelper.js index 7e0b4cff..f7f6f6ee 100644 --- a/forward_engineering/helpers/tableHelper.js +++ b/forward_engineering/helpers/tableHelper.js @@ -1,4 +1,5 @@ const _ = require('lodash'); +const { preSpace } = require('../utils/preSpace'); module.exports = app => { const { tab } = app.require('@hackolade/ddl-fe-utils').general; @@ -52,7 +53,9 @@ module.exports = app => { return ''; } - return `TARGET_LAG = ${targetLagDownstream ? 'DOWNSTREAM' : `'${targetLagAmount} ${targetLagTimeSpan}'`}\n`; + const targetLagValue = targetLagDownstream ? 'DOWNSTREAM' : `'${targetLagAmount} ${targetLagTimeSpan}'`; + + return `TARGET_LAG = ${targetLagValue}\n`; } function getSelectStatement(selectStatement) { @@ -62,9 +65,8 @@ module.exports = app => { return `AS\n${selectStatement.split('\n').map(mapStatement).join('')}`; } - const getDynamicTableProps = ({ + const getTableExtraProps = ({ tableData, - transient, tagsStatement, clusterKeys, comment, @@ -72,21 +74,26 @@ module.exports = app => { copyGrants, columnDefinitions, }) => { - if (!tableData.dynamicTableProps) { + if (!tableData.tableExtraProps) { return {}; } - const { selectStatement } = tableData; const { - targetLag, - warehouse, - refreshMode, - initialize, - maxDataExtensionTime, - externalVolume, - catalog, - baseLocation, - } = tableData.dynamicTableProps; + iceberg, + dynamic, + transient, + selectStatement, + tableExtraProps: { + targetLag, + warehouse, + refreshMode, + initialize, + maxDataExtensionTime, + externalVolume, + catalog, + baseLocation, + }, + } = tableData; return { targetLag: getTargetLag(targetLag), @@ -106,6 +113,9 @@ module.exports = app => { copyGrants: copyGrants ? `${copyGrants.trim()}\n` : '', comment: comment ? `${comment.trim()}\n` : '', tagsStatement: tagsStatement ? `${tagsStatement.trim()}\n` : '', + transient: preSpace(transient && 'TRANSIENT'), + iceberg: preSpace(iceberg && 'ICEBERG'), + dynamic: preSpace(dynamic && 'DYNAMIC'), }; }; @@ -115,6 +125,6 @@ module.exports = app => { addOptions, getAtOrBefore, mergeKeys, - getDynamicTableProps, + getTableExtraProps, }; }; diff --git a/forward_engineering/helpers/tagHelper.js b/forward_engineering/helpers/tagHelper.js index be970fcd..d2838c30 100644 --- a/forward_engineering/helpers/tagHelper.js +++ b/forward_engineering/helpers/tagHelper.js @@ -3,6 +3,7 @@ */ const { differenceBy, some, partition, isEmpty } = require('lodash'); +const { preSpace } = require('../utils/preSpace'); module.exports = ({ getName, toString }) => { /** @@ -33,7 +34,7 @@ module.exports = ({ getName, toString }) => { .map(({ value }) => toString(value)) .join(', '); - return isEmpty(values) ? '' : ` ALLOWED_VALUES ${values}`; + return preSpace(!isEmpty(values) && `ALLOWED_VALUES ${values}`); }; /** diff --git a/forward_engineering/utils/preSpace.js b/forward_engineering/utils/preSpace.js new file mode 100644 index 00000000..b51aa66b --- /dev/null +++ b/forward_engineering/utils/preSpace.js @@ -0,0 +1,3 @@ +const preSpace = str => (str ? ` ${str}` : ''); + +module.exports = { preSpace }; diff --git a/properties_pane/entity_level/entityLevelConfig.json b/properties_pane/entity_level/entityLevelConfig.json index 574349fc..4b872c3b 100644 --- a/properties_pane/entity_level/entityLevelConfig.json +++ b/properties_pane/entity_level/entityLevelConfig.json @@ -159,7 +159,14 @@ making sure that you maintain a proper JSON format. { "propertyName": "Dynamic", "propertyKeyword": "dynamic", - "propertyType": "checkbox" + "propertyType": "checkbox", + "dependency": { + "type": "not", + "values": { + "key": "external", + "value": true + } + } }, { "propertyName": "Or replace", @@ -168,10 +175,6 @@ making sure that you maintain a proper JSON format. "disabledOnCondition": { "key": "tableIfNotExists", "value": true - }, - "dependency": { - "key": "dynamic", - "value": true } }, { @@ -182,10 +185,6 @@ making sure that you maintain a proper JSON format. "disabledOnCondition": { "key": "orReplace", "value": true - }, - "dependency": { - "key": "dynamic", - "value": true } }, { @@ -193,8 +192,17 @@ making sure that you maintain a proper JSON format. "propertyKeyword": "iceberg", "propertyType": "checkbox", "dependency": { - "key": "dynamic", - "value": true + "type": "not", + "values": [ + { + "key": "external", + "value": true + }, + { + "key": "transient", + "value": true + } + ] } }, { @@ -268,7 +276,20 @@ making sure that you maintain a proper JSON format. { "propertyName": "Transient", "propertyKeyword": "transient", - "propertyType": "checkbox" + "propertyType": "checkbox", + "dependency": { + "type": "not", + "values": [ + { + "key": "iceberg", + "value": true + }, + { + "key": "external", + "value": true + } + ] + } }, { "propertyName": "Refresh Mode", @@ -293,7 +314,24 @@ making sure that you maintain a proper JSON format. { "propertyName": "External", "propertyKeyword": "external", - "propertyType": "checkbox" + "propertyType": "checkbox", + "dependency": { + "type": "not", + "values": [ + { + "key": "dynamic", + "value": true + }, + { + "key": "iceberg", + "value": true + }, + { + "key": "transient", + "value": true + } + ] + } }, { "propertyName": "Cluster by",