Comparing version 0.1.8 to 0.2.0
@@ -0,3 +1,4 @@ | ||
var whenfn = require('when/function'); | ||
var nodefn = require('when/node/function'); | ||
var _ = require('underscore'); | ||
var _ = require('underscore'); | ||
@@ -18,3 +19,3 @@ // Setup is called with the context of the current client. | ||
var instance = this; | ||
this.pool = require('generic-pool').Pool(_.extend({ | ||
var poolInstance = this.pool = require('generic-pool').Pool(_.extend({ | ||
name: 'pool-' + name, | ||
@@ -49,2 +50,11 @@ min: 2, | ||
}, this.poolDefaults, options.pool)); | ||
// Default to draining on exit. | ||
if (poolInstance.drainOnExit !== false && typeof process === 'object') { | ||
process.on('exit', function() { | ||
poolInstance.drain(function() { | ||
poolInstance.destroyAllNow(); | ||
}); | ||
}); | ||
} | ||
}; | ||
@@ -73,3 +83,3 @@ | ||
releaseConnection: function(conn) { | ||
return nodefn.call(this.pool.release, conn); | ||
return whenfn.call(this.pool.release, conn); | ||
}, | ||
@@ -93,4 +103,5 @@ | ||
}).ensure(function() { | ||
ctx.releaseConnection(trans.connection); | ||
trans.connection = null; | ||
return ctx.releaseConnection(trans.connection).then(function() { | ||
trans.connection = null; | ||
}); | ||
}); | ||
@@ -105,2 +116,16 @@ } | ||
// 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 _.filter(blueprint.commands, function(value) { return value.name == name; }) || []; | ||
}, | ||
// Used to compile any database specific items. | ||
compileAdditional: function() {}, | ||
// Compile a create table command. | ||
@@ -127,2 +152,12 @@ compileCreateTable: function(blueprint) { | ||
// Create the column definition for a string type. | ||
typeString: function(column) { | ||
return "varchar(" + column.length + ")"; | ||
}, | ||
// Create the column definition for a text type. | ||
typeText: function() { | ||
return 'text'; | ||
}, | ||
// Create the column definition for a tiny integer type. | ||
@@ -148,2 +183,12 @@ typeTinyInteger: function() { | ||
// Create the column definition for a json type. | ||
typeJson: function() { | ||
return 'text'; | ||
}, | ||
// Create the column definition for a uuid type. | ||
typeUuid: function() { | ||
return 'char(36)'; | ||
}, | ||
// Get the SQL for a nullable column modifier. | ||
@@ -150,0 +195,0 @@ modifyNullable: function(blueprint, column) { |
@@ -10,2 +10,3 @@ var When = require('when'); | ||
base.setup.call(this, MysqlClient, name, options); | ||
this.dialect = 'mysql'; | ||
}; | ||
@@ -31,4 +32,5 @@ | ||
conn.query(builder.sql, builder.bindings, function (err, resp) { | ||
if (err) { return dfd.reject(err); } | ||
if (err) return dfd.reject(err); | ||
if (builder._source === 'Raw') return dfd.resolve(resp); | ||
@@ -38,4 +40,3 @@ | ||
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)); | ||
return dfd.resolve(resp.length > 0); | ||
} else { | ||
@@ -99,3 +100,2 @@ return dfd.resolve(null); | ||
if (conn.collation) sql += ' collate ' + conn.collation; | ||
if (blueprint.isEngine) { | ||
@@ -105,5 +105,9 @@ sql += ' engine = ' + blueprint.isEngine; | ||
if (blueprint.tableComment) { | ||
var maxTableCommentLength = 60; | ||
sql += " comment = '" + blueprint.tableComment + "'" | ||
// Checks if the table is commented | ||
var isCommented = this.getCommandByName(blueprint, 'comment'); | ||
// TODO: Handle max comment length. | ||
var maxTableCommentLength = 60; | ||
if (isCommented) { | ||
sql += " comment = '" + isCommented.comment + "'"; | ||
} | ||
@@ -180,5 +184,5 @@ | ||
// Create the column definition for a string type. | ||
typeString: function(column) { | ||
return "varchar(" + column.length + ")"; | ||
// Compiles the comment on the table. | ||
compileComment: function(blueprint, command) { | ||
// Handled on create table... | ||
}, | ||
@@ -232,3 +236,3 @@ | ||
typeTimestamp: function() { | ||
return 'timestamp default 0'; | ||
return 'timestamp'; | ||
}, | ||
@@ -268,7 +272,8 @@ | ||
// Get the SQL for a comment column modifier. (MySQL) | ||
// Get the SQL for a comment column modifier. | ||
modifyComment: function(blueprint, column) { | ||
// TODO: Look into limiting this length. | ||
var maxColumnCommentLength = 255; | ||
if (_.isString(column.comment)) { | ||
return " comment '" + column.comment + "'"; | ||
if (column.isCommented && _.isString(column.isCommented)) { | ||
return " comment '" + column.isCommented + "'"; | ||
} | ||
@@ -275,0 +280,0 @@ } |
@@ -10,2 +10,3 @@ var When = require('when'); | ||
base.setup.call(this, PostgresClient, name, options); | ||
this.dialect = 'postgresql'; | ||
}; | ||
@@ -22,2 +23,3 @@ | ||
var instance = this; | ||
return When((builder._connection || this.getConnection())) | ||
@@ -46,4 +48,3 @@ .then(function(conn) { | ||
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)); | ||
return dfd.resolve(resp.rows.length > 0); | ||
} else { | ||
@@ -57,3 +58,3 @@ return dfd.resolve(null); | ||
} else if (resp.command === 'INSERT') { | ||
resp = _.map(resp.rows, function(row) { return row[builder._idAttribute]; }); | ||
resp = _.map(resp.rows, function(row) { return row[builder.isReturning]; }); | ||
} else if (resp.command === 'UPDATE' || resp.command === 'DELETE') { | ||
@@ -77,6 +78,20 @@ resp = resp.rowCount; | ||
getRawConnection: function(callback) { | ||
var conn = new pg.Client(this.connectionSettings); | ||
conn.connect(function(err) { | ||
callback(err, conn); | ||
var instance = this; | ||
var connection = new pg.Client(this.connectionSettings); | ||
connection.connect(function(err) { | ||
if (!instance.version && !err) { | ||
return instance.checkVersion.call(instance, connection, callback); | ||
} | ||
callback(err, connection); | ||
}); | ||
}, | ||
// Check Version | ||
checkVersion: function(connection, callback) { | ||
var instance = this; | ||
connection.query('select version();', function(err, resp) { | ||
if (err) return callback(err); | ||
instance.version = /^PostgreSQL (.*?) /.exec(resp.rows[0].version)[1]; | ||
callback(null, connection); | ||
}); | ||
} | ||
@@ -102,4 +117,4 @@ | ||
var sql = require('../knex').Grammar.compileInsert.call(this, qb); | ||
if (qb._idAttribute) { | ||
sql += ' returning "' + qb._idAttribute + '"'; | ||
if (qb.isReturning) { | ||
sql += ' returning "' + qb.isReturning + '"'; | ||
} | ||
@@ -180,29 +195,18 @@ return sql; | ||
compileComment: function(blueprint, command) { | ||
var table = this.wrapTable(blueprint); | ||
var comment; | ||
if (command.comment == void 0) { | ||
comment = 'NULL' | ||
} else { | ||
comment = "'" + command.comment + "'"; | ||
var sql = ''; | ||
if (command.comment) { | ||
sql += 'comment on table ' + this.wrapTable(blueprint) + ' is ' + "'" + command.comment + "'"; | ||
} | ||
var identifier; | ||
if (command.isTable) { | ||
identifier = 'table ' + table; | ||
} else { | ||
var column = this.wrap(command.columnName); | ||
identifier = 'column ' + table + '.' + column; | ||
} | ||
return 'comment on ' + identifier + ' is ' + comment; | ||
return sql; | ||
}, | ||
// Create the column definition for a string type. | ||
typeString: function(column) { | ||
return "varchar(" + column.length + ")"; | ||
// Compile any additional postgres specific items. | ||
compileAdditional: function(blueprint, command) { | ||
return _.compact(_.map(blueprint.columns, function(column) { | ||
if (column.isCommented && _.isString(column.isCommented)) { | ||
return 'comment on column ' + this.wrapTable(blueprint) + '.' + this.wrap(column.name) + " is '" + column.isCommented + "'"; | ||
} | ||
}, this)); | ||
}, | ||
// Create the column definition for a text type. | ||
typeText: function() { | ||
return 'text'; | ||
}, | ||
// Create the column definition for a integer type. | ||
@@ -234,4 +238,5 @@ typeInteger: function(column) { | ||
// Create the column definition for an enum type. | ||
// Using method 2 here: http://stackoverflow.com/questions/10923213/postgres-enum-data-type-or-check-constraint | ||
typeEnum: function(column) { | ||
return "enum('" + column.allowed.join("', '") + "')"; | ||
return 'text check(' + this.wrap(column.name) + " in('" + column.allowed.join("', '") + "'))"; | ||
}, | ||
@@ -259,2 +264,17 @@ | ||
// Create the column definition for a uuid type. | ||
typeUuid: function() { | ||
return 'uuid'; | ||
}, | ||
// Create the column definition for a json type, | ||
// checking whether the json type is supported - falling | ||
// back to "text" if it's not. | ||
typeJson: function(column, blueprint) { | ||
if (parseFloat(blueprint.client.version) >= 9.2) { | ||
return 'json'; | ||
} | ||
return 'text'; | ||
}, | ||
// Get the SQL for an auto-increment column modifier. | ||
@@ -266,2 +286,3 @@ modifyIncrement: function(blueprint, column) { | ||
} | ||
}); |
@@ -11,2 +11,3 @@ var When = require('when'); | ||
base.setup.call(this, Sqlite3Client, name, options); | ||
this.dialect = 'sqlite3'; | ||
}; | ||
@@ -40,4 +41,3 @@ | ||
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)); | ||
return dfd.resolve(resp.length > 0); | ||
} else { | ||
@@ -133,5 +133,4 @@ return dfd.resolve(null); | ||
var keys = _.keys(values[0]).sort(); | ||
var names = this.columnize(keys); | ||
var columns = []; | ||
var columns = _.pluck(values[0], 0); | ||
var blocks = []; | ||
@@ -141,14 +140,13 @@ // SQLite requires us to build the multi-row insert as a listing of select with | ||
// then join them all together with select unions to complete the queries. | ||
for (var i = 0, l = keys.length; i < l; i++) { | ||
var column = keys[i]; | ||
columns.push('? as ' + this.wrap(column)); | ||
for (var i = 0, l = columns.length; i < l; i++) { | ||
blocks.push('? as ' + this.wrap(columns[i])); | ||
} | ||
var joinedColumns = columns.join(', '); | ||
columns = []; | ||
var joinedColumns = blocks.join(', '); | ||
blocks = []; | ||
for (i = 0, l = values.length; i < l; i++) { | ||
columns.push(joinedColumns); | ||
blocks.push(joinedColumns); | ||
} | ||
return "insert into " + table + " (" + names + ") select " + columns.join(' union all select '); | ||
return "insert into " + table + " (" + this.columnize(columns) + ") select " + blocks.join(' union all select '); | ||
}, | ||
@@ -198,9 +196,9 @@ | ||
var sql = ''; | ||
var foreigns = this.getCommandsByName(blueprint, 'foreign'); | ||
for (var i = 0, l = foreigns.length; i < l; i++) { | ||
var foreign = foreigns[i]; | ||
var on = this.wrapTable(foreign.on); | ||
var columns = this.columnize(foreign.columns); | ||
var onColumns = this.columnize(foreign.references); | ||
sql += ', foreign key(' + columns + ') references ' + on + '(' + onColumns + ')'; | ||
var commands = this.getCommandsByName(blueprint, 'foreign'); | ||
for (var i = 0, l = commands.length; i < l; i++) { | ||
var command = commands[i]; | ||
var column = this.columnize(command.columns); | ||
var foreignTable = this.wrapTable(command.foreignTable); | ||
var foreignColumn = this.columnize([command.foreignColumn]); | ||
sql += ', foreign key(' + column + ') references ' + foreignTable + '(' + foreignColumn + ')'; | ||
} | ||
@@ -210,13 +208,2 @@ 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 _.find(blueprint.commands, function(value) { return value.name == name; }) || []; | ||
}, | ||
// Get the primary key syntax for a table creation statement. | ||
@@ -276,12 +263,2 @@ addPrimaryKeys: function(blueprint) { | ||
// Create the column definition for a string type. | ||
typeString: function() { | ||
return 'varchar'; | ||
}, | ||
// Create the column definition for a text type. | ||
typeText: function() { | ||
return 'text'; | ||
}, | ||
// Create the column definition for a integer type. | ||
@@ -288,0 +265,0 @@ typeInteger: function() { |
278
knex.js
@@ -1,2 +0,2 @@ | ||
// Knex.js 0.1.8 | ||
// Knex.js 0.2.0 | ||
// | ||
@@ -13,3 +13,3 @@ // (c) 2013 Tim Griesser | ||
var _ = require('underscore'); | ||
var When = require('when'); | ||
var when = require('when'); | ||
@@ -27,3 +27,3 @@ var push = Array.prototype.push; | ||
// Keep in sync with package.json | ||
Knex.VERSION = '0.1.8'; | ||
Knex.VERSION = '0.2.0'; | ||
@@ -105,3 +105,7 @@ // Methods common to both the `Grammar` and `SchemaGrammar` interfaces, | ||
for (var i = 0, l = bindings.length; i < l; i++) { | ||
if (!(bindings[i] instanceof Raw)) cleaned.push(bindings[i]); | ||
if (!(bindings[i] instanceof Raw)) { | ||
cleaned.push(bindings[i]); | ||
} else { | ||
push.apply(cleaned, bindings[i].bindings); | ||
} | ||
} | ||
@@ -114,3 +118,3 @@ return cleaned; | ||
if (this.transaction) { | ||
if (!this.transaction.connection) return When.reject(new Error('The transaction has already completed.')); | ||
if (!this.transaction.connection) return when.reject(new Error('The transaction has already completed.')); | ||
this._connection = this.transaction.connection; | ||
@@ -325,6 +329,5 @@ } | ||
compileInsert: function(qb) { | ||
var values = qb.values; | ||
var table = this.wrapTable(qb.table); | ||
var columns = this.columnize(_.keys(values[0]).sort()); | ||
var parameters = this.parameterize(_.values(values[0])); | ||
var values = qb.values; | ||
var table = this.wrapTable(qb.table); | ||
var columns = _.pluck(values[0], 0); | ||
var paramBlocks = []; | ||
@@ -337,6 +340,6 @@ | ||
for (var i = 0, l = values.length; i < l; ++i) { | ||
paramBlocks.push("(" + parameters + ")"); | ||
paramBlocks.push("(" + this.parameterize(_.pluck(values[i], 1)) + ")"); | ||
} | ||
return "insert into " + table + " (" + columns + ") values " + paramBlocks.join(', '); | ||
return "insert into " + table + " (" + this.columnize(columns) + ") values " + paramBlocks.join(', '); | ||
}, | ||
@@ -388,3 +391,3 @@ | ||
var segments; | ||
if (value instanceof Raw) return value.value; | ||
if (value instanceof Raw) return value.sql; | ||
if (_.isNumber(value)) return value; | ||
@@ -418,2 +421,3 @@ if (value.toLowerCase().indexOf(' as ') !== -1) { | ||
columnize: function(columns) { | ||
if (!_.isArray(columns)) columns = [columns]; | ||
return _.map(columns, this.wrap, this).join(', '); | ||
@@ -423,2 +427,3 @@ }, | ||
parameterize: function(values) { | ||
if (!_.isArray(values)) values = [values]; | ||
return _.map(values, this.parameter, this).join(', '); | ||
@@ -428,3 +433,3 @@ }, | ||
parameter: function(value) { | ||
return (value instanceof Raw ? value.value : '?'); | ||
return (value instanceof Raw ? value.sql : '?'); | ||
} | ||
@@ -458,12 +463,2 @@ }; | ||
_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. | ||
@@ -503,3 +498,3 @@ from: function(tableName) { | ||
var items = [ | ||
'_idAttribute', 'isDistinct', 'joins', 'wheres', 'orders', | ||
'isDistinct', 'joins', 'wheres', 'orders', | ||
'columns', 'bindings', 'grammar', 'transaction', 'unions' | ||
@@ -523,3 +518,4 @@ ]; | ||
this.bindings = []; | ||
this.isDistinct = false; | ||
this.isDistinct = false; | ||
this.isReturning = false; | ||
}, | ||
@@ -552,3 +548,3 @@ | ||
if (column instanceof Raw) { | ||
return this.whereRaw(column.value, bool); | ||
return this.whereRaw(column.sql, column.bindings, bool); | ||
} | ||
@@ -591,4 +587,6 @@ if (_.isObject(column)) { | ||
// Adds a raw `where` clause to the query. | ||
whereRaw: function(sql, bool) { | ||
whereRaw: function(sql, bindings, bool) { | ||
bindings = _.isArray(bindings) ? bindings : (bindings ? [bindings] : []); | ||
this.wheres.push({type: 'Raw', sql: sql, bool: bool || 'and'}); | ||
push.apply(this.bindings, bindings); | ||
return this; | ||
@@ -598,4 +596,4 @@ }, | ||
// Adds a raw `or where` clause to the query. | ||
orWhereRaw: function(sql) { | ||
return this.whereRaw(sql, 'or'); | ||
orWhereRaw: function(sql, bindings) { | ||
return this.whereRaw(sql, bindings, 'or'); | ||
}, | ||
@@ -804,3 +802,4 @@ | ||
// Sets the values for an `insert` query. | ||
insert: function(values) { | ||
insert: function(values, returning) { | ||
if (returning) this.returning(returning); | ||
this.values = this._prepValues(values); | ||
@@ -810,2 +809,8 @@ return this._setType('insert'); | ||
// Sets the returning value for the query. | ||
returning: function(returning) { | ||
this.isReturning = returning; | ||
return this; | ||
}, | ||
// Sets the values for an `update` query. | ||
@@ -819,3 +824,3 @@ update: function(values) { | ||
this.bindings = bindings.concat(this.bindings || []); | ||
this.values = obj; | ||
this.values = obj; | ||
return this._setType('update'); | ||
@@ -846,4 +851,6 @@ }, | ||
transacting: function(t) { | ||
if (!t) throw new Error('A transaction object must be passed to "transacting".'); | ||
this.transaction = t; | ||
if (t) { | ||
if (this.transaction) throw new Error('A transaction has already been set for the current query chain'); | ||
this.transaction = t; | ||
} | ||
return this; | ||
@@ -857,3 +864,3 @@ }, | ||
for (var i = 0, l = values.length; i<l; i++) { | ||
var obj = sortObject(values[i]); | ||
var obj = values[i] = sortObject(values[i]); | ||
for (var i2 = 0, l2 = obj.length; i2 < l2; i2++) { | ||
@@ -962,3 +969,5 @@ this.bindings.push(obj[i2][1]); | ||
var transaction = function(container) { | ||
var client = this.client; | ||
return client.startTransaction().then(function(connection) { | ||
@@ -968,11 +977,11 @@ | ||
// transaction completes or fails, we know what to do. | ||
var dfd = When.defer(); | ||
var dfd = when.defer(); | ||
// Ensure the transacting object methods are bound with the correct context. | ||
// The object passed around inside the transaction container. | ||
var containerObj = { | ||
commit: function(msg) { | ||
client.finishTransaction('commit', this, dfd, msg); | ||
commit: function(val) { | ||
client.finishTransaction('commit', this, dfd, val); | ||
}, | ||
rollback: function(msg) { | ||
client.finishTransaction('rollback', this, dfd, msg); | ||
rollback: function(err) { | ||
client.finishTransaction('rollback', this, dfd, err); | ||
}, | ||
@@ -982,2 +991,4 @@ // "rollback to"? | ||
}; | ||
// Ensure the transacting object methods are bound with the correct context. | ||
_.bindAll(containerObj, 'commit', 'rollback'); | ||
@@ -1084,9 +1095,12 @@ | ||
if (this.columns.length > 0 && !this.creating()) { | ||
this.commands.unshift(new Chainable({name: 'add'})); | ||
this.commands.unshift({name: 'add'}); | ||
} | ||
// Add an "additional" command, for any extra dialect-specific logic. | ||
this.commands.push({name: 'additional'}); | ||
// Add indicies | ||
for (var i = 0, l = this.columns.length; i < l; i++) { | ||
var column = this.columns[i]; | ||
var indices = ['primary', 'unique', 'index']; | ||
var indices = ['primary', 'unique', 'index', 'foreign']; | ||
@@ -1102,3 +1116,3 @@ continueIndex: | ||
if (column[indexVar] === true) { | ||
this[index](column); | ||
this[index](column, null); | ||
continue continueIndex; | ||
@@ -1110,3 +1124,3 @@ | ||
} else if (_.has(column, indexVar)) { | ||
this[index](column.name, column[indexVar]); | ||
this[index](column.name, column[indexVar], column); | ||
continue continueIndex; | ||
@@ -1117,22 +1131,2 @@ } | ||
// Add table comments. (Postgres) | ||
if (this.tableComment) { | ||
this._addCommand('comment', { | ||
comment: this.tableComment, | ||
isTable: true | ||
}); | ||
} | ||
// Add column comments. (Postgres) | ||
for (var i = 0, l = this.columns.length; i < l; i++) { | ||
var column = this.columns[i]; | ||
if (_.has(column, 'comment')) { | ||
this._addCommand('comment', { | ||
comment: column.comment, | ||
columnName: column.name, | ||
isTable: false | ||
}); | ||
} | ||
} | ||
var statements = []; | ||
@@ -1148,3 +1142,3 @@ | ||
var sql = this.grammar[method](this, command); | ||
statements = statements.concat(sql); | ||
if (sql) statements = statements.concat(sql); | ||
} | ||
@@ -1171,2 +1165,7 @@ } | ||
// Adds a comment to the current table being created. | ||
comment: function(comment) { | ||
return this._addCommand('comment', {comment: comment}); | ||
}, | ||
// Indicate that the given columns should be dropped. | ||
@@ -1218,11 +1217,12 @@ dropColumn: function(columns) { | ||
// Specify a foreign key for the table. | ||
foreign: function(columns, name) { | ||
return this._indexCommand('foreign', columns, name); | ||
// Specify a foreign key for the table, also getting any | ||
// relevant info from the chain during column. | ||
foreign: function(column, name) { | ||
var chained, chainable = this._indexCommand('foreign', column, name); | ||
if (_.isObject(column)) { | ||
chained = _.pick(column, 'foreignColumn', 'foreignTable', 'commandOnDelete', 'commandOnUpdate'); | ||
} | ||
return _.extend(chainable, ForeignChainable, chained); | ||
}, | ||
comment: function(comment) { | ||
this.tableComment = comment || null; | ||
}, | ||
// Create a new auto-incrementing column on the table. | ||
@@ -1309,6 +1309,6 @@ increments: function(column) { | ||
// Add creation and update timestamps to the table. | ||
// Add creation and update dateTime's to the table. | ||
timestamps: function() { | ||
this.timestamp('created_at'); | ||
this.timestamp('updated_at'); | ||
this.dateTime('created_at'); | ||
this.dateTime('updated_at'); | ||
}, | ||
@@ -1323,2 +1323,3 @@ | ||
enu: function(column, allowed) { | ||
if (!_.isArray(allowed)) allowed = [allowed]; | ||
return this._addColumn('enum', column, {allowed: allowed}); | ||
@@ -1337,2 +1338,12 @@ }, | ||
// Create a new json column on the table. | ||
json: function(column) { | ||
return this._addColumn('json', column); | ||
}, | ||
// Create a new uuid column on the table. | ||
uuid: function(column) { | ||
return this._addColumn('uuid', column); | ||
}, | ||
// ---------------------------------------------------------------------- | ||
@@ -1361,3 +1372,3 @@ | ||
var table = this.table.replace(/\.|-/g, '_'); | ||
index = (table + '_' + _.map(columns, function(col) { return col.name; }).join('_') + '_' + type).toLowerCase(); | ||
index = (table + '_' + _.map(columns, function(col) { return col.name || col; }).join('_') + '_' + type).toLowerCase(); | ||
} | ||
@@ -1370,4 +1381,3 @@ return this._addCommand(type, {index: index, columns: columns}); | ||
if (!name) throw new Error('A `name` must be defined to add a column'); | ||
var attrs = _.extend({type: type, name: name}, parameters); | ||
var column = new Chainable(attrs); | ||
var column = _.extend({type: type, name: name}, ChainableColumn, parameters); | ||
this.columns.push(column); | ||
@@ -1379,3 +1389,3 @@ return column; | ||
_addCommand: function(name, parameters) { | ||
var command = new Chainable(_.extend({name: name}, parameters)); | ||
var command = _.extend({name: name}, parameters); | ||
this.commands.push(command); | ||
@@ -1386,8 +1396,33 @@ return command; | ||
// Chainable object used in creating SchemaBuilder commands. | ||
var Chainable = function(obj) { | ||
_.extend(this, obj); | ||
var ForeignChainable = { | ||
// Sets the "column" that the current column references | ||
// as the a foreign key | ||
references: function(column) { | ||
this.isForeign = true; | ||
this.foreignColumn = column || null; | ||
return this; | ||
}, | ||
// Sets the "table" where the foreign key column is located. | ||
inTable: function(table) { | ||
this.foreignTable = table || null; | ||
return this; | ||
}, | ||
// SQL command to run "onDelete" | ||
onDelete: function(command) { | ||
this.commandOnDelete = command || null; | ||
return this; | ||
}, | ||
// SQL command to run "onUpdate" | ||
onUpdate: function(command) { | ||
this.commandOnUpdate = command || null; | ||
return this; | ||
} | ||
}; | ||
Chainable.prototype = { | ||
var ChainableColumn = _.extend({ | ||
@@ -1446,8 +1481,9 @@ // Sets the default value for a column. | ||
comment: function(comment) { | ||
this.comment = comment || null; | ||
this.isCommented = comment || null; | ||
return this; | ||
} | ||
}; | ||
}, ForeignChainable); | ||
Knex.SchemaGrammar = { | ||
@@ -1457,20 +1493,18 @@ | ||
compileForeign: function(blueprint, command) { | ||
var table = this.wrapTable(blueprint); | ||
var on = this.wrapTable(command.on); | ||
var sql; | ||
if (command.foreignTable && command.foreignColumn) { | ||
var table = this.wrapTable(blueprint); | ||
var column = this.columnize(command.columns); | ||
var foreignTable = this.wrapTable(command.foreignTable); | ||
var foreignColumn = this.columnize(command.foreignColumn); | ||
// 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); | ||
sql = "alter table " + table + " add constraint " + command.index + " "; | ||
sql += "foreign key (" + column + ") references " + foreignTable + " (" + foreignColumn + ")"; | ||
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; | ||
// 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.commandOnDelete) sql += " on delete " + command.commandOnDelete; | ||
if (command.commandOnUpdate) sql += " on update " + command.commandOnUpdate; | ||
} | ||
return sql; | ||
@@ -1486,3 +1520,3 @@ }, | ||
var column = blueprint.columns[i]; | ||
var sql = this.wrap(column) + ' ' + this.getType(column); | ||
var sql = this.wrap(column) + ' ' + this.getType(column, blueprint); | ||
columns.push(this.addModifiers(sql, blueprint, column)); | ||
@@ -1506,4 +1540,4 @@ } | ||
// Get the SQL for the column data type. | ||
getType: function(column) { | ||
return this["type" + capitalize(column.type)](column); | ||
getType: function(column, blueprint) { | ||
return this['type' + capitalize(column.type)](column, blueprint); | ||
}, | ||
@@ -1524,3 +1558,3 @@ | ||
wrap: function(value) { | ||
if (value instanceof Chainable) value = value.name; | ||
if (value && value.name) value = value.name; | ||
return Knex.Grammar.wrap.call(this, value); | ||
@@ -1531,3 +1565,3 @@ }, | ||
getDefaultValue: function(value) { | ||
if (value instanceof Raw) return value.value; | ||
if (value instanceof Raw) return value.sql; | ||
if (value === true || value === false) { | ||
@@ -1546,11 +1580,12 @@ return parseInt(value, 10); | ||
// is an instanceof Raw, and if it is, use the supplied value. | ||
Knex.Raw = function(value) { | ||
Knex.Raw = function(sql, bindings) { | ||
if (!Knex.Instances['main']) { | ||
throw new Error('The Knex instance has not been initialized yet.'); | ||
} | ||
return Knex.Instances['main'].Raw(value); | ||
return Knex.Instances['main'].Raw(sql, bindings); | ||
}; | ||
var Raw = function(value) { | ||
this.value = value; | ||
var Raw = function(sql, bindings) { | ||
this.bindings = (!_.isArray(bindings) ? (bindings ? [bindings] : []) : bindings); | ||
this.sql = sql; | ||
}; | ||
@@ -1564,9 +1599,5 @@ | ||
toSql: function() { | ||
return this.value; | ||
}, | ||
return this.sql; | ||
} | ||
// Returns the bindings for a raw query. | ||
_cleanBindings: function() { | ||
return []; | ||
} | ||
}); | ||
@@ -1617,3 +1648,3 @@ | ||
if (Knex.Instances[name]) { | ||
throw new Error('An instance named ' + name + ' already exists'); | ||
throw new Error('An instance named ' + name + ' already exists.'); | ||
} | ||
@@ -1629,3 +1660,7 @@ | ||
client = client.toLowerCase(); | ||
ClientCtor = require(Clients[client]); | ||
try { | ||
ClientCtor = require(Clients[client]); | ||
} catch (e) { | ||
throw new Error(client + ' is not a valid Knex client, did you misspell it?'); | ||
} | ||
} else { | ||
@@ -1657,2 +1692,3 @@ ClientCtor = client; | ||
initSchema(Knex, client); | ||
Knex.client = client; | ||
} | ||
@@ -1672,4 +1708,4 @@ | ||
// Executes a Raw query. | ||
Target.Raw = function(value) { | ||
var raw = new Raw(value); | ||
Target.Raw = function(sql, bindings) { | ||
var raw = new Raw(sql, bindings); | ||
raw.client = client; | ||
@@ -1701,2 +1737,2 @@ return raw; | ||
}).call(this); | ||
}).call(this); |
{ | ||
"name": "knex", | ||
"version": "0.1.8", | ||
"version": "0.2.0", | ||
"description": "A query builder for Postgres, MySQL and SQLite3, designed to be flexible, portable, and fun to use.", | ||
@@ -10,11 +10,12 @@ "main": "knex.js", | ||
"devDependencies": { | ||
"mocha": "1.9.x", | ||
"objectdump": ">=0.3.0", | ||
"mocha": "~1.12.0", | ||
"objectdump": "~0.2.1", | ||
"mysql": "~2.0.0-alpha7", | ||
"pg": "~1.1.0", | ||
"sqlite3": "~2.1.7" | ||
"pg": "~2.3.1", | ||
"sqlite3": "~2.1.7", | ||
"node-uuid": "~1.4.0" | ||
}, | ||
"dependencies": { | ||
"when": ">=2.1.0", | ||
"underscore": "~1.4.4", | ||
"underscore": "~1.5.1", | ||
"generic-pool": "~2.0.3" | ||
@@ -25,3 +26,3 @@ }, | ||
}, | ||
"repository":{ | ||
"repository": { | ||
"type": "git", | ||
@@ -39,5 +40,5 @@ "url": "https://github.com/tgriesser/knex.git" | ||
"name": "Tim Griesser", | ||
"web": "https://github.com/tgriesser" | ||
"web": "https://github.com/tgriesser" | ||
}, | ||
"license": "MIT" | ||
} |
@@ -24,3 +24,9 @@ var equal = require('assert').equal; | ||
connection: conn.mysql, | ||
pool: pool | ||
pool: _.extend({}, pool, { | ||
afterCreate: function(conn, done) { | ||
conn.query("SET sql_mode='TRADITIONAL';", [], function(err) { | ||
done(err); | ||
}); | ||
} | ||
}) | ||
}); | ||
@@ -27,0 +33,0 @@ var Sqlite3 = Knex.Initialize('sqlite3', { |
var uuid = require('node-uuid'); | ||
module.exports = function(Knex, dbName, resolver) { | ||
@@ -7,3 +9,3 @@ | ||
it("should handle simple inserts", function(ok) { | ||
Knex('accounts').insert({ | ||
@@ -17,8 +19,8 @@ first_name: 'Test', | ||
updated_at: new Date() | ||
}).then(resolver(ok), ok); | ||
}, 'id').then(resolver(ok), ok); | ||
}); | ||
it('should allow for using the `exec` interface', function(ok) { | ||
Knex('test_table_two').insert([{ | ||
@@ -36,11 +38,11 @@ account_id: 1, | ||
status: 1 | ||
}]).exec(function(err, resp) { | ||
}], 'id').exec(function(err, resp) { | ||
if (err) return ok(err); | ||
ok(); | ||
}); | ||
}); | ||
it('should handle multi inserts', function (ok) { | ||
Knex('accounts') | ||
@@ -63,3 +65,3 @@ .insert([{ | ||
updated_at: new Date() | ||
}]).then(resolver(ok), ok); | ||
}], 'id').then(resolver(ok), ok); | ||
@@ -86,3 +88,3 @@ }); | ||
email:'test5@example.com' | ||
}]) | ||
}], 'id') | ||
.then(resolver(ok), ok); | ||
@@ -105,3 +107,3 @@ | ||
updated_at: new Date() | ||
}) | ||
}, 'id') | ||
.then(ok, function() { | ||
@@ -126,9 +128,41 @@ ok(); | ||
updated_at: new Date() | ||
}) | ||
}, 'id') | ||
.then(resolver(ok), ok); | ||
}); | ||
it('should not allow inserting invalid values into enum fields', function(ok) { | ||
Knex('datatype_test') | ||
.insert({'enum_value': 'd'}) | ||
.then(function() { | ||
// No errors happen in sqlite3, which doesn't have native support | ||
// for the enum type. | ||
if (Knex.client.dialect === 'sqlite3') ok(); | ||
}, function() { | ||
ok(); | ||
}); | ||
}); | ||
it('should not allow invalid uuids in postgresql', function(ok) { | ||
Knex('datatype_test') | ||
.insert({ | ||
enum_value: 'c', | ||
uuid: uuid.v4()}) | ||
.then(function() { | ||
return Knex('datatype_test').insert({enum_value: 'c', uuid: 'test'}); | ||
}).then(function() { | ||
// No errors happen in sqlite3 or mysql, which dont have native support | ||
// for the enum type. | ||
if (Knex.client.dialect !== 'postgresql') ok(); | ||
}, function() { | ||
if (Knex.client.dialect === 'postgresql') ok(); | ||
}); | ||
}); | ||
}); | ||
}; |
@@ -7,14 +7,16 @@ var When = require('when'); | ||
return When.all([ | ||
Knex.Schema.dropTableIfExists('test_foreign_table_two'), | ||
Knex.Schema.dropTableIfExists('test_table_one'), | ||
Knex.Schema.dropTableIfExists('test_table_two'), | ||
Knex.Schema.dropTableIfExists('test_table_three'), | ||
Knex.Schema.dropTableIfExists('datatype_test'), | ||
Knex.Schema.dropTableIfExists('accounts') | ||
]).then(function(resp) { | ||
res = [resp[0]]; // only really need one of these for the test output. | ||
return When.all([ | ||
Knex.Schema.createTable('test_table_one', function(table) { | ||
table.engine('InnoDB'); | ||
table.comment('A table comment.') | ||
table.comment('A table comment.'); | ||
table.increments('id'); | ||
@@ -28,8 +30,8 @@ table.string('first_name'); | ||
}), | ||
Knex.Schema.createTable('test_table_two', function(t) { | ||
t.engine('InnoDB'); | ||
t.increments(); | ||
t.integer('account_id'); | ||
t.text('details'); | ||
t.tinyint('status'); | ||
Knex.Schema.createTable('test_table_two', function(table) { | ||
table.engine('InnoDB'); | ||
table.increments(); | ||
table.integer('account_id'); | ||
table.text('details'); | ||
table.tinyint('status'); | ||
}), | ||
@@ -40,2 +42,13 @@ Knex.Schema.createTable('test_table_three', function(table) { | ||
table.text('paragraph').defaultTo('Lorem ipsum Qui quis qui in.'); | ||
}), | ||
Knex.Schema.createTable('datatype_test', function(table) { | ||
table.enum('enum_value', ['a', 'b', 'c']); | ||
table.uuid('uuid'); | ||
}), | ||
Knex.Schema.createTable('test_foreign_table_two', function(table) { | ||
table.increments(); | ||
table.integer('fkey_two') | ||
.unsigned() | ||
.references('id') | ||
.inTable('test_table_two'); | ||
}) | ||
@@ -47,6 +60,9 @@ ]); | ||
res = res.concat(resp); | ||
return Knex.Schema.table('test_table_one', function(t) { | ||
t.string('phone').nullable(); | ||
return Knex.Schema.table('test_table_two', function(t) { | ||
t.json('json_data').nullable(); | ||
}).then(function() { | ||
return Knex.Schema.table('test_table_one', function(t) { | ||
t.string('phone').nullable(); | ||
}); | ||
}); | ||
}).then(function(resp) { | ||
@@ -71,2 +87,6 @@ // conditionally drops tables with `dropTableIfExists` | ||
res.push(resp); | ||
// Drop this here so we don't have foreign key constraints... | ||
return Knex.Schema.dropTable('test_foreign_table_two'); | ||
}) | ||
.then(function() { | ||
return res; | ||
@@ -73,0 +93,0 @@ }) |
@@ -10,2 +10,3 @@ var assert = require('assert'); | ||
.transacting(t) | ||
.returning('id') | ||
.insert({ | ||
@@ -49,2 +50,3 @@ first_name: 'Transacting', | ||
.transacting(t) | ||
.returning('id') | ||
.insert({ | ||
@@ -51,0 +53,0 @@ first_name: 'Transacting', |
@@ -19,4 +19,4 @@ var When = require('when'); | ||
require('./lib/schema')(Knex, function(output) { | ||
output = _.map(output, function(item) { | ||
delete item['object']; | ||
output = _.map(output, function(item) { | ||
delete item['object']; | ||
return item; | ||
@@ -30,2 +30,6 @@ }); | ||
describe('Schema Tests', function() { | ||
require('./lib/schema-tests')(Knex, dbType, handler(dbType, 'schema-tests')); | ||
}); | ||
describe('Inserts', function() { | ||
@@ -90,3 +94,3 @@ require('./lib/inserts')(Knex, dbType, handler(dbType, 'inserts')); | ||
var item = 1; | ||
// The `isAll` allows us to run a bunch of queries in a `When.all` | ||
@@ -102,3 +106,3 @@ // and then split those out into individual items. | ||
_.each(['string', 'object'], function(type) { | ||
var typeData = data[type]; | ||
@@ -121,3 +125,3 @@ | ||
try { | ||
// If we're on the object, | ||
// If we're on the object, | ||
if (type === 'object') { | ||
@@ -134,3 +138,4 @@ if (_.isArray(typeData)) { | ||
} catch (e) { | ||
console.log(e.stack); | ||
console.log(typeData.sql); | ||
console.log(checkData.sql); | ||
resolver(e); | ||
@@ -143,3 +148,3 @@ } | ||
}; | ||
// Process the `data` on the function. | ||
@@ -146,0 +151,0 @@ return function(data) { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
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
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
208028
27
6244
6
+ Addedunderscore@1.5.2(transitive)
- Removedunderscore@1.4.4(transitive)
Updatedunderscore@~1.5.1