Skip to content
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
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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.

Original file line number Diff line number Diff line change
@@ -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, {});
});
});
Loading