Use a wrapper to cleanup

Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com>
This commit is contained in:
Alexandre Bodin 2020-04-23 18:14:12 +02:00
parent de5d1d6d54
commit 9ddeaffed1
3 changed files with 121 additions and 170 deletions

View File

@ -5,62 +5,52 @@
*/
module.exports = {
// Before saving a value.
// Fired before an `insert` or `update` query.
// beforeSave: async (model, attrs, options) => {},
// After saving a value.
// Fired after an `insert` or `update` query.
// afterSave: async (model, response, options) => {},
// Before fetching a value.
// Fired before a `fetch` operation.
beforeFetch: async (...args) => {
console.log('beforeFetch', ...args);
},
// After fetching a value.
// Fired after a `fetch` operation.
afterFetch: async (...args) => {
console.log('afterFetch', ...args);
},
// Before fetching all values.
// Fired before a `fetchAll` operation.
beforeFetchAll: async (...args) => {
console.log('beforeFetchAll', ...args);
},
// After fetching all values.
// Fired after a `fetchAll` operation.
afterFetchAll: async (...args) => {
console.log('afterFetchAll', ...args);
},
// Before creating a value.
// Fired before an `insert` query.
beforeCreate: async (...args) => {
beforeCreate(...args) {
console.log('beforeCreate', ...args);
args[0].name += ' - Coucou';
},
// After creating a value.
// Fired after an `insert` query.
afterCreate: async (...args) => {
afterCreate(...args) {
console.log('afterCreate', ...args);
},
// Before updating a value.
// Fired before an `update` query.
beforeUpdate: async (...args) => {
beforeUpdate(...args) {
console.log('beforeUpdate', ...args);
args[1].name += ' - Coucou';
},
// After updating a value.
// Fired after an `update` query.
afterUpdate: async (...args) => {
afterUpdate(...args) {
console.log('afterUpdate', ...args);
},
// Before destroying a value.
// Fired before a `delete` query.
beforeDestroy: async (...args) => {
console.log('beforeDestroy', ...args);
beforeDelete(...args) {
console.log('beforeDelete', ...args);
},
// After destroying a value.
// Fired after a `delete` query.
afterDestroy: async (...args) => {
console.log('afterDestroy', ...args);
afterDelete(...args) {
console.log('afterDelete', ...args);
},
beforeFind(...args) {
console.log('beforeFind', ...args);
},
afterFind(...args) {
console.log('afterFind', ...args);
},
beforeFindOne(...args) {
console.log('beforeFindOne', ...args);
},
afterFindOne(...args) {
console.log('afterFindOne', ...args);
},
beforeCount(...args) {
console.log('beforeCount', ...args);
},
afterCount(...args) {
console.log('afterCount', ...args);
},
beforeSearch(...args) {
console.log('beforeSearch', ...args);
},
afterSearch(...args) {
console.log('afterSearch', ...args);
},
beforeCountSearch(...args) {
console.log('beforeCountSearch', ...args);
},
afterCountSearch(...args) {
console.log('afterCountSearch', ...args);
},
};

View File

@ -1,133 +1,74 @@
'use strict';
const _ = require('lodash');
const { replaceIdByPrimaryKey } = require('../utils/primary-key');
const { executeBeforeHook, executeAfterHook } = require('../utils/hooks');
module.exports = function createQuery(opts) {
return new Query(opts);
const { model, connectorQuery } = opts;
return {
get model() {
return model;
},
get orm() {
return model.orm;
},
get primaryKey() {
return model.primaryKey;
},
get associations() {
return model.associations;
},
/**
* Run custom database logic
*/
custom(mapping) {
if (typeof mapping === 'function') {
return mapping.bind(this, { model: this.model });
}
if (!mapping[this.orm]) {
throw new Error(`Missing mapping for orm ${this.orm}`);
}
if (typeof mapping[this.orm] !== 'function') {
throw new Error(`Custom queries must be functions received ${typeof mapping[this.orm]}`);
}
return mapping[this.model.orm].call(this, { model: this.model });
},
create: wrapQuery({ hook: 'create', model, connectorQuery }),
update: wrapQuery({ hook: 'update', model, connectorQuery }),
delete: wrapQuery({ hook: 'delete', model, connectorQuery }),
find: wrapQuery({ hook: 'find', model, connectorQuery }),
findOne: wrapQuery({ hook: 'findOne', model, connectorQuery }),
count: wrapQuery({ hook: 'count', model, connectorQuery }),
search: wrapQuery({ hook: 'search', model, connectorQuery }),
countSearch: wrapQuery({ hook: 'countSearch', model, connectorQuery }),
};
};
class Query {
constructor({ model, connectorQuery }) {
this.connectorQuery = connectorQuery;
this.model = model;
}
// wraps a connectorQuery call with:
// - param substitution
// - lifecycle hooks
const wrapQuery = ({ hook, model, connectorQuery }) => async (params, ...rest) => {
// substite id for primaryKey value in params
const newParams = replaceIdByPrimaryKey(params, model);
get orm() {
return this.model.orm;
}
// execute before hook
await executeBeforeHook(hook, model, newParams, ...rest);
get primaryKey() {
return this.model.primaryKey;
}
// execute query
const result = await connectorQuery[hook](newParams, ...rest);
get associations() {
return this.model.associations;
}
// execute after hook
await executeAfterHook(hook, model, result);
async executeHook(hook, ...args) {
if (_.has(this.model, hook)) {
await this.model[hook](...args);
}
}
/**
* Run custom database logic
*/
custom(mapping) {
if (typeof mapping === 'function') {
return mapping.bind(this, { model: this.model });
}
if (!mapping[this.orm]) {
throw new Error(`Missing mapping for orm ${this.orm}`);
}
if (typeof mapping[this.orm] !== 'function') {
throw new Error(`Custom queries must be functions received ${typeof mapping[this.orm]}`);
}
return mapping[this.model.orm].call(this, { model: this.model });
}
async find(params = {}, ...args) {
const newParams = replaceIdByPrimaryKey(params, this.model);
await this.executeHook('beforeFetchAll', newParams, ...args);
const results = await this.connectorQuery.find(newParams, ...args);
await this.executeHook('afterFetchAll', results);
return results;
}
async findOne(params = {}, ...args) {
const newParams = replaceIdByPrimaryKey(params, this.model);
await this.executeHook('beforeFetch', newParams, ...args);
const result = await this.connectorQuery.findOne(newParams, ...args);
await this.executeHook('afterFetch', result);
return result;
}
async create(params = {}, ...args) {
const newParams = replaceIdByPrimaryKey(params, this.model);
await this.executeHook('beforeCreate', newParams, ...args);
const entry = await this.connectorQuery.create(newParams, ...args);
await this.executeHook('afterCreate', entry);
return entry;
}
async update(params = {}, ...args) {
const newParams = replaceIdByPrimaryKey(params, this.model);
await this.executeHook('beforeUpdate', newParams, ...args);
const entry = await this.connectorQuery.update(newParams, ...args);
await this.executeHook('afterUpdate', entry);
return entry;
}
async delete(params = {}, ...args) {
const newParams = replaceIdByPrimaryKey(params, this.model);
await this.executeHook('beforeDestroy', newParams, ...args);
const entry = await this.connectorQuery.delete(newParams, ...args);
await this.executeHook('afterDestroy', entry);
return entry;
}
async count(params = {}, ...args) {
const newParams = replaceIdByPrimaryKey(params, this.model);
await this.executeHook('beforeCount', newParams, ...args);
const count = await this.connectorQuery.count(newParams, ...args);
await this.executeHook('afterCount', count);
return count;
}
async search(params = {}, ...args) {
const newParams = replaceIdByPrimaryKey(params, this.model);
await this.executeHook('beforeSearch', newParams, ...args);
const results = await this.connectorQuery.search(newParams, ...args);
await this.executeHook('afterSearch', results);
return results;
}
async countSearch(params = {}, ...args) {
const newParams = replaceIdByPrimaryKey(params, this.model);
await this.executeHook('beforeCountSearch', newParams, ...args);
const count = await this.connectorQuery.countSearch(newParams, ...args);
await this.executeHook('afterCountSearch', count);
return count;
}
}
// return result
return result;
};

View File

@ -0,0 +1,20 @@
'use strict';
const _ = require('lodash');
const executeHook = async (hook, model, ...args) => {
if (_.has(model, hook)) {
await model[hook](...args);
}
};
const executeBeforeHook = (hook, model, ...args) =>
executeHook(`before${_.upperFirst(hook)}`, model, ...args);
const executeAfterHook = (hook, model, ...args) =>
executeHook(`after${_.upperFirst(hook)}`, model, ...args);
module.exports = {
executeBeforeHook,
executeAfterHook,
};