/** Utility functions used by DataPersister implementations * @since 2015-2-4 */ class DbUtil implements DataPersister.UtilConfig { /** Predefined log verbosity levels: * `log.NONE`: No logging. * `log.ERROR`: Log errors. * `log.DEBUG`: Verbose logging. */ public static logLevels = { NONE: 0, ERROR: 1, DEBUG: 2 }; NONE: number; ERROR: number; DEBUG: number; public verbosity: number; public trace: DataPersister.DbLogger | undefined = null; public logTimings: any; // Create a deferred object public defer: () => DataPersister.SimpleDeferred; public whenAll: (promises: ArrayLike>) => PsPromise; private dbTypeName: string; isDatabase: (db: any) => db is T; /** DB Utility configuration: * @param dbTypeName the name to show in error message (ex: 'WebSQL') * @param dbToStringId the Object.prototype.toString() name of the type (ex: '[Database]' for WebSQL instances). NOTE: this should match type * @param settings configuration object with the following properties: * `defer`: specifies the function that constructs a deferred object, such as: * - Promise (native browser/node.js implementation) * - [`when.js`](https://github.com/cujojs/when) * - [`Q.js`](https://github.com/kriskowal/q) * - [`jQuery's Deferred`](http://api.jquery.com/category/deferred-object/) * - Other... * `whenAll`: a Promise.all() style function for the promises returned by the 'defer' object * `trace`: specifies the object used for logging messages. Default is `window.console`. * `verbosity`: specifies verbosity of logging (NONDE, ERROR or DEBUG). Default is `log.NONE`. * `logTimings`: whether to log query timings */ constructor(dbTypeName: string, dbToStringId: string, settings: DataPersister.UtilConfig) { this.NONE = DbUtil.logLevels.NONE; this.ERROR = DbUtil.logLevels.ERROR; this.DEBUG = DbUtil.logLevels.DEBUG; this.verbosity = this.NONE; this.logTimings = settings.logTimings; this.defer = settings.defer; this.whenAll = settings.whenAll; this.dbTypeName = dbTypeName; this.isDatabase = (db: any): db is T => this._toString(db) === dbToStringId; if (!this.isFunction(settings.defer)) { throw new Error("no 'defer' promise function option provided to " + dbTypeName + " adapter"); } if (settings.trace != null && this.isFunction(settings.trace.log)) { this.trace = settings.trace; } if (typeof settings.verbosity !== "undefined") { this.verbosity = settings.verbosity; } } // Internal Functions _toString(obj: any): string { return Object.prototype.toString.call(obj); } isString(fn: any): fn is string { return this._toString(fn) === "[object String]"; } isFunction(fn: any): fn is Function { return this._toString(fn) === "[object Function]"; } isPromise(obj: any): obj is PromiseLike { return obj && this.isFunction(obj.then); } /** Calls `onSuccess` or `onError` when `promise` is resolved. * Returns a new promise that is resolved/rejected based on the * values returned from the callbacks. */ public pipe(p: PsPromise, onSuccess: (arg: T) => U, onError?: (err: any) => V): PsPromise { var self = this; var dfd = this.defer(); p.then(function (val) { var res: U = onSuccess(val); if (self.isPromise(res)) { res.then(dfd.resolve, dfd.reject); } else { dfd.resolve(res); } }, function (err) { if (onError) { err = onError(err); } if (self.isPromise(err)) { err.then(dfd.resolve, dfd.reject); } else { dfd.reject(err); } }); return dfd.promise; } /** Log statement if level > verbosity * Usage: * log(DEBUG, "Calling function", functionName); * log(ERROR, "Something horrible happened:", error); */ public log(level: number, ...args: any[]): void { var trc = this.trace; if (level <= this.verbosity && trc != null) { args.unshift(this.dbTypeName); if (this.isFunction(trc.text)) { trc.text(args, "color: purple"); } else if (level === this.ERROR && this.isFunction(trc.error)) { trc.error(args); } else if (this.isFunction(trc.log)) { trc.log(args); } } } public setConsole(console: DataPersister.DbLogger): void { this.trace = console; } public rejectError(dfd: DataPersister.SimpleDeferred, error: string | Error, options?: { exception?: any; sqlError?: SQLError; }): PsPromise { if (typeof error === "string") { error = new Error(error); } if (options != null) { if (options.exception) (error).exception = options.exception; if (options.sqlError) (error).sqlError = options.sqlError; } this.log(this.ERROR, "ERROR: " + ((error).exception || ((error).sqlError ? ((error).sqlError).message : (error).sqlError) || error.message)); dfd.reject(error); return dfd.promise; } public static getReadOptionsOrDefault(opts: DataPersister.ReadOptions | null | undefined, defaultOpts: DataPersister.ReadOptions | null | undefined): DataPersister.ReadOptions { var defaultDataColumnName = (defaultOpts != null && defaultOpts.dataColumnName) || null; var defaultDecompress = (defaultOpts != null && defaultOpts.decompress) || false; var defaultIsChunks = (defaultOpts != null && defaultOpts.isChunks) || false; return { dataColumnName: opts != null ? (opts.dataColumnName || defaultDataColumnName) : defaultDataColumnName, decompress: opts != null ? opts.decompress : defaultDecompress, isChunks: opts != null ? opts.isChunks : defaultIsChunks, }; } public static getWriteOptionsOrDefault(opts: DataPersister.WriteOptions | null | undefined, defaultOpts: DataPersister.WriteOptions | null | undefined): DataPersister.WriteOptions { var defaultCompress = (defaultOpts != null && defaultOpts.compress) || false; var defaultKeyAutoGenerate = (defaultOpts != null && defaultOpts.keyAutoGenerate) || null; var defaultKeyGetter = (defaultOpts != null && defaultOpts.keyGetter) || null; var defaultKeyColumn = (defaultOpts != null && defaultOpts.keyColumn) || null; var defaultGroupByKey = (defaultOpts != null && defaultOpts.groupByKey) || null; var defaultDataColumnName = (defaultOpts != null && defaultOpts.dataColumnName) || null; var defaultChunkSize = (defaultOpts != null && defaultOpts.maxObjectsPerChunk) || null; var defaultDeleteIfExists = (defaultOpts != null && defaultOpts.deleteIfExists) || false; return { compress: opts != null ? opts.compress : defaultCompress, keyAutoGenerate: opts != null ? opts.keyAutoGenerate : defaultKeyAutoGenerate, keyGetter: opts != null ? opts.keyGetter : defaultKeyGetter, keyColumn: opts != null ? opts.keyColumn : defaultKeyColumn, groupByKey: opts != null ? opts.groupByKey : defaultGroupByKey, dataColumnName: opts != null ? (opts.dataColumnName || defaultDataColumnName) : defaultDataColumnName, maxObjectsPerChunk: opts != null ? (opts.maxObjectsPerChunk || defaultChunkSize) : defaultChunkSize, deleteIfExists: opts != null ? opts.deleteIfExists : defaultDeleteIfExists, }; } /** Create a timer that uses window.performance.now() * @param name the new timer's name */ public static newTimer(name: string) { var useWnd = typeof window !== "undefined"; var startMillis = (useWnd ? window.performance.now() : new Date().getTime()); var inst = { name: name, startMillis: startMillis, endMillis: null, measure: () => { var endMillis = (useWnd ? window.performance.now() : new Date().getTime()); var durationMillis = endMillis - startMillis; inst.endMillis = endMillis; return durationMillis; }, }; return inst; } } export = DbUtil;