Comparing version 0.2.6 to 0.4.0
@@ -1,201 +0,57 @@ | ||
var whenfn = require('when/function'); | ||
var nodefn = require('when/node/function'); | ||
var _ = require('underscore'); | ||
// ClientBase | ||
// ---------- | ||
(function(define) { | ||
// Setup is called with the context of the current client. | ||
exports.setup = function(Client, 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; | ||
this.grammar = Client.grammar; | ||
this.schemaGrammar = Client.schemaGrammar; | ||
"use strict"; | ||
// Extend the genericPool with the options | ||
// passed into the init under the "pool" option. | ||
var instance = this; | ||
var poolInstance = this.pool = require('generic-pool').Pool(_.extend({ | ||
name: 'pool-' + name, | ||
min: 2, | ||
max: 10, | ||
log: false, | ||
idleTimeoutMillis: 30000, | ||
create: function(callback) { | ||
var pool = this; | ||
instance.getRawConnection(function(err, conn) { | ||
if (err) return callback(err); | ||
conn.__cid = _.uniqueId('__cid'); | ||
if (pool.afterCreate) { | ||
pool.afterCreate(conn, function(err) { | ||
callback(err, conn); | ||
}); | ||
} else { | ||
callback(null, conn); | ||
} | ||
}); | ||
}, | ||
destroy: function(conn) { | ||
if (this.beforeDestroy) { | ||
this.beforeDestroy(conn, function() { | ||
conn.end(); | ||
}); | ||
} else { | ||
conn.end(); | ||
} | ||
} | ||
}, this.poolDefaults, options.pool)); | ||
define(function(require, exports) { | ||
// Default to draining on exit. | ||
if (poolInstance.drainOnExit !== false && typeof process === 'object') { | ||
process.on('exit', function() { | ||
poolInstance.drain(function() { | ||
poolInstance.destroyAllNow(); | ||
}); | ||
}); | ||
} | ||
}; | ||
var Helpers = require('../lib/helpers').Helpers; | ||
exports.skim = function(data) { | ||
return _.map(data, function(obj) { | ||
return _.pick(obj, _.keys(obj)); | ||
}); | ||
}; | ||
// The `ClientBase` is assumed as the object that all database `clients` | ||
// inherit from, and is used in an `instanceof` check when initializing the | ||
// library. If you wish to write or customize an adapter, just inherit from | ||
// this base, with `ClientBase.extend`, and you're good to go. | ||
var ClientBase = function() {}; | ||
exports.debug = function(builder, conn) { | ||
console.log({sql: builder.sql, bindings: builder.bindings, __cid: conn.__cid}); | ||
}; | ||
// The methods assumed when building a client. | ||
ClientBase.prototype = { | ||
exports.protoProps = { | ||
// Gets the raw connection for the current client. | ||
getRawConnection: function() {}, | ||
// Retrieves a connection from the connection pool, | ||
// returning a promise. | ||
getConnection: function() { | ||
return nodefn.call(this.pool.acquire); | ||
}, | ||
// Execute a query on the specified `Builder` or `SchemaBuilder` | ||
// interface. If a `connection` is specified, use it, otherwise | ||
// acquire a connection, and then dispose of it when we're done. | ||
query: function() {}, | ||
// Releases a connection from the connection pool, | ||
// returning a promise. | ||
releaseConnection: function(conn) { | ||
return whenfn.call(this.pool.release, conn); | ||
}, | ||
// Retrieves a connection from the connection pool, | ||
// returning a promise. | ||
getConnection: function() {}, | ||
// Begins a transaction statement on the instance, | ||
// resolving with the connection of the current transaction. | ||
startTransaction: function() { | ||
return this.getConnection().then(function(connection) { | ||
return nodefn.call(connection.query.bind(connection), 'begin;', []).then(function() { | ||
return connection; | ||
}); | ||
}); | ||
}, | ||
// Releases a connection from the connection pool, | ||
// returning a promise. | ||
releaseConnection: function(conn) {}, | ||
finishTransaction: function(type, trans, dfd, msg) { | ||
var ctx = this; | ||
nodefn.call(trans.connection.query.bind(trans.connection), type + ';', []).then(function(resp) { | ||
if (type === 'commit') dfd.resolve(msg || resp); | ||
if (type === 'rollback') dfd.reject(msg || resp); | ||
}, function (err) { | ||
dfd.reject(err); | ||
}).ensure(function() { | ||
return ctx.releaseConnection(trans.connection).then(function() { | ||
trans.connection = null; | ||
}); | ||
}); | ||
} | ||
// Begins a transaction statement on the instance, | ||
// resolving with the connection of the current transaction. | ||
startTransaction: function() {}, | ||
}; | ||
// Finishes a transaction, taking the `type` | ||
finishTransaction: function(type, transaction, msg) {}, | ||
exports.grammar = {}; | ||
// The pool defaults. | ||
poolDefaults: function() {} | ||
exports.schemaGrammar = { | ||
}; | ||
// 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]; | ||
}, | ||
// Grab the standard `Object.extend` as popularized by Backbone.js. | ||
ClientBase.extend = Helpers.extend; | ||
// Get all of the commands with a given name. | ||
getCommandsByName: function(blueprint, name) { | ||
return _.filter(blueprint.commands, function(value) { return value.name == name; }) || []; | ||
}, | ||
exports.ClientBase = ClientBase; | ||
// Used to compile any database specific items. | ||
compileAdditional: function() {}, | ||
}); | ||
// Compile a create table command. | ||
compileCreateTable: function(blueprint) { | ||
var columns = this.getColumns(blueprint).join(', '); | ||
return 'create table ' + this.wrapTable(blueprint) + ' (' + columns + ')'; | ||
}, | ||
// Compile a drop table command. | ||
compileDropTable: function(blueprint) { | ||
return 'drop table ' + this.wrapTable(blueprint); | ||
}, | ||
// Compile a drop table (if exists) command. | ||
compileDropTableIfExists: function(blueprint) { | ||
return 'drop table if exists ' + this.wrapTable(blueprint); | ||
}, | ||
// Compile a drop index command. | ||
compileDropIndex: function(blueprint, command) { | ||
return 'drop index ' + command.index; | ||
}, | ||
// 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. | ||
typeTinyInteger: function() { | ||
return 'tinyint'; | ||
}, | ||
// Create the column definition for a time type. | ||
typeTime: function() { | ||
return 'time'; | ||
}, | ||
// Create the column definition for a date type. | ||
typeDate: function() { | ||
return 'date'; | ||
}, | ||
// Create the column definition for a binary type. | ||
typeBinary: function() { | ||
return 'blob'; | ||
}, | ||
// 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. | ||
modifyNullable: function(blueprint, column) { | ||
return column.isNullable ? ' null' : ' not null'; | ||
}, | ||
// Get the SQL for a default column modifier. | ||
modifyDefault: function(blueprint, column) { | ||
if (column.defaultValue != void 0) { | ||
return " default '" + this.getDefaultValue(column.defaultValue) + "'"; | ||
} | ||
} | ||
}; | ||
})( | ||
typeof define === 'function' && define.amd ? define : function(factory) { factory(require, exports); | ||
}); |
1733
knex.js
@@ -1,3 +0,4 @@ | ||
// Knex.js 0.2.6 | ||
// | ||
// Knex.js 0.4.0 | ||
// -------------- | ||
// (c) 2013 Tim Griesser | ||
@@ -13,1679 +14,115 @@ // Knex may be freely distributed under the MIT license. | ||
// Required dependencies. | ||
// Base library dependencies of the app. | ||
var _ = require('underscore'); | ||
var when = require('when'); | ||
// `Knex` is the root namespace and a chainable function: `Knex('tableName')` | ||
var Knex = function(table) { | ||
if (!Knex.Instances['main']) { | ||
throw new Error('The Knex instance has not been initialized yet.'); | ||
} | ||
return Knex.Instances['main'](table); | ||
}; | ||
// Require the main constructors necessary for a `Knex` instance, | ||
// each of which are injected with the current instance, so they maintain | ||
// the correct client reference & grammar. | ||
var Raw = require('./lib/raw').Raw; | ||
var Transaction = require('./lib/transaction').Transaction; | ||
var Builder = require('./lib/builder').Builder; | ||
// Keep in sync with package.json | ||
Knex.VERSION = '0.2.6'; | ||
// var Interface = require('./lib/builder/interface').Interface; | ||
var ClientBase = require('./clients/base').ClientBase; | ||
var SchemaBuilder = require('./lib/schemabuilder').SchemaBuilder; | ||
var SchemaInterface = require('./lib/schemainterface').SchemaInterface; | ||
// Methods common to both the `Grammar` and `SchemaGrammar` interfaces, | ||
// used to generate the sql in one form or another. | ||
var Common = { | ||
// The `Knex` module, taking either a fully initialized | ||
// database client, or a configuration to initialize one. This is something | ||
// you'll typically only want to call once per application cycle. | ||
var Knex = function(config) { | ||
_debug: false, | ||
var Dialect, client; | ||
_promise: null, | ||
debug: function() { | ||
this._debug = true; | ||
return this; | ||
}, | ||
// For those who dislike promise interfaces. | ||
// Multiple calls to `exec` will resolve with the same value | ||
// if called more than once. Any unhandled errors will be thrown | ||
// after the last block. | ||
exec: function(callback) { | ||
this._promise || (this._promise = this.runQuery()); | ||
return this._promise.then(function(resp) { | ||
if (callback) callback(null, resp); | ||
}, function(err) { | ||
if (callback) callback(err, null); | ||
}).then(null, function(err) { | ||
setTimeout(function() { throw err; }, 0); | ||
}); | ||
}, | ||
// The promise interface for the query builder. | ||
then: function(onFulfilled, onRejected) { | ||
this._promise || (this._promise = this.runQuery()); | ||
return this._promise.then(onFulfilled, onRejected); | ||
}, | ||
// Returns an array of query strings filled out with the | ||
// correct values based on bindings, etc. Useful for debugging. | ||
toString: function() { | ||
this.type || (this.type = 'select'); | ||
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('; '); | ||
}, | ||
// Explicitly 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]); | ||
} else { | ||
push.apply(cleaned, bindings[i].bindings); | ||
// If the client isn't actually a client, we need to configure it into one. | ||
// On the client, this isn't acceptable, since we need to return immediately | ||
// rather than wait on an async load of a client library. | ||
if (config instanceof ClientBase) { | ||
client = config; | ||
} else { | ||
if (typeof define === 'function' && define.amd) { | ||
throw new Error('A valid `Knex` client must be passed into the Knex constructor.'); | ||
} else { | ||
var clientName = config.client; | ||
if (!Clients[clientName]) { | ||
throw new Error(clientName + ' is not a valid Knex client, did you misspell it?'); | ||
} | ||
Dialect = require(Clients[clientName]); | ||
client = new Dialect.Client(_.omit(config, 'client')); | ||
} | ||
return cleaned; | ||
}, | ||
// Runs the query on the current builder instance and returns a promise. | ||
runQuery: function() { | ||
if (this.transaction) { | ||
if (!this.transaction.connection) return when.reject(new Error('The transaction has already completed.')); | ||
this._connection = this.transaction.connection; | ||
} | ||
// Prep the SQL associated with the this. | ||
this.sql = this.toSql(); | ||
this.bindings = this._cleanBindings(); | ||
if (!_.isArray(this.sql)) this.sql = [this.sql]; | ||
var chain; | ||
for (var i = 0, l = this.sql.length; i < l; i++) { | ||
if (chain) { | ||
chain.then(multiQuery(this, i, chain)); | ||
} else { | ||
chain = multiQuery(this, i); | ||
} | ||
} | ||
return chain; | ||
} | ||
}; | ||
// Enables the `knex('tableName')` shorthand syntax. | ||
var knex = function(tableName) { | ||
return knex.builder(tableName); | ||
}; | ||
// Grammar | ||
// ------- | ||
knex.grammar = Dialect.grammar; | ||
knex.schemaGrammar = Dialect.schemaGrammar; | ||
// The list of different components | ||
var components = [ | ||
'aggregate', 'columns', 'from', | ||
'joins', 'wheres', 'groups', 'havings', | ||
'orders', 'limit', 'offset', 'unions' | ||
]; | ||
// Main namespaces for key library components. | ||
knex.schema = {}; | ||
knex.migrate = {}; | ||
Knex.Grammar = { | ||
// Enable the `Builder('tableName')` syntax, as is used in the main `knex('tableName')`. | ||
knex.builder = function(tableName) { | ||
var builder = new Builder(knex); | ||
return tableName ? builder.from(tableName) : builder; | ||
}; | ||
// Compiles the `select` statement, or nested sub-selects | ||
// by calling each of the component compilers, trimming out | ||
// the empties, and returning a generated query string. | ||
compileSelect: function(qb) { | ||
var sql = {}; | ||
if (_.isEmpty(qb.columns)) qb.columns = ['*']; | ||
for (var i = 0, l = components.length; i < l; i++) { | ||
var component = components[i]; | ||
var result = _.result(qb, component); | ||
if (result != null) { | ||
sql[component] = this['compile' + capitalize(component)](qb, result); | ||
} | ||
} | ||
return _.compact(sql).join(' '); | ||
}, | ||
// Compiles an aggregate query. | ||
compileAggregate: function(qb) { | ||
var column = this.columnize(qb.aggregate.columns); | ||
if (qb.isDistinct && column !== '*') { | ||
column = 'distinct ' + column; | ||
} | ||
return 'select ' + qb.aggregate.type + '(' + column + ') as aggregate'; | ||
}, | ||
// Compiles the columns in the query, specifying if an item was distinct. | ||
compileColumns: function(qb, columns) { | ||
if (qb.aggregate != null) return; | ||
return (qb.isDistinct ? 'select distinct ' : 'select ') + this.columnize(columns); | ||
}, | ||
// Compiles the `from` tableName portion of the query. | ||
compileFrom: function(qb, table) { | ||
return 'from ' + this.wrapTable(table); | ||
}, | ||
// Compiles all each of the `join` clauses on the query, | ||
// including any nested join queries. | ||
compileJoins: function(qb, joins) { | ||
var sql = []; | ||
for (var i = 0, l = joins.length; i < l; i++) { | ||
var join = joins[i]; | ||
var clauses = []; | ||
for (var i2 = 0, l2 = join.clauses.length; i2 < l2; i2++) { | ||
var clause = join.clauses[i2]; | ||
clauses.push( | ||
[clause['bool'], this.wrap(clause['first']), clause.operator, this.wrap(clause['second'])].join(' ') | ||
); | ||
} | ||
clauses[0] = clauses[0].replace(/and |or /, ''); | ||
sql.push(join.type + ' join ' + this.wrapTable(join.table) + ' on ' + clauses.join(' ')); | ||
} | ||
return sql.join(' '); | ||
}, | ||
// Compiles all `where` statements on the query. | ||
compileWheres: function(qb) { | ||
var sql = []; | ||
var wheres = qb.wheres; | ||
if (wheres.length === 0) return ''; | ||
for (var i = 0, l = wheres.length; i < l; i++) { | ||
var where = wheres[i]; | ||
sql.push(where.bool + ' ' + this['where' + where.type](qb, where)); | ||
} | ||
return (sql.length > 0 ? 'where ' + sql.join(' ').replace(/and |or /, '') : ''); | ||
}, | ||
// 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. | ||
whereNested: function(qb, where) { | ||
return '(' + this.compileWheres(where.query).slice(6) + ')'; | ||
}, | ||
// Compiles a nested where clause. | ||
whereSub: function(qb, where) { | ||
return this.wrap(where.column) + ' ' + where.operator + ' (' + (this.compileSelect(where.query)) + ')'; | ||
}, | ||
// Compiles a basic where clause. | ||
whereBasic: function(qb, where) { | ||
return this.wrap(where.column) + ' ' + where.operator + ' ' + this.parameter(where.value); | ||
}, | ||
// Compiles a basic exists clause. | ||
whereExists: function(qb, where) { | ||
return 'exists (' + this.compileSelect(where.query) + ')'; | ||
}, | ||
// Compiles a basic not exists clause. | ||
whereNotExists: function(qb, where) { | ||
return 'not exists (' + this.compileSelect(where.query) + ')'; | ||
}, | ||
// Compiles a where in clause. | ||
whereIn: function(qb, where) { | ||
return this.wrap(where.column) + ' in (' + this.parameterize(where.value) + ')'; | ||
}, | ||
// Compiles a where not in clause. | ||
whereNotIn: function(qb, where) { | ||
return this.wrap(where.column) + ' not in (' + this.parameterize(where.value) + ')'; | ||
}, | ||
// Compiles a sub-where in clause. | ||
whereInSub: function(qb, where) { | ||
return this.wrap(where.column) + ' in (' + this.compileSelect(where.query) + ')'; | ||
}, | ||
// Compiles a sub-where not in clause. | ||
whereNotInSub: function(qb, where) { | ||
return this.wrap(where.column) + ' not in (' + this.compileSelect(where.query) + ')'; | ||
}, | ||
// Where between. | ||
whereBetween: function(qb, where) { | ||
return this.wrap(where.column) + ' between ? and ?'; | ||
}, | ||
whereNull: function(qb, where) { | ||
return this.wrap(where.column) + ' is null'; | ||
}, | ||
whereNotNull: function(qb, where) { | ||
return this.wrap(where.column) + ' is not null'; | ||
}, | ||
whereRaw: function(qb, where) { | ||
return where.sql; | ||
}, | ||
// Compiles the `group by` columns. | ||
compileGroups: function(qb, groups) { | ||
return 'group by ' + this.columnize(groups); | ||
}, | ||
// Compiles the `having` statements. | ||
compileHavings: function(qb, havings) { | ||
return 'having ' + havings.map(function(having) { | ||
if (having.type === 'Raw') { | ||
return having.bool + ' ' + having.sql; | ||
} | ||
return having.bool + ' ' + this.wrap(having.column) + ' ' + having.operator + ' ' + this.parameter(having['value']); | ||
}, this).replace(/and |or /, ''); | ||
}, | ||
// Compiles the `order by` statements. | ||
compileOrders: function(qb, orders) { | ||
if (orders.length > 0) { | ||
return 'order by ' + orders.map(function(order) { | ||
return '' + this.wrap(order.column) + ' ' + order.direction; | ||
}, this).join(', '); | ||
} | ||
}, | ||
// Compiles the `limit` statements. | ||
compileLimit: function(qb, limit) { | ||
return 'limit ' + limit; | ||
}, | ||
// Compiles an `offset` statement on the query. | ||
compileOffset: function(qb, offset) { | ||
return 'offset ' + offset; | ||
}, | ||
// Compiles an `insert` query, allowing for multiple | ||
// inserts using a single query statement. | ||
compileInsert: function(qb) { | ||
var values = qb.values; | ||
var table = this.wrapTable(qb.table); | ||
var columns = _.pluck(values[0], 0); | ||
var paramBlocks = []; | ||
// If there are any "where" clauses, we need to omit | ||
// any bindings that may have been associated with them. | ||
if (qb.wheres.length > 0) this._clearWhereBindings(qb); | ||
for (var i = 0, l = values.length; i < l; ++i) { | ||
paramBlocks.push("(" + this.parameterize(_.pluck(values[i], 1)) + ")"); | ||
} | ||
return "insert into " + table + " (" + this.columnize(columns) + ") values " + paramBlocks.join(', '); | ||
}, | ||
// Depending on the type of `where` clause, this will appropriately | ||
// remove any binding caused by "where" constraints, allowing the same | ||
// query to be used for `insert` and `update` without issue. | ||
_clearWhereBindings: function(qb) { | ||
var wheres = qb.wheres; | ||
var bindingCount = 0; | ||
for (var i = 0, l = wheres.length; i<l; i++) { | ||
var where = wheres[i]; | ||
if (_.isArray(where.value)) { | ||
bindingCount += where.value.length; | ||
} else if (where.query) { | ||
bindingCount += where.query.bindings.length; | ||
} else { | ||
bindingCount += 1; | ||
} | ||
} | ||
qb.bindings = qb.bindings.slice(bindingCount); | ||
}, | ||
// Compiles an `update` query. | ||
compileUpdate: function(qb) { | ||
var values = qb.values; | ||
var table = this.wrapTable(qb.table), columns = []; | ||
for (var i=0, l = values.length; i < l; i++) { | ||
var value = values[i]; | ||
columns.push(this.wrap(value[0]) + ' = ' + this.parameter(value[1])); | ||
} | ||
return 'update ' + table + ' set ' + columns.join(', ') + ' ' + this.compileWheres(qb); | ||
}, | ||
// Compiles a `delete` query. | ||
compileDelete: function(qb) { | ||
var table = this.wrapTable(qb.table); | ||
var where = !_.isEmpty(qb.wheres) ? this.compileWheres(qb) : ''; | ||
return 'delete from ' + table + ' ' + where; | ||
}, | ||
// Compiles a `truncate` query. | ||
compileTruncate: function(qb) { | ||
return 'truncate ' + this.wrapTable(qb.table); | ||
}, | ||
wrap: function(value) { | ||
var segments; | ||
if (value instanceof Raw) return value.sql; | ||
if (_.isNumber(value)) return value; | ||
if (value.toLowerCase().indexOf(' as ') !== -1) { | ||
segments = value.split(' '); | ||
return this.wrap(segments[0]) + ' as ' + this.wrap(segments[2]); | ||
} | ||
var wrapped = []; | ||
segments = value.split('.'); | ||
for (var i = 0, l = segments.length; i < l; i = ++i) { | ||
value = segments[i]; | ||
if (i === 0 && segments.length > 1) { | ||
wrapped.push(this.wrapTable(value)); | ||
} else { | ||
wrapped.push(this.wrapValue(value)); | ||
} | ||
} | ||
return wrapped.join('.'); | ||
}, | ||
wrapArray: function(values) { | ||
return _.map(values, this.wrap, this); | ||
}, | ||
wrapTable: function(table) { | ||
if (table instanceof Raw) return table.sql; | ||
return this.wrap(table); | ||
}, | ||
columnize: function(columns) { | ||
if (!_.isArray(columns)) columns = [columns]; | ||
return _.map(columns, this.wrap, this).join(', '); | ||
}, | ||
parameterize: function(values) { | ||
if (!_.isArray(values)) values = [values]; | ||
return _.map(values, this.parameter, this).join(', '); | ||
}, | ||
parameter: function(value) { | ||
return (value instanceof Raw ? value.sql : '?'); | ||
} | ||
}; | ||
// Knex.Builder | ||
// ------- | ||
var Builder = Knex.Builder = function(table) { | ||
// We use this logic to create sub-builders | ||
// for the advanced query statements. | ||
if (table) { | ||
if (_.isString(table) || table instanceof Raw) { | ||
this.table = table; | ||
} else { | ||
this.client = table.client; | ||
this.grammar = table.grammar; | ||
} | ||
} | ||
this.reset(); | ||
}; | ||
// All operators used in the `where` clause generation. | ||
var operators = ['=', '<', '>', '<=', '>=', '<>', '!=', 'like', 'not like', 'between', 'ilike']; | ||
_.extend(Builder.prototype, Common, { | ||
_source: 'Builder', | ||
// Sets the `tableName` on the query. | ||
from: function(tableName) { | ||
if (!tableName) return this.table; | ||
this.table = tableName; | ||
return this; | ||
}, | ||
// Adds a column to the list of "columns" being selected | ||
// on the query. | ||
column: function(value) { | ||
this.columns.push(value); | ||
return this; | ||
}, | ||
// Adds a `distinct` clause to the query. | ||
distinct: function(column) { | ||
this.column(column); | ||
this.isDistinct = true; | ||
return this; | ||
}, | ||
// Compiles the current query builder. | ||
toSql: function() { | ||
this.type || (this.type = 'select'); | ||
return this.grammar['compile' + capitalize(this.type)](this); | ||
}, | ||
// Clones the current query builder, including any | ||
// 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', 'transaction', 'unions' | ||
]; | ||
for (var i = 0, l = items.length; i < l; i++) { | ||
var k = items[i]; | ||
item[k] = this[k]; | ||
} | ||
return item; | ||
}, | ||
// Resets all attributes on the query builder. | ||
reset: function() { | ||
this.joins = []; | ||
this.values = []; | ||
this.unions = []; | ||
this.wheres = []; | ||
this.orders = []; | ||
this.columns = []; | ||
this.bindings = []; | ||
this.isDistinct = false; | ||
this.isReturning = false; | ||
}, | ||
// Adds a join clause to the query, allowing for advanced joins | ||
// with an anonymous function as the second argument. | ||
join: function(table, first, operator, second, type) { | ||
var join; | ||
if (_.isFunction(first)) { | ||
type = operator; | ||
join = new JoinClause(type || 'inner', table); | ||
first.call(join, join); | ||
} else { | ||
join = new JoinClause(type || 'inner', table); | ||
join.on(first, operator, second); | ||
} | ||
this.joins.push(join); | ||
return this; | ||
}, | ||
// The where function can be used in several ways: | ||
// The most basic is `where(key, value)`, which expands to | ||
// where key = value. | ||
where: function(column, operator, value, bool) { | ||
bool || (bool = 'and'); | ||
if (_.isFunction(column)) { | ||
return this._whereNested(column, bool); | ||
} | ||
if (column instanceof Raw) { | ||
return this.whereRaw(column.sql, column.bindings, bool); | ||
} | ||
if (_.isObject(column)) { | ||
for (var key in column) { | ||
value = column[key]; | ||
this[bool + 'Where'](key, '=', value); | ||
} | ||
return this; | ||
} | ||
if (!_.contains(operators, operator)) { | ||
value = operator; | ||
operator = '='; | ||
} | ||
if (_.isFunction(value)) { | ||
return this._whereSub(column, operator, value, bool); | ||
} | ||
this.wheres.push({ | ||
type: 'Basic', | ||
column: column, | ||
operator: operator, | ||
value: value, | ||
bool: bool | ||
}); | ||
this.bindings.push(value); | ||
return this; | ||
}, | ||
// Alias to `where`, for internal builder consistency. | ||
andWhere: function() { | ||
return this.where.apply(this, arguments); | ||
}, | ||
// Adds an `or where` clause to the query. | ||
orWhere: function(column, operator, value) { | ||
return this.where(column, operator, value, 'or'); | ||
}, | ||
// Adds a raw `where` clause to the query. | ||
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; | ||
}, | ||
// Adds a raw `or where` clause to the query. | ||
orWhereRaw: function(sql, bindings) { | ||
return this.whereRaw(sql, bindings, 'or'); | ||
}, | ||
// Adds a `where exists` clause to the query. | ||
whereExists: function(callback, bool, type) { | ||
var query = new Builder(this); | ||
callback.call(query, query); | ||
this.wheres.push({ | ||
type: (type || 'Exists'), | ||
query: query, | ||
bool: (bool || 'and') | ||
}); | ||
push.apply(this.bindings, query.bindings); | ||
return this; | ||
}, | ||
// Adds an `or where exists` clause to the query. | ||
orWhereExists: function(callback) { | ||
return this.whereExists(callback, 'or'); | ||
}, | ||
// Adds a `where not exists` clause to the query. | ||
whereNotExists: function(callback) { | ||
return this.whereExists(callback, 'and', 'NotExists'); | ||
}, | ||
// Adds a `or where not exists` clause to the query. | ||
orWhereNotExists: function(callback) { | ||
return this.whereExists(callback, 'or', 'NotExists'); | ||
}, | ||
// Adds a `where in` clause to the query. | ||
whereIn: function(column, values, bool, condition) { | ||
bool || (bool = 'and'); | ||
if (_.isFunction(values)) { | ||
return this._whereInSub(column, values, bool, (condition || 'In')); | ||
} | ||
this.wheres.push({ | ||
type: (condition || 'In'), | ||
column: column, | ||
value: values, | ||
bool: bool | ||
}); | ||
push.apply(this.bindings, values); | ||
return this; | ||
}, | ||
// Adds a `or where in` clause to the query. | ||
orWhereIn: function(column, values) { | ||
return this.whereIn(column, values, 'or'); | ||
}, | ||
// Adds a `where not in` clause to the query. | ||
whereNotIn: function(column, values) { | ||
return this.whereIn(column, values, 'and', 'NotIn'); | ||
}, | ||
// Adds a `or where not in` clause to the query. | ||
orWhereNotIn: function(column, values) { | ||
return this.whereIn(column, values, 'or', 'NotIn'); | ||
}, | ||
// Adds a `where null` clause to the query. | ||
whereNull: function(column, bool, type) { | ||
this.wheres.push({type: (type || 'Null'), column: column, bool: (bool || 'and')}); | ||
return this; | ||
}, | ||
// Adds a `or where null` clause to the query. | ||
orWhereNull: function(column) { | ||
return this.whereNull(column, 'or', 'Null'); | ||
}, | ||
// Adds a `where not null` clause to the query. | ||
whereNotNull: function(column) { | ||
return this.whereNull(column, 'and', 'NotNull'); | ||
}, | ||
// Adds a `or where not null` clause to the query. | ||
orWhereNotNull: function(column) { | ||
return this.whereNull(column, 'or', 'NotNull'); | ||
}, | ||
// Adds a `where between` clause to the query. | ||
whereBetween: function(column, values) { | ||
this.wheres.push({column: column, type: 'Between', bool: 'and'}); | ||
push.apply(this.bindings, values); | ||
return this; | ||
}, | ||
// Adds a `or where between` clause to the query. | ||
orWhereBetween: function(column, values) { | ||
this.wheres.push({column: column, type: 'Between', bool: 'or'}); | ||
push.apply(this.bindings, values); | ||
return this; | ||
}, | ||
// ---------------------------------------------------------------------- | ||
// Adds a `group by` clause to the query. | ||
groupBy: function() { | ||
this.groups = (this.groups || []).concat(_.toArray(arguments)); | ||
return this; | ||
}, | ||
// Adds a `order by` clause to the query. | ||
orderBy: function(column, direction) { | ||
this.orders.push({column: column, direction: (direction || 'asc')}); | ||
return this; | ||
}, | ||
// 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. | ||
having: function(column, operator, value, bool) { | ||
if (column instanceof Raw) { | ||
return this.havingRaw(column.value, bool); | ||
} | ||
this.havings.push({column: column, operator: (operator || ''), value: (value || ''), bool: bool || 'and'}); | ||
this.bindings.push(value); | ||
return this; | ||
}, | ||
// Adds an `or having` clause to the query. | ||
orHaving: function(column, operator, value) { | ||
return this.having(column, operator, value, 'or'); | ||
}, | ||
// Adds a raw `having` clause to the query. | ||
havingRaw: function(sql, bool) { | ||
this.havings.push({type: 'Raw', sql: sql, bool: bool || 'and'}); | ||
return this; | ||
}, | ||
// Adds a raw `or having` clause to the query. | ||
orHavingRaw: function(sql) { | ||
return this.havingRaw(sql, 'or'); | ||
}, | ||
// ---------------------------------------------------------------------- | ||
offset: function(value) { | ||
if (value == null) return this.isOffset; | ||
this.isOffset = value; | ||
return this; | ||
}, | ||
limit: function(value) { | ||
if (value == null) return this.isLimit; | ||
this.isLimit = value; | ||
return this; | ||
}, | ||
// ---------------------------------------------------------------------- | ||
// Retrieve the "count" result of the query. | ||
count: function(column) { | ||
return this._aggregate('count', column); | ||
}, | ||
// Retrieve the minimum value of a given column. | ||
min: function(column) { | ||
return this._aggregate('min', column); | ||
}, | ||
// Retrieve the maximum value of a given column. | ||
max: function(column) { | ||
return this._aggregate('max', column); | ||
}, | ||
// Retrieve the sum of the values of a given column. | ||
sum: function(column) { | ||
return this._aggregate('sum', column); | ||
}, | ||
// Increments a column's value by the specified amount. | ||
increment: function(column, amount) { | ||
return this._counter(column, amount); | ||
}, | ||
// Decrements a column's value by the specified amount. | ||
decrement: function(column, amount) { | ||
return this._counter(column, amount, '-'); | ||
}, | ||
// Sets the values for a `select` query. | ||
select: function(columns) { | ||
if (columns) { | ||
push.apply(this.columns, _.isArray(columns) ? columns : _.toArray(arguments)); | ||
} | ||
return this._setType('select'); | ||
}, | ||
// Sets the values for an `insert` query. | ||
insert: function(values, returning) { | ||
if (returning) this.returning(returning); | ||
this.values = this._prepValues(_.clone(values)); | ||
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. | ||
update: function(values) { | ||
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. | ||
"delete": function() { | ||
return this._setType('delete'); | ||
}, | ||
// Executes a delete statement on the query; | ||
del: function() { | ||
return this._setType('delete'); | ||
}, | ||
// Truncate | ||
truncate: function() { | ||
return this._setType('truncate'); | ||
}, | ||
// Set by `transacting` - contains the object with the connection | ||
// needed to execute a transaction | ||
transaction: false, | ||
// Sets the current Builder connection to that of the | ||
// the currently running transaction | ||
transacting: function(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; | ||
}, | ||
// ---------------------------------------------------------------------- | ||
_prepValues: function(values) { | ||
if (!_.isArray(values)) values = values ? [values] : []; | ||
for (var i = 0, l = values.length; i<l; i++) { | ||
var obj = values[i] = sortObject(values[i]); | ||
for (var i2 = 0, l2 = obj.length; i2 < l2; i2++) { | ||
this.bindings.push(obj[i2][1]); | ||
} | ||
} | ||
return values; | ||
}, | ||
// Helper for compiling any advanced `where in` queries. | ||
_whereInSub: function(column, callback, bool, condition) { | ||
condition += 'Sub'; | ||
var query = new Builder(this); | ||
callback.call(query, query); | ||
this.wheres.push({type: condition, column: column, query: query, bool: bool}); | ||
push.apply(this.bindings, query.bindings); | ||
return this; | ||
}, | ||
// Helper for compiling any advanced `where` queries. | ||
_whereNested: function(callback, bool) { | ||
var query = new Builder(this); | ||
query.table = this.table; | ||
callback.call(query, query); | ||
this.wheres.push({type: 'Nested', query: query, bool: bool}); | ||
push.apply(this.bindings, query.bindings); | ||
return this; | ||
}, | ||
// Helper for compiling any of the `where` advanced queries. | ||
_whereSub: function(column, operator, callback, bool) { | ||
var query = new Builder(this); | ||
callback.call(query, query); | ||
this.wheres.push({ | ||
type: 'Sub', | ||
column: column, | ||
operator: operator, | ||
query: query, | ||
bool: bool | ||
}); | ||
push.apply(this.bindings, query.bindings); | ||
return this; | ||
}, | ||
// Helper for compiling any aggregate queries. | ||
_aggregate: function(type, columns) { | ||
if (!_.isArray(columns)) columns = [columns]; | ||
this.aggregate = {type: type, columns: columns}; | ||
return this._setType('select'); | ||
}, | ||
// Helper for the incrementing/decrementing queries. | ||
_counter: function(column, amount, symbol) { | ||
var sql = {}; | ||
sql[column] = new Raw('' + this.grammar.wrap(column) + ' ' + (symbol || '+') + ' ' + amount); | ||
return this.update(sql); | ||
}, | ||
// Helper for compiling any `union` queries. | ||
_union: function(callback, bool) { | ||
var query = new Builder(this); | ||
callback.call(query, query); | ||
this.unions.push({query: query, all: bool}); | ||
push.apply(this.bindings, query.bindings); | ||
} | ||
}); | ||
// Knex.JoinClause | ||
// --------- | ||
var JoinClause = Knex.JoinClause = function(type, table) { | ||
this.clauses = []; | ||
this.type = type; | ||
this.table = table; | ||
}; | ||
JoinClause.prototype = { | ||
on: function(first, operator, second) { | ||
this.clauses.push({first: first, operator: operator, second: second, bool: 'and'}); | ||
return this; | ||
}, | ||
andOn: function() { | ||
return this.on.apply(this, arguments); | ||
}, | ||
orOn: function(first, operator, second) { | ||
this.clauses.push({first: first, operator: operator, second: second, bool: 'or'}); | ||
return this; | ||
} | ||
}; | ||
// Knex.Transaction | ||
// --------- | ||
Knex.Transaction = function(container) { | ||
if (!Knex.Instances['main']) { | ||
throw new Error('The Knex instance has not been initialized yet.'); | ||
} | ||
return transaction.call(Knex.Instances['main'], container); | ||
}; | ||
var transaction = function(container) { | ||
var client = this.client; | ||
return client.startTransaction().then(function(connection) { | ||
// Initiate a deferred object, so we know when the | ||
// transaction completes or fails, we know what to do. | ||
var dfd = when.defer(); | ||
// The object passed around inside the transaction container. | ||
var containerObj = { | ||
commit: function(val) { | ||
client.finishTransaction('commit', this, dfd, val); | ||
}, | ||
rollback: function(err) { | ||
client.finishTransaction('rollback', this, dfd, err); | ||
}, | ||
// "rollback to"? | ||
connection: connection | ||
// Attach each of the `Schema` "interface" methods directly onto to `knex.schema` namespace, e.g.: | ||
// `knex.schema.table('tableName', function() {...` | ||
// `knex.schema.createTable('tableName', function() {...` | ||
// `knex.schema.dropTableIfExists('tableName');` | ||
_.each(SchemaInterface, function(val, key) { | ||
knex.schema[key] = function() { | ||
var schemaBuilder = new SchemaBuilder(knex); | ||
schemaBuilder.table = _.first(arguments); | ||
return SchemaInterface[key].apply(schemaBuilder, _.rest(arguments)); | ||
}; | ||
// Ensure the transacting object methods are bound with the correct context. | ||
_.bindAll(containerObj, 'commit', 'rollback'); | ||
// Call the container with the transaction | ||
// commit & rollback objects. | ||
container(containerObj); | ||
return dfd.promise; | ||
}); | ||
}; | ||
// Knex.Schema | ||
// --------- | ||
var initSchema = function(Target, client) { | ||
// Top level object for Schema related functions | ||
var Schema = Target.Schema = {}; | ||
// Attach main static methods, which passthrough to the | ||
// SchemaBuilder instance methods | ||
_.each(['hasTable', 'createTable', 'table', 'dropTable', 'renameTable', 'dropTableIfExists'], function(method) { | ||
Schema[method] = function() { | ||
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)); | ||
}; | ||
}); | ||
}; | ||
// 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'); | ||
}, | ||
// Create a new table on the schema. | ||
createTable: function(callback) { | ||
this._addCommand('createTable'); | ||
this.callback(callback); | ||
return this._setType('createTable'); | ||
}, | ||
// Drop a table from the schema. | ||
dropTable: function() { | ||
this._addCommand('dropTable'); | ||
return this._setType('dropTable'); | ||
}, | ||
// Drop a table from the schema if it exists. | ||
dropTableIfExists: function() { | ||
this._addCommand('dropTableIfExists'); | ||
return this._setType('dropTableIfExists'); | ||
}, | ||
// Rename a table on the schema. | ||
renameTable: function(to) { | ||
this._addCommand('renameTable', {to: to}); | ||
return this._setType('renameTable'); | ||
}, | ||
// Determine if the given table exists. | ||
hasTable: function() { | ||
this.bindings.push(this.table); | ||
this._addCommand('tableExists'); | ||
return this._setType('tableExists'); | ||
} | ||
}; | ||
// Knex.SchemaBuilder | ||
// -------- | ||
var SchemaBuilder = Knex.SchemaBuilder = function(table) { | ||
this.table = table; | ||
this.columns = []; | ||
this.commands = []; | ||
this.bindings = []; | ||
}; | ||
_.extend(SchemaBuilder.prototype, Common, { | ||
_source: 'SchemaBuilder', | ||
// A callback from the table building `Knex.schemaBuilder` calls. | ||
callback: function(callback) { | ||
if (callback) callback.call(this, this); | ||
return this; | ||
}, | ||
// Get the raw sql statements for the blueprint. | ||
toSql: function() { | ||
// Add the commands that are implied by the blueprint. | ||
if (this.columns.length > 0 && !this.creating()) { | ||
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', 'foreign']; | ||
continueIndex: | ||
for (var i2 = 0, l2 = indices.length; i2 < l2; i2++) { | ||
var index = indices[i2]; | ||
var indexVar = 'is' + capitalize(index); | ||
// If the index has been specified on the given column, but is simply | ||
// equal to "true" (boolean), no name has been specified for this | ||
// index, so we will simply call the index methods without one. | ||
if (column[indexVar] === true) { | ||
this[index](column, null); | ||
continue continueIndex; | ||
// If the index has been specified on the column and it is something | ||
// other than boolean true, we will assume a name was provided on | ||
// the index specification, and pass in the name to the method. | ||
} else if (_.has(column, indexVar)) { | ||
this[index](column.name, column[indexVar], column); | ||
continue continueIndex; | ||
} | ||
} | ||
} | ||
var statements = []; | ||
// Each type of command has a corresponding compiler function on the schema | ||
// grammar which is used to build the necessary SQL statements to build | ||
// the blueprint element, so we'll just call that compilers function. | ||
for (i = 0, l = this.commands.length; i < l; i++) { | ||
var command = this.commands[i]; | ||
var method = 'compile' + capitalize(command.name); | ||
if (_.has(this.grammar, method)) { | ||
var sql = this.grammar[method](this, command); | ||
if (sql) statements = statements.concat(sql); | ||
} | ||
} | ||
return statements; | ||
}, | ||
// Determine if the blueprint has a create command. | ||
creating: function() { | ||
for (var i = 0, l = this.commands.length; i < l; i++) { | ||
if (this.commands[i].name == 'createTable') return true; | ||
} | ||
return false; | ||
}, | ||
// Sets the engine to use when creating the table in MySql | ||
engine: function(name) { | ||
if (!this.creating()) throw new Error('The `engine` modifier may only be used while creating a table.'); | ||
this.isEngine = name; | ||
return this; | ||
}, | ||
// 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. | ||
dropColumn: function(columns) { | ||
if (!_.isArray(columns)) columns = columns ? [columns] : []; | ||
return this._addCommand('dropColumn', {columns: columns}); | ||
}, | ||
// Indicate that the given columns should be dropped. | ||
dropColumns: function() { | ||
return this.dropColumn(arguments); | ||
}, | ||
// Indicate that the given primary key should be dropped. | ||
dropPrimary: function(index) { | ||
return this._dropIndexCommand('dropPrimary', index); | ||
}, | ||
// Indicate that the given unique key should be dropped. | ||
dropUnique: function(index) { | ||
return this._dropIndexCommand('dropUnique', index); | ||
}, | ||
// Indicate that the given index should be dropped. | ||
dropIndex: function(index) { | ||
return this._dropIndexCommand('dropIndex', index); | ||
}, | ||
// Indicate that the given foreign key should be dropped. | ||
dropForeign: function(index) { | ||
return this._dropIndexCommand('dropForeign', index); | ||
}, | ||
// Specify the primary key(s) for the table. | ||
primary: function(columns, name) { | ||
return this._indexCommand('primary', columns, name); | ||
}, | ||
// Specify a unique index for the table. | ||
unique: function(columns, name) { | ||
return this._indexCommand('unique', columns, name); | ||
}, | ||
// Specify an index for the table. | ||
index: function(columns, name) { | ||
return this._indexCommand('index', 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); | ||
}, | ||
// Create a new auto-incrementing column on the table. | ||
increments: function(column) { | ||
return this._addColumn('integer', (column || 'id'), {autoIncrement: true, length: 11}); | ||
}, | ||
// Create a new string column on the table. | ||
string: function(column, length) { | ||
return this._addColumn('string', column, {length: (length || 255)}); | ||
}, | ||
// Alias varchar to string | ||
varchar: function(column, length) { | ||
return this.string(column, length); | ||
}, | ||
// Create a new text column on the table. | ||
text: function(column, length) { | ||
return this._addColumn('text', column, {length: (length || false)}); | ||
}, | ||
// Create a new integer column on the table. | ||
integer: function(column, length) { | ||
return this._addColumn('integer', column, {length: (length || 11)}); | ||
}, | ||
// Create a new tinyinteger column on the table. | ||
tinyInteger: function(column) { | ||
return this._addColumn('tinyInteger', column); | ||
}, | ||
// Alias for tinyinteger column. | ||
tinyint: function(column) { | ||
return this.tinyInteger(column); | ||
}, | ||
// Create a new float column on the table. | ||
float: function(column, precision, scale) { | ||
return this._addColumn('float', column, { | ||
precision: (precision == null ? 8 : precision), | ||
scale: (scale == null ? 2 : scale) | ||
}); | ||
}, | ||
// Create a new decimal column on the table. | ||
decimal: function(column, precision, scale) { | ||
return this._addColumn('decimal', column, { | ||
precision: (precision == null ? 8 : precision), | ||
scale: (scale == null ? 2 : scale) | ||
}); | ||
}, | ||
// Alias to "bool" | ||
boolean: function(column) { | ||
return this.bool(column); | ||
}, | ||
// Create a new boolean column on the table | ||
bool: function(column) { | ||
return this._addColumn('boolean', column); | ||
}, | ||
// Create a new date column on the table. | ||
date: function(column) { | ||
return this._addColumn('date', column); | ||
}, | ||
// Create a new date-time column on the table. | ||
dateTime: function(column) { | ||
return this._addColumn('dateTime', column); | ||
}, | ||
// Create a new time column on the table. | ||
time: function(column) { | ||
return this._addColumn('time', column); | ||
}, | ||
// Create a new timestamp column on the table. | ||
timestamp: function(column) { | ||
return this._addColumn('timestamp', column); | ||
}, | ||
// Add creation and update dateTime's to the table. | ||
timestamps: function() { | ||
this.dateTime('created_at'); | ||
this.dateTime('updated_at'); | ||
}, | ||
// Alias to enum. | ||
"enum": function(column, allowed) { | ||
return this.enu(column, allowed); | ||
}, | ||
// Create a new enum column on the table. | ||
enu: function(column, allowed) { | ||
if (!_.isArray(allowed)) allowed = [allowed]; | ||
return this._addColumn('enum', column, {allowed: allowed}); | ||
}, | ||
// Create a new bit column on the table. | ||
bit: function(column, length) { | ||
return this._addColumn('bit', column, {length: (length || false)}); | ||
}, | ||
// Create a new binary column on the table. | ||
binary: function(column) { | ||
return this._addColumn('binary', column); | ||
}, | ||
// 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); | ||
}, | ||
// ---------------------------------------------------------------------- | ||
// Create a new drop index command on the blueprint. | ||
// If the index is an array of columns, the developer means | ||
// to drop an index merely by specifying the columns involved. | ||
_dropIndexCommand: function(type, index) { | ||
var columns = []; | ||
if (_.isArray(index)) { | ||
columns = index; | ||
index = null; | ||
} | ||
return this._indexCommand(type, columns, index); | ||
}, | ||
// Add a new index command to the blueprint. | ||
// If no name was specified for this index, we will create one using a basic | ||
// convention of the table name, followed by the columns, followed by an | ||
// index type, such as primary or index, which makes the index unique. | ||
_indexCommand: function(type, columns, index) { | ||
index || (index = null); | ||
if (!_.isArray(columns)) columns = columns ? [columns] : []; | ||
if (index === null) { | ||
var table = this.table.replace(/\.|-/g, '_'); | ||
index = (table + '_' + _.map(columns, function(col) { return col.name || col; }).join('_') + '_' + type).toLowerCase(); | ||
} | ||
return this._addCommand(type, {index: index, columns: columns}); | ||
}, | ||
// Add a new column to the blueprint. | ||
_addColumn: function(type, name, parameters) { | ||
if (!name) throw new Error('A `name` must be defined to add a column'); | ||
var column = _.extend({type: type, name: name}, ChainableColumn, parameters); | ||
this.columns.push(column); | ||
return column; | ||
}, | ||
// Add a new command to the blueprint. | ||
_addCommand: function(name, parameters) { | ||
var command = _.extend({name: name}, parameters); | ||
this.commands.push(command); | ||
return command; | ||
} | ||
}); | ||
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; | ||
} | ||
}; | ||
var ChainableColumn = _.extend({ | ||
// Sets the default value for a column. | ||
// For `boolean` columns, we'll permit 'false' | ||
// to be used as default values. | ||
defaultTo: function(value) { | ||
if (this.type === 'boolean') { | ||
if (value === 'false') value = 0; | ||
value = (value ? 1 : 0); | ||
} | ||
this.defaultValue = value; | ||
return this; | ||
}, | ||
// Sets an integer as unsigned, is a no-op | ||
// if the column type is not an integer. | ||
unsigned: function() { | ||
this.isUnsigned = true; | ||
return this; | ||
}, | ||
// Allows the column to contain null values. | ||
nullable: function() { | ||
this.isNullable = true; | ||
return this; | ||
}, | ||
// Adds an index on the specified column. | ||
index: function(name) { | ||
this.isIndex = name || true; | ||
return this; | ||
}, | ||
// Sets this column as the primary key. | ||
primary: function(name) { | ||
this.isPrimary = name || true; | ||
return this; | ||
}, | ||
// 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; | ||
}, | ||
// Adds a comment to this column. | ||
comment: function(comment) { | ||
this.isCommented = comment || null; | ||
return this; | ||
} | ||
}, ForeignChainable); | ||
Knex.SchemaGrammar = { | ||
// Compile a foreign key command. | ||
compileForeign: function(blueprint, command) { | ||
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); | ||
sql = "alter table " + table + " add constraint " + command.index + " "; | ||
sql += "foreign key (" + column + ") references " + foreignTable + " (" + foreignColumn + ")"; | ||
// 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; | ||
}, | ||
// 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, blueprint); | ||
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 SQL for the column data type. | ||
getType: function(column, blueprint) { | ||
return this['type' + capitalize(column.type)](column, blueprint); | ||
}, | ||
// 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 && value.name) 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.sql; | ||
if (value === true || value === false) { | ||
return parseInt(value, 10); | ||
} | ||
return '' + value; | ||
} | ||
}; | ||
// Knex.Raw | ||
// ------- | ||
// 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(sql, bindings) { | ||
if (!Knex.Instances['main']) { | ||
throw new Error('The Knex instance has not been initialized yet.'); | ||
} | ||
return Knex.Instances['main'].Raw(sql, bindings); | ||
}; | ||
var Raw = function(sql, bindings) { | ||
this.bindings = (!_.isArray(bindings) ? (bindings ? [bindings] : []) : bindings); | ||
this.sql = sql; | ||
}; | ||
_.extend(Raw.prototype, Common, { | ||
_source: 'Raw', | ||
// Returns the raw sql for the query. | ||
toSql: function() { | ||
return this.sql; | ||
} | ||
}); | ||
// Simple capitalization of a word. | ||
var capitalize = function(word) { | ||
return word.charAt(0).toUpperCase() + word.slice(1); | ||
}; | ||
// Sorts an object based on the names. | ||
var sortObject = function(obj) { | ||
return _.sortBy(_.pairs(obj), function(a) { | ||
return a[0]; | ||
}); | ||
}; | ||
// Sets up a multi-query to be executed with serial promises. | ||
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 | ||
// ------- | ||
// Takes a hash of options to initialize the database | ||
// connection. The `client` is required to choose which client | ||
// path above is loaded, or to specify a custom path to a client. | ||
// Other options, such as `connection` or `pool` are passed | ||
// into `client.initialize`. | ||
Knex.Initialize = function(name, options) { | ||
var Target, ClientCtor, client; | ||
// A name for the connection isn't required in | ||
// cases where there is only a single connection. | ||
if (_.isObject(name)) { | ||
options = name; | ||
name = 'main'; | ||
} | ||
// Don't try to initialize the same `name` twice... If necessary, | ||
// delete the instance from `Knex.Instances`. | ||
if (Knex.Instances[name]) { | ||
throw new Error('An instance named ' + name + ' already exists.'); | ||
} | ||
client = options.client; | ||
if (!client) throw new Error('The client is required to use Knex.'); | ||
// Checks if this is a default client. If it's not, | ||
// that means it's a custom lib, set the object to the client. | ||
if (_.isString(client)) { | ||
client = client.toLowerCase(); | ||
try { | ||
ClientCtor = require(Clients[client]); | ||
} catch (e) { | ||
throw new Error(client + ' is not a valid Knex client, did you misspell it?'); | ||
} | ||
} else { | ||
ClientCtor = client; | ||
} | ||
// Creates a new instance of the db client, passing the name and options. | ||
client = new ClientCtor(name, _.omit(options, 'client')); | ||
// 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 | ||
Target = function(table) { | ||
var builder = new Knex.Builder(table); | ||
builder.client = client; | ||
builder.grammar = client.grammar; | ||
return builder; | ||
// Method to run a new `Raw` query on the current client. | ||
knex.raw = function(sql, bindings) { | ||
return new Raw(knex).query(sql, bindings); | ||
}; | ||
// Inherit static properties, without any that don't apply except | ||
// on the "root" `Knex`. | ||
_.extend(Target, _.omit(Knex, 'Initialize', 'Instances', 'VERSION')); | ||
// Keep a reference to the current client. | ||
knex.client = client; | ||
// Initialize the schema builder methods. | ||
if (name === 'main') { | ||
initSchema(Knex, client); | ||
Knex.client = client; | ||
} | ||
// Keep in sync with package.json | ||
knex.VERSION = '0.4.0'; | ||
initSchema(Target, client); | ||
// Specifically set the client on the current target. | ||
Target.client = client; | ||
Target.instanceName = name; | ||
// Setup the transacting function properly for this connection. | ||
Target.Transaction = function(handler) { | ||
return transaction.call(this, handler); | ||
// Runs a new transaction, taking a container and returning a promise | ||
// for when the transaction is resolved. | ||
knex.transaction = function(container) { | ||
return new Transaction(knex).run(container); | ||
}; | ||
// Executes a Raw query. | ||
Target.Raw = function(sql, bindings) { | ||
var raw = new Raw(sql, bindings); | ||
raw.client = client; | ||
return raw; | ||
}; | ||
// Add this instance to the global `Knex` instances, and return. | ||
Knex.Instances[name] = Target; | ||
return Target; | ||
// Return the new `Knex` instance. | ||
return knex; | ||
}; | ||
var array = []; | ||
var push = array.push; | ||
// Default client paths, located in the `./clients` directory. | ||
var Clients = { | ||
'mysql' : './clients/mysql.js', | ||
'pg' : './clients/postgres.js', | ||
'postgres' : './clients/postgres.js', | ||
'sqlite' : './clients/sqlite3.js', | ||
'sqlite3' : './clients/sqlite3.js' | ||
// The client names we'll allow in the `{name: lib}` pairing. | ||
var Clients = Knex.Clients = { | ||
'mysql' : './clients/server/mysql.js', | ||
'pg' : './clients/server/postgres.js', | ||
'postgres' : './clients/server/postgres.js', | ||
'postgresql' : './clients/server/postgres.js', | ||
'sqlite' : './clients/server/sqlite3.js', | ||
'sqlite3' : './clients/server/sqlite3.js' | ||
}; | ||
// Named instances of Knex, presumably with different database | ||
// connections, the main instance being named "main"... | ||
Knex.Instances = {}; | ||
// Used primarily to type-check a potential `Knex` client in `Bookshelf.js`, | ||
// by examining whether the object's `client` is an `instanceof Knex.ClientBase`. | ||
Knex.ClientBase = ClientBase; | ||
// Export the Knex module | ||
// finally, export the `Knex` object for node and the browser. | ||
module.exports = Knex; | ||
Knex.initialize = function(config) { | ||
return Knex(config); | ||
}; | ||
}); | ||
@@ -1692,0 +129,0 @@ |
{ | ||
"name": "knex", | ||
"version": "0.2.6", | ||
"version": "0.4.0", | ||
"description": "A query builder for Postgres, MySQL and SQLite3, designed to be flexible, portable, and fun to use.", | ||
@@ -17,3 +17,8 @@ "main": "knex.js", | ||
"grunt": "~0.4.1", | ||
"grunt-release": "~0.5.1" | ||
"grunt-release": "~0.5.1", | ||
"mocha-as-promised": "~1.4.0", | ||
"chai": "~1.7.2", | ||
"chai-as-promised": "~3.3.1", | ||
"sinon": "~1.7.3", | ||
"sinon-chai": "~2.4.0" | ||
}, | ||
@@ -23,3 +28,3 @@ "dependencies": { | ||
"underscore": "~1.5.1", | ||
"generic-pool": "~2.0.3" | ||
"generic-pool-redux": "~0.1.0" | ||
}, | ||
@@ -26,0 +31,0 @@ "scripts": { |
@@ -1,71 +0,57 @@ | ||
var equal = require('assert').equal; | ||
var When = require('when'); | ||
var _ = require('underscore'); | ||
var Knex = require('../knex'); | ||
var conn = require(process.env.KNEX_TEST || './shared/config'); | ||
// The output goes here. | ||
exports.output = {}; | ||
require("mocha-as-promised")(); | ||
var pool = { | ||
afterCreate: function(conn, done) { | ||
equal(_.has(conn, '__cid'), true); | ||
done(); | ||
}, | ||
beforeDestroy: function(conn, done) { | ||
equal(_.has(conn, '__cid'), true); | ||
done(); | ||
} | ||
}; | ||
global.sinon = require("sinon"); | ||
Knex.Initialize({ | ||
client: 'mysql', | ||
connection: conn.mysql, | ||
pool: _.extend({}, pool, { | ||
afterCreate: function(conn, done) { | ||
conn.query("SET sql_mode='TRADITIONAL';", [], function(err) { | ||
done(err); | ||
}); | ||
} | ||
}) | ||
var chai = global.chai = require("chai"); | ||
chai.use(require("chai-as-promised")); | ||
chai.use(require("sinon-chai")); | ||
chai.should(); | ||
global._ = require('underscore'); | ||
global.whenResolve = require('when').resolve; | ||
global.expect = chai.expect; | ||
global.AssertionError = chai.AssertionError; | ||
global.Assertion = chai.Assertion; | ||
global.assert = chai.assert; | ||
// Unit tests | ||
describe('Unit Tests', function() { | ||
require('./unit/knex'); | ||
require('./unit/common'); | ||
require('./unit/builder'); | ||
require('./unit/builder/joinclause'); | ||
require('./unit/raw'); | ||
require('./unit/transaction'); | ||
require('./unit/clients/base'); | ||
require('./unit/clients/base/grammar'); | ||
require('./unit/clients/base/schemagrammar'); | ||
require('./unit/clients/server/base'); | ||
require('./unit/clients/server/mysql'); | ||
require('./unit/clients/server/postgres'); | ||
require('./unit/clients/server/sqlite3'); | ||
}); | ||
var Sqlite3 = Knex.Initialize('sqlite3', { | ||
client: 'sqlite3', | ||
connection: conn.sqlite3, | ||
pool: pool | ||
}); | ||
var Postgres = Knex.Initialize('postgres', { | ||
client: 'postgres', | ||
connection: conn.postgres, | ||
pool: pool | ||
}); | ||
var regularThen = Knex.Builder.prototype.then; | ||
var then = function(success, error) { | ||
var ctx = this; | ||
var bindings = ctx._cleanBindings(); | ||
var chain = regularThen.call(this, function(resp) { | ||
return { | ||
object: resp, | ||
string: { | ||
sql: ctx.sql, | ||
bindings: bindings | ||
} | ||
}; | ||
// Integration Tests | ||
describe('Integration Tests', function() { | ||
var helper = require('./integration/helper'); | ||
before(function() { | ||
helper.setLib(this); | ||
}); | ||
return chain.then(success, error); | ||
}; | ||
describe('Knex', function() { | ||
require('./integration/knex'); | ||
_.each(['Builder', 'SchemaBuilder', 'Raw'], function(item) { | ||
Knex[item].prototype.then = then; | ||
Postgres[item].prototype.then = then; | ||
Sqlite3[item].prototype.then = then; | ||
after(function() { | ||
helper.writeResult(); | ||
}); | ||
require('./regular')(Knex, 'mysql'); | ||
require('./regular')(Postgres, 'postgres'); | ||
require('./regular')(Sqlite3, 'sqlite3'); | ||
}); | ||
}); | ||
// Benchmarks | ||
describe('Benchmarks', function() { | ||
}); |
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
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
216516
67
13
5677
8
1
+ Addedgeneric-pool-redux@~0.1.0
+ Addedgeneric-pool-redux@0.1.0(transitive)
- Removedgeneric-pool@~2.0.3
- Removedgeneric-pool@2.0.4(transitive)