yangchengit / marilyn

Marilyn is a client side, Socket.IO driven, Pub/Sub, model layer with a query system similar to Mongoose.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Marilyn

Marilyn is a client side, WebSocket driven, Pub/Sub, model layer with a query system similar to Mongoose.

Angular, Backbone, Ember, and many other libraries provide model layers which are AJAX driven. While variations on these models exist they are usually only useful if you're using the entire framework they are built to work with.

Marilyn can work with any framework, or by itself if you just need more data abstraction.

Installation

Install the module with bower: $ bower install marilyn
or download it from GitHub and copy the files into your application.

Include a script for the marilyn.js or marilyn-min.js file after a script for it's dependency, underscore.js or lodash.js.

Upon including the marilyn.js file a global Marilyn object will be available.

Marilyn does not yet support AMD. You will have to load it using the <script></script> tags for now.

Usage

Configure Socket.IO

Before using Marilyn with Socket.IO you have to configure Marilyn to use Socket.IO's socket connection. Lets use the client side example connection from the Socket.IO website to demonstrate this.

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
</script>

This creates a global variable called socket. This variable should be passed to Marilyn so Marilyn can use the Socket.IO on and emit methods.

<script>
  Marilyn.config(socket);
</script>

After this Marilyn has on and emit methods that we should call instead of the Socket.IO methods. This allows us to centralize all data querying and data fetching methods to Marilyn.

Creating Model

Like Mongoose, Marilyn creates models using the model method.

var MyModel = Marilyn.model('someModelName');

MyModel is now a Marilyn model, containing query and event methods.

You can also create a model by passing the Marilyn.model methods a second parameter, a callback function. Within this callback function this represents the model that has been created.

var MyModel = Marilyn.model('someModelName', function(){

	// "this" is the same as MyModel

});

Like Mongoose, the Marilyn model created, called someModelName, can now be accessed from the global Marilyn object.

This allows you to use self executing functions to create a model and not pollute the global scope.

// myModel.js

(function(){

	var NonPollutingModel = Marilyn.model('someModelName', function(){

		this.on('someSocketEvent', function(data){
			// do something with data in model
			this.inform('someBrowserEvent', data);
		});

	});

	NonPollutingModel.on('someOtherSocketEvent', function(data){
		// do something else
	});

})();
// myController.js

(function(){

	var MyModel = Marilyn.model('someModelName');

	MyModel.receive('someBrowserEvent', function(){
		// do something with data in controller
	});

})();

Adding Data to Models

All models have a _collection variable.

This variable is an array of all the objects you have stored in your frontend model.

To populate this variable you can use the built in CRUD methods listed below, or the collection setter.

If you use the CRUD methods various built in callbacks will be run. If you use the collection setter these callback functions won't be called.

Marilyn.model('someModelName', function(){

	this.on('someSocketEvent', function(data){

		// sets the _collection array
		// this won't trigger any callbacks
		this.collection(data);

	});

	this.on('someOtherServerEvent', function(data){

		// pushes a new object into the _collection array and performs many other tasks
		// this will trigger all the "create" callbacks
		this.create(data);

	});

});

When new objects are added to the _collection variable a property of __id is added to them so Marilyn can internally track them.

Setting the _collection variable directly without the CRUD methods or the collection setter will not create this __id property and Marilyn will not function properly.

Event Handlers

Marilyn has four types of event handlers, socket events, browser events, befores, and afters.

Socket events are for communicating from your model to a socket server, or from a socket server to your model.

Browser events are for communicating between your model and controller, or client side logic layer.

Befores run before a query method is executed.

Afters run after a query method is executed.

Socket events and browser events have two methods, an event listener and an event dispatcher.

Socket Events

The socket event methods behave the same events as Socket.IO.

They are on and emit.

Refere to Socket.IO documentation to understand how these work.

Browser Events

Browser event methods are receive and inform. They act very similarly to Socket.IO's on and emit.

They can send data and receive data with callback functions.

// myModel.js

Marilyn.model('someModelName', function(){

	this.inform('modelReady', {
		'someKey':'someValue'
	});

});
// myController.js

var MyModel = Marilyn.model('someModelName');

MyModel.receive('modelReady', function(data){
	// do something here
	// data is the object passed from the inform method
});

All query events inform receivers after completion. This is best shown in the next example.

Befores and Afters

Befores and afters are similar to Mongoose's pre and post events. Befores are triggered before all querys, and afters are after the query.

All befores and afters are passed data that they can manipulate and a next method, which must be called in order to progress the flow control.

// myModel.js

Marilyn.model('someModelName', function(){

	this.before('create', function(data, next){
		// this is useful for validating data before a CRUD method runs
		console.log('I ran before');
		next();
	});

	this.after('create', function(data, next){
		// this is useful for altering data before it's returned to the controller
		console.log('I ran after');
		next();
	});

});
// myController.js

var MyModel = Marilyn.model('someModelName');

MyModel.receive('create', function(data){
	console.log('I ran in the controller create receiver')
});


MyModel.create({}, function(err, result){
	console.log('I ran in the controller create callback')
});

This code above will output this.

I ran before
I ran in the controller create receiver
I ran after
I ran in the controller create callback

Befores and afters are triggered from create, read, readOne, update, delete, and save.

Sometimes multiple befores and afters can be triggered by one CRUD method being invoked, for example the save method can trigger befores and afters for create and update in addition to befores and afters for save events.

Querying Data with CRUD Methods

Each Marilyn model has a private variable called _collection, which can be populated with an array of data. All query methods query this variable.

There are ten query methods, create, createSilent, read, readSilent, readOne, readOneSilent, update, updateSilent, del, and delSilent.

All silent query methods don't trigger befores or afters.

Create

var myModel = new MyModel();
myModel.title = 'Star Wars';
myModel.director = 'George Lucas';

// calling this method will trigger save befores and afters
myModel.save(function(err, result){
	// result is the object created
});

// OR

var myModel = new MyModel({
	'title':'Star Wars',
	'director':'George Lucas'
});

// calling this method will trigger save befores and afters
myModel.save(function(err, result){
	// result is the object created
});

// OR

// calling this method will trigger create befores and afters
MyModel.create({
	'title':'Star Wars',
	'director':'George Lucas'
}, function(err, result){
	// result is the object created
});

Read

// calling this method will trigger read befores and afters
MyModel.read({
	'director':'George Lucas'
}, function(err, results){
	// results is an array of all the objects found
});

// calling this method will trigger readOne befores and afters
MyModel.readOne({
	'id':1138
}, function(err, result){
	// result is the single object found
});

Update

// updates using readOne
MyModel.readOne({
	'id':1138
}, function(err, result){

	result.director = 'George Lucas';

	result.save(function(err, result){
		// result is the updated object
	});

});

// calling this method will trigger update befores and afters
MyModel.update({
	'id':1138
}, {
	'propertyToUpdate':'someValue'
}, function(err, results){
	// results is an array of all the objects updated
});

Delete

// calling this method will trigger delete befores and afters
MyModel.del({
	'id':1138
}, function(err results){
	// results is an array of all the objects deleted
});

err is always populated if nothing matches the query.

Query methods don't directly call the server, you must call the server manually with emit either before or after query methods are invoked. This makes before and after very useful for server integration.

Dependencies

Marilyn requires Underscore >= 1.5.0. Get it from: http://underscorejs.org/

Author

Alan James: alanjames1987@gmail.com

License

Licensed under MIT.

About

Marilyn is a client side, Socket.IO driven, Pub/Sub, model layer with a query system similar to Mongoose.

License:MIT License