silvie
Version:
Typescript Back-end Framework
640 lines (619 loc) • 21.6 kB
JavaScript
"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", {});