diff --git a/examples/getstarted/api/restaurant/models/Restaurant.js b/examples/getstarted/api/restaurant/models/Restaurant.js index 968936b2a8..c246a01d75 100755 --- a/examples/getstarted/api/restaurant/models/Restaurant.js +++ b/examples/getstarted/api/restaurant/models/Restaurant.js @@ -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); }, }; diff --git a/packages/strapi-database/lib/queries/create-query.js b/packages/strapi-database/lib/queries/create-query.js index 3a7204b9e8..fe1015f727 100644 --- a/packages/strapi-database/lib/queries/create-query.js +++ b/packages/strapi-database/lib/queries/create-query.js @@ -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; +}; diff --git a/packages/strapi-database/lib/utils/hooks.js b/packages/strapi-database/lib/utils/hooks.js new file mode 100644 index 0000000000..8cd266e62b --- /dev/null +++ b/packages/strapi-database/lib/utils/hooks.js @@ -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, +};