Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
5f0273a973 | |||
3317e0a8f2 | |||
61fbf434af | |||
f71e06362b | |||
a5e6b2dd46 |
29
Gruntfile.js
Normal file
29
Gruntfile.js
Normal file
@ -0,0 +1,29 @@
|
||||
module.exports = function(grunt) {
|
||||
grunt.initConfig({
|
||||
babel: {
|
||||
scripts: {
|
||||
files: [{
|
||||
expand: true,
|
||||
cwd: 'src',
|
||||
src: '**/*.js',
|
||||
dest: 'build/'
|
||||
}]
|
||||
}
|
||||
},
|
||||
clean: {
|
||||
files: ['build/**/*.js']
|
||||
},
|
||||
watch: {
|
||||
scripts: {
|
||||
files: ['src/**/*.js', 'server/**/*.js'],
|
||||
tasks: ['babel']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-babel');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
grunt.registerTask('default', ['clean', 'babel']);
|
||||
};
|
25
README.md
25
README.md
@ -28,34 +28,11 @@ await register({
|
||||
register: require('hapi-sequelize-crud'),
|
||||
options: {
|
||||
prefix: '/v1',
|
||||
name: 'db', // the same name you used for configuring `hapi-sequelize` (options.name)
|
||||
defaultConfig: { ... }, // passed as `config` to all routes created
|
||||
models: ['cat', 'dog'] // only the cat and dog models will have routes created
|
||||
// or
|
||||
models: {
|
||||
// possible methods: list, get, scope, create, destroy, destroyAll, destroyScope, update
|
||||
cat: ['get', 'list'], // the cat model only has get and list methods enabled
|
||||
dog: true, // the dog model has all methods enabled
|
||||
bat: {
|
||||
methods: ['list'],
|
||||
config: { ... } // if provided, overrides the default config
|
||||
}
|
||||
}
|
||||
defaultConfig: { ... } // passed as `config` to all routes created
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Methods
|
||||
* list: get all rows in a table
|
||||
* get: get a single row
|
||||
* scope: reference a [sequelize scope](http://docs.sequelizejs.com/en/latest/api/model/#scopeoptions-model)
|
||||
* create: create a new row
|
||||
* destroy: delete a row
|
||||
* destroyAll: delete all models in the table
|
||||
* destroyScope: use a [sequelize scope](http://docs.sequelizejs.com/en/latest/api/model/#scopeoptions-model) to find rows, then delete them
|
||||
* update: update a row
|
||||
|
||||
|
||||
Please note that you should register `hapi-sequelize-crud` after defining your
|
||||
associations.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@getable/hapi-sequelize-crud",
|
||||
"version": "2.3.0",
|
||||
"version": "2.2.0",
|
||||
"description": "Hapi plugin that automatically generates RESTful API for CRUD",
|
||||
"main": "build/index.js",
|
||||
"config": {
|
||||
@ -30,7 +30,7 @@
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.10.3",
|
||||
"babel-preset-stage-1": "^6.5.0",
|
||||
"eslint": "2.10.2",
|
||||
"eslint-config-pichak": "1.1.0",
|
||||
"eslint-config-pichak": "1.0.1",
|
||||
"ghooks": "1.0.3",
|
||||
"scripty": "^1.6.0"
|
||||
},
|
||||
|
@ -14,15 +14,15 @@ export default (server, a, b, names, options) => {
|
||||
|
||||
@error
|
||||
async handler(request, reply) {
|
||||
const instanceb = await b.findOne({
|
||||
let instanceb = await b.findOne({
|
||||
where: {
|
||||
[b.primaryKeyField]: request.params.bid,
|
||||
id: request.params.bid,
|
||||
},
|
||||
});
|
||||
|
||||
const instancea = await a.findOne({
|
||||
let instancea = await a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -28,23 +28,18 @@ export const get = (server, a, b, names) => {
|
||||
async handler(request, reply) {
|
||||
const include = parseInclude(request);
|
||||
|
||||
const base = await a.findOne({
|
||||
const base = a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
|
||||
const method = getMethod(base, names.b);
|
||||
|
||||
const list = await method({ where: {
|
||||
[b.primaryKeyField]: request.params.bid,
|
||||
id: request.params.bid,
|
||||
}, include });
|
||||
|
||||
if (Array.isArray(list)) {
|
||||
reply(list[0]);
|
||||
} else {
|
||||
reply(list);
|
||||
}
|
||||
},
|
||||
|
||||
config: defaultConfig,
|
||||
@ -63,7 +58,7 @@ export const list = (server, a, b, names) => {
|
||||
|
||||
const base = await a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
|
||||
@ -78,7 +73,7 @@ export const list = (server, a, b, names) => {
|
||||
};
|
||||
|
||||
export const scope = (server, a, b, names) => {
|
||||
const scopes = Object.keys(b.options.scopes);
|
||||
let scopes = Object.keys(b.options.scopes);
|
||||
|
||||
server.route({
|
||||
method: 'GET',
|
||||
@ -91,7 +86,7 @@ export const scope = (server, a, b, names) => {
|
||||
|
||||
const base = await a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
|
||||
@ -117,7 +112,7 @@ export const scope = (server, a, b, names) => {
|
||||
};
|
||||
|
||||
export const scopeScope = (server, a, b, names) => {
|
||||
const scopes = {
|
||||
let scopes = {
|
||||
a: Object.keys(a.options.scopes),
|
||||
b: Object.keys(b.options.scopes),
|
||||
};
|
||||
@ -131,7 +126,7 @@ export const scopeScope = (server, a, b, names) => {
|
||||
const include = parseInclude(request);
|
||||
const where = parseWhere(request);
|
||||
|
||||
const list = await b.scope(request.params.scopeb).findAll({
|
||||
let list = await b.scope(request.params.scopeb).findAll({
|
||||
where,
|
||||
include: include.concat({
|
||||
model: a.scope(request.params.scopea),
|
||||
@ -164,7 +159,7 @@ export const destroy = (server, a, b, names) => {
|
||||
|
||||
const base = await a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
|
||||
@ -180,7 +175,7 @@ export const destroy = (server, a, b, names) => {
|
||||
};
|
||||
|
||||
export const destroyScope = (server, a, b, names) => {
|
||||
const scopes = Object.keys(b.options.scopes);
|
||||
let scopes = Object.keys(b.options.scopes);
|
||||
|
||||
server.route({
|
||||
method: 'DELETE',
|
||||
@ -193,7 +188,7 @@ export const destroyScope = (server, a, b, names) => {
|
||||
|
||||
const base = await a.findOne({
|
||||
where: {
|
||||
[a.primarykeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
|
||||
@ -233,7 +228,7 @@ export const update = (server, a, b, names) => {
|
||||
|
||||
const base = await a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -26,7 +26,7 @@ export const get = (server, a, b, names) => {
|
||||
|
||||
const base = await a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
const method = getMethod(base, names.b, false);
|
||||
@ -53,7 +53,7 @@ export const create = (server, a, b, names) => {
|
||||
async handler(request, reply) {
|
||||
const base = await a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.id,
|
||||
id: request.params.id,
|
||||
},
|
||||
});
|
||||
|
||||
@ -79,12 +79,10 @@ export const destroy = (server, a, b, names) => {
|
||||
|
||||
const base = await a.findOne({
|
||||
where: {
|
||||
[a.primaryKeyField]: request.params.aid,
|
||||
id: request.params.aid,
|
||||
},
|
||||
});
|
||||
|
||||
where[b.primaryKeyField] = request.params.bid;
|
||||
|
||||
const method = getMethod(base, names.b, false, 'get');
|
||||
const instance = await method({ where, include });
|
||||
await instance.destroy();
|
||||
@ -112,8 +110,6 @@ export const update = (server, a, b, names) => {
|
||||
},
|
||||
});
|
||||
|
||||
where[b.primaryKeyField] = request.params.bid;
|
||||
|
||||
const method = getMethod(base, names.b, false);
|
||||
|
||||
const instance = await method({ where, include });
|
||||
|
118
src/crud.js
118
src/crud.js
@ -4,66 +4,24 @@ import _ from 'lodash';
|
||||
import { parseInclude, parseWhere } from './utils';
|
||||
import { notFound } from 'boom';
|
||||
|
||||
const createAll = ({server, model, prefix, config}) => {
|
||||
Object.keys(methods).forEach((method) => {
|
||||
methods[method]({server, model, prefix, config});
|
||||
});
|
||||
let prefix;
|
||||
let defaultConfig;
|
||||
|
||||
export default (server, model, options) => {
|
||||
prefix = options.prefix;
|
||||
defaultConfig = options.defaultConfig;
|
||||
|
||||
list(server, model);
|
||||
get(server, model);
|
||||
scope(server, model);
|
||||
create(server, model);
|
||||
destroy(server, model);
|
||||
destroyAll(server, model);
|
||||
destroyScope(server, model);
|
||||
update(server, model);
|
||||
};
|
||||
|
||||
/*
|
||||
The `models` option, becomes `permissions`, and can look like:
|
||||
|
||||
```
|
||||
models: ['cat', 'dog']
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
models: {
|
||||
cat: ['list', 'get']
|
||||
, dog: true // all
|
||||
}
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
export default (server, model, {prefix, defaultConfig: config, models: permissions}) => {
|
||||
const modelName = model._singular;
|
||||
|
||||
if (!permissions) {
|
||||
createAll({server, model, prefix, config});
|
||||
}
|
||||
else if (Array.isArray(permissions) && permissions.includes(modelName)) {
|
||||
createAll({server, model, prefix, config});
|
||||
}
|
||||
else if (_.isPlainObject(permissions)) {
|
||||
const permittedModels = Object.keys(permissions);
|
||||
|
||||
if (permissions[modelName] === true) {
|
||||
createAll({server, model, prefix, config});
|
||||
}
|
||||
else if (permittedModels.includes(modelName)) {
|
||||
if (Array.isArray(permissions[modelName])) {
|
||||
permissions[modelName].forEach((method) => {
|
||||
methods[method]({server, model, prefix, config});
|
||||
});
|
||||
}
|
||||
else if (_.isPlainObject(permissions[modelName])) {
|
||||
permissions[modelName].methods.forEach((method) => {
|
||||
methods[method]({
|
||||
server,
|
||||
model,
|
||||
prefix,
|
||||
config: permissions[modelName].config || config,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const list = ({server, model, prefix, config}) => {
|
||||
export const list = (server, model) => {
|
||||
server.route({
|
||||
method: 'GET',
|
||||
path: `${prefix}/${model._plural}`,
|
||||
@ -82,11 +40,11 @@ export const list = ({server, model, prefix, config}) => {
|
||||
reply(list);
|
||||
},
|
||||
|
||||
config,
|
||||
config: defaultConfig,
|
||||
});
|
||||
};
|
||||
|
||||
export const get = ({server, model, prefix, config}) => {
|
||||
export const get = (server, model) => {
|
||||
server.route({
|
||||
method: 'GET',
|
||||
path: `${prefix}/${model._singular}/{id?}`,
|
||||
@ -96,7 +54,7 @@ export const get = ({server, model, prefix, config}) => {
|
||||
const include = parseInclude(request);
|
||||
const where = parseWhere(request);
|
||||
const {id} = request.params;
|
||||
if (id) where[model.primaryKeyField] = id;
|
||||
if (id) where.id = id;
|
||||
|
||||
const instance = await model.findOne({ where, include });
|
||||
|
||||
@ -110,12 +68,12 @@ export const get = ({server, model, prefix, config}) => {
|
||||
id: joi.any(),
|
||||
}),
|
||||
},
|
||||
}, config),
|
||||
}, defaultConfig),
|
||||
});
|
||||
};
|
||||
|
||||
export const scope = ({server, model, prefix, config}) => {
|
||||
const scopes = Object.keys(model.options.scopes);
|
||||
export const scope = (server, model) => {
|
||||
let scopes = Object.keys(model.options.scopes);
|
||||
|
||||
server.route({
|
||||
method: 'GET',
|
||||
@ -136,11 +94,11 @@ export const scope = ({server, model, prefix, config}) => {
|
||||
scope: joi.string().valid(...scopes),
|
||||
}),
|
||||
},
|
||||
}, config),
|
||||
}, defaultConfig),
|
||||
});
|
||||
};
|
||||
|
||||
export const create = ({server, model, prefix, config}) => {
|
||||
export const create = (server, model) => {
|
||||
server.route({
|
||||
method: 'POST',
|
||||
path: `${prefix}/${model._singular}`,
|
||||
@ -152,11 +110,11 @@ export const create = ({server, model, prefix, config}) => {
|
||||
reply(instance);
|
||||
},
|
||||
|
||||
config,
|
||||
config: defaultConfig,
|
||||
});
|
||||
};
|
||||
|
||||
export const destroy = ({server, model, prefix, config}) => {
|
||||
export const destroy = (server, model) => {
|
||||
server.route({
|
||||
method: 'DELETE',
|
||||
path: `${prefix}/${model._singular}/{id?}`,
|
||||
@ -164,7 +122,7 @@ export const destroy = ({server, model, prefix, config}) => {
|
||||
@error
|
||||
async handler(request, reply) {
|
||||
const where = parseWhere(request);
|
||||
if (request.params.id) where[model.primaryKeyField] = request.params.id;
|
||||
if (request.params.id) where.id = request.params.id;
|
||||
|
||||
const list = await model.findAll({ where });
|
||||
|
||||
@ -173,11 +131,11 @@ export const destroy = ({server, model, prefix, config}) => {
|
||||
reply(list.length === 1 ? list[0] : list);
|
||||
},
|
||||
|
||||
config,
|
||||
config: defaultConfig,
|
||||
});
|
||||
};
|
||||
|
||||
export const destroyAll = ({server, model, prefix, config}) => {
|
||||
export const destroyAll = (server, model) => {
|
||||
server.route({
|
||||
method: 'DELETE',
|
||||
path: `${prefix}/${model._plural}`,
|
||||
@ -193,12 +151,12 @@ export const destroyAll = ({server, model, prefix, config}) => {
|
||||
reply(list.length === 1 ? list[0] : list);
|
||||
},
|
||||
|
||||
config,
|
||||
config: defaultConfig,
|
||||
});
|
||||
};
|
||||
|
||||
export const destroyScope = ({server, model, prefix, config}) => {
|
||||
const scopes = Object.keys(model.options.scopes);
|
||||
export const destroyScope = (server, model) => {
|
||||
let scopes = Object.keys(model.options.scopes);
|
||||
|
||||
server.route({
|
||||
method: 'DELETE',
|
||||
@ -209,7 +167,7 @@ export const destroyScope = ({server, model, prefix, config}) => {
|
||||
const include = parseInclude(request);
|
||||
const where = parseWhere(request);
|
||||
|
||||
const list = await model.scope(request.params.scope).findAll({ include, where });
|
||||
let list = await model.scope(request.params.scope).findAll({ include, where });
|
||||
|
||||
await Promise.all(list.map(instance => instance.destroy()));
|
||||
|
||||
@ -221,11 +179,11 @@ export const destroyScope = ({server, model, prefix, config}) => {
|
||||
scope: joi.string().valid(...scopes),
|
||||
}),
|
||||
},
|
||||
}, config),
|
||||
}, defaultConfig),
|
||||
});
|
||||
};
|
||||
|
||||
export const update = ({server, model, prefix, config}) => {
|
||||
export const update = (server, model) => {
|
||||
server.route({
|
||||
method: 'PUT',
|
||||
path: `${prefix}/${model._singular}/{id}`,
|
||||
@ -250,13 +208,9 @@ export const update = ({server, model, prefix, config}) => {
|
||||
validate: {
|
||||
payload: joi.object().required(),
|
||||
},
|
||||
}, config),
|
||||
}, defaultConfig),
|
||||
});
|
||||
};
|
||||
|
||||
import * as associations from './associations/index';
|
||||
export { associations };
|
||||
|
||||
const methods = {
|
||||
list, get, scope, create, destroy, destroyAll, destroyScope, update,
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
export default (target, key, descriptor) => {
|
||||
const fn = descriptor.value;
|
||||
let fn = descriptor.value;
|
||||
|
||||
descriptor.value = async (request, reply) => {
|
||||
try {
|
||||
|
24
src/index.js
24
src/index.js
@ -8,10 +8,9 @@ import qs from 'qs';
|
||||
|
||||
const register = (server, options = {}, next) => {
|
||||
options.prefix = options.prefix || '';
|
||||
options.name = options.name || 'db';
|
||||
|
||||
const db = server.plugins['hapi-sequelize'][options.name];
|
||||
const models = db.sequelize.models;
|
||||
let db = server.plugins['hapi-sequelize'].db;
|
||||
let models = db.sequelize.models;
|
||||
|
||||
const onRequest = function (request, reply) {
|
||||
const uri = request.raw.req.url;
|
||||
@ -27,9 +26,9 @@ const register = (server, options = {}, next) => {
|
||||
method: onRequest,
|
||||
});
|
||||
|
||||
for (const modelName of Object.keys(models)) {
|
||||
const model = models[modelName];
|
||||
const { plural, singular } = model.options.name;
|
||||
for (let modelName of Object.keys(models)) {
|
||||
let model = models[modelName];
|
||||
let { plural, singular } = model.options.name;
|
||||
model._plural = plural.toLowerCase();
|
||||
model._singular = singular.toLowerCase();
|
||||
|
||||
@ -38,11 +37,11 @@ const register = (server, options = {}, next) => {
|
||||
|
||||
crud(server, model, options);
|
||||
|
||||
for (const key of Object.keys(model.associations)) {
|
||||
const association = model.associations[key];
|
||||
const { source, target } = association;
|
||||
for (let key of Object.keys(model.associations)) {
|
||||
let association = model.associations[key];
|
||||
let { source, target } = association;
|
||||
|
||||
const sourceName = source.options.name;
|
||||
let sourceName = source.options.name;
|
||||
|
||||
const names = (rev) => {
|
||||
const arr = [{
|
||||
@ -58,9 +57,8 @@ const register = (server, options = {}, next) => {
|
||||
return rev ? { b: arr[0], a: arr[1] } : { a: arr[0], b: arr[1] };
|
||||
};
|
||||
|
||||
const targetAssociations = target.associations[sourceName.plural]
|
||||
|| target.associations[sourceName.singular];
|
||||
const sourceType = association.associationType,
|
||||
let targetAssociations = target.associations[sourceName.plural] || target.associations[sourceName.singular];
|
||||
let sourceType = association.associationType,
|
||||
targetType = (targetAssociations || {}).associationType;
|
||||
|
||||
try {
|
||||
|
10
src/utils.js
10
src/utils.js
@ -5,14 +5,16 @@ export const parseInclude = request => {
|
||||
: [request.query.include];
|
||||
|
||||
const noGetDb = typeof request.getDb !== 'function';
|
||||
const noRequestModels = !request.models;
|
||||
const noRequestModels = request.models;
|
||||
|
||||
if (noGetDb && noRequestModels) {
|
||||
return new Error('`request.getDb` or `request.models` are not defined.'
|
||||
+ 'Be sure to load hapi-sequelize before hapi-sequelize-crud.');
|
||||
return new Error('`request.getDb` or `request.models` are not defined. Be sure to load hapi-sequelize before hapi-sequelize-crud.');
|
||||
}
|
||||
|
||||
const { models } = noGetDb ? request : request.getDb();
|
||||
const {models} = !noGetDb
|
||||
? request.getDb()
|
||||
: request
|
||||
;
|
||||
|
||||
return include.map(a => {
|
||||
if (typeof a === 'string') return models[a];
|
||||
|
Reference in New Issue
Block a user