Add Change.apply method for object modification
This commit is contained in:
parent
26e427f4a0
commit
a80cedd870
|
@ -2,6 +2,7 @@
|
|||
|
||||
## CURRENT
|
||||
|
||||
- Add Change.apply method for modifying objects
|
||||
- Update bunyan to 0.23.1
|
||||
- #143 Preserve raw Buffer value in Control objects
|
||||
- Test code coverage with node-istanbul
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||
|
||||
var assert = require('assert');
|
||||
var assert = require('assert-plus');
|
||||
|
||||
var Attribute = require('./attribute');
|
||||
var Protocol = require('./protocol');
|
||||
|
@ -111,6 +111,68 @@ Change.compare = function (a, b) {
|
|||
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) {
|
||||
assert.ok(ber);
|
||||
|
|
|
@ -114,3 +114,129 @@ test('parse', function (t) {
|
|||
|
||||
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