Rasmus Hansen
Rasmus Hansen

Reputation: 1573

How to create a mongoose schema from a class (function)

I would like to be able to define classes for mongoose instead of using the normal Schema and then defining functions for that. I have a class like such:

var odd = function() {
    this.name = String;
    this.someprop = {
        type: String,
        required: true
    }
}

this class then has some functions:

odd.prototype.cake = function() {
    return "This cake has the name \"" + this.name + "\".";
}

Normally in mongoose I have to define the last function after I have created my schema, but I loose my intellisense by doing that (More than it already is).

Is there a good way to make my class into a mongoose schema without too much hassle?

Upvotes: 2

Views: 2130

Answers (1)

Rasmus Hansen
Rasmus Hansen

Reputation: 1573

The best way I have been able to find is to create a helper function like this, which I have then put into a seperate file:

var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var helpers = require("./helpers");

/**
 * Dark wizardry function that creates a mongoose schema from a normal JS class
 * Objects can also be passed along, and any properties that has methods will be turned into methods on the mongoose Schema.
 * @param c The class to creare the schema from
 * @param options The additional options to pass to the schema creation
 * @returns {Schema} A new mongoose schema for the describing the given class
 */
module.exports = function(c, options) {
    var f = null;
    // Figure out if f is an object or a function, and take appropriate action
    if(helpers.isFunction(c)) {
        f = new c();
    } else if(typeof f === "object") {
        f = c;
    } else {
        throw new TypeError("Class schema cannot work with that type. Whatever it was you supplied, probably a simple type. ");
    }

    var prop;
    var o = {};
    // Save all the properties of f into a new object
    for(prop in f) {
        var p = f[prop];
        switch (p) {
            case String:
            case Number:
            case Date:
            case Buffer:
            case Boolean:
            case mongoose.Types.Mixed:
            case mongoose.Types.ObjectId:
            case Array:
                o[prop] = p;
                break;
            default:
                if(!helpers.isFunction(p)) {
                    o[prop] = p;
                }
        }
    }
    // Create the schema
    var sch = new Schema(o, options);
    // Create the methods for the schema
    for(prop in f) {
        if (prop in f) {
            var func = f[prop];
            switch (func) {
                case String:
                case Number:
                case Date:
                case Buffer:
                case Boolean:
                case mongoose.Types.Mixed:
                case mongoose.Types.ObjectId:
                case Array:
                    continue
            }
            if (helpers.isFunction(func)) {
                sch.methods[prop] = func;
            }
        }
    }
    return sch;
};

My helpers.js contains a very simple function for isFunction:

function isFunction(f) {
    return typeof f === "function";
}

exports.isFunction = isFunction;

Then whenever I want a mongoose schema I just do the following:

var mongoose = require("mongoose");
var classSchema = require("./class-schema");
var odd = function() {
   ...
}

odd.prototype.cake = function() {
   ...
}

var oddSchema = classSchema(odd, {timestamps: true});

module.exports = mongoose.model("Odd", oddSchema);

That will create a model with the same properties and the same functions as the original odd class.

Upvotes: 1

Related Questions