Looks better now
This commit is contained in:
parent
1cab0164c2
commit
638002bc59
|
@ -495,13 +495,9 @@ Inclusion.include = function (objects, include, options, cb) {
|
||||||
function includeHasManySimple(callback) {
|
function includeHasManySimple(callback) {
|
||||||
//Map for Indexing objects by their id for faster retrieval
|
//Map for Indexing objects by their id for faster retrieval
|
||||||
var objIdMap2 = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, relation.keyFrom);
|
var objIdMap2 = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, relation.keyFrom);
|
||||||
console.log("### objIdMap2: " + JSON.stringify(objIdMap2));
|
|
||||||
// all ids of primary objects to use in query are original. So, ObjectIds stay ObjectIds and Ints stay Ints.
|
|
||||||
// No .toString() conversion.
|
|
||||||
var sourceIds = objIdMap2.originalKeys;
|
|
||||||
|
|
||||||
filter.where[relation.keyTo] = {
|
filter.where[relation.keyTo] = {
|
||||||
inq: uniq(sourceIds)
|
inq: uniq(objIdMap2.getKeys())
|
||||||
};
|
};
|
||||||
|
|
||||||
relation.applyScope(null, filter);
|
relation.applyScope(null, filter);
|
||||||
|
@ -511,8 +507,8 @@ Inclusion.include = function (objects, include, options, cb) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
var targetsIdMap = includeUtils.buildOneToManyIdentityMap(targets, relation.keyTo);
|
var targetsIdMap = includeUtils.buildOneToManyIdentityMapWithOrigKeys(targets, relation.keyTo);
|
||||||
includeUtils.join(objIdMap2.simplified, targetsIdMap, function(obj1, valueToMergeIn){
|
includeUtils.join(objIdMap2, targetsIdMap, function(obj1, valueToMergeIn){
|
||||||
defineCachedRelations(obj1);
|
defineCachedRelations(obj1);
|
||||||
obj1.__cachedRelations[relationName] = valueToMergeIn;
|
obj1.__cachedRelations[relationName] = valueToMergeIn;
|
||||||
processTargetObj(obj1, function(){});
|
processTargetObj(obj1, function(){});
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
module.exports.buildOneToOneIdentityMap = buildOneToOneIdentityMap;
|
module.exports.buildOneToOneIdentityMap = buildOneToOneIdentityMap;
|
||||||
module.exports.buildOneToManyIdentityMap = buildOneToManyIdentityMap;
|
module.exports.buildOneToManyIdentityMap = buildOneToManyIdentityMap;
|
||||||
module.exports.buildOneToOneIdentityMapWithOrigKeys = buildOneToOneIdentityMapWithOrigKeys;
|
module.exports.buildOneToOneIdentityMapWithOrigKeys = buildOneToOneIdentityMapWithOrigKeys;
|
||||||
|
module.exports.buildOneToManyIdentityMapWithOrigKeys = buildOneToManyIdentityMapWithOrigKeys;
|
||||||
module.exports.join = join;
|
module.exports.join = join;
|
||||||
|
module.exports.KVMap = KVMap;
|
||||||
/**
|
/**
|
||||||
* Effectively builds associative map on id -> object relation.
|
* Effectively builds associative map on id -> object relation.
|
||||||
* Map returned in form of object with ids in keys and object as values.
|
* Map returned in form of object with ids in keys and object as values.
|
||||||
|
@ -20,72 +22,22 @@ function buildOneToOneIdentityMap(objs, idName) {
|
||||||
return idMap;
|
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.
|
* 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.
|
* Map returned in form of object with ids in keys and object as values.
|
||||||
* @param objs array of objects to build from
|
* @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.
|
* @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()
|
* In case of collisions last wins. For non-unique ids use buildOneToManyIdentityMap()
|
||||||
* @returns {{}} object where keys are ids and values are objects itself
|
* @returns {} object where keys are ids and values are objects itself
|
||||||
*/
|
*/
|
||||||
function buildOneToOneIdentityMapWithOrigKeys(objs, idName) {
|
function buildOneToOneIdentityMapWithOrigKeys(objs, idName) {
|
||||||
var idMap = newIdMap("originalKey", "value");
|
var kvMap = new KVMap();
|
||||||
|
|
||||||
for(var i = 0; i < objs.length; i++) {
|
for(var i = 0; i < objs.length; i++) {
|
||||||
var obj = objs[i];
|
var obj = objs[i];
|
||||||
var id = obj[idName];
|
var id = obj[idName];
|
||||||
idMap.set(id, obj);
|
kvMap.set(id, obj);
|
||||||
}
|
}
|
||||||
return idMap;
|
return kvMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,18 +61,15 @@ function buildOneToManyIdentityMap(objs, idName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
|
function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
|
||||||
var idMap = newIdMap("originalKey", "value");
|
var kvMap = new KVMap();
|
||||||
for(var i = 0; i < objs.length; i++) {
|
for(var i = 0; i < objs.length; i++) {
|
||||||
var obj = objs[i];
|
var obj = objs[i];
|
||||||
var id = obj[idName];
|
var id = obj[idName];
|
||||||
var idString = id.toString();
|
var value = kvMap.get(id) || [];
|
||||||
if(idString in idMap) {
|
value.push(obj);
|
||||||
idMap[idString]["value"].push(obj);
|
kvMap.set(id, value);
|
||||||
} else {
|
|
||||||
idMap.set(id, [obj]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return idMap;
|
return kvMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,11 +81,54 @@ function buildOneToManyIdentityMapWithOrigKeys(objs, idName) {
|
||||||
* @param mergeF function(obj, objectsToMergeIn)
|
* @param mergeF function(obj, objectsToMergeIn)
|
||||||
*/
|
*/
|
||||||
function join(oneToOneIdMap, oneToManyIdMap, mergeF) {
|
function join(oneToOneIdMap, oneToManyIdMap, mergeF) {
|
||||||
var ids = Object.keys(oneToOneIdMap);
|
var ids = oneToOneIdMap.getKeys();
|
||||||
for(var i = 0; i < ids.length; i++) {
|
for(var i = 0; i < ids.length; i++) {
|
||||||
var id = ids[i];
|
var id = ids[i];
|
||||||
var obj = oneToOneIdMap[id];
|
var obj = oneToOneIdMap.get(id);
|
||||||
var objectsToMergeIn = oneToManyIdMap[id] || [];
|
var objectsToMergeIn = oneToManyIdMap.get(id) || [];
|
||||||
mergeF(obj, objectsToMergeIn);
|
mergeF(obj, objectsToMergeIn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function KVMap(){
|
||||||
|
var _originalKeyFieldName = 'originalKey';
|
||||||
|
var _valueKeyFieldName = 'value';
|
||||||
|
var _dict = {};
|
||||||
|
var keyToString = function(key){ return key.toString() };
|
||||||
|
var mapImpl = {
|
||||||
|
set: function(key, value){
|
||||||
|
var recordObj = {};
|
||||||
|
recordObj[_originalKeyFieldName] = key;
|
||||||
|
recordObj[_valueKeyFieldName] = value;
|
||||||
|
_dict[keyToString(key)] = recordObj;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
get: function(key){
|
||||||
|
var storeObj = _dict[keyToString(key)];
|
||||||
|
if(storeObj) {
|
||||||
|
return storeObj[_valueKeyFieldName];
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
remove: function(key){
|
||||||
|
delete _dict[keyToString(key)];
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
exist: function(key) {
|
||||||
|
var result = _dict.hasOwnProperty(keyToString(key));
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
getKeys: function(){
|
||||||
|
var result = [];
|
||||||
|
for(var key in _dict) {
|
||||||
|
result.push(_dict[key][_originalKeyFieldName]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
return mapImpl;
|
||||||
|
}
|
||||||
|
|
|
@ -31,56 +31,19 @@ describe('include_util', function(){
|
||||||
result["33"]["letter"].should.equal("C");
|
result["33"]["letter"].should.equal("C");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#buildOneToOneIdentityMapWithOrigKeys', function(){
|
describe('#buildOneToOneIdentityMapWithOrigKeys', function(){
|
||||||
it('should return an object with keys', function(){
|
it('should return an object with keys', function(){
|
||||||
var objs = [
|
var objs = [
|
||||||
{id: 11, letter: "A"},
|
{id: 11, letter: "A"},
|
||||||
{id: 22, letter: "B"}
|
{id: 22, letter: "B"}
|
||||||
];
|
];
|
||||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, "id");
|
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, 'id');
|
||||||
result.should.be.an.instanceOf(Object);
|
result.get(11).should.be.ok;
|
||||||
result.should.have.property("11");
|
result.get(22).should.be.ok;
|
||||||
result.should.have.property("22");
|
result.getKeys().should.have.lengthOf(2); // no additional properties
|
||||||
Object.keys(result).should.have.lengthOf(2); // no additional properties
|
|
||||||
});
|
|
||||||
it('should return all stringized keys with .keys method', function(){
|
|
||||||
var objs = [
|
|
||||||
{id: 11, letter: "A"},
|
|
||||||
{id: 22, letter: "B"},
|
|
||||||
{id: "cc", letter: "C"}
|
|
||||||
];
|
|
||||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, "id");
|
|
||||||
var keys = result.keys;
|
|
||||||
keys.should.be.instanceOf(Array);
|
|
||||||
keys.should.have.lengthOf(3);
|
|
||||||
keys.should.be.eql(['11', '22', 'cc']);
|
|
||||||
});
|
|
||||||
it("should return all original keys with .originalKeys method", function(){
|
|
||||||
var objs = [
|
|
||||||
{id: 11, letter: "A"},
|
|
||||||
{id: 22, letter: "B"},
|
|
||||||
{id: "vv", letter: "V"}
|
|
||||||
];
|
|
||||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, "id");
|
|
||||||
var origKeys = result.originalKeys;
|
|
||||||
origKeys.should.be.instanceOf(Array);
|
|
||||||
origKeys.should.have.lengthOf(3);
|
|
||||||
origKeys.should.be.eql([11, 22, 'vv']);
|
|
||||||
});
|
|
||||||
it('should have .keys and .originalKeys in same order', function(){
|
|
||||||
var objs = [
|
|
||||||
{id: 11, letter: "A"},
|
|
||||||
{id: 22, letter: "B"},
|
|
||||||
{id: "vv", letter: "V"}
|
|
||||||
];
|
|
||||||
var result = includeUtils.buildOneToOneIdentityMapWithOrigKeys(objs, "id");
|
|
||||||
var keys = result.keys;
|
|
||||||
var origKeys = result.originalKeys;
|
|
||||||
origKeys.map(function(a){return a.toString();}).should.be.eql(keys);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#buildOneToManyIdentityMap', function(){
|
describe('#buildOneToManyIdentityMap', function(){
|
||||||
it('should return an object with keys', function(){
|
it('should return an object with keys', function(){
|
||||||
var objs = [
|
var objs = [
|
||||||
{id: 11, letter: "A"},
|
{id: 11, letter: "A"},
|
||||||
|
@ -108,3 +71,63 @@ describe('include_util', function(){
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('KVMap', function(){
|
||||||
|
it('should allow to set and get value with key string', function(){
|
||||||
|
var map = new includeUtils.KVMap();
|
||||||
|
map.set('name', 'Alex');
|
||||||
|
map.set('gender', true);
|
||||||
|
map.set('age', 25);
|
||||||
|
map.get('name').should.be.equal('Alex');
|
||||||
|
map.get('gender').should.be.equal(true);
|
||||||
|
map.get('age').should.be.equal(25);
|
||||||
|
});
|
||||||
|
it('should allow to set and get value with arbitrary key type', function(){
|
||||||
|
var map = new includeUtils.KVMap();
|
||||||
|
map.set('name', 'Alex');
|
||||||
|
map.set(true, 'male');
|
||||||
|
map.set(false, false);
|
||||||
|
map.set({isTrue: 'yes'}, 25);
|
||||||
|
map.get('name').should.be.equal('Alex');
|
||||||
|
map.get(true).should.be.equal('male');
|
||||||
|
map.get(false).should.be.equal(false);
|
||||||
|
map.get({isTrue: 'yes'}).should.be.equal(25);
|
||||||
|
});
|
||||||
|
it('should not allow to get values with [] operator', function(){
|
||||||
|
var map = new includeUtils.KVMap();
|
||||||
|
map.set('name', 'Alex');
|
||||||
|
(map['name'] === undefined).should.be.equal(true);
|
||||||
|
});
|
||||||
|
it('should provide .exist() method for checking if key presented', function(){
|
||||||
|
var map = new includeUtils.KVMap();
|
||||||
|
map.set('one', 1);
|
||||||
|
map.set(2, 'two');
|
||||||
|
map.set(true, 'true');
|
||||||
|
map.exist('one').should.be.true;
|
||||||
|
map.exist(2).should.be.true;
|
||||||
|
map.exist(true).should.be.true;
|
||||||
|
map.exist('two').should.be.false;
|
||||||
|
});
|
||||||
|
it('should return array of original keys with .getKeys()', function(){
|
||||||
|
var map = new includeUtils.KVMap();
|
||||||
|
map.set('one', 1);
|
||||||
|
map.set(2, 'two');
|
||||||
|
map.set(true, 'true');
|
||||||
|
var keys = map.getKeys();
|
||||||
|
keys.should.containEql('one');
|
||||||
|
keys.should.containEql(2);
|
||||||
|
keys.should.containEql(true);
|
||||||
|
});
|
||||||
|
it('should allow to store and fetch arrays', function(){
|
||||||
|
var map = new includeUtils.KVMap();
|
||||||
|
map.set(1, [1, 2, 3]);
|
||||||
|
map.set(2, [2, 3, 4]);
|
||||||
|
var valueOne = map.get(1);
|
||||||
|
valueOne.should.be.eql([1, 2, 3]);
|
||||||
|
valueOne.push(99);
|
||||||
|
map.set(1, valueOne);
|
||||||
|
var valueOneUpdated = map.get(1);
|
||||||
|
valueOneUpdated.should.be.eql([1, 2, 3, 99]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue