Coder Social home page Coder Social logo

promised-models's Introduction

Promised Models

Key features

  • promise based
  • typed attributes
  • nested models and collections
  • async calculations and validation

Install

$npm install --save promised-models

Usage

var Model = require('promises-models'),
    FashionModel = new Model.inherit({
        attributes: {
            name: Model.attributeTypes.String
        }
    }),
    model = new FashionModel({
        name: 'Kate'
    });

model.get('name'); // 'Kate'

Api reference (in progress)

Model sync methods

inherit Model.inherit(properties, [classPorperties])

Creates you own model class by extending Model. You can define attributes, instance/class method and properties. Inheritance is built over inherit.

var CountedModels = Model.inherit({
    __constructor: function () {
        this.__base.apply(this, arguments); //super
        this.attributes.index.set(this.__self._count); //static properties
        this.__self._count ++;
    },
    getIndex: function () {
        return this.get('index');
    }
}, {
    _count: 0,
    getCount: function () {
        return this._count;
    }
});

attributeTypes Model.attributeTypes

Namespace for predefined types of attributes. Supported types:

  • String
  • Number
  • Boolean
  • List — for storing arrays
  • Model — for nested models
  • ModelsList — for nested collections
  • Object — serializable objects

You can extend default attribute types or create your own

var DateAttribute = Model.attributeTypes.Number.inherit({
    //..
}),
FashionModel = Model.inherit({
    attributes: {
        name: Model.attributeTypes.String,
        birthDate: DateAttribute
    }
});

Note: models.attributes will be replaced in constructor with attribute instances.

var model = new FashionModel();
model.attributes.birthDate instanceof DateAttribute; //true

set model.set(attributeName, value)

Set current value of attribute.

var model = new FashionModel();
model.set('name', 'Kate');
model.attributes.name.set('Kate');
model.set({
    name: 'Kate',
    birthDate: new Date(1974, 1, 16)
});

Note: setting null is equivalent to call .unset()

get model.get(attributeName)

Get current value of attribute.

var model = new FashionModel({
    name: 'Kate',
    birthDate: new Date(1974, 1, 16)
})
model.get('name'); //Kate
model.attributes.name.get(); //Kate
model.get('some'); //throws error as unknown attribute

toJSON model.toJSON()

Return shallow copy of model data.

Note: You can create internal attributes, which wouldn't be included to returned object.

var FashionModel = new Model.inherit({
    attributes: {
        name: Model.attributeTypes.String.inherit({
            internal: true;
        }),
        sename: Model.attributeTypes.String.inherit({
            internal: true;
        }),
        fullName: Model.attributeTypes.String
    }
}),
model = new FashionModel({
    name: 'Kate',
    sename: 'Moss',
    fullName: 'Kate Moss'
});
model.toJSON(); // {fullName: 'Kate Moss'}
model.get('name'); // Kate

Note: Returned object supposed to be serializable via JSON.parse(). Due to this reason NaN and Infinity are serialized in this way:

NaN -> null
Infinity -> 'Infinity'

isChanged model.isChanged([branch])

Has model changed since init or last commit/save/fetch.

var FashionModel = Model.inherit({
        attributes: {
            name: Model.attributeTypes.String,
            weight: Model.attributeTypes.Number.inherit({
                default: 50
            })
        }
    }),
    model = new FashionModel({
        name: 'Kate',
        weight: 55
    });
model.isChanged(); //false
model.set('weight', 56);
model.isChanged(); //true

commit model.commit([branch])

Cache current model state

var model = new FashionModel();
model.set({
    name: 'Kate',
    weight: 55
});
model.isChanged();//true
model.commit();
model.isChanged();//false

revert model.revert([branch])

Revert model state to last cashed one

var model = new FashionModel({
    name: 'Kate',
    weight: 55
});
model.set('weight', 56);
model.revert();
model.get('weight'); //55
model.isChanged(); //false

Note: You can create your own cache by passing branch param.

var RENDERED = 'RENDERED';
model.on('change', function () {
    if (model.isChanged(RENDERED)) {
        View.render();
        model.commit(RENDERED);
    }
});

on model.on([attributes], events, cb, [ctx])

Add event handler for one or multiple model events.

List of events:

  • change – some of attributes have been changed
  • change:attributeNameattributeName have been changed
  • destruct – model was destructed
  • calculate – async calculations started
model.on('change', this.changeHandler, this)
     .on('change:weight change:name', this.changeHandler, this);

un model.un([attributes], events, cb, [ctx])

Unsubscribe event handler from events.

//subscribe
model.on('weight name', 'change', this.changeHandler, this);

//unsubscribe
model.un('change:weight change:name', this.changeHandler, this);

destruct model.destruct()

Remove all events handlers from model and removes model from collections

isSet model.isSet(attributeName)

Returns true if attribute was set via constructor or set

var model = new FashionModel();
model.isSet('name'); //false
model.set('name', 'Kate');
model.isSet('name'); //true

unset model.unset(attributeName)

Set attribute to default value and model.isSet() === 'false'

var model = new FashionModel();
model.set('name', 'Kate');
model.unset('name');
model.isSet('name'); //false
model.get('name'); //empty string (default value)

Model async methods

validate model.validate()

Validate model attributes.

var FashionModel = Model.inherit({
        attributes: {
            name: Model.attributeTypes.String.inherit({
                validate: function () {
                    return $.get('/validateName', {
                        name: this.get()
                    }).then(function () {
                        return true; //valid
                    }, function () {
                        return false; //invalid
                    });
                }
            })
        }
    }),
    model = new FashionModel();

model.validate().fail(function (err) {
    if (err instanceof Model.ValidationError) {
        console.log('Invalid attributes:' + err.attributes.join());
    } else {
        return err;
    }
}).done();

ready model.ready()

Fulfils when all calculations over model finished.

var FashionModel = Model.inherit({
        attributes: {
            name: Model.attributeTypes.String,
            ratingIndex: Model.attributeTypes.Number.inherit({
                calculate: function () {
                    return $.get('/rating', {
                        annualFee: this.model.get('annualFee')
                    });
                }
            }),
            annualFee: Model.attributeTypes.Number
        }
    }),
    model = new FashionModel();

model.set('annualFee', 1000000);
model.ready().then(function () {
    model.get('ratingIndex');
}).done();

fetch model.fetch()

Fetch data associated with model from storage.

var FashionModel = Model.inherit({
        attributes: {
            name: Model.attributeTypes.String
        },
        storage: Model.Storage.inherit({
            find: function (model) {
                return $.get('/models', {
                    id: model.id
                });
            }
        })
    }),
    model = new FashionModel(id);

model.fetch().then(function () {
    model.get('name');
}).done();

save model.save()

var FashionModel = Model.inherit({
        attributes: {
            name: Model.attributeTypes.String,
            weight: Model.attributeTypes.Number
        },
        storage: Model.Storage.inherit({
            insert: function (model) {
                return $.post('/models', model.toJSON()).then(function (result) {
                    return result.id;
                });
            },
            update: function (model) {
                return $.put('/models', model.toJSON());
            }
        })
    }),
    model = new FashionModel();

model.set({
    name: 'Kate',
    weight: 55
});
model.save().then(function () { //create
    model.id; //storage id
    model.set('weight', 56);
    return model.save(); //update
}).done()

remove model.remove()

Removes model from storage.

Model additional methods and properties

  • model.isNew()
  • model.isReady()
  • model.trigger(event)
  • model.calculate()
  • model.CHANGE_BRANCH
  • model.CALCULATIONS_BRANCH

These methods provided for advanced model extending. Consult source for details.

Model static methods and properties

Storage Model.Storage

Abstract class for model storage

var FashionModel = Model.inherit({
    attributes: {
        //..
    },
    storage: Model.Storage.inherit({
        //..
    })
});

Class storage Model.storage

Storage class

var SuperModel = FashionModel.inherit({
    storage: FashionModel.storage.inherit({ //extend storage from FashionModel
        //..
    })
});

Attribute Model.Attribute

Base class for model attribute

var CustomAttribute = Model.attribute.inherit({
    //..
})

Class attributes Model.attributes

Model class attributes

var SuperModel = FashionModel.inherit({
    attributes: {
        name: FashionModel.attributes.name,
        weight: FashionModel.attributes.weight.inherit({
            default: 50
        })
    }
});

Model.on([attributes], events, cb, [ctx])

Bind event on all models of class

FashionModel.on('change', this.changeHandler, this);

Model.un([attributes], events, cb, [ctx])

Unbind event on all models of class

List

Array like object returned for fields types List and ModelsList

var Podium = Model.inherit({
    attributes: {
        models: Model.attributeTypes.ModelsList(FashionModel)
    }
}),

podium = new Podium(data),
list = podium.get('models'), //instanceof List
model = list.get(0); //instanceof Model

Mutating methods

List inerits Array mutating methods: pop, push, reverse, shift, sort, splice, unshift

podium.get('models').push(new FashionModel());

list.get(index)

Get list item by index

podium.get('models').get(0);// instanceof Model

list.length()

Returns length of list

list.toArray()

Returns shallow copy of Array, wich stores List items

podium.get('models').forEach(function (model) {
    model; // instanceof Model
});

ValidationError Model.ValidationError

Error class for validation fail report

run tests

$ npm test

promised-models's People

Contributors

delfrrr avatar ostannya avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

promised-models's Issues

attributes inheritance documents

  1. do not understand how to build child model, that contains all parent's attributes and some it's own
  2. do not understand how to build child model, that removes one or more of all parent attributes (and if is it possible)

null-able attributes

Fields may be not set. So

  1. attribute should have method that checks if attribute is set
  2. method from 1) should be passed up into model
  3. attribute should have method that unsets value from it
  4. method from 3) should be passed up into model
  5. initializiation of attribute with null value should set it to undefined state

ModelsList 'id' serialization

var Podium = Model.inherit({
attributes: {
models: Model.attributeTypes.ModelsList(FashionModel)
}
}),

podium = new Podium(data),
list = podium.get('models'),
kate = new FasionModel(1, {name: 'Kate'}),
list.push(kate),
podiumRestored;

kate.isNew(); // false

podiumRestored = new Podium(podium.toJSON());
kate = podiumRestored.get('models').get(0);

kate.isNew(); // true

Vow.fulfill().isResolved() === false

В Vow 0.3.x sResolved() === true только в nextTick. В конструкторе модели calculate() проверяет isReady() который всегда false.

nested models does not resubscribes after model replacement

Model1 = Model.inherit({
        attributes: {
         .....
        }
    });
Model2 = Model.inherit({
    attributes: {
        submodel: {
            type: 'Model',
            modelType: 'Model1'
        }
    }
});

m2Instance = new Model2();
m2Instance.on('change:submodel', function () {do smth});
m2Instance.get('submodel').set({});//emits change on m2Instance
m2Instance.set('submodel', new Model1());
m2Instance.get('submodel').set({});//does not emit change on m2Instance

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.