Skip to content
This repository has been archived by the owner on Jul 30, 2018. It is now read-only.

Simple object filters #83

Merged
merged 3 commits into from
Jan 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 50 additions & 3 deletions src/query/createFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,20 @@ export const enum BooleanOp {
Or
}

export type FilterChainMember<T> = (SimpleFilter<T> | BooleanOp);
function isBooleanOp(op: any): op is BooleanOp {
return op === BooleanOp.And || op === BooleanOp.Or;
}
export type FilterChainMember<T> = SimpleFilter<T> | BooleanOp;

export interface FilterDescriptor {
readonly filterType: FilterType;
readonly path: ObjectPointer;
readonly value: any;
}

export type FilterArrayEntry = FilterDescriptor | BooleanOp | FilterArray;

interface FilterArray extends Array<FilterArrayEntry> {}

export interface SimpleFilter<T> extends Query<T> {
readonly filterType: FilterType;
Expand All @@ -35,6 +48,7 @@ export interface SimpleFilter<T> extends Query<T> {
readonly path?: ObjectPointer;
readonly value?: any;
}

export interface BooleanFilter<T> extends SimpleFilter<T> {
lessThan(path: ObjectPointer, value: number): Filter<T>;
lessThanOrEqualTo(path: ObjectPointer, value: number): Filter<T>;
Expand Down Expand Up @@ -63,9 +77,42 @@ function isFilter<T>(filterOrFunction: FilterChainMember<T>): filterOrFunction i
return typeof filterOrFunction !== 'function' && (<any> filterOrFunction).apply;
}

function createFilter<T>(serializer?: (filter: Filter<T>) => string): Filter<T> {
// var subFilters: NestedFilter<T> = subFilters || [];
function createFilterOrReturnOp<T>(descriptorOrOp: FilterDescriptor | BooleanOp) {
if (isBooleanOp(descriptorOrOp)) {
return descriptorOrOp;
}
else {
return createComparator<T>(
descriptorOrOp.filterType,
descriptorOrOp.value,
descriptorOrOp.path
);
}
}

function createFilter<T>(filterDescriptors?: FilterDescriptor | FilterArray, serializer?: (filter: Filter<T>) => string): Filter<T> {
let filters: FilterChainMember<T>[] = [];
if (filterDescriptors) {
if (Array.isArray(filterDescriptors)) {
filters = filterDescriptors.map((descriptorChainMember) => {
if (Array.isArray(descriptorChainMember)) {
return createFilter<T>(descriptorChainMember);
}
else {
return createFilterOrReturnOp<T>(descriptorChainMember);
}
});
}
else {
filters.push(
createComparator<T>(
filterDescriptors.filterType,
filterDescriptors.value,
filterDescriptors.path
)
);
}
}

return createFilterHelper(filters, serializer || serializeFilter);
}
Expand Down
98 changes: 97 additions & 1 deletion tests/unit/query/createFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,102 @@ registerSuite({
}
},

'from objects': {
'nested'() {
const individualFilter = {
filterType: FilterType.EqualTo,
value: 5,
path: createJsonPointer('key', 'key2')
};
const pickFirstItem = [
{
filterType: FilterType.LessThanOrEqualTo,
value: 5,
path: createJsonPointer('key', 'key2')
},
BooleanOp.And,
{
filterType: FilterType.EqualTo,
value: 'item-1',
path: 'id'
},
BooleanOp.Or,
{
filterType: FilterType.GreaterThanOrEqualTo,
value: 5,
path: createJsonPointer('key', 'key2')
},
{
filterType: FilterType.EqualTo,
value: 'item-1',
path: 'id'
},
BooleanOp.Or,
{
filterType: FilterType.GreaterThan,
value: 5,
path: createJsonPointer('key', 'key2')
},
{
filterType: FilterType.EqualTo,
value: 'item-1',
path: 'id'
}
];

const pickAllItems = [
{
filterType: FilterType.LessThan,
value: 100,
path: createJsonPointer('key', 'key2')
}
];

const pickNoItems = [
{
filterType: FilterType.GreaterThan,
value: 100,
path: createJsonPointer('key', 'key2')
}
];

const pickLastItem = [
{
filterType: FilterType.EqualTo,
value: '3',
path: 'id'
}
];

assert.deepEqual(createFilter(pickFirstItem).apply(nestedList), [ nestedList[0] ], 'Should pick first item');
assert.deepEqual(createFilter(pickAllItems).apply(nestedList), nestedList, 'Should pick all items');
assert.deepEqual(createFilter(pickNoItems).apply(nestedList), [], 'Should pick no items');
assert.deepEqual(createFilter(pickLastItem).apply(nestedList), [ nestedList[2] ], 'Should pick last item');
assert.deepEqual(
createFilter([ pickFirstItem, BooleanOp.And, pickLastItem ]).apply(nestedList),
[],
'Shouldn\'t pick any items'
);
assert.deepEqual(
createFilter([ pickFirstItem, BooleanOp.Or, pickLastItem ]).apply(nestedList),
[ nestedList[0], nestedList[2] ],
'Should have picked first and last item'
);

assert.deepEqual(
createFilter(
[ pickFirstItem, BooleanOp.Or, [ pickAllItems, BooleanOp.And, pickNoItems ], BooleanOp.Or, pickLastItem ]
).apply(nestedList),
[ nestedList[0], nestedList[2] ],
'Should have picked first and last item'
);

assert.deepEqual(
createFilter(individualFilter).apply(nestedList), [ nestedList[0] ], 'Should have picked first item'
);
}
},

'serializing': {
'simple - no path': {
'empty filter': function() {
Expand Down Expand Up @@ -447,7 +543,7 @@ registerSuite({
return 'Return any item where' + recursivelySerialize(filter);
}

assert.strictEqual(createFilter(serializeFilter)
assert.strictEqual(createFilter(undefined, serializeFilter)
.greaterThan('key', 3)
.lessThan('key', 5)
.or()
Expand Down