knex/lib/schema/tablebuilder.js

267 lines
5.6 KiB
JavaScript
Raw Normal View History

// TableBuilder
// Takes the function passed to the "createTable" or "table/editTable"
// functions and calls it with the "TableBuilder" as both the context and
// the first argument. Inside this function we can specify what happens to the
// method, pushing everything we want to do onto the "allStatements" array,
// which is then compiled into sql.
// -------
var _ = require('lodash');
function TableBuilder(tableName) {
this._tableName = tableName;
this._statements = [];
this._single = {};
}
// Compile the "alter" query for the table.
// We attach any "alter" methods to the object
// before invoking the function, so as to
TableBuilder.prototype._alter = function(fn) {
this._method = 'alter';
_.extend(this, AlterMethods);
fn.call(this, this);
return this;
};
// Compile the "create" query for the table.
TableBuilder.prototype._create = function(fn) {
this._method = 'create';
fn.call(this, this);
return this;
};
var AlterMethods = {
// Renames the current column `from` the current
// TODO: this.column(from).rename(to)
renameColumn: function(from, to) {
this._statements.push({
grouping: 'alterColumns',
type: 'renameColumn',
args: [from, to]
});
return this;
},
dropTimestamps: function() {
return this.dropColumns(['created_at', 'updated_at']);
}
// TODO: changeType
};
// Drop a column from the current table.
// TODO: Enable this.column(columnName).drop();
AlterMethods.dropColumn =
AlterMethods.dropColumns = function() {
this._statements.push({
grouping: 'alterColumns',
type: 'dropColumn',
args: Helpers.normalizeArr.apply(null, arguments)
});
return this;
};
_.each(['dropPrimary', 'dropUnique', 'dropIndex', 'dropForeign'], function(method) {
AlterMethods[method] = function() {
this._statements.push({
grouping: 'indexes',
type: method,
args: _.toArray(arguments)
});
return this;
};
});
// Warn if we're not in MySQL, since that's the only time these
// three are supported.
var specialMethods = ['engine', 'charset', 'collate'];
_.each(specialMethods, function(method) {
if (false) {
warn('Knex only supports ' + method + ' statement with mysql.');
} if (this.__method === 'alter') {
warn('Knex does not support altering the ' + method + ' outside of the create table, please use knex.raw statement.');
}
this._single[method] = value;
});
// For each of the column types that we can add, we just push it onto the "allStatements"
// stack and then return the appropriate chainable interface for the column.
var columnMethods = [
// Numeric
'tinyint',
'smallint',
'mediumint',
'int',
'bigint',
'decimal',
'float',
'double',
'real',
'bit',
'boolean',
'serial',
// Date / Time
'date',
'datetime',
'timestamp',
'time',
'year',
// String
'char',
'varchar',
'tinytext',
'tinyText',
'text',
'mediumtext',
'mediumText',
'longtext',
'longText',
'binary',
'varbinary',
'tinyblob',
'tinyBlob',
'mediumblob',
'mediumBlob',
'blob',
'longblob',
'longBlob',
'enum',
'set',
// Increments, Aliases, and Additional
'bool',
'dateTime',
'increments',
'bigincrements',
'bigIncrements',
'integer',
'biginteger',
'bigInteger',
'string',
'timestamps',
'json',
'uuid',
'enu',
'specificType'
];
// "SPATIAL"
// geometry
// point
// linestring
// polygon
// multipoint
// multilinestring
// multipolygon
// geometrycollection
/*
// SQLITE3 Definitions:
// type: integer (1)
int
integer
tinyint
smallint
mediumint
bigint
unsigned BIG INT
int2
int8
// type: text (2)
character(20)
varchar(255)
varying CHARACTER(255)
nchar(55)
native CHARACTER(70)
nvarchar(100)
text
clob
// type: no datatype specified (none) (3)
blob
// type: float / real (4)
real
double
double precision
// type numeric (5)
numeric
decimal(10,5)
boolean
date
datetime
*/
// Alias a few methods for clarity when processing.
var aliasColumn = {
'float' : 'floating',
'enum' : 'enu',
'boolean': 'bool',
'string' : 'varchar',
'bigint' : 'bigInteger'
};
// For each of the column methods, create a new "ColumnBuilder" interface,
// push it onto the "allStatements" stack, and then return the interface,
// with which we can add indexes, etc.
_.each(columnMethods, function(method) {
TableBuilder.prototype[method] = function() {
var args = _.toArray(arguments);
// The "timestamps" call is really a compound call to set the
// `created_at` and `updated_at` columns.
if (method === 'timestamps') {
if (args[0] === true) {
this.timestamp('created_at');
this.timestamp('updated_at');
} else {
this.datetime('created_at');
this.datetime('updated_at');
}
return;
}
var aliased = (aliasColumn[method] || method).toLowerCase();
var chainable = new ColumnBuilder(this, args[0]).type(aliased);
this._statements.push({
grouping: 'column',
method: aliased,
originalMethod: method,
args: args,
builder: builder
});
return chainable;
};
});
// Each of the index methods can be called individually, with the
// column name to be used, e.g. table.unique('column').
var indexMethods = ['index', 'primary', 'unique'];
_.each(indexMethods, function(method) {
TableBuilder.prototype[method] = function() {
this._statements.push({
type: 'indexes',
method: method,
args: _.toArray(arguments)
});
};
});
// Set the comment value for a table, they're only allowed to be called
// once per table.
TableBuilder.prototype.comment = function(value) {
this._single.comment = value;
};
module.exports = TableBuilder;