Skip to content
/ VeryModel Public
forked from fritzy/VeryModel

A JavaScript model system for validation, creation, and editing of models.

License

Notifications You must be signed in to change notification settings

nlf/VeryModel

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VeryModel

A JavaScript model system for validation, creation, and editing of models.

I wrote this because the robust model systems that I found were tightly integrated with frameworks, or only served to be useful for validation.
VeryModel is not tied to a framework, and it implements a full purpose Model system.

OK, But What Is It?

Models are useful for managing the lifecycle of an object.
They are commonly used for framework ORMs (Object Relational Managers) and the M in MVC (Model-View-Controller) patterns like Backbone.js.

Load Network Data, Giving Proper Errors, Save It

Pretend we're working in Node.js Express,
using VeryModel as an ORM to save, load, and validate models.

function goodPassword(password) {
    //test for password being strong
    //would go here
    return true;
}

//Create a User Factory
var User = new VeryModel({
    id: {primary: true, type: VeryType().isAlphanumeric(), default: 1},
    username: {required: true, type: VeryType().isAlphanumeric().len(4, 25), default: ''},
    password: {required: false, type: VeryType().len(6).custom(goodPassword)}, default: ''},
    passhash: {private: true},
});

//create some model controller functions to interact with the database
User.extendModel({
    doSave: function(cb) {
        if (this.password) {
            this.passhash = sha1(this.password + 'static salt');
            this.password = undefined;
        }
        riak.put(this.id, model.toJSON({withPrivate: true}), cb);
    },
    doLoad: function(id, cb) {
        riak.get(id, function (err, data) {
            var model = this.create(data);
            cb(err, model);
        });
    }
});


this.post = function (req, res) {
    var user = User.create(req.body);
    var errors = user.doValidate();
    if (errors.length > 0) {
        res.send(400, errors.join('\n'));
    } else {
        var uid = uuid();
        user.id = uid;
        user.doSave(function() {
            res.send(201, user.toObject());
        });
    }
};

Create a fresh object with default values.

We can also create empty/default objects to work with as a starting point.

this.new = function (req, res) {
    res.send(200, User.create().toObject());
};

Which would send

{id: 1, username: '', password: ''}

Validate and Name Function Arguments

Model definitions can be objects or arrays.
Using an array definition, we can use VeryModel help manage function arguments (mapping, optional arguments, and validation).

doItArgs = new VeryModel([
    {required: true, keyword: 'msg'},
    {required: true, type: VeryType().isIn('small', 'big', 'huge'), default: 'small'},
    {required: false, keyword: 'save', default: false, type: 'boolean'},
    {required: true, keyword: 'cb', type: 'function'}
]);

function doIt() {
    var args = doItArgs.create(arguments);
    var errors = args.doValidate();
    args.cb(errors, args.type, args.msg, args.save);
}

doIt('hi there', function(err, type, msg, save) {
    console.log("Made it!");
});

Install

npm install verymodel

API

VeryType

Definition

Model defintions are recursive Javascript object. At each layer, you can have the following fields:

  • required (boolean): Error on validation if this field isn't set.
  • type (VeryType): VeryType chain to validate field against if set.
  • default (any): Default value set automatically.
  • model (definition object or VeryModel): set this field as another model.
  • collection (definition object or VeryModel): set this field as a collection of a model.
  • derive function): Derive the value of this field with this function whenever field is accessed {derive: function(model) {return model.first + ' ' + model.last}
  • depends ({some_other_field: VeryType or true}, ...): Require other fields when this field is set, optionally run VeryType chain check on other field.
  • private (boolean): toObject() will not include this field in expect unless the argument withPrivate is true
  • processIn (function): value will be transformed on set via the processIn function
  • processOut (function): value will be transformed on set via the processOut function when toObject() is called

Example Definition

var generaldef = {
    name: {
        required: true,
        model: {
            first: {required: false, type: VeryType().isAlpha().len(2, 25)},
            last: {required: false, type: VeryType().isAlpha().len(3, 25)},
            title: {depends: {last: true},
            full: {derive: function (name) {
                return (typeof name.title !== 'undefined' ? name.title + ' ' : '') + (typeof name.first !== 'undefined' ? name.first + ' ': '') + name.last;
                }
            }
        }
    },
    knowledge: {collection: {
            name: {required: true},
            category: {required: true, type: VeryType().isIn(['vegetable', 'animal', 'mineral'])}
        }
    },
    rank: {
        required: true,
        type: VeryType().isIn(['Private', 'Corpral', 'Major', 'General', 'Major-General']),
        default: 'Major-General'
    }
};

Models

Models can be treated like normal objects. Each field has a getter/setter. Models also refer to their __parent

loadData(data)

Rather than setting fields individually, set them en masse with an object.

toObject()

Export an object with no getters, setters, state, etc... just the object with derived fields.

doValidate()

returns an array of error strings.

toJSON()

helper for JSON.stringify(model.toObject());

VeryModel

This class interprets defintions and spawns models from create.

Initialize with a definition.

var MajorGeneral = new VeryModel(generaldef);
var stanley = MajorGeneral.create({
    name: {title: 'Major-General', last: 'Stanley'},
    rank: 'Major-General',
    knowledge: [{name: 'animalculous', category: 'animal'}, {name: 'calculus', category: 'mathmatical'}]
});
var errors = stanley.doValidate();
console.log(errors);

Output:

[ 'knowledge[1].category: Unexpected value or invalid argument' ]

Turns out he knows more than just animals, vegetables, minerals.

stanley.knowledge[1].category = 'vegetable';

That ought to do it.

var errors = stanley.doValidate();
console.log(errors);

Output:

[]

Let's see what our object looks like:

console.log(stanley.toObject());

Output:

{ name:
   { last: 'Stanley',
     title: 'Major-General',
     full: 'Major-General Stanley' },
  knowledge:
   [ { name: 'animalculous', category: 'animal' },
     { name: 'calculus', category: 'vegetable' } ],
  rank: 'Major-General' }

Noticed that the derived field, name.full was populated.

About

A JavaScript model system for validation, creation, and editing of models.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 100.0%