gson-query
Advanced tools
Comparing version 2.1.0 to 3.0.0
@@ -1,2 +0,2 @@ | ||
var rIsRegExp = /^\{.*\}$/; | ||
const rIsRegExp = /^\{.*\}$/; | ||
@@ -36,5 +36,3 @@ | ||
function parsePointer(pointer) { | ||
var partials; | ||
var current; | ||
var result; | ||
let current; | ||
pointer = stripPointerPrefix(pointer); | ||
@@ -46,4 +44,4 @@ | ||
result = []; | ||
partials = splitRegExp(pointer); | ||
const result = []; | ||
const partials = splitRegExp(pointer); | ||
@@ -50,0 +48,0 @@ while ((current = partials.shift()) != null) { |
@@ -1,11 +0,11 @@ | ||
var pointerDelete = require("gson-pointer").delete; | ||
var removeUndefinedItems = require("gson-pointer/lib/removeUndefinedItems"); | ||
var queryGet = require("./get"); | ||
const pointerDelete = require("gson-pointer").delete; | ||
const removeUndefinedItems = require("gson-pointer/lib/removeUndefinedItems"); | ||
const queryGet = require("./get"); | ||
var POINTER = 3; | ||
var PARENT = 2; | ||
const POINTER = 3; | ||
const PARENT = 2; | ||
function queryDelete(obj, jsonPointer) { | ||
var matches = queryGet(obj, jsonPointer, queryGet.ALL); | ||
const matches = queryGet(obj, jsonPointer, queryGet.ALL); | ||
matches.forEach(function (match) { | ||
@@ -12,0 +12,0 @@ pointerDelete(obj, match[POINTER], true); |
@@ -1,6 +0,6 @@ | ||
var o = require("gson-conform"); | ||
var common = require("./common"); | ||
const o = require("gson-conform"); | ||
const common = require("./common"); | ||
var f = { | ||
const f = { | ||
queryKey: function (obj, query) { | ||
@@ -18,3 +18,3 @@ return function (key) { | ||
var MAP = { | ||
const MAP = { | ||
"false": false, | ||
@@ -39,4 +39,4 @@ "true": true, | ||
var selectCurly = /(\{[^}]*\})/g; | ||
var selectPlaceholder = /§§§\d+§§§/g; | ||
const selectCurly = /(\{[^}]*\})/g; | ||
const selectPlaceholder = /§§§\d+§§§/g; | ||
function splitQuery(value) { | ||
@@ -49,10 +49,10 @@ // nothing to escape | ||
// @todo this must be simpler to solve | ||
var map = {}; | ||
var temp = value.replace(selectCurly, function replace(match, group, index) { | ||
var id = "§§§" + index + "§§§"; | ||
const map = {}; | ||
const temp = value.replace(selectCurly, function replace(match, group, index) { | ||
const id = "§§§" + index + "§§§"; | ||
map[id] = match; | ||
return id; | ||
}); | ||
var result = temp.split("?", 2); | ||
for (var i = 0; i < result.length; i += 1) { | ||
const result = temp.split("?", 2); | ||
for (let i = 0; i < result.length; i += 1) { | ||
result[i] = result[i].replace(selectPlaceholder, function revertReplacement(match) { | ||
@@ -74,8 +74,8 @@ return map[match]; | ||
if (obj && query) { | ||
var matches = splitQuery(query); | ||
var propertyQuery = matches[0]; | ||
var filterQuery = matches[1]; | ||
const matches = splitQuery(query); | ||
const propertyQuery = matches[0]; | ||
const filterQuery = matches[1]; | ||
var keys; | ||
var regex; | ||
let keys; | ||
let regex; | ||
if (propertyQuery === "*" || propertyQuery === "**") { | ||
@@ -112,8 +112,8 @@ keys = o.keys(obj); | ||
var key; | ||
var value; | ||
var isValid = true; | ||
var truthy; | ||
let key; | ||
let value; | ||
let isValid = true; | ||
let truthy; | ||
var tests = query | ||
const tests = query | ||
.replace(/(&&)/g, "§$1§") | ||
@@ -123,4 +123,4 @@ .replace(/(\|\|)/g, "§$1§") | ||
var or = false; | ||
for (var i = 0, l = tests.length; i < l; i += 2) { | ||
let or = false; | ||
for (let i = 0, l = tests.length; i < l; i += 2) { | ||
if (tests[i].indexOf(":!") > -1) { | ||
@@ -127,0 +127,0 @@ truthy = false; |
/* eslint no-unused-vars: 0 */ | ||
var query = require("./run"); | ||
const query = require("./run"); | ||
@@ -21,4 +21,4 @@ | ||
function queryGet(obj, jsonPointer, type) { | ||
var matches = type === queryGet.MAP ? {} : []; | ||
var cb = getCbFactory(type, matches); | ||
const matches = type === queryGet.MAP ? {} : []; | ||
const cb = getCbFactory(type, matches); | ||
query(obj, jsonPointer, cb); | ||
@@ -32,2 +32,3 @@ return matches; | ||
queryGet.VALUE = "value"; | ||
queryGet.getCbFactory = getCbFactory; | ||
@@ -34,0 +35,0 @@ |
@@ -5,1 +5,2 @@ exports.get = require("./get"); | ||
exports.filter = require("./filter"); | ||
exports.pattern = require("./pattern"); |
@@ -1,5 +0,5 @@ | ||
var filter = require("./filter"); | ||
var parsePointer = require("./common").parsePointer; | ||
const filter = require("./filter"); | ||
const { parsePointer } = require("./common"); | ||
// @note gson-pointer: only strings are valid pointer properties to join. Ensure key is a string (could be index) | ||
var join = require("gson-pointer").join; | ||
const { join } = require("gson-pointer"); | ||
@@ -15,4 +15,9 @@ | ||
function queryRun(obj, jsonPointer, cb) { | ||
if (/^#?\/?$/.test(jsonPointer)) { | ||
cb(obj, null, null, "#"); | ||
return; | ||
} | ||
// get steps into obj | ||
var steps = parsePointer(jsonPointer); | ||
const steps = parsePointer(jsonPointer); | ||
// cleanup first and last | ||
@@ -39,4 +44,4 @@ if (steps[0] === "") { | ||
function _query(obj, steps, cb, pointer) { | ||
var matches; | ||
var query = steps.shift(); | ||
let matches; | ||
const query = steps.shift(); | ||
@@ -43,0 +48,0 @@ if (steps.length === 0) { |
{ | ||
"name": "gson-query", | ||
"version": "2.1.0", | ||
"version": "3.0.0", | ||
"description": "json-pointer utilities for querying and transforming data", | ||
@@ -11,4 +11,4 @@ "main": "lib/index.js", | ||
"scripts": { | ||
"test": "mocha --recursive 'test/unit/*.test.js' -R spec; exit 0", | ||
"tdd": "watch 'npm run test' lib/ app/ test/; exit 0", | ||
"test": "mocha --recursive 'test/unit/**/*.test.js' -R spec; exit 0", | ||
"tdd": "watch 'npm run test' lib/ test/; exit 0", | ||
"lint": "eslint lib test", | ||
@@ -23,6 +23,6 @@ "coverage": "nyc npm run test --reporter=lcov", | ||
"devDependencies": { | ||
"chai": "^3.5.0", | ||
"eslint": "^4.19.1", | ||
"mocha": "^3.1.2", | ||
"nyc": "^11.6.0", | ||
"chai": "^4.2.0", | ||
"eslint": "^6.4.0", | ||
"mocha": "^6.2.0", | ||
"nyc": "^14.1.1", | ||
"watch": "^1.0.1" | ||
@@ -29,0 +29,0 @@ }, |
@@ -27,9 +27,12 @@ <h1 align="left"><img src="./docs/gson-query.png" width="256" alt="gson-query"></h1> | ||
- [query.delete](#query.delete) | ||
- [query.pattern](#query.pattern) | ||
- [Further examples](#further-examples) | ||
## Breaking Changes | ||
- with version `v3.0.0` (2019/09/26) | ||
- the syntax has changed to es6, which might require code transpilation | ||
- queries for root-pointer (`#`, `#/`, `/`) no callback root object with `(rootObject, null, null, "#")` | ||
- with `v2.0.0` a negated filter (lookahead), e.g. `*?valid:!true` will not return objects where `valid === undefined`. To match objects with missing properties you can still query them explicitly with `*?valid:!true||valid:undefined` | ||
## Quick introduction | ||
@@ -73,3 +76,15 @@ | ||
Use **patterns** to query patterns recursively | ||
```js | ||
query.pattern(data, "/node(/nodes/*)+/value"); | ||
``` | ||
and to select multiple properties of an object or array: | ||
```js | ||
query.pattern(data, "/server((/store), (/{front-.*}))/services/*"); | ||
``` | ||
## API | ||
@@ -293,2 +308,73 @@ | ||
### query.pattern | ||
The pattern-queries behave as the default `query.get` methods: | ||
```js | ||
import query from "gson-query"; | ||
// predefined callback | ||
const targets = query.pattern(data, "#/*(/node/*?valid)+/valid", query.get.POINTER); // return pointers | ||
const values = query.pattern(data, "#/*(/node/*?valid)+/valid", query.get.VALUES); // return values | ||
// ... | ||
// custom callback | ||
query.pattern(data, "#/*(/node/*?valid)+/valid", (value, key, parent, jsonPointer) => {}); | ||
``` | ||
Pattern-queries enable selection of recursive patterns and offer a way to build up a collection of data for further filterung. A pattern uses brackets `()` to identify repeatable structures and offers multiple selections for the same data-entry. | ||
Using a pattern-query like `#/tree((/left),(/right))*` will recursively select all *left* and *right*-nodes. e.g. | ||
```js | ||
const data = { | ||
tree: { | ||
left: { | ||
id: "1", | ||
left: { id: "2" }, | ||
right: { id: "3" } | ||
}, | ||
right: { | ||
id: "4" | ||
} | ||
} | ||
}; | ||
const result = query.pattern(data, "#/tree((/left),(/right))*/id"); | ||
// ["1", "2", "3", "4"] | ||
``` | ||
**Note** that each pattern-queries are resovled using `query.get` and thus support all mentioned features. | ||
One use-case for pattern-queries can be found in json-schema specification. Any definition in `#/defs` may reference itself or be referenced circular. A linear query cannot describe the corresponding data, but pattern-queries might be sufficient. | ||
#### details | ||
A pattern is a simple group defined by brackets: `#/a(/b)/c`, which is identical to `#/a/b/c`. But a group may also have a quantifier `+`: `#/a(/b)+/c`. Using a quantifier, the query within the pattern will be applied as long as it matches any data. Its combined result will then be passed to `/c`. | ||
e.g. applying the pattern `#/a(/b)+/c` on the following input data: | ||
```js | ||
const input = { | ||
a: { | ||
b: { | ||
c: "1", | ||
b: { | ||
c: "2", | ||
b: {} | ||
} | ||
} | ||
} | ||
}; | ||
``` | ||
will first select property `a` and then repeatedly select property `b`: `[a/b, a/b/b, a/b/b/b]`. This result is filtered by `c`, which will return `["1", "2"]` (the last `b`-object has no property `c`). | ||
Patterns can also be used for **OR**-operations. An *OR* is identified by a semicolon `,` and must be within and between patterns, like `((/a/b),(/c))`. **Not valid** patterns are *(/a/b, /c)* and *r/(/a/b),(/c)/f*. | ||
Currently, using **OR** is *commutative* in a sense that `((/a),(/b)) = ((/b),(/a))`, (with a different ordering of the resulting set), *distributive* so that `/a((/b), (/c)) = ((/a/b), (/a/c))`. **Parenthesis** without a quantifier are *associative*, e.g. `#/a/b/c = #/a(/b)/c = #/a(/b/c) = #/a(/b)(/c)`. Thus, a pattern `((/b)(/c))+` can also be written like `(/b/c)+`. | ||
## further examples | ||
for further examples refer to the unit tests | ||
@@ -299,1 +385,2 @@ | ||
- [query.query](https://github.com/sagold/json-query/blob/master/test/unit/query.test.js) | ||
- [query.pattern](https://github.com/sagold/json-query/blob/master/test/unit/pattern.test.js) |
Sorry, the diff of this file is not supported yet
16
467
383
52321