From d13c4ca0f0b96cb6e6341cb3c9ca692d7617173e Mon Sep 17 00:00:00 2001 From: Agnes Lin Date: Wed, 7 Aug 2019 09:48:21 -0400 Subject: [PATCH] fix: fixup findByForeignKeys Co-authored-by: Nora --- .../repositories/relation.helpers.unit.ts | 37 +++++++++++++++++-- .../src/relations/relation.helpers.ts | 26 ++++++++----- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts b/packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts index 216b3f7ff397..87f6dc79127a 100644 --- a/packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts +++ b/packages/repository/src/__tests__/unit/repositories/relation.helpers.unit.ts @@ -19,27 +19,46 @@ describe('findByForeignKeys', () => { await productRepo.deleteAll(); }); + it('returns an empty array when no foreign keys are passed in', async () => { + const fkIds: number[] = []; + await productRepo.create({id: 1, name: 'product', categoryId: 1}); + const products = await findByForeignKeys(productRepo, 'categoryId', fkIds); + expect(products).to.be.empty(); + }); + it('returns an empty array when no instances have the foreign key value', async () => { await productRepo.create({id: 1, name: 'product', categoryId: 1}); - const products = await findByForeignKeys(productRepo, 'categoryId', [2]); + const products = await findByForeignKeys(productRepo, 'categoryId', 2); expect(products).to.be.empty(); }); + it('returns an empty array when no instances have the foreign key values', async () => { + await productRepo.create({id: 1, name: 'product', categoryId: 1}); + const products = await findByForeignKeys(productRepo, 'categoryId', [2, 3]); + expect(products).to.be.empty(); + }); it('returns all instances that have the foreign key value', async () => { const pens = await productRepo.create({name: 'pens', categoryId: 1}); const pencils = await productRepo.create({name: 'pencils', categoryId: 1}); - const products = await findByForeignKeys(productRepo, 'categoryId', [1]); + const products = await findByForeignKeys(productRepo, 'categoryId', 1); expect(products).to.deepEqual([pens, pencils]); }); it('does not include instances with different foreign key values', async () => { const pens = await productRepo.create({name: 'pens', categoryId: 1}); const pencils = await productRepo.create({name: 'pencils', categoryId: 2}); - const products = await findByForeignKeys(productRepo, 'categoryId', [1]); + const products = await findByForeignKeys(productRepo, 'categoryId', 1); expect(products).to.deepEqual([pens]); expect(products).to.not.containDeep(pencils); }); + it('includes instances when there is one value in the array of foreign key values', async () => { + const pens = await productRepo.create({name: 'pens', categoryId: 1}); + const pencils = await productRepo.create({name: 'pencils', categoryId: 2}); + const products = await findByForeignKeys(productRepo, 'categoryId', [2]); + expect(products).to.deepEqual([pencils]); + expect(products).to.not.containDeep(pens); + }); it('returns all instances that have any of multiple foreign key values', async () => { const pens = await productRepo.create({name: 'pens', categoryId: 1}); const pencils = await productRepo.create({name: 'pencils', categoryId: 2}); @@ -61,6 +80,18 @@ describe('findByForeignKeys', () => { expect(errorMessage).to.eql('scope is not supported'); }); + it('does not throw an error if scope is passed in and is undefined or empty', async () => { + let products = await findByForeignKeys( + productRepo, + 'categoryId', + [1], + undefined, + {}, + ); + expect(products).to.be.empty(); + products = await findByForeignKeys(productRepo, 'categoryId', 1, {}, {}); + expect(products).to.be.empty(); + }); /******************* HELPERS *******************/ @model() diff --git a/packages/repository/src/relations/relation.helpers.ts b/packages/repository/src/relations/relation.helpers.ts index 921c27570d19..17d8860e50fa 100644 --- a/packages/repository/src/relations/relation.helpers.ts +++ b/packages/repository/src/relations/relation.helpers.ts @@ -11,19 +11,18 @@ import {Entity, EntityCrudRepository, Filter, Options, Where} from '..'; * * @param targetRepository - The target repository where the model instances are found * @param fkName - Name of the foreign key - * @param fkValues - Array of the values of the foreign keys to be included + * @param fkValues - One value or array of values of the foreign key to be included * @param scope - Additional scope constraints (not currently supported) * @param options - Options for the operations */ export async function findByForeignKeys< Target extends Entity, - TargetID, TargetRelations extends object, - ForeignKey + ForeignKey extends StringKeyOf >( - targetRepository: EntityCrudRepository, - fkName: StringKeyOf, - fkValues: ForeignKey[], + targetRepository: EntityCrudRepository, + fkName: ForeignKey, + fkValues: Target[ForeignKey][] | Target[ForeignKey], scope?: Filter, options?: Options, ): Promise<(Target & TargetRelations)[]> { @@ -33,12 +32,19 @@ export async function findByForeignKeys< throw new Error('scope is not supported'); } - const where = ({ - [fkName]: fkValues.length === 1 ? fkValues[0] : {inq: fkValues}, - } as unknown) as Where; + let value; + + if (Array.isArray(fkValues)) { + if (fkValues.length === 0) return []; + value = fkValues.length === 1 ? fkValues[0] : {inq: fkValues}; + } else { + value = fkValues; + } + + const where = ({[fkName]: value} as unknown) as Where; const targetFilter = {where}; return targetRepository.find(targetFilter, options); } -export type StringKeyOf = Extract; +type StringKeyOf = Extract;