/** * Service API methods * @module app/db/service/base/methods */ import * as db from "app/db/query"; import { reduceValidColumns } from "app/db/helpers"; import { PERMISSIONS } from "app/constants"; import debugModule from "debug"; /** * Export methods for dealing with multiple records */ export { showMany, updateMany, destroyMany } from "app/db/service/base/many"; /** * Debug logger */ const debug = debugModule("shoebox:service"); /** * API to filter and paginate lists of resources */ export function index(service) { const { columns } = service; return async function indexMiddleware(request, response, next) { const { query: userQuery, params, permission, user } = request; const { paginate } = service.options; const queryBuilder = service.queryBuilder; const query = { ...userQuery, ...params, }; const withRelated = userQuery.related ? userQuery.related.split(",") : []; if (permission === PERMISSIONS.ALLOW_FOR_OWNER) { query.user_id = user.user_id; } let data, pagination; let promises = [ db.index({ Model: service.Model, query, paginate, user, columns, queryBuilder, withRelated, }), ]; if (paginate) { promises.push( db.count({ Model: service.Model, query, paginate, user, columns, queryBuilder, }) ); } else { promises.push(new Promise((resolve) => resolve({}))); } try { [data, pagination] = await Promise.all(promises); } catch (error) { debug(`${service.resource} Index error`); debug(error); console.error(error); return next(error); } response.locals = { data, pagination, query, }; next(); }; } /** * API to query for a single record by ID */ export function show(service) { return async function showMiddleware(request, response, next) { const { user, permission, query } = request; const withRelated = query.related ? query.related.split(",") : []; let data; try { data = await db.show({ Model: service.Model, objectID: parseInt(request.params.id), withRelated, }); } catch (error) { debug(`${service.resource} Show error`); debug(error); return next(error); } if (!data) { response.locals = {}; next(); } else if ( permission === PERMISSIONS.ALLOW_FOR_OWNER && data.get("user_id") !== user.user_id ) { next(new Error("PermissionsError")); } else { response.locals = { data }; next(); } }; } /** * API to insert a new record */ export function create(service) { return async function createMiddleware(request, response, next) { const body = reduceValidColumns( request.body, service.columns, service.options.privateFields ); if (service.options.parent) { service.idAttributes.forEach((idAttribute) => { if (idAttribute in request.params && idAttribute in service.columns) { body[idAttribute] = request.params[idAttribute]; } }); } let data; try { data = await db.create({ Model: service.Model, data: body }); } catch (error) { debug(`${service.resource} create error`); console.error(error); return next(error); } response.locals = { data }; next(); }; } /** * API to update a single record */ export function update(service) { return async function updateMiddleware(request, response, next) { const { data: instance } = response.locals; const { user, permission } = request; if ( permission === PERMISSIONS.ALLOW_FOR_OWNER && instance.get("user_id") !== user.user_id ) { return next(new Error("PermissionsError")); } const body = reduceValidColumns( request.body, service.columns, service.options.privateFields ); let data; try { data = await db.update({ instance, data: body, }); } catch (error) { debug(`${service.resource} update error`); debug(error); next(new Error(error)); } response.locals = { data }; next(); }; } /** * API to sort records */ export function sort(service) { return async function sortMiddleware(request, response, next) { const { ids } = request.body; const items = await db.showIDs({ Model: service.Model, ids, }); for (let item of items) { item.set("sort_order", ids.indexOf(item.id)); } await Promise.all(items.map((item) => item.save())); response.locals.success = true; next(); }; } /** * API to destroy a single record */ export function destroy(service) { return async function destroyMiddleware(request, response, next) { try { await db.destroy({ Model: service.Model, objectID: request.params.id, }); } catch (error) { debug(`${service.resource} destroy error`); console.error(error); return next(new Error(error)); } response.locals.success = true; response.locals.id = request.params.id; next(); }; }