UNPKG

@avonjs/avonjs

Version:

A fluent Node.js API generator.

226 lines (225 loc) 6.92 kB
"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;