Skip to content

Commit d670d10

Browse files
committed
feat(repository): implement EntityNotFoundError
1 parent 5a493cf commit d670d10

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright IBM Corp. 2018. All Rights Reserved.
2+
// Node module: @loopback/repository
3+
// This file is licensed under the MIT License.
4+
// License text available at https://opensource.org/licenses/MIT
5+
6+
import {Entity} from '../model';
7+
8+
export class EntityNotFoundError<ID, Props extends object = {}> extends Error {
9+
code: string;
10+
entityName: string;
11+
entityId: ID;
12+
13+
constructor(
14+
entityOrName: typeof Entity | string,
15+
entityId: ID,
16+
extraProperties?: Props,
17+
) {
18+
const entityName =
19+
typeof entityOrName === 'string'
20+
? entityOrName
21+
: entityOrName.modelName || entityOrName.name;
22+
23+
const quotedId = JSON.stringify(entityId);
24+
25+
super(`Entity not found: ${entityName} with id ${quotedId}`);
26+
27+
Error.captureStackTrace(this, this.constructor);
28+
29+
this.code = 'ENTITY_NOT_FOUND';
30+
this.entityName = entityName;
31+
this.entityId = entityId;
32+
33+
Object.assign(this, extraProperties);
34+
}
35+
}
36+
37+
// tslint:disable-next-line:no-any
38+
export function isEntityNotFoundError(e: any): e is EntityNotFoundError<any> {
39+
return e instanceof EntityNotFoundError;
40+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright IBM Corp. 2018. All Rights Reserved.
2+
// Node module: @loopback/repository
3+
// This file is licensed under the MIT License.
4+
// License text available at https://opensource.org/licenses/MIT
5+
6+
export * from './entity-not-found.error';

packages/repository/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
export * from './connectors';
77
export * from './decorators';
8+
export * from './errors';
89
export * from './mixins';
910
export * from './repositories';
1011
export * from './types';
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright IBM Corp. 2017,2018. All Rights Reserved.
2+
// Node module: @loopback/repository
3+
// This file is licensed under the MIT License.
4+
// License text available at https://opensource.org/licenses/MIT
5+
6+
import {expect} from '@loopback/testlab';
7+
import {
8+
Entity,
9+
EntityNotFoundError,
10+
model,
11+
isEntityNotFoundError,
12+
} from '../../../';
13+
14+
describe('EntityNotFoundError', () => {
15+
it('inherits from Error correctly', () => {
16+
const err = givenAnErrorInstance();
17+
expect(err).to.be.instanceof(EntityNotFoundError);
18+
expect(err).to.be.instanceof(Error);
19+
expect(err.stack)
20+
.to.be.String()
21+
.and.match((s: string) => s.indexOf(__filename) > -1);
22+
});
23+
24+
it('sets code to "ENTITY_NOT_FOUND"', () => {
25+
const err = givenAnErrorInstance();
26+
expect(err.code).to.equal('ENTITY_NOT_FOUND');
27+
});
28+
29+
it('sets entity name and id properties', () => {
30+
const err = new EntityNotFoundError('Product', 'an-id');
31+
expect(err).to.have.properties({
32+
entityName: 'Product',
33+
entityId: 'an-id',
34+
});
35+
});
36+
37+
it('has a descriptive error message', () => {
38+
const err = new EntityNotFoundError('Product', 'an-id');
39+
expect(err.message).to.match(/not found.*Product.*"an-id"/);
40+
});
41+
42+
it('infers entity name from entity class via name', () => {
43+
class Product extends Entity {}
44+
45+
const err = new EntityNotFoundError(Product, 1);
46+
expect(err.entityName).to.equal('Product');
47+
});
48+
49+
it('infers entity name from entity class via modelName', () => {
50+
@model({name: 'CustomProduct'})
51+
class Product extends Entity {}
52+
53+
const err = new EntityNotFoundError(Product, 1);
54+
expect(err.entityName).to.equal('CustomProduct');
55+
});
56+
57+
function givenAnErrorInstance() {
58+
return new EntityNotFoundError('Product', 1);
59+
}
60+
});
61+
62+
describe('isEntityNotFoundError', () => {
63+
it('returns true for an instance of EntityNotFoundError', () => {
64+
const error = new EntityNotFoundError('Product', 123);
65+
expect(isEntityNotFoundError(error)).to.be.true();
66+
});
67+
68+
it('returns false for an instance of Error', () => {
69+
const error = new Error('A generic error');
70+
expect(isEntityNotFoundError(error)).to.be.false();
71+
});
72+
});

0 commit comments

Comments
 (0)