knex/lib/dialects/mysql/schema.js

432 lines
12 KiB
JavaScript

module.exports = function(client) {
var _ = require('lodash');
var inherits = require('inherits');
var Promise = require('../../promise');
var SchemaBuilder = require('../../schema/builder');
var SchemaCompiler = require('../../schema/compiler');
var TableBuilder = require('../../schema/tablebuilder');
var TableCompiler = require('../../schema/tablecompiler');
var ColumnBuilder = require('../../schema/columnbuilder');
var ColumnCompiler = require('../../schema/columncompiler');
function SchemaBuilder_MySQL() {
SchemaBuilder.apply(this, arguments);
}
inherits(SchemaBuilder_MySQL, SchemaBuilder);
SchemaBuilder_MySQL.prototype.toSql = function() {
var sql = [];
new SchemaCompiler_MySQL(this);
for (var i = 0, l = this._sequence.length; i < l; i++) {
}
_.map(this._sequence, function() {
});
};
// Set the "then" method to call `runThen` on the client, processing the query.
SchemaBuilder_MySQL.prototype.then = function(onFulfilled, onRejected) {
return client.runThen(this).then(onFulfilled, onRejected);
};
function SchemaCompiler_MySQL() {
this.Formatter = client.Formatter;
SchemaCompiler.apply(this, arguments);
}
inherits(SchemaCompiler_MySQL, SchemaCompiler);
// Rename a table on the schema.
SchemaCompiler_MySQL.prototype.renameTable = function(tableName, to) {
return {
sql: 'rename table ' + this.formatter.wrap(tableName) + ' to ' + this.formatter.wrap(to)
};
};
// Check whether a table exists on the query.
SchemaCompiler_MySQL.prototype.hasTable = function(tableName) {
return {
sql: 'select * from information_schema.tables where table_schema = ? and table_name = ?',
bindings: [client.database(), tableName],
output: function(resp) {
return resp.length > 0;
}
};
};
// Check whether a column exists on the
SchemaCompiler_MySQL.prototype.hasColumn = function(tableName, column) {
return {
sql: 'show columns from ' + this.formatter.wrap(tableName) + ' like ?',
output: function(resp) {
return resp.length > 0;
}
};
};
// Create a new table.
SchemaCompiler_MySQL.prototype.createTable = function() {
};
SchemaCompiler_MySQL.prototype.alterTable = function() {
};
function TableCompiler_MySQL() {
this.modifierTypes = ['unsigned', 'nullable', 'defaultTo', 'after', 'comment'];
TableCompiler.apply(this, arguments);
}
inherits(TableCompiler_MySQL, TableCompiler);
TableCompiler_MySQL.prototype.create = function() {
var conn = {};
var returnSql = TableCompiler_MySQL.super_.create();
var sql = returnSql[0].sql;
// Check if the connection settings are set.
if (client.connectionSettings) {
conn = client.connectionSettings;
}
var charset = this.flags.charset || conn.charset;
var collation = this.flags.collate || conn.collate;
var engine = this.flags.engine;
// var conn = builder.client.connectionSettings;
if (charset) sql += ' default character set ' + charset;
if (collation) sql += ' collate ' + collation;
if (engine) sql += ' engine = ' + engine;
// // TODO: Handle max comment length ?
var maxTableCommentLength = 60;
var hasComment = _.has(this.attributes, 'comment');
if (hasComment) sql += " comment = '" + (this.attributes.comment || '') + "'";
this.push(sql);
};
addColumnsPrefix: 'add ',
dropColumnPrefix: 'drop ',
// Compiles the comment on the table.
SchemaCompiler_MySQL.prototype.comment = function(comment) {
this.push('alter table ' + this.tableName() + " comment = '" + comment + "'");
},
changeType: function() {
alter table + table + ' modify ' + wrapped + '// type';
}
// Renames a column on the table.
renameColumn: function(from, to) {
var wrapped = this._wrap(from) + ' ' + this._wrap(to);
var table = this.tableName();
return {
sql: 'show fields from ' + table + ' where field = ' +
this.formatter.parameter(from),
output: function(resp) {
var column = resp[0];
return this.query({
sql: 'alter table ' + table + ' change ' + wrapped + ' ' + column.Type
});
}
};
}
};
function TableBuilder_MySQL() {
}
// 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) {
TableBuilder.prototype[method] = function(value) {
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.');
} else {
this.__attributes[method] = value;
}
};
});
module.exports = function(client) {
var _ = require('lodash');
var SchemaTableCompiler = require('../../../schema/tablecompiler')(client);
return SchemaTableCompiler.extend({
// The possible column modifiers.
modifierTypes: ['unsigned', 'nullable', 'defaultTo', 'after', 'comment'],
// All types for sqlite3 builder. Feel free to fiddle with them on
// the client object if you wish, they're unique per-client.
types: require('./tablecompiler/types')(client),
// All modifiers for the sqlite3 builder.
modifiers: require('./tablecompiler/modifiers')(client),
// All key related statements for the sqlite3 builder.
keys: require('./tablecompiler/keys')(client),
// Create a new table
create: function() {
var conn = {};
var returnSql = SchemaTableCompiler.prototype.create.apply(this, arguments);
var sql = returnSql[0].sql;
// Check if the connection settings are set.
if (client.connectionSettings) {
conn = client.connectionSettings;
}
var charset = this.attributes.charset || conn.charset;
var collation = this.attributes.collate || conn.collate;
var engine = this.attributes.engine;
// var conn = builder.client.connectionSettings;
if (charset) sql += ' default character set ' + charset;
if (collation) sql += ' collate ' + collation;
if (engine) sql += ' engine = ' + engine;
// // TODO: Handle max comment length ?
var maxTableCommentLength = 60;
var hasComment = _.has(this.attributes, 'comment');
if (hasComment) sql += " comment = '" + (this.attributes.comment || '') + "'";
returnSql[0].sql = sql;
return returnSql;
},
addColumnsPrefix: 'add ',
dropColumnPrefix: 'drop ',
// Compiles the comment on the table.
comment: function(comment) {
return {
sql: 'alter table ' + this.tableName + " comment = '" + comment + "'"
};
},
// Renames a column on the table.
renameColumn: function(from, to) {
var wrapped = this._wrap(from) + ' ' + this._wrap(to);
var table = this.tableName;
return {
sql: 'show fields from ' + this.tableName + ' where field = ?',
bindings: [from],
output: function(resp) {
var column = resp[0];
return this.query({
sql: 'alter table ' + table + ' change ' + wrapped + ' ' + column.Type
});
}
};
}
});
};
// MySQL Schema Types
// -------
module.exports = function() {
var _ = require('lodash');
return _.extend({}, require('../../../../schema/tablecompiler/types'), {
increments: 'int unsigned not null auto_increment primary key',
bigincrements: 'bigint unsigned not null auto_increment primary key',
bigint: 'bigint',
double: function(precision, scale) {
if (!precision) return 'double';
return 'double(' + num(precision, 8) + ', ' + num(scale, 2) + ')';
},
integer: function(length) {
length = length ? '(' + num(length, 11) + ')' : '';
return 'int' + length;
},
mediumint: 'mediumint',
smallint: 'smallint',
tinyint: function(length) {
length = length ? '(' + num(length, 1) + ')' : '';
return 'tinyint' + length;
},
text: function(column) {
switch (column) {
case 'medium':
case 'mediumtext':
return 'mediumtext';
case 'long':
case 'longtext':
return 'longtext';
default:
return 'text';
}
},
mediumtext: function() {
return this.text('medium');
},
longtext: function() {
return this.text('long');
},
float: function(precision, scale) {
return 'float(' + precision + ',' + scale + ')';
},
typeDecimal: function(precision, scale) {
return 'decimal(' + precision + ', ' + scale + ')';
},
enu: function(allowed) {
return "enum('" + allowed.join("', '") + "')";
},
datetime: 'datetime',
timestamp: 'timestamp',
bit: function(length) {
return length ? 'bit(' + length + ')' : 'bit';
}
});
function num(val, fallback) {
if (val == null) return fallback;
var number = parseInt(val, 10);
return isNaN(number) ? fallback : number;
}
};
module.exports = function(client) {
var _ = require('lodash');
return {
index: function(columns, indexName) {
indexName = indexName || this._indexCommand('index', this.tableNameRaw, columns);
return {
sql: 'alter table ' + this.tableName + " add index " + indexName + "(" + this.formatter.columnize(columns) + ")"
};
},
primary: function(columns, indexName) {
indexName = indexName || this._indexCommand('primary', this.tableNameRaw, columns);
return {
sql: 'alter table ' + this.tableName + " add primary key " + indexName + "(" + this.formatter.columnize(columns) + ")"
};
},
unique: function(columns, indexName) {
indexName = indexName || this._indexCommand('unique', this.tableNameRaw, columns);
return {
sql: 'alter table ' + this.tableName + " add unique " + indexName + "(" + this.formatter.columnize(columns) + ")"
};
},
// Compile a drop index command.
dropIndex: function(key) {
return {
sql: 'alter table ' + this.tableName + ' drop index ' + key
};
},
// Compile a drop foreign key command.
dropForeign: function(key) {
return {
sql: 'alter table ' + this.tableName + ' drop foreign key ' + key
};
},
// Compile a drop primary key command.
dropPrimary: function() {
return {
sql: 'alter table ' + this.tableName + ' drop primary key'
};
},
// Compile a drop unique key command.
dropUnique: function(key) {
return {
sql: 'alter table ' + this.tableName + ' drop index ' + key
};
},
// Compile a foreign key command.
foreign: function(foreignData) {
var sql = '';
if (foreignData.inTable && foreignData.references) {
var keyName = this._indexCommand('foreign', this.tableNameRaw, foreignData.column);
var column = this.formatter.columnize(foreignData.column);
var references = this.formatter.columnize(foreignData.references);
var inTable = this.formatter.wrap(foreignData.inTable);
sql = 'alter table ' + this.tableName + ' add constraint ' + keyName + ' ';
sql += 'foreign key (' + column + ') references ' + inTable + ' (' + references + ')';
// 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 (foreignData.onDelete) sql += ' on delete ' + foreignData.onDelete;
if (foreignData.onUpdate) sql += ' on update ' + foreignData.onUpdate;
}
return {
sql: sql
};
}
};
};
module.exports = function(client) {
var _ = require('lodash');
var BaseModifiers = require('../../../../schema/tablecompiler/modifiers');
return _.extend({}, BaseModifiers, {
// Get the SQL for a default column modifier.
defaultTo: function MySQLModifiers$defaultTo(value) {
var defaultVal = BaseModifiers.defaultTo.apply(this, arguments);
var column = this.currentColumn;
if (column.method != 'blob' && column.method.indexOf('text') === -1) {
return defaultVal;
}
return '';
},
// Get the SQL for an unsigned column modifier.
unsigned: function() {
return 'unsigned';
},
// Get the SQL for an "after" column modifier.
after: function(column) {
return 'after ' + this.formatter.wrap(column);
},
// Get the SQL for a comment column modifier.
comment: function(comment) {
var maxColumnCommentLength = 255;
if (comment) return "comment '" + comment + "'";
}
});
};