UNPKG

@kitmi/data

Version:

Jacaranda Framework Data Access Model

164 lines (163 loc) 5.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return _default; } }); const _utils = require("@kitmi/utils"); const _types = require("@kitmi/types"); class DbModel { get paramToken() { return this.connector.specParamToken; } escapeId(id) { return this.connector.escapeId(id); } escapeValue(val) { return this.connector.escapeValue(val); } /** * Get the db model metadata, e.g. Entity classes. */ get meta() { return this.constructor.meta; } /** * Get the schema name. * @returns {string} */ get schemaName() { return this.meta.schemaName; } /** * Get the driver. * @returns {string} */ get driver() { return this.connector.driver; } /** * Fork the model with transaction flag. * @param {Client} transaction - Client created from beginTransaction_. * @returns {DbModel} */ fork(transaction) { const db = new this.constructor(this.app, this.connector, transaction); if (this.ctx) { db.ctx = this.ctx; } return db; } /** * Fork the model with context. * @param {Context} ctx - The context object. * @returns {DbModel} */ forkWithCtx(ctx) { const db = new this.constructor(this.app, this.connector); db.ctx = ctx.response ? this.extractFromCtx(ctx) : ctx; return db; } /** * Extract from context. * @param {Object} ctx - The http context object. * @returns {Object} */ extractFromCtx(ctx) { return _utils._.pick(ctx, [ 'request', 'header', 'session', 'state' ]); } /** * Get an entity instance by entity name. * @param {string} entityName * @returns {EntityModel} */ entity(entityName) { const modelClassName = _utils.naming.pascalCase(entityName); const EntityModel = this.meta.entities[modelClassName]; if (typeof EntityModel !== 'function') { throw new Error(`Entity "${entityName}" not found in the db model.`); } return new EntityModel(this); } /** * Run a transaction. * @param {AsyncFunction} action_ * @param {String} [purpose] * @returns {Promise} */ async transaction_(transactionFunc, purpose) { if (this.transaction != null) { // already in transaction return transactionFunc(this); } let db; try { db = this.fork(await this.connector.beginTransaction_(this.ctx, purpose)); let result = await transactionFunc(db); await db.connector.commit_(db.transaction, db.ctx, purpose); delete db.transaction; return result; } catch (error) { if (db) { await db.connector.rollback_(db.transaction, error, db.ctx, purpose); delete db.transaction; } throw error; } finally{ db.end(); } } /** * Run an action and automatically retry when failed. * @param {String} transactionName - Name of the transaction for tracking purpose. * @param {Function} action_ - The action to run. * @param {Function} onNextRetry_ - The action to run if action failed and before next retry. * @param {*} maxRetry * @param {*} interval * @returns {Promise} result */ async retry_(transactionName, action_, onRetry_, payload, maxRetry, interval) { if (this.transaction != null) { throw new _types.ApplicationError('"db.retry_" is not allowed in a transaction for performance issue.'); } let i = 0; if (maxRetry == null) maxRetry = 2; while(i++ <= maxRetry){ try { const [finished, result] = await action_(payload); if (finished) { return result; } } catch (error) { this.app.logErrorAsWarning(error, `Unable to complete "${transactionName}" transaction and will try ${maxRetry - i + 1} more times after ${interval || 0} ms.`, this.ctx ? { reqId: this.ctx.state.reqId } : null); } if (i > maxRetry) { break; } if (interval != null) { await (0, _utils.sleep_)(interval); } if (onRetry_) { await onRetry_(payload); } } throw new _types.UnexpectedState(`Failed to complete "${transactionName}" transaction after ${maxRetry} retries.`); } /** * End the model. */ end() { delete this.transaction; delete this.ctx; delete this.connector; delete this.app; } constructor(app, connector, transaction){ this.app = app; this.connector = connector; this.transaction = transaction; } } const _default = DbModel; //# sourceMappingURL=DbModel.js.map