Skip to content

Commit

Permalink
Merge pull request #5 from feathersjs/error-mapping
Browse files Browse the repository at this point in the history
Error mapping
  • Loading branch information
ekryski committed Dec 19, 2015
2 parents 06b346a + 23d66be commit 6c263da
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 70 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ node_modules

lib/
*.sqlite
*.sqlite-journal
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
language: node_js
node_js:
- '0.10'
- '0.12'
- 'node'
- 'iojs'
Binary file removed db.sqlite-journal
Binary file not shown.
8 changes: 5 additions & 3 deletions example/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ var sequelize = new Sequelize('sequelize', '', '', {
});
var Todo = sequelize.define('todo', {
text: {
type: Sequelize.STRING
type: Sequelize.STRING,
allowNull: false
},
complete: {
type: Sequelize.BOOLEAN
type: Sequelize.BOOLEAN,
defaultValue: false
}
}, {
freezeTableName: true
Expand Down Expand Up @@ -46,4 +48,4 @@ app.use('/todos', sequelizeService({
// Start the server
module.exports = app.listen(3030);

console.log('Feathers Todo memory service running on 127.0.0.1:3030');
console.log('Feathers Todo sequelize service running on 127.0.0.1:3030');
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,23 @@
},
"dependencies": {
"babel-polyfill": "^6.3.14",
"feathers-errors": "^0.2.5",
"feathers": "^1.3.0",
"feathers-errors": "^1.1.5",
"feathers-query-filters": "^1.1.1",
"uberproto": "^1.1.2"
},
"devDependencies": {
"sequelize": "^3.14.1",
"babel-cli": "^6.1.2",
"babel-core": "^6.1.2",
"babel-plugin-add-module-exports": "^0.1.1",
"babel-preset-es2015": "^6.1.2",
"body-parser": "^1.14.1",
"chai": "^3.4.1",
"feathers": "^1.2.0",
"feathers-service-tests": "^0.5.1",
"feathers-service-tests": "^0.5.2",
"jshint": "^2.8.0",
"mocha": "^2.3.3",
"sequelize": "^3.14.1",
"sqlite3": "^3.1.1"
}
}
55 changes: 18 additions & 37 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,8 @@ if(!global._babelPolyfill) { require('babel-polyfill'); }

import Proto from 'uberproto';
import filter from 'feathers-query-filters';
import { types as errors } from 'feathers-errors';

function getOrder(sort) {
let order = [];

Object.keys(sort).forEach(name =>
order.push([ name, sort[name] === 1 ? 'ASC' : 'DESC' ]));

return order;
}

function getWhere(query) {
let where = Object.assign({}, query);

Object.keys(where).forEach(prop => {
let value = where[prop];
if(value.$nin) {
value = Object.assign({}, value);

value.$notIn = value.$nin;
delete value.$nin;

where[prop] = value;
}
});

return where;
}
import errors from 'feathers-errors';
import {errorHandler, getOrder, getWhere} from './utils';

class Service {
constructor(options) {
Expand All @@ -53,7 +27,7 @@ class Service {
attributes: filters.$select || null
};

if(this.paginate.default) {
if (this.paginate.default) {
const limit = Math.min(filters.$limit || this.paginate.default,
this.paginate.max || Number.MAX_VALUE);

Expand All @@ -66,10 +40,10 @@ class Service {
skip: filters.$skip || 0,
data: result.rows
};
});
}).catch(errorHandler);
}

return this.Model.findAll(query);
return this.Model.findAll(query).catch(errorHandler);
}

get(id) {
Expand All @@ -79,12 +53,16 @@ class Service {
}

return instance;
});
})
.catch(errorHandler);
}

create(data) {
return Array.isArray(data) ?
this.Model.bulkCreate(data) : this.Model.create(data);
if (Array.isArray(data)) {
return this.Model.bulkCreate(data).catch(errorHandler);
}

return this.Model.create(data).catch(errorHandler);
}

patch(id, data, params) {
Expand All @@ -102,7 +80,8 @@ class Service {
}

return this.get(id, params);
});
})
.catch(errorHandler);
}

update(id, data) {
Expand All @@ -127,7 +106,8 @@ class Service {
});

return instance.update(copy);
});
})
.catch(errorHandler);
}

remove(id, params) {
Expand All @@ -141,7 +121,8 @@ class Service {
}

return this.Model.destroy({ where }).then(() => data);
});
})
.catch(errorHandler);
}
}

Expand Down
60 changes: 60 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import errors from 'feathers-errors';

export function errorHandler(error) {
let feathersError = error;

if (error.name) {
switch(error.name) {
case 'SequelizeValidationError':
case 'SequelizeUniqueConstraintError':
case 'SequelizeExclusionConstraintError':
case 'SequelizeForeignKeyConstraintError':
case 'SequelizeInvalidConnectionError':
feathersError = new errors.BadRequest(error);
break;
case 'SequelizeTimeoutError':
case 'SequelizeConnectionTimedOutError':
feathersError = new errors.Timeout(error);
break;
case 'SequelizeConnectionRefusedError':
case 'SequelizeAccessDeniedError':
feathersError = new errors.Forbidden(error);
break;
case 'SequelizeHostNotReachableError':
feathersError = new errors.Unavailable(error);
break;
case 'SequelizeHostNotFoundError':
feathersError = new errors.NotFound(error);
break;
}
}

throw feathersError;
}

export function getOrder(sort) {
let order = [];

Object.keys(sort).forEach(name =>
order.push([ name, sort[name] === 1 ? 'ASC' : 'DESC' ]));

return order;
}

export function getWhere(query) {
let where = Object.assign({}, query);

Object.keys(where).forEach(prop => {
let value = where[prop];
if(value.$nin) {
value = Object.assign({}, value);

value.$notIn = value.$nin;
delete value.$nin;

where[prop] = value;
}
});

return where;
}
59 changes: 32 additions & 27 deletions test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
// jshint expr:true

import { base, example } from 'feathers-service-tests';
import { base, orm, example } from 'feathers-service-tests';
import Sequelize from 'sequelize';
import errors from 'feathers-errors';
import feathers from 'feathers';
import service from '../src';
import server from '../example/app';

describe('Feathers Sequelize Service', () => {
const sequelize = new Sequelize('sequelize', '', '', {
dialect: 'sqlite',
storage: './db.sqlite',
logging: false
});
const Model = sequelize.define('user', {
name: {
type: Sequelize.STRING
},
age: {
type: Sequelize.INTEGER
},
created: {
type: Sequelize.BOOLEAN
},
time: {
type: Sequelize.INTEGER
}
}, {
freezeTableName: true
});
const _ids = {};
const app = feathers().use('/people', service({ Model }));
const people = app.service('people');
const sequelize = new Sequelize('sequelize', '', '', {
dialect: 'sqlite',
storage: './db.sqlite',
logging: false
});
const Model = sequelize.define('user', {
name: {
type: Sequelize.STRING,
allowNull: false
},
age: {
type: Sequelize.INTEGER
},
created: {
type: Sequelize.BOOLEAN
},
time: {
type: Sequelize.INTEGER
}
}, {
freezeTableName: true
});
const _ids = {};
const app = feathers().use('/people', service({ Model }));
const people = app.service('people');

describe('Feathers Sequelize Service', () => {
beforeEach(done => {
Model.sync({ force: true }).then(() => {
return Model.create({
Expand All @@ -45,7 +46,11 @@ describe('Feathers Sequelize Service', () => {
});
});

base(people, _ids, errors.types);
base(people, _ids, errors);
});

describe('Sequelize service ORM errors', () => {
orm(people, _ids, errors);
});

describe('Sequelize service example test', () => {
Expand Down
Loading

0 comments on commit 6c263da

Please sign in to comment.