UNPKG

@naturalcycles/db-lib

Version:

Lowest Common Denominator API to supported Databases

203 lines (202 loc) 5.85 kB
import { _truncate } from '@naturalcycles/js-lib/string/string.util.js'; import { _objectAssign } from '@naturalcycles/js-lib/types'; export const dbQueryFilterOperatorValues = [ '<', '<=', '==', '!=', '>=', '>', 'in', 'not-in', 'array-contains', 'array-contains-any', ]; /** * Lowest Common Denominator Query object. * To be executed by CommonDao / CommonDB. * * Fluent API (returns `this` after each method). * * Methods do MUTATE the query object, be careful. * * <DBM> is the type of **queried** object (so e.g `key of DBM` can be used), not **returned** object. */ export class DBQuery { table; constructor(table) { this.table = table; } /** * Convenience method. */ static create(table) { return new DBQuery(table); } static fromPlainObject(obj) { return Object.assign(new DBQuery(obj.table), obj); } _filters = []; _limitValue = 0; // 0 means "no limit" _offsetValue = 0; // 0 means "no offset" _orders = []; _startCursor; _endCursor; /** * If defined - only those fields will be selected. * In undefined - all fields (*) will be returned. */ _selectedFieldNames; _groupByFieldNames; _distinct = false; filter(name, op, val) { this._filters.push({ name, op, val }); return this; } filterEq(name, val) { this._filters.push({ name, op: '==', val }); return this; } filterIn(name, val) { this._filters.push({ name, op: 'in', val }); return this; } /** * Passing 0 means "no limit". */ limit(limit) { this._limitValue = limit; return this; } offset(offset) { this._offsetValue = offset; return this; } order(name, descending) { this._orders.push({ name, descending, }); return this; } select(fieldNames) { this._selectedFieldNames = fieldNames; return this; } groupBy(fieldNames) { this._groupByFieldNames = fieldNames; return this; } distinct(distinct = true) { this._distinct = distinct; return this; } startCursor(startCursor) { this._startCursor = startCursor; return this; } endCursor(endCursor) { this._endCursor = endCursor; return this; } clone() { return _objectAssign(new DBQuery(this.table), { _filters: [...this._filters], _limitValue: this._limitValue, _offsetValue: this._offsetValue, _orders: [...this._orders], _selectedFieldNames: this._selectedFieldNames && [...this._selectedFieldNames], _groupByFieldNames: this._groupByFieldNames && [...this._groupByFieldNames], _distinct: this._distinct, _startCursor: this._startCursor, _endCursor: this._endCursor, }); } pretty() { return this.prettyConditions().join(', '); } prettyConditions() { const tokens = []; // if (this.name) { // tokens.push(`"${this.name}"`) // } if (this._selectedFieldNames) { tokens.push(`select${this._distinct ? ' distinct' : ''}(${this._selectedFieldNames.join(',')})`); } tokens.push(...this._filters.map(f => `${f.name}${f.op}${f.val}`), ...this._orders.map(o => `order by ${o.name}${o.descending ? ' desc' : ''}`)); if (this._groupByFieldNames) { tokens.push(`groupBy(${this._groupByFieldNames.join(',')})`); } if (this._offsetValue) { tokens.push(`offset ${this._offsetValue}`); } if (this._limitValue) { tokens.push(`limit ${this._limitValue}`); } if (this._startCursor) { tokens.push(`startCursor ${_truncate(this._startCursor, 8)}`); } if (this._endCursor) { tokens.push(`endCursor ${_truncate(this._endCursor, 8)}`); } return tokens; } } /** * DBQuery that has additional method to support Fluent API style. */ export class RunnableDBQuery extends DBQuery { dao; /** * Pass `table` to override table. */ constructor(dao, table) { super(table || dao.cfg.table); this.dao = dao; } async runQuery(opt) { return await this.dao.runQuery(this, opt); } async runQuerySingleColumn(opt) { return await this.dao.runQuerySingleColumn(this, opt); } async runQueryAsDBM(opt) { return await this.dao.runQueryAsDBM(this, opt); } async runQueryExtended(opt) { return await this.dao.runQueryExtended(this, opt); } async runQueryExtendedAsDBM(opt) { return await this.dao.runQueryExtendedAsDBM(this, opt); } async runQueryCount(opt) { return await this.dao.runQueryCount(this, opt); } async patchByQuery(patch, opt) { return await this.dao.patchByQuery(this, patch, opt); } async streamQueryForEach(mapper, opt) { await this.dao.streamQueryForEach(this, mapper, opt); } async streamQueryAsDBMForEach(mapper, opt) { await this.dao.streamQueryAsDBMForEach(this, mapper, opt); } streamQuery(opt) { return this.dao.streamQuery(this, opt); } streamQueryAsDBM(opt) { return this.dao.streamQueryAsDBM(this, opt); } async queryIds(opt) { return await this.dao.queryIds(this, opt); } streamQueryIds(opt) { return this.dao.streamQueryIds(this, opt); } async streamQueryIdsForEach(mapper, opt) { await this.dao.streamQueryIdsForEach(this, mapper, opt); } async deleteByQuery(opt) { return await this.dao.deleteByQuery(this, opt); } }