miridoo-js-orm
Version:
miridoo javascript orm for database
337 lines (304 loc) • 12.1 kB
JavaScript
var Table = require(__dirname+'/../sgbd/Table');
var ShemaBuilder = require(__dirname+'/ShemaBuilder');
var QueryBuilder = require(__dirname+'/QueryBuilder');
function getOrmType(type){
if(type == 'varchar') return 'string';
if(type == 'enum') return 'choice';
return type;
}
function fromEnum(str){
var r = str.split(',').map(function(value){
if((value[0] == '\'' && value[value.length-1] == '\'') || (value[0] == '"' && value[value.length-1] == '"'))
value = value.substr(1, value.length-2);
return value;
});
return r;
}
var MySqlTable = function($name, $connection){
Table.apply(this, arguments);
this.$primaryColumn = 'id';
this.$relations = [];
this.$proxy = {
$original : [],
$yield : 0,
$set : {}
};
var self = this;
$name = ($name || '').toLowerCase();
//contain all query who must be execute
this.queue = [];
this.$QueryBuilder = function(){
var r = new QueryBuilder($name, $name);
r.$builder = new MySqlTable($name, $connection);
return r;
};
this.alter = function(schema){
var rschema = {};
for(var i in schema)
rschema[i] = (typeof schema[i] == 'function')?schema[i]().get():schema[i].get();
return new Promise(function(resolve, reject){
self.schema().then(function(columns){
var make = [];
var fromTable = Object.keys(columns);
for(var col in fromTable){
if(!rschema[fromTable[col]]){
make.push('DROP COLUMN '+fromTable[col]);
}
}
for(var col in rschema){
if(columns[col]){
if(
(rschema[col].type != columns[col].type)
||
(rschema[col].default != columns[col].default && rschema[col].default != undefined)
||
(rschema[col].null != columns[col].null && rschema[col].null != undefined)
||
(rschema[col].size != columns[col].size && rschema[col].type != 'enum')
||
(rschema[col].values != columns[col].values && rschema[col].type == 'enum')
) make.push('CHANGE '+col+' '+col+' '+ShemaBuilder(schema[col], col));
}else make.push('ADD COLUMN '+col+' '+ShemaBuilder(schema[col], col));
}
var i = 0;
var fn = function(){
if(i >= make.length)
return resolve()
self.$sql.query('ALTER TABLE '+$name+' '+make[i], {}, function(rsp, err){
if(err) throw new Error(err);
fn(i++);
});
};
if(make.length > 0) fn();
else resolve();
//build the query
}).catch(reject);
});
};
this.create = function(schema, autoUpdate){
return new Promise(function(resolve, reject){
self.$sql.tables().then(function(r){
if(r.indexOf($name) != -1){
if(autoUpdate)
self.alter(schema).then(resolve).catch(reject);
else
resolve();
}
else{
var query = [];
for(var i in schema)
query.push(i+' '+ShemaBuilder(schema[i], i));
$connection.query('CREATE TABLE IF NOT EXISTS '+$name+'('+query.join(',')+')', function(res, err){
if(err) reject(err);
else resolve(res);
});
}
}).catch(reject);
});
};
this.drop = function(){
return new Promise(function(resolve, reject){
$connection.query('DROP TABLE IF EXISTS '+$name, function(res, err){
if(err) reject(err);
else resolve(res);
});
});
};
this.rename = function(newname){
return new Promise(function(resolve, reject){
$connection.query('RENAME TABLE '+$name+' TO '+newname, function(res, err){
if(err) reject(err);
else{
$name = newname;
resolve(res);
}
});
});
};
this.clone = function(newtable, data){
var sql = 'CREATE TABLE '+newtable+' LIKE '+$name;
if(data === true)
sql = 'CREATE TABLE '+newtable+' AS SELECT * FROM '+$name;
return new Promise(function(resolve, reject){
$connection.query(sql, function(res, err){
if(err) reject(err);
else{
resolve(new MySqlTable(newtable));
}
});
});
};
this.delete = function(where, params, uquer){
return new Promise(function(resolve, reject){
var query = '';
if(typeof where == 'function'){
var x = new QueryBuilder($name, $name);
where(x);
query = x.toString();
params = x.params;
}else if(!uquer){
query = 'DELETE FROM '+$name+' '+(where?'WHERE '+where:'');
}
$connection.query(query, params || {}, function(res, err){
if(err) reject(err);
else{
resolve(res);
}
});
});
};
this.reset = function(){
return new Promise(function(resolve, reject){
$connection.query('TRUNCATE '+$name, function(res, err){
if(err) reject(err);
else{
resolve(res);
}
});
});
};
this.all = function(query, params){
return this.get(query, params);
};
this.get = function(query, params, uquer){
return new Promise(function(resolve, reject){
query = (self.$where?'WHERE '+self.$where:'')+self.$query+(query || '');
if(typeof query == 'function'){
var x = new QueryBuilder($name, $name);
query(x);
query = x.toString();
params = x.params;
}else if(!uquer){
query = 'SELECT '+self.only()+' FROM '+$name+' '+query;
}
$connection.query(query, params || {}, function(res, err){
if(err) reject(err);
else{
for(var i in res){
for(var j in self.$relationsUes){
self.$relationsUes[j].push(res[i][j]);
}
}
self.$hrefBuilder(res, function(){
self.$cleanRelation();
self.$proxy.$original = res;
resolve(res);
});
}
});
});
};
this.schema = function(){
return new Promise(function(resolve, reject){
$connection.query('DESCRIBE '+$name, function(res, err){
if(err) reject(err);
else{
var r = {}, x = null, type = '';
for(var i in res){
x = res[i];
type = {type : '', size : 0};
x.Type.replace(/([a-z]+)\(([\s\S]+)\)/ig, function(all, t, s){
type = {type : t, size : s};
});
if(!type.type) type.type = x.Type;
r[x.Field] = {
type : getOrmType(type.type),
size : parseInt((type.type != 'enum')?type.size:''),
value : (type.type == 'enum')?fromEnum(type.size):'',
unsigned : (new RegExp(/unsigned/)).test(x.Type),
null : (x.Null == 'YES'),
default : x.Default,
pk : (x.Key == 'PRI'),
increment : (r.Extra == 'auto_increment')
};
}
resolve(r);
}
});
});
};
this.save = function(json){
json = json || {};
var keys = Object.keys(json);
return new Promise(function(resolve, reject){
$connection.query('INSERT INTO '+$name+'('+keys.join(',')+') VALUES (:'+keys.join(', :')+')', json , function(res, err){
if(err) reject(err);
else{
resolve(res);
}
});
});
};
this.msave = function(){
var values = [], valuesData = {};
var args = Array.from(arguments);
var keys = Object.keys(args[0]);
args.map(function(obj, index){
var r = {}, k = '', lkeys = [];
for(var key in obj){
k = key+'_'+index;
lkeys.push(k);
valuesData[k] = obj[key];
}
values.push('(:'+lkeys.join(', :')+')');
return obj;
});
return new Promise(function(resolve, reject){
$connection.query('INSERT INTO '+$name+'('+keys.join(',')+') VALUES '+values.join(','), valuesData , function(res, err){
if(err) reject(err);
else{
resolve(res);
}
});
});
};
this.link = function(name, relation){
//name is the var name in the result object
self.$relationsUes[relation.use] = [];
this.$relations.push({
auto : relation.auto,
name : name,
call : function(next){
relation.only = relation.only || [];
if(relation.only.length > 0 && relation.only[0] != '*' && relation.only.indexOf(relation.column) == -1)
relation.only.push(relation.column);
$connection.query('SELECT '+((relation.only && relation.only.length > 0)?relation.only.join(','):'*')+' FROM '+relation.to+' WHERE '+relation.column+' IN ('+(self.$relationsUes[relation.use].join(','))+')', function(res, err){
if(err) next(err);
else{
next(name, res, relation);
}
});
}
});
return this;
};
this.column = function(){
return new Column($name, $connection);
};
/*
* simple query maker
*/
this.first = function(nb){
nb = nb || 1;
this.$query += ' ORDER BY '+self.$primaryColumn+' ASC LIMIT 0, '+nb;
return new Promise(function(resolve, reject){
self.get().then(function(r){
resolve((r.length > 0 && nb == 1)?r[0]:r);
}).catch(reject)
});
};
this.last = function(nb){
nb = nb || 1;
this.$query += ' ORDER BY '+self.$primaryColumn+' DESC LIMIT 0, '+nb;
return new Promise(function(resolve, reject){
self.get().then(function(r){
resolve((r.length > 0 && nb == 1)?r[0]:r);
}).catch(reject)
});
};
this.each = function(calback){
this.$proxy.$original.forEach(calback);
return this;
};
};
module.exports = MySqlTable;