loopback-datasource-juggler/lib/include_utils.js

121 lines
3.7 KiB
JavaScript
Raw Normal View History

2019-05-08 15:45:37 +00:00
// Copyright IBM Corp. 2015,2018. All Rights Reserved.
2016-04-01 22:25:16 +00:00
// Node module: loopback-datasource-juggler
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
2016-08-22 19:55:22 +00:00
'use strict';
2018-12-07 14:54:29 +00:00
const g = require('strong-globalize')();
2018-10-19 18:56:51 +00:00
module.exports.buildOneToOneIdentityMapWithOrigKeys = buildOneToOneIdentityMapWithOrigKeys;
2015-10-30 15:15:48 +00:00
module.exports.buildOneToManyIdentityMapWithOrigKeys = buildOneToManyIdentityMapWithOrigKeys;
module.exports.join = join;
2015-10-30 15:15:48 +00:00
module.exports.KVMap = KVMap;
const util = require('util');
function getId(obj, idName) {
2018-12-07 14:54:29 +00:00
const id = obj && obj[idName];
if (id == null) {
2018-10-19 18:56:51 +00:00
const msg = g.f('ID property "%s" is missing for included item: %j. ' +
'Please make sure `fields` include "%s" if it\'s present in the `filter`',
idName, obj, idName);
const err = new Error(msg);
err.statusCode = 400;
throw err;
}
return id;
}
/**
* Effectively builds associative map on id -> object relation and stores original keys.
* Map returned in form of object with ids in keys and object as values.
* @param objs array of objects to build from
* @param idName name of property to be used as id. Such property considered to be unique across array.
* In case of collisions last wins. For non-unique ids use buildOneToManyIdentityMap()
2015-10-30 15:15:48 +00:00
* @returns {} object where keys are ids and values are objects itself
*/
function buildOneToOneIdentityMapWithOrigKeys(objs, idName) {
2018-12-07 14:54:29 +00:00
const kvMap = new KVMap();
for (let i = 0; i < objs.length; i++) {
const obj = objs[i];
const id = getId(obj, idName);
2015-10-30 15:15:48 +00:00
kvMap.set(id, obj);
}
2015-10-30 15:15:48 +00:00
return kvMap;
}
function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
2018-12-07 14:54:29 +00:00
const kvMap = new KVMap();
for (let i = 0; i < objs.length; i++) {
const obj = objs[i];
const id = getId(obj, idName);
const value = kvMap.get(id) || [];
2015-10-30 15:15:48 +00:00
value.push(obj);
kvMap.set(id, value);
}
2015-10-30 15:15:48 +00:00
return kvMap;
}
/**
* Yeah, it joins. You need three things id -> obj1 map, id -> [obj2] map and merge function.
* This functions will take each obj1, locate all data to join in map2 and call merge function.
* @param oneToOneIdMap
* @param oneToManyIdMap
* @param mergeF function(obj, objectsToMergeIn)
*/
function join(oneToOneIdMap, oneToManyIdMap, mergeF) {
2018-12-07 14:54:29 +00:00
const ids = oneToOneIdMap.getKeys();
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
const obj = oneToOneIdMap.get(id);
const objectsToMergeIn = oneToManyIdMap.get(id) || [];
mergeF(obj, objectsToMergeIn);
}
}
2015-10-30 15:15:48 +00:00
2015-10-30 15:19:37 +00:00
/**
* Map with arbitrary keys and values. User .set() and .get() to work with values instead of []
* @returns {{set: Function, get: Function, remove: Function, exist: Function, getKeys: Function}}
* @constructor
*/
2016-04-01 11:48:17 +00:00
function KVMap() {
2018-12-07 14:54:29 +00:00
const _originalKeyFieldName = 'originalKey';
const _valueKeyFieldName = 'value';
const _dict = {};
const keyToString = function(key) { return key.toString(); };
const mapImpl = {
2016-04-01 11:48:17 +00:00
set: function(key, value) {
2018-12-07 14:54:29 +00:00
const recordObj = {};
2015-10-30 15:15:48 +00:00
recordObj[_originalKeyFieldName] = key;
recordObj[_valueKeyFieldName] = value;
_dict[keyToString(key)] = recordObj;
return true;
},
2016-04-01 11:48:17 +00:00
get: function(key) {
2018-12-07 14:54:29 +00:00
const storeObj = _dict[keyToString(key)];
2016-04-01 11:48:17 +00:00
if (storeObj) {
2015-10-30 15:15:48 +00:00
return storeObj[_valueKeyFieldName];
} else {
return undefined;
}
},
2016-04-01 11:48:17 +00:00
remove: function(key) {
2015-10-30 15:15:48 +00:00
delete _dict[keyToString(key)];
return true;
},
exist: function(key) {
2018-12-07 14:54:29 +00:00
const result = _dict.hasOwnProperty(keyToString(key));
2015-10-30 15:15:48 +00:00
return result;
},
2016-04-01 11:48:17 +00:00
getKeys: function() {
2018-12-07 14:54:29 +00:00
const result = [];
for (const key in _dict) {
2015-10-30 15:15:48 +00:00
result.push(_dict[key][_originalKeyFieldName]);
}
return result;
2016-04-01 11:48:17 +00:00
},
2015-10-30 15:15:48 +00:00
};
return mapImpl;
}