UNPKG

ts-db-helper

Version:
317 lines 12.4 kB
import { DefaultLogger } from '../internal/default-logger'; import { Subject } from 'rxjs/Subject'; import { QueryError } from '../errors/query.error'; import { ModelManager } from './model-manager'; import { UnsatisfiedRequirementError } from '../errors/unsatisfied-requirement.error'; import { PendingDbQuery } from '../models/pending-db-query.model'; import 'rxjs/add/operator/share'; /** * @private * @class QueryManager * * @description * This class is a singleton manging query * This manager has not to be exposed, it is used to handle queries * with the connector. It stack it during connector is not ready and * release it when connector ca query * * @author Olivier Margarit * @since 0.1 */ var QueryManager = /** @class */ (function () { /** * @private * @constructor private constructor to preserve from other instance creation */ function QueryManager() { /** * @private * @property {Array<PendingDbQuery>} pendingDbQueries stack of queries to fire when the * connector is ready */ this.pendingDbQueries = []; /** * @private * @property {Array<PendingDbQuery>} pendingBatchDbQueries stack of queries to fire in a single transaction */ this.pendingBatchDbQueries = []; /** * @private * @property {boolean} isReady flag that should pas to true only when * query can be sent */ this.isReady = false; /** * @private * @property {boolean} isInitializationFailed flag to reject all queries * in case of connector activation failure */ this.isInitializationFailed = false; this.supportRowidValue = false; } Object.defineProperty(QueryManager.prototype, "logger", { get: function () { if (!this.loggerValue) { this.loggerValue = new DefaultLogger(); } return this.loggerValue; }, enumerable: true, configurable: true }); Object.defineProperty(QueryManager.prototype, "supportRowid", { get: function () { return this.supportRowidValue; }, enumerable: true, configurable: true }); /** * @static * @public * @method init is a part of the private API, config is submitted to * pass connector, model migration and other config. see {@link NgDbHelperModuleConfig} * for more informations * * @param {NgDbHelperModuleConfig} config the module configuration with connector instance and model migration * * @return {QueryManager} the initialized instance */ QueryManager.init = function (config) { var instance = QueryManager.getInstance(); instance.queryConnector = config.queryConnector; instance.modelMigration = config.modelMigration; instance.supportRowidValue = config.queryConnector.supportRowid; if (config.logger) { instance.loggerValue = config.logger; } ModelManager.version = config.version; if (config.autoIncrementVersion && ModelManager.version) { // compute auto upgrade version ModelManager.version += '.' + ModelManager.getInstance().getModelCount(); } instance.queryConnector.onReady().subscribe(function (ready) { if (ready) { instance.onQueryConnectorReady(); } else { instance.onInitializationFailure(null); } }, instance.onInitializationFailure); return instance; }; /** * @static * @public * @method getInstance to get the unique QueryManager instance * * @return {QueryManager} the instance */ QueryManager.getInstance = function () { return QueryManager.instance; }; /** * @private * @method onQueryConnectorReady is called when query connector is ready to * manage model migration then dequeuing each pending queries */ QueryManager.prototype.onQueryConnectorReady = function () { var _this = this; if (this.queryConnector && this.modelMigration) { var modelMigration_1 = this.modelMigration; this.queryConnector.getDbVersion().subscribe(function (version) { _this.logger.info('old version: ' + version); var dataModel = ModelManager.getInstance().getDataModel(); dataModel.version = ModelManager.version; _this.logger.info('new version: ' + dataModel.version); var isFailed = false; if (!version) { _this.logger.info('call init data model migration'); modelMigration_1.initModel(dataModel).subscribe(function () { _this.logger.info('init data model migration successed'); }, function (err) { isFailed = err; _this.logger.warn('init data model migration failed'); }, function () { if (isFailed) { _this.onInitializationFailure(isFailed); } else { _this.dequeuePendingRequest(); } }); } else if (version !== ModelManager.version) { _this.logger.info('call upgrade data model migration'); modelMigration_1.upgradeModel(dataModel, version).subscribe(function () { _this.logger.info('upgrade data model migration successed'); }, function (err) { isFailed = err; _this.logger.warn('upgrade data model migration failed'); }, function () { if (isFailed) { _this.onInitializationFailure(isFailed); } else { _this.dequeuePendingRequest(); } }); } else { _this.dequeuePendingRequest(); } }, function (err) { return _this.onInitializationFailure(err); }); } else { throw (new UnsatisfiedRequirementError('ModelMigration or QueryConnector object is missing, check and fix NgDbHelperModule configuration !')); } }; /** * @private * @method onInitializationFailure is called on initilization failure to cancel * all started queries and nexts * * @param {Error} err the error return by the initialization failure */ QueryManager.prototype.onInitializationFailure = function (err) { this.logger.error(err); this.isInitializationFailed = true; this.dequeuePendingRequest(); }; /** * @private * @method dequeuePendingRequest is called to dequeue pending request */ QueryManager.prototype.dequeuePendingRequest = function () { while (this.pendingDbQueries.length) { var pendingDbQuery = this.pendingDbQueries.shift(); if (pendingDbQuery) { this.executeQuery(pendingDbQuery.dbQuery, pendingDbQuery.observer); } } this.isReady = true; }; /** * @public * @method startBatch start transaction for multiple queries * @param {any} locker the locker that can fire the transaction if none is set */ QueryManager.prototype.startBatch = function (locker) { if (!this.batchLock) { this.batchLock = locker; } }; /** * @public * @method query private API to start queries, it check if queries can be executed * If initialization failed, error is sent back. If connector is not ready, query will * be stack until connector ready signal * * @param {DbQuery} dbQuery query information with params * * @return {Observable<QueryResult<any>>} in case of success, {@link QueryResult<any>} is passed * in case of failure, {@link QueryError} is passed */ QueryManager.prototype.query = function (dbQuery) { var subject = new Subject(); if (this.batchLock) { this.pendingBatchDbQueries.push({ dbQuery: dbQuery, observer: subject }); } else if (this.isReady) { this.executeQuery(dbQuery, subject); } else { this.pendingDbQueries.push(new PendingDbQuery(dbQuery, subject)); } return subject; }; /** * @public * @method queryBatch should only be called from {@link QueryBatch} function. * * @param locker the locker passed to startBatch that allow queries releasing * * @return {Observable<QueryResult<any>>} in case of success, {@link QueryResult<any>} is passed * in case of failure, {@link QueryError} is passed * * @since 0.2 */ QueryManager.prototype.execBatch = function (locker) { var queries = []; var observers = []; if (!this.batchSubject) { this.batchSubject = new Subject(); } if (this.batchLock === locker) { this.batchLock = null; } else { return this.batchSubject; } while (this.pendingBatchDbQueries.length) { var pendingQuery = this.pendingBatchDbQueries.shift(); queries.push(pendingQuery.dbQuery); observers.push(pendingQuery.observer); } var obs = this.queryConnector.queryBatch(queries); obs.map(function (res) { for (var _i = 0, observers_1 = observers; _i < observers_1.length; _i++) { var observer = observers_1[_i]; observer.next({ insertId: undefined, rowsAffected: 0, rows: { length: 0, item: function (index) { return null; }, toArray: function () { return []; } } }); observer.complete(); } return res; }); obs.share().subscribe(this.batchSubject); this.batchSubject = undefined; return obs; }; /** * @private * @method executeQuery should be called only when connector is ready * * @param {DbQuery} dbQuery query information with params * @param {Observer} observer observer to manage query callback * * @return {Observable<QueryResult<any>>} in case of success, {@link QueryResult<any>} is passed * in case of failure, {@link QueryError} is passed */ QueryManager.prototype.executeQuery = function (dbQuery, observer) { if (this.isInitializationFailed) { var error = new QueryError('query manager initialization did failed', dbQuery.query, dbQuery.params ? dbQuery.params.join(', ') : ''); observer.error(error); } else { if (this.queryConnector) { this.queryConnector.query(dbQuery).subscribe(observer); } else { throw (new UnsatisfiedRequirementError('QueryConnector object is missing, check and fix NgDbHelperModule configuration !')); } } }; /** * @static * @private * @property {QueryManager} instance private reference to the model manager instance */ QueryManager.instance = new QueryManager(); return QueryManager; }()); export { QueryManager }; //# sourceMappingURL=query-manager.js.map