UNPKG

@sap/hdbext

Version:

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

190 lines (162 loc) 6.63 kB
'use strict'; var assert = require('assert'); var async = require('async'); var _ = require('lodash'); var hdb = require('@sap/hana-client'); var hdbPromise = require('@sap/hana-client/extension/Promise.js'); var safeSql = require('./safe-sql'); var debug = require('debug')('hdbext:client-factory'); module.exports.createConnection = createConnection; module.exports.createConnectionPromise = createConnectionPromise; function createConnection(options, callback) { options = normalizeOptions(options); let serverNode = getServerNode(options); debug(`createConnection() start for createConnection ${serverNode}`); var client = hdb.createConnection(options); debug(`HANA client created for createConnection ${serverNode}`); async.series([ function (cb) { debug(`Connect to HANA ${serverNode}`); client.connect(function(err){ if (err) { debug(`Failed to connect to HANA ${serverNode}:`, err); return cb(err); } debug(`Successfully connected to HANA ${serverNode}`); if (Object.prototype.hasOwnProperty.call(options, 'autoCommit')) { debug(`Set AutoCommit to ${options.autoCommit}`); try { client.setAutoCommit(options.autoCommit); debug(`AutoCommit applied for ${serverNode}`); } catch (err2) { debug(`Failed to set AutoCommit for ${serverNode}:`, err2); return cb(err2); } } else { debug(`No AutoCommit option provided for ${serverNode}`); } debug(`Connection setup step completed for createConnection ${serverNode}`); cb(null); }); }, function (cb) { var xsAppUser = options['sessionVariable:XS_APPLICATIONUSER']; if (!xsAppUser) { debug(`No XS_APPLICATIONUSER provided for createConnection ${serverNode}; skipping session variable setup`); return cb(null); } client.exec("SET 'XS_APPLICATIONUSER' = " + safeSql.stringLiteral(xsAppUser), function (err) { if (err) { debug(`Failed to set XS_APPLICATIONUSER for ${serverNode} createConnection:`, err); return cb(err); } debug(`XS_APPLICATIONUSER session variable set for ${serverNode} createConnection`); cb(null); }); } ], function (err) { if (err) { debug('Error in createConnection', err); debug(`Disconnecting client for ${serverNode} because createConnection failed`); client.disconnect(function (e) { if (e) { debug('Error while closing connection.', e); } else { debug(`Client disconnected for ${serverNode}`); } }); debug(`createConnection() returning error for ${serverNode}`); return callback(err); } debug(`createConnection() succeeded for ${serverNode}`); callback(null, client); }); } async function createConnectionPromise(options) { options = normalizeOptions(options); let serverNode = getServerNode(options); var conn = hdb.createConnection(); debug(`Connect to HANA ${serverNode}`); try { await hdbPromise.connect(conn, options); debug(`Successfully connected to HANA ${serverNode}`); } catch (err) { debug(`Failed to connect to HANA ${serverNode}:`, err); throw err; } if (Object.prototype.hasOwnProperty.call(options, 'autoCommit')) { debug(`Set AutoCommit to ${options.autoCommit}`); try { conn.setAutoCommit(options.autoCommit); } catch (err) { debug(`Failed to set AutoCommit for ${serverNode}:`, err); tryCloseConnection(conn); throw err; } } var xsAppUser = options['sessionVariable:XS_APPLICATIONUSER']; if (xsAppUser) { try { await hdbPromise.exec(conn, "SET 'XS_APPLICATIONUSER' = " + safeSql.stringLiteral(xsAppUser)); debug('Successfully set XS_APPLICATIONUSER session variable'); } catch (err) { debug('Failed to set XS_APPLICATIONUSER:', err); tryCloseConnection(conn); throw err; } } return conn; } async function tryCloseConnection(conn) { try { await hdbPromise.close(conn); } catch (err) { debug('Failed to close connection:', err); } } function getServerNode(hanaOptions){ if (hanaOptions.serverNode){ return hanaOptions.serverNode; } return `${hanaOptions.host}:${hanaOptions.port}`; } function normalizeOptions(options) { assert(_.isObject(options), 'options should be an object'); options = _.clone(options); assert(!Object.prototype.hasOwnProperty.call(options, 'autoCommit') || _.isBoolean(options.autoCommit), 'options.autoCommit should be a boolean'); if (options.schema) { options.currentSchema = safeSql.identifier(options.schema); delete options.schema; } if (options.locale) { options.locale = options.locale.replace(/-/g, '_'); } if (!options.hosts && options.db_hosts) { assert(Array.isArray(options.db_hosts), 'options.db_hosts should be an array'); options.hosts = options.db_hosts; delete options.db_hosts; } if (!options.ca && options.certificate) { options.ca = [options.certificate]; delete options.certificate; } if (!Object.prototype.hasOwnProperty.call(options, 'sslValidateCertificate') && Object.prototype.hasOwnProperty.call(options, 'validate_certificate')) { assert(_.isBoolean(options.validate_certificate), 'options.validate_certificate should be a boolean'); options.sslValidateCertificate = options.validate_certificate; delete options.validate_certificate; } assert(!Object.prototype.hasOwnProperty.call(options, 'encrypt') || _.isBoolean(options.encrypt), 'options.encrypt should be a boolean'); if (!options.sslHostNameInCertificate && options.hostname_in_certificate) { assert(_.isString(options.hostname_in_certificate), 'options.hostname_in_certificate should be a string'); options.sslHostNameInCertificate = options.hostname_in_certificate; delete options.hostname_in_certificate; } if (!options.cert && options.client_authentication_certificate) { assert(_.isString(options.client_authentication_certificate), 'options.client_authentication_certificate should be a string'); options.cert = options.client_authentication_certificate; delete options.client_authentication_certificate; } if (!options.key && options.client_authentication_private_key) { assert(_.isString(options.client_authentication_private_key), 'options.client_authentication_private_key should be a string'); options.key = options.client_authentication_private_key; delete options.client_authentication_private_key; } return options; }