UNPKG

@sap/hdbext

Version:

Hana-client extension library and utility functions for using SAP HANA in node.js

135 lines (118 loc) 4.91 kB
'use strict'; var VError = require('verror'); var debug = require('debug')('hdbext:sp'); var StoredProcedure = require('./StoredProcedure'); module.exports = loadPromise; async function loadPromise(client, schema, name) { var procInfo = { schema: null, name: name, metadata: null }; function resolveSchema() { return new Promise ((resolve, reject) => { client.exec('SELECT CURRENT_SCHEMA FROM DUMMY', function (err, rs) { if (err) { return reject(err); } schema = rs[0].CURRENT_SCHEMA; resolve (schema); }); }); } if (!schema) { await resolveSchema(); } async function resolveProcedureInfoPromise (schema) { procInfo.schema = schema; await fetchMetadataPromise(client, procInfo); if (procInfo.metadata.length) { return procInfo; } var exist = await checkIfProcedureExistsPromise(client, procInfo); if (exist) { debug('Procedure %s.%s does not have any parameters', procInfo.schema, procInfo.name); return procInfo; } var checkSynResult = await checkSynonymsPromise(client, procInfo); if (!checkSynResult.isSynonym) { throw new VError('Procedure %s.%s does not exist', procInfo.schema, procInfo.name); } debug('%s.%s is a synonym for %s.%s', procInfo.schema, procInfo.name, checkSynResult.schema, checkSynResult.name); // use the data of the referenced procedure procInfo.schema = checkSynResult.schema; procInfo.name = checkSynResult.name; procInfo.metadata = null; await fetchMetadataPromise(client, procInfo); return procInfo; } function buildSpFunctionPromise(procInfo) { return new Promise ((resolve) => { var sp = new StoredProcedure(client, procInfo.schema, procInfo.name, procInfo.metadata); var spFunction = StoredProcedure.prototype.exec.bind(sp); spFunction.paramsMetadata = procInfo.metadata; resolve(spFunction); }); } var procInfoPromise = await resolveProcedureInfoPromise(schema); return await buildSpFunctionPromise(procInfoPromise); } function fetchMetadataPromise(client, procInfo) { return new Promise((resolve, reject) => { var sqlProcedureMetadata = "SELECT \ PARAMS.PARAMETER_NAME, \ PARAMS.DATA_TYPE_NAME, \ PARAMS.PARAMETER_TYPE, \ PARAMS.HAS_DEFAULT_VALUE, \ PARAMS.IS_INPLACE_TYPE, \ PARAMS.TABLE_TYPE_SCHEMA, \ PARAMS.TABLE_TYPE_NAME, \ \ CASE WHEN SYNONYMS.OBJECT_NAME IS NULL THEN 'FALSE' ELSE 'TRUE' END AS IS_TABLE_TYPE_SYNONYM, \ IFNULL(SYNONYMS.OBJECT_SCHEMA, '') AS OBJECT_SCHEMA, \ IFNULL(SYNONYMS.OBJECT_NAME, '') AS OBJECT_NAME \ \ FROM SYS.PROCEDURE_PARAMETERS AS PARAMS \ LEFT JOIN SYS.SYNONYMS AS SYNONYMS \ ON SYNONYMS.SCHEMA_NAME = PARAMS.TABLE_TYPE_SCHEMA AND SYNONYMS.SYNONYM_NAME = PARAMS.TABLE_TYPE_NAME \ WHERE PARAMS.SCHEMA_NAME = ? AND PARAMS.PROCEDURE_NAME = ? \ ORDER BY PARAMS.POSITION"; client.exec(sqlProcedureMetadata, [procInfo.schema, procInfo.name], (err, metadata) => { if (err) { return reject(err); } procInfo.metadata = metadata; resolve(); }); }); } function checkSynonymsPromise (client, procInfo) { return new Promise ((resolve, reject) => { var sqlLookupSynonym = 'SELECT OBJECT_SCHEMA, OBJECT_NAME, IS_VALID FROM SYS.SYNONYMS WHERE SCHEMA_NAME = ? AND SYNONYM_NAME = ?'; client.exec(sqlLookupSynonym, [procInfo.schema, procInfo.name], function (err, rs) { if (err) { return reject(err); } var result = { isSynonym: !!rs.length }; if (!result.isSynonym) { return resolve(result); } if (rs[0].IS_VALID !== 'TRUE') { debug('Data for synonym %s.%s: %j', procInfo.schema, procInfo.name, rs[0]); return reject(new VError('Synonym %s.%s is not valid', procInfo.schema, procInfo.name)); } result.schema = rs[0].OBJECT_SCHEMA; result.name = rs[0].OBJECT_NAME; resolve(result); }); }); } function checkIfProcedureExistsPromise(client, procInfo) { return new Promise ((resolve, reject) => { var sqlCheckIfProcedureExists = 'SELECT COUNT(0) AS "count" FROM SYS.PROCEDURES WHERE SCHEMA_NAME = ? AND PROCEDURE_NAME = ?'; client.exec(sqlCheckIfProcedureExists, [procInfo.schema, procInfo.name], function (err, rs) { if (err) { return reject(err); } resolve(!!rs[0].count); }); }); }