diff --git a/CHANGELOG.json b/CHANGELOG.json index eb5e346..9448815 100644 --- a/CHANGELOG.json +++ b/CHANGELOG.json @@ -3,9 +3,11 @@ "date": "2023-08-25", "version": "3.202308.1", "Changed": [ - "Major CAP version 7.1.2", + "[CAP version 7.1.2](https://cap.cloud.sap/docs/releases/jul23)", "Fixed Web Socket Error Handling", - "Upgrade to SAPUI5 1.117.1" + "Upgrade to [SAPUI5 1.117.1](https://sapui5.hana.ondemand.com/#/topic/029d3b4a39c84384be6398c444f7e06a)", + "Fix [Issue #111](https://github.com/SAP-samples/hana-developer-cli-tool-example/issues/111) - add checks on container and group names for createContainer", + "Complete [Issue #83](https://github.com/SAP-samples/hana-developer-cli-tool-example/issues/83) - add support for SQL and Calculation view parameters" ] }, { diff --git a/CHANGELOG.md b/CHANGELOG.md index 84634b4..8a306ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/). +## [3.202308.1] - 2023-08-25 + +**Changed** + +- [CAP version 7.1.2](https://cap.cloud.sap/docs/releases/jul23) +- Fixed Web Socket Error Handling +- Upgrade to [SAPUI5 1.117.1](https://sapui5.hana.ondemand.com/#/topic/029d3b4a39c84384be6398c444f7e06a) +- Fix [Issue #111](https://github.com/SAP-samples/hana-developer-cli-tool-example/issues/111) - add checks on container and group names for createContainer +- Complete [Issue #83](https://github.com/SAP-samples/hana-developer-cli-tool-example/issues/83) - add support for SQL and Calculation view parameters + ## [3.202307.1] - 2023-07-10 **Changed** diff --git a/bin/inspectView.js b/bin/inspectView.js index f311578..6814708 100644 --- a/bin/inspectView.js +++ b/bin/inspectView.js @@ -114,10 +114,13 @@ export async function viewInspect(prompts) { let object = await dbInspect.getView(db, schema, prompts.view) let fields = [] + let parameters = [] if (await dbInspect.isCalculationView(db, schema, prompts.view)) { fields = await dbInspect.getCalcViewFields(db, schema, prompts.view, object[0].VIEW_OID) + parameters = await dbInspect.getCalcViewParameters(db, schema, prompts.view, object[0].VIEW_OID) } else { fields = await dbInspect.getViewFields(db, object[0].VIEW_OID) + parameters = await dbInspect.getViewParameters(db, object[0].VIEW_OID) } // @ts-ignore @@ -130,6 +133,10 @@ export async function viewInspect(prompts) { results.basic = object[0] console.log("\n") base.outputTableFancy(fields) + if (parameters && parameters.length > 0){ + results.parameters = parameters + base.outputTableFancy(parameters) + } results.fields = fields break case 'sql': { @@ -153,13 +160,13 @@ export async function viewInspect(prompts) { break } case 'cds': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) results.cds = cdsSource console.log(highlight(cdsSource)) break } case 'json': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` console.log(highlight(cds.compile.to.json(cds.parse(cdsSource)))) break @@ -185,27 +192,27 @@ export async function viewInspect(prompts) { break } case 'yaml': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` console.log(highlight(cds.compile.to.yaml(cds.parse(cdsSource)))) break } case 'cdl': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` // @ts-ignore console.log(highlight(cds.compile.to.cdl(cds.parse(cdsSource)))) break } case 'graphql': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` // @ts-ignore console.log(highlight(cds.compile.to.gql(cds.parse(cdsSource)))) break } case 'edmx': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` let metadata = await cds.compile.to.edmx(cds.parse(cdsSource), { version: 'v4', @@ -215,7 +222,7 @@ export async function viewInspect(prompts) { break } case 'annos': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` let metadata = await cds.compile.to.edmx(cds.parse(cdsSource), { // @ts-ignore @@ -226,7 +233,7 @@ export async function viewInspect(prompts) { break } case 'edm': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` console.log(highlight(JSON.stringify(cds.compile.to.edm(cds.parse(cdsSource)), null, 4))) break @@ -247,7 +254,7 @@ export async function viewInspect(prompts) { break } case 'openapi': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` try { // @ts-ignore @@ -269,7 +276,7 @@ export async function viewInspect(prompts) { } } case 'jsdoc': { - let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema) + let cdsSource = await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) cdsSource = `service HanaCli { ${cdsSource} } ` try { // @ts-ignore diff --git a/utils/dbInspect.js b/utils/dbInspect.js index 07346e5..c7a9a4b 100644 --- a/utils/dbInspect.js +++ b/utils/dbInspect.js @@ -195,6 +195,58 @@ export async function getViewFields(db, viewOid) { return fields } +/** + * Get View Parameters and Metadata + * @param {object} db - Database Connection + * @param {string} schema - Schema + * @param {string} viewId - View Unique ID + * @param {string} viewOid - View Unique ID + * @returns {Promise} + */ +export async function getCalcViewParameters(db, schema, viewId, viewOid) { + base.debug(`getCalcViewParameters ${schema} ${viewId}`) + //Select Fields + const statement = await db.preparePromisified( + `SELECT SCHEMA_NAME, QUALIFIED_NAME as "VIEW_NAME", VARIABLE_NAME AS "PARAMETER_NAME", + COLUMN_TYPE, COLUMN_TYPE_D as "DATA_TYPE_NAME", + COLUMN_SQL_TYPE, VALUE_TYPE, MANDATORY, DESCRIPTION, + PLACEHOLDER_NAME, DEFAULT_VALUE, SCHEMA_NAME, QUALIFIED_NAME, IS_INPUT_ENABLED, + VARIABLE_TYPE, VARIABLE_SUB_TYPE + FROM _SYS_BI.BIMC_VARIABLE_VIEW + WHERE SCHEMA_NAME LIKE ? + AND QUALIFIED_NAME = ?`) + let parameters = await db.statementExecPromisified(statement, [schema, viewId]) + for (let parameter of parameters) { + let temp1 = parameter.COLUMN_SQL_TYPE.split("(") + if(temp1.length > 1){ + let temp2 = temp1[1].split(")") + parameter.LENGTH = temp2[0] + }else{ + parameter.LENGTH = 0 + } + } + + return parameters +} + +/** + * Get View Parameters and Metadata + * @param {object} db - Database Connection + * @param {string} viewOid - View Unique ID + * @returns {Promise} + */ +export async function getViewParameters(db, viewOid) { + base.debug(`getViewParameters ${viewOid}`) + //Select Fields + const statement = await db.preparePromisified( + `SELECT SCHEMA_NAME, VIEW_NAME, VIEW_OID, PARAMETER_NAME, DATA_TYPE_ID, DATA_TYPE_NAME, + LENGTH, SCALE, POSITION, HAS_DEFAULT_VALUE + FROM VIEW_PARAMETERS + WHERE VIEW_OID = ?`) + let parameters = await db.statementExecPromisified(statement, [viewOid]) + return parameters +} + /** * Get DB Table Details * @param {object} db - Database Connection @@ -442,9 +494,10 @@ export let results = { * @param {string} type - DB Object type * @param {string} [schema] - Schema * @param {string} [parent] - Calling context which impacts formatting + * @param {object} [parameters] - View Parameters * @returns {Promise} */ -export async function formatCDS(db, object, fields, constraints, type, schema, parent) { +export async function formatCDS(db, object, fields, constraints, type, schema, parent, parameters) { base.debug(`formatCDS ${type}`) let cdstable = "" let originalName @@ -477,11 +530,150 @@ export async function formatCDS(db, object, fields, constraints, type, schema, p } } if (options.useQuoted){ - newName && (cdstable += `Entity ![${newName}] {\n`) + newName && (cdstable += `Entity ![${newName}] `) }else{ - newName && (cdstable += `Entity ${newName} {\n`) + newName && (cdstable += `Entity ${newName} `) } + if (parameters && parameters.length > 0){ + cdstable += `(` + for (let parameter of parameters) { + cdstable += `${parameter.PARAMETER_NAME} : ` + if (options.useHanaTypes) { + switch (parameter.DATA_TYPE_NAME) { + case "NVARCHAR": + cdstable += `String(${parameter.LENGTH})` + break + case "NCLOB": + cdstable += "LargeString" + break + case "VARBINARY": + cdstable += `Binary(${parameter.LENGTH})` + break + case "BLOB": + cdstable += "LargeBinary" + break + case "INTEGER": + cdstable += "Integer" + break + case "BIGINT": + cdstable += "Integer64" + break + case "DECIMAL": + cdstable += parameter.SCALE ? `Decimal(${parameter.LENGTH}, ${parameter.SCALE})` : `Decimal(${parameter.LENGTH})` + break + case "DOUBLE": + cdstable += "Double" + break + case "DATE": + cdstable += "Date" + break + case "TIME": + cdstable += "Time" + break + case "SECONDDATE": + cdstable += "String" + break + case "TIMESTAMP": + if (parent === 'preview') { + cdstable += "String" + } else { + cdstable += "Timestamp" + } + break + case "BOOLEAN": + cdstable += "Boolean" + break + // hana types + case "SMALLINT": + case "TINYINT": + case "SMALLDECIMAL": + case "REAL": + case "CLOB": + cdstable += `hana.${parameter.DATA_TYPE_NAME}` + break + case "CHAR": + case "NCHAR": + case "BINARY": + cdstable += `hana.${parameter.DATA_TYPE_NAME}(${parameter.LENGTH})` + break + case "VARCHAR": + cdstable += `hana.${parameter.DATA_TYPE_NAME}(${parameter.LENGTH})` + break + case "ST_POINT": + case "ST_GEOMETRY": + cdstable += `hana.${parameter.DATA_TYPE_NAME}(${await getGeoColumns(db, object[0], parameter, type)})` + break + default: + cdstable += `**UNSUPPORTED TYPE - ${parameter.DATA_TYPE_NAME}` + } + } else { + switch (parameter.DATA_TYPE_NAME) { + case "NVARCHAR": + cdstable += `String(${parameter.LENGTH})` + break + case "NCLOB": + cdstable += "LargeString" + break + case "VARBINARY": + cdstable += `Binary(${parameter.LENGTH})` + break + case "BLOB": + cdstable += "LargeBinary" + break + case "INTEGER": + cdstable += "Integer" + break + case "BIGINT": + cdstable += "Integer64" + break + case "TINYINT": + cdstable += "UInt8" + break + case "SMALLINT": + cdstable += "Int16" + break + case "DECIMAL": + cdstable += parameter.SCALE ? `Decimal(${parameter.LENGTH}, ${parameter.SCALE})` : `Decimal(${parameter.LENGTH})` + break + case "DOUBLE": + cdstable += "Double" + break + case "DATE": + cdstable += "Date" + break + case "TIME": + cdstable += "Time" + break + case "SECONDDATE": + cdstable += "String" + break + case "TIMESTAMP": + if (parent === 'preview') { + cdstable += "String" + } else { + cdstable += "Timestamp" + } + break + case "BOOLEAN": + cdstable += "Boolean" + break + case "VARCHAR": + // backward compatible change + cdstable += `String(${parameter.LENGTH})` + break + default: + cdstable += `**UNSUPPORTED TYPE - ${parameter.DATA_TYPE_NAME}` + } + } + cdstable += ", " + } + cdstable = cdstable.slice(0, -2) + cdstable += `)` + + } + //closing entity + cdstable += `{\n` // if modified real table names will be stored in synonyms if (newName !== originalName) { diff --git a/utils/massConvert.js b/utils/massConvert.js index 8546e61..b82fc13 100644 --- a/utils/massConvert.js +++ b/utils/massConvert.js @@ -205,7 +205,7 @@ async function hdbtableViews(prompts, viewResults, wss, db, schema, replacer, zi let object = await dbInspect.getView(db, schema, view.VIEW_NAME) let fields = [] if (await dbInspect.isCalculationView(db, schema, view.VIEW_NAME)) { - fields = await dbInspect.getCalcViewFields(db, schema, view.VIEW_NAME, object[0].VIEW_OID) + fields = await dbInspect.getCalcViewFields(db, schema, view.VIEW_NAME, object[0].VIEW_OID) } else { fields = await dbInspect.getViewFields(db, object[0].VIEW_OID) } @@ -399,12 +399,15 @@ async function cdsViews(prompts, viewResults, wss, db, schema, cdsSource, logOut broadcast(wss, view.VIEW_NAME, i / viewResults.length * 100) let object = await dbInspect.getView(db, schema, view.VIEW_NAME) let fields = [] + let parameters = [] if (await dbInspect.isCalculationView(db, schema, view.VIEW_NAME)) { fields = await dbInspect.getCalcViewFields(db, schema, view.VIEW_NAME, object[0].VIEW_OID) + parameters = await dbInspect.getCalcViewParameters(db, schema, view.VIEW_NAME, object[0].VIEW_OID) } else { fields = await dbInspect.getViewFields(db, object[0].VIEW_OID) + parameters = await dbInspect.getViewParameters(db, object[0].VIEW_OID) } - cdsSource += await dbInspect.formatCDS(db, object, fields, null, "view", schema) + cdsSource += await dbInspect.formatCDS(db, object, fields, null, "view", schema, null, parameters) viewProgressBar.itemDone(view.VIEW_NAME) logOutput.push({ object: view.VIEW_NAME, status: 'Success' })