Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 42 additions & 36 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,62 +1,68 @@
var toDot = require('jsonpath-to-dot');
function toDot(path) {
return path.replace(/^\//, '').replace(/\//g, '.').replace(/~1/g, '/').replace(/~0/g, '~');
}

module.exports = function(patches){
var update = {};
patches.map(function(p){
if(p.op === 'add'){
switch(p.op) {
case 'add':
var path = toDot(p.path),
parts = path.split('.');

var key = parts[0];
var $position = parts[1] && parseInt(parts[1], 10);
var positionPart = parts.length > 1 && parts[parts.length - 1];
var addToEnd = positionPart === '-';
var key = parts.slice(0, -1).join('.');
var $position = positionPart && parseInt(positionPart, 10) || null;

update.$push = update.$push || {};

if (!isNaN($position)) {
if (update.$push[key]) {
if (!isNaN(update.$push[key].$position)) {
$position = update.$push[key].$position;
delete update.$push[key].$position;
}

if (!update.$push[key].$each) {
update.$push[key] = {
$each: [
update.$push[key]
]
};
}

update.$push[key].$each.push(p.value);
update.$push[key].$position = $position;
} else {
if ($position !== null) {
if (update.$push[key] === undefined) {
update.$push[key] = {
$each: [p.value],
$position: $position
};
} else {
if (update.$push[key] === null || update.$push[key].$position === undefined) {
throw new Error("Unsupported Operation! can't use add op with mixed positions");
}
var posDiff = $position - update.$push[key].$position;
if (posDiff > update.$push[key].$each.length) {
throw new Error("Unsupported Operation! can use add op only with contiguous positions");
}
update.$push[key].$each.splice(posDiff, 0, p.value);
update.$push[key].$position = Math.min($position, update.$push[key].$position);
}
} else {
if (update.$push[key]) {
if (!update.$push[key].$each) {
} else if(addToEnd) {
if (update.$push[key] === undefined) {
update.$push[key] = p.value;
} else {
if (update.$push[key] === null || update.$push[key].$each === undefined) {
update.$push[key] = {
$each: [update.$push[key]]
};
}
update.$push[path].$each.push(p.value);
} else {
update.$push[path] = p.value;
if (update.$push[key].$position !== undefined) {
throw new Error("Unsupported Operation! can't use add op with mixed positions");
}
update.$push[key].$each.push(p.value);
}
} else {
throw new Error("Unsupported Operation! can't use add op without position");
}
}
else if(p.op === 'remove'){
if(!update.$unset) update.$unset = {};
break;
case 'remove':
update.$unset = update.$unset || {};
update.$unset[toDot(p.path)] = 1;
}
else if(p.op === 'replace'){
if(!update.$set) update.$set = {};
break;
case 'replace':
update.$set = update.$set || {};
update.$set[toDot(p.path)] = p.value;
}
else if(p.op !== 'test') {
break;
case 'test':
break;
default:
throw new Error('Unsupported Operation! op = ' + p.op);
}
});
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
"scripts": {
"test": "mocha"
},
"dependencies": {
"jsonpath-to-dot": "~0.2.0"
},
"dependencies": {},
"devDependencies": {
"chai": "^3.5.0",
"mocha": "~3.1.2"
Expand Down
154 changes: 149 additions & 5 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('jsonpatch to mongodb', function() {
it('should work with single add', function() {
var patches = [{
op: 'add',
path: '/name',
path: '/name/-',
value: 'dave'
}];

Expand All @@ -20,6 +20,22 @@ describe('jsonpatch to mongodb', function() {
assert.deepEqual(toMongodb(patches), expected);
});

it('should work with escaped characters', function() {
var patches = [{
op: 'replace',
path: '/foo~1bar~0',
value: 'dave'
}];

var expected = {
$set: {
"foo/bar~": 'dave'
}
};

assert.deepEqual(toMongodb(patches), expected);
});

it('should work with array set', function() {
var patches = [{
op: 'add',
Expand Down Expand Up @@ -50,13 +66,18 @@ describe('jsonpatch to mongodb', function() {
op: 'add',
path: '/name/2',
value: 'bob'
}, {
op: 'add',
path: '/name/2',
value: 'john'
}];

var expected = {
$push: {
name: {
$each: [
'dave',
'john',
'bob'
],
$position: 1
Expand All @@ -67,18 +88,42 @@ describe('jsonpatch to mongodb', function() {
assert.deepEqual(toMongodb(patches), expected);
});

it('should work with multiple adds in reverse position', function() {
var patches = [{
op: 'add',
path: '/name/1',
value: 'dave'
},{
op: 'add',
path: '/name/1',
value: 'bob'
},{
op: 'add',
path: '/name/1',
value: 'john'
}];

var expected = {
$push: {
name: {$each: ['john', 'bob', 'dave'], $position: 1}
}
};

assert.deepEqual(toMongodb(patches), expected);
});

it('should work with multiple adds', function() {
var patches = [{
op: 'add',
path: '/name',
path: '/name/-',
value: 'dave'
},{
op: 'add',
path: '/name',
path: '/name/-',
value: 'bob'
},{
op: 'add',
path: '/name',
path: '/name/-',
value: 'john'
}];

Expand All @@ -91,6 +136,54 @@ describe('jsonpatch to mongodb', function() {
assert.deepEqual(toMongodb(patches), expected);
});

it('should work with multiple adds with some null at the end', function() {
var patches = [{
op: 'add',
path: '/name/-',
value: null
},{
op: 'add',
path: '/name/-',
value: 'bob'
},{
op: 'add',
path: '/name/-',
value: null
}];

var expected = {
$push: {
name: {$each: [null, 'bob', null]}
}
};

assert.deepEqual(toMongodb(patches), expected);
});

it('should work with multiple adds with some null and position', function() {
var patches = [{
op: 'add',
path: '/name/1',
value: null
},{
op: 'add',
path: '/name/1',
value: 'bob'
},{
op: 'add',
path: '/name/1',
value: null
}];

var expected = {
$push: {
name: {$each: [null, 'bob', null], $position: 1}
}
};

assert.deepEqual(toMongodb(patches), expected);
});

it('should work with remove', function() {
var patches = [{
op: 'remove',
Expand Down Expand Up @@ -135,6 +228,58 @@ describe('jsonpatch to mongodb', function() {
assert.deepEqual(toMongodb(patches), expected);
});

it('blow up on adds with non contiguous positions', function() {
var patches = [{
op: 'add',
path: '/name/1',
value: 'bob'
},{
op: 'add',
path: '/name/3',
value: 'john'
}];

chai.expect(function(){toMongodb(patches)}).to.throw("Unsupported Operation! can use add op only with contiguous positions");
});

it('blow up on adds with mixed position 1', function() {
var patches = [{
op: 'add',
path: '/name/1',
value: 'bob'
},{
op: 'add',
path: '/name/-',
value: 'john'
}];

chai.expect(function(){toMongodb(patches)}).to.throw("Unsupported Operation! can't use add op with mixed positions");
});

it('blow up on adds with mixed position 2', function() {
var patches = [{
op: 'add',
path: '/name/-',
value: 'bob'
},{
op: 'add',
path: '/name/1',
value: 'john'
}];

chai.expect(function(){toMongodb(patches)}).to.throw("Unsupported Operation! can't use add op with mixed positions");
});

it('should blow up on add without position', function() {
var patches = [{
op: 'add',
path: '/name',
value: 'dave'
}];

chai.expect(function(){toMongodb(patches)}).to.throw("Unsupported Operation! can't use add op without position");
});

it('should blow up on move', function() {
var patches = [{
op: 'move',
Expand All @@ -143,7 +288,6 @@ describe('jsonpatch to mongodb', function() {
}];

chai.expect(function(){toMongodb(patches)}).to.throw('Unsupported Operation! op = move');

});


Expand Down