Skip to content

Instantly share code, notes, and snippets.

@goliatone
Last active October 19, 2016 17:36
Show Gist options
  • Save goliatone/2ef3359ac9b0eaf4245797ff6666adcb to your computer and use it in GitHub Desktop.
Save goliatone/2ef3359ac9b0eaf4245797ff6666adcb to your computer and use it in GitHub Desktop.
Waterline BaseModel

Waterline BaseModel

Creating a Waterline BaseModel where extended collections automagically call afterCreate, afterUpdate, afterDestroy of BaseModel.

We could achieve the same by simple calling the super method:

petCollection.__super__.afterUpdate(record, next);

The idea is to trasnparently get create, update, and destroy events over the wire...

This is just a spin on nexus' BaseModel.

'use strict';
const Waterline = require('waterline');
const _ = require('underscore');
const sailsMemoryAdapter = require('sails-memory');
var BaseModel = Waterline.Collection.extend({
connection: 'default',
pubsubModule: null,
attributes: {
displayName: function displayName() {
// Appears there is no way to get to the attribute definitions from an instance.
var firstString = _.first(_.compact(_(this).pairs().map(([key, value]) => { if (!_.contains(['name', 'label', 'id', 'createdAt', 'updatedAt'], key) && _.isString(value)) return key })));
return this[firstString];
}
},
afterCreate: function (record, next) {
console.log('BaseModel: here afterCreate');
if(this.pubsubModule){
this.pubsubModule.emitModelEvent(this.getEventType('create'), record);
}
next()
},
afterUpdate: function(record, next) {
console.log('BaseModel: here afterUpdate');
if(this.pubsubModule){
this.pubsubModule.emitModelEvent(this.getEventType('update'), record);
}
next()
},
afterDestroy: function(record, next){
if(this.pubsubModule){
this.pubsubModule.emitModelEvent(this.getEventType('destroy'), record);
}
next();
},
getEventType: function(action){
return this.identity + ':' + action;
}
});
BaseModel.extend = function(protoProps, staticProps) {
// Waterline wants each model to have its own connection property, rather than inheriting
if (protoProps.connection === undefined) {
protoProps.connection = this.prototype.connection
}
// Waterline wants each model to have its own attributes property, we want to combine
if (protoProps.attributes === undefined) {
protoProps.attributes = {}
}
['afterCreate', 'beforeCreate', 'afterUpdate', 'beforeUpdate'].map(wrapBaseMethod);
function wrapBaseMethod(method){
var _ac = protoProps[method];
if(_ac){
protoProps[method] = function(record, next){
var self = this;
var wrap = function(err){
if(err) next(err);
else self.constructor.__super__[method](record, next);
};
_ac.call(protoProps, record, wrap);
}
}
}
protoProps.attributes = _.extend({}, this.prototype.attributes, protoProps.attributes)
return Waterline.Collection.extend.call(this, protoProps, staticProps)
};
// Create the waterline instance.
var waterline = new Waterline();
// Create a specification for a User model.
var userCollection = BaseModel.extend({
identity: 'user',
connection: 'default',
attributes: {
firstName: 'string',
lastName: 'string',
// Add a reference to Pets
pets: {
collection: 'pet',
via: 'owner'
}
},
afterCreate: function(record, next){
console.log('User collection after create');
// petCollection.__super__.afterCreate(record, next);
next();
},
afterUpdate: function(record, next){
console.log('User collection afterUpdate');
// petCollection.__super__.afterUpdate(record, next);
next();
}
});
// Create a specification for a Pet model.
var petCollection = BaseModel.extend({
identity: 'pet',
connection: 'default',
attributes: {
breed: 'string',
type: 'string',
name: 'string',
// Add a reference to User
owner: {
model: 'user'
}
},
afterCreate: function(record, next){
console.log('pet collection after create');
// petCollection.__super__.afterCreate(record, next);
next();
},
afterUpdate: function(record, next){
console.log('pet collection afterUpdate');
next();
}
});
// Add the models to the waterline instance.
waterline.loadCollection(userCollection);
waterline.loadCollection(petCollection);
// Set up the storage configuration for waterline.
var config = {
adapters: {
'memory': sailsMemoryAdapter
},
connections: {
default: {
adapter: 'memory'
}
}
};
// Initialise the waterline instance.
waterline.initialize(config, function (err, ontology) {
if (err) {
return console.error(err);
}
// Tease out fully initialised models.
var User = ontology.collections.user;
var Pet = ontology.collections.pet;
// First we create a user.
User.create({
firstName: 'Neil',
lastName: 'Armstrong'
})
.then(function (user) {
// Then we can create a pet for the user.
// Note that waterline automatically adds the `id` primary key to the model.
Pet.create({
breed: 'beagle',
type: 'dog',
name: 'Astro',
owner: user.id
})
.then(function (pet) {
// Then we can associate the pet with the user.
user.pets = [pet];
// And save the user.
return user.save();
})
.then(function () {
// And now we want to get the new user back,
// and populate the pets the user might own.
return User.find()
.populate('pets');
})
.then(console.log)
.catch(console.error);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment