Socket
Socket
Sign inDemoInstall

feathers-sequelize

Package Overview
Dependencies
Maintainers
2
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

feathers-sequelize - npm Package Compare versions

Comparing version 3.1.3 to 4.0.0

26

CHANGELOG.md
# Change Log
## [v3.1.3](https://github.com/feathersjs-ecosystem/feathers-sequelize/tree/v3.1.3) (2018-10-29)
[Full Changelog](https://github.com/feathersjs-ecosystem/feathers-sequelize/compare/v3.1.2...v3.1.3)
**Closed issues:**
- Include hook doesn't work on create [\#242](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/242)
- Warning messages when using "sequelize db:migrate" [\#240](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/240)
- Extending service class fails when transpiling to ES5 [\#237](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/237)
- Example in readme.md doesn't work [\#236](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/236)
- How to use raw where clause [\#233](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/233)
- Associations on Create [\#230](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/230)
- Valid password characters can break the connection string [\#229](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/229)
- Does Feathers-Sequalize support class and instance methods? [\#225](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/225)
- Find & include data structure shape [\#224](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/224)
- Fix bug Pg-Native [\#222](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/222)
- Connection pool [\#221](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/221)
- Question: Feathers Sequelize raw query and feathers service without using model. [\#215](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/215)
- Sub include relations with Sequelize: Query erro [\#203](https://github.com/feathersjs-ecosystem/feathers-sequelize/issues/203)
**Merged pull requests:**
- use transactions in `update`, related to \#188 [\#243](https://github.com/feathersjs-ecosystem/feathers-sequelize/pull/243) ([jiangts](https://github.com/jiangts))
- Update README to fix \#240 [\#241](https://github.com/feathersjs-ecosystem/feathers-sequelize/pull/241) ([leedongwei](https://github.com/leedongwei))
- minor typos [\#232](https://github.com/feathersjs-ecosystem/feathers-sequelize/pull/232) ([Strongbyte-ES](https://github.com/Strongbyte-ES))
- Update README: Latest version requires mysql2 [\#219](https://github.com/feathersjs-ecosystem/feathers-sequelize/pull/219) ([ricardopolo](https://github.com/ricardopolo))
## [v3.1.2](https://github.com/feathersjs-ecosystem/feathers-sequelize/tree/v3.1.2) (2018-06-07)

@@ -4,0 +30,0 @@ [Full Changelog](https://github.com/feathersjs-ecosystem/feathers-sequelize/compare/v3.1.1...v3.1.2)

228

lib/index.js

@@ -1,23 +0,40 @@

const omit = require('lodash.omit');
const Proto = require('uberproto');
const errors = require('@feathersjs/errors');
const { select, filterQuery } = require('@feathersjs/commons');
const { _ } = require('@feathersjs/commons');
const { select, AdapterService } = require('@feathersjs/adapter-commons');
const utils = require('./utils');
const defaultOperators = Op => {
return {
$eq: Op.eq,
$ne: Op.ne,
$gte: Op.gte,
$gt: Op.gt,
$lte: Op.lte,
$lt: Op.lt,
$in: Op.in,
$nin: Op.notIn,
$like: Op.like,
$notLike: Op.notLike,
$iLike: Op.ilike,
$notILike: Op.notILike,
$or: Op.or,
$and: Op.and
};
};
class Service {
class Service extends AdapterService {
constructor (options) {
if (!options) {
throw new Error('Sequelize options have to be provided');
}
if (!options.Model) {
throw new Error('You must provide a Sequelize Model');
}
this.paginate = options.paginate || false;
this.options = options;
this.Model = options.Model;
this.id = options.id || 'id';
this.events = options.events;
const defaultOps = defaultOperators(options.Model.sequelize.Op);
const operators = Object.assign(defaultOps, options.operators);
const whitelist = Object.keys(operators).concat(options.whitelist || []);
super(Object.assign({
id: 'id',
operators,
whitelist
}, options));
this.raw = options.raw !== false;

@@ -27,3 +44,3 @@ }

getModel (params) {
return this.Model;
return this.options.Model;
}

@@ -38,9 +55,43 @@

extend (obj) {
return Proto.extend(obj, this);
filterQuery (params) {
const filtered = super.filterQuery(params);
const operators = this.options.operators;
const convertOperators = query => {
if (Array.isArray(query)) {
return query.map(convertOperators);
}
if (!_.isObject(query)) {
return query;
}
return Object.keys(query).reduce((result, prop) => {
const value = query[prop];
const key = operators[prop] ? operators[prop] : prop;
result[key] = convertOperators(value);
return result;
}, {});
};
filtered.query = convertOperators(filtered.query);
return filtered;
}
_find (params, getFilter = filterQuery, paginate) {
const { filters, query } = getFilter(params.query || {});
const where = utils.getWhere(query);
// returns either the model intance for an id or all unpaginated
// items for `params` if id is null
_getOrFind (id, params) {
if (id === null) {
return this._find(Object.assign(params, {
paginate: false
}));
}
return this._get(id, params);
}
_find (params) {
const { filters, query: where, paginate } = this.filterQuery(params);
const order = utils.getOrder(filters.$sort);

@@ -75,3 +126,3 @@

if (paginate) {
if (paginate && paginate.default) {
return Model.findAndCountAll(q).then(result => {

@@ -85,24 +136,9 @@ return {

}).catch(utils.errorHandler);
} else {
return Model.findAll(q).then(result => {
return {
data: result
};
}).catch(utils.errorHandler);
}
}
find (params) {
const paginate = (params && typeof params.paginate !== 'undefined') ? params.paginate : this.paginate;
const result = this._find(params, where => filterQuery(where, paginate), paginate);
if (!paginate.default) {
return result.then(page => page.data);
}
return result;
return Model.findAll(q).catch(utils.errorHandler);
}
_get (id, params) {
const where = utils.getWhere(params.query);
const { query: where } = this.filterQuery(params);

@@ -112,3 +148,3 @@ // Attach 'where' constraints, if any were used.

raw: this.raw,
where: Object.assign({[this.id]: id}, where)
where: Object.assign({ [this.id]: id }, where)
}, params.sequelize);

@@ -126,25 +162,7 @@

return result[0];
})
.then(select(params, this.id))
.catch(error => {
throw new errors.NotFound(`No record found for id '${id}'`, error);
});
}).then(select(params, this.id)).catch(utils.errorHandler);
}
// returns either the model intance for an id or all unpaginated
// items for `params` if id is null
_getOrFind (id, params) {
if (id === null) {
return this._find(params).then(page => page.data);
}
return this._get(id, params);
}
get (id, params) {
return this._get(id, params).then(select(params, this.id));
}
create (data, params) {
const options = Object.assign({raw: this.raw}, params.sequelize);
_create (data, params) {
const options = Object.assign({ raw: this.raw }, params.sequelize);
// Model.create's `raw` option is different from other methods.

@@ -155,3 +173,3 @@ // In order to use `raw` consistently to serialize the result,

const ignoreSetters = Boolean(options.ignoreSetters);
const createOptions = Object.assign({}, options, {raw: ignoreSetters});
const createOptions = Object.assign({}, options, { raw: ignoreSetters });
const isArray = Array.isArray(data);

@@ -180,5 +198,5 @@ let promise;

patch (id, data, params) {
const where = Object.assign({}, filterQuery(params.query || {}).query);
const mapIds = page => page.data.map(current => current[this.id]);
_patch (id, data, params) {
const where = Object.assign({}, this.filterQuery(params).query);
const mapIds = data => data.map(current => current[this.id]);

@@ -189,3 +207,3 @@ if (id !== null) {

const options = Object.assign({raw: this.raw}, params.sequelize, { where });
const options = Object.assign({ raw: this.raw }, params.sequelize, { where });

@@ -199,3 +217,3 @@ let Model = this.applyScope(params);

return this._getOrFind(id, params)
.then(results => this.getModel(params).update(omit(data, this.id), options))
.then(results => this.getModel(params).update(_.omit(data, this.id), options))
.then(results => {

@@ -222,50 +240,37 @@ if (id === null) {

return ids
.then(idList => {
// Create a new query that re-queries all ids that
// were originally changed
const findParams = Object.assign({}, params, {
query: { [this.id]: { $in: idList } }
return ids.then(idList => {
// Create a new query that re-queries all ids that
// were originally changed
const findParams = Object.assign({}, params, Object.assign({}, {
query: Object.assign({ [this.id]: { $in: idList } }, params.query)
}));
return Model.update(_.omit(data, this.id), options)
.then(() => {
if (params.$returning !== false) {
return this._getOrFind(id, findParams);
} else {
return Promise.resolve([]);
}
});
return Model.update(omit(data, this.id), options)
.then(() => {
if (params.$returning !== false) {
return this._getOrFind(id, findParams);
} else {
return Promise.resolve([]);
}
});
})
.then(select(params, this.id))
.catch(utils.errorHandler);
}).then(select(params, this.id)).catch(utils.errorHandler);
}
update (id, data, params) {
const where = Object.assign({}, filterQuery(params.query || {}).query);
_update (id, data, params) {
const where = Object.assign({}, this.filterQuery(params).query);
const options = Object.assign({ raw: this.raw }, params.sequelize);
if (Array.isArray(data)) {
return Promise.reject(new errors.BadRequest('Not replacing multiple records. Did you mean `patch`?'));
}
// Force the {raw: false} option as the instance is needed to properly
// update
const updateOptions = Object.assign({ raw: false }, params.sequelize);
const updateOptions = Object.assign({}, params.sequelize, { raw: false });
const getOptions = Object.assign({}, params, { query: where, sequelize: { raw: false } });
return this._get(id, { sequelize: { raw: false }, query: where }).then(instance => {
if (!instance) {
throw new errors.NotFound(`No record found for id '${id}'`);
}
return this._get(id, getOptions).then(instance => {
const copy = Object.keys(instance.toJSON()).reduce((result, key) => {
result[key] = typeof data[key] === 'undefined' ? null : data[key];
let copy = {};
Object.keys(instance.toJSON()).forEach(key => {
if (typeof data[key] === 'undefined') {
copy[key] = null;
} else {
copy[key] = data[key];
}
});
return result;
}, {});
return instance.update(copy, updateOptions).then(() => this._get(id, {sequelize: options}));
return instance.update(copy, updateOptions).then(() => this._get(id, { sequelize: options }));
})

@@ -276,5 +281,5 @@ .then(select(params, this.id))

remove (id, params) {
_remove (id, params) {
const opts = Object.assign({ raw: this.raw }, params);
const where = Object.assign({}, filterQuery(params.query || {}).query);
const where = Object.assign({}, this.filterQuery(params).query);

@@ -285,3 +290,3 @@ if (id !== null) {

const options = Object.assign({}, params.sequelize, { where });
const options = Object.assign({}, { where }, params.sequelize);

@@ -304,12 +309,9 @@ let Model = this.applyScope(params);

function init (options) {
return new Service(options);
}
const init = options => new Service(options);
module.exports = init;
// Exposed Modules
Object.assign(module.exports, {
module.exports = Object.assign(init, {
default: init,
ERROR: utils.ERROR,
Service
});
const errors = require('@feathersjs/errors');
const ERROR = Symbol('feathers-sequelize/error');
const wrap = (error, original) => Object.assign(error, { [ERROR]: original });
exports.errorHandler = function errorHandler (error) {
let feathersError = error;
exports.ERROR = ERROR;
if (error.name) {
switch (error.name) {
exports.errorHandler = error => {
const { name, message } = error;
if (name) {
switch (name) {
case 'SequelizeValidationError':

@@ -13,53 +17,23 @@ case 'SequelizeUniqueConstraintError':

case 'SequelizeInvalidConnectionError':
feathersError = new errors.BadRequest(error);
break;
throw wrap(new errors.BadRequest(message, { errors: error.errors }), error);
case 'SequelizeTimeoutError':
case 'SequelizeConnectionTimedOutError':
feathersError = new errors.Timeout(error);
break;
throw wrap(new errors.Timeout(message), error);
case 'SequelizeConnectionRefusedError':
case 'SequelizeAccessDeniedError':
feathersError = new errors.Forbidden(error);
break;
throw wrap(new errors.Forbidden(message), error);
case 'SequelizeHostNotReachableError':
feathersError = new errors.Unavailable(error);
break;
throw wrap(new errors.Unavailable(message), error);
case 'SequelizeHostNotFoundError':
feathersError = new errors.NotFound(error);
break;
throw wrap(new errors.NotFound(message), error);
}
}
throw feathersError;
throw error;
};
exports.getOrder = function getOrder (sort = {}) {
let order = [];
exports.getOrder = (sort = {}) => Object.keys(sort).reduce((order, name) => {
order.push([ name, parseInt(sort[name], 10) === 1 ? 'ASC' : 'DESC' ]);
Object.keys(sort).forEach(name =>
order.push([ name, parseInt(sort[name], 10) === 1 ? 'ASC' : 'DESC' ]));
return order;
};
exports.getWhere = function getWhere (query) {
let where = Object.assign({}, query);
if (where.$select) {
delete where.$select;
}
Object.keys(where).forEach(prop => {
let value = where[prop];
if (value && value.$nin) {
value = Object.assign({}, value);
value.$notIn = value.$nin;
delete value.$nin;
where[prop] = value;
}
});
return where;
};
}, []);
{
"name": "feathers-sequelize",
"description": "A service adapter for Sequelize an SQL ORM",
"version": "3.1.3",
"version": "4.0.0",
"homepage": "https://github.com/feathersjs-ecosystem/feathers-sequelize",

@@ -60,22 +60,21 @@ "main": "lib/",

"dependencies": {
"@feathersjs/commons": "^1.3.0",
"@feathersjs/errors": "^3.2.0",
"lodash.omit": "^4.3.0",
"uberproto": "^2.0.0"
"@feathersjs/adapter-commons": "^1.0.5",
"@feathersjs/commons": "^4.0.0",
"@feathersjs/errors": "^3.3.5"
},
"devDependencies": {
"@feathersjs/express": "^1.1.2",
"@feathersjs/feathers": "^3.0.1",
"body-parser": "^1.14.1",
"chai": "^4.0.0",
"feathers-service-tests": "^0.10.0",
"@feathersjs/express": "^1.3.0",
"@feathersjs/feathers": "^3.3.0",
"body-parser": "^1.18.3",
"chai": "^4.2.0",
"feathers-service-tests": "^0.10.2",
"istanbul": "^1.1.0-alpha.1",
"mocha": "^5.0.0",
"mysql2": "^1.4.2",
"pg": "^7.3.0",
"mocha": "^5.2.0",
"mysql2": "^1.6.4",
"pg": "^7.7.1",
"pg-hstore": "^2.3.2",
"semistandard": "^12.0.0",
"sequelize": "^4.36.1",
"sqlite3": "^4.0.0"
"semistandard": "^13.0.1",
"sequelize": "^4.42.0",
"sqlite3": "^4.0.4"
}
}

@@ -50,2 +50,5 @@ # feathers-sequelize

- `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' ]`)
- `operators` (*optional*) - A mapping from query syntax property names to to [Sequelize secure operators](http://docs.sequelizejs.com/manual/tutorial/querying.html)
- `whitelist` (*optional*) - A list of additional query parameters to allow (e..g `[ '$regex', '$geoNear' ]`). Default is the supported `operators`

@@ -74,2 +77,23 @@ ### params.sequelize

### operators
Sequelize deprecated string based operators a while ago for security reasons. Starting at version 4.0.0 `feathers-sequelize` converts queries securely. If you want to support additional Sequelize operators, the `operators` service option can contain a mapping from query parameter name to Sequelize operator. By default supported are:
```
'$eq',
'$ne',
'$gte',
'$gt',
'$lte',
'$lt',
'$in',
'$nin',
'$like',
'$notLike',
'$iLike',
'$notILike',
'$or',
'$and'
```
## Sequelize `raw` queries

@@ -485,6 +509,32 @@

### Migrating
`feathers-sequelize` 4.0.0 comes with important security and usability updates.
> __Important:__ For general migration information to the new database adapter functionality see [crow.docs.feathersjs.com/migrating.html#database-adapters](https://crow.docs.feathersjs.com/migrating.html#database-adapters).
The following breaking changes have been introduced:
- All methods now take `params.sequelize` into account
- All methods allow additional query parameters
- Multiple updates are disabled by default (see the `multi` option)
- Upgraded to secure Sequelize operators (see the [operators](#operators) option)
- Errors no longer contain Sequelize specific information. The original Sequelize error can be retrieved on the server via:
```js
const { ERROR } = require('feathers-sequelize');
try {
await sequelizeService.doSomethign();
} catch(error) {
// error is a FeathersError
// Safely retrieve the Sequelize error
const sequelizeError = error[ERROR];
}
```
## License
Copyright (c) 2017
Copyright (c) 2019
Licensed under the [MIT license](LICENSE).
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc