Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.

Commit 1dc4fbc

Browse files
committed
1 parent 6536d09 commit 1dc4fbc

5 files changed

Lines changed: 103 additions & 10 deletions

File tree

core/@model/model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -920,7 +920,8 @@ function save(changeSet?: { [key: string]: any } | null, options?: ReplaceOneOpt
920920
}
921921

922922
if (!this.id) {
923-
return Promise.reject(new SapiMissingIdErr('Model missing id field, cannot save', this));
923+
return Promise.reject(new SapiMissingIdErr('Model missing id field, cannot save. Did you mean ' +
924+
'to use create?', this));
924925
}
925926

926927
const dbObj = changeSet || this.toDb(this);

core/@routable/routable.spec.ts

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {NextFunction, Request, Response} from 'express';
33
import {ObjectID} from 'mongodb';
44
import {testSapi, testUrl} from '../../spec/helpers/sakuraapi';
55
import {Db, Json, Model, SakuraApiModel} from '../@model';
6+
import {DUPLICATE_RESOURCE} from '../helpers/http-status';
67
import {Routable, routableSymbols, Route, SakuraApiRoutable} from './';
78
import {IRoutableLocals} from './routable';
89
import request = require('supertest');
@@ -336,6 +337,15 @@ describe('core/@Routable', () => {
336337
@Db({model: Contact})
337338
@Json()
338339
contact = new Contact();
340+
341+
@Db('email')
342+
email: string;
343+
344+
// constructor() {
345+
// super();
346+
//
347+
// this.email = `test+${new Date().getTime().toString()}@test.olivetech.net`;
348+
// }
339349
}
340350

341351
@Model({
@@ -386,15 +396,14 @@ describe('core/@Routable', () => {
386396
});
387397

388398
beforeEach((done) => {
389-
sapi
390-
.listen({bootMessage: ''})
399+
sapi.listen({bootMessage: ''})
400+
.then(() => User.removeAll({}))
391401
.then(done)
392402
.catch(done.fail);
393403
});
394404

395405
afterEach((done) => {
396-
sapi
397-
.close()
406+
sapi.close()
398407
.then(done)
399408
.catch(done.fail);
400409
});
@@ -996,6 +1005,61 @@ describe('core/@Routable', () => {
9961005
.catch(done.fail);
9971006
});
9981007

1008+
it('sends http status 409 on MongoError: E11000', (done) => {
1009+
let indexName;
1010+
1011+
const userDb = sapi.dbConnections.getDb('userDb');
1012+
userDb
1013+
.collection('usersRoutableTests')
1014+
.createIndex({email: 1}, {unique: true})
1015+
.then((idxName) => {
1016+
indexName = idxName;
1017+
1018+
const user1 = User.fromJson({
1019+
email: 'test'
1020+
});
1021+
1022+
const user2 = User.fromJson({
1023+
email: 'test'
1024+
});
1025+
1026+
const wait = [];
1027+
1028+
wait.push(user1.create());
1029+
wait.push(user2.create());
1030+
1031+
return Promise.all(wait);
1032+
})
1033+
.then(() => {
1034+
done.fail('A MongoDB duplicate error should have been thrown, this test is invalid');
1035+
})
1036+
.catch((err) => {
1037+
expect(err.name).toBe('MongoError', 'Test setup should have returned a MongoError. ' +
1038+
`It returned ${(err || {} as any).name} instead. This test is not in a valid state`);
1039+
expect(err.code).toBe(11000, 'The wrong kind of mongo error was thrown, the test is in an invalid state');
1040+
})
1041+
.then(() => {
1042+
return request(sapi.app)
1043+
.post(testUrl(`/user`))
1044+
.type('application/json')
1045+
.send({
1046+
email: 'test',
1047+
firstName: 'george',
1048+
lastName: 'washington',
1049+
password: '123'
1050+
})
1051+
.expect(DUPLICATE_RESOURCE);
1052+
})
1053+
.then(() => {
1054+
return sapi
1055+
.dbConnections
1056+
.getDb('userDb')
1057+
.collection('usersRoutableTests')
1058+
.dropIndex(indexName);
1059+
})
1060+
.then(done)
1061+
.catch(done.fail);
1062+
});
9991063
});
10001064

10011065
describe('PUT ./model', () => {

core/@routable/routable.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {Handler, NextFunction, Request, Response} from 'express';
2-
32
import * as path from 'path';
43
import 'reflect-metadata';
54
import {IDbGetParams, modelSymbols, SakuraApiModel} from '../@model';
65
import {addDefaultStaticMethods} from '../helpers';
6+
import {DUPLICATE_RESOURCE} from '../helpers/http-status';
77
import {SanitizeMongoDB as Sanitize} from '../security/mongo-db';
88

99
const debug = {
@@ -676,8 +676,33 @@ function postRouteHandler(req: Request, res: Response, next: NextFunction) {
676676
next();
677677
})
678678
.catch((err) => {
679+
if (err.name === 'MongoError') {
680+
switch (err.code) {
681+
case 11000:
682+
err.status = DUPLICATE_RESOURCE;
683+
resLocals.send(DUPLICATE_RESOURCE, {
684+
error: 'duplicate_resource'
685+
});
686+
break;
687+
default:
688+
err.status = 500;
689+
resLocals.send(500, {
690+
error: 'internal_server_error'
691+
});
692+
}
693+
} else {
694+
err.status = 500;
695+
resLocals.send(500, {
696+
error: 'internal_server_error'
697+
});
698+
}
699+
679700
// TODO add some kind of error handling
680-
console.log(err); // tslint:disable-line:no-console
701+
if (err.status === 500) {
702+
console.log(err); // tslint:disable-line:no-console
703+
}
704+
705+
next();
681706
});
682707
}
683708

core/helpers/http-status.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const DUPLICATE_RESOURCE = 409;
2+
export const INVALID_BODY_PARAMETER = 422;
3+
export const SERVER_ERROR = 500;

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sakuraapi/api",
3-
"version": "0.7.0-3",
3+
"version": "0.7.0-4",
44
"description": "MongoDB and TypeScript MEAN Stack Framework for NodeJS",
55
"main": "index.js",
66
"typings": "index.d.ts",
@@ -20,8 +20,8 @@
2020
"istanbul": "istanbul",
2121
"jasmine": "jasmine",
2222
"lint": "npm run build && npm run lint:code && npm run lint:tests",
23-
"lint:code": "echo 'CODE LINT' ; npm run tslint -- -e \"**/node_modules/**/**/*.ts\" -t stylish -c tslint.json -p tsconfig.json",
24-
"lint:tests": "echo 'TEST LINT' ; npm run tslint -- -e \"**/node_modules/**/**/*.ts\" -t stylish -c tslint.spec.json -p tsconfig.json",
23+
"lint:code": "echo 'CODE LINT' ; npm run tslint -- -t stylish -c tslint.json -p tsconfig.json",
24+
"lint:tests": "echo 'TEST LINT' ; npm run tslint -- -t stylish -c tslint.spec.json -p tsconfig.json",
2525
"nsp": "nsp",
2626
"prepublish": "npm test && npm run nsp check",
2727
"say:fail": "say 'fail' || echo ''",

0 commit comments

Comments
 (0)