UNPKG

@bitblit/ratchet-rdbms

Version:

Ratchet tooling for working with relational databases

138 lines 5.57 kB
import { BeginTransactionCommand, CommitTransactionCommand, ExecuteStatementCommand, RollbackTransactionCommand } from "@aws-sdk/client-rds-data"; import { Logger } from "@bitblit/ratchet-common/logger/logger"; import SqlString from 'sqlstring'; export class RdsDataApiDatabaseAccess { client; cfg; _currentTransactionId; constructor(client, cfg) { this.client = client; this.cfg = cfg; } async beginTransaction() { const tmp = await this.client.send(new BeginTransactionCommand({ resourceArn: 'ss', secretArn: 'yy' })); this._currentTransactionId = tmp.transactionId; Logger.info('Started transaction %s', this._currentTransactionId); } async close() { if (!this._currentTransactionId) { Logger.info('Close called with transaction still open, rolling back'); await this.rollbackTransaction(); } return true; } async commitTransaction() { if (this._currentTransactionId) { const out = await this.client.send(new CommitTransactionCommand({ resourceArn: this.cfg.resourceArn, secretArn: this.cfg.secretArn, transactionId: this._currentTransactionId })); Logger.info('Commit transaction %s returned %j', this._currentTransactionId, out); this._currentTransactionId = null; } else { Logger.warn('Commit transaction called while no transaction in session'); } } escape(value) { const rval = SqlString.escape(value); return rval; } async modify(query, fields) { const params = RdsDataApiDatabaseAccess.toSqlParameters(fields); const tmp = await this.client.send(new ExecuteStatementCommand({ resourceArn: this.cfg.resourceArn, secretArn: this.cfg.secretArn, database: this.cfg.database, sql: query, parameters: params, includeResultMetadata: true })); const rval = { results: { changedRows: tmp.numberOfRecordsUpdated, affectedRows: tmp.numberOfRecordsUpdated }, fields: tmp.columnMetadata }; return rval; } static toSqlParameters(record) { return Object.entries(record).map(([key, val]) => { let value; if (val === null) { value = { isNull: true }; } else if (typeof val === "number") { value = { longValue: val }; } else if (typeof val === "boolean") { value = { booleanValue: val }; } else if (val instanceof Date) { value = { stringValue: val.toISOString(), typeHint: "TIMESTAMP" }; } else { value = { stringValue: String(val) }; } return { name: key, value }; }); } static fieldToValue(field) { let rval = null; if (field.isNull) { rval = null; } else if (field.stringValue !== undefined) { rval = field.stringValue; } else if (field.blobValue !== undefined) { rval = Buffer.from(field.blobValue); } else if (field.doubleValue !== undefined) { rval = field.doubleValue; } else if (field.longValue !== undefined) { rval = field.longValue; } else if (field.booleanValue !== undefined) { rval = field['booleanValue']; } ; return rval; } static parseRecords(output) { const { records, columnMetadata } = output; if (!records || !columnMetadata) return []; const rval = records.map((row) => { const obj = {}; row.forEach((field, i) => { const name = columnMetadata[i].name || `col${i}`; obj[name] = RdsDataApiDatabaseAccess.fieldToValue(field); }); return obj; }); return rval; } async query(query, fields) { const params = RdsDataApiDatabaseAccess.toSqlParameters(fields); const _tmp = await this.client.send(new ExecuteStatementCommand({ resourceArn: this.cfg.resourceArn, secretArn: this.cfg.secretArn, database: this.cfg.database, sql: query, parameters: params, includeResultMetadata: true })); Logger.info('tmp: %j cm: %j', _tmp.records, _tmp.columnMetadata); const records = RdsDataApiDatabaseAccess.parseRecords(_tmp); const rval = { results: records, fields: _tmp.columnMetadata ?? [] }; return rval; } async rollbackTransaction() { if (this._currentTransactionId) { const out = await this.client.send(new RollbackTransactionCommand({ resourceArn: this.cfg.resourceArn, secretArn: this.cfg.secretArn, transactionId: this._currentTransactionId })); Logger.info('Rollback transaction %s returned %j', this._currentTransactionId, out); this._currentTransactionId = null; } else { Logger.warn('Rollback transaction called while no transaction in session'); } } async testConnection(logTestResults) { const output = await this.query('SELECT 1 AS test_result', {}); if (logTestResults) { Logger.info('Test connection returned %j', output); } const rval = output?.results?.length ? output.results[0]['test_result'] : null; return rval; } } //# sourceMappingURL=rds-data-api-database-access.js.map