New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

hapi-forest

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hapi-forest - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

test/get-one-handler-test.js

11

forest.js

@@ -6,2 +6,4 @@ 'use strict';

const stubJoi = require('./lib/stub-joi');
const call = new require('call');
const router = new call.Router();

@@ -12,2 +14,3 @@ module.exports = (server, opts, next) => {

model: joi.func().required(),
preQuery: joi.func().maxArity(1),
type: joi.string().allow([

@@ -31,2 +34,9 @@ 'getOne', 'getAll', 'post', 'put', 'patch', 'delete'

const analyzed = router.analyze(route.path);
// set idKey to first param if not set
if (analyzed.params[0] && options.idKey === undefined) {
if (analyzed.params[0] === 'id') options.idKey = '_id';
else options.idKey = analyzed.params[0];
}
if (route.method === 'get') {

@@ -44,2 +54,3 @@ if (/.*\/\?$/.test(route.fingerprint) === true) {

}
const oSchema = hoek.applyToDefaults(defaultSchema, handler.validOptions || {});

@@ -46,0 +57,0 @@ options = joi.attempt(options, oSchema, 'invalid options');

5

handlers/delete.js

@@ -11,4 +11,5 @@ 'use strict';

const q = hu.getIdQuery(options, req);
Model.remove(q, (err, mod) => {
const query = hu.getIdQuery(options, req);
if (options.preQuery) options.preSend(query); // query extension point
Model.remove(query, (err, mod) => {

@@ -15,0 +16,0 @@ if (err) return reply(boom.badImplementation(err));

7

handlers/getAll.js

@@ -13,6 +13,7 @@ 'use strict';

const filter = options.filterByQuery ? req.query : {};
const readQuery = Model.find(filter).lean();
if (options.select) readQuery.select(options.select);
const query = Model.find(filter).lean();
if (options.select) query.select(options.select);
if (options.preQuery) options.preSend(query); // query extension point
const readStream = readQuery.cursor().pipe(jsonStream.stringify());
const readStream = query.cursor().pipe(jsonStream.stringify());
const stream2 = new stream.Readable().wrap(readStream);

@@ -19,0 +20,0 @@

@@ -13,7 +13,10 @@ 'use strict';

const q = hu.getIdQuery(options, req);
const query = Model.findOne(q);
const query = Model.findOne(q).lean();
if (options.select) query.select(options.select);
if (options.preQuery) options.preSend(query); // query extension point
query.exec((err, mod) => {
if (err) return reply(boom.badImplementation(err));
if (mod === null) return reply(boom.notFound(`${Model.modelName} not found`));
return reply(mod);

@@ -20,0 +23,0 @@ });

@@ -11,4 +11,5 @@ 'use strict';

const q = hu.getIdQuery(options, req);
Model.update(q, req.payload, (err, mod) => {
const query = hu.getIdQuery(options, req);
if (options.preQuery) options.preSend(query); // query extension point
Model.update(query, req.payload, (err, mod) => {

@@ -15,0 +16,0 @@ if (err) return reply(boom.badImplementation(err));

@@ -10,8 +10,8 @@ 'use strict';

Model.create(req.payload, (err, item) => {
const model = Model.create(req.payload);
if (options.preQuery) options.preSend(model); // query extension point
if (err) return hu.handleError(err, reply);
return reply(item).code(201);
});
model.then(item => reply(item).code(201))
.catch(err => hu.handleError(err, reply));
};
};

@@ -11,7 +11,9 @@ 'use strict';

const q = hu.getIdQuery(options, req);
const condition = hu.getIdQuery(options, req);
req.payload[options.idKey] = hu.getId(options, req);
Model.update(q, req.payload, {
const query = Model.update(condition, req.payload, {
upsert: options.allowUpsert
}, (err, mod) => {
});
if (options.preQuery) options.preSend(query); // query extension point
query.exec((err, mod) => {

@@ -18,0 +20,0 @@ if (err) return hu.handleError(err, reply);

{
"name": "hapi-forest",
"version": "0.2.0",
"version": "0.3.0",
"description": "A hapi plugin to generate routes based on mongoose models",

@@ -37,2 +37,3 @@ "main": "forest.js",

"boom": "^4.0.0",
"call": "^3.0.3",
"joi": "^9.0.4",

@@ -39,0 +40,0 @@ "lodash": "^4.15.0"

@@ -17,3 +17,3 @@ hapi-forest

* [ ] A lot more test coverage
* [ ] More ways to customize the generated queries.
* [x] More ways to customize the generated queries.

@@ -58,5 +58,18 @@ ## Quickstart

You can also overwrite the behaviour by setting the `type` option.
The `model` option is always required.
#### URL parameter
For routes like `GET /collection/{name}`, the first URL parameter (`name` in this case)
is used as the "id". It will be used in the condition of the mongoose query.
`{id}` will translate to `_id` for convenience.
#### Generic Options for all methods
Option | Description
:--------- | :--------------------------------------------------------------------------------------
`model` | **required** – The mongoose Model for this route.
`type` | Overwrites the auto selected handler. Can be one of `getOne, getAll, post, put, delete`
`preQuery` | A `Function` that gets passed the current mongoose query, that was generated by forest.
### `getOne`

@@ -67,4 +80,3 @@

* Only custom fields can be selected using `select`.
* you can select a custom property `idKey` to be used for lookup instead of
`_id`. The path key should be the same name.
* the first parameter in the path (`name` in this example) will be used to query

@@ -74,7 +86,6 @@ ```JavaScript

method: 'GET',
path: '/users/{name}', // {name} should be the same as the idKey
path: '/users/{name}',
handler: {
forest: {
model: User,
idKey: 'name', // custom mongoose field to use as the id
}

@@ -131,4 +142,2 @@ }

* you can disallow creating new documents with `allowUpsert: false`. PUT will behave like PATCH in that case.
* you can specify an `idKey`.
In that case the `_id` field will be autogenerated and not set by the user.

@@ -143,3 +152,2 @@ ```JavaScript

allowUpsert: true,
idKey: 'name',
}

@@ -154,3 +162,3 @@ }

* you can specify an `idKey` that will be used for lookup instead of `_id`.
* the first parameter in the path (`name` in this example) will be used to query

@@ -164,3 +172,2 @@ ```JavaScript

model: User,
idKey: 'name',
}

@@ -167,0 +174,0 @@ }

@@ -15,3 +15,3 @@ const test = require('ava');

test.cb('registerand bootstrap', (t) => {
test.cb('register and bootstrap', (t) => {
const server = new hapi.Server();

@@ -23,4 +23,3 @@ server.connection({ host: 'localhost' }); // will never be used

bootstrap: [
require('../example/models/cat-model'),
require('../example/models/user-model'),
require('./fixtures/test-cat-model'),
]

@@ -27,0 +26,0 @@ }

@@ -12,3 +12,4 @@ const mongoose = require('mongoose');

weight: { type: Number },
}
},
fromTest: String,
}, {

@@ -15,0 +16,0 @@ timestamps: true

const test = require('ava');
const hapi = require('hapi');
// TODO: separate connection for each test

@@ -7,44 +6,32 @@ const mongoose = require('mongoose');

mongoose.connect('localhost');
const createServer = require('./helpers/createServer.js');
const CatModel = require('./fixtures/test-cat-model');
test.beforeEach.cb(t => {
const server = new hapi.Server();
server.connection({ port: 9999 }); // never started
server.register({
register: require('../forest'),
}, e => {
t.true(e === undefined, 'no error');
server.route({
method: 'POST',
path: '/testCats1',
handler: {
forest: { model: CatModel }
},
config: {
validate: {
payload: server.plugins['hapi-forest'].stubJoi(CatModel),
}
test.beforeEach(async t => {
await t.notThrows(t.notThrows(CatModel.remove({ fromTest: 'post' })));
const server = await createServer(t);
server.route({
method: 'POST',
path: '/testCats1',
handler: {
forest: { model: CatModel }
},
config: {
validate: {
payload: server.plugins['hapi-forest'].stubJoi(CatModel),
}
});
t.context.server = server;
t.context.send = (payload) => {
return server.inject({
method: 'POST',
url: '/testCats1',
payload,
})
};
t.end();
}
});
t.pass();
});
test('respond with 400 for invalid payload', async t => {
const send = t.context.send;
const a = await send('');
const create = t.context.create;
const a = await create('');
t.true(a.statusCode === 400, 'empty payload');
const b = await send({});
const b = await create({});
t.true(b.statusCode === 400, 'empty object');
const c = await send({ wrong: 1 });
const c = await create({ wrong: 1 });
t.true(c.statusCode === 400, 'wrong attributes');
const d = await send({ born: 'wrong type' });
const d = await create({ born: 'wrong type' });
t.true(d.statusCode === 400, 'wrong type');

@@ -56,5 +43,6 @@

test('create a new database entry', async t => {
const send = t.context.send;
const res = await send({
const create = t.context.create;
const res = await create({
name: 'PostCat1',
fromTest: 'post',
});

@@ -71,12 +59,14 @@

test('do not allow duplicate entries', async t => {
const send = t.context.send;
const res = await send({
const create = t.context.create;
const res = await create({
name: 'testCat2',
meta: { age: 1 },
fromTest: 'post',
});
t.is(res.statusCode, 201, 'Status code is 201 for first POST');
const res2 = await send({
const res2 = await create({
name: 'testCat2',
meta: { age: 2 },
fromTest: 'post',
});

@@ -92,5 +82,1 @@ t.is(res2.statusCode, 409, 'Status code is 409 (conflict) for second POST');

});
test.after.always(t => {
return t.notThrows(CatModel.remove({}));
});

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