Skip to content

Instantly share code, notes, and snippets.

@formula1
Created April 21, 2015 07:39
Show Gist options
  • Save formula1/d278fb7c81d4ff1b364e to your computer and use it in GitHub Desktop.
Save formula1/d278fb7c81d4ff1b364e to your computer and use it in GitHub Desktop.
wip
function Adapter(options){
if(options instanceof Adapter){
options.waterline = waterline;
return options;
}
if(!(this instanceof Adapter) return new Adapter(options,waterline);
if(!waterline) throw new Error("need a waterline instance to attach to");
this.waterline = waterline;
Object.defineProperty(this,"state",{
get:function(){
if(!this.waterline.adapters[this.adapter]) return Waterline.STATES.QUEUED;
if(!this.checked) return Waterline.STATES.QUEUED;
if(!this.error) return Waterline.STATES.FAILED;
if(!this.connected) return Waterline.STATES.OFFLINE;
return Waterline.STATES.ONLINE;
}
})
this.initialize();
}
module.exports = Adapter;
module.exports.handleConnectionDependencies = function(self){
if(!self.connection) self.connection = ["default"];
if(!Array.isArray(self.connection)) self.connection = [self.connection];
function queue(connection){
self.waterline.once("add-connection["+connection+"]",function(connection){
if(self.state === Waterline.STATES.ONLINE && self.emittedAdd === false){
self.emittedRemoval = true;
self.emittedRemoval = false;
self.waterline.emit("add-collection["+self.name+"]",self);
}
activate(connection);
})
}
function activate(connection){
self.waterline.once("sub-connection["+connection+"]",function(connection){
if(self.emittedRemoval === false){
self.emittedRemoval = true;
self.emittedOnline = false;
self.waterline.emit("sub-collection["+self.name+"]",self);
}
queue(connection);
});
}
self.connection = self.connection.map(function(connection){
if(connection instanceof Connection){
connection = self.waterline.loadConnection(connection).name;
}else if(typeof connection !== "string" ) throw new Error("Connections should be referenced by key");
if(!self.waterline.connections[connection]) queue(connection);
else activate(connection);
return connection;
});
};
module.exports.handleCollectionDependencies = function(self,schema){
var depends = [];
var collection;
for(var i in schema.paths){
if(schema.paths[i].type !== "OBJECTID") continue;
if(schema.paths[i].model){
collection = schema.paths[i].model
if(collection instanceof Collection){
collection = self.waterline.loadConnection(Collection).name;
}else if(typeof collection !== "string" ) throw new Error("Connections should be referenced by key");
if(!self.waterline.collections[collection]) queue(collection);
else activate(collection);
depends.push(collection);
}
}
this.collections = depends;
function queue(collection){
self.waterline.once("add-collection["+collection+"]",function(collection){
if(self.state === Waterline.STATES.ONLINE && self.emittedOnline === false){
self.emittedRemoval = false;
self.emittedOnline = true;
self.waterline.emit("add-collection["+self.name+"]",self);
}
activate(collection);
})
}
function activate(connection){
self.waterline.once("sub-collection["+collection+"]",function(collection){
if(self.emittedRemoval === false){
self.emittedRemoval = true;
self.emittedOnline = false;
self.waterline.emit("sub-collection["+self.name+"]",self);
}
queue(collection);
});
}
switch(this.state){
case Waterline.STATES.ONLINE: return activate();
case Waterline.STATES.REJECTED: throw Error("Adapter has been Rejected");
case Waterline.STATES.QUEUED: return queue();
case Waterline.STATES.OFFLINE: return queue();
}
};
module.exports.inheritMethods = function(self,schema){
for(var i in schema.statics){
if(/before|after|validate|create|update|find|destroy/.test(i)){
throw new Error("Attempting to define restricted static method: "+i);
}
self[i] = schema.statics[i];
}
for(var i in schema.methods){
if(/save|populate|destroy/.test(i)){
throw new Error("Attempting to define restricted instance method: "+i);
}
self.prototype[i] = schema.methods[i];
}
};
module.exports.getCollectionState = getCollectionState;
module.exports.getConnectionState = getConnectionState;
function getCollectionState(self,previousCollections){
previousCollections = previousCollections||[];
var allRejected=true,i,l,state;
for(i=0,l=self.collections.length;i<l;i++){
var depCol = self.collection[i];
if(!self.waterline.collections[depCol]) return Waterline.STATES.QUEUED;
if(previousCollections.indexOf(depCol) != -1) continue;
state = getCollectionState(this.waterline.collections[depCol],previousCollections.concat([this.name]));
if(state !== Waterline.STATES.ONLINE){
return state;
}
}
return Waterline.STATES.ONLINE;
}
function getConnectionState(self){
for(i=0,l=self.connections.length;i<l;i++){
var conn = self.connections[i];
if(!self.waterline.connections[conn]) continue;
if(self.waterline.connections[conn].state == Waterline.STATES.ONLINE){
return Waterline.STATES.ONLINE;
}
if(self.waterline.connections[conn].state == Waterline.STATES.OFFLINE){
return Waterline.STATES.OFFLINE;
}
}
return Waterline.STATES.QUEUED;
}
var constructors = require("./constructor.js");
function Collection(options,connections,waterline){
if(options instanceof Collection){
options.waterline = waterline;
return options;
}
if(!(this instanceof Collection) return new Collection(options,waterline);
if(!waterline) throw new Error("need a waterline instance to attach to");
this.waterline = waterline;
var self = this;
this.name = options.name;
delete options.name;
constructors.handleConnectionDependencies(self);
constructors.handleCollectionDependencies(self)
constructors.inheritMethods(self,options);
Object.defineProperty(this,"state",{
get:function(){
var state = constructors.getCollectionState(self,[]);
if(state !== Waterline.STATES.ONLINE){
return state;
}
return constructors.getConnectionState(self);
}
})
this._middleware = {
beforeValidate:[],
afterValidate:[],
beforeCreate:[],
afterCreate:[],
beforeUpdate:[],
afterUpdate:[],
beforeDestroy:[],
afterDestroy:[],
};
}
Collection.prototype.prototype = require("Instance");
Collection.prototype.getMiddleware = function(type){
if(!(type in collection._middleware)) throw new Error(type+" not in the middleware");
return this._middleware[type];
};
var MIDDLEWARE_TYPES = [
"validate",
"create",
"update",
"destroy"
];
var MIDDLEWARE_TIMINGS = [
"before",
"after"
];
MIDDLEWARE_TIMINGS.forEach(function(time){
Collection.prototype[time] = function(type,fn){
if(MIDDLEWARE_TYPES.indexOf(type) === -1){
throw new Error(
"cannot add middleware not in types: "+
JSON.stringify(MIDDLEWARE_TYPES)
);
}
if(typeof fn != "function"){
throw new Error(
"callback supplied for("+
time+" "+type+
" is not a function"
);
}
this._middleware[time+capitalizeFirstLetter(type)].push(fn);
};
});
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
module.exports = Collection;
function Connection(options,waterline){
if(options instanceof Connection){
options.waterline = waterline;
return options;
}
if(!(this instanceof Connection) return new Connection(options,waterline);
if(!waterline) throw new Error("need a waterline instance to attach to");
this.waterline = waterline;
Object.defineProperty(this,"state",{
get:function(){
if(this.error) return Waterline.STATES.FAILED;
if(!this.waterline) return Waterline.States.UNINITIALIZED;
if(!this.waterline.adapters[this.adapter]) return Waterline.STATES.QUEUED;
return waterline.adapters[this.adapter].state;
}
})
var self = this;
function queue(){
self.waterline.once("add-adapter["+this.adapter+"]",function(adapter){
self.initialize(function(err){
if(err){
self.error = err;
return self.waterline.emit("error",err,self);
}
activate();
})
})
}
function activate(){
self.waterline.emit("add-connection["+self.name+"]",self);
self.waterline.once("sub-adapter["+self.adapter+"]",function(adapter){
self.waterline.emit("sub-connection["+self.name+"]",self);
queue();
});
}
switch(this.state){
case Waterline.STATES.ONLINE: return activate();
case Waterline.STATES.REJECTED: throw Error("Adapter has been Rejected");
case Waterline.STATES.QUEUED: return queue();
case Waterline.STATES.OFFLINE: return queue();
}
}
module.exports = Connection;
//Example Test
var wl = new Waterline();
wl.on("new-connection[fakeConnection]",function(){
throw new Error("this should not happen yet");
})
var connection = wl.loadConnection({name:"fakeConnection",adapter:"fakeAdapter"});
wl.removeAllListeners("new-connection[fakeConnection]");
var adapterDone = false;
wl.on("new-adapter[fakeAdapter]",function(){
console.log(adapter.state);
adapterDone = true;
})
wl.on("new-connection[fakeConnection]",function(){
if(!adapterDone) throw new Error("Connection happened before adapter");
console.log(connection.state);
})
var adapter = wl.loadAdapter({name:"fakeAdapter"});
wl.on("new-collection[Model1]",function(){
throw new Error("this should not be working yet");
})
wl.on("new-collection[Model2]",function(){
throw new Error("this should not be working yet");
})
var schema1 = new Schema({
prop:{model:"Model2"}
})
var model1 = wl.loadCollection("Model1",schema1,"fakeConnection");
var schema2 = new Schema({
prop:{model:"Model3"}
})
var model2 = wl.loadCollection("Model2",schema2,"fakeConnection");
var schema3 = new Schema({
prop:{model:"Model1"}
})
wl.removeAllListeners("new-collection[Model1]");
wl.removeAllListeners("new-collection[Model2]");
wl.on("new-collection[Model1]",function(){
console.log(model1.state);
})
wl.on("new-collection[Model2]",function(){
console.log(model2.state);
})
wl.on("new-collection[Model3]",function(){
console.log(model3.state);
})
var model3 = wl.loadCollection("Model3",schema3,"fakeConnection");
var cluster = require('cluster');
var async = require("async")
var ee = require('events').EventEmitter;
function WaterLine(){
ee.call(this);
var self = this;
this.master;
if(!cluster.isMaster){
process.send("waterline-child");
process.once("message",function(msg){
if(msg === "waterline-master"){
self.master = true;
process.on("message",function(msg){
if(msg.type !== "waterline-master-event") return;
self.emit(msg.event,msg.data);
})
}
});
}
this.adapters = {};
this.connections = {};
this.collections = {};
}
Waterline.prototype = Object.create(ee.prototype);
Waterline.prototype.constructor = Waterline;
Waterline.prototype.loadAdapter = function(adapter,next){
this.adapters[adapter.name] = Adapter(adapter,this);
return this.adapters[adapter.name];
}
Waterline.prototype.loadConnection = function(connnection){
if(connection.adapter instanceof Adapter && !(connection.adapter.name in this.adapters)){
connection.adapter = this.loadAdapter(connection.adapter).name;
}
this.connections[connection.name] = Connection(connection,this);
return this.connections[connection.name];
}
Waterline.prototype.loadCollection = function(collection,connections){
this.collection[collection.name] = Collection(collection,connections,this);
return this.collection[collection.name];
}
Waterline.prototype.removeAdapter = function(adapter){
var oc = this.adapter[adapter]
oc.destroy()
delete this.adapter[adapter
return oc;
}
Waterline.prototype.removeConnection = function(connnection){
var oc = this.connection[connection]
oc.destroy()
delete this.connection[connection];
return oc;
}
Waterline.prototype.removeCollection = function(collection){
var oc = this.collection[collection]
oc.destroy()
delete this.collection[collection];
return oc;
}
Waterline.STATES = [
QUEUED: "queued",
ONLINE:"online",
OFFLINE:"offline",
REJECTED:"fail"
]
module.exports = Waterline;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment