merge and deep-copy objects, get/set properties by dotted name, taint detect
npm install qhashqhash
================================================================


Hash and object manipulation
Functions to get/set properties by dotted name, deep-copy, merge, taint detect.
qhash Api
----------------------------------------------------------------
const qhash = require('qhash');
Deep copy all enumerable properties of the source hash into the target hash. No sub-hash
contained in source is reused on target, each is copied recursively. If target
is not specified, the this object is used. If noOverwrite is set, existing
properties of target are not modified. Returns target.
Hashes are javascript objects that are not instanceof any class (ie, whose
constructor is the same as the constructor of {}, Object). Non-hash objects
are assumed to be class instances and are assigned directly; if their properties
are modified in target, they will also change in source.
var dst = { };
var src = { a: {b:2}, d: new Date() };
qhash.merge(dst, src);
dst.a // => {b:2}, hash copied
dst.a === src.a; // => false, copied into new hash
assert.deepEqual(dst.a, src.a); // => true, hash contents match
dst.d === src.d; // => true, same Date instance
dst.d.x = 1;
src.d.x === 1; // => true, same Date modified
Merge multiple: recursively deep copy all properties from all sources onto target
by repeatedly calling qhash.merge. Target must be specified, there is no default.
It is safe to layer multiple read-only hashes, no sub-hash from any source is used
directly. Returns target.
If noOverwrite is set it retains the first seen version of each set property (from
the lowest-numered source object), else retains the last seen version.
Retrieve a property set on the source hash by dotted name. Returns the property
value. Returns undefined if the named property or one of its internal hashes is
not set.
qhash.get({ a: {b: 2} }, 'a'); // => {b: 2}
qhash.get({ a: {b: 2} }, 'a.b'); // => 2
qhash.get({ a: {b: 2} }, 'b'); // => undefined
qhash.get({ a: {} }, 'a.b.c'); // => undefined
Set a property on the target hash by dotted name. Any missing internal hashes
are created as necessary. Returns the value.
It is possible to set a property to undefined, making it appear to be unset.
var x;
qhash.set(x = {}, 'a', 1); // x => { a: 1 }
qhash.set(x = {}, 'a.a.a', 1); // x => { a: {a: {a: 1}} }
qhash.set(x = {c:3}, 'a.b', 1); // x => { c: 3, a: {b: 1} }
Retrieve the named property from every hash in the array. Returns an array of
values in the same order as the hashes, with undefined for any unset property.
var dataset = [{a:1}, {a:2}, {c:3}];
qhash.selectField(dataset, 'a'); // => [1, 2, undefined]
var dataset = [{a:{b:11}}, {a:{b:22}}];
qhash.selectField(dataset, 'a.b'); // => [11, 22]
Map the array of objects by their idName property into the provided hash intoHash
(or into a new hash {}), and return the mapping.
var dataset = [ { _id: 'one', a: 1 }, { _id: 'two', b: 2 } ];
var hash = qhash.mapById(dataset, '_id');
// => { one: {_id:'one', a:1}, two: {_id:'two', b:2} }
Attach the given properties to the target object. The methods argument is a
name-value hash of the property names and property values to attach. This call can
be useful for decorating container objects with hidden get/set/merge methods.
Options:
* hide - make the attached methods non-enumerable. Default false.
* noOverwrite - do not overwrite existing properties. Default false.
E.g.,
var qhash = require('qhash');
var hash = { a: 0 };
qhash.decorate(hash, {set: qhash.set, get: qhash.get}, {hide: true});
hash.set === qhash.set; // => true
hash.set('a', 123);
hash.a === 123; // => true
hash.get('a'); // => 123
Object.keys(hash); // => [ 'a' ]
JSON.stringify(hash); // => '{"a":123}'
Convert obj to a struct for optimized property access.
Node objects can be hashes or structs. A hash is tuned for unpredictable property
names; a struct for a fixed set of properties in mapped locations. The difference
between hash and struct is invisible, but it is faster to access the properties of
a struct.
Node internally will also detect usage and eventually convert: repeatedly
accessing the same properties on a hash will optimize it into a struct, and adding
new properties to a struct will convert it into a hash.
var obj = new Object(); // once a hash
obj.a = 1;
obj.b = 2;
qhash.optimize(obj); // now a struct
qdiff Api
----------------------------------------------------------------
const qdiff = require('qhash/qdiff');
Compute a backup object that captures all details of item. Any modifications made
to item or any of its properties (ie objects reachable from the item), including
property or object attributes, will be reflected in a subsequent backup.
Compare the two backups and return true if they are the same, false if they are not.
This comparison detects added/deleted/changed contents and properties, as well as
changes to property attributes (writable, enumerable, configurable) or state (sealed,
frozen, extensible).
Options:
- name - the top-level object name to use, else the default is 'x'
- skip - object whose properties are names of properties to not compare. The names
are in hierchical dotted names format, eg { skip: { 'x.a.b': 1 } } meaning ignore
differences in property a.b of { a: { b: 1 } } and { a: { b: 2 } }.
Change Log
----------------
- 1.3.0 - qdiff.backup and qdiff.compare functions
- 1.2.0 - mmerge, mapById functions
- 1.1.0 - optimize call to convert hash to struct
- 1.0.2 - fix null deref in test
- 1.0.1 - faster get/set for longer property names
- 1.0.0 - initial fixed version, 2017-03-27
Related Work
----------------------------------------------------------------
- util._extend(to, fm) - shallow copy (in reverse order!) of own properties, 8.4m/s
- Object.assign(to, fm) - shallow copy (in order) of own properties, 3.3m/s
- Object.create(ob) - new object with its inherited properties set to the copied object, 17m/s
- for (key in ob) - iterate over all enumerable properties, 16m/s copy but only 1m/s if ob has non-empty prototype
- Object.keys(ob) - list of enumerable own properties, 13m/s for just keys, 8.8m/s copy