UNPKG

silvie

Version:

Typescript Back-end Framework

640 lines (619 loc) 21.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _pluralize = _interopRequireDefault(require("pluralize")); var _changeCase = require("change-case"); var _query = _interopRequireDefault(require("../builders/query")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } class ModelQueryBuilder { /** * Create a new instance of this model from a initial data object * @param initialData */ constructor(initialData) { if (initialData) { Object.keys(initialData).forEach(key => { this[key] = initialData[key]; }); } } /** * The table name for this model */ static get table() { if (!this.tableName) { this.tableName = (0, _changeCase.snakeCase)((0, _pluralize.default)(this.name)); } return this.tableName; } /** * Cast a RawDataPacket into the current model * @param data */ static cast(data) { return new this(data); } /** * Cast an array of RawDataPackets into the current model * @param data */ static castAll(data) { return data.map(row => this.cast(row)); } /** * Create many to many relation * @param model * @param foreignKey * @param primaryKey */ static hasMany(model, foreignKey, primaryKey) { return { type: 'HasMany', count: 'many', model, localKey: foreignKey, remoteKey: primaryKey || this.primaryKey }; } /** * Create one to one relation * @param model * @param foreignKey * @param primaryKey */ static hasOne(model, foreignKey, primaryKey) { return { type: 'HasOne', count: 'one', model, localKey: foreignKey, remoteKey: primaryKey || this.primaryKey }; } /** * Create one to many relation * @param model * @param foreignKey * @param primaryKey */ static belongsTo(model, foreignKey, primaryKey) { return { type: 'BelongsTo', count: 'one', model, remoteKey: foreignKey, localKey: primaryKey || this.primaryKey }; } /** * Creates reversed many to many relation * @param model * @param foreignKey * @param primaryKey */ static belongsToMany(model, foreignKey, primaryKey) { return { type: 'BelongsToMany', count: 'many', model, remoteKey: foreignKey, localKey: primaryKey || this.primaryKey }; } /** * Specify the relations you want to be fetched along with the main query * @param relationNames */ static with(...relationNames) { const qb = this.baseQueryBuilder; const relations = []; relationNames.forEach(relationName => { const relationPath = relationName.split('.'); let superModel = this; let relation = null; relationPath.forEach(part => { if (part in superModel.relations) { relation = superModel.relations[part]; superModel = relation.model; } else { throw new Error(`There is no relation named '${part}' on '${superModel}' model.`); } }); relations.push({ name: relationName, path: relationPath, parent: relationPath.slice(0, relationPath.length - 1).join(''), relation }); }); relations.sort((a, b) => a.path.length - b.path.length); qb.options.fetchingRelations = relations; qb.options.processFinalQuery = finalQueryBuilder => { const queryBuilders = {}; const rootQuery = finalQueryBuilder.clone(); rootQuery.options.fetchingRelations = []; rootQuery.options.alongQueries = []; rootQuery.options.processFinalQuery = null; relations.forEach(rel => { const { relation } = rel; const parentQuery = (rel.parent ? queryBuilders[rel.parent] : rootQuery).clone(); queryBuilders[rel.name] = relation.model.select(`${relation.model.table}.*`).join(parentQuery, `${relation.model.tableName}.${relation.localKey}`, `t.${relation.remoteKey}`, `t`); }); Object.values(queryBuilders).forEach(queryBuilder => { finalQueryBuilder.alongWith(queryBuilder); }); }; return qb; } static processResults(results, queryBuilder) { if (queryBuilder.options.fetchingRelations.length === 0) { return this.castAll(results); } const relations = queryBuilder.options.fetchingRelations; const mainData = this.castAll(results[0]); const relationsData = {}; relations.forEach((relation, index) => { relationsData[relation.name] = results[index + 1]; }); relations.reverse(); relations.forEach(rel => { if (rel.parent) { relationsData[rel.parent].forEach(item => { const relationData = rel.relation.model.castAll(relationsData[rel.name].filter(row => row[rel.relation.localKey] === item[rel.relation.remoteKey])); item[rel.path.slice(-1)[0]] = rel.relation.count === 'one' ? relationData[0] || null : relationData; }); } else { mainData.forEach(item => { const relationData = rel.relation.model.castAll(relationsData[rel.name].filter(row => row[rel.relation.localKey] === item[rel.relation.remoteKey])); item[rel.name] = rel.relation.count === 'one' ? relationData[0] || null : relationData; }); } }); return mainData; } static extendBaseQueryBuilder(queryBuilder) { // This does nothing by default return queryBuilder; } /** * Configures a query builder to match this model table and configuration */ static get baseQueryBuilder() { const queryBuilder = new _query.default(this.table).extend({ processData: this.processResults.bind(this), useTimestamps: this.useTimestamps, createTimestamp: this.createTimestamp, updateTimestamp: this.updateTimestamp, useSoftDeletes: this.useSoftDeletes, softDeleteTimestamp: this.softDeleteTimestamp }); if (this.extendBaseQueryBuilder instanceof Function) { this.extendBaseQueryBuilder(queryBuilder); } return queryBuilder; } /** * Configures a query builder to match with this model's primary key * @param queryBuilder Query builder instance to add conditions to * @param thisRef Uses the current instance properties to get primary key values * @param ids ID or IDs to search for */ static primaryKeyCondition(queryBuilder, thisRef, ids) { if (thisRef) { if (this.primaryKey instanceof Array) { this.primaryKey.forEach(key => { queryBuilder.where(key, thisRef[key]); }); } else { queryBuilder.where(this.primaryKey, thisRef[this.primaryKey]); } } else if (this.primaryKey instanceof Array) { ids.forEach(id => { queryBuilder.orWhere(cb => { this.primaryKey.forEach((key, index) => { cb.where(key, id[index]); }); }); }); } else { queryBuilder.whereIn(this.primaryKey, ids); } return queryBuilder; } /** * Insert a data array into the table and return with [LastInsertId, AffectedRows] * @param data * @param ignore Weather to ignore duplicate keys or not */ static insert(data, ignore) { return this.baseQueryBuilder.insert(data, ignore); } /** * Delete a record of this kind (uses soft delete if it is enabled in model) * @param id */ static delete(id) { return this.primaryKeyCondition(this.baseQueryBuilder, null, [id]).delete(this.useSoftDeletes); } /** * Delete all the records of this kind (uses soft delete if it is enabled in model) * @param ids */ static deleteAll(...ids) { return this.primaryKeyCondition(this.baseQueryBuilder, null, ids).delete(this.useSoftDeletes); } /** * Restore a soft deleted record of this kind * @param id */ static restore(id) { return this.primaryKeyCondition(this.baseQueryBuilder, null, [id]).restore(); } /** * Restore soft deleted records of this kind * @param ids */ static restoreAll(...ids) { return this.primaryKeyCondition(this.baseQueryBuilder, null, ids).delete(this.useSoftDeletes); } static bulkUpdate(data, keys = [], silent = false) { return this.baseQueryBuilder.bulkUpdate(data, keys, silent); } /** * Delete a record of this kind * @param id */ static forceDelete(id) { return this.primaryKeyCondition(this.baseQueryBuilder, null, [id]).delete(); } /** * Delete all the records of this kind * @param ids */ static forceDeleteAll(...ids) { return this.primaryKeyCondition(this.baseQueryBuilder, null, ids).delete(); } /** * Create a base query builder configured to reach the current instance matching record */ get baseQueryBuilder() { const BaseClass = this.constructor; return BaseClass.primaryKeyCondition(BaseClass.baseQueryBuilder, this); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * FORWARDING METHODS TO QUERY BUILDER * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static pluck(keyColumn, valueColumn = null, override = true) { return this.baseQueryBuilder.pluck(keyColumn, valueColumn, override); } static count() { return this.baseQueryBuilder.count(); } static average(column) { return this.baseQueryBuilder.average(column); } static sum(column) { return this.baseQueryBuilder.sum(column); } static min(column) { return this.baseQueryBuilder.min(column); } static max(column) { return this.baseQueryBuilder.max(column); } static withTrashed() { if (this.useSoftDeletes) { return this.baseQueryBuilder.withTrashed(); } throw new Error(`'${this.name}' model does not support soft deletes`); } static onlyTrashed() { if (this.useSoftDeletes) { return this.baseQueryBuilder.onlyTrashed(); } throw new Error(`'${this.name}' model does not support soft deletes`); } static withoutTrashed() { if (this.useSoftDeletes) { return this.baseQueryBuilder.withoutTrashed(); } throw new Error(`'${this.name}' model does not support soft deletes`); } static sharedLock() { return this.baseQueryBuilder.sharedLock(); } static lockForUpdate() { return this.baseQueryBuilder.lockForUpdate(); } static clearLock() { return this.baseQueryBuilder.clearLock(); } static into(variableName) { return this.baseQueryBuilder.into(variableName); } static select(...columns) { return this.baseQueryBuilder.select(...columns); } static selectSub(queryBuilder, alias) { return this.baseQueryBuilder.selectSub(queryBuilder, alias); } static selectRaw(query, params) { return this.baseQueryBuilder.selectRaw(query, params); } static orderBy(column, direction) { return this.baseQueryBuilder.orderBy(column, direction); } static orderByRaw(query, params) { return this.baseQueryBuilder.orderByRaw(query, params); } static reorder(column, direction) { return this.baseQueryBuilder.reorder(column, direction); } static shuffle(seed) { return this.baseQueryBuilder.shuffle(seed); } static offset(count) { return this.baseQueryBuilder.offset(count); } static skip(count) { return this.baseQueryBuilder.skip(count); } static limit(count) { return this.baseQueryBuilder.limit(count); } static take(count) { return this.baseQueryBuilder.take(count); } static selectCount(alias) { return this.baseQueryBuilder.selectCount(alias); } static selectAverage(column, alias) { return this.baseQueryBuilder.selectAverage(column, alias); } static selectSum(column, alias) { return this.baseQueryBuilder.selectSum(column, alias); } static selectMin(column, alias) { return this.baseQueryBuilder.selectMin(column, alias); } static selectMax(column, alias) { return this.baseQueryBuilder.selectMax(column, alias); } static groupBy(...columns) { return this.baseQueryBuilder.groupBy(...columns); } static groupByRaw(query, params) { return this.baseQueryBuilder.groupByRaw(query, params); } static union(queryBuilder, all = false) { return this.baseQueryBuilder.union(queryBuilder, all); } static unionRaw(query, params, all = false) { return this.baseQueryBuilder.unionRaw(query, params, all); } static join(table, column1, operator, column2, alias) { return this.baseQueryBuilder.join(table, column1, operator, column2, alias); } static leftJoin(table, column1, operator, column2, alias) { return this.baseQueryBuilder.leftJoin(table, column1, operator, column2, alias); } static rightJoin(table, column1, operator, column2, alias) { return this.baseQueryBuilder.rightJoin(table, column1, operator, column2, alias); } static crossJoin(table, column1, operator, column2, alias) { return this.baseQueryBuilder.crossJoin(table, column1, operator, column2, alias); } static outerJoin(table, column1, operator, column2, alias) { return this.baseQueryBuilder.outerJoin(table, column1, operator, column2, alias); } static where(column, operator, value) { return this.baseQueryBuilder.where(column, operator, value); } static orWhere(column, operator, value) { return this.baseQueryBuilder.orWhere(column, operator, value); } static whereNull(column) { return this.baseQueryBuilder.whereNull(column); } static orWhereNull(column) { return this.baseQueryBuilder.orWhereNull(column); } static whereNotNull(column) { return this.baseQueryBuilder.whereNotNull(column); } static orWhereNotNull(column) { return this.baseQueryBuilder.orWhereNotNull(column); } static whereBetween(column, values) { return this.baseQueryBuilder.whereBetween(column, values); } static orWhereBetween(column, values) { return this.baseQueryBuilder.orWhereBetween(column, values); } static whereNotBetween(column, values) { return this.baseQueryBuilder.whereNotBetween(column, values); } static orWhereNotBetween(column, values) { return this.baseQueryBuilder.orWhereNotBetween(column, values); } static whereIn(column, values) { return this.baseQueryBuilder.whereIn(column, values); } static orWhereIn(column, values) { return this.baseQueryBuilder.orWhereIn(column, values); } static whereNotIn(column, values) { return this.baseQueryBuilder.whereNotIn(column, values); } static orWhereNotIn(column, values) { return this.baseQueryBuilder.orWhereNotIn(column, values); } static whereLike(column, value) { return this.baseQueryBuilder.whereLike(column, value); } static orWhereLike(column, value) { return this.baseQueryBuilder.orWhereLike(column, value); } static whereNotLike(column, value) { return this.baseQueryBuilder.whereNotLike(column, value); } static orWhereNotLike(column, value) { return this.baseQueryBuilder.orWhereNotLike(column, value); } static whereColumn(firstColumn, operator, secondColumn) { return this.baseQueryBuilder.whereColumn(firstColumn, operator, secondColumn); } static orWhereColumn(firstColumn, operator, secondColumn) { return this.baseQueryBuilder.orWhereColumn(firstColumn, operator, secondColumn); } static whereDate(column, operator, value) { return this.baseQueryBuilder.whereDate(column, operator, value); } static orWhereDate(column, operator, value) { return this.baseQueryBuilder.orWhereDate(column, operator, value); } static whereYear(column, operator, value) { return this.baseQueryBuilder.whereYear(column, operator, value); } static orWhereYear(column, operator, value) { return this.baseQueryBuilder.orWhereYear(column, operator, value); } static whereMonth(column, operator, value) { return this.baseQueryBuilder.whereMonth(column, operator, value); } static orWhereMonth(column, operator, value) { return this.baseQueryBuilder.orWhereMonth(column, operator, value); } static whereDay(column, operator, value) { return this.baseQueryBuilder.whereDay(column, operator, value); } static orWhereDay(column, operator, value) { return this.baseQueryBuilder.orWhereDay(column, operator, value); } static whereTime(column, operator, value) { return this.baseQueryBuilder.whereTime(column, operator, value); } static orWhereTime(column, operator, value) { return this.baseQueryBuilder.orWhereTime(column, operator, value); } static whereRaw(query, params) { return this.baseQueryBuilder.whereRaw(query, params); } static orWhereRaw(query, params) { return this.baseQueryBuilder.orWhereRaw(query, params); } static having(column, operator, value) { return this.baseQueryBuilder.having(column, operator, value); } static orHaving(column, operator, value) { return this.baseQueryBuilder.orHaving(column, operator, value); } static havingNull(column) { return this.baseQueryBuilder.havingNull(column); } static orHavingNull(column) { return this.baseQueryBuilder.orHavingNull(column); } static havingNotNull(column) { return this.baseQueryBuilder.havingNotNull(column); } static orHavingNotNull(column) { return this.baseQueryBuilder.orHavingNotNull(column); } static havingBetween(column, values) { return this.baseQueryBuilder.havingBetween(column, values); } static orHavingBetween(column, values) { return this.baseQueryBuilder.orHavingBetween(column, values); } static havingNotBetween(column, values) { return this.baseQueryBuilder.havingNotBetween(column, values); } static orHavingNotBetween(column, values) { return this.baseQueryBuilder.orHavingNotBetween(column, values); } static havingIn(column, values) { return this.baseQueryBuilder.havingIn(column, values); } static orHavingIn(column, values) { return this.baseQueryBuilder.orHavingIn(column, values); } static havingNotIn(column, values) { return this.baseQueryBuilder.havingNotIn(column, values); } static orHavingNotIn(column, values) { return this.baseQueryBuilder.orHavingNotIn(column, values); } static havingLike(column, value) { return this.baseQueryBuilder.havingLike(column, value); } static orHavingLike(column, value) { return this.baseQueryBuilder.orHavingLike(column, value); } static havingNotLike(column, value) { return this.baseQueryBuilder.havingNotLike(column, value); } static orHavingNotLike(column, value) { return this.baseQueryBuilder.orHavingNotLike(column, value); } static havingColumn(firstColumn, operator, secondColumn) { return this.baseQueryBuilder.havingColumn(firstColumn, operator, secondColumn); } static orHavingColumn(firstColumn, operator, secondColumn) { return this.baseQueryBuilder.orHavingColumn(firstColumn, operator, secondColumn); } static havingDate(column, operator, value) { return this.baseQueryBuilder.havingDate(column, operator, value); } static orHavingDate(column, operator, value) { return this.baseQueryBuilder.orHavingDate(column, operator, value); } static havingYear(column, operator, value) { return this.baseQueryBuilder.havingYear(column, operator, value); } static orHavingYear(column, operator, value) { return this.baseQueryBuilder.orHavingYear(column, operator, value); } static havingMonth(column, operator, value) { return this.baseQueryBuilder.havingMonth(column, operator, value); } static orHavingMonth(column, operator, value) { return this.baseQueryBuilder.orHavingMonth(column, operator, value); } static havingDay(column, operator, value) { return this.baseQueryBuilder.havingDay(column, operator, value); } static orHavingDay(column, operator, value) { return this.baseQueryBuilder.orHavingDay(column, operator, value); } static havingTime(column, operator, value) { return this.baseQueryBuilder.havingTime(column, operator, value); } static orHavingTime(column, operator, value) { return this.baseQueryBuilder.orHavingTime(column, operator, value); } static havingRaw(query, params) { return this.baseQueryBuilder.havingRaw(query, params); } static orHavingRaw(query, params) { return this.baseQueryBuilder.orHavingRaw(query, params); } } exports.default = ModelQueryBuilder; _defineProperty(ModelQueryBuilder, "tableName", ''); _defineProperty(ModelQueryBuilder, "primaryKey", 'id'); _defineProperty(ModelQueryBuilder, "useTimestamps", true); _defineProperty(ModelQueryBuilder, "createTimestamp", 'created_at'); _defineProperty(ModelQueryBuilder, "updateTimestamp", 'updated_at'); _defineProperty(ModelQueryBuilder, "useSoftDeletes", false); _defineProperty(ModelQueryBuilder, "softDeleteTimestamp", 'deleted_at'); _defineProperty(ModelQueryBuilder, "relations", {});