Skip to content

Commit

Permalink
Merge pull request #224 from wovalle/feat/not-equal-in-operators
Browse files Browse the repository at this point in the history
Feat: not equal/in operators
  • Loading branch information
wovalle authored Jan 12, 2021
2 parents 770dd8a + 63d5677 commit 0b269d9
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 2 deletions.
30 changes: 30 additions & 0 deletions src/AbstractFirestoreRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,21 @@ export abstract class AbstractFirestoreRepository<T extends IEntity> extends Bas
return new QueryBuilder<T>(this).whereEqualTo(prop, val);
}

/**
* Returns a new QueryBuilder with a filter specifying that the
* value in @param prop must not be equal to @param val.
*
* @param {IWherePropParam<T>} prop field to be filtered on, where
* prop could be keyof T or a lambda where T is the first parameter
* @param {IFirestoreVal} val value to compare in the filter
* @returns {QueryBuilder<T>} A new QueryBuilder with the specified
* query applied.
* @memberof AbstractFirestoreRepository
*/
whereNotEqualTo(prop: IWherePropParam<T>, val: IFirestoreVal): IQueryBuilder<T> {
return new QueryBuilder<T>(this).whereNotEqualTo(prop, val);
}

/**
* Returns a new QueryBuilder with a filter specifying that the
* value in @param prop must be greater than @param val.
Expand Down Expand Up @@ -254,6 +269,21 @@ export abstract class AbstractFirestoreRepository<T extends IEntity> extends Bas
return new QueryBuilder<T>(this).whereIn(prop, val);
}

/**
* Returns a new QueryBuilder with a filter specifying that the
* field @param prop matches none of the comparison values in @param val
*
* @param {IWherePropParam<T>} prop field to be filtered on, where
* prop could be keyof T or a lambda where T is the first parameter
* @param {IFirestoreVal[]} val[] array of values to compare in the filter (max 10 items in array)
* @returns {QueryBuilder<T>} A new QueryBuilder with the specified
* query applied.
* @memberof AbstractFirestoreRepository
*/
whereNotIn(prop: IWherePropParam<T>, val: IFirestoreVal[]): IQueryBuilder<T> {
return new QueryBuilder<T>(this).whereNotIn(prop, val);
}

/**
* Returns a new QueryBuilder with a maximum number of results
* to return. Can only be used once per query.
Expand Down
19 changes: 19 additions & 0 deletions src/BaseFirestoreRepository.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,12 @@ describe('BaseFirestoreRepository', () => {
expect(list[0].name).toEqual('Porcupine Tree');
});

it('must filter with whereNotEqualTo', async () => {
const list = await bandRepository.whereNotEqualTo('name', 'Porcupine Tree').find();
expect(list.length).toEqual(1);
expect(list[0].formationYear).toEqual(1983);
});

it('must filter with whereGreaterThan', async () => {
const list = await bandRepository.whereGreaterThan('formationYear', 1983).find();
expect(list.length).toEqual(1);
Expand Down Expand Up @@ -437,6 +443,11 @@ describe('BaseFirestoreRepository', () => {
expect(list.length).toEqual(3);
});

it('must filter with whereNotIn', async () => {
const list = await bandRepository.whereNotIn('formationYear', [1965]).find();
expect(list.length).toEqual(2);
});

it('should throw with whereArrayContainsAny and more than 10 items in val array', async () => {
expect(async () => {
await bandRepository
Expand All @@ -451,6 +462,14 @@ describe('BaseFirestoreRepository', () => {
}).rejects.toThrow(Error);
});

it('should throw with whereNotIn and more than 10 items in val array', async () => {
expect(async () => {
await bandRepository
.whereNotIn('formationYear', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
.find();
}).rejects.toThrow(Error);
});

it('must filter with two or more operators', async () => {
const list = await bandRepository
.whereLessOrEqualThan('formationYear', 1983)
Expand Down
28 changes: 26 additions & 2 deletions src/QueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ export default class QueryBuilder<T extends IEntity> implements IQueryBuilder<T>
return this;
}

whereNotEqualTo(param: IWherePropParam<T>, val: IFirestoreVal) {
this.queries.push({
prop: this.extractWhereParam(param),
val,
operator: FirestoreOperators.notEqual,
});
return this;
}

whereGreaterThan(prop: IWherePropParam<T>, val: IFirestoreVal) {
this.queries.push({
prop: this.extractWhereParam(prop),
Expand Down Expand Up @@ -81,7 +90,7 @@ export default class QueryBuilder<T extends IEntity> implements IQueryBuilder<T>
if (val.length > 10) {
throw new Error(`
This query supports up to 10 values. You provided ${val.length}.
For details please visit: https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any
For details please visit: https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_and_array-contains-any
`);
}
this.queries.push({
Expand All @@ -96,7 +105,7 @@ export default class QueryBuilder<T extends IEntity> implements IQueryBuilder<T>
if (val.length > 10) {
throw new Error(`
This query supports up to 10 values. You provided ${val.length}.
For details please visit: https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any
For details please visit: https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_and_array-contains-any
`);
}
this.queries.push({
Expand All @@ -107,6 +116,21 @@ export default class QueryBuilder<T extends IEntity> implements IQueryBuilder<T>
return this;
}

whereNotIn(prop: IWherePropParam<T>, val: IFirestoreVal[]) {
if (val.length > 10) {
throw new Error(`
This query supports up to 10 values. You provided ${val.length}.
For details please visit: https://firebase.google.com/docs/firestore/query-data/queries#in_not-in_and_array-contains-any
`);
}
this.queries.push({
prop: this.extractWhereParam(prop),
val,
operator: FirestoreOperators.notIn,
});
return this;
}

limit(limitVal: number) {
if (this.limitVal) {
throw new Error(
Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ export type IFirestoreVal = string | number | Date | boolean | DocumentReference

export enum FirestoreOperators {
equal = '==',
notEqual = '!=',
lessThan = '<',
greaterThan = '>',
lessThanEqual = '<=',
greaterThanEqual = '>=',
arrayContains = 'array-contains',
arrayContainsAny = 'array-contains-any',
in = 'in',
notIn = 'not-in',
}

export interface IFireOrmQueryLine {
Expand All @@ -36,13 +38,15 @@ export type IWherePropParam<T> = keyof T | ((t: T) => unknown);

export interface IQueryable<T extends IEntity> {
whereEqualTo(prop: IWherePropParam<T>, val: IFirestoreVal): IQueryBuilder<T>;
whereNotEqualTo(prop: IWherePropParam<T>, val: IFirestoreVal): IQueryBuilder<T>;
whereGreaterThan(prop: IWherePropParam<T>, val: IFirestoreVal): IQueryBuilder<T>;
whereGreaterOrEqualThan(prop: IWherePropParam<T>, val: IFirestoreVal): IQueryBuilder<T>;
whereLessThan(prop: IWherePropParam<T>, val: IFirestoreVal): IQueryBuilder<T>;
whereLessOrEqualThan(prop: IWherePropParam<T>, val: IFirestoreVal): IQueryBuilder<T>;
whereArrayContains(prop: IWherePropParam<T>, val: IFirestoreVal): IQueryBuilder<T>;
whereArrayContainsAny(prop: IWherePropParam<T>, val: IFirestoreVal[]): IQueryBuilder<T>;
whereIn(prop: IWherePropParam<T>, val: IFirestoreVal[]): IQueryBuilder<T>;
whereNotIn(prop: IWherePropParam<T>, val: IFirestoreVal[]): IQueryBuilder<T>;
find(): Promise<T[]>;
findOne(): Promise<T | null>;
}
Expand Down

0 comments on commit 0b269d9

Please sign in to comment.