Add Change.apply method for object modification
This commit is contained in:
parent
26e427f4a0
commit
a80cedd870
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
## CURRENT
|
## CURRENT
|
||||||
|
|
||||||
|
- Add Change.apply method for modifying objects
|
||||||
- Update bunyan to 0.23.1
|
- Update bunyan to 0.23.1
|
||||||
- #143 Preserve raw Buffer value in Control objects
|
- #143 Preserve raw Buffer value in Control objects
|
||||||
- Test code coverage with node-istanbul
|
- Test code coverage with node-istanbul
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||||
|
|
||||||
var assert = require('assert');
|
var assert = require('assert-plus');
|
||||||
|
|
||||||
var Attribute = require('./attribute');
|
var Attribute = require('./attribute');
|
||||||
var Protocol = require('./protocol');
|
var Protocol = require('./protocol');
|
||||||
|
@ -111,6 +111,68 @@ Change.compare = function (a, b) {
|
||||||
return Attribute.compare(a.modification, b.modification);
|
return Attribute.compare(a.modification, b.modification);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a Change to properties of an object.
|
||||||
|
*
|
||||||
|
* @param {Object} change the change to apply.
|
||||||
|
* @param {Object} obj the object to apply it to.
|
||||||
|
* @param {Boolean} scalar convert single-item arrays to scalars. Default: false
|
||||||
|
*/
|
||||||
|
Change.apply = function apply(change, obj, scalar) {
|
||||||
|
assert.string(change.operation);
|
||||||
|
assert.string(change.modification.type);
|
||||||
|
assert.ok(Array.isArray(change.modification.vals));
|
||||||
|
assert.object(obj);
|
||||||
|
|
||||||
|
var type = change.modification.type;
|
||||||
|
var vals = change.modification.vals;
|
||||||
|
var data = obj[type];
|
||||||
|
if (data !== undefined) {
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
data = [data];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data = [];
|
||||||
|
}
|
||||||
|
switch (change.operation) {
|
||||||
|
case 'replace':
|
||||||
|
if (vals.length === 0) {
|
||||||
|
// replace empty is a delete
|
||||||
|
delete obj[type];
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
|
data = vals;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'add':
|
||||||
|
// add only new unique entries
|
||||||
|
var newValues = vals.filter(function (entry) {
|
||||||
|
return (data.indexOf(entry) === -1);
|
||||||
|
});
|
||||||
|
data = data.concat(newValues);
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
data = data.filter(function (entry) {
|
||||||
|
return (vals.indexOf(entry) === -1);
|
||||||
|
});
|
||||||
|
if (data.length === 0) {
|
||||||
|
// Erase the attribute if empty
|
||||||
|
delete obj[type];
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (scalar && data.length === 1) {
|
||||||
|
// store single-value outputs as scalars, if requested
|
||||||
|
obj[type] = data[0];
|
||||||
|
} else {
|
||||||
|
obj[type] = data;
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
Change.prototype.parse = function (ber) {
|
Change.prototype.parse = function (ber) {
|
||||||
assert.ok(ber);
|
assert.ok(ber);
|
||||||
|
|
|
@ -114,3 +114,129 @@ test('parse', function (t) {
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('apply - replace', function (t) {
|
||||||
|
var res;
|
||||||
|
var single = new Change({
|
||||||
|
operation: 'replace',
|
||||||
|
modification: {
|
||||||
|
type: 'cn',
|
||||||
|
vals: ['new']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var twin = new Change({
|
||||||
|
operation: 'replace',
|
||||||
|
modification: {
|
||||||
|
type: 'cn',
|
||||||
|
vals: ['new', 'two']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// plain
|
||||||
|
res = Change.apply(single, { cn: ['old'] });
|
||||||
|
t.ok(res.cn);
|
||||||
|
t.equal(res.cn.length, 1);
|
||||||
|
t.equal(res.cn[0], 'new');
|
||||||
|
|
||||||
|
// multiple
|
||||||
|
res = Change.apply(single, { cn: ['old', 'also'] });
|
||||||
|
t.ok(res.cn);
|
||||||
|
t.equal(res.cn.length, 1);
|
||||||
|
t.equal(res.cn[0], 'new');
|
||||||
|
|
||||||
|
//absent
|
||||||
|
res = Change.apply(single, { dn: ['otherjunk'] });
|
||||||
|
t.ok(res.cn);
|
||||||
|
t.equal(res.cn.length, 1);
|
||||||
|
t.equal(res.cn[0], 'new');
|
||||||
|
|
||||||
|
// scalar formatting "success"
|
||||||
|
res = Change.apply(single, { cn: 'old' }, true);
|
||||||
|
t.ok(res.cn);
|
||||||
|
t.equal(res.cn, 'new');
|
||||||
|
|
||||||
|
// scalar formatting "failure"
|
||||||
|
res = Change.apply(twin, { cn: 'old' }, true);
|
||||||
|
t.ok(res.cn);
|
||||||
|
t.equal(res.cn.length, 2);
|
||||||
|
t.equal(res.cn[0], 'new');
|
||||||
|
t.equal(res.cn[1], 'two');
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('apply - add', function (t) {
|
||||||
|
var res;
|
||||||
|
var single = new Change({
|
||||||
|
operation: 'add',
|
||||||
|
modification: {
|
||||||
|
type: 'cn',
|
||||||
|
vals: ['new']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// plain
|
||||||
|
res = Change.apply(single, { cn: ['old'] });
|
||||||
|
t.deepEqual(res.cn, ['old', 'new']);
|
||||||
|
|
||||||
|
// multiple
|
||||||
|
res = Change.apply(single, { cn: ['old', 'also'] });
|
||||||
|
t.deepEqual(res.cn, ['old', 'also', 'new']);
|
||||||
|
|
||||||
|
//absent
|
||||||
|
res = Change.apply(single, { dn: ['otherjunk'] });
|
||||||
|
t.deepEqual(res.cn, ['new']);
|
||||||
|
|
||||||
|
// scalar formatting "success"
|
||||||
|
res = Change.apply(single, { }, true);
|
||||||
|
t.equal(res.cn, 'new');
|
||||||
|
|
||||||
|
// scalar formatting "failure"
|
||||||
|
res = Change.apply(single, { cn: 'old' }, true);
|
||||||
|
t.deepEqual(res.cn, ['old', 'new']);
|
||||||
|
|
||||||
|
// duplicate add
|
||||||
|
res = Change.apply(single, { cn: 'new' });
|
||||||
|
t.deepEqual(res.cn, ['new']);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('apply - delete', function (t) {
|
||||||
|
var res;
|
||||||
|
var single = new Change({
|
||||||
|
operation: 'delete',
|
||||||
|
modification: {
|
||||||
|
type: 'cn',
|
||||||
|
vals: ['old']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// plain
|
||||||
|
res = Change.apply(single, { cn: ['old', 'new'] });
|
||||||
|
t.deepEqual(res.cn, ['new']);
|
||||||
|
|
||||||
|
// empty
|
||||||
|
res = Change.apply(single, { cn: ['old'] });
|
||||||
|
t.equal(res.cn, undefined);
|
||||||
|
t.ok(Object.keys(res).indexOf('cn') === -1);
|
||||||
|
|
||||||
|
// scalar formatting "success"
|
||||||
|
res = Change.apply(single, { cn: ['old', 'one'] }, true);
|
||||||
|
t.equal(res.cn, 'one');
|
||||||
|
|
||||||
|
// scalar formatting "failure"
|
||||||
|
res = Change.apply(single, { cn: ['old', 'several', 'items'] }, true);
|
||||||
|
t.deepEqual(res.cn, ['several', 'items']);
|
||||||
|
|
||||||
|
|
||||||
|
//absent
|
||||||
|
res = Change.apply(single, { dn: ['otherjunk'] });
|
||||||
|
t.ok(res);
|
||||||
|
t.equal(res.cn, undefined);
|
||||||
|
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue