diff --git a/__tests__/jsonpath-value/1.0/index.test.js b/__tests__/jsonpath/1.0/index.test.js similarity index 97% rename from __tests__/jsonpath-value/1.0/index.test.js rename to __tests__/jsonpath/1.0/index.test.js index 44b74681..3a4ae665 100644 --- a/__tests__/jsonpath-value/1.0/index.test.js +++ b/__tests__/jsonpath/1.0/index.test.js @@ -1,4 +1,4 @@ -import jsonpath from '../../../functions/jsonpath-value/1.0'; +import jsonpath from '../../../functions/jsonpath/1.0'; const TEST_DATA = ` { diff --git a/__tests__/jsonpath-value/1.1/index.test.js b/__tests__/jsonpath/1.1/index.test.js similarity index 97% rename from __tests__/jsonpath-value/1.1/index.test.js rename to __tests__/jsonpath/1.1/index.test.js index 04a38726..6209e216 100644 --- a/__tests__/jsonpath-value/1.1/index.test.js +++ b/__tests__/jsonpath/1.1/index.test.js @@ -1,4 +1,4 @@ -import jsonpath from '../../../functions/jsonpath-value/1.1'; +import jsonpath from '../../../functions/jsonpath/1.1'; const TEST_DATA = ` { diff --git a/__tests__/jsonpath/2.0/index.test.js b/__tests__/jsonpath/2.0/index.test.js new file mode 100644 index 00000000..76b6fc62 --- /dev/null +++ b/__tests__/jsonpath/2.0/index.test.js @@ -0,0 +1,183 @@ +import jsonpath from '../../../functions/jsonpath/2.0'; + +const TEST_DATA = ` +{ + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95, + "sold": true + } + } +} +`; + +describe('Jsonpath value', () => { + describe('with input type string and return type', () => { + test('object', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$..book[(@.length-1)]', + method: 'value', + }); + expect(result).toStrictEqual({ + author: 'J. R. R. Tolkien', + category: 'fiction', + isbn: '0-395-19395-8', + price: 22.99, + title: 'The Lord of the Rings', + }); + }); + + test('text', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$.store.bicycle.color', + method: 'value', + }); + expect(result).toBe('red'); + }); + + test('number', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$.store.bicycle.price', + method: 'value', + }); + expect(result).toBe(19.95); + }); + + test('boolean', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$.store.bicycle.sold', + method: 'value', + }); + expect(result).toBe(true); + }); + + test('list returns the first item', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$.store.book[*].author', + method: 'value', + }); + expect(result).toStrictEqual('Nigel Rees'); + }); + }); + + test('with input type object return type text', async () => { + const { result } = await jsonpath({ + data: JSON.parse(TEST_DATA), + path: '$.store.bicycle.color', + method: 'value', + }); + expect(result).toBe('red'); + }); + + test('with input type integer', async () => + expect(async () => + jsonpath({ + data: 12345, + path: '$.store.bicycle.color', + method: 'value', + }), + ).rejects.toThrow(new Error('obj needs to be an object'))); +}); + +describe('Jsonpath query', () => { + describe('with input type string', () => { + test('The authors of all books in the store', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$.store.book[*].author', + method: 'query', + }); + expect(result).toStrictEqual([ + 'Nigel Rees', + 'Evelyn Waugh', + 'Herman Melville', + 'J. R. R. Tolkien', + ]); + }); + + test('The first two books via subscript array slice', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$..book[:2]', + method: 'query', + }); + expect(result).toStrictEqual([ + { + category: 'reference', + author: 'Nigel Rees', + title: 'Sayings of the Century', + price: 8.95, + }, + { + category: 'fiction', + author: 'Evelyn Waugh', + title: 'Sword of Honour', + price: 12.99, + }, + ]); + }); + + test('Filter all books cheaper than 10', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$..book[?(@.price<10)]', + method: 'query', + }); + expect(result).toStrictEqual([ + { + category: 'reference', + author: 'Nigel Rees', + title: 'Sayings of the Century', + price: 8.95, + }, + { + category: 'fiction', + author: 'Herman Melville', + title: 'Moby Dick', + isbn: '0-553-21311-3', + price: 8.99, + }, + ]); + }); + + test('No results with provided path', async () => { + const { result } = await jsonpath({ + data: TEST_DATA, + path: '$..book[?(@.price==0)]', + method: 'query', + }); + expect(result).toStrictEqual([]); + }); + }); +}); diff --git a/blocks/jsonpath.json b/blocks/jsonpath.json index 01f359f5..c8273506 100644 --- a/blocks/jsonpath.json +++ b/blocks/jsonpath.json @@ -1,5 +1,5 @@ { "dependencies": [], - "functions": ["jsonpathValue 1.1"], + "functions": ["jsonpath 2.0"], "includes": ["./functions/utils"] } diff --git a/functions/jsonpath-value/1.0/function.json b/functions/jsonpath/1.0/function.json similarity index 100% rename from functions/jsonpath-value/1.0/function.json rename to functions/jsonpath/1.0/function.json diff --git a/functions/jsonpath-value/1.0/index.js b/functions/jsonpath/1.0/index.js similarity index 100% rename from functions/jsonpath-value/1.0/index.js rename to functions/jsonpath/1.0/index.js diff --git a/functions/jsonpath-value/1.1/function.json b/functions/jsonpath/1.1/function.json similarity index 100% rename from functions/jsonpath-value/1.1/function.json rename to functions/jsonpath/1.1/function.json diff --git a/functions/jsonpath-value/1.1/index.js b/functions/jsonpath/1.1/index.js similarity index 100% rename from functions/jsonpath-value/1.1/index.js rename to functions/jsonpath/1.1/index.js diff --git a/functions/jsonpath/2.0/function.json b/functions/jsonpath/2.0/function.json new file mode 100644 index 00000000..b98165d8 --- /dev/null +++ b/functions/jsonpath/2.0/function.json @@ -0,0 +1,97 @@ +{ + "description": "Allows to select fields from json/objects using JSONPath: https://www.npmjs.com/package/jsonpath.", + "label": "JSONPath", + "category": "Data", + "icon": { + "name": "RightIcon", + "color": "Purple" + }, + "options": [ + { + "info": "The data or object.", + "name": "data", + "label": "Data", + "meta": { + "type": "Value", + "validations": { + "required": true + }, + "allowedKinds": ["OBJECT", "JSON", "STRING", "ARRAY"] + } + }, + { + "info": "The method you want to use to find the correct element(s). The value method returns the value of the first element matching the expression. The query method returns an array of elements matching the expression. See https://www.npmjs.com/package/jsonpath#methods for more information.", + "label": "Method", + "meta": { + "type": "Select", + "default": "value", + "values": [ + { + "label": "Value", + "value": "value" + }, + { + "label": "Query", + "value": "query" + } + ], + "validations": { + "required": true + } + }, + "name": "method" + }, + { + "info": "The jsonpath, see: https://www.npmjs.com/package/jsonpath.", + "name": "path", + "label": "JSONPath", + "configuration": { + "placeholder": "$." + }, + "meta": { + "type": "Text", + "validations": { + "required": true + } + } + }, + { + "info": "The schema model can be utilized to type the output of this step when it is an object or an array of objects.", + "meta": { + "type": "SchemaModel" + }, + "name": "schemaModel", + "label": "Schema Model" + }, + { + "meta": { + "type": "Output", + "validations": { + "required": true + }, + "output": { + "anyOf": [ + { + "type": "Text" + }, + { + "type": "Boolean" + }, + { + "type": "Number" + }, + { "type": "Object", "schemaModel": "schemaModel" }, + { + "type": "Array", + "schemaModel": "schemaModel", + "dataType": "SCHEMA" + } + ] + } + }, + "name": "result", + "label": "Result" + } + ], + "yields": "NONE" +} diff --git a/functions/jsonpath/2.0/index.js b/functions/jsonpath/2.0/index.js new file mode 100644 index 00000000..fc2b40e1 --- /dev/null +++ b/functions/jsonpath/2.0/index.js @@ -0,0 +1,21 @@ +import jsonpath from '../../utils/jsonpath.min'; + +export default async ({ data, path, method }) => { + let parsed = data; + let result = ''; + + if (typeof data === 'string') { + parsed = JSON.parse(data); + } + + switch (method) { + case 'value': + result = jsonpath.value(parsed, path); + break; + case 'query': + result = jsonpath.query(parsed, path); + break; + } + + return { result }; +};