import knex, { Knex } from "knex"; import * as path from 'path'; import * as env from "@sap/xsenv"; // const sharedLib = require('portal-cf-shared-lib'); // const cfLogger:any = sharedLib.cfLogger; // const logger = cfLogger.initLogger('portal-cf-shared-database-client/knexClient.ts'); import { CDM_RUNTIME_SCHEMA, CDM_CORE_SCHEMA, RUNTIME, CORE } from "../utils/globals"; import mode from "../utils/mode"; let databaseClientsMap = new Map(); const MAX_CLIENTS_CONNECTIONS = getEnvVariableValue('MAX_CLIENTS_CONNECTIONS', 4); export async function getTransaction(scenario:string):Promise> { const dbClient = await getDatabaseClient(scenario); const trx = await dbClient.transaction(); return trx; } export async function commitTransaction(trx:Knex.Transaction) { await trx.commit(); } export async function rollbackTransaction(trx:Knex.Transaction) { await trx.rollback(); } export default async function getDatabaseClient(scenario:string):Promise> { if (!databaseClientsMap.has(scenario)){ try { const dbClient:Knex = connectDbClient(scenario); await runMigrations(dbClient); databaseClientsMap.set(scenario, dbClient); return dbClient; } catch (err) { // logger.logMessage('error','getDatabasebClient failed. %s', logger.printObject(err)); throw err; } } return databaseClientsMap.get(scenario); } function getConnectionConfigurations(scenario:string){ let connectionConfiguration:any; let dbServiceInstanceName:string; switch(scenario){ case RUNTIME: { dbServiceInstanceName = process.env.RUNTIME_DB_INSTANCE_NAME || "portal-postgresql-db-rt"; connectionConfiguration = { dbServiceInstanceName : dbServiceInstanceName, databaseClient : "pg", schema : CDM_RUNTIME_SCHEMA } break; } case CORE: { dbServiceInstanceName = process.env.CORE_DB_INSTANCE_NAME || "portal-postgresql-db-dt"; connectionConfiguration = { dbServiceInstanceName : dbServiceInstanceName, databaseClient : "pg", schema : CDM_CORE_SCHEMA } break; } } const credentials = getDbCredentials(connectionConfiguration.dbServiceInstanceName); connectionConfiguration.credentials = credentials; // Set ssl configurations if (credentials.sslcert && credentials.sslrootcert) { connectionConfiguration.ssl = {ca: credentials.sslrootcert, cert: credentials.sslcert}; } else if (credentials.ca_base64) { connectionConfiguration.ssl = {ca: credentials.ca_base64}; } return connectionConfiguration; } async function runMigrations(dbClient:Knex) { await dbClient.schema.createSchemaIfNotExists(dbClient.client.config.searchPath[0]); await dbClient.migrate.latest(); } export async function rollbackMigrations(dbClient:Knex, scenario:string, rollbackAll:boolean = false) { const migrationDirectoryPath = mode.isTest() ? path.join(__dirname, `./testMigrations/${scenario}`) : path.join(__dirname, `./migrations/${scenario}`); const migrationsExtension = mode.isTest() ? ['.ts'] : [`.js`]; await dbClient.migrate.rollback({ directory: migrationDirectoryPath, disableMigrationsListValidation: true, loadExtensions: migrationsExtension, schemaName: dbClient.client.config.searchPath[0], tableName: "knex_migrations" }, rollbackAll); } function connectDbClient(scenario:string): Knex { const config = getConfigurationsByMode(scenario); return knex(config); } function getConfigurationsByMode(scenario:string) { const configurations = getConnectionConfigurations(scenario); const migrationDirectoryPath = mode.isTest() ? path.join(__dirname, `./testMigrations/${scenario}`) : path.join(__dirname, `./migrations/${scenario}`); const migrationsExtension = mode.isTest() ? ['.ts'] : [`.js`]; return { client: configurations.databaseClient, connection: { host: configurations?.credentials.hostname, port: configurations?.credentials.port, user: configurations?.credentials.username, password: configurations?.credentials.password, database: configurations?.credentials.dbname, ssl: configurations?.ssl }, pool: { min: 0, max: MAX_CLIENTS_CONNECTIONS }, searchPath: [configurations.schema], migrations: { directory: migrationDirectoryPath, disableMigrationsListValidation: true, loadExtensions: migrationsExtension, schemaName: configurations.schema, tableName: "knex_migrations" } } } function getDbCredentials(dbServiceInstanceName:string) { if (!dbServiceInstanceName){ throw new Error("Database service instance name is missing"); } let credentials:any = env.cfServiceCredentials(dbServiceInstanceName); return credentials; } // Get value of env variable (only for integers) function getEnvVariableValue(variableKey:string, defaultValue:number) { let value:number = defaultValue; if (process.env[variableKey]) { try { value = parseInt(process.env[variableKey]!); } catch (err) { // logger.logMessage('error', '%s is not a number: %s', variableKey, process.env[variableKey]); throw err; } } return value; }