modelfactory

Data models with schema definition, and event propagation inspired by Mongoose & Backbone.js

Usage no npm install needed!

<script type="module">
  import modelfactory from 'https://cdn.skypack.dev/modelfactory';
</script>

README

modelfactory

Data models with schema definition, and event propagation inspired by Mongoose & Backbone.js

Installation

Install with component:

$ component install pgherveou/modelfactory

Install with npm:

$ npm install modelfactory

Example

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

reuse mongoose schema definition

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();

Reuse models & ref / populate

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;

API

coming soon..

supported browsers

should work on any browser supporting Object.defineProperty

Credits

License

MIT