forked from extern/bruno
Merge pull request #108 from ajaishankar/feature/object-predicate
filter shortcut for scalar properties
This commit is contained in:
commit
e6a754b933
@ -18,6 +18,10 @@ Array filtering [?] with corresponding filter function
|
|||||||
```js
|
```js
|
||||||
get(data, '..items[?].amount', i => i.amount > 20)
|
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
|
Array mapping [?] with corresponding mapper function
|
||||||
```js
|
```js
|
||||||
get(data, '..items[?].amount', i => i.amount + 10)
|
get(data, '..items[?].amount', i => i.amount + 10)
|
||||||
@ -26,4 +30,4 @@ get(data, '..items[?].amount', i => i.amount + 10)
|
|||||||
### Publish to Npm Registry
|
### Publish to Npm Registry
|
||||||
```bash
|
```bash
|
||||||
npm publish --access=public
|
npm publish --access=public
|
||||||
```
|
```
|
||||||
|
@ -19,11 +19,11 @@ function normalize(value: any) {
|
|||||||
/**
|
/**
|
||||||
* Gets value of a prop from source.
|
* 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.
|
* 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 {
|
function getValue(source: any, prop: string, deep = false): any {
|
||||||
if (typeof source !== 'object') return;
|
if (typeof source !== 'object') return;
|
||||||
@ -47,14 +47,27 @@ function getValue(source: any, prop: string, deep = false): any {
|
|||||||
return normalize(value);
|
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
|
* Apply filter on source array or object
|
||||||
*
|
*
|
||||||
* If the filter returns a non boolean non null value it is treated as a mapped value
|
* 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 isArray = Array.isArray(source);
|
||||||
const list = isArray ? source : [source];
|
const list = isArray ? source : [source];
|
||||||
const result = [] as any[];
|
const result = [] as any[];
|
||||||
@ -67,7 +80,7 @@ function filterOrMap(source: any, fun: PredicateOrMapper) {
|
|||||||
result.push(value); // mapper
|
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
|
* ```js
|
||||||
* get(data, '..items[?].amount', i => i.amount > 20)
|
* 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
|
* ```js
|
||||||
* get(data, '..items[?].amount', i => i.amount + 10)
|
* 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);
|
source = filterOrMap(source, fun);
|
||||||
break;
|
break;
|
||||||
case typeof token === 'number':
|
case typeof token === 'number':
|
||||||
source = source[token];
|
source = normalize(source[token]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
source = getValue(source, token as string, lookbehind === "..");
|
source = getValue(source, token as string, lookbehind === "..");
|
||||||
@ -131,4 +148,4 @@ export function get(source: any, path: string, ...fns: PredicateOrMapper[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ const data = {
|
|||||||
{ id: 4, amount: 40 }
|
{ id: 4, amount: 40 }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,11 +48,13 @@ describe("get", () => {
|
|||||||
// filter and map
|
// filter and map
|
||||||
it.each([
|
it.each([
|
||||||
["..items[?].amount", [40], (i: any) => i.amount > 30], // [?] filter
|
["..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]", 40, (amt: number) => amt > 30],
|
||||||
["..items..amount[0][?]", undefined, (amt: number) => amt > 30], // filter on single value
|
["..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[?]", [11, 21, 31, 41], (amt: number) => amt + 1], // [?] mapper
|
||||||
["..items..amount[0][?]", 11, (amt: number) => amt + 1], // [?] map on single value
|
["..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);
|
expect(get(data, expr, filter)).toEqual(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user