diff --git a/forward_engineering/configs/types.js b/forward_engineering/configs/types.js index 99098ad5..318cad7c 100644 --- a/forward_engineering/configs/types.js +++ b/forward_engineering/configs/types.js @@ -117,4 +117,7 @@ module.exports = { TABLE: { mode: 'table', }, + JSON: { + format: 'semi-structured', + }, }; diff --git a/package.json b/package.json index 39a7b0dc..495c5328 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "2016", "2017", "2019", - "2022" + "2022", + "2025" ] }, "features": { diff --git a/polyglot/adapter.json b/polyglot/adapter.json index 9ddbbfdc..3a8ce65d 100644 --- a/polyglot/adapter.json +++ b/polyglot/adapter.json @@ -94,6 +94,19 @@ "from": { "childType": "timestamp_ntz" }, "to": { "mode": "datetime2", "childType": "datetime" } }, + /** + * It is a bit tricky adapter. Here we rely on the type detection priority of application. Keyword "mode" has higher + * priority, so it will be used first and when available (in SQL Server 2025 and higher) it will be used. When not available + * it will try to use "childType" and convert the type to "varchar" which is available in all version of SQL Server. + */ + { + "from": { "type": "json" }, + "to": { + "hasMaxLength": true, + "childType": "varchar", + "mode": "json" + } + }, ["convertLengthToHasMaxLength", 8001], [ "renameBlockItemProperties", @@ -108,29 +121,5 @@ } ] ] - }, - "postConvert": { - "modify": { - "field": [ - { - "from": { - "type": "jsonObject" - }, - "to": { - "hasMaxLength": true, - "mode": "varchar" - } - }, - { - "from": { - "type": "jsonArray" - }, - "to": { - "hasMaxLength": true, - "mode": "varchar" - } - } - ] - } } } diff --git a/properties_pane/field_level/fieldLevelConfig.json b/properties_pane/field_level/fieldLevelConfig.json index af6bf17b..bc1398ba 100644 --- a/properties_pane/field_level/fieldLevelConfig.json +++ b/properties_pane/field_level/fieldLevelConfig.json @@ -5123,6 +5123,90 @@ making sure that you maintain a proper JSON format. "propertyType": "details", "template": "textarea" } + ], + "json": [ + "name", + "code", + "schemaId", + "type", + { + "propertyName": "JSON Type", + "propertyKeyword": "physicalType", + "propertyType": "select", + "hidden": true + }, + { + "propertyName": "JSON Types", + "propertyKeyword": "subtype", + "propertyType": "select", + "options": [ + { + "name": "object", + "value": "object" + }, + { + "name": "array", + "value": "array" + } + ], + "defaultValue": "object" + }, + { + "propertyName": "Min Properties", + "propertyKeyword": "minProperties", + "propertyType": "numeric", + "dependency": { + "key": "subtype", + "value": "object" + } + }, + { + "propertyName": "Max Properties", + "propertyKeyword": "maxProperties", + "propertyType": "numeric", + "dependency": { + "key": "subtype", + "value": "object" + } + }, + { + "propertyName": "Default", + "propertyKeyword": "default", + "propertyType": "text" + }, + { + "propertyName": "Default constraint name", + "propertyKeyword": "defaultConstraintName", + "propertyType": "text" + }, + { + "propertyName": "Comments", + "propertyKeyword": "description", + "propertyTooltip": "comments", + "addTimestampButton": false, + "propertyType": "details", + "template": "textarea" + }, + { + "propertyName": "Not null", + "propertyKeyword": "required", + "enableForReference": true, + "propertyType": "checkbox", + "defaultValue": false + }, + "foreignCollection", + "foreignField", + "relationshipType", + "sample", + { + "propertyName": "Remarks", + "propertyKeyword": "comments", + "shouldValidate": false, + "propertyTooltip": "remarks", + "addTimestampButton": true, + "propertyType": "details", + "template": "textarea" + } ] } } diff --git a/properties_pane/model_level/modelLevelConfig.json b/properties_pane/model_level/modelLevelConfig.json index 935a2caa..0fe611ed 100644 --- a/properties_pane/model_level/modelLevelConfig.json +++ b/properties_pane/model_level/modelLevelConfig.json @@ -71,7 +71,7 @@ making sure that you maintain a proper JSON format. "shouldValidate": false, "propertyTooltip": "DB version", "propertyType": "select", - "options": ["2008", "2012", "2014", "2016", "2017", "2019", "2022"], + "options": ["2008", "2012", "2014", "2016", "2017", "2019", "2022", "2025"], "disabledOption": false }, { diff --git a/reverse_engineering/reverseEngineeringService/helpers/containsJson.js b/reverse_engineering/reverseEngineeringService/helpers/containsJson.js index 90e7252d..4215ecb0 100644 --- a/reverse_engineering/reverseEngineeringService/helpers/containsJson.js +++ b/reverse_engineering/reverseEngineeringService/helpers/containsJson.js @@ -1,5 +1,9 @@ const containsJson = ({ tableInfo }) => tableInfo.some(item => { + if (item['DATA_TYPE'] === 'json') { + return true; + } + if (item['DATA_TYPE'] !== 'nvarchar') { return false; } diff --git a/reverse_engineering/reverseEngineeringService/helpers/defineJSONTypes.js b/reverse_engineering/reverseEngineeringService/helpers/defineJSONTypes.js index 74d6f48e..3eb37f16 100644 --- a/reverse_engineering/reverseEngineeringService/helpers/defineJSONTypes.js +++ b/reverse_engineering/reverseEngineeringService/helpers/defineJSONTypes.js @@ -16,7 +16,7 @@ const defineType = value => { }; const handleField = (name, properties, cellValue) => { - if (!cellValue || properties.mode !== 'nvarchar') { + if (!cellValue || (properties.mode !== 'nvarchar' && properties.type !== 'json')) { return { [name]: properties }; } @@ -68,7 +68,7 @@ const defineJSONTypes = row => jsonSchema => { }; const getColumnValue = (firstRow, fieldName, fieldProperties, rows) => { - if (!['varchar', 'nvarchar'].includes(fieldProperties.mode)) { + if (!['varchar', 'nvarchar', 'json'].includes(fieldProperties.mode)) { return firstRow[fieldName]; } const complexValueRow = rows.find(row => { diff --git a/reverse_engineering/reverseEngineeringService/helpers/reverseTableColumn.js b/reverse_engineering/reverseEngineeringService/helpers/reverseTableColumn.js index 153e5e7a..925e84a4 100644 --- a/reverse_engineering/reverseEngineeringService/helpers/reverseTableColumn.js +++ b/reverse_engineering/reverseEngineeringService/helpers/reverseTableColumn.js @@ -39,7 +39,7 @@ const handleType = type => { case 'xml': case 'cursor': case 'rowversion': - return { type }; + case 'json': default: return { type }; } diff --git a/types/json.json b/types/json.json new file mode 100644 index 00000000..d670a3a2 --- /dev/null +++ b/types/json.json @@ -0,0 +1,69 @@ +{ + "name": "json", + "erdAbbreviation": "", + "dtdAbbreviation": "{...}", + "parentType": "jsonObject", + "hiddenOnEntity": "view", + "jsonType": { + "order": 2, + "name": "json", + "jsonRoot": true + }, + "defaultValues": { + "primaryKey": false, + "additionalProperties": false, + "mode": "json", + "subtype": "object", + "properties": [] + }, + "subtypes": { + "object": { + "parentType": "jsonObject", + "childValueType": ["jsonString", "jsonNumber", "jsonObject", "jsonArray", "jsonBoolean", "jsonNull"] + }, + "array": { + "parentType": "jsonArray", + "childValueType": ["jsonString", "jsonNumber", "jsonObject", "jsonArray", "jsonBoolean", "jsonNull"] + } + }, + "dependency": { + "type": "not", + "values": [ + { + "level": "model", + "key": "dbVersion", + "value": "2008" + }, + { + "level": "model", + "key": "dbVersion", + "value": "2012" + }, + { + "level": "model", + "key": "dbVersion", + "value": "2014" + }, + { + "level": "model", + "key": "dbVersion", + "value": "2016" + }, + { + "level": "model", + "key": "dbVersion", + "value": "2017" + }, + { + "level": "model", + "key": "dbVersion", + "value": "2019" + }, + { + "level": "model", + "key": "dbVersion", + "value": "2022" + } + ] + } +} diff --git a/types/object.json b/types/object.json index 8c3de96d..3c40fd04 100644 --- a/types/object.json +++ b/types/object.json @@ -23,7 +23,8 @@ "table", "reference", "multiple", - "object" + "object", + "json" ] } }