@leapfrogtechnology/db-model
Version:
Low-footprint database abstraction layer and model built on top of Knex.
386 lines • 16.2 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var debug = require("debug");
var db = require("./db");
var constants_1 = require("./constants");
var ModelNotFoundError_1 = require("./ModelNotFoundError");
var ramda_1 = require("ramda");
var log = debug(constants_1.NS_MODEL);
/**
* Create Model for different connection
*
* @param {ConnectionResolver} [resolver]
* @returns {typeof BaseModel}
*/
function createBaseModel(resolver) {
var _a;
return _a = /** @class */ (function () {
function BaseModel() {
}
/**
* Binds a database connection to the model.
*
* @param {Knex} connection
* @returns {void}
*/
BaseModel.bindConnection = function (connection) {
log('Binding database connection to the model (Lazy)');
this.connection = connection;
};
/**
* Binds a database connection to the model (chainable version of bindConnection()).
*
* @param {Knex} connection
* @returns {any}
*/
BaseModel.bind = function (connection) {
this.bindConnection(connection);
return this;
};
/**
* Resolves a database connection.
*
* Note: It would throw an Error on the run time if it couldn't resolve the
* connection by the time any DB methods are invoked on it.
* @returns {Knex}
*/
BaseModel.getConnection = function () {
if (this.connection) {
return this.connection;
}
// Note: We need to resolve db connection everytime.
if (resolver) {
return resolver();
}
throw new Error('Cannot resolve the database connection.');
};
/**
* Generic query builder.
*
* @param {Transaction} [trx]
* @returns {(Knex.Transaction | Knex)}
*/
BaseModel.queryBuilder = function (trx) {
return db.queryBuilder(this.getConnection(), trx);
};
/**
* Finds a record based on the params.
*
* @param {object} [params={}]
* @param {Function} callback
* @param {Knex.Transaction} trx
* @returns {Knex.QueryBuilder}
*/
BaseModel.find = function (params, callback, trx) {
if (params === void 0) { params = {}; }
return db.find(this.getConnection(), this.table, params, callback, trx);
};
/**
* Finds the first record based on the params.
*
* @param {object} [params={}]
* @param {Function} callback
* @param {Knex.Transaction} trx
* @returns {Promise<T | null>}
*/
BaseModel.findFirst = function (params, callback, trx) {
if (params === void 0) { params = {}; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, db.findFirst(this.getConnection(), this.table, params, ramda_1.any, trx)];
});
});
};
/**
* Find record by it's id.
* Throws an exception if not found.
*
* @param {any} id
* @param {Function} callback
* @param {Knex.Transaction} trx
* @returns {Promise<T | null>}
*/
BaseModel.findById = function (id, callback, trx) {
var idParams = this.buildIdParams(id);
return db.findFirst(this.getConnection(), this.table, idParams, callback, trx);
};
/**
* Find record by it's id.
* Throws an exception if not found.
*
* @param {any} id
* @param {Function} callback
* @param {Knex.Transaction} trx
* @throws {ModelNotFoundError}
* @returns {Promise<T | null>}
*/
BaseModel.findByIdOrFail = function (id, callback, trx) {
var _this = this;
var idParams = this.buildIdParams(id);
return db.findFirst(this.getConnection(), this.table, idParams, callback, trx).then(function (result) {
if (!result) {
throw new ModelNotFoundError_1.default(_this.name + ' not found');
}
return result;
});
};
/**
* Finds records based on the params with records limit.
*
* @param {object} [params={}]
* @param {PaginationParams} pageParams
* @param {OrderBy[]} sortParams
* @param {Knex.Transaction} trx
* @param {Function} callback
* @returns {Knex.QueryBuilder}
*/
BaseModel.findWithPageAndSort = function (params, pageParams, sortParams, callback, trx) {
if (params === void 0) { params = {}; }
var offset = (pageParams.page - 1) * pageParams.pageSize;
var qb = this.find(params, trx).offset(offset).limit(pageParams.pageSize);
if (sortParams && sortParams.length > 0) {
qb.clearOrder();
sortParams.forEach(function (item) {
qb.orderBy(item.field, item.direction);
});
}
if (callback)
callback(qb);
return qb;
};
/**
* Count the total records.
*
* @param {object} [params={}]
* @param {Function} callback
* @param {Knex.Transaction} trx
* @returns {Knex.QueryBuilder}
*/
BaseModel.count = function (params, callback, trx) {
if (params === void 0) { params = {}; }
var qb = this.find(params, trx).clearSelect().count('*').clearOrder();
if (callback)
callback(qb);
return qb.then(function (_a) {
var result = _a[0];
return result.count;
});
};
/**
* Insert all records sent in data object.
*
* @param {(object | object[])} data
* @param {Transaction} [trx]
* @returns {Promise<T[]>}
*/
BaseModel.insert = function (data, trx) {
return db.insert(this.getConnection(), this.table, data, trx);
};
/**
* Update records by id.
*
* @param {number} id
* @param {object} params
* @param {Transaction} transaction
* @returns {Promise<object>}
*/
BaseModel.updateById = function (id, params, trx) {
var idParams = this.buildIdParams(id);
return db.update(this.getConnection(), this.table, idParams, params, trx);
};
/**
* Update records by where condition.
*
* @param {object} where
* @param {object} params
* @param {Transaction} transaction
* @returns {Promise<T[]>}
*/
BaseModel.update = function (where, params, trx) {
return db.update(this.getConnection(), this.table, where, params, trx);
};
/**
* Delete row in table.
*
* @param {object} params
* @param {Transaction} trx
* @returns {Promise<T[]>}
*/
BaseModel.deleteById = function (id, trx) {
var idParams = this.buildIdParams(id);
return db.remove(this.getConnection(), this.table, idParams, trx);
};
/**
* Delete row in table.
*
* @param {object} params
* @param {Transaction} trx
* @returns {Promise<T[]>}
*/
BaseModel.delete = function (params, trx) {
return db.remove(this.getConnection(), this.table, params, trx);
};
/**
* Execute SQL raw query and return results.
*
* @param {string} sql
* @param {RawBindingParams | ValueMap} params
* @param {Transaction} trx
* @returns {Promise<T[]>}
*/
BaseModel.query = function (sql, params, trx) {
return db.query(this.getConnection(), sql, params, trx);
};
/**
* Method to perform a transactional query execution.
*
* @param {(trx: Transaction) => any} callback
* @param {Transaction} trx
* @returns {any}
*/
BaseModel.transaction = function (callback, trx) {
if (trx) {
return callback(trx);
}
return this.getConnection().transaction(callback);
};
/**
* Batch insert rows of data.
*
* @param {object[]} data
* @param {Transaction} [trx]
* @param {number} [chunksize=30]
* @returns {Promise<T[]>}
*/
BaseModel.batchInsert = function (data, trx, chunksize) {
if (chunksize === void 0) { chunksize = 30; }
return db.batchInsert(this.getConnection(), this.table, data, chunksize, trx);
};
/**
* Execute SQL raw query and return scalar value.
*
* @param {string} sql
* @param {any} params
* @param {Transaction} trx
* @returns {Promise<T | null>}
*/
BaseModel.getValue = function (sql, params, trx) {
return db.getValue(this.getConnection(), sql, params, trx);
};
/**
* Execute SQL raw query returning a boolean result.
*
* @param {string} sql
* @param {*} [params]
* @param {Transaction} [trx]
* @returns {Promise<boolean>}
*/
BaseModel.check = function (sql, params, trx) {
return db.check(this.getConnection(), sql, params, trx);
};
/**
* Execute SQL raw query returning a JSON encoded result
* and produce the parsed object.
*
* @param {string} sql
* @param {*} [params]
* @param {Transaction} [trx]
* @returns {(Promise<T | null>)}
*/
BaseModel.getJson = function (sql, params, trx) {
return db.getJson(this.getConnection(), sql, params, trx);
};
/**
* Invoke a scalar-valued function and return results.
*
* Example usage:
*
* const username = await User.invoke<string>('dbo.can_user_access_object', { userId: 10, objectId: 15 });
*
* // => Runs SQL: SELECT dbo.can_user_access_object(:userId, :objectId)
* // => Binds params: { userId: 10, objectId: 15 }
*
* @param {string} objectName
* @param {RawBindingParams | ValueMap} [params]
* @param {Knex.Transaction} [trx]
* @returns {Promise<T | null>}
*/
BaseModel.invoke = function (objectName, params, trx) {
return db.invoke(trx || this.getConnection(), objectName, params);
};
/**
* Execute a procedure and return the results returned (if any).
*
* Example usage:
*
* await Recommendation.exec<string>('dbo.update_top_recommendations', { userId: 10, type });
*
* // => Runs SQL: EXEC dbo.update_top_recommendations :userId, :type
* // => Binds params: { userId: 10, type }
*
* @param {string} objectName
* @param {RawBindingParams | ValueMap} [params]
* @param {Knex.Transaction} [trx]
* @returns {Promise<T[]>}
*/
BaseModel.exec = function (objectName, params, trx) {
return db.exec(trx || this.getConnection(), objectName, params);
};
/**
* Build param object for given id.
*
* @param {any} id
* @returns {object}
*/
BaseModel.buildIdParams = function (id) {
var _a;
if (typeof id === 'number' || typeof id === 'string') {
return _a = {}, _a[this.id] = id, _a;
}
return id;
};
return BaseModel;
}()),
_a.defaultOrderBy = [{ field: 'id', direction: 'asc' }],
_a.id = 'id',
_a;
}
exports.createBaseModel = createBaseModel;
exports.Model = createBaseModel();
//# sourceMappingURL=model.js.map