loopback-datasource-juggler/lib/include_utils.js

143 lines
4.8 KiB
JavaScript

module.exports.buildOneToOneIdentityMap = buildOneToOneIdentityMap;
module.exports.buildOneToManyIdentityMap = buildOneToManyIdentityMap;
module.exports.buildOneToOneIdentityMapWithOrigKeys = buildOneToOneIdentityMapWithOrigKeys;
module.exports.join = join;
/**
* Effectively builds associative map on id -> object relation.
* 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()
* @returns {{}} object where keys are ids and values are objects itself
*/
function buildOneToOneIdentityMap(objs, idName) {
var idMap = {};
for(var i = 0; i < objs.length; i++) {
var obj = objs[i];
var id = obj[idName].toString();
idMap[id] = obj;
}
return idMap;
}
/**
* Builds key -> value map on js object base. As js object keys can be only strings keys are stored on value side.
* So, each value should be an object like that:
* { origKey: 34, value: {...}}
* origKey field name should be passed as parameter to function.
*
* @param origKeyField filed name on value side to pick original key from.
* @returns empty object to be filled with key-value pair and additional methods `keys` and `originalKeys`
*/
function newIdMap(origKeyField, valueField) {
//var idMap = Object.create(null); // not any single properties within our identity map
var idMap = {};
Object.defineProperty(idMap, "set", {
value: function(origKey, value){
var key = origKey.toString();
this[key] = {};
this[key][origKeyField] = origKey;
this[key][valueField] = value;
}
});
Object.defineProperty(idMap, "keys", { // can ask for keys simply by idMap.keys
get: function(){ return Object.keys(this); },
enumerable: false // explicitly non-enumerable
});
Object.defineProperty(idMap, "originalKeys", { // can ask for all original keys by idMap.originalKeys
get: function(){
var keys = this.keys;
var origKeys = [];
for(var i = 0; i < keys.length; i++) {
var origKey = this[keys[i]][origKeyField];
origKeys.push(origKey);
}
return origKeys;
},
enumerable: false // explicitly non-enumerable
});
Object.defineProperty(idMap, "simplified",{
get: function(){
var keys = this.keys;
var simplified = {};
for(var i = 0; i < keys.length; i++) {
var key = keys[i];
simplified[key] = this[key][valueField];
}
return simplified;
}
});
return idMap;
}
/**
* 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()
* @returns {{}} object where keys are ids and values are objects itself
*/
function buildOneToOneIdentityMapWithOrigKeys(objs, idName) {
var idMap = newIdMap("originalKey", "value");
for(var i = 0; i < objs.length; i++) {
var obj = objs[i];
var id = obj[idName];
idMap.set(id, obj);
}
return idMap;
}
/**
* Effectively builds associate map on id -> Array[Object].
* Map returned in form of object with ids in keys and array of objects with given id.
* @param objs array of objects to build from
* @param idName name of property to be used as id
*/
function buildOneToManyIdentityMap(objs, idName) {
var idMap = {};
for(var i = 0; i < objs.length; i++) {
var obj = objs[i];
var id = obj[idName].toString();
if(id in idMap) {
idMap[id].push(obj);
} else {
idMap[id] = [obj];
}
}
return idMap;
}
function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
var idMap = newIdMap("originalKey", "value");
for(var i = 0; i < objs.length; i++) {
var obj = objs[i];
var id = obj[idName];
var idString = id.toString();
if(idString in idMap) {
idMap[idString]["value"].push(obj);
} else {
idMap.set(id, [obj]);
}
}
return idMap;
}
/**
* 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) {
var ids = Object.keys(oneToOneIdMap);
for(var i = 0; i < ids.length; i++) {
var id = ids[i];
var obj = oneToOneIdMap[id];
var objectsToMergeIn = oneToManyIdMap[id] || [];
mergeF(obj, objectsToMergeIn);
}
}