Comparing version 0.0.1 to 0.0.2
@@ -1,112 +0,68 @@ | ||
var mysql = require('mysql'); | ||
var Q = require('q'); | ||
var _ = require('underscore'); | ||
var util = require('util'); | ||
var genericPool = require('generic-pool'); | ||
var base = require('./base'); | ||
var mysql = require('mysql'); | ||
// Constructor for the MysqlClient | ||
var MysqlClient = module.exports = function(name, options) { | ||
if (!options.connection) { | ||
throw new Error('The database connection properties must be specified.'); | ||
} | ||
this.name = name; | ||
this.debug = options.debug; | ||
this.connectionSettings = options.connection; | ||
// Extend the genericPool with the options | ||
// passed into the init under the "pool" option | ||
var instance = this; | ||
this.pool = genericPool.Pool(_.extend({ | ||
name : 'pool' + name, | ||
create : function(callback) { | ||
callback(null, instance.getConnection()); | ||
}, | ||
destroy : function(client) { | ||
client.end(); | ||
}, | ||
max : 10, | ||
min : 2, | ||
idleTimeoutMillis: 30000, | ||
log : false | ||
}, options.pool)); | ||
this.grammar = MysqlClient.grammar; | ||
this.schemaGrammar = MysqlClient.schemaGrammar; | ||
base.setup.call(this, MysqlClient, name, options); | ||
}; | ||
_.extend(MysqlClient.prototype, { | ||
_.extend(MysqlClient.prototype, base.protoProps, { | ||
// Execute a query on the database. | ||
// If the fourth parameter is set, this will be used as the connection | ||
// to the database. | ||
query: function (data, connection) { | ||
// Execute a query on the specified Builder or QueryBuilder | ||
// interface. If a `connection` is specified, use it, otherwise | ||
// acquire a connection, and then dispose of it when we're done. | ||
query: function(builder) { | ||
var emptyConnection = !builder._connection; | ||
var debug = this.debug || builder._debug; | ||
var instance = this; | ||
return Q((builder._connection || this.getConnection())) | ||
.then(function(conn) { | ||
var dfd = Q.defer(); | ||
var dfd = Q.defer(); | ||
// If we have a debug flag set, console.log the query. | ||
if (debug) base.debug(builder, conn); | ||
// Call the querystring and then release the client | ||
conn.query(builder.sql, builder.bindings, function (err, resp) { | ||
if (err) { return dfd.reject(err); } | ||
if (builder._source === 'SchemaBuilder') { | ||
if (builder.type === 'tableExists') { | ||
if (resp.length > 0) return dfd.resolve(_.pick(resp, _.keys(resp))); | ||
return dfd.reject(new Error('Table does not exist:' + builder.sql)); | ||
} else { | ||
return dfd.resolve(null); | ||
} | ||
} | ||
if (this.debug) { | ||
if (connection) data.__cid = connection.__cid; | ||
console.log(data); | ||
} | ||
if (builder.type === 'select') { | ||
resp = base.skim(resp); | ||
} else if (builder.type === 'insert') { | ||
resp = [resp.insertId]; | ||
} else if (builder.type === 'delete' || builder.type === 'update') { | ||
resp = resp.affectedRows; | ||
} else { | ||
resp = ''; | ||
} | ||
// If there is a specific connection specified, use that. | ||
if (connection) { | ||
dfd.resolve(resp); | ||
}); | ||
connection.query(data.sql, (data.bindings || []), function(err, res) { | ||
if (err) return dfd.reject(err); | ||
dfd.resolve(res); | ||
}); | ||
} else { | ||
// Acquire connection - callback function is called | ||
// once a resource becomes available. | ||
var instance = this; | ||
this.pool.acquire(function(err, client) { | ||
if (err) return dfd.reject(err); | ||
// Make the query and then release the client. | ||
client.query(data.sql, (data.bindings || []), function (err, res) { | ||
instance.pool.release(client); | ||
if (err) return dfd.reject(err); | ||
dfd.resolve(res); | ||
// Empty the connection after we run the query, unless one was specifically | ||
// set (in the case of transactions, etc). | ||
return dfd.promise.fin(function() { | ||
if (emptyConnection) instance.pool.release(conn); | ||
}); | ||
}); | ||
} | ||
return dfd.promise; | ||
}, | ||
// Returns a mysql connection, with a __cid property uniquely | ||
// identifying the connection. | ||
getConnection: function () { | ||
var connection = mysql.createConnection(this.connectionSettings); | ||
connection.connect(); | ||
connection.__cid = _.uniqueId('__cid'); | ||
return connection; | ||
}, | ||
getRawConnection: function() { | ||
var conn = mysql.createConnection(this.connectionSettings); | ||
conn.connect(); | ||
return conn; | ||
} | ||
// Begins a transaction statement on the instance, | ||
// resolving with the connection of the current transaction. | ||
startTransaction: function() { | ||
var dfd = Q.defer(); | ||
var connection = this.getConnection(); | ||
connection.query('begin;', [], function(err) { | ||
if (err) dfd.reject(err); | ||
dfd.resolve(connection); | ||
}); | ||
return dfd.promise; | ||
}, | ||
finishTransaction: function(type, trans, promise) { | ||
trans.connection.query(type + ';', [], function(err, resp) { | ||
trans.connection.end(); | ||
trans.connection = null; | ||
if (type === 'commit') promise.resolve(resp); | ||
if (type === 'rollback') promise.reject(resp); | ||
}); | ||
} | ||
}); | ||
@@ -125,3 +81,3 @@ | ||
// Grammar for the schema builder. | ||
MysqlClient.schemaGrammar = _.extend({}, MysqlClient.grammar, { | ||
MysqlClient.schemaGrammar = _.extend({}, base.schemaGrammar, MysqlClient.grammar, { | ||
@@ -132,12 +88,7 @@ // The possible column modifiers. | ||
// Compile the query to determine if a table exists. | ||
compileTableExists: function() { | ||
compileTableExists: function(blueprint) { | ||
blueprint.bindings.unshift(blueprint.client.connectionSettings.database); | ||
return 'select * from information_schema.tables where table_schema = ? and table_name = ?'; | ||
}, | ||
// Compile a create table command. | ||
compileCreateTable: function(blueprint, command) { | ||
var columns = this.getColumns(blueprint).join(', '); | ||
return 'create table ' + this.wrapTable(blueprint) + ' (' + columns + ')'; | ||
}, | ||
// Compile an add command. | ||
@@ -151,3 +102,3 @@ compileAdd: function(blueprint, command) { | ||
compilePrimary: function(blueprint, command) { | ||
command.name(null); | ||
command.name = null; | ||
return this.compileKey(blueprint, command, 'primary key'); | ||
@@ -172,12 +123,2 @@ }, | ||
}, | ||
// Compile a drop table command. | ||
compileDropTable: function(blueprint, command) { | ||
return 'drop table ' + this.wrapTable(blueprint); | ||
}, | ||
// Compile a drop table (if exists) command. | ||
compileDropTableIfExists: function(blueprint, command) { | ||
return 'drop table if exists ' + this.wrapTable(blueprint); | ||
}, | ||
@@ -211,3 +152,3 @@ // Compile a drop column command. | ||
// Compile a rename table command. | ||
compileRename: function(blueprint, command) { | ||
compileRenameTable: function(blueprint, command) { | ||
return 'rename table ' + this.wrapTable(blueprint) + ' to ' + this.wrapTable(command.to); | ||
@@ -297,5 +238,3 @@ }, | ||
modifyUnsigned: function(blueprint, column) { | ||
if (column.type == 'integer' && column.isUnsigned) { | ||
return ' unsigned'; | ||
} | ||
if (column.isUnsigned) return ' unsigned'; | ||
}, | ||
@@ -310,3 +249,4 @@ | ||
modifyDefault: function(blueprint, column) { | ||
if (column.defaultValue) { | ||
// TODO - no default on blob/text | ||
if (column.defaultValue && column.type != 'blob' && column.type.indexOf('text') === -1) { | ||
return " default '" + this.getDefaultValue(column.defaultValue) + "'"; | ||
@@ -321,3 +261,11 @@ } | ||
} | ||
}, | ||
// Get the SQL for an "after" column modifier. | ||
modifyAfter: function(blueprint, column) { | ||
if (column.isAfter) { | ||
return ' after ' + this.wrap(column.isAfter); | ||
} | ||
} | ||
}); |
@@ -0,112 +1,80 @@ | ||
var Q = require('q'); | ||
var _ = require('underscore'); | ||
var util = require('util'); | ||
var base = require('./base'); | ||
var pg = require('pg'); | ||
var pg = require('pg'); | ||
// Constructor for the PostgresClient | ||
var PostgresClient = module.exports = function(name, options) { | ||
base.setup.call(this, PostgresClient, name, options); | ||
}; | ||
var _ = require('underscore'); | ||
var util = require('util'); | ||
var genericPool = require('generic-pool'); | ||
_.extend(PostgresClient.prototype, base.protoProps, { | ||
var init, debug, pool, connection, connectionSettings; | ||
// Execute a query on the specified Builder or QueryBuilder | ||
// interface. If a `connection` is specified, use it, otherwise | ||
// acquire a connection, and then dispose of it when we're done. | ||
query: function(builder) { | ||
var emptyConnection = !builder._connection; | ||
var debug = this.debug || builder._debug; | ||
var instance = this; | ||
return Q((builder._connection || this.getConnection())) | ||
.then(function(conn) { | ||
var dfd = Q.defer(); | ||
// Initializes the postgres module with an options hash, | ||
// containing the connection settings, as well as the | ||
// pool config settings | ||
exports.initialize = function (options) { | ||
// Bind all of the ? to numbered vars. | ||
var questionCount = 0; | ||
builder.sql = builder.sql.replace(/\?/g, function() { | ||
questionCount++; | ||
return '$' + questionCount; | ||
}); | ||
// If we have a debug flag set, console.log the query. | ||
if (debug) base.debug(builder, conn); | ||
// If there isn't a connection setting | ||
if (!options.connection) return; | ||
// Call the querystring and then release the client | ||
conn.query(builder.sql, builder.bindings, function (err, resp) { | ||
if (err) return dfd.reject(err); | ||
resp || (resp = {}); | ||
connectionSettings = options.connection; | ||
debug = options.debug; | ||
if (builder._source === 'SchemaBuilder') { | ||
if (builder.type === 'tableExists') { | ||
if (resp.rows.length > 0) return dfd.resolve(resp.rows[0]); | ||
return dfd.reject(new Error('Table does not exist:' + builder.sql)); | ||
} else { | ||
return dfd.resolve(null); | ||
} | ||
} | ||
// If pooling is disabled, set the query getter to | ||
// something below and create a connection on the connection object | ||
if (options.pool === false) { | ||
pool = false; | ||
connection = this.getConnection(); | ||
return; | ||
} | ||
if (resp.command === 'SELECT') { | ||
resp = resp.rows; | ||
} else if (resp.command === 'INSERT') { | ||
resp = _.map(resp.rows, function(row) { return row[builder._idAttribute]; }); | ||
} else if (resp.command === 'UPDATE' || resp.command === 'DELETE') { | ||
resp = resp.rowCount; | ||
} else { | ||
resp = ''; | ||
} | ||
dfd.resolve(resp); | ||
}); | ||
// Extend the genericPool with the options | ||
// passed into the init under the "pool" option | ||
pool = genericPool.Pool(_.extend({ | ||
name : 'postgres', | ||
create : function(callback) { | ||
callback(null, exports.getConnection()); | ||
}, | ||
destroy : function(client) { | ||
client.end(); | ||
}, | ||
max : 10, | ||
min : 2, | ||
idleTimeoutMillis: 30000, | ||
log : false | ||
}, options.pool)); | ||
}; | ||
// Empty the connection after we run the query, unless one was specifically | ||
// set (in the case of transactions, etc). | ||
return dfd.promise.fin(function() { | ||
if (emptyConnection) instance.pool.release(conn); | ||
}); | ||
}); | ||
}, | ||
exports.beginTransaction = function(callback) { | ||
var connection = this.getConnection(); | ||
this.query("begin;", null, function(err) { | ||
callback(err, connection); | ||
}, connection); | ||
}; | ||
exports.commitTransaction = function(connection, callback) { | ||
this.query("commit;", null, callback, connection); | ||
}; | ||
exports.rollbackTransaction = function(connection, callback) { | ||
this.query("rollback;", null, callback, connection); | ||
}; | ||
// Execute a query on the database. | ||
// If the fourth parameter is set, this will be used as the connection | ||
// to the database. | ||
exports.query = function (querystring, params, callback, connection) { | ||
if (debug) console.log([querystring, params]); | ||
// If there is a connection, use it. | ||
if (connection) { | ||
return connection.query(querystring, params, callback); | ||
// Returns a connection from the `pg` lib. | ||
getRawConnection: function() { | ||
var conn = new pg.Client(this.connectionSettings); | ||
conn.connect(); | ||
return conn; | ||
} | ||
// Bind all of the ? to numbered vars. | ||
var questionCount = 0; | ||
querystring = querystring.replace(/\?/g, function () { | ||
questionCount++; | ||
return '$' + questionCount; | ||
}); | ||
}); | ||
// Acquire connection - callback function is called | ||
// once a resource becomes available. | ||
pool.acquire(function(err, client) { | ||
if (err) throw new Error(err); | ||
// Call the querystring and then release the client | ||
client.query(querystring, params, function (err, resp) { | ||
pool.release(client); | ||
resp || (resp = {}); | ||
if (resp.command === 'INSERT' || resp.command === 'UPDATE') { | ||
_.extend(resp, {insertId: resp.oid}); | ||
callback.call(this, err, resp); | ||
} else { | ||
callback.call(this, err, resp.rows); | ||
} | ||
}); | ||
}); | ||
}; | ||
// Returns a pg connection, with a __cid property uniquely | ||
// identifying the connection. | ||
exports.getConnection = function () { | ||
var connection = new pg.Client(connectionSettings); | ||
connection.connect(); | ||
connection.__cid = _.uniqueId('__cid'); | ||
return connection; | ||
}; | ||
// Extends the standard sql grammar. | ||
var grammar = exports.grammar = { | ||
PostgresClient.grammar = { | ||
@@ -118,11 +86,20 @@ // The keyword identifier wrapper format. | ||
compileTruncate: function (qb) { | ||
var query = {}; | ||
query['truncate ' + this.wrapTable(qb.from) + ' restart identity'] = []; | ||
return query; | ||
compileTruncate: function(qb) { | ||
return 'truncate ' + this.wrapTable(qb.table) + ' restart identity'; | ||
}, | ||
// Compiles an `insert` query, allowing for multiple | ||
// inserts using a single query statement. | ||
compileInsert: function(qb) { | ||
var sql = require('../knex').Grammar.compileInsert.call(this, qb); | ||
if (qb._idAttribute) { | ||
sql += ' returning "' + qb._idAttribute + '"'; | ||
} | ||
return sql; | ||
} | ||
}; | ||
// Grammar for the schema builder. | ||
exports.schemaGrammar = _.extend({}, grammar, { | ||
PostgresClient.schemaGrammar = _.extend({}, base.schemaGrammar, PostgresClient.grammar, { | ||
@@ -138,8 +115,2 @@ // The possible column modifiers. | ||
// Compile a create table command. | ||
compileCreateTable: function(blueprint, command) { | ||
var columns = this.getColumns(blueprint).join(', '); | ||
return 'create table ' + this.wrapTable(blueprint) + " (" + columns + ")"; | ||
}, | ||
// Compile a create table command. | ||
compileAdd: function(blueprint, command) { | ||
@@ -161,3 +132,3 @@ var table = this.wrapTable(blueprint); | ||
var columns = this.columnize(command.columns); | ||
return 'alter table table add constraint ' + command.index + ' unique (' + columns + ')'; | ||
return 'alter table ' + table + ' add constraint ' + command.index + ' unique (' + columns + ')'; | ||
}, | ||
@@ -171,12 +142,2 @@ | ||
// Compile a drop table command. | ||
compileDropTable: function(blueprint, command) { | ||
return 'drop table ' + this.wrapTable(blueprint); | ||
}, | ||
// Compile a drop table (if exists) command. | ||
compileDropTableIfExists: function(blueprint, command) { | ||
return 'drop table if exists ' + this.wrapTable(blueprint); | ||
}, | ||
// Compile a drop column command. | ||
@@ -213,3 +174,3 @@ compileDropColumn: function(blueprint, command) { | ||
// Compile a rename table command. | ||
compileRename: function(blueprint, command) { | ||
compileRenameTable: function(blueprint, command) { | ||
return 'alter table ' + this.wrapTable(blueprint) + ' rename to ' + this.wrapTable(command.to); | ||
@@ -255,3 +216,3 @@ }, | ||
typeEnum: function(column) { | ||
return 'varchar(255)'; | ||
return "enum('" + column.allowed.join("', '") + "')"; | ||
}, | ||
@@ -258,0 +219,0 @@ |
@@ -0,101 +1,79 @@ | ||
var Q = require('q'); | ||
var _ = require('underscore'); | ||
var util = require('util'); | ||
var base = require('./base'); | ||
var sqlite3 = require('sqlite3'); | ||
var sqlite3 = require('sqlite3'); | ||
// Constructor for the Sqlite3Client | ||
var Sqlite3Client = module.exports = function(name, options) { | ||
base.setup.call(this, Sqlite3Client, name, options); | ||
}; | ||
var _ = require('underscore'); | ||
var util = require('util'); | ||
var genericPool = require('generic-pool'); | ||
_.extend(Sqlite3Client.prototype, base.protoProps, { | ||
var init, debug, pool, connection, connectionSettings; | ||
// Execute a query on the specified Builder or QueryBuilder | ||
// interface. If a `connection` is specified, use it, otherwise | ||
// acquire a connection, and then dispose of it when we're done. | ||
query: function(builder) { | ||
var emptyConnection = !builder._connection; | ||
var debug = this.debug || builder._debug; | ||
var instance = this; | ||
return Q((builder._connection || this.getConnection())) | ||
.then(function(conn) { | ||
var dfd = Q.defer(); | ||
var method = (builder.type === 'insert' || builder.type === 'update') ? 'run' : 'all'; | ||
// Initializes the sqlite3 module with an options hash, | ||
// containing the connection settings, as well as the | ||
// pool config settings | ||
exports.initialize = function (options) { | ||
// If we have a debug flag set, console.log the query. | ||
if (debug) base.debug(builder, conn); | ||
// Call the querystring and then release the client | ||
conn[method](builder.sql, builder.bindings, function (err, resp) { | ||
if (err) return dfd.reject(err); | ||
// If there isn't a connection setting | ||
if (!options.connection) return; | ||
if (builder._source === 'SchemaBuilder') { | ||
if (builder.type === 'tableExists') { | ||
if (resp.length > 0) return dfd.resolve(_.pick(resp, _.keys(resp))); | ||
return dfd.reject(new Error('Table does not exist:' + builder.sql)); | ||
} else { | ||
return dfd.resolve(null); | ||
} | ||
} | ||
connectionSettings = options.connection; | ||
debug = options.debug; | ||
if (builder.type === 'select') { | ||
resp = base.skim(resp); | ||
} else if (builder.type === 'insert') { | ||
resp = [this.lastID]; | ||
} else if (builder.type === 'delete' || builder.type === 'update') { | ||
resp = this.changes; | ||
} else { | ||
resp = ''; | ||
} | ||
// If pooling is disabled, set the query getter to | ||
// something below and create a connection on the connection object | ||
if (options.pool === false) { | ||
pool = false; | ||
connection = this.getConnection(); | ||
return; | ||
} | ||
dfd.resolve(resp); | ||
}); | ||
// Extend the genericPool with the options | ||
// passed into the init under the "pool" option | ||
pool = genericPool.Pool(_.extend({ | ||
name : 'sqlite3', | ||
create : function(callback) { | ||
var conn = exports.getConnection(); | ||
// Set to allow multiple connections on the database. | ||
conn.run("PRAGMA journal_mode=WAL;", function () { | ||
callback(null, conn); | ||
// Empty the connection after we run the query, unless one was specifically | ||
// set (in the case of transactions, etc). | ||
return dfd.promise.fin(function(resp) { | ||
if (emptyConnection) instance.pool.release(conn); | ||
return resp; | ||
}); | ||
}); | ||
}, | ||
destroy : function(client) { | ||
client.close(); | ||
}, | ||
max : 1, | ||
min : 1, | ||
idleTimeoutMillis: 30000, | ||
log : false | ||
}, options.pool)); | ||
}; | ||
}, | ||
exports.query = function (querystring, params, callback, connection, type) { | ||
poolDefaults: { | ||
max: 1, | ||
min: 1, | ||
destroy: function(client) { client.close(); } | ||
}, | ||
if (debug) console.log([querystring, params]); | ||
// If there is a connection, use it. | ||
if (connection) { | ||
return connection.run(querystring, params, callback); | ||
getRawConnection: function() { | ||
return new sqlite3.Database(this.connectionSettings.filename); | ||
} | ||
// Acquire connection - callback function is called | ||
// once a resource becomes available. | ||
pool.acquire(function(err, client) { | ||
}); | ||
if (err) throw new Error(err); | ||
var method = (type === 'insert' || type === 'update') ? 'run' : 'all'; | ||
// Call the querystring and then release the client | ||
client[method](querystring, params, function (err, resp) { | ||
if (_.has(this, 'lastID')) resp = {insertId: this.lastID, changes: this.changes}; | ||
pool.release(client); | ||
callback.call(this, err, resp); | ||
}); | ||
}); | ||
}; | ||
exports.beginTransaction = function(callback) { | ||
var connection = this.getConnection(); | ||
this.query("begin;", null, function(err) { | ||
callback(err, connection); | ||
}, connection); | ||
}; | ||
exports.commitTransaction = function(connection, callback) { | ||
this.query("commit;", null, callback, connection); | ||
}; | ||
exports.rollbackTransaction = function(connection, callback) { | ||
this.query("rollback;", null, callback, connection); | ||
}; | ||
// Returns a mysql connection, with a __cid property uniquely | ||
// identifying the connection. | ||
exports.getConnection = function () { | ||
var connection = new sqlite3.Database(connectionSettings.filename); | ||
connection.__cid = _.uniqueId('__cid'); | ||
return connection; | ||
}; | ||
// Extends the standard sql grammar. | ||
var grammar = exports.grammar = { | ||
Sqlite3Client.grammar = { | ||
@@ -116,4 +94,4 @@ // The keyword identifier wrapper format. | ||
// Compile an insert statement into SQL. | ||
compileInsert: function(qb, values) { | ||
if (!_.isArray(values)) values = [values]; | ||
compileInsert: function(qb) { | ||
var values = qb.values; | ||
var table = this.wrapTable(qb.table); | ||
@@ -127,6 +105,6 @@ var parameters = this.parameterize(values[0]); | ||
if (values.length === 1) { | ||
return require('../knex').Grammar.prototype.compileInsert.call(this, qb, values); | ||
return require('../knex').Grammar.compileInsert.call(this, qb); | ||
} | ||
var keys = _.keys(values[0]); | ||
var keys = _.keys(values[0]).sort(); | ||
var names = this.columnize(keys); | ||
@@ -149,3 +127,3 @@ var columns = []; | ||
return "insert into " + table + " (" + names + ") select " + columns.join(' union select '); | ||
return "insert into " + table + " (" + names + ") select " + columns.join(' union all select '); | ||
}, | ||
@@ -155,5 +133,6 @@ | ||
compileTruncate: function (qb) { | ||
var sql = {}; | ||
sql['delete from sqlite_sequence where name = ?'] = [qb.from]; | ||
sql['delete from ' + this.wrapTable(query.from)] = []; | ||
var sql = []; | ||
var table = this.wrapTable(qb.table); | ||
sql.push('delete from sqlite_sequence where name = ' + table); | ||
sql.push('delete from ' + table); | ||
return sql; | ||
@@ -164,3 +143,3 @@ } | ||
// Grammar for the schema builder. | ||
exports.schemaGrammar = _.extend({}, grammar, { | ||
Sqlite3Client.schemaGrammar = _.extend({}, base.schemaGrammar, Sqlite3Client.grammar, { | ||
@@ -186,2 +165,3 @@ // The possible column modifiers. | ||
sql +=')'; | ||
return sql; | ||
@@ -246,12 +226,2 @@ }, | ||
// Compile a drop table command. | ||
compileDropTable: function(blueprint, command) { | ||
return 'drop table ' + this.wrapTable(blueprint); | ||
}, | ||
// Compile a drop table (if exists) command. | ||
compileDropTableIfExists: function(blueprint, command) { | ||
return 'drop table if exists ' + this.wrapTable(blueprint); | ||
}, | ||
// Compile a drop column command. | ||
@@ -273,3 +243,3 @@ compileDropColumn: function(blueprint, command) { | ||
// Compile a rename table command. | ||
compileRename: function(blueprint, command) { | ||
compileRenameTable: function(blueprint, command) { | ||
return 'alter table ' + this.wrapTable(blueprint) + ' rename to ' + this.wrapTable(command.to); | ||
@@ -345,3 +315,3 @@ }, | ||
modifyNullable: function(blueprint, column) { | ||
return column.nullable ? ' null' : ' not null'; | ||
return ' null'; | ||
}, | ||
@@ -348,0 +318,0 @@ |
730
knex.js
@@ -1,2 +0,2 @@ | ||
// Knex.js 0.1.0 | ||
// Knex.js 0.0.0 | ||
// | ||
@@ -19,3 +19,3 @@ // (c) 2013 Tim Griesser | ||
var Knex = function(table) { | ||
return new Knex.Builder(table, Knex.client); | ||
return new Knex.Builder(table); | ||
}; | ||
@@ -26,12 +26,77 @@ | ||
// Methods common to both the `Grammar` and `SchemaGrammar` interfaces, | ||
// used to generate the sql in one form or another. | ||
var Common = { | ||
_debug: false, | ||
debug: function(val) { | ||
this._debug = val; | ||
return this; | ||
}, | ||
// For those who dislike promise interfaces. | ||
exec: function(callback) { | ||
var run = Knex.runQuery(this); | ||
return run.nodeify(callback); | ||
}, | ||
// The promise interface for the query builder. | ||
then: function(onFulfilled, onRejected) { | ||
var run = Knex.runQuery(this); | ||
return run.then(onFulfilled, onRejected); | ||
}, | ||
// Specifies to resolve the statement with the `data` rather | ||
// than a promise... useful in testing/debugging. | ||
toString: function() { | ||
if (!this.type) { | ||
throw new Error('Cannot be converted to string'); | ||
} | ||
var data = this.toSql(); | ||
var builder = this; | ||
if (!_.isArray(data)) data = [data]; | ||
return _.map(data, function(str) { | ||
var questionCount = 0; | ||
return str.replace(/\?/g, function() { | ||
return builder.bindings[questionCount++]; | ||
}); | ||
}).join('; '); | ||
}, | ||
// Sets the connection | ||
connection: function(connection) { | ||
this._connection = connection; | ||
return this; | ||
}, | ||
// The connection the current query is being run on, optionally | ||
// specified by the `connection` method. | ||
_connection: false, | ||
// Sets the "type" of the current query, so we can potentially place | ||
// `select`, `update`, `del`, etc. anywhere in the query statement | ||
// and have it come out fine. | ||
_setType: function(type) { | ||
if (this.type) { | ||
throw new Error('The query type has already been set to ' + this.type); | ||
} | ||
this.type = type; | ||
return this; | ||
}, | ||
// Returns all bindings excluding the `Knex.Raw` types. | ||
_cleanBindings: function() { | ||
var bindings = this.bindings; | ||
var cleaned = []; | ||
for (var i = 0, l = bindings.length; i < l; i++) { | ||
if (!(bindings[i] instanceof Raw)) cleaned.push(bindings[i]); | ||
} | ||
return cleaned; | ||
} | ||
}; | ||
// Grammar | ||
// ------- | ||
// Creates a new Grammar, with the mixins for the | ||
// specified query dialect, which are defined in each | ||
// client's `exports.grammar`. | ||
var Grammar = function(mixins) { | ||
_.extend(this, mixins); | ||
}; | ||
// The list of different components | ||
@@ -41,6 +106,6 @@ var components = [ | ||
'joins', 'wheres', 'groups', 'havings', | ||
'orders', 'limit', 'offset' | ||
'orders', 'limit', 'offset', 'unions' | ||
]; | ||
Grammar.prototype = { | ||
Knex.Grammar = { | ||
@@ -57,4 +122,5 @@ dateFormat: 'Y-m-d H:i:s', | ||
var component = components[i]; | ||
if (_.result(qb, component) != null) { | ||
sql[component] = this['compile' + capitalize(component)](qb, _.result(qb, component)); | ||
var result = _.result(qb, component); | ||
if (result != null) { | ||
sql[component] = this['compile' + capitalize(component)](qb, result); | ||
} | ||
@@ -66,8 +132,8 @@ } | ||
// Compiles an aggregate query. | ||
compileAggregate: function(qb, aggregate) { | ||
var column = this.columnize(aggregate.columns); | ||
compileAggregate: function(qb) { | ||
var column = this.columnize(qb.aggregate.columns); | ||
if (qb.isDistinct && column !== '*') { | ||
column = 'distinct ' + column; | ||
} | ||
return 'select ' + aggregate.type + '(' + column + ') as aggregate'; | ||
return 'select ' + qb.aggregate.type + '(' + column + ') as aggregate'; | ||
}, | ||
@@ -117,2 +183,12 @@ | ||
// Compile the "union" queries attached to the main query. | ||
compileUnions: function(qb) { | ||
var sql = ''; | ||
for (var i = 0, l = qb.unions.length; i < l; i++) { | ||
var union = qb.unions[i]; | ||
sql += (union.all ? 'union all ' : 'union ') + this.compileSelect(union.query); | ||
} | ||
return sql; | ||
}, | ||
// Compiles a nested where clause. | ||
@@ -188,4 +264,7 @@ whereNested: function(qb, where) { | ||
return 'having ' + havings.map(function(having) { | ||
if (having.type === 'raw') { | ||
return having.bool + ' ' + having.sql; | ||
} | ||
return '' + this.wrap(having.column) + ' ' + having.operator + ' ' + this.parameter(having['value']); | ||
}, this).join(' and').replace(/and /, ''); | ||
}, this).join('and ').replace(/and /, ''); | ||
}, | ||
@@ -214,3 +293,4 @@ | ||
// inserts using a single query statement. | ||
compileInsert: function(qb, values) { | ||
compileInsert: function(qb) { | ||
var values = qb.values; | ||
var table = this.wrapTable(qb.table); | ||
@@ -252,7 +332,8 @@ var columns = this.columnize(_.keys(values[0]).sort()); | ||
// Compiles an `update` query. | ||
compileUpdate: function(qb, values) { | ||
compileUpdate: function(qb) { | ||
var values = qb.values; | ||
var table = this.wrapTable(qb.table), columns = []; | ||
for (var key in values) { | ||
var value = values[key]; | ||
columns.push(this.wrap(key) + ' = ' + this.parameter(value)); | ||
for (var i=0, l = values.length; i < l; i++) { | ||
var value = values[i]; | ||
columns.push(this.wrap(value[0]) + ' = ' + this.parameter(value[1])); | ||
} | ||
@@ -271,3 +352,3 @@ return 'update ' + table + ' set ' + columns.join(', ') + ' ' + this.compileWheres(qb); | ||
compileTruncate: function(qb) { | ||
return 'truncate ' + this.wrapTable(qb.from); | ||
return 'truncate ' + this.wrapTable(qb.table); | ||
}, | ||
@@ -277,3 +358,3 @@ | ||
var segments; | ||
if (value instanceof Knex.Raw) return value.value; | ||
if (value instanceof Raw) return value.value; | ||
if (_.isNumber(value)) return value; | ||
@@ -302,3 +383,3 @@ if (value.toLowerCase().indexOf(' as ') !== -1) { | ||
wrapTable: function(table) { | ||
if (table instanceof Knex.Raw) return table.value; | ||
if (table instanceof Raw) return table.value; | ||
return this.wrapValue(table); | ||
@@ -316,3 +397,3 @@ }, | ||
parameter: function(value) { | ||
return (value instanceof Knex.Raw ? value.value : '?'); | ||
return (value instanceof Raw ? value.value : '?'); | ||
} | ||
@@ -323,8 +404,16 @@ }; | ||
// ------- | ||
var Builder = Knex.Builder = function(table, client) { | ||
client || (client = {}); | ||
this.table = table; | ||
var Builder = Knex.Builder = function(table) { | ||
// We use this logic to create sub-builders | ||
// for the advanced query statements. | ||
if (table) { | ||
if (_.isString(table)) { | ||
this.table = table; | ||
} else { | ||
this.client = table.client; | ||
this.grammar = table.grammar; | ||
} | ||
} | ||
this.reset(); | ||
this.client = client; | ||
this.grammar = new Grammar(client.grammar); | ||
}; | ||
@@ -335,4 +424,16 @@ | ||
Builder.prototype = { | ||
_.extend(Builder.prototype, Common, { | ||
_source: 'Builder', | ||
_idAttribute: 'id', | ||
// Sets the `returning` for the query - only necessary | ||
// to set the "returning" value for the postgres insert, | ||
// defaults to `id`. | ||
idAttribute: function(val) { | ||
this._idAttribute = val; | ||
return this; | ||
}, | ||
// Sets the `tableName` on the query. | ||
@@ -345,5 +446,5 @@ from: function(tableName) { | ||
// Specifies to returns the statement as SQL rather than as a promise. | ||
asSql: function() { | ||
this.asSql = true; | ||
// Select a `column` rather than | ||
column: function(value) { | ||
this.columns.push(value); | ||
return this; | ||
@@ -353,3 +454,4 @@ }, | ||
// Adds a `distinct` clause to the query. | ||
distinct: function() { | ||
distinct: function(column) { | ||
this.column(column); | ||
this.isDistinct = true; | ||
@@ -359,10 +461,15 @@ return this; | ||
toSql: function() { | ||
return this.grammar['compile' + capitalize(this.type)](this); | ||
}, | ||
// Clones the current query builder, including any | ||
// pieces that have been set thus far | ||
// pieces that have been set thus far. | ||
clone: function() { | ||
var item = new Builder(this.table); | ||
item.client = this.client; | ||
item.grammar = this.grammar; | ||
var items = [ | ||
'isDistinct', 'joins', | ||
'wheres', 'orders', 'columns', 'bindings', | ||
'grammar', 'connection', 'transaction' | ||
'_idAttribute', 'isDistinct', 'joins', 'wheres', 'orders', | ||
'columns', 'bindings', 'grammar', 'transaction', 'unions' | ||
]; | ||
@@ -378,6 +485,8 @@ for (var i = 0, l = items.length; i < l; i++) { | ||
reset: function() { | ||
this.joins = []; | ||
this.wheres = []; | ||
this.orders = []; | ||
this.columns = []; | ||
this.joins = []; | ||
this.values = []; | ||
this.unions = []; | ||
this.wheres = []; | ||
this.orders = []; | ||
this.columns = []; | ||
this.bindings = []; | ||
@@ -387,13 +496,2 @@ this.isDistinct = false; | ||
toJSON: function() { | ||
return { | ||
joins: this.joins, | ||
wheres: this.wheres, | ||
order: this.orders, | ||
columns: this.columns, | ||
bindings: this.bindings, | ||
isDistinct: this.isDistinct | ||
}; | ||
}, | ||
// Adds a join clause to the query, allowing for advanced joins | ||
@@ -473,3 +571,3 @@ // with an anonymous function as the second argument. | ||
whereExists: function(callback, bool, type) { | ||
var query = new Builder(); | ||
var query = new Builder(this); | ||
query.isSubQuery = true; | ||
@@ -581,2 +679,14 @@ callback.call(query, query); | ||
// Add a union statement to the query. | ||
union: function(callback) { | ||
this._union(callback, false); | ||
return this; | ||
}, | ||
// Adds a union all statement to the query. | ||
unionAll: function(callback) { | ||
this._union(callback, true); | ||
return this; | ||
}, | ||
// Adds a `having` clause to the query. | ||
@@ -589,2 +699,14 @@ having: function(column, operator, value) { | ||
havingRaw: function(sql, bindings) { | ||
this.havings.push({type: 'raw', sql: sql, bool: 'and'}); | ||
this.bindings.push(bindings); | ||
return this; | ||
}, | ||
orHavingRaw: function(sql, bindings) { | ||
this.havings.push({type: 'raw', sql: sql, bool: 'or'}); | ||
this.bindings.push(bindings); | ||
return this; | ||
}, | ||
// ---------------------------------------------------------------------- | ||
@@ -608,5 +730,4 @@ | ||
exists: function() { | ||
return this.count().then(function(count) { | ||
return (count > 0); | ||
}); | ||
this.count(); | ||
return this.setType('exists'); | ||
}, | ||
@@ -644,33 +765,31 @@ | ||
// Performs a `select` query, returning a promise. | ||
// Sets the values for a `select` query. | ||
select: function(columns) { | ||
this.columns = this.columns.concat(columns ? (_.isArray(columns) ? columns : _.toArray(arguments)) : '*'); | ||
if (!this.isSubQuery) { | ||
return Knex.runQuery(this, {sql: this.grammar.compileSelect(this), bindings: this._cleanBindings()}); | ||
if (columns) { | ||
this.columns = this.columns.concat(_.isArray(columns) ? columns : _.toArray(arguments)); | ||
} | ||
return this; | ||
return this._setType('select'); | ||
}, | ||
// Performs an `insert` query, returning a promise. | ||
insert: function(values, returning) { | ||
if (!_.isArray(values)) values = values ? [values] : []; | ||
for (var i = 0, l = values.length; i<l; i++) { | ||
var obj = sortObject(values[i]); | ||
for (var i2 = 0, l2 = obj.length; i2 < l2; i2++) { | ||
this.bindings.push(obj[i2][1]); | ||
} | ||
} | ||
var str = this.grammar.compileInsert(this, values); | ||
return Knex.runQuery(this, {sql: str, bindings: this._cleanBindings(), type: 'insert'}); | ||
// Sets the values for an `insert` query. | ||
insert: function(values) { | ||
this.values = this._prepValues(values); | ||
return this._setType('insert'); | ||
}, | ||
// Performs an `update` query, returning a promise. | ||
// Sets the values for an `update` query. | ||
update: function(values) { | ||
this.bindings = _.values(values).concat(this.bindings); | ||
return Knex.runQuery(this, {sql: this.grammar.compileUpdate(this, values), bindings: this._cleanBindings(), type: 'update'}); | ||
var obj = sortObject(values); | ||
var bindings = []; | ||
for (var i = 0, l = obj.length; i < l; i++) { | ||
bindings[i] = obj[i][1]; | ||
} | ||
this.bindings = bindings.concat(this.bindings || []); | ||
this.values = obj; | ||
return this._setType('update'); | ||
}, | ||
// Alias to del | ||
// Alias to del. | ||
"delete": function() { | ||
return this.del(); | ||
return this._setType('delete'); | ||
}, | ||
@@ -680,3 +799,3 @@ | ||
del: function() { | ||
return Knex.runQuery(this, {sql: this.grammar.compileDelete(this), bindings: this._cleanBindings()}); | ||
return this._setType('delete'); | ||
}, | ||
@@ -686,3 +805,3 @@ | ||
truncate: function() { | ||
return Knex.runQuery(this, {sql: this.grammar.compileTruncate(this)}); | ||
return this._setType('truncate'); | ||
}, | ||
@@ -703,5 +822,16 @@ | ||
_prepValues: function(values) { | ||
if (!_.isArray(values)) values = values ? [values] : []; | ||
for (var i = 0, l = values.length; i<l; i++) { | ||
var obj = sortObject(values[i]); | ||
for (var i2 = 0, l2 = obj.length; i2 < l2; i2++) { | ||
this.bindings.push(obj[i2][1]); | ||
} | ||
} | ||
return values; | ||
}, | ||
_whereInSub: function(column, callback, bool, condition) { | ||
var type = condition ? 'NotInSub' : 'InSub'; | ||
var query = new Builder(); | ||
var query = new Builder(this); | ||
query.isSubQuery = true; | ||
@@ -715,3 +845,3 @@ callback.call(query, query); | ||
_whereNested: function(callback, bool) { | ||
var query = new Builder(); | ||
var query = new Builder(this); | ||
query.isSubQuery = true; | ||
@@ -726,3 +856,3 @@ query.table = this.table; | ||
_whereSub: function(column, operator, callback, bool) { | ||
var query = new Builder(); | ||
var query = new Builder(this); | ||
query.isSubQuery = true; | ||
@@ -742,4 +872,5 @@ callback.call(query, query); | ||
_aggregate: function(type, columns) { | ||
if (!_.isArray(columns)) columns = [columns]; | ||
this.aggregate = {type: type, columns: columns}; | ||
return this.get(columns); | ||
return this._setType('select'); | ||
}, | ||
@@ -749,14 +880,15 @@ | ||
var sql = {}; | ||
sql[column] = new Knex.Raw('' + this.grammar.wrap(column) + ' ' + (symbol || '+') + ' ' + amount); | ||
return this.update(sql, callback); | ||
sql[column] = new Raw('' + this.grammar.wrap(column) + ' ' + (symbol || '+') + ' ' + amount); | ||
return this.update(sql); | ||
}, | ||
// Returns all bindings excluding the `Knex.Raw` types. | ||
_cleanBindings: function() { | ||
return _.map(this.bindings, function(binding) { | ||
return (binding instanceof Knex.Raw ? void 0 : binding); | ||
}); | ||
_union: function(callback, bool) { | ||
var query = new Builder(this); | ||
query.isSubQuery = true; | ||
callback.call(query, query); | ||
this.unions.push({query: query, all: bool}); | ||
push.apply(this.bindings, query.bindings); | ||
} | ||
}; | ||
}); | ||
@@ -779,2 +911,7 @@ // Knex.JoinClause | ||
andOn: function() { | ||
this.on.apply(this, arguments); | ||
return this; | ||
}, | ||
orOn: function(first, operator, second) { | ||
@@ -784,3 +921,2 @@ this.clauses.push({first: first, operator: operator, second: second, bool: 'or'}); | ||
} | ||
}; | ||
@@ -826,7 +962,10 @@ | ||
// SchemaBuilder instance methods | ||
_.each(['hasTable', 'createTable', 'table', 'dropTable', 'dropTableIfExists', 'transacting'], function(method) { | ||
_.each(['hasTable', 'createTable', 'table', 'dropTable', 'renameTable', 'dropTableIfExists'], function(method) { | ||
Schema[method] = function() { | ||
var builder = new Knex.SchemaBuilder(client); | ||
return builder[method].apply(builder, arguments); | ||
var args = _.toArray(arguments); | ||
var builder = new Knex.SchemaBuilder(args[0]); | ||
builder.client = client; | ||
builder.grammar = client.schemaGrammar; | ||
return SchemaInterface[method].apply(builder, args.slice(1)); | ||
}; | ||
@@ -837,187 +976,67 @@ }); | ||
// Knex.SchemaBuilder | ||
// -------- | ||
// All of the Schame methods that should be called with a | ||
// `SchemaBuilder` context, to disallow calling more than one method at once. | ||
var SchemaInterface = { | ||
// Modify a table on the schema. | ||
table: function(callback) { | ||
this.callback(callback); | ||
return this._setType('table'); | ||
}, | ||
var SchemaBuilder = Knex.SchemaBuilder = function(client) { | ||
this.client = client; | ||
this.grammar = new SchemaGrammar(client.schemaGrammar); | ||
}; | ||
SchemaBuilder.prototype = { | ||
// Create a new table on the schema. | ||
createTable: function(table, callback) { | ||
return new Blueprint(table, this.client).createTable().callback(callback).build(this.grammar); | ||
createTable: function(callback) { | ||
this._addCommand('createTable'); | ||
this.callback(callback); | ||
return this._setType('createTable'); | ||
}, | ||
// Modify a table on the schema. | ||
table: function(table, callback) { | ||
return new Blueprint(table, this.client).callback(callback).build(this.grammar); | ||
}, | ||
// Drop a table from the schema. | ||
dropTable: function(table) { | ||
return new Blueprint(table, this.client).dropTable().build(this.grammar); | ||
dropTable: function() { | ||
this._addCommand('dropTable'); | ||
return this._setType('dropTable'); | ||
}, | ||
// Drop a table from the schema if it exists. | ||
dropTableIfExists: function(table) { | ||
return new Blueprint(table, this.client).dropTableIfExists().build(this.grammar); | ||
dropTableIfExists: function() { | ||
this._addCommand('dropTableIfExists'); | ||
return this._setType('dropTableIfExists'); | ||
}, | ||
// Rename a table on the schema. | ||
renameTable: function(from, to) { | ||
return new Blueprint(from, this.client).renameTable(to).build(this.grammar); | ||
renameTable: function(to) { | ||
this._addCommand('renameTable', {to: to}); | ||
return this._setType('renameTable'); | ||
}, | ||
// Determine if the given table exists. | ||
// TODO: Bindings here need to be fixed for mysql, including `table`. | ||
hasTable: function(table) { | ||
var sql = this.grammar.compileTableExists(); | ||
return Knex.runQuery(this, {sql: sql, bindings: [table]}).then(function(resp) { | ||
return (resp.length > 0 ? resp : Q.reject('Table' + table + ' does not exist')); | ||
}); | ||
hasTable: function() { | ||
this.bindings.push(this.table); | ||
this._addCommand('tableExists'); | ||
return this._setType('tableExists'); | ||
} | ||
}; | ||
// SchemaGrammar | ||
// Knex.SchemaBuilder | ||
// -------- | ||
var SchemaGrammar = function(mixins) { | ||
_.extend(this, mixins); | ||
}; | ||
_.extend(SchemaGrammar.prototype, Grammar.prototype, { | ||
// Compile a foreign key command. | ||
compileForeign: function(blueprint, command) { | ||
var table = this.wrapTable(blueprint); | ||
var on = this.wrapTable(command.on); | ||
// We need to prepare several of the elements of the foreign key definition | ||
// before we can create the SQL, such as wrapping the tables and convert | ||
// an array of columns to comma-delimited strings for the SQL queries. | ||
var columns = this.columnize(command.columns); | ||
var onColumns = this.columnize(command.references); | ||
var sql = "alter table " + table + " add constraint " + command.index + " "; | ||
sql += "foreign key (" + columns + ") references " + on + " (" + onColumns + ")"; | ||
// Once we have the basic foreign key creation statement constructed we can | ||
// build out the syntax for what should happen on an update or delete of | ||
// the affected columns, which will get something like "cascade", etc. | ||
if (command.onDelete) sql += " on delete " + command.onDelete; | ||
if (command.onUpdate) sql += " on update " + command.onUpdate; | ||
return sql; | ||
}, | ||
// Each of the column types have their own compiler functions which are | ||
// responsible for turning the column definition into its SQL format | ||
// for the platform. Then column modifiers are compiled and added. | ||
getColumns: function(blueprint) { | ||
var columns = []; | ||
for (var i = 0, l = blueprint.columns.length; i < l; i++) { | ||
var column = blueprint.columns[i]; | ||
var sql = this.wrap(column) + ' ' + this.getType(column); | ||
columns.push(this.addModifiers(sql, blueprint, column)); | ||
} | ||
return columns; | ||
}, | ||
// Add the column modifiers to the definition. | ||
addModifiers: function(sql, blueprint, column) { | ||
for (var i = 0, l = this.modifiers.length; i < l; i++) { | ||
var modifier = this.modifiers[i]; | ||
var method = "modify" + modifier; | ||
if (_.has(this, method)) { | ||
sql += this[method](blueprint, column) || ''; | ||
} | ||
} | ||
return sql; | ||
}, | ||
// Get the primary key command if it exists on the blueprint. | ||
getCommandByName: function(blueprint, name) { | ||
var commands = this.getCommandsByName(blueprint, name); | ||
if (commands.length > 0) return commands[0]; | ||
}, | ||
// Get all of the commands with a given name. | ||
getCommandsByName: function(blueprint, name) { | ||
return _.where(blueprint.commands, function(value) { return value.name == name; }); | ||
}, | ||
// Get the SQL for the column data type. | ||
getType: function(column) { | ||
return this["type" + capitalize(column.type)](column); | ||
}, | ||
// Add a prefix to an array of values, utilized in the client libs. | ||
prefixArray: function(prefix, values) { | ||
return _.map(values, function(value) { return prefix + ' ' + value; }); | ||
}, | ||
// Wrap a table in keyword identifiers. | ||
wrapTable: function(table) { | ||
if (table instanceof Blueprint) table = table.table; | ||
return Grammar.prototype.wrapTable.call(this, table); | ||
}, | ||
// Wrap a value in keyword identifiers. | ||
wrap: function(value) { | ||
if (value instanceof Chainable) value = value.name; | ||
return Grammar.prototype.wrap.call(this, value); | ||
}, | ||
// Format a value so that it can be used in "default" clauses. | ||
getDefaultValue: function(value) { | ||
if (value === true || value === false) { | ||
return parseInt(value, 10); | ||
} | ||
return '' + value; | ||
} | ||
}); | ||
// Knex.Blueprint | ||
// ------ | ||
var Blueprint = Knex.Blueprint = function(table, client) { | ||
var SchemaBuilder = Knex.SchemaBuilder = function(table) { | ||
this.table = table; | ||
this.columns = []; | ||
this.commands = []; | ||
this.client = client; | ||
this.bindings = []; | ||
}; | ||
Blueprint.prototype = { | ||
_.extend(SchemaBuilder.prototype, Common, { | ||
_source: 'SchemaBuilder', | ||
// A callback from the table building `Knex.schemaBuilder` calls. | ||
callback: function(callback) { | ||
callback.call(this, this); | ||
if (callback) callback.call(this, this); | ||
return this; | ||
}, | ||
// Builds the schemaBuilder statements to be executed. | ||
build: function(grammar) { | ||
var statements = this.toSql(grammar); | ||
var promises = []; | ||
var dfd = Q.defer(); | ||
var builder = this; | ||
this.client.pool.acquire(function(err, connection) { | ||
builder.connection = connection; | ||
for (var i = 0, l = statements.length; i < l; i++) { | ||
var statement = statements[i]; | ||
promises.push(Knex.runQuery(builder, {sql: statement})); | ||
} | ||
// Ensures all queries for the same table | ||
// are run on the same connection. | ||
return Q.all(promises).then(dfd.resolve, dfd.reject).fin(function() { | ||
builder.client.pool.release(connection); | ||
}); | ||
}); | ||
return dfd.promise; | ||
}, | ||
// Get the raw sql statements for the blueprint. | ||
toSql: function(grammar) { | ||
toSql: function() { | ||
@@ -1064,5 +1083,5 @@ // Add the commands that are implied by the blueprint. | ||
var method = 'compile' + capitalize(command.name); | ||
if (_.has(grammar, method)) { | ||
var sql = grammar[method](this, command); | ||
statements.push(sql); | ||
if (_.has(this.grammar, method)) { | ||
var sql = this.grammar[method](this, command); | ||
statements = statements.concat(sql); | ||
} | ||
@@ -1084,20 +1103,2 @@ } | ||
// Indicate that the table needs to be created. | ||
createTable: function() { | ||
this._addCommand('createTable'); | ||
return this; | ||
}, | ||
// Indicate that the table should be dropped. | ||
dropTable: function() { | ||
this._addCommand('dropTable'); | ||
return this; | ||
}, | ||
// Indicate that the table should be dropped if it exists. | ||
dropTableIfExists: function() { | ||
this._addCommand('dropTableIfExists'); | ||
return this; | ||
}, | ||
// Indicate that the given columns should be dropped. | ||
@@ -1109,7 +1110,2 @@ dropColumn: function(columns) { | ||
// Rename the table to a given name. | ||
renameTable: function(to) { | ||
return this._addCommand('renameTable', {to: to}); | ||
}, | ||
// Indicate that the given columns should be dropped. | ||
@@ -1310,3 +1306,3 @@ dropColumns: function() { | ||
} | ||
}; | ||
}); | ||
@@ -1339,2 +1335,3 @@ // Chainable object used in creating SchemaBuilder commands. | ||
// Adds an index on the specified column. | ||
index: function(name) { | ||
@@ -1345,2 +1342,3 @@ this.isIndex = name || true; | ||
// Sets this column as the primary key. | ||
primary: function(name) { | ||
@@ -1351,5 +1349,13 @@ this.isPrimary = name || true; | ||
// Sets this column as unique. | ||
unique: function(name) { | ||
this.isUnique = name || true; | ||
return this; | ||
}, | ||
// Sets the column to be inserted after another, | ||
// used in MySql alter tables. | ||
after: function(name) { | ||
this.isAfter = name; | ||
return this; | ||
} | ||
@@ -1359,2 +1365,95 @@ | ||
Knex.SchemaGrammar = { | ||
// Compile a foreign key command. | ||
compileForeign: function(blueprint, command) { | ||
var table = this.wrapTable(blueprint); | ||
var on = this.wrapTable(command.on); | ||
// We need to prepare several of the elements of the foreign key definition | ||
// before we can create the SQL, such as wrapping the tables and convert | ||
// an array of columns to comma-delimited strings for the SQL queries. | ||
var columns = this.columnize(command.columns); | ||
var onColumns = this.columnize(command.references); | ||
var sql = "alter table " + table + " add constraint " + command.index + " "; | ||
sql += "foreign key (" + columns + ") references " + on + " (" + onColumns + ")"; | ||
// Once we have the basic foreign key creation statement constructed we can | ||
// build out the syntax for what should happen on an update or delete of | ||
// the affected columns, which will get something like "cascade", etc. | ||
if (command.onDelete) sql += " on delete " + command.onDelete; | ||
if (command.onUpdate) sql += " on update " + command.onUpdate; | ||
return sql; | ||
}, | ||
// Each of the column types have their own compiler functions which are | ||
// responsible for turning the column definition into its SQL format | ||
// for the platform. Then column modifiers are compiled and added. | ||
getColumns: function(blueprint) { | ||
var columns = []; | ||
for (var i = 0, l = blueprint.columns.length; i < l; i++) { | ||
var column = blueprint.columns[i]; | ||
var sql = this.wrap(column) + ' ' + this.getType(column); | ||
columns.push(this.addModifiers(sql, blueprint, column)); | ||
} | ||
return columns; | ||
}, | ||
// Add the column modifiers to the definition. | ||
addModifiers: function(sql, blueprint, column) { | ||
for (var i = 0, l = this.modifiers.length; i < l; i++) { | ||
var modifier = this.modifiers[i]; | ||
var method = "modify" + modifier; | ||
if (_.has(this, method)) { | ||
sql += this[method](blueprint, column) || ''; | ||
} | ||
} | ||
return sql; | ||
}, | ||
// Get the primary key command if it exists on the blueprint. | ||
getCommandByName: function(blueprint, name) { | ||
var commands = this.getCommandsByName(blueprint, name); | ||
if (commands.length > 0) return commands[0]; | ||
}, | ||
// Get all of the commands with a given name. | ||
getCommandsByName: function(blueprint, name) { | ||
return _.where(blueprint.commands, function(value) { return value.name == name; }); | ||
}, | ||
// Get the SQL for the column data type. | ||
getType: function(column) { | ||
return this["type" + capitalize(column.type)](column); | ||
}, | ||
// Add a prefix to an array of values, utilized in the client libs. | ||
prefixArray: function(prefix, values) { | ||
return _.map(values, function(value) { return prefix + ' ' + value; }); | ||
}, | ||
// Wrap a table in keyword identifiers. | ||
wrapTable: function(table) { | ||
if (table instanceof SchemaBuilder) table = table.table; | ||
return Knex.Grammar.wrapTable.call(this, table); | ||
}, | ||
// Wrap a value in keyword identifiers. | ||
wrap: function(value) { | ||
if (value instanceof Chainable) value = value.name; | ||
return Knex.Grammar.wrap.call(this, value); | ||
}, | ||
// Format a value so that it can be used in "default" clauses. | ||
getDefaultValue: function(value) { | ||
if (value instanceof Raw) return value.value; | ||
if (value === true || value === false) { | ||
return parseInt(value, 10); | ||
} | ||
return '' + value; | ||
} | ||
}; | ||
var capitalize = function(word) { | ||
@@ -1372,3 +1471,11 @@ return word.charAt(0).toUpperCase() + word.slice(1); | ||
// ------- | ||
// Helpful for injecting a snippet of raw SQL into a | ||
// `Knex` block... in most cases, we'll check if the value | ||
// is an instanceof Raw, and if it is, use the supplied value. | ||
Knex.Raw = function(value) { | ||
return new Raw(value); | ||
}; | ||
var Raw = function(value) { | ||
this.value = value; | ||
@@ -1384,12 +1491,36 @@ }; | ||
// and returns a deferred promise. | ||
Knex.runQuery = function(builder, data) { | ||
Knex.runQuery = function(builder) { | ||
if (builder.transaction) { | ||
if (!builder.transaction.connection) return Q.reject(new Error('The transaction has already completed.')); | ||
builder.connection = builder.transaction.connection; | ||
builder._connection = builder.transaction.connection; | ||
} | ||
// Query on the query builder, which should resolve with a promise, | ||
// spreadable to include more information including the query. | ||
return builder.client.query(data, builder.connection); | ||
// Prep the SQL associated with the builder. | ||
builder.sql = builder.toSql(); | ||
builder.bindings = builder._cleanBindings(); | ||
if (!_.isArray(builder.sql)) builder.sql = [builder.sql]; | ||
var chain; | ||
for (var i = 0, l = builder.sql.length; i < l; i++) { | ||
if (chain) { | ||
chain.then(multiQuery(builder, i, chain)); | ||
} else { | ||
chain = multiQuery(builder, i); | ||
} | ||
} | ||
// Query on the query builder, which should resolve with a promise. | ||
return chain; | ||
}; | ||
// Sets up a multi-query | ||
var multiQuery = function(builder, i, chain) { | ||
if (chain) { | ||
return function() { | ||
return multiQuery(builder, i); | ||
}; | ||
} | ||
return builder.client.query(_.extend({}, builder, {sql: builder.sql[i]})); | ||
}; | ||
// Knex.Initialize | ||
@@ -1406,2 +1537,4 @@ // ------- | ||
// A name for the connection isn't required in | ||
// cases where there is only a single connection. | ||
if (_.isObject(name)) { | ||
@@ -1436,12 +1569,20 @@ options = name; | ||
// Setup the grammars specific to the client. | ||
client.grammar = _.extend({}, Knex.Grammar, client.grammar); | ||
client.schemaGrammar = _.extend({}, client.grammar, Knex.SchemaGrammar, client.schemaGrammar); | ||
// If this is named "default" then we're setting this on the Knex | ||
if (name === 'default') { | ||
Target = Knex.Instances['default'] = Knex; | ||
Target = Knex; | ||
} else { | ||
Target = Knex.Instances[name] = function(table) { | ||
return new Knex.Builder(table, client); | ||
Target = function(table) { | ||
var builder = new Target.Builder(table); | ||
builder.client = client; | ||
builder.grammar = client.grammar; | ||
return builder; | ||
}; | ||
// Inherit static properties. | ||
_.extend(Target, _.omit(Knex, 'Initialize', 'Instances')); | ||
// Inherit static properties, without any that don't apply except | ||
// on the "root" `Knex`. | ||
_.extend(Target, _.omit(Knex, 'Initialize', 'Instances', 'VERSION')); | ||
} | ||
@@ -1454,2 +1595,8 @@ | ||
Target.client = client; | ||
Target.instanceName = name; | ||
// Add this instance to the global `Knex` instances, and return. | ||
Knex.Instances[name] = Target; | ||
return Target; | ||
}; | ||
@@ -1461,2 +1608,3 @@ | ||
'postgres' : './clients/postgres.js', | ||
'sqlite' : './clients/sqlite3.js', | ||
'sqlite3' : './clients/sqlite3.js' | ||
@@ -1463,0 +1611,0 @@ }; |
{ | ||
"name": "knex", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"description": "a fun sql query builder", | ||
@@ -11,8 +11,11 @@ "main": "knex.js", | ||
"mocha": "1.7.x", | ||
"mysql": "~2.0.0-alpha5" | ||
"objectdump": ">=0.3.0", | ||
"mysql": "~2.0.0-alpha7", | ||
"pg": "~1.1.0", | ||
"sqlite3": "~2.1.7" | ||
}, | ||
"dependencies": { | ||
"q": "0.9.x", | ||
"underscore": "1.4.x", | ||
"generic-pool": "2.0.x" | ||
"q": "~0.9.3", | ||
"underscore": "~1.4.4", | ||
"generic-pool": "~2.0.3" | ||
}, | ||
@@ -22,3 +25,3 @@ "scripts": { | ||
}, | ||
"repository": "", | ||
"repository": "https://github.com/tgriesser/knex", | ||
"keywords": [ | ||
@@ -29,10 +32,4 @@ "sql", | ||
], | ||
"author": { | ||
"name": "Tim Griesser" | ||
}, | ||
"license": "MIT", | ||
"readme": "# Knex Query Builder", | ||
"readmeFilename": "README.md", | ||
"_id": "knex@0.0.1", | ||
"_from": "knex@" | ||
"author": "Tim Griesser", | ||
"license": "MIT" | ||
} |
@@ -1,1 +0,21 @@ | ||
# Knex Query Builder | ||
``` | ||
._____. ______ | ||
| | / / | ||
| | / / | ||
| | _____ ._____ ._____. ,_____________. ______ / / | ||
| | / / | \ | | / \ \ \ / / | ||
| | / / | \ | | / \ \ \ / / | ||
| | / / | \ | | / ,______. \ \ \ / / | ||
| | / / | \ | | / / \ \ \ \/ / | ||
| |/ \ | \ | | | | ____\ | \ / | ||
| |\ \ | \| | | | / | \ \ | ||
| | \ \ | |\ | | | /__________| / \ | ||
| | \ \ | | \ | \ \ / /\ \ | ||
| | \ \ | | \ | \ \__________/\ / / \ \ | ||
| | \ \ | | \ | \ \ / / \ \ | ||
|_____| \_____\ |_____| \______| \_______________/ /_____/ \_____\ | ||
``` | ||
Knex.js is a multi-dialect query builder for Node.js. | ||
[http://knexjs.org](knexjs.org) |
@@ -0,6 +1,58 @@ | ||
var Q = require('q'); | ||
var _ = require('underscore'); | ||
var Knex = require('../knex'); | ||
var conn = require(process.env.KNEX_TEST || './shared/config'); | ||
require('./mock'); | ||
// The output goes here. | ||
exports.output = {}; | ||
// require('./mysql/index'); | ||
// require('./sqlite3/index'); | ||
// require('./postgres/index'); | ||
var MySql = Knex.Initialize('mysql', { | ||
client: 'mysql', | ||
connection: conn.mysql | ||
}); | ||
var Sqlite3 = Knex.Initialize('sqlite3', { | ||
client: 'sqlite3', | ||
connection: conn.sqlite3 | ||
}); | ||
var Postgres = Knex.Initialize('postgres', { | ||
client: 'postgres', | ||
connection: conn.postgres | ||
}); | ||
var runQuery = Knex.runQuery; | ||
Knex.runQuery = function(builder) { | ||
if (builder.transaction) { | ||
if (!builder.transaction.connection) return Q.reject(new Error('The transaction has already completed.')); | ||
builder._connection = builder.transaction.connection; | ||
} | ||
// Query on the query builder, which should resolve with a promise. | ||
return Q({ | ||
sql: builder.toSql(), | ||
bindings: builder._cleanBindings() | ||
}); | ||
}; | ||
describe('Knex', function() { | ||
var allDone; | ||
Q.all([ | ||
require('./string')(MySql, 'mysql'), | ||
require('./string')(Postgres, 'postgres'), | ||
require('./string')(Sqlite3, 'sqlite3') | ||
]).then(function() { | ||
Knex.runQuery = runQuery; | ||
return Q.all([ | ||
require('./regular')(MySql, 'mysql'), | ||
require('./regular')(Postgres, 'postgres'), | ||
require('./regular')(Sqlite3, 'sqlite3') | ||
]); | ||
}).then(function() { | ||
allDone(); | ||
}, allDone); | ||
after(function(ok) { | ||
allDone = ok; | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
162491
4838
21
5
24
9
1
Updatedgeneric-pool@~2.0.3
Updatedq@~0.9.3
Updatedunderscore@~1.4.4