From e14aef85939d0429abb6661876a338f57c95c8e6 Mon Sep 17 00:00:00 2001 From: ivan-m-dev Date: Thu, 5 Feb 2026 13:21:10 +0100 Subject: [PATCH 1/2] HCK-14597:add separate CREATE frow for streaming tables --- forward_engineering/config.json | 2 +- forward_engineering/helpers/columnHelper.js | 10 +- .../helpers/foreignKeyHelper.js | 151 +++++++++++++++++ .../helpers/scriptBuilder/feScriptBuilder.js | 25 ++- forward_engineering/helpers/tableHelper.js | 157 +++++++++++++++--- .../entity_level/entityLevelConfig.json | 74 +++++++++ .../field_level/fieldLevelConfig.json | 96 ++++++++++- 7 files changed, 483 insertions(+), 32 deletions(-) create mode 100644 forward_engineering/helpers/foreignKeyHelper.js diff --git a/forward_engineering/config.json b/forward_engineering/config.json index 431964aa..58c5d443 100644 --- a/forward_engineering/config.json +++ b/forward_engineering/config.json @@ -98,7 +98,7 @@ "value": { "inline": { "default": false, - "disabled": true, + "disabled": false, "disabledLabel": "" }, "separate": { diff --git a/forward_engineering/helpers/columnHelper.js b/forward_engineering/helpers/columnHelper.js index 768ba141..3d0b9375 100644 --- a/forward_engineering/helpers/columnHelper.js +++ b/forward_engineering/helpers/columnHelper.js @@ -299,8 +299,8 @@ const getTypeByProperty = } }; -const getColumn = (name, type, comment, constraints, isActivated, generatedExpression) => ({ - [name]: { type, comment, constraints, isActivated, generatedExpression }, +const getColumn = (name, type, comment, constraints, isActivated, generatedExpression, maskingFunction) => ({ + [name]: { type, comment, constraints, isActivated, generatedExpression, maskingFunction }, }); const getGeneratedExpression = (expressionData, defaultValue = '') => { @@ -370,6 +370,7 @@ const getColumns = (jsonSchema, definitions, dbVersion) => { }, property.isActivated, getGeneratedExpression(property.generatedDefaultValue, property.default), + property.maskingFunction, ), ); }, {}); @@ -403,12 +404,15 @@ const getColumnStatement = ({ isActivated, isParentActivated, generatedExpression, + maskingFunction, }) => { const commentStatement = comment ? ` COMMENT '${encodeStringLiteral(comment)}'` : ''; const constraintsStatement = constraints ? getColumnConstraintsStatement(constraints) : ''; const isColumnActivated = isParentActivated ? isActivated : true; + const maskingStatement = maskingFunction ? ` MASK ${maskingFunction}` : ''; + return commentDeactivatedStatements( - `${replaceSpaceWithUnderscore(name)} ${type}${generatedExpression}${constraintsStatement}${commentStatement}`, + `${replaceSpaceWithUnderscore(name)} ${type}${generatedExpression}${maskingStatement}${constraintsStatement}${commentStatement}`, isColumnActivated, ); }; diff --git a/forward_engineering/helpers/foreignKeyHelper.js b/forward_engineering/helpers/foreignKeyHelper.js new file mode 100644 index 00000000..07c6bbc2 --- /dev/null +++ b/forward_engineering/helpers/foreignKeyHelper.js @@ -0,0 +1,151 @@ +const _ = require('lodash'); +const schemaHelper = require('./jsonSchemaHelper'); +const { getName, getTab, commentDeactivatedStatements, prepareName } = require('../utils/general'); + +const getIdToNameHashTable = ( + relationships, + entities, + jsonSchemas, + internalDefinitions, + otherDefinitions, + relatedSchemas, +) => { + const entitiesForHashing = entities + .concat(Object.keys(relatedSchemas)) + .filter(entityId => + relationships.find( + relationship => relationship.childCollection === entityId || relationship.parentCollection === entityId, + ), + ); + + return entitiesForHashing.reduce((hashTable, entityId) => { + return { + ...hashTable, + ...schemaHelper.getIdToNameHashTable( + [ + jsonSchemas[entityId] ?? relatedSchemas[entityId], + internalDefinitions[entityId], + ...otherDefinitions, + ].filter(Boolean), + ), + }; + }, {}); +}; + +const getForeignKeyHashTable = ({ + relationships, + entities, + entityData, + jsonSchemas, + internalDefinitions, + otherDefinitions, + isContainerActivated, + relatedSchemas, +}) => { + const idToNameHashTable = getIdToNameHashTable( + relationships, + entities, + jsonSchemas, + internalDefinitions, + otherDefinitions, + relatedSchemas, + ); + + return relationships.reduce((hashTable, relationship) => { + if (!hashTable[relationship.childCollection]) { + hashTable[relationship.childCollection] = {}; + } + + const constraintName = relationship.code || relationship.name; + const parentSchema = + jsonSchemas[relationship.parentCollection] ?? relatedSchemas[relationship.parentCollection]; + const childSchema = jsonSchemas[relationship.childCollection] ?? relatedSchemas[relationship.childCollection]; + const parentDifferentSchemaName = prepareName(parentSchema?.bucketName) || ''; + const parentTableData = getTab(0, entityData[relationship.parentCollection]); + const parentTableSingleName = prepareName(getName(parentTableData) || parentSchema?.collectionName) || ''; + const parentTableName = parentDifferentSchemaName + ? `${parentDifferentSchemaName}.${parentTableSingleName}` + : parentTableSingleName; + const childTableData = getTab(0, entityData[relationship.childCollection]); + const childTableName = prepareName(getName(childTableData) || childSchema?.collectionName) || ''; + const groupKey = parentTableName + constraintName; + const childFieldActivated = relationship.childField.reduce((isActivated, field) => { + const fieldData = schemaHelper.getItemByPath(field.slice(1), childSchema); + return isActivated && _.get(fieldData, 'isActivated'); + }, true); + const parentFieldActivated = relationship.parentField.reduce((isActivated, field) => { + const fieldData = schemaHelper.getItemByPath(field.slice(1), parentSchema); + return isActivated && _.get(fieldData, 'isActivated'); + }, true); + + if (!hashTable[relationship.childCollection][groupKey]) { + hashTable[relationship.childCollection][groupKey] = []; + } + const disableNoValidate = relationship?.customProperties?.disableNoValidate; + + hashTable[relationship.childCollection][groupKey].push({ + name: relationship.name, + code: relationship.code, + disableNoValidate: disableNoValidate, + parentTableName: parentTableName, + childTableName: childTableName, + parentColumn: getPreparedForeignColumns(relationship.parentField, idToNameHashTable), + childColumn: getPreparedForeignColumns(relationship.childField, idToNameHashTable), + isActivated: + isContainerActivated && + _.get(parentTableData, 'isActivated') && + _.get(childTableData, 'isActivated') && + childFieldActivated && + parentFieldActivated, + }); + + return hashTable; + }, {}); +}; + +const getForeignKeyConstraint = ({ constraintName, childColumns, parentTableName, parentColumns }) => { + const constraintNameStatement = constraintName ? `CONSTRAINT ${prepareName(constraintName)} ` : ''; + return `${constraintNameStatement}FOREIGN KEY (${childColumns}) REFERENCES ${parentTableName}(${parentColumns})`.trim(); +}; + +const getForeignKeyStatementsByHashItem = hashItem => { + return Object.keys(hashItem || {}) + .map(groupKey => { + const keys = hashItem[groupKey]; + const firstKey = keys[0] || {}; + const keyName = firstKey.code || firstKey.name || ''; + const constraintName = keyName.includes(' ') ? `\`${keyName}\`` : keyName; + const parentTableName = firstKey.parentTableName; + const disableNoValidate = keys.some(item => item?.disableNoValidate); + const childColumns = keys.map(item => item.childColumn).join(', '); + const parentColumns = keys.map(item => item.parentColumn).join(', '); + const isActivated = firstKey.isActivated; + + const statement = getForeignKeyConstraint({ + constraintName, + childColumns, + parentTableName, + parentColumns, + disableNoValidate, + }); + + return commentDeactivatedStatements(statement, isActivated); + }) + .join(',\n'); +}; + +const getPreparedForeignColumns = (columnsPaths, idToNameHashTable) => { + if (columnsPaths.length > 0 && Array.isArray(columnsPaths[0])) { + return columnsPaths + .map(path => schemaHelper.getNameByPath(idToNameHashTable, (path || []).slice(1))) + .join(', '); + } else { + return schemaHelper.getNameByPath(idToNameHashTable, (columnsPaths || []).slice(1)); + } +}; + +module.exports = { + getForeignKeyHashTable, + getForeignKeyStatementsByHashItem, + getForeignKeyConstraint, +}; diff --git a/forward_engineering/helpers/scriptBuilder/feScriptBuilder.js b/forward_engineering/helpers/scriptBuilder/feScriptBuilder.js index 303ea04d..72121fe7 100644 --- a/forward_engineering/helpers/scriptBuilder/feScriptBuilder.js +++ b/forward_engineering/helpers/scriptBuilder/feScriptBuilder.js @@ -55,6 +55,7 @@ const { } = require('../../utils/general'); const { generateSamplesScript, generateSamplesForEntity } = require('../../sampleGeneration/sampleGenerationService'); const { getDataForSampleGeneration } = require('../../sampleGeneration/getDataForSampleGeneration'); +const foreignKeyHelper = require('../foreignKeyHelper'); /** * @param data {CoreData} @@ -136,27 +137,45 @@ const getContainerLevelEntitiesScriptDtos = }) => { const scriptDtos = []; + const foreignKeyHashTable = foreignKeyHelper.getForeignKeyHashTable({ + relationships: data.relationships, + entities: data.entities, + entityData: data.entityData, + jsonSchemas: entitiesJsonSchema, + internalDefinitions: internalDefinitions, + otherDefinitions: [modelDefinitions, externalDefinitions], + isContainerActivated: containerData[0]?.isActivated, + relatedSchemas: relatedSchemas, + }); + for (const entityId of data.entities) { const entityData = data.entityData[entityId]; - + const tableData = getTab(0, entityData); + const isStreaming = tableData?.streamingTable; const dbVersion = data.modelData[0].dbVersion; - const likeTableData = data.entityData[getTab(0, entityData)?.like]; + const likeTableData = data.entityData[tableData?.like]; const entityJsonSchema = entitiesJsonSchema[entityId]; const definitions = [internalDefinitions[entityId], modelDefinitions, externalDefinitions]; const createTableStatementArgs = [containerData, entityData, entityJsonSchema, definitions]; + const foreignKeyStatement = foreignKeyHelper.getForeignKeyStatementsByHashItem( + foreignKeyHashTable[entityId] || {}, + ); + const tableStatement = getTableStatement(app)( ...createTableStatementArgs, arePkFkConstraintsAvailable, areNotNullConstraintsAvailable, likeTableData, dbVersion, + false, + foreignKeyStatement, ); const indexScript = getIndexes(...createTableStatementArgs); let relationshipScripts = []; - if (includeRelationshipsInEntityScripts && arePkFkConstraintsAvailable) { + if (includeRelationshipsInEntityScripts && arePkFkConstraintsAvailable && !isStreaming) { const relationshipsWithThisTableAsChild = data.relationships.filter( relationship => relationship.childCollection === entityId, ); diff --git a/forward_engineering/helpers/tableHelper.js b/forward_engineering/helpers/tableHelper.js index d61db9de..c26251e9 100644 --- a/forward_engineering/helpers/tableHelper.js +++ b/forward_engineering/helpers/tableHelper.js @@ -51,29 +51,47 @@ const getCreateStatement = ({ isStreaming, orRefresh, scheduleGroup, + selectStreamingStatement, + expectations, + rowFilterGroup, + entityJsonProperties, }) => { const temporary = isTemporary ? 'TEMPORARY' : ''; const external = isExternal ? 'EXTERNAL' : ''; - const streaming = isStreaming ? 'STREAMING' : ''; - let replaceRefreshStatement = ''; - - if (isStreaming && orRefresh) { - replaceRefreshStatement = 'OR REFRESH'; - } else if (orReplace && !isStreaming) { - replaceRefreshStatement = 'OR REPLACE'; - } + const replaceStatement = orReplace ? 'OR REPLACE' : ''; const scheduleClause = isStreaming ? getScheduleClause(scheduleGroup?.[0]) : ''; const isNotExistsStatement = ifNotExists ? ' IF NOT EXISTS' : ''; const modifiersStatement = ' ' + - [replaceRefreshStatement, temporary, external, streaming] + [replaceStatement, temporary, external] .filter(d => d) .map(item => item + ' ') .join(''); + if (isStreaming) { + return getCreateStreamingStatement({ + fullTableName, + columnStatement, + primaryKeyStatement, + foreignKeyStatement, + comment, + orRefresh, + isNotExistsStatement, + isActivated, + selectStreamingStatement, + expectations, + clusteredKeys, + tableProperties, + scheduleClause, + rowFilterGroup, + partitionedByKeys, + entityJsonProperties, + }); + } + if (using && likeStatement) { return getCreateLikeStatement({ modifiersStatement, @@ -97,7 +115,6 @@ const getCreateStatement = ({ isActivated, tableOptions, isNotExistsStatement, - scheduleClause, }); } @@ -123,7 +140,6 @@ const getCreateStatement = ({ isActivated, tableOptions, isNotExistsStatement, - scheduleClause, }); } @@ -146,7 +162,6 @@ const getCreateStatement = ({ isActivated, tableOptions, isNotExistsStatement, - scheduleClause, }); }; @@ -169,7 +184,6 @@ const getCreateUsingStatement = ({ isNotExistsStatement, rowFormatStatement, storedAsStatement, - scheduleClause, }) => { return buildStatement(`CREATE${modifiersStatement}TABLE${isNotExistsStatement} ${fullTableName} (`, isActivated)( columnStatement, @@ -189,7 +203,7 @@ const getCreateUsingStatement = ({ )(checkTablePropertiesDefined(tableProperties), `TBLPROPERTIES (${getTablePropertiesClause(tableProperties)})`)( tableOptions, `OPTIONS ${tableOptions}`, - )(scheduleClause, scheduleClause)(selectStatement, `AS ${selectStatement}`)(true, ';')(); + )(selectStatement, `AS ${selectStatement}`)(true, ';')(); }; const getCreateHiveStatement = ({ @@ -211,7 +225,6 @@ const getCreateHiveStatement = ({ isActivated, tableOptions, isNotExistsStatement, - scheduleClause, }) => { const isAddBrackets = columnStatement || primaryKeyStatement || foreignKeyStatement; return buildStatement(`CREATE${modifiersStatement}TABLE${isNotExistsStatement} ${fullTableName} `, isActivated)( @@ -235,7 +248,7 @@ const getCreateHiveStatement = ({ )(checkTablePropertiesDefined(tableProperties), `TBLPROPERTIES (${getTablePropertiesClause(tableProperties)})`)( tableOptions, `OPTIONS ${tableOptions}`, - )(scheduleClause, scheduleClause)(selectStatement, `AS ${selectStatement}`)(true, ';')(); + )(selectStatement, `AS ${selectStatement}`)(true, ';')(); }; const getCreateLikeStatement = ({ @@ -253,7 +266,6 @@ const getCreateLikeStatement = ({ isNotExistsStatement, tableOptions, likeStatement, - scheduleClause, }) => { return buildStatement( `CREATE${modifiersStatement}TABLE${isNotExistsStatement} ${fullTableName} ${likeStatement} (`, @@ -267,7 +279,7 @@ const getCreateLikeStatement = ({ )(checkTablePropertiesDefined(tableProperties), `TBLPROPERTIES (${getTablePropertiesClause(tableProperties)})`)( tableOptions, `OPTIONS ${tableOptions}`, - )(location, `LOCATION '${location}'`)(scheduleClause, scheduleClause)(true, ';')(); + )(location, `LOCATION '${location}'`)(true, ';')(); }; const getClusteringKeys = (clusteredKeys, deactivatedColumnNames, isParentItemActivated) => { @@ -444,6 +456,7 @@ const getTableStatement = likeTableData, dbVersion, isCalledFromAlterScript = false, + foreignKeyStatement = null, ) => { const { getEntityTagsStatement } = require('../helpers/unityTagsHelper'); @@ -468,6 +481,17 @@ const getTableStatement = ) : ''; + let streamingSourceQuery = ''; + let dltExpectations = []; + + if (tableData.streamingTable) { + streamingSourceQuery = tableData.streamingSourceSelect || ''; + + if (tableData.dltExpectations) { + dltExpectations = Array.isArray(tableData.dltExpectations) ? tableData.dltExpectations : []; + } + } + let tableStatement = getCreateStatement({ fullTableName, isTemporary: tableData.temporaryTable, @@ -504,6 +528,11 @@ const getTableStatement = isStreaming: tableData.streamingTable, scheduleGroup: tableData.scheduleGroup, orRefresh: tableData.orRefresh, + selectStreamingStatement: streamingSourceQuery, + expectations: dltExpectations, + rowFilterGroup: tableData.rowFilterGroup, + foreignKeyStatement, + entityJsonProperties: entityJsonSchema.properties, }); if (getDBVersionNumber(dbVersion) >= Runtime.MINIMUM_UNITY_TAGS_SUPPORT_VERSION) { @@ -658,7 +687,7 @@ const buildTriggerClause = scheduleGroup => { const { triggerIntervalUnit, triggerIntervalValue } = scheduleGroup; if (triggerIntervalValue && triggerIntervalUnit) { - return `TRIGGER ON UPDATE AT MOST EVERY ${triggerIntervalValue} ${triggerIntervalUnit}`; + return `TRIGGER ON UPDATE AT MOST EVERY INTERVAL ${triggerIntervalValue} ${triggerIntervalUnit}`; } return 'TRIGGER ON UPDATE'; }; @@ -682,6 +711,96 @@ const getScheduleClause = scheduleGroup => { } }; +const getRowFilterClause = (rowFilterGroup, properties) => { + if (!Array.isArray(rowFilterGroup) || rowFilterGroup.length === 0) { + return ''; + } + + const rawFilter = rowFilterGroup[0]; + + const guidToNameMap = Object.keys(properties || {}).reduce((acc, key) => { + const property = properties[key]; + if (property.GUID) { + acc[property.GUID] = property.code || key; + } + return acc; + }, {}); + + const resolvedColumns = (rawFilter.rowFilterColumns || []) + .map(colItem => guidToNameMap[colItem.keyId]) + .filter(Boolean); + + if (rawFilter.rowFilterFunction) { + const hasColumns = resolvedColumns.length > 0; + const columns = hasColumns ? ` ON (${resolvedColumns.join(', ')})` : ''; + return `WITH ROW FILTER ${rawFilter.rowFilterFunction}${columns}`; + } + + return ''; +}; + +const getCreateStreamingStatement = ({ + fullTableName, + columnStatement, + primaryKeyStatement, + foreignKeyStatement, + comment, + orRefresh, + ifNotExists, + isActivated, + selectStreamingStatement, + expectations, + clusteredKeys, + tableProperties, + scheduleClause, + rowFilterGroup, + partitionedByKeys, + isNotExistsStatement, + entityJsonProperties, +}) => { + const createPrefix = orRefresh ? 'CREATE OR REFRESH STREAMING TABLE' : 'CREATE STREAMING TABLE'; + let tableStructureLines = [columnStatement]; + + if (expectations && expectations.length > 0) { + const expectationsSql = expectations.map(exp => { + const action = exp.expectationAction ? ` ON VIOLATION ${exp.expectationAction}` : ''; + return `CONSTRAINT ${exp.expectationName} EXPECT (${exp.expectationExpr})${action}`; + }); + tableStructureLines.push(...expectationsSql); + } + + if (primaryKeyStatement) { + tableStructureLines.push(primaryKeyStatement); + } + if (foreignKeyStatement) { + tableStructureLines.push(foreignKeyStatement); + } + + const tableStructure = tableStructureLines.filter(Boolean).join(',\n\t'); + + const commentClause = comment ? `COMMENT '${encodeStringLiteral(comment)}'` : ''; + const clusterClause = clusteredKeys ? `CLUSTER BY (${clusteredKeys})` : ''; + const partitionedStatement = partitionedByKeys ? `PARTITIONED BY (${partitionedByKeys})` : ''; + const propsClause = checkTablePropertiesDefined(tableProperties) + ? `TBLPROPERTIES (${getTablePropertiesClause(tableProperties)})` + : ''; + + const rowFilterClause = getRowFilterClause(rowFilterGroup, entityJsonProperties); + + const queryClause = selectStreamingStatement ? `AS ${selectStreamingStatement}` : ''; + + return buildStatement(`${createPrefix}${isNotExistsStatement} ${fullTableName} (`, isActivated)( + tableStructure, + tableStructure, + )(true, ')')(commentClause, commentClause)(partitionedStatement, partitionedStatement)( + clusterClause, + clusterClause, + )(propsClause, propsClause)(rowFilterClause, rowFilterClause)(scheduleClause, scheduleClause)( + queryClause, + queryClause, + )(true, ';')(); +}; + module.exports = { getTableStatement, getTablePropertiesClause, diff --git a/properties_pane/entity_level/entityLevelConfig.json b/properties_pane/entity_level/entityLevelConfig.json index 9d3d219f..36424540 100644 --- a/properties_pane/entity_level/entityLevelConfig.json +++ b/properties_pane/entity_level/entityLevelConfig.json @@ -396,6 +396,80 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Source Query", + "propertyKeyword": "streamingSourceSelect", + "propertyTooltip": "Defines the query for the streaming table. You must include the SELECT part. Example: SELECT id, name FROM STREAM(default.source_table)", + "propertyType": "details", + "template": "textarea", + "markdown": false, + "dependency": { + "key": "streamingTable", + "value": true + } + }, + { + "propertyName": "Data Quality Expectations", + "propertyKeyword": "dltExpectations", + "propertyTooltip": "Define data quality constraints (Delta Live Tables)", + "propertyType": "group", + "groupItemLimit": 10, + "dependency": { + "key": "streamingTable", + "value": true + }, + "structure": [ + { + "propertyName": "Constraint Name", + "propertyKeyword": "expectationName", + "propertyTooltip": "Unique name (e.g. valid_timestamp)", + "propertyType": "text", + "validation": { + "regex": "^[a-zA-Z_][a-zA-Z0-9_]*$" + } + }, + { + "propertyName": "Condition (SQL)", + "propertyKeyword": "expectationExpr", + "propertyTooltip": "Boolean expression (e.g. amount > 0)", + "propertyType": "details", + "template": "textarea", + "markdown": false + }, + { + "propertyName": "On Violation", + "propertyKeyword": "expectationAction", + "propertyType": "select", + "options": ["", "FAIL UPDATE", "DROP ROW"], + "defaultValue": "" + } + ] + }, + { + "propertyName": "Row Filter", + "propertyKeyword": "rowFilterGroup", + "propertyType": "group", + "groupItemLimit": 1, + "dependency": { + "key": "streamingTable", + "value": true + }, + "structure": [ + { + "propertyName": "Filter Function", + "propertyKeyword": "rowFilterFunction", + "propertyTooltip": "Full name of the UDF (e.g. default.filter_by_region)", + "propertyType": "text" + }, + { + "propertyName": "Input Columns", + "propertyKeyword": "rowFilterColumns", + "propertyTooltip": "Columns passed to the filter function", + "propertyType": "fieldList", + "template": "orderedList" + } + ] + }, { "propertyName": "Using", "propertyKeyword": "using", diff --git a/properties_pane/field_level/fieldLevelConfig.json b/properties_pane/field_level/fieldLevelConfig.json index 45b63fdf..5a432618 100644 --- a/properties_pane/field_level/fieldLevelConfig.json +++ b/properties_pane/field_level/fieldLevelConfig.json @@ -460,6 +460,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, "default", { "propertyName": "Check constraint", @@ -825,6 +831,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, { "fieldName": "Default", "fieldKeyword": "default", @@ -1019,6 +1031,12 @@ making sure that you maintain a proper JSON format. "enableForReference": true, "propertyType": "checkbox" }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, "default", { "propertyName": "Check constraint", @@ -1370,6 +1388,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, "default", { "propertyName": "Check constraint", @@ -1745,6 +1769,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, "default", { "propertyName": "Check constraint", @@ -2075,6 +2105,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, "default", { "propertyName": "Check constraint", @@ -2404,6 +2440,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, "default", { "propertyName": "Check constraint", @@ -2753,6 +2795,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, { "propertyName": "Check constraint", "propertyKeyword": "check", @@ -3123,6 +3171,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, { "propertyName": "Check constraint", "propertyKeyword": "check", @@ -3450,6 +3504,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, { "propertyName": "Check constraint", "propertyKeyword": "check", @@ -3600,12 +3660,30 @@ making sure that you maintain a proper JSON format. "propertyKeyword": "subtype", "propertyType": "select", "options": [ - { "name": "object", "value": "object" }, - { "name": "array", "value": "array" }, - { "name": "string", "value": "string" }, - { "name": "number", "value": "number" }, - { "name": "boolean", "value": "boolean" }, - { "name": "null", "value": "null" } + { + "name": "object", + "value": "object" + }, + { + "name": "array", + "value": "array" + }, + { + "name": "string", + "value": "string" + }, + { + "name": "number", + "value": "number" + }, + { + "name": "boolean", + "value": "boolean" + }, + { + "name": "null", + "value": "null" + } ], "dependency": { "key": "childType", @@ -3809,6 +3887,12 @@ making sure that you maintain a proper JSON format. } ] }, + { + "propertyName": "Masking Function", + "propertyKeyword": "maskingFunction", + "propertyTooltip": "Unity Catalog UDF to mask column data (e.g. default.mask_pii)", + "propertyType": "text" + }, { "propertyName": "Check constraint", "propertyKeyword": "check", From 54b664d451fe5243e955cb75666108f2bbfd4f36 Mon Sep 17 00:00:00 2001 From: ivan-m-dev Date: Thu, 5 Feb 2026 16:57:20 +0100 Subject: [PATCH 2/2] HCK-14597: update getRowFilterClause --- forward_engineering/helpers/tableHelper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forward_engineering/helpers/tableHelper.js b/forward_engineering/helpers/tableHelper.js index c26251e9..e4687ae8 100644 --- a/forward_engineering/helpers/tableHelper.js +++ b/forward_engineering/helpers/tableHelper.js @@ -721,7 +721,7 @@ const getRowFilterClause = (rowFilterGroup, properties) => { const guidToNameMap = Object.keys(properties || {}).reduce((acc, key) => { const property = properties[key]; if (property.GUID) { - acc[property.GUID] = property.code || key; + acc[property.GUID] = key; } return acc; }, {});