hapi-forest
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -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'); |
@@ -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)); |
@@ -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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
181107
29
717
169
5
1
+ Addedcall@^3.0.3
+ Addedcall@3.0.4(transitive)