2011-10-01 19:40:22 +00:00
|
|
|
var Sequelize = require('sequelize');
|
|
|
|
|
2011-11-05 09:55:11 +00:00
|
|
|
exports.initialize = function initializeSchema(schema, callback) {
|
2011-10-01 19:40:22 +00:00
|
|
|
schema.adapter = new SequelizeAdapter(schema);
|
2011-11-13 08:05:50 +00:00
|
|
|
process.nextTick(callback);
|
2011-10-01 19:40:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
function SequelizeAdapter(schema) {
|
|
|
|
this.schema = schema;
|
|
|
|
this._models = {};
|
|
|
|
this._modelDefinitions = {};
|
2011-10-05 20:33:07 +00:00
|
|
|
this._modelSettings = {};
|
2011-10-01 19:40:22 +00:00
|
|
|
this.client = new Sequelize(
|
|
|
|
schema.settings.database,
|
|
|
|
schema.settings.username,
|
|
|
|
schema.settings.password, {
|
|
|
|
host: schema.settings.host,
|
|
|
|
port: schema.settings.port,
|
|
|
|
logging: schema.settings.port,
|
|
|
|
maxConcurrentQueries: schema.settings.maxConcurrentQueries
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.define = function (d) {
|
|
|
|
var model = d.model;
|
|
|
|
var settings = d.settings;
|
|
|
|
var properties = d.properties;
|
2011-10-05 20:33:07 +00:00
|
|
|
var m = model.modelName;
|
2011-10-01 19:40:22 +00:00
|
|
|
var translate = {
|
|
|
|
'String': Sequelize.STRING,
|
|
|
|
'Text': Sequelize.TEXT,
|
|
|
|
'Number': Sequelize.INTEGER,
|
|
|
|
'Boolean': Sequelize.BOOLEAN,
|
|
|
|
'Date': Sequelize.DATE
|
|
|
|
};
|
|
|
|
|
|
|
|
var props = {};
|
|
|
|
|
|
|
|
Object.keys(properties).forEach(function (property) {
|
|
|
|
props[property] = translate[properties[property].type.name];
|
|
|
|
});
|
|
|
|
|
2011-10-05 20:33:07 +00:00
|
|
|
this._modelDefinitions[m] = props;
|
|
|
|
this._modelSettings[m] = settings;
|
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.defineSequelizeModel = function (m) {
|
|
|
|
this._models[m] = this.client.define(m, this._modelDefinitions[m], this._modelSettings[m]);
|
|
|
|
};
|
2011-10-01 19:40:22 +00:00
|
|
|
|
2011-10-05 20:33:07 +00:00
|
|
|
SequelizeAdapter.prototype.defineForeignKey = function (model, key, cb) {
|
|
|
|
this._modelDefinitions[model][key] = {type: Sequelize.INTEGER, index: true};
|
|
|
|
cb(null, Number);
|
2011-10-01 19:40:22 +00:00
|
|
|
};
|
|
|
|
|
2011-10-05 20:33:07 +00:00
|
|
|
|
2011-10-01 19:40:22 +00:00
|
|
|
SequelizeAdapter.prototype.model = function getModel(name) {
|
|
|
|
return this._models[name];
|
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.cleanup = function (model, obj) {
|
|
|
|
if (!obj) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
var def = this._modelDefinitions[model];
|
|
|
|
var data = {};
|
|
|
|
Object.keys(def).concat(['id']).forEach(function (key) {
|
|
|
|
data[key] = obj[key];
|
|
|
|
});
|
|
|
|
return data;
|
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.save = function (model, data, callback) {
|
|
|
|
this.model(model).find(data.id)
|
|
|
|
.on('success', function (record) {
|
|
|
|
record.updateAttributes(data)
|
|
|
|
.on('success', callback.bind(data, null))
|
|
|
|
.on('failure', callback);
|
|
|
|
})
|
|
|
|
.on('failure', callback);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.updateAttributes = function (model, id, data, callback) {
|
|
|
|
data.id = id;
|
|
|
|
this.save(model, data, callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.create = function (model, data, callback) {
|
|
|
|
this.model(model)
|
|
|
|
.build(data)
|
|
|
|
.save()
|
|
|
|
.on('success', function (obj) {
|
|
|
|
callback(null, obj.id);
|
|
|
|
})
|
|
|
|
.on('failure', callback);
|
|
|
|
};
|
|
|
|
|
2011-10-05 20:33:07 +00:00
|
|
|
SequelizeAdapter.prototype.freezeSchema = function () {
|
|
|
|
Object.keys(this._modelDefinitions).forEach(function (m) {
|
|
|
|
this.defineSequelizeModel(m);
|
|
|
|
}.bind(this));
|
|
|
|
};
|
|
|
|
|
2011-10-01 19:40:22 +00:00
|
|
|
SequelizeAdapter.prototype.automigrate = function (cb) {
|
|
|
|
this.client.sync({force: true})
|
|
|
|
.on('success', cb.bind(this, null))
|
|
|
|
.on('failure', cb);
|
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.exists = function (model, id, callback) {
|
|
|
|
this.model(model)
|
|
|
|
.find(id)
|
|
|
|
.on('success', function (data) {
|
|
|
|
if (callback) {
|
|
|
|
callback.calledOnce = true;
|
|
|
|
callback(null, data);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.on('failure', co(callback));
|
|
|
|
};
|
|
|
|
|
|
|
|
function co(cb, args) {
|
|
|
|
|
|
|
|
return function () {
|
|
|
|
if (!cb.calledOnce) {
|
|
|
|
cb.calledOnce = true;
|
|
|
|
cb.call.apply(cb, args || []);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.find = function find(model, id, callback) {
|
|
|
|
this.model(model)
|
|
|
|
.find(id)
|
|
|
|
.on('success', function (data) {
|
|
|
|
callback(null, this.cleanup(model, data));
|
|
|
|
}.bind(this))
|
|
|
|
.on('failure', callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.destroy = function destroy(model, id, callback) {
|
|
|
|
this.model(model)
|
|
|
|
.find(id)
|
|
|
|
.on('success', function (data) {
|
|
|
|
data.destroy()
|
|
|
|
.on('success', callback.bind(null, null))
|
|
|
|
.on('failure', callback);
|
|
|
|
}.bind(this))
|
|
|
|
.on('failure', callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.all = function all(model, filter, callback) {
|
|
|
|
this.model(model).all.on('success', function (data) {
|
|
|
|
// TODO: filter
|
2011-10-05 20:33:07 +00:00
|
|
|
callback(null, filter ? data.filter(applyFilter(filter)) : data);
|
2011-10-01 19:40:22 +00:00
|
|
|
}).on('failure', callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
function applyFilter(filter) {
|
2011-11-04 07:30:25 +00:00
|
|
|
if (typeof filter.where === 'function') {
|
|
|
|
return filter.where;
|
2011-10-01 19:40:22 +00:00
|
|
|
}
|
2011-11-04 07:30:25 +00:00
|
|
|
var keys = Object.keys(filter.where || {});
|
2011-10-01 19:40:22 +00:00
|
|
|
return function (obj) {
|
|
|
|
var pass = true;
|
|
|
|
keys.forEach(function (key) {
|
2011-11-04 07:30:25 +00:00
|
|
|
if (!test(filter.where[key], obj[key])) {
|
2011-10-01 19:40:22 +00:00
|
|
|
pass = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return pass;
|
|
|
|
}
|
|
|
|
|
|
|
|
function test(example, value) {
|
|
|
|
if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
|
|
|
|
return value.match(example);
|
|
|
|
}
|
|
|
|
// not strict equality
|
|
|
|
return example == value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.destroyAll = function destroyAll(model, callback) {
|
2011-10-05 20:33:07 +00:00
|
|
|
var wait;
|
|
|
|
this.model(model)
|
|
|
|
.all
|
|
|
|
.on('success', function (data) {
|
|
|
|
wait = data.length;
|
|
|
|
data.forEach(function (obj) {
|
|
|
|
obj.destroy()
|
|
|
|
.on('success', done)
|
|
|
|
.on('false', error)
|
|
|
|
});
|
|
|
|
}.bind(this))
|
|
|
|
.on('failure', callback);
|
|
|
|
|
|
|
|
var err = null;
|
|
|
|
function done() {
|
|
|
|
if (--wait === 0) callback(err);
|
|
|
|
}
|
|
|
|
function error(e) {
|
|
|
|
err = e;
|
|
|
|
if (--wait === 0) callback(err);
|
|
|
|
}
|
2011-10-01 19:40:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
SequelizeAdapter.prototype.count = function count(model, callback) {
|
|
|
|
this.model(model).count()
|
|
|
|
.on('success', function (c) {
|
|
|
|
if (callback) callback(null, c);
|
|
|
|
})
|
|
|
|
.on('failure', callback);
|
|
|
|
};
|
|
|
|
|