Skip to content

Commit

Permalink
Merge 3165d54 into 033050a
Browse files Browse the repository at this point in the history
  • Loading branch information
agnes512 committed Sep 17, 2019
2 parents 033050a + 3165d54 commit 2326a73
Show file tree
Hide file tree
Showing 9 changed files with 545 additions and 93 deletions.
15 changes: 15 additions & 0 deletions packages/repository/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion packages/repository/package.json
Expand Up @@ -22,7 +22,9 @@
"@loopback/eslint-config": "^4.1.0",
"@loopback/testlab": "^1.8.1",
"@types/lodash": "^4.14.138",
"@types/node": "^10.14.18"
"@types/node": "^10.14.18",
"@types/bson": "^4.0.0",
"bson": "1.0.6"
},
"dependencies": {
"@loopback/context": "^1.23.0",
Expand Down
@@ -0,0 +1,78 @@
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/repository
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {expect} from '@loopback/testlab';
import {buildLookupMap, reduceAsArray, reduceAsSingleItem} from '../../../..';
import {
Category,
Product,
createProduct,
createCategory,
} from './relations-helpers-fixtures';

describe('buildLookupMap', () => {
describe('get the result of using reduceAsArray strategy for hasMany relation', () => {
it('returns multiple instances in an array', () => {
const pen = createProduct({name: 'pen', categoryId: 1});
const pencil = createProduct({name: 'pencil', categoryId: 1});

const result = buildLookupMap<unknown, Product, Category[]>(
[pen, pencil],
'categoryId',
reduceAsArray,
);
const expected = new Map<Number, Array<Product>>();
expected.set(1, [pen, pencil]);
expect(result).to.eql(expected);
});

it('return instances in multiple arrays', () => {
const pen = createProduct({name: 'pen', categoryId: 1});
const pencil = createProduct({name: 'pencil', categoryId: 1});
const eraser = createProduct({name: 'eraser', categoryId: 2});
// 'id' is the foreign key in Category in respect to Product when we talk about belongsTo
const result = buildLookupMap<unknown, Product, Category[]>(
[pen, eraser, pencil],
'categoryId',
reduceAsArray,
);
const expected = new Map<Number, Array<Product>>();
expected.set(1, [pen, pencil]);
expected.set(2, [eraser]);
expect(result).to.eql(expected);
});
});

describe('get the result of using reduceAsSingleItem strategy for belongsTo relation', () => {
it('returns one instance when one target instance is passed in', () => {
const cat = createCategory({name: 'stationery', id: 1});

const result = buildLookupMap<unknown, Category>(
[cat],
'id',
reduceAsSingleItem,
);
const expected = new Map<Number, Category>();
expected.set(1, cat);
expect(result).to.eql(expected);
});

it('returns multiple instances when multiple target instances are passed in', () => {
const cat1 = createCategory({name: 'stationery', id: 1});
const cat2 = createCategory({name: 'book', id: 2});

// 'id' is the foreign key in Category in respect to Product when we talk about belongsTo
const result = buildLookupMap<unknown, Category>(
[cat1, cat2],
'id',
reduceAsSingleItem,
);
const expected = new Map<Number, Category>();
expected.set(1, cat1);
expected.set(2, cat2);
expect(result).to.eql(expected);
});
});
});

This file was deleted.

@@ -0,0 +1,147 @@
// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/repository
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {
expect,
createStubInstance,
sinon,
StubbedInstanceWithSinonAccessor,
} from '@loopback/testlab';
import {findByForeignKeys} from '../../../..';
import {
ProductRepository,
Product,
createProduct,
} from './relations-helpers-fixtures';

describe('findByForeignKeys', () => {
let productRepo: StubbedInstanceWithSinonAccessor<ProductRepository>;

// use beforeEach to restore sinon stub
beforeEach(() => {
productRepo = createStubInstance(ProductRepository);
});

it('returns an empty array when no foreign keys are passed in', async () => {
const RESULTS: Product[] = [];
productRepo.stubs.find.resolves(RESULTS);

const fkIds: number[] = [];
await productRepo.create({id: 1, name: 'product', categoryId: 1});
const products = await findByForeignKeys(productRepo, 'categoryId', fkIds);
expect(products).to.be.empty();

sinon.assert.notCalled(productRepo.stubs.find);
});

it('returns an empty array when no instances have the foreign key value', async () => {
const find = productRepo.stubs.find;
find.resolves([]);
await productRepo.create({id: 1, name: 'product', categoryId: 1});
const products = await findByForeignKeys(productRepo, 'categoryId', 2);
expect(products).to.be.empty();
sinon.assert.calledWithMatch(find, {});
});

it('returns an empty array when no instances have the foreign key values', async () => {
const find = productRepo.stubs.find;
find.resolves([]);
await productRepo.create({id: 1, name: 'product', categoryId: 1});
const products = await findByForeignKeys(productRepo, 'categoryId', [2, 3]);
expect(products).to.be.empty();
sinon.assert.calledWithMatch(find, {});
});

it('returns all instances that have the foreign key value', async () => {
const find = productRepo.stubs.find;
const pen = createProduct({name: 'pen', categoryId: 1});
const pencil = createProduct({name: 'pencil', categoryId: 1});
find.resolves([pen, pencil]);

const products = await findByForeignKeys(productRepo, 'categoryId', 1);
expect(products).to.deepEqual([pen, pencil]);

sinon.assert.calledWithMatch(find, {
where: {
categoryId: 1,
},
});
});

it('does not include instances with different foreign key values', async () => {
const find = productRepo.stubs.find;
const pen = await productRepo.create({name: 'pen', categoryId: 1});
const pencil = await productRepo.create({name: 'pencil', categoryId: 2});
find.resolves([pen]);
const products = await findByForeignKeys(productRepo, 'categoryId', 1);
expect(products).to.deepEqual([pen]);
expect(products).to.not.containDeep(pencil);
sinon.assert.calledWithMatch(find, {
where: {
categoryId: 1,
},
});
});

it('includes instances when there is one value in the array of foreign key values', async () => {
const find = productRepo.stubs.find;
const pen = await productRepo.create({name: 'pen', categoryId: 1});
const pencil = await productRepo.create({name: 'pencil', categoryId: 2});
find.resolves([pencil]);
const products = await findByForeignKeys(productRepo, 'categoryId', [2]);
expect(products).to.deepEqual([pencil]);
expect(products).to.not.containDeep(pen);
sinon.assert.calledWithMatch(find, {
where: {
categoryId: 2,
},
});
});

it('returns all instances that have any of multiple foreign key values', async () => {
const pen = createProduct({name: 'pen', categoryId: 1});
const pencil = createProduct({name: 'pencil', categoryId: 2});
const paper = createProduct({name: 'paper', categoryId: 3});
const find = productRepo.stubs.find;
find.resolves([pen, paper]);
const products = await findByForeignKeys(productRepo, 'categoryId', [1, 3]);
expect(products).to.deepEqual([pen, paper]);
expect(products).to.not.containDeep(pencil);
sinon.assert.calledWithMatch(find, {
where: {
categoryId: {
inq: [1, 3],
},
},
});
});

// update the test when scope is supported
it('throws error if scope is passed in and is non-empty', async () => {
productRepo.stubs.find.resolves([]);
await expect(
findByForeignKeys(productRepo, 'categoryId', [1], {limit: 1}),
).to.be.rejectedWith('scope is not supported');
sinon.assert.notCalled(productRepo.stubs.find);
});

// update the test when scope is supported
it('does not throw an error if scope is passed in and is undefined or empty', async () => {
const find = productRepo.stubs.find;
find.resolves([]);
let products = await findByForeignKeys(
productRepo,
'categoryId',
[1],
undefined,
{},
);
expect(products).to.be.empty();
sinon.assert.calledWithMatch(find, {});
products = await findByForeignKeys(productRepo, 'categoryId', 1, {}, {});
expect(products).to.be.empty();
sinon.assert.calledWithMatch(find, {});
});
});

0 comments on commit 2326a73

Please sign in to comment.