Skip to content

Commit 9233336

Browse files
authored
Merge pull request #72 from odobosh-lohika-tix/support-for-collections-without-nested-property-key
Add ability to use all filters on the item itself with collection operators (any / all)
2 parents 9b2237d + 7d4613e commit 9233336

File tree

2 files changed

+57
-8
lines changed

2 files changed

+57
-8
lines changed

src/index.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,11 @@ export type QueryOptions<T> = ExpandOptions<T> & {
8383
action: string;
8484
func: string | { [functionName: string]: { [parameterName: string]: any } };
8585
format: string;
86-
aliases: Alias[];
86+
aliases: Alias[];
8787
}
8888

89+
export const ITEM_ROOT = "";
90+
8991
export default function <T>({
9092
select: $select,
9193
search: $search,
@@ -183,10 +185,12 @@ function buildFilter(filters: Filter = {}, propPrefix = ''): string {
183185
const value = (filter as any)[filterKey];
184186
let propName = '';
185187
if (propPrefix) {
186-
if (INDEXOF_REGEX.test(filterKey)) {
187-
propName = filterKey.replace(INDEXOF_REGEX, `(${propPrefix}/$1)`);
188+
if (filterKey === ITEM_ROOT) {
189+
propName = propPrefix;
190+
} else if (INDEXOF_REGEX.test(filterKey)) {
191+
propName = filterKey.replace(INDEXOF_REGEX, (_,$1)=>$1.trim() === ITEM_ROOT ? `(${propPrefix})` : `(${propPrefix}/${$1.trim()})`);
188192
} else if (FUNCTION_REGEX.test(filterKey)) {
189-
propName = filterKey.replace(FUNCTION_REGEX, `(${propPrefix}/$1)`);
193+
propName = filterKey.replace(FUNCTION_REGEX, (_,$1)=>$1.trim() === ITEM_ROOT ? `(${propPrefix})` : `(${propPrefix}/${$1.trim()})`);
190194
} else {
191195
propName = `${propPrefix}/${filterKey}`;
192196
}
@@ -490,7 +494,7 @@ function buildGroupBy<T>(groupBy: GroupBy<T>) {
490494
function buildOrderBy<T>(orderBy: OrderBy<T>, prefix: string = ''): string {
491495
if (Array.isArray(orderBy)) {
492496
return (orderBy as OrderByOptions<T>[])
493-
.map(value =>
497+
.map(value =>
494498
(Array.isArray(value) && value.length === 2 && ['asc', 'desc'].indexOf(value[1]) !== -1)? value.join(' ') : value
495499
)
496500
.map(v => `${prefix}${v}`).join(',');
@@ -506,7 +510,7 @@ function buildUrl(path: string, params: PlainObject): string {
506510
// This can be refactored using URL API. But IE does not support it.
507511
const queries: string[] = [];
508512
for (const key of Object.getOwnPropertyNames(params)) {
509-
const value = params[key];
513+
const value = params[key];
510514
if (value === 0 || !!value) {
511515
queries.push(`${key}=${value}`);
512516
}
@@ -516,4 +520,4 @@ function buildUrl(path: string, params: PlainObject): string {
516520

517521
function parseNot(builtFilters: string[]): string {
518522
return `not(${builtFilters.join(' and ')})`;
519-
}
523+
}

test/index.test.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import buildQuery, { Expand, OrderBy, alias, json } from '../src/index';
1+
import buildQuery, {Expand, OrderBy, alias, json, ITEM_ROOT} from '../src/index';
22

33
it('should return an empty string by default', () => {
44
expect(buildQuery()).toEqual('');
@@ -672,6 +672,51 @@ describe('filter', () => {
672672
const actual = buildQuery({ filter });
673673
expect(actual).toEqual(expected);
674674
})
675+
676+
it('should handle collection operator with "in" operator on the item of a simple collection', () => {
677+
const filter = {
678+
tags: {
679+
any: {
680+
[ITEM_ROOT]: { in: ['tag1', 'tag2']},
681+
},
682+
},
683+
};
684+
const expected = "?$filter=tags/any(tags:tags in ('tag1','tag2'))";
685+
const actual = buildQuery({ filter });
686+
expect(actual).toEqual(expected);
687+
})
688+
689+
690+
it('should handle collection operator with "or" operator on the item of a simple collection', () => {
691+
const filter = {
692+
tags: {
693+
any: {
694+
or: [
695+
{ [ITEM_ROOT]: 'tag1'},
696+
{ [ITEM_ROOT]: 'tag2'},
697+
]
698+
}
699+
}
700+
};
701+
702+
const expected = "?$filter=tags/any(tags:((tags eq 'tag1') or (tags eq 'tag2')))";
703+
const actual = buildQuery({ filter });
704+
expect(actual).toEqual(expected);
705+
})
706+
707+
it('should handle collection operator with a function on the item of a simple collection', () => {
708+
const filter = {
709+
tags: {
710+
any: {
711+
[`tolower(${ITEM_ROOT})`]: 'tag1'
712+
}
713+
}
714+
}
715+
const expected =
716+
"?$filter=tags/any(tags:tolower(tags) eq 'tag1')";
717+
const actual = buildQuery({ filter });
718+
expect(actual).toEqual(expected);
719+
});
675720
});
676721

677722
describe('data types', () => {

0 commit comments

Comments
 (0)