UNPKG

ra-core

Version:

Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React

383 lines 15.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.applyCallbacks = exports.withLifecycleCallbacks = void 0; /** * Extend a dataProvider to execute callbacks before and after read and write calls. * * @param {DataProvider} dataProvider The dataProvider to wrap * @param {ResourceCallbacks[]} handlers An array of ResourceCallbacks * * @typedef {Object} ResourceCallbacks * @property {string} resource The resource name * @property {AfterCreate} [afterCreate] A callback (or array of callbacks) executed after create * @property {AfterDelete} [afterDelete] A callback (or array of callbacks) executed after delete * @property {AfterDeleteMany} [afterDeleteMany] A callback (or array of callbacks) executed after deleteMany * @property {AfterGetList} [afterGetList] A callback (or array of callbacks) executed after getList * @property {AfterGetMany} [afterGetMany] A callback (or array of callbacks) executed after getMany * @property {AfterGetManyReference} [afterGetManyReference] A callback (or array of callbacks) executed after getManyReference * @property {AfterGetOne} [afterGetOne] A callback (or array of callbacks) executed after getOne * @property {AfterRead} [afterRead] A callback (or array of callbacks) executed after read (getList, getMany, getManyReference, getOne) * @property {AfterSave} [afterSave] A callback (or array of callbacks) executed after save (create, update, updateMany) * @property {AfterUpdate} [afterUpdate] A callback (or array of callbacks) executed after update * @property {AfterUpdateMany} [afterUpdateMany] A callback (or array of callbacks) executed after updateMany * @property {BeforeCreate} [beforeCreate] A callback (or array of callbacks) executed before create * @property {BeforeDelete} [beforeDelete] A callback (or array of callbacks) executed before delete * @property {BeforeDeleteMany} [beforeDeleteMany] A callback (or array of callbacks) executed before deleteMany * @property {BeforeGetList} [beforeGetList] A callback (or array of callbacks) executed before getList * @property {BeforeGetMany} [beforeGetMany] A callback (or array of callbacks) executed before getMany * @property {BeforeGetManyReference} [beforeGetManyReference] A callback (or array of callbacks) executed before getManyReference * @property {BeforeGetOne} [beforeGetOne] A callback (or array of callbacks) executed before getOne * @property {BeforeSave} [beforeSave] A callback (or array of callbacks) executed before save (create, update, updateMany) * @property {BeforeUpdate} [beforeUpdate] A callback (or array of callbacks) executed before update * @property {BeforeUpdateMany} [beforeUpdateMany] A callback (or array of callbacks) executed before updateMany * * Warnings: * - As queries issued in the callbacks are not done through react-query, * any change in the data will not be automatically reflected in the UI. * - The callbacks are not executed in a transaction. In case of error, * the backend may be left in an inconsistent state. * - When calling the API directly using fetch or another client, * the callbacks will not be executed, leaving the backend in a possibly inconsistent state. * - If a callback triggers the query it's listening to, this will lead to a infinite loop. * * @example * * const dataProvider = withLifecycleCallbacks( * jsonServerProvider("http://localhost:3000"), * [ * { * resource: "posts", * afterRead: async (data, dataProvider, resource) => { * // rename field to the record * data.user_id = data.userId; * return data; * }, * // executed after create, update and updateMany * afterSave: async (record, dataProvider, resource) => { * // update the author's nb_posts * const { total } = await dataProvider.getList("users", { * filter: { id: record.user_id }, * pagination: { page: 1, perPage: 1 }, * }); * await dataProvider.update("users", { * id: user.id, * data: { nb_posts: total }, * previousData: user, * }); * return record; * }, * beforeDelete: async (params, dataProvider, resource) => { * // delete all comments linked to the post * const { data: comments } = await dataProvider.getManyReference( * "comments", * { * target: "post_id", * id: params.id, * } * ); * if (comments.length > 0) { * await dataProvider.deleteMany("comments", { * ids: comments.map((comment) => comment.id), * }); * } * // update the author's nb_posts * const { data: post } = await dataProvider.getOne("posts", { * id: params.id, * }); * const { total } = await dataProvider.getList("users", { * filter: { id: post.user_id }, * pagination: { page: 1, perPage: 1 }, * }); * await dataProvider.update("users", { * id: user.id, * data: { nb_posts: total - 1 }, * previousData: user, * }); * return params; * }, * }, * ] * ); */ const withLifecycleCallbacks = (dataProvider, handlers) => { return { ...dataProvider, getList: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeGetList', params: newParams, dataProvider, handlers, resource, }); let result = await dataProvider.getList(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterGetList', params: result, dataProvider, handlers, resource, }); result.data = await Promise.all(result.data.map(record => (0, exports.applyCallbacks)({ name: 'afterRead', params: record, dataProvider, handlers, resource, }))); return result; }, getOne: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeGetOne', params: newParams, dataProvider, handlers, resource, }); let result = await dataProvider.getOne(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterGetOne', params: result, dataProvider, handlers, resource, }); result.data = await (0, exports.applyCallbacks)({ name: 'afterRead', params: result.data, dataProvider, handlers, resource, }); return result; }, getMany: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeGetMany', params: newParams, dataProvider, handlers, resource, }); let result = await dataProvider.getMany(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterGetMany', params: result, dataProvider, handlers, resource, }); result.data = await Promise.all(result.data.map(record => (0, exports.applyCallbacks)({ name: 'afterRead', params: record, dataProvider, handlers, resource, }))); return result; }, getManyReference: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeGetManyReference', params: newParams, dataProvider, handlers, resource, }); let result = await dataProvider.getManyReference(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterGetManyReference', params: result, dataProvider, handlers, resource, }); result.data = await Promise.all(result.data.map(record => (0, exports.applyCallbacks)({ name: 'afterRead', params: record, dataProvider, handlers, resource, }))); return result; }, update: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeUpdate', params: newParams, dataProvider, handlers, resource, }); newParams.data = await (0, exports.applyCallbacks)({ name: 'beforeSave', params: newParams.data, dataProvider, handlers, resource, }); let result = await dataProvider.update(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterUpdate', params: result, dataProvider, handlers, resource, }); result.data = await (0, exports.applyCallbacks)({ name: 'afterSave', params: result.data, dataProvider, handlers, resource, }); return result; }, create: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeCreate', params: newParams, dataProvider, handlers, resource, }); newParams.data = await (0, exports.applyCallbacks)({ name: 'beforeSave', params: newParams.data, dataProvider, handlers, resource, }); let result = await dataProvider.create(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterCreate', params: result, dataProvider, handlers, resource, }); result.data = await (0, exports.applyCallbacks)({ name: 'afterSave', params: result.data, dataProvider, handlers, resource, }); return result; }, delete: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeDelete', params: newParams, dataProvider, handlers, resource, }); let result = await dataProvider.delete(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterDelete', params: result, dataProvider, handlers, resource, }); return result; }, updateMany: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeUpdateMany', params: newParams, dataProvider, handlers, resource, }); newParams.data = await (0, exports.applyCallbacks)({ name: 'beforeSave', params: newParams.data, dataProvider, handlers, resource, }); let result = await dataProvider.updateMany(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterUpdateMany', params: result, dataProvider, handlers, resource, }); const afterSaveHandlers = handlers.filter(h => (h.resource === resource || h.resource === '*') && h.afterSave); if (afterSaveHandlers.length > 0) { const { data: records } = await dataProvider.getMany(resource, { //@ts-ignore ids: result.data, }); await Promise.all(records.map(record => (0, exports.applyCallbacks)({ name: 'afterSave', params: record, dataProvider, handlers, resource, }))); } return result; }, deleteMany: async function (resource, params) { let newParams = params; newParams = await (0, exports.applyCallbacks)({ name: 'beforeDeleteMany', params: newParams, dataProvider, handlers, resource, }); let result = await dataProvider.deleteMany(resource, newParams); result = await (0, exports.applyCallbacks)({ name: 'afterDeleteMany', params: result, dataProvider, handlers, resource, }); return result; }, }; }; exports.withLifecycleCallbacks = withLifecycleCallbacks; /** * Apply callbacks to the params for the given resource and hook * @param {DataProvider} dataProvider The dataProvider * @param {ResourceCallbacks[]} handlers An array of ResourceCallbacks * @param {string} resource The resource name * @param {string} hook The hook name (beforeGetList, afterGetOne, etc.) * @param {U} params The params / result to pass to the callbacks * @returns {Promise<U>} The params / result after the callbacks have been applied */ const applyCallbacks = async function ({ name, params, dataProvider, handlers, resource, }) { let newParams = params; const handlersToApply = handlers.filter(h => (h.resource === resource || h.resource === '*') && h[name]); for (const handler of handlersToApply) { const callbacksValue = handler[name]; if (Array.isArray(callbacksValue)) { for (const callback of callbacksValue ?? []) { newParams = await callback(newParams, dataProvider, resource); } } else { newParams = await callbacksValue(newParams, dataProvider, resource); } } return newParams; }; exports.applyCallbacks = applyCallbacks; //# sourceMappingURL=withLifecycleCallbacks.js.map