UNPKG

hana-cli

Version:
266 lines (247 loc) 8.98 kB
import * as base from '../base.js' import cds from '@sap/cds' /** * Database Client Abstract Super Class * @class * @constructor * @public * @classdesc Database Client Abstract Level */ export default class dbClientClass { /** * prompts current value * @type {typeof import("prompt")} */ #prompts /** * CDS connection options * @type {Object} */ #optionsCDS /** * CDS connection object - returned from cds.connect.to or hdb module instance * @type {Object} */ #db /** * Database Client type/flavor * @type {String} */ #clientType = 'generic' /** * Create an instance of the database client specific to the prompt profile * @param {typeof import("prompt")} prompts - input prompts current value */ constructor(prompts, optionsCDS) { this.#prompts = prompts this.#optionsCDS = optionsCDS base.setPrompts(prompts) base.debug(optionsCDS) base.debug(base.bundle.getText("debug.dbClientGenericProfile", [this.#prompts.profile])) } /** * Static Factory Method to initialize the DB Client in your selected Flavor * @param {object} prompts - processed input prompts * @returns {Promise<dbClientClass>} childClass - flavor specific DB client class instance */ static async getNewClient(prompts) { let childClass = Object if (!prompts.profile) { //HANA Without CDS prompts.profile = 'hybrid' //Default to HANA if not selected from input const { default: classAccess } = await import("./hanaDirect.js") childClass = new classAccess(prompts) } else { //CDS based connectivity process.env.CDS_ENV = prompts.profile process.env.NODE_ENV = prompts.profile let optionsCDS = cds.env.requires.db if (!optionsCDS || !optionsCDS.kind) { throw new Error(base.bundle.getText("error.cdsProjectMissing")) } const normalizedProfile = prompts.profile?.toLowerCase?.() const profileKindMap = { hana: 'hana', postgres: 'postgres', pg: 'postgres', sqlite: 'sqlite' } const expectedKind = normalizedProfile ? profileKindMap[normalizedProfile] : undefined if (expectedKind && optionsCDS.kind !== expectedKind) { throw new Error(base.bundle.getText("error.cdsProjectMissing")) } if (optionsCDS.kind === 'sqlite') { //SQLite CDS // Load actual SQLite credentials and merge them into optionsCDS if needed const conn = await import("../connections.js") const credentials = await conn.getConnOptions(prompts) if (credentials && credentials.sqlite) { optionsCDS.credentials = credentials.sqlite } const { default: classAccess } = await import("./sqlite.js") childClass = new classAccess(prompts, optionsCDS) } else if (optionsCDS.kind === 'postgres') { //PostgresSQL CDS // Load actual Postgres credentials and merge them into optionsCDS if needed const conn = await import("../connections.js") const credentials = await conn.getConnOptions(prompts) if (credentials && credentials.postgres) { optionsCDS.credentials = credentials.postgres } const { default: classAccess } = await import("./postgres.js") childClass = new classAccess(prompts, optionsCDS) } else if (optionsCDS.kind === 'hana') { //HANA CDS // Load actual HANA credentials and merge them into optionsCDS const conn = await import("../connections.js") const credentials = await conn.getConnOptions(prompts) if (credentials && credentials.hana) { optionsCDS.credentials = credentials.hana } const { default: classAccess } = await import("./hanaCDS.js") childClass = new classAccess(prompts, optionsCDS) } else { throw new Error(base.bundle.getText("error.unsupportedDbClient", [optionsCDS.kind])) } } return childClass } /** * Connect to the target database * @returns {Promise<object>} cds connection object */ async connect() { this.#db = await cds.connect.to(this.#optionsCDS) this.#connectLogging() return this.#db } /** * Disconnect from the target database */ async disconnect() { base.debug(base.bundle.getText("debug.call", ["Disconnect"])) base.debug(base.bundle.getText("debug.inGui", [base.isGui(this.#prompts)])) if (!base.isGui(this.#prompts)) { // Don't call base.end() as it exits the process base.debug(base.bundle.getText("debug.cdsExitCalled")) await cds.exit() } // Connection cleanup handled naturally } /** * Connect to the target database and set a specific Schema * @param {String} schema - Database Schema name * @returns {Promise<object>} cds connection object */ async connectTargetSchema(schema) { let optionsCDS = this.#optionsCDS optionsCDS.credentials.schema = schema this.#db = await cds.connect.to(optionsCDS) this.#connectLogging() return this.#db } /** * Set logging parameters upon connect. Deactivate most logging unless in debug mode */ #connectLogging() { if (!this.#prompts.debug) { cds.log('pool', 'log') } if (base.verboseOutput(this.#prompts)) { console.log(`${base.bundle.getText("connFile2")} ${base.bundle.getText("cds.profiles", [this.#optionsCDS.kind])} \n`) } } /** * Database specific wildcard handling * @param {String} input - database object name that needs wildcard handling */ adjustWildcard(input) { base.debug(base.bundle.getText("debug.call", ["adjustWildcard"])) if (input == "*") { input = "%" } return input } /** * TableData as JSON * @typedef {Object} TableLine * @property {String} [SCHEMA_NAME] * @property {String} TABLE_NAME * @property {String} [TABLE_OID] * @property {String} [COMMENTS] */ /** * TableData as JSON * @typedef {Array.<TableLine>} TableData */ /** * return a list of database tables * @returns {Promise<TableData>} table of database tables */ async listTables() { return } /** * Execute single SQL Statement and directly return result set * @param {string} query - SQL Statement * @param {Array<any>} [params] - Optional parameter bindings * @returns {Promise<any>} - result set object */ async execSQL(query, params){ base.debug(base.bundle.getText("debug.dbExecSqlForClient", [this.#clientType])) if (params && Array.isArray(params) && params.length > 0) { return await this.#db.run(query, params) } let results = await this.#db.run(query) return results } /** * Getter for Prompts Private Attribute * @returns {typeof import("prompt")} prompts - input prompts current value */ getPrompts() { return this.#prompts } /** * Getter for CDS or HDB database object Private Attribute * @returns @type {Object} */ getDB() { return this.#db } /** * Getter for database kind/flavor Private Attribute * @returns @type {String} Database Kind / Flavor */ getKind() { if (this.#optionsCDS) { return this.#optionsCDS.kind } return "" } /** * Setter for CDS or HDB database object Private Attribute * @param @type {Object} db */ setDB(db) { this.#db = db } /** * From Input parameters, calculate the schema that should be used for the rest of this operation * @param @type {typeof import("prompt")} prompts - input prompts current value * @param @type {Object} optionsCDS - CDS based Connection Options */ schemaCalculation(prompts, optionsCDS) { let schema = "" if (!prompts.schema || prompts.schema === '**CURRENT_SCHEMA**') { if (optionsCDS && optionsCDS.credentials && optionsCDS.credentials.schema) { schema = optionsCDS.credentials.schema } else { schema = "public" } } else if (prompts.schema === '*') { schema = "%" } else { schema = prompts.schema } return schema } }