mattkrea/sequelize-handlers

View on GitHub
lib/children.js

Summary

Maintainability
A
3 hrs
Test Coverage
'use strict';

const { findOne, findAll, createRecord, updateRecord, deleteRecord } = require('./database');
const { buildWhere } = require('./querying');
const { HTTP_METHOD } = require('./constants');
const dasherize = require('dasherize');

/**
 * Configure the query to be used for SELECT calls
 *
 * @param   {Sequelize.Model} model - Sequelize parent data model
 * @param   {string}          association - Name of the child association
 * @param   {Express.Request} req - Express HTTP request
 * @param   {Object}          options - Controller configuration
 * @returns {Object} Returns configured query parameters
 */
const buildGet = (model, association, req, options) => {
    let query = buildWhere(HTTP_METHOD.GET, req, options);
    // Adjust the query to filter on the child
    query.where[model.associations[association].foreignKey] = req.params.parent;
    // Exclude relations since we will assume the caller already
    // knows the related (i.e. parent) models
    delete query.include;
    return query;
};

const createChildren = (router, model, opts) => {
    if (opts.createChildren !== true) {
        return;
    }

    for (const association of Object.keys(model.associations)) {
        // We're going to skip singular associations for now as well since
        // they don't provide much value e.g. /posts/1/author
        if (model.associations[association].isSingleAssociation === true) {
            continue;
        }

        // TODO: Support map tables
        if (typeof model.associations[association].through !== 'undefined') {
            continue;
        }

        // TODO: Add ability to override output name for children
        const options = Object.assign(opts, { overrideOutputName: null });

        const child = model.associations[association].target;

        if (options.handlers.get === true) {
            router.get(`/:parent/${dasherize(association)}/:id`, (req, res) => {
                const query = buildGet(model, association, req, options);
                return findOne(child, query, req, res, options);
            });

            router.get(`/:parent/${dasherize(association)}`, (req, res) => {
                const query = buildGet(model, association, req, options);
                return findAll(child, query, req, res, options);
            });
        }

        if (options.handlers.post === true) {
            router.post(`/:parent/${dasherize(association)}`, (req, res) => {
                let input = (options.disableNestedData === true ? req.body : req.body[child.name]);
                input[model.associations[association].foreignKey] = req.params.parent;
                const query = buildWhere(HTTP_METHOD.POST, req, options);
                return createRecord(child, query, input, req, res, options);
            });
        }

        if (options.handlers.put === true) {
            router.put(`/:parent/${dasherize(association)}/:id`, (req, res) => {
                const query = buildWhere(HTTP_METHOD.PUT, req, options);
                query.where[model.associations[association].foreignKey] = req.params.parent;
                const input = (options.disableNestedData === true ? req.body : req.body[child.name]);
                return updateRecord(child, query, input, req, res, options);
            });
        }

        if (options.handlers.delete === true) {
            router.delete(`/:parent/${dasherize(association)}/:id`, (req, res) => {
                const query = buildWhere(HTTP_METHOD.DELETE, req, options);
                query.where[model.associations[association].foreignKey] = req.params.parent;
                return deleteRecord(child, query, req, res);
            });
        }
    }
};

module.exports = createChildren;