UNPKG

3.77 kBJavaScriptView Raw
1// Copyright IBM Corp. 2015,2019. All Rights Reserved.
2// Node module: loopback-datasource-juggler
3// This file is licensed under the MIT License.
4// License text available at https://opensource.org/licenses/MIT
5
6'use strict';
7
8const g = require('strong-globalize')();
9
10module.exports.buildOneToOneIdentityMapWithOrigKeys = buildOneToOneIdentityMapWithOrigKeys;
11module.exports.buildOneToManyIdentityMapWithOrigKeys = buildOneToManyIdentityMapWithOrigKeys;
12module.exports.join = join;
13module.exports.KVMap = KVMap;
14
15const util = require('util');
16
17function getId(obj, idName) {
18 const id = obj && obj[idName];
19 if (id == null) {
20 const msg = g.f('ID property "%s" is missing for included item: %j. ' +
21 'Please make sure `fields` include "%s" if it\'s present in the `filter`',
22 idName, obj, idName);
23 const err = new Error(msg);
24 err.statusCode = 400;
25 throw err;
26 }
27 return id;
28}
29/**
30 * Effectively builds associative map on id -> object relation and stores original keys.
31 * Map returned in form of object with ids in keys and object as values.
32 * @param objs array of objects to build from
33 * @param idName name of property to be used as id. Such property considered to be unique across array.
34 * In case of collisions last wins. For non-unique ids use buildOneToManyIdentityMap()
35 * @returns {} object where keys are ids and values are objects itself
36 */
37function buildOneToOneIdentityMapWithOrigKeys(objs, idName) {
38 const kvMap = new KVMap();
39 for (let i = 0; i < objs.length; i++) {
40 const obj = objs[i];
41 const id = getId(obj, idName);
42 kvMap.set(id, obj);
43 }
44 return kvMap;
45}
46
47function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
48 const kvMap = new KVMap();
49 for (let i = 0; i < objs.length; i++) {
50 const obj = objs[i];
51 const id = getId(obj, idName);
52 const value = kvMap.get(id) || [];
53 value.push(obj);
54 kvMap.set(id, value);
55 }
56 return kvMap;
57}
58
59/**
60 * Yeah, it joins. You need three things id -> obj1 map, id -> [obj2] map and merge function.
61 * This functions will take each obj1, locate all data to join in map2 and call merge function.
62 * @param oneToOneIdMap
63 * @param oneToManyIdMap
64 * @param mergeF function(obj, objectsToMergeIn)
65 */
66function join(oneToOneIdMap, oneToManyIdMap, mergeF) {
67 const ids = oneToOneIdMap.getKeys();
68 for (let i = 0; i < ids.length; i++) {
69 const id = ids[i];
70 const obj = oneToOneIdMap.get(id);
71 const objectsToMergeIn = oneToManyIdMap.get(id) || [];
72 mergeF(obj, objectsToMergeIn);
73 }
74}
75
76/**
77 * Map with arbitrary keys and values. User .set() and .get() to work with values instead of []
78 * @returns {{set: Function, get: Function, remove: Function, exist: Function, getKeys: Function}}
79 * @constructor
80 */
81function KVMap() {
82 const _originalKeyFieldName = 'originalKey';
83 const _valueKeyFieldName = 'value';
84 const _dict = {};
85 const keyToString = function(key) { return key.toString(); };
86 const mapImpl = {
87 set: function(key, value) {
88 const recordObj = {};
89 recordObj[_originalKeyFieldName] = key;
90 recordObj[_valueKeyFieldName] = value;
91 _dict[keyToString(key)] = recordObj;
92 return true;
93 },
94 get: function(key) {
95 const storeObj = _dict[keyToString(key)];
96 if (storeObj) {
97 return storeObj[_valueKeyFieldName];
98 } else {
99 return undefined;
100 }
101 },
102 remove: function(key) {
103 delete _dict[keyToString(key)];
104 return true;
105 },
106 exist: function(key) {
107 const result = _dict.hasOwnProperty(keyToString(key));
108 return result;
109 },
110 getKeys: function() {
111 const result = [];
112 for (const key in _dict) {
113 result.push(_dict[key][_originalKeyFieldName]);
114 }
115 return result;
116 },
117
118 };
119 return mapImpl;
120}