Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated dependencies and introduced delete option with test #41

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
## Changelog

### 0.2.8 (Nov 1. 2016)

- Added `filter` function to remove elements conditionally.
- Updated tests and Readme with `filter` function.
53 changes: 51 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,11 @@ Returns the parent of the first matching element.

#### jp.apply(obj, pathExpression, fn)

Runs the supplied function `fn` on each matching element, and replaces each matching element with the return value from the function. The function accepts the value of the matching element as its only parameter. Returns matching nodes with their updated values.
Runs the supplied application function `fn` on each matching element, and replaces each matching element with the return value from the function. The function accepts the value of the matching element and a context object with the `parent` and `key`. Returns matching nodes with their updated values.


```javascript
var nodes = jp.apply(data, '$..author', function(value) { return value.toUpperCase() });
var nodes = jp.apply(data, '$..author', function(value, ctx) { return value.toUpperCase() });
// [
// { path: ['$', 'store', 'book', 0, 'author'], value: 'NIGEL REES' },
// { path: ['$', 'store', 'book', 1, 'author'], value: 'EVELYN WAUGH' },
Expand All @@ -166,6 +166,55 @@ var nodes = jp.apply(data, '$..author', function(value) { return value.toUpperCa
// ]
```

#### jp.filter(obj, pathExpression, fn)

Filters the data by removing the matched value if the callback returns a truthy value.

Sample data:

```js
var data = {
a: [
{
id: 'book',
price: 100
},
{
id: 'car',
price: 3456
}
],
b: {
c: 2,
d: 1
}
};
```

Example: Using `filter` to remove element from an `Array` or `Object` parent node.

```js
// Remove the first element in `a`
jp.filter(data, '$..a[0]', function(v, ctx) {
return true;
});

// Remove the element at 'c' from object b
jp.filter(data, '$..b.c', function(v, ctx) {
return true;
});

console.log(data)
// {
// a: [
// { id: 'car', price: 3456 }
// ],
// b: {
// c: 2
// }
// }
```

#### jp.parse(pathExpression)

Parse the provided JSONPath expression into path components and their associated operations.
Expand Down
29 changes: 28 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,33 @@ JSONPath.prototype.parent = function(obj, string) {
return this.value(obj, node.path);
}

JSONPath.prototype.filter = function(obj, string, fn) {
assert.ok(obj instanceof Object, "obj needs to be an object");
assert.ok(string, "we need a path");
assert.equal(typeof fn, "function", "fn needs to be function")

var nodes = this.nodes(obj, string).sort(function(a, b) {
// sort nodes so we apply from the bottom up
return b.path.length - a.path.length;
});

nodes.forEach(function(node) {
var key = node.path.pop();
var parent = this.value(obj, this.stringify(node.path));
var val = node.value = fn.call(obj, parent[key], {parent: parent, key: key});

if (!val) return;

if (Array.isArray(parent)) {
parent.splice(key, 1);
return;
}
delete parent[key];
}, this);

return nodes;
}

JSONPath.prototype.apply = function(obj, string, fn) {

assert.ok(obj instanceof Object, "obj needs to be an object");
Expand All @@ -41,7 +68,7 @@ JSONPath.prototype.apply = function(obj, string, fn) {
nodes.forEach(function(node) {
var key = node.path.pop();
var parent = this.value(obj, this.stringify(node.path));
var val = node.value = fn.call(obj, parent[key]);
var val = node.value = fn.call(obj, parent[key], {parent: parent, key: key});
parent[key] = val;
}, this);

Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"name": "jsonpath",
"description": "Query JavaScript objects with JSONPath expressions. Robust / safe JSONPath engine for Node.js.",
"version": "0.2.7",
"version": "0.2.8",
"author": "david@fmail.co.uk",
"scripts": {
"postinstall": "node lib/aesprim.js > generated/aesprim-browser.js",
"test": "mocha -u tdd test && jscs lib && jshint lib",
"generate": "node bin/generate_parser.js > generated/parser.js"
},
"dependencies": {
"esprima": "1.2.2",
"jison": "0.4.13",
"static-eval": "0.2.3",
"underscore": "1.7.0"
"esprima": "^2.0.0",
"jison": "^0.4.17",
"static-eval": "^1.1.1",
"underscore": "^1.8.3"
},
"browser": {
"./lib/aesprim.js": "./generated/aesprim-browser.js"
Expand All @@ -24,7 +24,7 @@
"grunt-contrib-uglify": "0.9.1",
"jscs": "1.10.0",
"jshint": "2.6.0",
"mocha": "2.1.0"
"mocha": "^3.1.0"
},
"repository": {
"type": "git",
Expand Down
48 changes: 48 additions & 0 deletions test/sugar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,54 @@ suite('sugar', function() {
assert.equal(data.z.a, 101);
});

test('filter method deletes object from Array specified by remove function', function() {
var data = {
a: [
{
id: 'book',
price: 100
},
{
id: 'car',
price: 3456
}
],
b: 2
};

jp.filter(data, '$..a[0]', function(v) {
return true;
});

assert.equal(data.a[0].id, 'car');
});

test('filter method deletes object from Array specified by special remove object', function() {
var data = {
a: [
{
id: 'book',
price: 100
},
{
id: 'car',
price: 3456
}
],
b: {
c: 2,
d: 1
}
};

jp.filter(data, '$..b.c', function(v) {
return true;
});

assert.equal(data.b.c, undefined);
assert.equal(data.b.d, 1);
});

test('apply method applies survives structural changes', function() {
var data = {a: {b: [1, {c: [2,3]}]}};
jp.apply(data, '$..*[?(@.length > 1)]', function(array) {
Expand Down