Uncategorized

Automating Ext Model Creation from Sequelize Model Definitions

In one of the applications I’m building I’m using Node.js, Express, Sequelize and Ext. All are fantastic tools but not necessarily meant to work together in perfect harmony (specifically Sequelize and Ext.)

Because I’m lazy I wanted my Node.js application to provide some standard boilerplate code for me; rather than writing it out myself long-hand. Once such case is in the Ext.data.Model definitions required for the client-side of the application.

Models are subject to change, a lot, and so it’s actually kind of not a stupid idea to have as much of the low-hanging fruit “just taken care of” as possible. This keeps your front-end application in sync with your backend and you could easily extend this to produce static files if you wanted to reduce processing overhead (although it’s not going to be much anyway.)

The way that Ext autoloads model classes for your application is pretty simple and it’s easy to hack once you know that it will convert:

MyApp.model.User

Into something like (a web request for):

http://server.com/app/model/User.js

From here, using an Express router (I stuck mine in the routes/index.js file of a default Express bundle, something like:

var router = require("express").router;

router.route("/app/model/:modelname")
    .get(
        function (req, res) {
            "use strict";
            var modelName = req.params.modelname.replace(/.js/, "");
            res.send(router.app.tools.buildExtModel(modelName));
        }
    );

router.init = function (_app) {
    router.app = _app;
}

module.exports = router;

The above takes the url from the Ext loader, drops the .js bit and then calls a subordinate function which actually builds up the model definition from the Sequelize class. *These functions are buried in a “tools” class that’s global to the application.

Produce an Ext.data.Model Def.

buildExtModel:
    function (forModelString) {
        var model = tools.app.db[forModelString],
            fieldDefs = tools.clientCompatibleFieldDefs(model),
            output = "";

        output += "Ext.define("MyApp.model." + forModelString + "",n";
        output += JSON.stringify(
            {
                "extend": "Ext.data.Model",
                "fields": fieldDefs
            }
        ) + "n";
        output += (");");

        return output;
    },

Build a List of Fields

This builds a field list that is compatible with Ext. Sadly our naming convention probably won’t support additional platforms but goddamn if I’m gonna write all this boilerplate by hand! You could conceivably implement support for any kind of output model definition, Objective-C classes, Java classes, etc.

clientCompatibleFieldDefs:
    function (model) {
        var fieldDefs = [{"name": "id", "type": "int"}],
            fieldKey,
            field,
            fieldType;

        for (fieldKey in model.rawAttributes) {
            if (model.rawAttributes.hasOwnProperty(fieldKey)) {
                if (fieldKey !== "id") {
                    field = model.rawAttributes[fieldKey];
                    fieldDefs.push(
                        {
                            "name": fieldKey,
                            "type": tools.sequelizeToExtFieldType(field)
                        }
                    );
                }
            }
        }

        return fieldDefs;
    },

Convert Field Types

This converts between Sequelize and Ext.data.Model field formats. If a field type is not represented it (the type) will not be included in the output and Ext will infer a type of “string” for safety. You could build this up to support whatever other field types your specific instance employs.

Of note here, Sequelize doesn’t define all models the same. Sometimes field types are objects, sometimes they are functions and other times they are just strings. In my particular case I’m only handling the “private” _typeName and the string form of “type.”

sequelizeToExtFieldType:
    function (field) {
        var fieldType,
            fieldMatch = {
                "INTEGER": "int",
                "STRING": "string",
                "VARCHAR": "string",
                "DATETIME": "date"
            };

        if (field.hasOwnProperty("_typeName")) {
            fieldType = fieldMatch[field._typeName];
        } else if (field.hasOwnProperty("type") &&
            typeof(field.type) === "string") {
            fieldType = fieldMatch[field.type];
        }

        return fieldType;
    }

What Next?

After I built this it occurred to me that it would be much better to use text-based templates (like Mustache or Jade) to build up the output. I started looking at using Jade but unfortunately it trends heavily toward making HTML output which you just end up fighting with. Mustache would probably work if you could iterate easily and likely I’ll move in that direction when I have more time. Right now I supply both my Ext.data.Model and Ext.data.Store class definitions using this pattern. Hope you find it useful, let me know.

Leave a Reply

Powered by: Wordpress