Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

feathers-memory

Package Overview
Dependencies
Maintainers
2
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

feathers-memory - npm Package Compare versions

Comparing version 0.4.0 to 0.4.1

example/app.js

286

lib/index.js
'use strict';
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.specialFilters = undefined;
exports.default = init;

@@ -22,2 +24,4 @@ var _lodash = require('lodash');

var _utils = require('./utils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -27,185 +31,171 @@

var specialFilters = exports.specialFilters = {
$in: function $in(key, ins) {
return function (current) {
return ins.indexOf(current[key]) !== -1;
};
},
$nin: function $nin(key, nins) {
return function (current) {
return nins.indexOf(current[key]) === -1;
};
},
$lt: function $lt(key, value) {
return function (current) {
return current[key] < value;
};
},
$lte: function $lte(key, value) {
return function (current) {
return current[key] <= value;
};
},
$gt: function $gt(key, value) {
return function (current) {
return current[key] > value;
};
},
$gte: function $gte(key, value) {
return function (current) {
return current[key] >= value;
};
},
$ne: function $ne(key, value) {
return function (current) {
return current[key] !== value;
};
}
};
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function filterSpecials(values, query) {
if (query.$or) {
values = values.filter(function (current) {
return _lodash2.default.some(query.$or, function (or) {
return _lodash2.default.isMatch(current, or);
});
});
delete query.$or;
require('babel-polyfill');
var Service = (function () {
function Service() {
var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
_classCallCheck(this, Service);
this.paginate = options.paginate || {};
this._id = options.idField || 'id';
this._uId = options.startId || 0;
this.store = options.store || {};
}
_lodash2.default.each(query, function (value, key) {
if (_lodash2.default.isObject(value)) {
_lodash2.default.each(value, function (target, prop) {
if (specialFilters[prop]) {
values = values.filter(specialFilters[prop](key, target));
}
});
delete query[key];
_createClass(Service, [{
key: 'extend',
value: function extend(obj) {
return _uberproto2.default.extend(obj, this);
}
});
}, {
key: 'find',
value: function find(params) {
var query = params.query || {};
var filters = (0, _feathersQueryFilters2.default)(query);
return values;
}
var values = (0, _utils.filterSpecials)(_lodash2.default.values(this.store), query);
function sorter($sort) {
return function (first, second) {
var comparator = 0;
_lodash2.default.each($sort, function (modifier, key) {
if (first[key] < second[key]) {
comparator -= 1 * modifier;
if (!_lodash2.default.isEmpty(query)) {
values = _lodash2.default.where(values, query);
}
if (first[key] > second[key]) {
comparator += 1 * modifier;
var total = values.length;
if (filters.$sort) {
values.sort((0, _utils.sorter)(filters.$sort));
}
});
return comparator;
};
}
var MemoryService = _uberproto2.default.extend({
init: function init(options) {
options = options || {};
if (filters.$skip) {
values = values.slice(parseInt(filters.$skip, 10));
}
this.type = 'memory';
this._id = options.idField || 'id';
this._uId = options.startId || 0;
this.store = options.store || {};
},
find: function find(params, cb) {
var query = params.query || {};
var filters = (0, _feathersQueryFilters2.default)(query);
var limit = parseInt(filters.$limit || this.paginate.default, 10);
var values = filterSpecials(_lodash2.default.values(this.store), query);
if (limit) {
limit = Math.min(this.paginate.max || Number.MAX_VALUE, limit);
values = values.slice(0, limit);
}
if (!_lodash2.default.isEmpty(query)) {
values = _lodash2.default.where(values, query);
}
if (filters.$select) {
values = values.map(function (value) {
return _lodash2.default.pick(value, filters.$select);
});
}
// Handle $sort
if (filters.$sort) {
values.sort(sorter(filters.$sort));
}
if (this.paginate.default) {
return Promise.resolve({
total: total,
limit: limit,
skip: parseInt(filters.$skip || 0, 10),
data: values
});
}
if (filters.$skip) {
values = values.slice(parseInt(filters.$skip, 10));
return Promise.resolve(values);
}
}, {
key: 'get',
value: function get(id) {
if (id in this.store) {
return Promise.resolve(this.store[id]);
}
if (filters.$limit) {
values = values.slice(0, parseInt(filters.$limit, 10));
return Promise.reject(new _feathersErrors.types.NotFound('No record found for id \'' + id + '\''));
}
}, {
key: 'create',
value: function create(data) {
var _this = this;
if (filters.$select) {
values = values.map(function (value) {
return _lodash2.default.pick(value, filters.$select);
});
}
if (Array.isArray(data)) {
return Promise.all(data.map(function (current) {
return _this.create(current);
}));
}
cb(null, values);
},
get: function get(id, params, cb) {
if (typeof id === 'function') {
return id(new _feathersErrors.types.BadRequest('An id needs to be provided'));
}
var id = data[this._id] || this._uId++;
var current = _lodash2.default.extend({}, data, _defineProperty({}, this._id, id));
if (id in this.store) {
return cb(null, this.store[id]);
if (this.store[id]) {
return Promise.reject(new _feathersErrors.types.Conflict('A record with id: ' + id + ' already exists'));
}
return Promise.resolve(this.store[id] = current);
}
}, {
key: 'update',
value: function update(id, data) {
if (id === null || Array.isArray(data)) {
return Promise.reject(new _feathersErrors.types.BadRequest('You can not replace multiple instances. Did you mean \'patch\'?'));
}
cb(new _feathersErrors.types.NotFound('No record found for id \'' + id + '\''));
},
create: function create(data, params, cb) {
var id = data[this._id] || this._uId++;
data = _lodash2.default.extend({}, data, _defineProperty({}, this._id, id));
if (id in this.store) {
data = _lodash2.default.extend({}, data, _defineProperty({}, this._id, id));
this.store[id] = data;
if (this.store[id]) {
return cb(new _feathersErrors.types.Conflict('A record with id: ' + id + ' already exists'));
return Promise.resolve(this.store[id]);
}
return Promise.reject(new _feathersErrors.types.NotFound('No record found for id \'' + id + '\''));
}
}, {
key: 'patch',
value: function patch(id, data, params) {
var _this2 = this;
this.store[id] = data;
if (id === null) {
return this.find(params).then(function (instances) {
return Promise.all(instances.map(function (current) {
return _this2.patch(current[_this2._id], data, params);
}));
});
}
cb(null, data);
},
update: function update(id, data, params, cb) {
if (id in this.store) {
data = _lodash2.default.extend({}, data, _defineProperty({}, this._id, id));
this.store[id] = data;
if (id in this.store) {
_lodash2.default.each(data, function (value, key) {
if (key !== _this2._id) {
_this2.store[id][key] = value;
}
});
return cb(null, this.store[id]);
return Promise.resolve(this.store[id]);
}
return Promise.reject(new _feathersErrors.types.NotFound('No record found for id \'' + id + '\''));
}
}, {
key: 'remove',
value: function remove(id, params) {
var _this3 = this;
cb(new _feathersErrors.types.NotFound('No record found for id \'' + id + '\''));
},
patch: function patch(id, data, params, cb) {
var _this = this;
if (id === null) {
return this.find(params).then(function (data) {
return Promise.all(data.map(function (current) {
return _this3.remove(current[_this3._id]);
}));
});
}
if (id in this.store) {
_lodash2.default.each(data, function (value, key) {
if (key !== _this._id) {
_this.store[id][key] = value;
}
});
if (id in this.store) {
var deleted = this.store[id];
delete this.store[id];
return cb(null, this.store[id]);
}
return Promise.resolve(deleted);
}
cb(new _feathersErrors.types.NotFound('No record found for id \'' + id + '\''));
},
remove: function remove(id, params, cb) {
if (id in this.store) {
var deleted = this.store[id];
delete this.store[id];
return cb(null, deleted);
return Promise.reject(new _feathersErrors.types.NotFound('No record found for id \'' + id + '\''));
}
}]);
cb(new _feathersErrors.types.NotFound('No record found for id \'' + id + '\''));
}
});
return Service;
})();
module.exports = function (options) {
return _uberproto2.default.create.call(MemoryService, options);
};
function init(options) {
return new Service(options);
}
module.exports.Service = MemoryService;
init.Service = Service;
module.exports = exports['default'];
{
"name": "feathers-memory",
"description": "An in memory service store",
"version": "0.4.0",
"version": "0.4.1",
"homepage": "https://github.com/feathersjs/feathers-memory",

@@ -43,3 +43,3 @@ "main": "lib/",

"mocha": "mocha test/ --compilers js:babel-core/register",
"test": "npm run jshint && npm run mocha"
"test": "npm run compile && npm run jshint && npm run mocha"
},

@@ -50,6 +50,7 @@ "directories": {

"dependencies": {
"babel-polyfill": "^6.2.0",
"feathers-errors": "^0.2.5",
"feathers-query-filters": "^1.1.1",
"lodash": "^3.10.1",
"uberproto": "^1.1.2"
"uberproto": "^1.2.0"
},

@@ -59,8 +60,18 @@ "devDependencies": {

"babel-core": "^6.1.2",
"babel-plugin-add-module-exports": "^0.1.1",
"babel-preset-es2015": "^6.1.2",
"body-parser": "^1.14.1",
"feathers": "^1.1.1",
"feathers-service-tests": "^0.3.0",
"feathers-service-tests": "^0.5.0",
"jshint": "^2.8.0",
"mocha": "^2.3.3"
},
"babel": {
"plugins": [
"add-module-exports"
],
"presets": [
"es2015"
]
}
}

@@ -17,3 +17,3 @@ # feathers-memory

Creating an in-memory service is this simple:
You can create an in-memory service with no options:

@@ -27,16 +27,14 @@ ```js

### Complete Example
## Complete Example
Here is an example of a Feathers server with a `todos` in-memory service.
Here is an example of a Feathers server with a `todos` in-memory service that supports pagination:
```js
// server.js
var feathers = require('feathers'),
bodyParser = require('body-parser'),
memory = require('feathers-memory');
// app.js
var feathers = require('feathers');
var bodyParser = require('body-parser');
var memory = require('feathers-memory');
// Create a feathers instance.
var app = feathers()
// Setup the public folder.
.use(feathers.static(__dirname + '/public'))
// Enable Socket.io

@@ -49,9 +47,24 @@ .configure(feathers.socketio())

// Turn on URL-encoded parser for REST services
.use(bodyParser.urlencoded({ extended: true }))
.use(bodyParser.urlencoded({ extended: true }));
// Connect to the db, create and register a Feathers service.
app.use('/todos', memory());
// Create an in-memory Feathers service with a default page size of 2 items
// and a maximum size of 4
app.use('/todos', memory({
paginate: {
default: 2,
max: 4
}
}));
// Create a dummy Todo
app.service('todos').create({
text: 'Server todo',
complete: false
}).then(function(todo) {
console.log('Created todo', todo);
});
// Start the server.
var port = 8080;
var port = 3030;
app.listen(port, function() {

@@ -62,28 +75,96 @@ console.log('Feathers server listening on port ' + port);

You can run this example by using `node examples/basic` and going to [localhost:8080/todos](http://localhost:8080/todos). You should see an empty array. That's because you don't have any Todos yet but you now have full CRUD for your new todos service.
You can run this example by using `node examples/app` and going to [localhost:3030/todos](http://localhost:3030/todos). You will see the test Todo that we created at the end of that file.
### Extending
## Extending
You can also extend any of the feathers services to do something custom.
There are several ways to extend the basic CRUD functionality of this service.
_Keep in mind that calling the original service methods will return a Promise that resolves with the value._
### feathers-hooks
The most flexible option is weaving in functionality through [feathers-hooks](https://github.com/feathersjs/feathers-hooks), for example, `createdAt` and `updatedAt` timestamps could be added like this:
```js
var feathers = require('feathers');
var hooks = require('feathers-hooks');
var memory = require('feathers-memory');
var app = feathers();
var myUserService = memory().extend({
find: function(params, cb){
// Do something awesome!
var app = feathers()
.configure(hooks())
.use('/todos', memory({
paginate: {
default: 2,
max: 4
}
}));
console.log('I am extending the find method');
var stripIds = function() {
delete hook.data.id;
next();
}
this._super.apply(this, arguments);
var updateTimestamp = function(hook, next) {
hook.data.updatedAt = new Date();
next();
}
app.service('todos').before({
// You can create a single hook like this
create: function(hook, next) {
hook.data.createdAt = new Date();
next();
},
// Or you can chain multiple hooks like this
update: [stripIds, updateTimeStamp]
});
app.listen(3030);
```
### Classes (ES6)
The module also exports a Babel transpiled ES6 class as `Service` that can be directly extended like this:
```js
import { Service } from 'feathers-memory';
class MyService extends Service {
create(data, params) {
data.created_at = new Date();
return super.create(data, params).then(todo);
}
}
app.use('/todos', new MyService({
paginate: {
default: 2,
max: 4
}
}));
```
### Uberproto (ES5)
You can also use `.extend` on a service instance (extension is provided by [Uberproto](https://github.com/daffl/uberproto)):
```js
var myService = memory({
paginate: {
default: 2,
max: 4
}
}).extend({
create: function(data) {
data.created_at = new Date();
return this._super.apply(this, arguments);
}
});
app.configure(feathers.rest())
.use('/users', myUserService)
.listen(8080);
app.use('/todos', myService);
```
**Note:** _this is more for backwards compatibility. We recommend the usage of hooks as they are easier to test, easier to maintain and are more flexible._

@@ -97,4 +178,22 @@ ## Options

- `store` - An object with id to item assignments to pre-initialize the data store
- `paginate` - A pagination object containing a `default` and `max` page size (see below)
## Pagination
When initializing the service you can set the following pagination options in the `paginate` object:
- `default` - Sets the default number of items
- `max` - Sets the maximum allowed number of items per page (even if the `$limit` query parameter is set higher)
When `paginate.default` is set, `find` will return an object (instead of the normal array) in the following form:
```
{
"total": "<total number of records>",
"limit": "<max number of items per page>",
"skip": "<number of skipped items (offset)>",
"data": [/* data */]
}
```
## Query Parameters

@@ -106,5 +205,5 @@

// Find all recipes that include salt, limit to 10, only include name field.
{"ingredients":"salt", "$limit":10, "$select": { "name" :1 } } // JSON
{"ingredients":"salt", "$limit":10, "$select": ["name"] } } // JSON
GET /?ingredients=salt&$limit=10&$select[name]=1 // HTTP
GET /?ingredients=salt&$limit=10&$select[]=name // HTTP
```

@@ -158,3 +257,4 @@

`$select` support in a query allows you to pick which fields to include or exclude in the results. Note: you can use the include syntax or the exclude syntax, not both together. See the section on [`Projections`](https://github.com/louischatriot/nedb#projections) in the NeDB docs.
`$select` support in a query allows you to pick which fields to include or exclude in the results.
```

@@ -161,0 +261,0 @@ // Only retrieve name.

Sorry, the diff of this file is not supported yet

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