Security News
UK Officials Consider Banning Ransomware Payments from Public Entities
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.
bookshelf-modelbase-plus
Advanced tools
Extended functionality for REST operations with validation, filtering, ordering, importing records.
Bookshelf modelbase plugin offers good functionality, however when dealing with a number of similar REST microservices it is good to have shared codebase for common operations like paginated list, updating the records with validation, importing set of records and etc.
npm i --save bookshelf-modelbase-plus
const db = require(knex)(require('./knexfile'));
const bookshelf = require('bookshelf')(db);
const modelbase = require('bookshelf-modelbase-plus');
// load plugin
bookshelf.plugin(require('bookshelf-modelbase-plus'));
// needs also pagination plugin (older versions of bookshelf)
// bookshelf.plugin('pagination');
const ModelBase = modelbase(bookshelf);
var Budget = ModelBase.extend({
tableName: 'budgets',
validationOptions: {}, // Joi options (default options: { abortEarly: false })
});
/**
* Get sorted, ordered, filtered, paginated list of records. Good for GET params object passing
* i.e. /?limit=5&page=1&order_by=-id&status=enabled
* @param {Object} data
* @param {Array} columns All table columns
* @return {Promise(bookshelf.Collection)} Bookshelf Collection of all Models
*/
var data = {
status: 'enabled', // where status = enabled
order_by: '-id', // order by id desc
limit: 5,
page: 1, // 1 based page number
}
Budget
.getList(data, ['id', 'name', 'status'])
.then(function(models) {
//
})
.catch(function(err) { });
Budget.getList({status: ['=', 'enabled']}, ['status']);
Budget.getList({a: 2, b: 3, _logic: 'or'});
Budget.getList({
status: {
operator: 'LIKE',
value: '%enabled%',
}}).then(models => {});
Budget.getList({status: ['IN', ['enabled', 'disabled']]}, ['status']);
Budget.getList({name: 'name0', _or: {name: 'name1', _and: {status: 'enabled'}}}, ['name', 'status'])
Budget.getList({name: 'name0', _or: [{name: 'name1'}, {status: 'enabled'}]}, ['name', 'status'])
A function may optionally be defined on the model to be used when
specifying withQuery
in the getList options, similar to withRelated
.
This function will then be called with the knex query builder so that
the model can define custom code to refine the search
(i.e. join, convert values, etc.). This must avoid the following keywords:
through, fetch, count, fetchOne, create, resetQuery, query, orderBy, sync, clone, _handleResponse, _handleEager
Example:
var Budget = ModelBase.extend({
tableName: 'budgets',
fancy: (qb, options) => {
return qb.where({name: options.name + options.name2});
},
});
Budget.getList({name: 'first', name2: 'last', withQuery: 'fancy'})
Use the optional select
param in the getList options to only return specific columns.
The value should be a comma-separated string or an array of strings.
Use the getListQuery
method to get the underlying getList query without executing
anything. This is useful in case you want to do something custom with the query,
such as stream to a CSV somewhere instead of fetching a list of Bookshelf models.
/**
* Create and save model and return all attributes
* @param {Object} data
* @param {Array} columns The set of columns will be used to fetch attribute values from the *data* object
* @return {Promise(bookshelf.Model)} Bookshelf Collection of all Models
*/
Budget
.createOne(data, ['id', 'name', 'status'])
.then((model) => {
//
})
.catch((err) => {
});
/**
* Update model through ID and revalidate all attributes before saving with modelbase Joi validation (if set)
* returns model with all attributes
* @param {Object} data
* @param {Number} id
* @param {Array} columns data The set of columns will be used to fetch attribute values from the *data* object
* @return {Promise(bookshelf.Model)} Bookshelf Collection of all Models
*/
Budget
.updateOneById(data, id, ['id', 'name', 'status'])
.then((model) => {
//
});
/**
* Update model through composite pKEY lookup and revalidate all attributes before saving with modelbase Joi validation (if set)
* returns model with all attributes
* @param {Object} data
* @param {Array} columns data The set of columns will be used to fetch attribute values from the *data* object including the composite key
* @return {Promise(bookshelf.Model)} Bookshelf Collection of all Models
*/
Budget
.updateOneByCompositePKey(data, ['id', 'name', 'status'])
.then((model) => {
//
});
/**
* Destroys model through composite pKEY lookup
* @param {Object} options should have the composite key fields
*/
Budget
.destroyOneByCompositePKey(options)
.then((cnt) => {
//
});
/**
* Update model and revalidate all attributes before saving with modelbase Joi validation (if set)
* returns model with all attributes
* @param {Array} data Array of records to import
* @param {Array} columns data The set of columns will be used to fetch attribute values from the *data* object
* @param {Function} callback Optional callback with *bookshelf.Model* and *Object* params to restore soft-deleted records
* @return {Promise(bookshelf.Model)} Bookshelf Collection of all Models
*/
Budget
.importMany([
{ id: 120, name: 'Test name 00' },
{ id: 139, name: 'Test name 01', status: 'enabled' },
{
// this will be definetely inserted
name: 'Test name 02', status: 'disabled',
},
],
columns,
(existingModel, updateData) => {
if (existingModel.get('status') === 'deleted' && !updateData.status) {
// in this particular example a callback has been raised cause one of the imported record with id = 120
// is already in the table, so we check it's attribute *status* (might by any soft-deleting logic) and
// decide to restore soft deleted record and clean *old* values before save new one
updateData.status = 'enabled';
// clear existing model attributes, since they were set before deleting the record,
// now are obsolete
existingModel.set('name', null);
return true;
} else {
// wasn't restored
return false;
}
})
.then((rowCount) => {
res.data = { rows: rowCount };
return next();
})
.catch(err => next(err));
Model.eventEmitter.on('import.created', function(createdModel) {...});
Model.eventEmitter.on('import.updated', function(updatedModel, prevModel) {...});
/**
* Destroys a set of model through where condition
* @param {Object} options.where should have the where condtions for destroy
*/
Budget
.destroyMany(options)
.then((cnt) => {
//
});
/**
* Synchronizes an existing collection to a desired collection
* @param {Array<*>} existing Collection (or array)
* @param {Array<*>} desired collection
* @param {Array<string>} columns to update
* @param options.noInsert - prevents inserting new records (default inserts)
* @param options.noUpdate - prevents updating existing records (default updates)
* @param options.noDestroy - prevents destroying existing records (default destroys)
* @param options.isMatch - comparison function called with existing row and desired row. Default: (a,b) => a.id === b.id
* @return Promise<*>
* {Array<*>} inserted
* {Array<*>} updated (models with getSavedAttributes accessible)
* {Array<*>} destroyed
* {Array<*>} unchanged
*/
const isMatch = (a, b) => (a.id && a.id === b.id) || (a.type === b.type);
Budget
.fetchAll()
.then(existing => Budget.bulkSync(existing, data, Budget.columns, { isMatch }))
.then((synced) => {
synced.inserted.forEach(i => events.emit('exchangeCreated', i, req));
synced.updated.forEach(i => events.emit('exchangeUpdated', i, req));
synced.destroyed.forEach(i => events.emit('exchangeDestroyed', i, req));
});
/**
* Destroys all matching models by ID
* @param {Array<*>} array of models with IDs to destroy
* @param options.transacting
* @return Promise<number> number of rows deleted
*/
Budget
.bulkDestroyIn({id: 1}, {id: 2})
.then(rows => console.log(`deleted ${rows}`));
FAQs
Extended functionality for REST operations with validation, filtering, ordering, importing records.
The npm package bookshelf-modelbase-plus receives a total of 15 weekly downloads. As such, bookshelf-modelbase-plus popularity was classified as not popular.
We found that bookshelf-modelbase-plus demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 6 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
Research
Security News
Socket researchers found several malicious npm packages typosquatting Chalk and Chokidar, targeting Node.js developers with kill switches and data theft.