summaryrefslogtreecommitdiff
path: root/src/app/db/service/pivot/helpers.js
blob: 1d8f7f2ed2e8713d212c9cea962da8356c1f0ca3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
 * 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 },
        })
      )
  );
}