diff --git a/src/BaseFirestoreRepository.spec.ts b/src/BaseFirestoreRepository.spec.ts index 97a40b7..405f7af 100644 --- a/src/BaseFirestoreRepository.spec.ts +++ b/src/BaseFirestoreRepository.spec.ts @@ -126,7 +126,24 @@ describe('BaseFirestoreRepository', () => { albumsSubColl.orderByAscending('releaseDate').orderByDescending('releaseDate'); }).toThrow(); }); + + it('must throw an Error if an orderBy* function is called more than once in the same expression ascending', async () => { + const pt = await bandRepository.findById('porcupine-tree'); + const albumsSubColl = pt.albums; + expect(() => { + albumsSubColl.orderByAscending('releaseDate').orderByAscending('releaseDate'); + }).toThrow(); + }); + + it('must succeed when orderBy* function is called more than once in the same expression with different fields', async () => { + const pt = await bandRepository.findById('porcupine-tree'); + const albumsSubColl = pt.albums; + expect(() => { + albumsSubColl.orderByAscending('releaseDate').orderByDescending('name'); + }).not.toThrow(); + }); }); + }); describe('orderByDescending', () => { it('must order repository objects', async () => { @@ -164,8 +181,39 @@ describe('BaseFirestoreRepository', () => { albumsSubColl.orderByAscending('releaseDate').orderByDescending('releaseDate'); }).toThrow(); }); + + it('must throw an Error if an orderBy* function is called more than once in the same expression descending', async () => { + const pt = await bandRepository.findById('porcupine-tree'); + const albumsSubColl = pt.albums; + expect(() => { + albumsSubColl.orderByDescending('releaseDate').orderByDescending('releaseDate'); + }).toThrow(); + }); + + it('must succeed when orderBy* function is called more than once in the same expression with different fields', async () => { + const pt = await bandRepository.findById('porcupine-tree'); + const albumsSubColl = pt.albums; + expect(() => { + albumsSubColl.orderByAscending('releaseDate').orderByDescending('name'); + }).not.toThrow(); + }); + + it('must succeed when orderBy* function is called more than once in the same expression with different fields ascending', async () => { + const pt = await bandRepository.findById('porcupine-tree'); + const albumsSubColl = pt.albums; + expect(() => { + albumsSubColl.orderByAscending('releaseDate').orderByAscending('name'); + }).not.toThrow(); + }); + + it('must succeed when orderBy* function is called more than once in the same expression with different fields descending', async () => { + const pt = await bandRepository.findById('porcupine-tree'); + const albumsSubColl = pt.albums; + expect(() => { + albumsSubColl.orderByDescending('releaseDate').orderByDescending('name'); + }).not.toThrow(); + }); }); - }); describe('findById', () => { it('must find by id', async () => { diff --git a/src/QueryBuilder.ts b/src/QueryBuilder.ts index 5ea60c8..73fea9a 100644 --- a/src/QueryBuilder.ts +++ b/src/QueryBuilder.ts @@ -17,6 +17,7 @@ export class QueryBuilder implements IQueryBuilder { protected limitVal: number; protected orderByObj: IOrderByParams; protected customQueryFunction?: ICustomQuery; + protected orderByFields: Set = new Set(); constructor(protected executor: IQueryExecutor) {} @@ -144,12 +145,19 @@ export class QueryBuilder implements IQueryBuilder { } orderByAscending(prop: IWherePropParam) { - if (this.orderByObj) { + const fieldProp: string = typeof prop == 'string' ? prop : ''; + const alreadyOrderedByField = this.orderByFields.has(fieldProp); + + if (this.orderByObj && alreadyOrderedByField) { throw new Error( 'An orderBy function cannot be called more than once in the same query expression' ); } + if (!alreadyOrderedByField && fieldProp) { + this.orderByFields.add(fieldProp); + } + this.orderByObj = { fieldPath: this.extractWhereParam(prop), directionStr: 'asc', @@ -159,12 +167,19 @@ export class QueryBuilder implements IQueryBuilder { } orderByDescending(prop: IWherePropParam) { - if (this.orderByObj) { + const fieldProp: string = typeof prop == 'string' ? prop : ''; + const alreadyOrderedByField = this.orderByFields.has(fieldProp); + + if (this.orderByObj && alreadyOrderedByField) { throw new Error( 'An orderBy function cannot be called more than once in the same query expression' ); } + if (!alreadyOrderedByField && fieldProp) { + this.orderByFields.add(fieldProp); + } + this.orderByObj = { fieldPath: this.extractWhereParam(prop), directionStr: 'desc',