Skip to content

Commit 0ccd2dc

Browse files
committed
feat: change option functions to overwrite the default functions instead of extending them
1 parent 7354377 commit 0ccd2dc

File tree

5 files changed

+32
-8
lines changed

5 files changed

+32
-8
lines changed

README.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,11 @@ jsonquery(data, [
9292
The build in functions can be extended with custom functions, like `times` in the following example:
9393

9494
```js
95-
import { jsonquery } from '@jsonquerylang/jsonquery'
95+
import { jsonquery, functions } from '@jsonquerylang/jsonquery'
9696

9797
const options = {
9898
functions: {
99+
...functions,
99100
times: (value) => (data) => data.map((item) => item * value)
100101
}
101102
}
@@ -368,22 +369,36 @@ Here:
368369
- `data` is the JSON document that will be queried, often an array with objects.
369370
- `query` is a JSON document containing a JSON query, either the text format or the parsed JSON format.
370371
- `options` is an optional object that can contain the following properties:
371-
- `functions` is an optional map with custom function creators. A function creator has optional arguments as input and must return a function that can be used to process the query data. For example:
372+
- `functions` is an optional map with function creators. A function creator has optional arguments as input and must return a function that can be used to process the query data. For example:
372373

373374
```js
375+
import { functions } from '@jsonquerylang/jsonquery'
376+
374377
const options = {
375378
functions: {
379+
// keep all built-in functions
380+
...functions,
381+
382+
// define a new custom function "times"
376383
// usage example: 'times(3)'
377384
times: (value) => (data) => data.map((item) => item * value)
378385
}
379386
}
380387
```
388+
389+
Note that configuring the option `functions` will overwrite the default functions. In order to extend the existing functions it is necessary to import the build-in functions and extend the custom `functions` object with them as in the example above.
381390

382391
If the parameters are not a static value but can be a query themselves, the function `compile` can be used to compile them. For example, the actual implementation of the function `filter` is the following:
383392

384393
```js
394+
import { functions } from '@jsonquerylang/jsonquery'
395+
385396
const options = {
386397
functions: {
398+
// keep all built-in functions
399+
...functions,
400+
401+
// overwrite function "filter" with our own implementation
387402
// usage example: 'filter(.age > 20)'
388403
filter: (predicate) => {
389404
const _predicate = compile(predicate)
@@ -409,16 +424,17 @@ Here:
409424
]
410425
```
411426

412-
When extending the built-in operators with a custom operator, the built-in operators can be imported via `import { operators } from 'jsonquery'` and then extended by mapping over them and adding the custom operator to the group with the right precedence level, or adding a new precedence level if needed.
427+
When extending the built-in operators with a custom operator, the built-in operators can be imported via `import { operators } from '@jsonquerylang/jsonquery'` and then extended by mapping over them and adding the custom operator to the group with the right precedence level (see example below), or adding a new precedence level if needed.
413428

414429
The defined operators can be used in a text query. Only operators with both a left and right hand side are supported, like `a == b`. They can only be executed when there is a corresponding function. For example:
415430

416431
```js
417-
import { buildFunction, operators } from 'jsonquery'
432+
import { buildFunction, functions, operators } from '@jsonquerylang/jsonquery'
418433

419434
const options = {
420435
// Define a new function "notEqual".
421436
functions: {
437+
...functions,
422438
notEqual: buildFunction((a, b) => a !== b)
423439
},
424440

@@ -521,8 +537,12 @@ The function `buildFunction` is a helper function to create a custom function. I
521537
The query engine passes the raw arguments to all functions, and the functions have to compile the arguments themselves when they are dynamic. For example:
522538

523539
```ts
540+
import { functions } from '@jsonquerylang/jsonquery'
541+
524542
const options = {
525543
functions: {
544+
...functions,
545+
526546
notEqual: (a: JSONQuery, b: JSONQuery) => {
527547
const aCompiled = compile(a)
528548
const bCompiled = compile(b)
@@ -544,10 +564,11 @@ const result = jsonquery(data, '(.x + .y) <> 6', options) // true
544564
To automatically compile and evaluate the arguments of the function, the helper function `buildFunction` can be used:
545565

546566
```ts
547-
import { jsonquery, buildFunction } from '@jsonquerylang/jsonquery'
567+
import { jsonquery, functions, buildFunction } from '@jsonquerylang/jsonquery'
548568

549569
const options = {
550570
functions: {
571+
...functions,
551572
notEqual: buildFunction((a: number, b: number) => a !== b)
552573
}
553574
}

src/compile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {
1111
const functionsStack: FunctionBuildersMap[] = []
1212

1313
export function compile(query: JSONQuery, options?: JSONQueryCompileOptions): Fun {
14-
functionsStack.unshift({ ...functions, ...functionsStack[0], ...options?.functions })
14+
functionsStack.unshift({ ...functionsStack[0], ...(options?.functions ?? functions) })
1515

1616
try {
1717
const exec = isArray(query)

src/jsonquery.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
type JSONQueryOptions,
55
buildFunction,
66
compile,
7+
functions,
78
jsonquery,
89
operators,
910
parse,
@@ -33,6 +34,7 @@ describe('jsonquery', () => {
3334
test('should execute a text query with custom functions', () => {
3435
const options: JSONQueryOptions = {
3536
functions: {
37+
...functions,
3638
customFn: () => (_data: unknown) => 42
3739
}
3840
}

src/jsonquery.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export function jsonquery(
1414
export { compile } from './compile'
1515
export { stringify } from './stringify'
1616
export { parse } from './parse'
17-
export { buildFunction } from './functions'
17+
export { buildFunction, functions } from './functions'
1818
export { operators } from './constants'
1919

2020
export * from './types'

src/parse.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type { JSONQuery, JSONQueryParseOptions } from './types'
2626
* // ]
2727
*/
2828
export function parse(query: string, options?: JSONQueryParseOptions): JSONQuery {
29+
const allFunctions = options?.functions ?? functions
2930
const allOperators = options?.operators ?? operators
3031

3132
const parsePipe = () => {
@@ -134,7 +135,7 @@ export function parse(query: string, options?: JSONQueryParseOptions): JSONQuery
134135
}
135136
i++
136137

137-
if (!options?.functions[name] && !functions[name]) {
138+
if (!allFunctions[name]) {
138139
throwError(`Unknown function '${name}'`)
139140
}
140141

0 commit comments

Comments
 (0)