@avonjs/avonjs
Version:
A fluent Node.js API generator.
226 lines (225 loc) • 6.92 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const pluralize_1 = require("pluralize");
const Contracts_1 = require("../Contracts");
const Models_1 = require("../Models");
const helpers_1 = require("../helpers");
const Repository_1 = __importDefault(require("./Repository"));
class KnexRepository extends Repository_1.default {
/**
* List of selectable columns.
*/
columns = ['*'];
/**
* The columns that should be searched.
*/
searches = [];
/**
* Start new transaction.
*/
async prepareTransaction() {
return this.connection().transaction();
}
/**
* Search storage for given query string.
*/
async search(search, page = 1, perPage = 15) {
const query = this.performSearch(this.makeQuery(), search);
const offset = (page - 1) * perPage > 0 ? (page - 1) * perPage : 0;
const [count] = await query
.clone()
.clearSelect()
.clearGroup()
.count(`${this.tableName()}.${this.model().getKeyName()} as count`);
const data = await this.selectColumns(query.limit(perPage).offset(offset));
return {
...count,
items: data.map((item) => this.fillModel(item)),
};
}
/**
* Perform searches on the given item.
*/
performSearch(query, search) {
if ((0, helpers_1.isNullish)(search)) {
return query;
}
// only apply when search value is valid
return query.where((whereQuery) => {
const searchValue = search.match(/%/) ? search : `%${search}%`;
this.searchableColumns().forEach((searchable) => {
if (typeof searchable === 'string') {
whereQuery.orWhere(searchable, 'LIKE', searchValue);
}
else {
whereQuery.orWhere(searchable, 'LIKE', searchValue);
}
});
return whereQuery;
});
}
/**
* Get the searchable columns for the resource.
*/
searchableColumns() {
return this.searches.length ? this.searches : [this.model().getKeyName()];
}
/**
* Find all model's for the given conditions.
*/
async all(wheres = []) {
const data = await this.selectColumns(this.where(wheres).makeQuery());
return data.map((item) => this.fillModel(item));
}
/**
* Get the select columns.
*/
selectColumns(query) {
return query.select(this.columns.map((column) => this.getQualifiedColumnName(column)));
}
/**
* Get list of selectable columns.
*/
select(columns = ['*']) {
this.columns = columns;
return this;
}
/**
* Find first model for the given conditions.
*/
async first(wheres = []) {
const query = this.selectColumns(this.where(wheres).makeQuery());
return this.parseResult(await query.first());
}
/**
* Store given model into the storage.
*/
async store(model) {
const insertedIds = await this.query().insert(model.getAttributes());
return this.find(insertedIds[0]);
}
/**
* Store given model into the storage.
*/
async update(model) {
const data = { ...model.getAttributes() };
// remove primary key
delete data[model.getKeyName()];
// update storage
await this.query().where(model.getKeyName(), model.getKey()).update(data);
return model;
}
/**
* Delete model for the given key.
*/
async delete(key) {
await this.whereKey(key).makeQuery().delete();
}
/**
* Get new query with wheres and orders.
*/
makeQuery() {
return this.applyModifiers(this.applyWheres(this.query().orderBy(this.prepareOrdersForQuery())));
}
/**
* Prepare raw orders for query.
*/
prepareOrdersForQuery() {
return this.orders.map((order) => {
return {
column: this.getQualifiedColumnName(order.key),
order: order.direction === Contracts_1.Direction.DESC ? 'desc' : 'asc',
};
});
}
/**
* Apply wheres to the query.
*/
applyWheres(query) {
this.wheres.forEach(({ key, operator, value }) => {
const sanitizedValue = this.sanitizeValueForOperator(value, operator);
if ([null, undefined].includes(value)) {
this.queryNullValues(query, key, operator);
}
else if (Contracts_1.Operator.notIn === operator) {
query.whereNotIn(this.getQualifiedColumnName(key), sanitizedValue);
}
else {
query.where(this.getQualifiedColumnName(key), operator, sanitizedValue);
}
});
return query;
}
/**
* Query where the value "is" or "isNot" null.
*/
queryNullValues(query, key, operator) {
if ([Contracts_1.Operator.eq, Contracts_1.Operator.in, Contracts_1.Operator.like].includes(operator)) {
query.whereNull(this.getQualifiedColumnName(key));
}
else {
query.whereNotNull(this.getQualifiedColumnName(key));
}
return query;
}
/**
* Get the sanitized value corresponding to the operator.
*/
sanitizeValueForOperator(value, operator) {
return [Contracts_1.Operator.in, Contracts_1.Operator.notIn].includes(operator) &&
!Array.isArray(value)
? [value]
: value;
}
/**
* Get fully qualified column name.
*/
getQualifiedColumnName(columnName) {
return `${this.tableName()}.${columnName}`;
}
/**
* Apply wheres to the query.
*/
applyModifiers(query) {
this.modifiers.forEach((modifier) => modifier(query));
return query;
}
/**
* Get the base query.
*/
query() {
const query = this.connection().table(this.tableName()).debug(this.debug());
const transaction = this.getTransaction();
return transaction
? query.transacting(transaction)
: query;
}
/**
* Get the database table name.
*/
tableName() {
return (0, pluralize_1.plural)((0, pluralize_1.singular)((0, helpers_1.slugify)(this.constructor.name, '_')));
}
/**
* Parse the query result.
*/
parseResult(result) {
return result ? this.fillModel(result) : result;
}
/**
* Create new instance of model.
*/
model() {
return new Models_1.Fluent();
}
/**
* Get the debugging state.
*/
debug() {
return false;
}
}
exports.default = KnexRepository;