RouteInjector/route-injector

View on GitHub
lib/mongoose-plugins/mongoose-jsonform/lib/mongoose-jsonform.js

Summary

Maintainability
D
2 days
Test Coverage
/*!
 * mongoose-jsonform - lib/mongoose-jsonform.js
 * Copyright(c) 2013 jussiva <jussiva@gmail.com>
 * MIT Licensed
 */
/**
 * Module dependencies.
 */
var _ = require('lodash');
var changeCase = require('change-case');

var jsonform = function (schema, options) {

    var shardKey = undefined;
    if (schema.statics.injector) {
        var injector = schema.statics.injector();
        shardKey = (injector.shard && injector.shard.shardKey) ? injector.shard.shardKey : undefined;
    }

    if (!options) options = {excludedPaths: [], includedPaths: false};
    if (!Array.isArray(options.excludedPaths)) {
        options.excludedPaths = ['__v', options.excludedPaths];
    }
    function getType(pathString, mongotype) {
        switch (mongotype) {
            case('String'):
            case('SchemaString'):
                return {type: 'string'};
            case('SchemaDate'):
                return {type: 'string', format: 'date'};
            case('SchemaBoolean'):
                return {type: 'boolean'};
            case('SchemaNumber'):
                return {type: 'number'};
            case('ObjectId'):
                return {type: 'string'};
            case('ObjectID'):
                return {type: 'string'};
            case('DocumentArray'):
                return {type: 'array', items: {type: 'object', properties: {}}};
            case('SchemaArray'):
                return {type: 'array', items: {}};
            case('Mixed'):
                return {type: 'object', mixed: true};
            case('Image'):
                return {type: 'image'};
            case ('Gallery'):
                return {type: 'gallery'};
            case ('GeoJSON'):
            case ('Point'):
            case ('MultiPoint'):
            case ('LineString'):
            case ('MultiLineString'):
            case ('Polygon'):
            case ('MultiPolygon'):
            case ('Geometry'):
            case ('GeometryCollection'):
            case ('Feature'):
            case ('FeatureCollection'):
                return {type: 'geojson', format: mongotype.toLowerCase()};
            default:
                return {type: pathString.constructor.name.toLowerCase(), format: 'mixed'};
        }
    }

    function convertTypeOptions(type, options) {
        function replace(obj, key, newKey) {
            if (obj[key]) {
                obj[newKey] = obj[key];
                delete obj[key];
            }
        }

        switch (type) {
            case('number'):
                replace(options, 'min', 'minimum');
                replace(options, 'max', 'maximum');
                break;
            default:
                break;
        }
        return options;
    }

    function addCustomOptions(pathO) {
        if (shardKey === pathO.path) {
            pathO.options.required = true;
            pathO.options.editOnCreate = true;
        }

        // if (pathO.options.format === 'image') {
        //     pathO.options.path = (pathO.arraypath || pathO.path).split('.image')[0].replace('.', '/');
        // }
        // if (pathO.options.format === 'file') {
        //     pathO.options.path = (pathO.arraypath || pathO.path).split('.file')[0].replace('.', '/');
        // }
    }

    /**
     * jsonform.
     */
    schema.methods.jsonform = function (opt) {
        var self = this;
        var jf = {};
        if (!opt) opt = {excluded: [], includes: '*', setDefaults: false};
        if (!opt.includes) opt.includes = '*';

        var excludedPaths = _.union(options.excludedPaths, opt.excludes);
        var includedPaths = _.union(options.includedPaths, opt.includes);


        // TODO: Optionally supply fullPath arrgument to know the fullpath if it's inside an object or an array
        function parseSchema(subschema, out, fullPath) {
            subschema.eachPath(function (pathString, pathO) {

                var include = excludedPaths.indexOf(pathString) === -1;
                if (include && opt.includes != '*')
                    include = includedPaths.indexOf(pathString) !== -1;

                if (include) {
                    var type = getType(pathString, pathO.constructor.name);
                    var defaultValue = false;
                    //if( self.isInit(pathString) )
                    defaultValue = self.get(pathString);

                    function iterate(path, obj) {
                        if (matches = path.match(/([^.]+)\.(.*)/)) {
                            var key = matches[1];
                            if (!obj[key]) {
                                // Humanize object title
                                var sentenceCased = changeCase.sentenceCase(key);
                                var titleCased = changeCase.titleCase(sentenceCased);
                                obj[key] = {type: 'object', title: titleCased, properties: {}}
                            }
                            iterate(matches[2], obj[key].properties);
                        } else {
                            if (['string', 'date', 'boolean', 'number', 'object', 'image', 'gallery', 'geojson'].indexOf(type.type) >= 0) {
                                obj[path] = {};
                                if (_.isFunction(pathO.options.default)) {
                                    type.default = pathO.options.default();
                                }
                                if (defaultValue && opt.setDefaults) {
                                    pathO.options.default = defaultValue;
                                    if (type.type == 'date') {
                                        pathO.options.default = pathO.options.default.toISOString();
                                    }
                                }
                                // TODO: Check if fullpath is undefined. If it is, attach it to options
                                if (fullPath) {
                                    pathO.arraypath = fullPath + '.' + pathString;
                                }
                                addCustomOptions(pathO);
                                _.extend(obj[path], convertTypeOptions(type.type, pathO.options), type);
                            } else if (type.type == 'array') {
                                obj[path] = type;
                                // Humanize array title
                                var sentenceCased = changeCase.sentenceCase(path);
                                var titleCased = changeCase.titleCase(sentenceCased);
                                obj[path].title = titleCased;
                                if (type.items.type == 'object') {
                                    // TODO: Pass to the the parseSchema the current path
                                    parseSchema(pathO.schema, obj[path].items.properties, pathO.path);
                                } else {
                                    type = getType(pathString, pathO.caster.instance);

                                    if (_.isFunction(pathO.options.default)) {
                                        type.default = pathO.options.default();
                                    }
                                    if (defaultValue && opt.setDefaults) {
                                        pathO.options.default = defaultValue;
                                        if (type.type == 'date') {
                                            pathO.options.default = pathO.options.default.toISOString();
                                        }
                                    }
                                    _.extend(obj[path].items, convertTypeOptions(type.type, pathO.options.type[0]), type);

                                }
                            } else {
                                console.log('unsupported type: ' + type.type);
                            }
                        }
                    }

                    iterate(pathString, out);
                }
            });
        }

        parseSchema(schema, jf);
        return jf;
    }
};
module.exports = exports = jsonform;