不要怂,就是干,撸起袖子干!

Commit 337e40a1 by Sascha Depold

removed old shit

1 parent 05c879a3
Showing with 233 additions and 1146 deletions
var reader = require('./serializers').reader;
var writer = require('./serializers').writer;
var cmd = require('./commands');
var net = require('net');
var sys = require('sys');
var queue = require('./containers').queue;
function packetLength(data)
{
var len = data.charCodeAt(0);
len += (data.charCodeAt(1) << 8);
len += (data.charCodeAt(2) << 16);
return len;
}
exports.createTCPClient = function(host, port)
{
var host = host ? host : "localhost";
var port = port ? port : 3306;
var connection = net.createConnection(port, host);
connection.pscache = {};
connection.setEncoding("binary");
connection.setTimeout(0);
return new socketClient(connection);
}
exports.createUNIXClient = function(path)
{
var path = path ? path : "/var/run/mysqld/mysqld.sock";
var connection = net.createConnection(path);
connection.pscache = {};
connection.setEncoding("binary");
connection.setTimeout(0);
return new socketClient(connection);
}
function dump(d)
{
return;
for (var i=0; i < d.length; ++i)
{
sys.puts(i.toString() + " " + d.charAt(i) + " " + d.charCodeAt(i).toString());
}
}
socketClient = function(connection)
{
var client = this;
this.commands = new queue();
this.connection = connection;
connection.buffer = "";
// TODO: fold following code into somthing without copy-paste
this.close = function()
{
return this.add(new cmd.close());
}
this.debug = function( text )
{
return this.add(new cmd.debug(text));
}
this.auth = function(dbname, user, password)
{
return this.add(new cmd.auth(dbname, user, password));
}
this.query = function(q)
{
return this.add(new cmd.query(q));
}
this.prepare = function(q)
{
return this.add(new cmd.prepare(q));
}
// TODO: too many copy-paste, cleanup
this.execute = function(q, parameters)
{
if (!this.pscache)
this.pscache = {};
if (this.auto_prepare == true)
{
var cached = this.connection.pscache[q];
if (!cached) {
var prepare_cmd = this.add(new cmd.prepare(q));
var execute_cmd = this.add(new cmd.execute(q, parameters));
prepare_cmd.addListener('prepared', function(ps) { execute_cmd.ps = ps; });
prepare_cmd.addListener('error', function(err)
{
execute_cmd.emit('error', err);
execute_cmd.prepare_failed = true;
});
return execute_cmd;
} else {
var execute_cmd = this.add(new cmd.execute(q, parameters));
execute_cmd.ps = cached;
return execute_cmd;
}
}
return this.add(new cmd.execute(q, parameters));
}
this.terminate = function()
{
this.connection.end();
}
this.write_packet = function(packet, pnum)
{
packet.addHeader(pnum);
this.connection.write(packet.data, 'binary');
}
this.dispatch_packet = function(packet)
{
if (this.commands.empty())
return;
if (this.commands.top().process_packet(packet))
{
this.commands.shift();
this.connection.emit('queue', this.commands.length);
this.dispatch_packet();
}
}
// proxy request to socket eventemitter
this.on = this.addListener = function()
{
this.connection.addListener.apply(this.connection, arguments);
}
this.add = function(c)
{
c.connection = this;
var need_start_queue = this.connection.connected && this.commands.empty();
this.commands.push(c);
this.connection.emit('queue', this.commands.length);
if (need_start_queue)
this.dispatch_packet();
var connection = this.connection;
//c.addListener('end', function(cmd) { connection.emit('command_end', c); });
//c.addListener('error', function(e) { sys.puts(e.message); }); // TODO: throw exception
return c;
}
this.connection.addListener("data",
function(data)
{
// TODO: move to 'onconnect' event
// replace connected with 'first packet' or 'ready state' or smth similar
if (!this.connected)
{
this.connected = true;
client.dispatch_packet();
}
this.buffer += data;
var len = packetLength(this.buffer);
while (this.buffer.length >= len + 4)
{
var packet = this.buffer.substr(4,len);
client.dispatch_packet(new reader(packet) );
this.buffer = this.buffer.substr(len+4, this.buffer.length-len-4);
len = packetLength(this.buffer);
}
}
);
return client;
}
var flags = exports.flags =
{
CLIENT_LONG_PASSWORD: 1 ,/* new more secure passwords */
CLIENT_FOUND_ROWS: 2 ,/* Found instead of affected rows */
CLIENT_LONG_FLAG: 4 ,/* Get all column flags */
CLIENT_CONNECT_WITH_DB: 8 ,/* One can specify db on connect */
CLIENT_NO_SCHEMA: 16 ,/* Don't allow database.table.column */
CLIENT_COMPRESS: 32 ,/* Can use compression protocol */
CLIENT_ODBC: 64 ,/* Odbc client */
CLIENT_LOCAL_FILES: 128 ,/* Can use LOAD DATA LOCAL */
CLIENT_IGNORE_SPACE: 256 ,/* Ignore spaces before '(' */
CLIENT_PROTOCOL_41: 512 ,/* New 4.1 protocol */
CLIENT_INTERACTIVE: 1024 ,/* This is an interactive client */
CLIENT_SSL: 2048 ,/* Switch to SSL after handshake */
CLIENT_IGNORE_SIGPIPE: 4096 ,/* IGNORE sigpipes */
CLIENT_TRANSACTIONS: 8192 ,/* Client knows about transactions */
CLIENT_RESERVED: 16384 ,/* Old flag for 4.1 protocol */
CLIENT_SECURE_CONNECTION: 32768 ,/* New 4.1 authentication */
CLIENT_MULTI_STATEMENTS: 65536 ,/* Enable/disable multi-stmt support */
CLIENT_MULTI_RESULTS: 131072 /* Enable/disable multi-results */
}
exports.field_flags =
{
NOT_NULL: 1, /* Field can't be NULL */
PRI_KEY: 2, /* Field is part of a primary key */
UNIQUE_KEY: 4, /* Field is part of a unique key */
MULTIPLE_KEY: 8, /* Field is part of a key */
BLOB: 16, /* Field is a blob */
UNSIGNED: 32, /* Field is unsigned */
ZEROFILL: 64, /* Field is zerofill */
BINARY: 128,
}
exports.flags.CLIENT_BASIC_FLAGS = flags.CLIENT_LONG_PASSWORD |
flags.CLIENT_FOUND_ROWS |
flags.CLIENT_LONG_FLAG |
flags.CLIENT_CONNECT_WITH_DB |
flags.CLIENT_ODBC |
flags.CLIENT_LOCAL_FILES |
flags.CLIENT_IGNORE_SPACE |
flags.CLIENT_PROTOCOL_41 |
flags.CLIENT_INTERACTIVE |
flags.CLIENT_IGNORE_SIGPIPE |
flags.CLIENT_TRANSACTIONS |
flags.CLIENT_RESERVED |
flags.CLIENT_SECURE_CONNECTION |
flags.CLIENT_MULTI_STATEMENTS |
flags.CLIENT_MULTI_RESULTS;
exports.types =
{
MYSQL_TYPE_DECIMAL: 0,
MYSQL_TYPE_TINY: 1,
MYSQL_TYPE_SHORT: 2,
MYSQL_TYPE_LONG: 3,
MYSQL_TYPE_FLOAT: 4,
MYSQL_TYPE_DOUBLE: 5,
MYSQL_TYPE_NULL: 6,
MYSQL_TYPE_TIMESTAMP: 7,
MYSQL_TYPE_LONGLONG: 8,
MYSQL_TYPE_INT24: 9,
MYSQL_TYPE_DATE: 10,
MYSQL_TYPE_TIME: 11,
MYSQL_TYPE_DATETIME: 12,
MYSQL_TYPE_YEAR: 13,
MYSQL_TYPE_NEWDATE: 14,
MYSQL_TYPE_VARCHAR: 15,
MYSQL_TYPE_BIT: 16,
MYSQL_TYPE_NEWDECIMAL: 246,
MYSQL_TYPE_ENUM: 247,
MYSQL_TYPE_SET: 248,
MYSQL_TYPE_TINY_BLOB: 249,
MYSQL_TYPE_MEDIUM_BLOB: 250,
MYSQL_TYPE_LONG_BLOB: 251,
MYSQL_TYPE_BLOB: 252,
MYSQL_TYPE_VAR_STRING: 253,
MYSQL_TYPE_STRING: 254,
MYSQL_TYPE_GEOMETR: 255
};
exports.type_names = {};
for (var tname in exports.types)
{
if(exports.types.hasOwnProperty(tname) )
{
var type = exports.types[tname];
exports.type_names[type] = tname;
}
}
// doubly-linked list for constant time shift
// each node have prev,next,data properties
var sys = require('sys');
function deque()
{
this.begin = null;
this.end = null;
this.length = 0;
}
deque.prototype.push = function(data)
{
if (!this.begin) // insert into empty list
{
this.begin = this.end = { 'data': data };
this.begin.next = this.begin;
this.begin.prev = this.begin;
} else {
var end = this.end;
this.end = { 'data': data };
this.end.prev = end;
end.next = this.end;
}
++this.length;
return this;
}
deque.prototype.top = function()
{
if (this.begin)
return this.begin.data;
}
deque.prototype.empty = function()
{
return this.length == 0;
}
deque.prototype.shift = function()
{
--this.length;
if (this.begin == this.end)
{
this.begin = this.end = null;
return this.begin;
}
var res = this.begin.data;
this.begin = this.begin.next;
return res;
}
exports.queue = deque;
var client = require('./client');
var pool = require('./pool');
exports.createClient = client.createClient;
exports.createTCPClient = client.createTCPClient;
exports.createUNIXClient = client.createUNIXClient;
exports.pool = pool.pool;
var queue = require('./containers').queue;
var sys= require('sys');
function pool(newConnectionFactory, minConnections)
{
this.newConnectionFactory = newConnectionFactory;
// some reasonable defaults
if (minConnections)
this.minConnections = minConnections; // lazy by default
else
this.minConnections = 0;
this.maxConnections = 16;
this.maxQueue = 2; // increase if average command time is much shorter compared to connect time
// TODO: calculate ratio on the fly? think of adaptiveMaxQueue
this.idleTimeout = 0; // TODO: also possible to make adaptive
this.maxWaiters = 100000000; // TODO: infinity?
this.waiters = new queue();
this.connections = new queue();
for (var i=0; i <= this.minConnections; ++i)
this.spawnConnection();
}
pool.prototype.spawnConnection = function()
{
var client = this.newConnectionFactory();
var self = this;
// todo: Qt-style connection-slot api?
client.connection.addListener('queue', function(new_size) { self.queueChanged(client, new_size); });
var node = this.connections.push(client);
client.pool_node = node;
return client;
}
pool.prototype.queueChanged = function(client, new_size)
{
if (new_size != 0)
return;
sys.puts('queue event ' + new_size);
//var new_size = client.commands.length;
// if (new_size == 1)
// sys.p(client.commands.begin.data);
// sys.puts("New queue:" + new_size);
if (!this.waiters.empty() && new_size == 0) //<= this.maxQueue)
{
var w = this.waiters.shift();
sys.puts("free connection released to waiter" );
if (w)
w(client);
}
// there is no commands left for current connection
// close it after idleTimeout
if (new_size == 0 && this.connections.length > this.minConnections)
{
if (this.idleTimeout > 0)
{
//todo: add close timer
} else {
client.close();
}
}
// calculate new index
}
pool.prototype.get = function(onClientReady)
{
sys.puts("=== pool::get === ");
// select client with minimal queue
// if its queue length <= maxQueue, return it
// if connections size less than maxConnection, spawn a new connection
// else enqueue request
// throw error if waiters queue length > maxWaiters
// quick hack
// TODO: add search using index
var minQueueConnection = null;
var minQueue = 1000000000;
for (var i = this.connections.begin; i != this.connections.end; i = i.next)
{
var cli = i.data;
var len = cli.commands.length;
sys.puts("client q:" + len);
if (len < minQueue)
{
minQueue = len;
minQueueConnection = cli;
}
}
sys.puts("min pool queue is " + minQueue);
if (minQueue <= this.maxQueue)
{
sys.puts("using existing connection");
return onClientReady(minQueueConnection);
}
if (this.connections.length < this.maxConnections)
{
sys.puts("sapwning new connection");
return onClientReady(this.spawnConnection());
}
if (this.waiters.length < this.maxWaiters)
{
sys.puts("waiting for awailable connection");
this.waiters.push(onClientReady);
return;
}
}
/*
pool.prototype.close = function()
{
for (var i = this.connections.begin; i != this.connections.end; i = i.next)
{
i.data.close();
}
}
*/
exports.pool = pool;
var sys = require('sys');
var constants = require('./constants');
function writer()
{
this.data = "";
}
writer.prototype.zstring = function(s)
{
this.data += s + "\u0000";
return this;
}
//
// length-coded number
//
// Value Of # Of Bytes Description
// First Byte Following
// ---------- ----------- -----------
// 0-250 0 = value of first byte
// 251 0 column value = NULL
// only appropriate in a Row Data Packet
// 252 2 = value of following 16-bit word
// 253 3 = value of following 24-bit word
// 254 8 = value of following 64-bit word
//
writer.prototype.lcnum = function(n)
{
if (n < 251)
this.data += String.fromCharCode(n);
else if (n < 0xffff)
{
this.data += String.fromCharCode(252);
this.data += String.fromCharCode( n & 0xff );
this.data += String.fromCharCode( (n >> 8) & 0xff );
} else if (n < 0xffffff)
{
this.data += String.fromCharCode(253);
this.data += String.fromCharCode( n & 0xff );
this.data += String.fromCharCode( (n >> 8) & 0xff );
this.data += String.fromCharCode( (n >> 16) & 0xff );
}
/*
TODO: 64 bit number
*/
return this;
}
//
// write length-coded string to the buffer
//
writer.prototype.lcstring = function(s)
{
this.lcnum(s.length);
this.data += s;
return this;
}
writer.prototype.add = function(s)
{
if (typeof s == "string") // add string bufer
this.data += s;
else if (typeof s == "number") // add four byte integer
{
this.data += String.fromCharCode( s & 0xff );
this.data += String.fromCharCode( (s >> 8) & 0xff );
this.data += String.fromCharCode( (s >> 16) & 0xff );
this.data += String.fromCharCode( (s >> 24) & 0xff );
}
return this;
}
writer.prototype.int2 = function(s)
{
this.data += String.fromCharCode( s & 0xff );
this.data += String.fromCharCode( (s >> 8) & 0xff );
}
writer.prototype.addHeader = function(n)
{
var length = this.data.length;
var header = "";
header += String.fromCharCode( length & 0xff );
header += String.fromCharCode( length>>8 & 0xff );
header += String.fromCharCode( length>>16 & 0xff );
var packet_num = n ? n : 0;
header += String.fromCharCode( packet_num );
this.data = header + this.data;
return this;
}
function reader(data)
{
this.data = data;
this.pos = 0;
}
reader.prototype.dump = function()
{
for (var i=this.pos; i < this.data.length; ++i)
{
sys.puts(this.data.charCodeAt(i));
}
}
// libmysql sets all fields to zero when binary packet has zero length
function zeroTime()
{
// todo: check how zero date is serialized to output in mysql
return new Date();
}
reader.prototype.unpackBinaryTime = function()
{
var length = this.lcnum();
if (length == 0)
return zeroTime();
var sign = this.num(1);
var day = this.num(4);
var hour = this.num(1);
var minutes = this.num(1);
var seconds = this.num(1);
var millisec = (length > 8) ? this.num(4) : 0;
if (day != 0)
hour += day*24;
var millisec_time_val = millisec + seconds*1000 + minutes*60000 + hour*3600000;
if (sign != 0)
millisec_time_val *= -1;
return millisec_time_val;
}
reader.prototype.unpackBinaryDateTime = function()
{
var length = this.lcnum();
if (length == 0)
return zeroTime();
var y = this.num(2);
var m = this.num(1);
var d = this.num(1);
var hour = 0;
var min = 0;
var sec = 0;
if (length > 4)
{
hour = this.num(1);
min = this.num(1);
sec = this.num(1);
}
var millisec = (length > 8) ? this.num(4) : 0;
var dt = new Date();
dt.setYear(y);
dt.setMonth(m);
dt.setDate(d);
dt.setHours(hour);
dt.setMinutes(min);
dt.setSeconds(sec);
dt.setMilliseconds(millisec);
return dt;
}
reader.prototype.unpackBinaryDate = function()
{
var length = this.lcnum();
if (length == 0)
return zeroTime();
var y = this.num(2);
var m = this.num(1);
var d = this.num(1);
var dt = new Date();
dt.setYear(y);
dt.setMonth(m);
dt.setDate(d);
return dt;
}
function parseIEEE754Double(data)
{
var fraction = 0.0;
fraction += data.charCodeAt(2) / ( 16 * 256 * 256 * 256 * 256 * 256 * 256);
fraction += data.charCodeAt(3) / ( 16 * 256 * 256 * 256 * 256 * 256 );
fraction += data.charCodeAt(4) / ( 16 * 256 * 256 * 256 * 256 );
fraction += data.charCodeAt(5) / ( 16 * 256 * 256 * 256);
fraction += data.charCodeAt(6) / ( 16 * 256 * 256 );
fraction += data.charCodeAt(7) / ( 16 * 256 );
fraction += (data.charCodeAt(8) & 0x0f) / 16.0;
var signbit = data.charCodeAt(9) & 128;
var exponent = ((data.charCodeAt(8) & 0xf0) >> 4) + ((data.charCodeAt(9) & 127) << 4);
var factor = Math.pow(2,exponent-1023);
var mantissa = 1.0 + fraction;
var sign = signbit > 0 ? -1 : 1;
return sign*factor*mantissa;
}
// deserialise mysql binary field
reader.prototype.unpackBinary = function(type, unsigned)
{
// debug dump
//return "_not_implemented_ " + constants.type_names[type] + " " + sys.inspect(this.data);
var result;
switch (type)
{
case constants.types.MYSQL_TYPE_STRING:
case constants.types.MYSQL_TYPE_VAR_STRING:
case constants.types.MYSQL_TYPE_BLOB:
result = this.lcstring();
break;
case constants.types.MYSQL_TYPE_LONG:
result = this.num(4);
break;
case constants.types.MYSQL_TYPE_LONGLONG:
result = this.num(8);
break;
case constants.types.MYSQL_TYPE_NEWDECIMAL:
result = parseFloat(this.lcstring());
break;
case constants.types.MYSQL_TYPE_DOUBLE:
result = parseIEEE754Double(this.data);
break;
/*
MYSQL_TYPE_TIMESTAMP: 7,
MYSQL_TYPE_LONGLONG: 8,
MYSQL_TYPE_INT24: 9,
MYSQL_TYPE_DATE: 10,
MYSQL_TYPE_TIME: 11,
MYSQL_TYPE_DATETIME: 12,
MYSQL_TYPE_YEAR: 13,
MYSQL_TYPE_NEWDATE: 14,
*/
case constants.types.MYSQL_TYPE_DATE:
return this.unpackBinaryDate();
case constants.types.MYSQL_TYPE_TIME:
return this.unpackBinaryTime();
case constants.types.MYSQL_TYPE_DATETIME:
case constants.types.MYSQL_TYPE_TYMESTAMP:
return this.unpackBinaryDateTime();
default:
result = "_not_implemented_ " + constants.type_names[type] + " " + sys.inspect(this.data); //todo: throw exception here
}
return result;
}
// read n-bytes number
reader.prototype.num = function(numbytes)
{
var res = 0;
var factor = 1;
for (var i=0; i < numbytes; ++i)
{
res += this.data.charCodeAt(this.pos) * factor;
factor = factor << 8;
this.pos++;
}
return res;
}
reader.prototype.field = function()
{
var field = {};
field.catalog = this.lcstring();
field.db = this.lcstring();
field.table = this.lcstring();
field.org_table = this.lcstring();
field.name = this.lcstring();
field.org_name = this.lcstring();
field.filler = this.num(1);
field.charsetnum = this.num(2);
field.length = this.num(4);
field.type = this.num(1);
field.flags = this.num(2);
field.decimals = this.num(1);
field.filler = this.num(2);
field.defval = this.lcstring();
return field;
}
function binary(n)
{
var res = "";
var nbits = 0;
while(n != 0)
{
var bit = n - Math.floor(n/2)*2;
res = bit + res;
n = Math.floor(n/2);
nbits++;
}
for(; nbits <= 8; ++nbits)
res = "0" + res;
return res;
}
reader.prototype.zstring = function()
{
var res = "";
var c;
while(c = this.data.charCodeAt(this.pos++))
{
res += String.fromCharCode(c);
}
return res;
}
reader.prototype.lcstring = function()
{
var len = this.lcnum();
var res = this.bytes(len);
return res;
}
reader.prototype.isEOFpacket = function()
{
return this.data.charCodeAt(0) == 254 && this.data.length < 9
}
reader.prototype.eof = function()
{
return this.pos >= this.data.length;
}
reader.prototype.tail = function()
{
var res = this.data.substr(this.pos, this.data.length - this.pos);
this.pos = this.data.length;
return res;
}
reader.prototype.isErrorPacket = function()
{
return this.data.charCodeAt(0) == 0xff;
}
reader.prototype.readOKpacket = function()
{
var res = {};
res.field_count = this.data.charCodeAt(this.pos++);
if (res.field_count == 0xff) // error
{
res.errno = this.data.charCodeAt(this.pos) + (this.data.charCodeAt(this.pos+1)<<8);
this.pos += 8;
//this.pos++; // skip sqlstate marker, "#"
//res.sqlstate = this.bytes(5);
} else {
res.affected_rows = this.lcnum();
res.insert_id = this.lcnum();
res.server_status = this.num(2);
res.warning_count = this.num(2);
}
res.message = this.tail();
return res;
}
reader.prototype.lcnum = function()
{
var b1 = this.data.charCodeAt(this.pos);
this.pos++;
if (b1 < 251)
return b1;
else if (b1 == 252)
return this.num(2);
else if (b1 == 253)
return this.num(3);
else if (b1 == 254)
return this.num(8);
}
reader.prototype.readPacketHeader = function()
{
var res = { length: 0, packetNum:0 };
res.length += this.data.charCodeAt(0);
res.length += this.data.charCodeAt(1) << 8;
res.length += this.data.charCodeAt(2) << 16;
res.packetNum = this.data.charCodeAt(3);
this.pos += 4;
return res;
}
reader.prototype.bytes = function(n)
{
var res = "";
var end = this.pos+n;
while(this.pos < end)
{
res += this.data.charAt(this.pos);
this.pos++;
}
return res;
}
exports.reader = reader;
exports.writer = writer;
// wrappers to provide WebSql-alike interface to mysql
var createTCPClient = require('./client').createTCPClient;
var sys = require('sys');
function transaction(connection)
{
this.connection = connection;
}
transaction.prototype.executeSql = function (query, args, rsCallback, errorCallback)
{
var tx = this;
if (!tx.clean)
{
sys.puts("skipped due to errors");
return;
}
var execCmd = this.connection.execute(query, args);
var results = {};
results.rows = [];
this.connection.row_as_hash = true;
execCmd.addListener('row', function(r) {
results.rows.push(r);
});
execCmd.addListener('end', function() { if (tx.clean && rsCallback) rsCallback(tx, results); });
execCmd.addListener('error', function(err)
{
tx.clean = false;
if (errorCallback)
errorCallback(tx, err);
if (tx.onerror)
tx.onerror(err);
});
tx.last_exec_cmd = execCmd;
}
exports.openDatabase = function(db, user, password)
{
var webdb = {};
var connection = createTCPClient();
connection.auth(db, user, password);
connection.query('SET autocommit=0;');
connection.auto_prepare = true;
webdb.transaction = function(txCreated, txError)
{
var t = new transaction(connection);
t.onerror = txError;
connection.query('BEGIN');
t.clean = true;
txCreated(t);
var commit = connection.query("");
t.last_exec_cmd.addListener('end', function()
{
commit.sql = t.clean ? "COMMIT" : "ROLLBACK"
});
}
webdb.close = function() { connection.close(); };
return webdb;
}
var Sequelize = function(database, username, password, options) {
options = options || {}
this.tables = {}
this.options = Sequelize.Helper.Hash.without(options, ["host", "port", "disableTableNameModification"])
this.config = {
database: database,
username: username,
password: (((["", null, false].indexOf(password) > -1) || (typeof password == 'undefined')) ? null : password),
host : options.host || 'localhost',
port : options.port || 3306
}
Sequelize.Helper.configure({
disableTableNameModification: (options.disableTableNameModification || false)
})
}
var classMethods = {
Helper: new (require(__dirname + "/Helper").Helper)(Sequelize),
STRING: 'VARCHAR(255)',
TEXT: 'TEXT',
INTEGER: 'INT',
DATE: 'DATETIME',
BOOLEAN: 'TINYINT(1)',
FLOAT: 'FLOAT',
sqlQueryFor: function(command, values) {
var query = null
if(values.hasOwnProperty('fields') && Array.isArray(values.fields))
values.fields = values.fields.map(function(field) { return ['', field, ''].join('`') }).join(", ")
switch(command) {
case 'create':
query = "CREATE TABLE IF NOT EXISTS `%{table}` (%{fields})"
break
case 'drop':
query = "DROP TABLE IF EXISTS `%{table}`"
break
case 'select':
values.fields = values.fields || '*'
query = "SELECT %{fields} FROM `%{table}`"
if(values.where) {
if(Sequelize.Helper.Hash.isHash(values.where))
values.where = Sequelize.Helper.SQL.hashToWhereConditions(values.where)
query += " WHERE %{where}"
}
if(values.order) query += " ORDER BY %{order}"
if(values.group) query += " GROUP BY %{group}"
if(values.limit) {
if(values.offset) query += " LIMIT %{offset}, %{limit}"
else query += " LIMIT %{limit}"
}
break
case 'insert':
query = "INSERT INTO `%{table}` (%{fields}) VALUES (%{values})"
break
case 'update':
if(Sequelize.Helper.Hash.isHash(values.values))
values.values = Sequelize.Helper.SQL.hashToWhereConditions(values.values)
query = "UPDATE `%{table}` SET %{values} WHERE `id`=%{id}"
break
case 'delete':
if(Sequelize.Helper.Hash.isHash(values.where))
values.where = Sequelize.Helper.SQL.hashToWhereConditions(values.where)
query = "DELETE FROM `%{table}` WHERE %{where}"
if(typeof values.limit == 'undefined') query += " LIMIT 1"
else if(values.limit != null) query += " LIMIT " + values.limit
break
}
return Sequelize.Helper.evaluateTemplate(query, values)
},
chainQueries: function() {
this.Helper.QueryChainer.chain.apply(this.Helper.QueryChainer, arguments)
}
}
Sequelize.prototype = {
define: function(name, attributes, options) {
var SequelizeTable = require(__dirname + "/SequelizeTable").SequelizeTable
var _attributes = {}
var createdAt = "createdAt";
var updatedAt = "updatedAt";
if(options){
if(options.createdAt)createdAt = options.createdAt;
if(options.updatedAt)updatedAt = options.updatedAt;
}
Sequelize.Helper.Hash.forEach(attributes, function(value, key) {
if(typeof value == 'string')
_attributes[key] = { type: value }
else if((typeof value == 'object') && (!value.length))
_attributes[key] = value
else
throw new Error("Please specify a datatype either by using Sequelize.* or pass a hash!")
})
_attributes[createdAt] = { type: Sequelize.DATE, allowNull: false}
_attributes[updatedAt] = { type: Sequelize.DATE, allowNull: false}
var table = new SequelizeTable(Sequelize, this, Sequelize.Helper.SQL.asTableName(name), _attributes, options)
// refactor this to use the table's attributes
this.tables[name] = {klass: table, attributes: attributes}
table.sequelize = this
return table
},
import: function(path) {
var imported = require(path),
self = this,
result = {}
Sequelize.Helper.Hash.forEach(imported, function(definition, functionName) {
definition(Sequelize, self)
})
Sequelize.Helper.Hash.forEach(this.tables, function(constructor, name) {
result[name] = constructor.klass
})
return result
},
get tableNames() {
var result = []
Sequelize.Helper.Hash.keys(this.tables).forEach(function(tableName) {
result.push(Sequelize.Helper.SQL.asTableName(tableName))
})
return result
},
sync: function(callback) {
var finished = [],
tables = this.tables,
errors = []
Sequelize.Helper.Hash.forEach(tables, function(table) {
table.klass.prepareAssociations()
})
if((Sequelize.Helper.Hash.keys(this.tables).length == 0) && callback)
callback()
else
Sequelize.Helper.Hash.forEach(tables, function(table) {
table.klass.sync(function(_, err) {
finished.push(true)
if(err) errors.push(err)
if((finished.length == Sequelize.Helper.Hash.keys(tables).length) && callback)
callback(errors)
})
})
},
drop: function(callback) {
var finished = [],
tables = this.tables,
errors = []
if((Sequelize.Helper.Hash.keys(tables).length == 0) && callback)
callback()
else
Sequelize.Helper.Hash.forEach(tables, function(table, tableName) {
table.klass.drop(function(_, err) {
finished.push(true)
if(err) errors.push(err)
if((finished.length == Sequelize.Helper.Hash.keys(tables).length) && callback)
callback(errors)
})
})
},
query: function(queryString, callback) {
var fields = [],
values = [],
self = this,
client = require(__dirname + "/../nodejs-mysql-native/index").createTCPClient(this.config.host, this.config.port)
client.connection.on('error', function() {
callback(null, null, { message: "Unable to establish a connection to " + [self.config.host, self.config.port].join(":") })
})
client.auto_prepare = true
client
.auth(self.config.database, self.config.username, self.config.password)
.on('error', function(err) { callback(null, null, err) })
.on('authorized', function() {
if(!self.options.disableLogging)
Sequelize.Helper.log("Executing the query: " + queryString)
client
.query(queryString)
.on('error', function(err) { Sequelize.Helper.log(err) })
.on('row', function(r){ values.push(r) })
.on('field', function(f){ fields.push(f)})
.on('end', function(stats) {
if(callback) {
var result = []
values.forEach(function(valueArray) {
var mapping = {}
for(var i = 0; i < fields.length; i++)
mapping[fields[i].name] = valueArray[i]
result.push(mapping)
})
if(callback) callback(result, stats)
}
})
client.close()
})
}
}
for (var key in classMethods) Sequelize[key] = classMethods[key]
exports.Sequelize = Sequelize
\ No newline at end of file
var Sequelize = function(database, username, password, options) {
options = options || {}
this.tables = {}
this.options = Sequelize.Helper.Hash.without(options, ["host", "port", "disableTableNameModification"])
this.config = {
database: database,
username: username,
password: (((["", null, false].indexOf(password) > -1) || (typeof password == 'undefined')) ? null : password),
host : options.host || 'localhost',
port : options.port || 3306
}
Sequelize.Helper.configure({
disableTableNameModification: (options.disableTableNameModification || false)
})
}
var classMethods = {
Helper: new (require(__dirname + "/Helper").Helper)(Sequelize),
STRING: 'VARCHAR(255)',
TEXT: 'TEXT',
INTEGER: 'INT',
DATE: 'DATETIME',
BOOLEAN: 'TINYINT(1)',
FLOAT: 'FLOAT',
sqlQueryFor: function(command, values) {
var query = null
if(values.hasOwnProperty('fields') && Array.isArray(values.fields))
values.fields = values.fields.map(function(field) { return ['', field, ''].join('`') }).join(", ")
switch(command) {
case 'create':
query = "CREATE TABLE IF NOT EXISTS `%{table}` (%{fields})"
break
case 'drop':
query = "DROP TABLE IF EXISTS `%{table}`"
break
case 'select':
values.fields = values.fields || '*'
query = "SELECT %{fields} FROM `%{table}`"
if(values.where) {
if(Sequelize.Helper.Hash.isHash(values.where))
values.where = Sequelize.Helper.SQL.hashToWhereConditions(values.where)
query += " WHERE %{where}"
}
if(values.order) query += " ORDER BY %{order}"
if(values.group) query += " GROUP BY %{group}"
if(values.limit) {
if(values.offset) query += " LIMIT %{offset}, %{limit}"
else query += " LIMIT %{limit}"
}
break
case 'insert':
query = "INSERT INTO `%{table}` (%{fields}) VALUES (%{values})"
break
case 'update':
if(Sequelize.Helper.Hash.isHash(values.values))
values.values = Sequelize.Helper.SQL.hashToWhereConditions(values.values)
query = "UPDATE `%{table}` SET %{values} WHERE `id`=%{id}"
break
case 'delete':
if(Sequelize.Helper.Hash.isHash(values.where))
values.where = Sequelize.Helper.SQL.hashToWhereConditions(values.where)
query = "DELETE FROM `%{table}` WHERE %{where}"
if(typeof values.limit == 'undefined') query += " LIMIT 1"
else if(values.limit != null) query += " LIMIT " + values.limit
break
}
return Sequelize.Helper.evaluateTemplate(query, values)
},
chainQueries: function() {
this.Helper.QueryChainer.chain.apply(this.Helper.QueryChainer, arguments)
}
}
Sequelize.prototype = {
define: function(name, attributes, options) {
var SequelizeTable = require(__dirname + "/SequelizeTable").SequelizeTable
var _attributes = {}
var createdAt = "createdAt";
var updatedAt = "updatedAt";
if(options){
if(options.createdAt)createdAt = options.createdAt;
if(options.updatedAt)updatedAt = options.updatedAt;
}
Sequelize.Helper.Hash.forEach(attributes, function(value, key) {
if(typeof value == 'string')
_attributes[key] = { type: value }
else if((typeof value == 'object') && (!value.length))
_attributes[key] = value
else
throw new Error("Please specify a datatype either by using Sequelize.* or pass a hash!")
})
_attributes[createdAt] = { type: Sequelize.DATE, allowNull: false}
_attributes[updatedAt] = { type: Sequelize.DATE, allowNull: false}
var table = new SequelizeTable(Sequelize, this, Sequelize.Helper.SQL.asTableName(name), _attributes, options)
// refactor this to use the table's attributes
this.tables[name] = {klass: table, attributes: attributes}
table.sequelize = this
return table
},
import: function(path) {
var imported = require(path),
self = this,
result = {}
Sequelize.Helper.Hash.forEach(imported, function(definition, functionName) {
definition(Sequelize, self)
})
Sequelize.Helper.Hash.forEach(this.tables, function(constructor, name) {
result[name] = constructor.klass
})
return result
},
get tableNames() {
var result = []
Sequelize.Helper.Hash.keys(this.tables).forEach(function(tableName) {
result.push(Sequelize.Helper.SQL.asTableName(tableName))
})
return result
},
sync: function(callback) {
var finished = [],
tables = this.tables,
errors = []
Sequelize.Helper.Hash.forEach(tables, function(table) {
table.klass.prepareAssociations()
})
if((Sequelize.Helper.Hash.keys(this.tables).length == 0) && callback)
callback()
else
Sequelize.Helper.Hash.forEach(tables, function(table) {
table.klass.sync(function(_, err) {
finished.push(true)
if(err) errors.push(err)
if((finished.length == Sequelize.Helper.Hash.keys(tables).length) && callback)
callback(errors)
})
})
},
drop: function(callback) {
var finished = [],
tables = this.tables,
errors = []
if((Sequelize.Helper.Hash.keys(tables).length == 0) && callback)
callback()
else
Sequelize.Helper.Hash.forEach(tables, function(table, tableName) {
table.klass.drop(function(_, err) {
finished.push(true)
if(err) errors.push(err)
if((finished.length == Sequelize.Helper.Hash.keys(tables).length) && callback)
callback(errors)
})
})
},
query: function(queryString, callback) {
var fields = [],
values = [],
self = this,
client = require(__dirname + "/../nodejs-mysql-native/index").createTCPClient(this.config.host, this.config.port)
client.connection.on('error', function() {
callback(null, null, { message: "Unable to establish a connection to " + [self.config.host, self.config.port].join(":") })
})
client.auto_prepare = true
client
.auth(self.config.database, self.config.username, self.config.password)
.on('error', function(err) { callback(null, null, err) })
.on('authorized', function() {
if(!self.options.disableLogging)
Sequelize.Helper.log("Executing the query: " + queryString)
client
.query(queryString)
.on('error', function(err) { Sequelize.Helper.log(err) })
.on('row', function(r){ values.push(r) })
.on('field', function(f){ fields.push(f)})
.on('end', function(stats) {
if(callback) {
var result = []
values.forEach(function(valueArray) {
var mapping = {}
for(var i = 0; i < fields.length; i++)
mapping[fields[i].name] = valueArray[i]
result.push(mapping)
})
if(callback) callback(result, stats)
}
})
client.close()
})
}
}
for (var key in classMethods) Sequelize[key] = classMethods[key]
module.exports = Sequelize
\ No newline at end of file
module.exports = {
username: 'root',
password: 'root',
database: 'sequelize_test'
}
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!