feat(associations): many-to-many associations
fix(associations): fix association queries, must use `include` instead of ForeignKey fix(error): error decorator was missing await, which prevented it from catching errors fix(error): console.error the error refactor(crud): don't use `request.models[name]`, use the model directly chore: README added
This commit is contained in:
parent
bae6820e64
commit
52ad030d0d
74
README.md
Normal file
74
README.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
hapi-sequelize-crud
|
||||||
|
===================
|
||||||
|
|
||||||
|
Automatically generate a RESTful API for your models and associations
|
||||||
|
|
||||||
|
This plugin depends on [`hapi-sequelize`](https://github.com/danecando/hapi-sequelize).
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install -S hapi-sequelize-crud
|
||||||
|
```
|
||||||
|
|
||||||
|
##Configure
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// First, register hapi-sequelize
|
||||||
|
await register({
|
||||||
|
register: require('hapi-sequelize'),
|
||||||
|
options: { ... }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Then, define your associations
|
||||||
|
let db = server.plugins['hapi-sequelize'].db;
|
||||||
|
let models = db.sequelize.models;
|
||||||
|
associations(models); // pretend this function defines our associations
|
||||||
|
|
||||||
|
// Now, register hapi-sequelize-crud
|
||||||
|
await register({
|
||||||
|
register: require('hapi-sequelize-crud'),
|
||||||
|
options: {
|
||||||
|
prefix: '/v1'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that you should register `hapi-sequelize-crud` after defining your
|
||||||
|
associations.
|
||||||
|
|
||||||
|
##What do I get
|
||||||
|
|
||||||
|
Let's say you have a `many-to-many` association like this:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Team.belongsToMany(Role, { through: 'TeamRoles' });
|
||||||
|
Role.belongsToMany(Team, { through: 'TeamRoles' });
|
||||||
|
```
|
||||||
|
|
||||||
|
You get these:
|
||||||
|
|
||||||
|
```
|
||||||
|
# get an array of records
|
||||||
|
GET /team/{id}/roles
|
||||||
|
GET /role/{id}/teams
|
||||||
|
#might also append query parameters to search for
|
||||||
|
GET /role/{id}/teams?members=5
|
||||||
|
|
||||||
|
# get a single record
|
||||||
|
GET /team/{id}/role/{id}
|
||||||
|
GET /role/{id}/team/{id}
|
||||||
|
|
||||||
|
# create
|
||||||
|
POST /team/{id}/role
|
||||||
|
POST /role/{id}/team
|
||||||
|
|
||||||
|
# update
|
||||||
|
PUT /team/{id}/role/{id}
|
||||||
|
PUT /role/{id}/team/{id}
|
||||||
|
|
||||||
|
# delete
|
||||||
|
DELETE /team/{id}/roles #search and destroy
|
||||||
|
DELETE /role/{id}/teams?members=5
|
||||||
|
|
||||||
|
DELETE /team/{id}/role/{id}
|
||||||
|
DELETE /role/{id}/team/{id}
|
||||||
|
```
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hapi-sequelize-crud",
|
"name": "hapi-sequelize-crud",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"description": "Hapi plugin that automatically generates RESTful API for CRUD",
|
"description": "Hapi plugin that automatically generates RESTful API for CRUD",
|
||||||
"main": "build/index.js",
|
"main": "build/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -18,11 +18,17 @@ export const list = (server, a, b) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let list = await request.models[b.name].findAll({
|
let list = await b.findAll({
|
||||||
where: {
|
where: {
|
||||||
...request.query,
|
...request.query,
|
||||||
[a.name + 'Id']: request.params.aid
|
},
|
||||||
}
|
|
||||||
|
include: [{
|
||||||
|
model: a,
|
||||||
|
where: {
|
||||||
|
id: request.params.aid
|
||||||
|
}
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
reply(list);
|
reply(list);
|
||||||
@ -37,11 +43,17 @@ export const destroy = (server, a, b) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let list = await request.models[b.name].findAll({
|
let list = await b.findAll({
|
||||||
where: {
|
where: {
|
||||||
...request.query,
|
...request.query
|
||||||
[a.name + 'Id']: request.params.aid
|
},
|
||||||
}
|
|
||||||
|
include: [{
|
||||||
|
model: a,
|
||||||
|
where: {
|
||||||
|
id: request.params.aid
|
||||||
|
}
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
await* list.map(instance => instance.destroy());
|
await* list.map(instance => instance.destroy());
|
||||||
@ -58,11 +70,17 @@ export const update = (server, a, b) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let list = await request.models[b.name].findOne({
|
let list = await b.findOne({
|
||||||
where: {
|
where: {
|
||||||
...request.query,
|
...request.query
|
||||||
[a.name + 'Id']: request.params.aid
|
},
|
||||||
}
|
|
||||||
|
include: [{
|
||||||
|
model: a,
|
||||||
|
where: {
|
||||||
|
id: request.params.aid
|
||||||
|
}
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
await* list.map(instance => instance.update(request.payload));
|
await* list.map(instance => instance.update(request.payload));
|
||||||
|
@ -19,11 +19,17 @@ export const get = (server, a, b) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let instance = await request.models[b.name].findOne({
|
let instance = await b.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: request.params.bid,
|
id: request.params.bid
|
||||||
[a.name + 'Id']: request.params.aid
|
},
|
||||||
}
|
|
||||||
|
include: [{
|
||||||
|
model: a,
|
||||||
|
where: {
|
||||||
|
id: request.params.aid
|
||||||
|
}
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
reply(instance);
|
reply(instance);
|
||||||
@ -53,11 +59,17 @@ export const destroy = (server, a, b) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let instance = await request.models[b.name].findOne({
|
let instance = await b.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: request.params.bid,
|
id: request.params.bid
|
||||||
[a.name + 'Id']: request.params.aid
|
},
|
||||||
}
|
|
||||||
|
include: [{
|
||||||
|
model: a,
|
||||||
|
where: {
|
||||||
|
id: request.params.aid
|
||||||
|
}
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
await instance.destroy();
|
await instance.destroy();
|
||||||
@ -74,11 +86,17 @@ export const update = (server, a, b) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let instance = await request.models[b.name].findOne({
|
let instance = await b.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: request.params.bid,
|
id: request.params.bid
|
||||||
[a.name + 'Id']: request.params.aid
|
},
|
||||||
}
|
|
||||||
|
include: [{
|
||||||
|
model: a,
|
||||||
|
where: {
|
||||||
|
id: request.params.aid
|
||||||
|
}
|
||||||
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
await instance.update(request.payload);
|
await instance.update(request.payload);
|
||||||
|
13
src/crud.js
13
src/crud.js
@ -21,8 +21,7 @@ export const list = (server, model) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
console.log(request.models[model.name], request.query);
|
let list = await model.findAll({
|
||||||
let list = await request.models[model.name].findAll({
|
|
||||||
where: request.query
|
where: request.query
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ export const get = (server, model) => {
|
|||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let where = request.params.id ? { id : request.params.id } : request.query;
|
let where = request.params.id ? { id : request.params.id } : request.query;
|
||||||
|
|
||||||
let instance = await request.models[model.name].findOne({ where });
|
let instance = await model.findOne({ where });
|
||||||
|
|
||||||
reply(instance);
|
reply(instance);
|
||||||
},
|
},
|
||||||
@ -63,7 +62,7 @@ export const scope = (server, model) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let list = await request.models[model.name].scope(request.params.scope).findAll();
|
let list = await model.scope(request.params.scope).findAll();
|
||||||
|
|
||||||
reply(list);
|
reply(list);
|
||||||
},
|
},
|
||||||
@ -84,7 +83,7 @@ export const create = (server, model) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let instance = await request.models[model.name].create(request.payload);
|
let instance = await model.create(request.payload);
|
||||||
|
|
||||||
reply(instance);
|
reply(instance);
|
||||||
}
|
}
|
||||||
@ -100,7 +99,7 @@ export const destroy = (server, model) => {
|
|||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let where = request.params.id ? { id : request.params.id } : request.query;
|
let where = request.params.id ? { id : request.params.id } : request.query;
|
||||||
|
|
||||||
let list = await request.models[model.name].findAll({ where });
|
let list = await model.findAll({ where });
|
||||||
|
|
||||||
await* list.map(instance => instance.destroy());
|
await* list.map(instance => instance.destroy());
|
||||||
|
|
||||||
@ -116,7 +115,7 @@ export const update = (server, model) => {
|
|||||||
|
|
||||||
@error
|
@error
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let instance = await request.models[model.name].findOne({
|
let instance = await model.findOne({
|
||||||
where: {
|
where: {
|
||||||
id: request.params.id
|
id: request.params.id
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
export default (target, key, descriptor) => {
|
export default (target, key, descriptor) => {
|
||||||
let fn = descriptor.value;
|
let fn = descriptor.value;
|
||||||
|
|
||||||
descriptor.value = (request, reply) => {
|
descriptor.value = async (request, reply) => {
|
||||||
try {
|
try {
|
||||||
fn(request, reply);
|
await fn(request, reply);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
console.error(e);
|
||||||
reply(e);
|
reply(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
src/index.js
11
src/index.js
@ -37,16 +37,23 @@ const register = (server, options = {}, next) => {
|
|||||||
associations.oneToOne(server, target, source, options);
|
associations.oneToOne(server, target, source, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceType === 'BelongsTo' && (targetType === 'HasMany')) {
|
if (sourceType === 'BelongsTo' && targetType === 'HasMany') {
|
||||||
associations.oneToOne(server, source, target, options);
|
associations.oneToOne(server, source, target, options);
|
||||||
associations.oneToOne(server, target, source, options);
|
associations.oneToOne(server, target, source, options);
|
||||||
associations.oneToMany(server, target, source, options);
|
associations.oneToMany(server, target, source, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sourceType === 'BelongsToMany' && targetType === 'BelongsToMany') {
|
||||||
|
associations.oneToOne(server, source, target, options);
|
||||||
|
associations.oneToOne(server, target, source, options);
|
||||||
|
|
||||||
|
associations.oneToMany(server, source, target, options);
|
||||||
|
associations.oneToMany(server, target, source, options);
|
||||||
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// There might be conflicts in case of models associated with themselves and some other
|
// There might be conflicts in case of models associated with themselves and some other
|
||||||
// rare cases.
|
// rare cases.
|
||||||
}
|
}
|
||||||
console.log(sourceName.singular, sourceType, targetName.singular, ' & ', targetName.singular, targetType, sourceName.singular);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user