Skip to content

Commit

Permalink
Upgrade to @feathersjs/adapter-commons and latest common service feat…
Browse files Browse the repository at this point in the history
…ures (#181)

* Start migration to @feathersjs/adapter-commons

* Finalize refactoring to adapter-commons

* Force remove to always work

* Command typo

* Update error handling and finalize docs
  • Loading branch information
daffl authored Dec 28, 2018
1 parent f1ebeaf commit c39c855
Show file tree
Hide file tree
Showing 9 changed files with 754 additions and 926 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ node_modules
.lock-wscript

dist/
*.sqlite
*.sqlite*
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
language: node_js
node_js:
- 10
- 6
- 'node'
- 8
sudo: false
install: npm install
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ __Options:__
- `id` (*optional*, default: `'id'`) - The name of the id field property.
- `events` (*optional*) - A list of [custom service events](https://docs.feathersjs.com/api/events.html#custom-events) sent by this service
- `paginate` (*optional*) - A [pagination object](https://docs.feathersjs.com/api/databases/common.html#pagination) containing a `default` and `max` page size
- `multi` (*optional*) - Allow `create` with arrays and `update` and `remove` with `id` `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`)
- `whitelist` (*optional*) - A list of additional query parameters to allow (e..g `[ '$regex', '$geoNear' ]`). Default is the supported `operators`

### `adapter.createQuery(query)`

Expand Down Expand Up @@ -281,8 +283,24 @@ app.service('mesages').hooks({
});
```

### Error handling

As of version 4.0.0 `feathers-knex` only throws [Feathers Errors](https://docs.feathersjs.com/api/errors.html) with the message. On the server, the original error can be retrieved through a secure symbol via `error[require('feathers-knex').ERROR]`

```js
const { ERROR } = require('feathers-knex');

try {
await sequelizeService.doSomething();
} catch(error) {
// error is a FeathersError with just the message
// Safely retrieve the Knex error
const knexError = error[ERROR];
}
```

## License

Copyright (c) 2016
Copyright (c) 2019

Licensed under the [MIT license](LICENSE).
58 changes: 27 additions & 31 deletions lib/error-handler.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
const errors = require('@feathersjs/errors');
const ERROR = Symbol('feathers-knex/error');

module.exports = function errorHandler (error) {
const { message } = error;
let feathersError = error;

// TODO (EK): Map PG, Oracle, etc. errors

// NOTE: SQLState values from
// https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-error-sqlstates.html

if (error.sqlState && error.sqlState.length) {
// remove SQLSTATE marker (#) and pad/truncate SQLSTATE to 5 chars
let sqlState = ('00000' + error.sqlState.replace('#', '')).slice(-5);
const sqlState = ('00000' + error.sqlState.replace('#', '')).slice(-5);

switch (sqlState.slice(0, 2)) {
case '02':
feathersError = new errors.NotFound(error);
feathersError = new errors.NotFound(message);
break;
case '28':
feathersError = new errors.Forbidden(error);
feathersError = new errors.Forbidden(message);
break;
case '08':
case '0A':
case '0K':
feathersError = new errors.Unavailable(error);
feathersError = new errors.Unavailable(message);
break;
case '20':
case '21':
Expand All @@ -33,66 +30,65 @@ module.exports = function errorHandler (error) {
case '40':
case '42':
case '70':
feathersError = new errors.BadRequest(error);
feathersError = new errors.BadRequest(message);
break;
default:
feathersError = new errors.GeneralError(error);
feathersError = new errors.GeneralError(message);
}
}

// NOTE (EK): Error codes taken from
// https://www.sqlite.org/c3ref/c_abort.html

if (error.code === 'SQLITE_ERROR') {
} else if (error.code === 'SQLITE_ERROR') {
// NOTE (EK): Error codes taken from
// https://www.sqlite.org/c3ref/c_abort.html
switch (error.errno) {
case 1:
case 8:
case 18:
case 19:
case 20:
feathersError = new errors.BadRequest(error);
feathersError = new errors.BadRequest(message);
break;
case 2:
feathersError = new errors.Unavailable(error);
feathersError = new errors.Unavailable(message);
break;
case 3:
case 23:
feathersError = new errors.Forbidden(error);
feathersError = new errors.Forbidden(message);
break;
case 12:
feathersError = new errors.NotFound(error);
feathersError = new errors.NotFound(message);
break;
default:
feathersError = new errors.GeneralError(error);
feathersError = new errors.GeneralError(message);
break;
}
}

// NOTE: Error codes taken from
// https://www.postgresql.org/docs/9.6/static/errcodes-appendix.html
if (typeof error.code === 'string' && error.severity && error.routine) {
} else if (typeof error.code === 'string' && error.severity && error.routine) {
// NOTE: Error codes taken from
// https://www.postgresql.org/docs/9.6/static/errcodes-appendix.html
// Omit query information
const messages = error.message.split('-');
error.message = messages[messages.length - 1];

switch (error.code.slice(0, 2)) {
case '22':
case '23':
feathersError = new errors.BadRequest(error);
feathersError = new errors.BadRequest(message);
break;
case '28':
feathersError = new errors.Forbidden(error);
feathersError = new errors.Forbidden(message);
break;
case '3D':
case '3F':
case '42':
feathersError = new errors.Unprocessable(error);
feathersError = new errors.Unprocessable(message);
break;
default:
feathersError = new errors.GeneralError(error);
feathersError = new errors.GeneralError(message);
break;
}
} else if (!(error instanceof errors.FeathersError)) {
feathersError = new errors.GeneralError(message);
}

feathersError[ERROR] = error;

throw feathersError;
};
14 changes: 6 additions & 8 deletions lib/hooks.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const debug = require('debug')('feathers-knex-transaction');

const RollbackReason = function(error) {
const RollbackReason = function (error) {
this.error = error;
};

const start = (options) => {
const start = () => {
return hook => new Promise(resolve => {
if (!hook.service.Model || typeof hook.service.Model.transaction !== 'function') {
return resolve(hook);
Expand Down Expand Up @@ -33,10 +33,10 @@ const start = (options) => {
});
};

const end = (options) => {
const end = () => {
return hook => {
if (hook.params.transaction) {
const { promise, trx, id, count } = hook.params.transaction;
const { trx, id, count } = hook.params.transaction;

if (count > 0) {
hook.params.transaction.count -= 1;
Expand All @@ -46,21 +46,19 @@ const end = (options) => {
hook.params.transaction = undefined;

return trx.commit()
.then(() => promise)
.then(() => debug('finished transaction %s with success', id))
.then(() => hook);
}
return hook;
};
};

const rollback = (options) => {
const rollback = () => {
return hook => {
if (hook.params.transaction) {
const { promise, trx, id } = hook.params.transaction;
const { trx, id } = hook.params.transaction;
return trx.rollback(new RollbackReason(hook.error))
.then(() => debug('rolling back transaction %s', id))
.then(() => promise)
.then(() => hook);
}
return hook;
Expand Down
Loading

0 comments on commit c39c855

Please sign in to comment.