forked from extern/bruno
feat(query): simple object predicate for scalar properties
This commit is contained in:
parent
b87cc7ccae
commit
ee4509f037
@ -18,6 +18,10 @@ Array filtering [?] with corresponding filter function
|
||||
```js
|
||||
get(data, '..items[?].amount', i => i.amount > 20)
|
||||
```
|
||||
Array filtering [?] with simple object predicate, same as (i => i.id === 2 && i.amount === 20)
|
||||
```js
|
||||
get(data, '..items[?]', { id: 2, amount: 20 })
|
||||
```
|
||||
Array mapping [?] with corresponding mapper function
|
||||
```js
|
||||
get(data, '..items[?].amount', i => i.amount + 10)
|
||||
@ -26,4 +30,4 @@ get(data, '..items[?].amount', i => i.amount + 10)
|
||||
### Publish to Npm Registry
|
||||
```bash
|
||||
npm publish --access=public
|
||||
```
|
||||
```
|
||||
|
@ -19,11 +19,11 @@ function normalize(value: any) {
|
||||
/**
|
||||
* Gets value of a prop from source.
|
||||
*
|
||||
* If source is an array get value for each item.
|
||||
* If source is an array get value from each item.
|
||||
*
|
||||
* If deep is true then recursively gets values for prop in nested objects.
|
||||
*
|
||||
* Once a value if found will not recurese further into that value.
|
||||
* Once a value is found will not recurse further into that value.
|
||||
*/
|
||||
function getValue(source: any, prop: string, deep = false): any {
|
||||
if (typeof source !== 'object') return;
|
||||
@ -47,14 +47,27 @@ function getValue(source: any, prop: string, deep = false): any {
|
||||
return normalize(value);
|
||||
}
|
||||
|
||||
type PredicateOrMapper = (obj: any) => any;
|
||||
type PredicateOrMapper = ((obj: any) => any) | Record<string, any>;
|
||||
|
||||
/**
|
||||
* Make a predicate function that checks scalar properties for equality
|
||||
*/
|
||||
function objectPredicate(obj: Record<string, any>) {
|
||||
return (item: any) => {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (item[key] !== value) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filter on source array or object
|
||||
*
|
||||
* If the filter returns a non boolean non null value it is treated as a mapped value
|
||||
*/
|
||||
function filterOrMap(source: any, fun: PredicateOrMapper) {
|
||||
function filterOrMap(source: any, funOrObj: PredicateOrMapper) {
|
||||
const fun = typeof funOrObj === 'object' ? objectPredicate(funOrObj) : funOrObj;
|
||||
const isArray = Array.isArray(source);
|
||||
const list = isArray ? source : [source];
|
||||
const result = [] as any[];
|
||||
@ -67,7 +80,7 @@ function filterOrMap(source: any, fun: PredicateOrMapper) {
|
||||
result.push(value); // mapper
|
||||
}
|
||||
}
|
||||
return isArray ? result : result[0];
|
||||
return normalize(isArray ? result : result[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,7 +102,11 @@ function filterOrMap(source: any, fun: PredicateOrMapper) {
|
||||
* ```js
|
||||
* get(data, '..items[?].amount', i => i.amount > 20)
|
||||
* ```
|
||||
* 5. Array mapping [?] with corresponding mapper function
|
||||
* 5. Array filtering [?] with simple object predicate, same as (i => i.id === 2 && i.amount === 20)
|
||||
* ```js
|
||||
* get(data, '..items[?]', { id: 2, amount: 20 })
|
||||
* ```
|
||||
* 6. Array mapping [?] with corresponding mapper function
|
||||
* ```js
|
||||
* get(data, '..items[?].amount', i => i.amount + 10)
|
||||
* ```
|
||||
@ -121,7 +138,7 @@ export function get(source: any, path: string, ...fns: PredicateOrMapper[]) {
|
||||
source = filterOrMap(source, fun);
|
||||
break;
|
||||
case typeof token === 'number':
|
||||
source = source[token];
|
||||
source = normalize(source[token]);
|
||||
break;
|
||||
default:
|
||||
source = getValue(source, token as string, lookbehind === "..");
|
||||
@ -131,4 +148,4 @@ export function get(source: any, path: string, ...fns: PredicateOrMapper[]) {
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ const data = {
|
||||
{ id: 4, amount: 40 }
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@ -48,11 +48,13 @@ describe("get", () => {
|
||||
// filter and map
|
||||
it.each([
|
||||
["..items[?].amount", [40], (i: any) => i.amount > 30], // [?] filter
|
||||
["..items[?].amount", [40], { id: 4, amount: 40 }], // object filter
|
||||
["..items[?].amount", undefined, { id: 5, amount: 40 }],
|
||||
["..items..amount[?][0]", 40, (amt: number) => amt > 30],
|
||||
["..items..amount[0][?]", undefined, (amt: number) => amt > 30], // filter on single value
|
||||
["..items..amount[?]", [11, 21, 31, 41], (amt: number) => amt + 1], // [?] mapper
|
||||
["..items..amount[0][?]", 11, (amt: number) => amt + 1], // [?] map on single value
|
||||
])("%s should be %j %s", (expr, result, filter) => {
|
||||
])("%s should be %j for %s", (expr, result, filter) => {
|
||||
expect(get(data, expr, filter)).toEqual(result);
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user