untold-json-pointer
v1.2.0
Published
The JSON Pointer was created to get the reference of properties in a JSON object. It has its own simple query system which helps you traverse the property tree. It is also "null-safe" you don't have to check if every single step in your path exists or no
Downloads
2
Readme
Untold JSON Pointer
The JSON Pointer was created to get the reference of properties in a JSON object. It has its own simple query system which helps you traverse the property tree. It is also "null-safe" you don't have to check if every single step in your path exists or not.
Since JSON Pointer works with references, you can use it to update the selected property.
Installing
Install with npm
npm install untold-json-pointer --save
Usage
For the purpose of this example we will write queries for the Character JSON object.
Your first query
First, import the json pointer library.
For the web:
import JSONPointer from 'untold-json-pointer';
In node:
const JSONPointer = require('untold-json-pointer');
Next, you should create a new instance from the JSON Pointer:
const pointer = new JSONPointer();
Let's say you want to get the name property of the character object. You have 2 ways to do this. You can pass the string into the pointer:
const result = pointer.executeQuery(character, '.name');
Or you can create a query object first
const query = pointer.createQuery('.name');
const result = pointer.executeQuery(character, query);
The second aproach is useful when you want to execute the same query on different objects because you save time on parsing.
Using the result object
The result object has the following methods and properties.
The isQueryValid property tells you if the parser was able to process your query
result.isQueryValid;
The error property stores the error message from the parser if the isQueryValid property is false
result.error;
The getAll() method returns all properties matching our query. The result is an array and every item in the array represents one of the properties. The length of the array is empty if nothing matches your query. It becomes useful when we we are using the onEach operator which is represented by a | character.
result.getAll();
The getSingle() method returns the first property which maches our query. The result is null if nothing matches our query. If you are only using paths and indexers then you should always use this method because multiple results can only occure for filters.
result.getSingle();
Working with Path
Every member in the path are being identified with the '.' character. That's also true for the root member. You have to put the path parts between string literals if they contain space character.
const nameOfCharacter = pointer.executeQuery(character, '.name');
const nameOfWeapon = pointer.executeQuery(character, '.weapon.name');
const originalOwnerHasSpace = pointer.executeQuery(character, '.weapon."original owner');
console.log(nameOfCharacter.getSingle()); // 'Conan'
console.log(nameOfWeapon.getSingle()); // 'sword'
console.log(originalOwnerHasSpace.getSingle()); // 'Bob'
You don't have to worry about missing members in your JSON.
const wrongPath = pointer.executeQuery(character, '.wrong.path');
console.log(wrongPath.getSingle()); // null
Working with Indexers
Indexers are very similar to their JavaScript counterparts. You can use numbers or string to access members of an object.
const nameOfTheFirstItem = pointer.executeQuery(character, '.items[0].name');
const nameOfTheWeapon = v.executeQuery(character, '.weapon["name"]');
console.log(nameOfTheFirstItem.getSingle()); // 'flask'
console.log(nameOfTheWeapon.getSingle()); // 'sword'
It is also null-safe so you don't have to worry about going out of bounds.
const indexerOverLength = pointer.executeQuery(character, '.items[5].name');
console.log(indexerOverLength.getSingle()); // null
Accessing each item in an array simultaneously
It is possible to access every single item in an array at the same time. The | operator iterates through the array and returns the specified property from each element.
const itemNames = pointer.executeQuery(character, '.items|name');
console.log(itemNames.getSingle()); // "flask"
console.log(itemNames.getAll()); // ["flask", "meat", "diamond", "golden key"]
When your query has a filter, you can start using the getAll() and setAll() methods because you can never be sure that it only matches one item.
Working with Filters
Filters can be very powerful because you can write a condition which will be executed against every single member of the array and identifies the matching ones.
Usually a filter looks like this: { lefthandSide operator righHandSide } The sides can be path or value. All of the regular javascript number and string operators are available (<, <=, >, >=, ==, ===, !=, !==) and also we have a special operator for contains which is the ':' character.
const itemsWhereWeightGreateThanOne = pointer.executeQuery(character, '.items{ .weight > 1}');
console.log(itemsWhereWeightGreateThanOne); // [{"name":"diamond","weight":2,"quantity":1,"equipped":false}]
The true, false, null keywords are also avilable in the queries.
const equipped = pointer.executeQuery(character, '.items{ .equipped == true}');
const notEquipped = pointer.executeQuery(character, '.items{ .equipped == true}');
const withoutPrice = pointer.executeQuery(character, '.items{ .price == null}');
Setting values
For simple queries you can use the setSingle() method to set the value of the selected property.
const result = pointer.executeQuery(character, '.name');
result.setSingle('Joe');
console.log(character.name); // "Joe"
If you are pointing to multiple items using the | operator then the setSingle() method will only update the first matching item. In that case you should use the setAll() method.
Built With
- TypeScript - The language being used
- PEGjs - Parse generator for the query
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to update tests as appropriate.
Building the application:
npm run build
Generating types for TypeScript:
npm run build:types
Executing tests in chrome:
npm run test
Authors
- Krisztian Nagy - LinkedIn
License