/** * Pivot Table Helpers * @module app/db/service/pivot/helpers */ import * as db from "app/db/query"; /** * Fetch a set of database objects from a pivot table via relations * @param {bookshelf.Model} Model the pivot table model to query * @param {string} parentIdAttribute the parent ID attribute on the pivot * @param {number} parentId the parent ID to query * @param {string} childIdAttribute the child ID attribute on the pivot * @param {number} childId the child ID to query */ export function indexPivotTable({ Model, parentIdAttribute, parentId, childIdAttribute, childId, }) { return Model.query((builder) => { builder.where(parentIdAttribute, parentId); if (Array.isArray(childId)) { builder.whereIn(childIdAttribute, childId); } else { builder.andWhere(childIdAttribute, childId); } }).fetchAll(); } /** * Get the parent, child, and pivot models from a service, as well as their ID attribute names * @param {Service} service the pivot table service * @return {object} the models and ID attribute names */ export function getPivotModels(service) { const { parent, Model, ChildModel, childRelation, parentPivotRelation, pivotChildRelation, } = service.options; const { Model: ParentModel } = service.options.parent; const parentIdAttribute = ParentModel.prototype.idAttribute; const pivotIdAttribute = Model.prototype.idAttribute; const childIdAttribute = ChildModel.prototype.idAttribute; const parentTableName = ParentModel.prototype.tableName; const pivotTableName = Model.prototype.tableName; const childTableName = ChildModel.prototype.tableName; return { parent, Model, ParentModel, ChildModel, parentTableName, pivotTableName, childTableName, parentIdAttribute, pivotIdAttribute, childIdAttribute, parentPivotRelation, pivotChildRelation, childRelation, }; } /** * Create a single instance * @param {bookshelf.Model} options.Model the model * @param {Object} options.data data to add * @param {Array} options.instances fetched instances to dedupe * @return {Object} result */ export async function handleCreateOne({ Model, data, instances }) { if (instances.length) { throw new Error("pivot relation already exists"); } return await db.create({ Model, data }); } /** * Create multiple instances * @param {bookshelf.Model} options.Model the model * @param {Object} options.data data to add * @param {Array} options.instances fetched instances to dedupe * @param {string} options.childIdAttribute the child ID, found on the body, which should point to an array * @return {Object} result */ export async function handleCreateMany({ Model, data, childIdAttribute, instances, }) { let { [childIdAttribute]: child_ids, ...columns } = data; const matched = new Set( instances.map((instance) => instance.get(childIdAttribute)) ); return await Promise.all( Array.from(new Set(child_ids)) .filter((child_id) => !matched.has(child_id)) .map((child_id) => db.create({ Model, data: { ...columns, [childIdAttribute]: child_id }, }) ) ); }