Data models with schema definition, and event propagation inspired by Mongoose & Backbone.js
Install with component:
$ component install pgherveou/modelfactory
Install with npm:
$ npm install modelfactory
var modelfactory = require('modelfactory'),
regex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
// create a User Model
var User = modelfactory.model({
email: {type: String, required: true, match: regex},
age: {type: Number, min: 13},
date: {type: Date, default: Date.now},
name: {
first: {type: String, required: true},
last: {type: String, required: true}
},
trophies: [{name: String, date: Date}]
})
// define virtuals
User.schema.virtual('name.full').get(function () {
return this.name.first + ' ' + this.name.last;
})
// define getters
User.schema.path('email').get(function(v) {
var split = v.split('@')
return split[0] + '[at]' + split[1];
});
// define setters
User.schema.path('name.last').set(function(v) {
return v[0].toUpperCase() + v.slice(1);
});
// define static methods
User.schema.static('fetch', function() {
// ...
});
// define instance methods
User.schema.method('greeting', function() {
return 'hello ' + this.name.full;
});
// create an instance
var user = new User({
email: "john@gmail.com",
name: {first: 'john', last: 'mcenroe'},
trophies: [
{name: 'Roland Garros', date: 'june-1984'},
{name: 'Wimbledon', date: 'aug-1984'}
]
});
// data are casted according to their type
user.age = "56"
user.age === 56 // true
user.date = 'oct-2013'
user.date instanceof Date // true
// events are emitted on ppty change
user.on('change:email', function() {/* do something when email change */});
user.email = 'johny@gmail.com'
user.set('email', 'johny2@gmail.com', {silent: true}) // or silent it
// work for nested properties as well
user.on('change:name.first', function() {/* do something when firstname change */});
user.on('change:name', function() {/* do something when name change */});
user.name.first = 'johny'
// or embedded arrays
user.trophies.on('add', function() {/* do something with added trophee */});
user.trophies.on('change:name', function() {/* do something when a trophee name change */});
// validation use schema rules
user.email = "johnyatgmail.com";
console.log(user.validate()); // KO
You can share your schema definition between node and the browser here is one way of doing it
/*!
* user.shared.js
*/
module.exports = function (Schema) {
var User = new Schema({
email: {type: String, lowercase: true, match: emailRegex},
firstname: {type: String, min: 2},
lastname: {type: String, min: 2}
});
User.virtual('fullname').get(function () {
return this.firstname + ' ' + this.lastname;
});
User.method('greating').get(function () {
return 'Hello ' + this.fullname;
});
return User;
};
/*!
* user.server.js
*/
var mongoose = require('mongoose'),
User = require('./user.shared')(mongoose.Schema);
// create a user
var user = new User({
email: 'pg@jogabo.com',
firstname: 'PG',
lastname: 'Herveou'
});
// ...
// play with user
user.fullname; // => PG Herveou
user.validate(); // => no errs
user.save();
/*!
* user.client.js
*/
var factory = require('modelfactory'),
User = require('./user.shared')(factory.Schema);
// add some client specific methods
User.prototype.save = function() { /* ... */ };
// create a user
var user = new User({
email: 'pg@jogabo.com',
firstname: 'PG',
lastname: 'Herveou'
});
// ...
user.fullname; // => PG Herveou
user.validate(); // => no errs
// do something when firstname change
user.on('change:firstname', function() { /*...*/});
// => trigger change:firstname event
user.firstname = 'Pierre-Guillaume';
user.save();
Usually you set your client model with populated objects coming from the server Here is an example of a Post model that reference a User model.
/*!
* post.shared.js
*/
module.exports = function(Schema) {
return new Schema({
date: { type: Date, required: true },
msg: { type: String, trim: true, required: true },
});
};
/*!
* post.server.js
*/
var mongoose = require('mongoose'),
schema = require('./post.shared')(mongoose.Schema);
schema.add({ _from: { type: ObjectId, ref: 'User' });
module.exports = schema;
/*!
* post.client.js
*/
var factory = require('modelfactory'),
User = require('./user').schema;
schema = require('./post.shared')(factory);
schema.add({ _from: User });
module.exports = schema;
coming soon..
should work on any browser supporting Object.defineProperty
MIT