Skip to content

Commit

Permalink
An attempt to implement .setNullable. Fixes knex#1218
Browse files Browse the repository at this point in the history
  • Loading branch information
wubzz committed Apr 2, 2016
1 parent bb9663f commit f3a0245
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 1 deletion.
8 changes: 8 additions & 0 deletions index.html
Expand Up @@ -188,6 +188,7 @@
<li><a href="#Schema-dropForeign">dropForeign</a></li>
<li><a href="#Schema-dropUnique">dropUnique</a></li>
<li><a href="#Schema-dropPrimary">dropPrimary</a></li>
<li><a href="#Schema-setNullable">setNullable</a></li>
<li><a href="#Chainable"><b>Chainable:</b></li>
<li><a href="#Chainable-index">index</a></li>
<li><a href="#Chainable-primary">primary</a></li>
Expand Down Expand Up @@ -2100,6 +2101,13 @@ <h3 id="Schema-Building">Schema Building:</h3>
Drops the primary key constraint on a table.
</p>


<p id="Schema-setNullable">
<b class="header">setNullable</b><code>table.setNullable(column, [true|false])</code>
<br />
Alters a columns nullable constraint.
</p>

<h3 id="Chainable">Chainable Methods:</h3>

<p>
Expand Down
23 changes: 22 additions & 1 deletion src/dialects/mssql/schema/tablecompiler.js
Expand Up @@ -6,7 +6,7 @@ var TableCompiler = require('../../../schema/tablecompiler');
var helpers = require('../../../helpers');
var Promise = require('../../../promise');

import {assign} from 'lodash'
import {assign, isEmpty} from 'lodash'

// Table Compiler
// ------
Expand Down Expand Up @@ -49,6 +49,27 @@ assign(TableCompiler_MSSQL.prototype, {
this.pushQuery('exec sp_rename ' + this.formatter.parameter(this.tableName() + '.' + from) + ', ' + this.formatter.parameter(to) + ', \'COLUMN\'');
},

setNullable: function (column, nullable) {
let tableName = this.tableName();
let columnName = this.formatter.columnize(column);
return this.pushQuery({
sql: 'SELECT 1',
output: () => {
return this.client.queryBuilder().from(this.tableNameRaw).columnInfo(column)
.then((columnInfo) => {
if(isEmpty(columnInfo)) {
throw new Error(`.setNullable: Column ${columnName} does not exist in table ${tableName}.`)
}
let nullableType = nullable ? 'null' : 'not null';
let columnType = columnInfo.type + (columnInfo.maxLength ? `(${columnInfo.maxLength})` : '');
let defaultValue = (columnInfo.defaultValue !== null && columnInfo.defaultValue !== void 0) ? `default '${columnInfo.defaultValue}'` : '';
let sql = `alter table ${tableName} alter column ${columnName} ${columnType} ${nullableType} ${defaultValue}`;
return this.client.raw(sql);
});
}
});
},

dropFKRefs: function (runner, refs) {
var formatter = this.client.formatter();
return Promise.all(refs.map(function (ref) {
Expand Down
9 changes: 9 additions & 0 deletions src/dialects/postgres/schema/tablecompiler.js
Expand Up @@ -18,6 +18,15 @@ TableCompiler_PG.prototype.renameColumn = function(from, to) {
});
};


TableCompiler_PG.prototype.setNullable = function (column, nullable) {
let constraintAction = nullable ? 'drop not null' : 'set not null';
let sql = `alter table ${this.tableName()} alter column ${this.formatter.wrap(column)} ${constraintAction}`;
return this.pushQuery({
sql: sql
});
};

TableCompiler_PG.prototype.compileAdd = function(builder) {
var table = this.formatter.wrap(builder);
var columns = this.prefixArray('add column', this.getColumns(builder));
Expand Down
5 changes: 5 additions & 0 deletions src/dialects/sqlite3/schema/tablecompiler.js
Expand Up @@ -107,6 +107,11 @@ TableCompiler_SQLite3.prototype.renameColumn = function(from, to) {
});
};


TableCompiler_SQLite3.prototype.setNullable = function() {
throw new Error('.setNullable is not supported for SQLite.');
};

TableCompiler_SQLite3.prototype.dropColumn = function(column) {
var compiler = this;
this.pushQuery({
Expand Down
10 changes: 10 additions & 0 deletions src/schema/tablebuilder.js
Expand Up @@ -248,6 +248,16 @@ var AlterMethods = {

dropTimestamps: function() {
return this.dropColumns(['created_at', 'updated_at']);
},

setNullable: function(column, nullable) {
this._statements.push({
grouping: 'alterTable',
method: 'setNullable',
args: [column, nullable === true]
});

return this;
}

// TODO: changeType
Expand Down
24 changes: 24 additions & 0 deletions src/schema/tablecompiler.js
Expand Up @@ -205,4 +205,28 @@ TableCompiler.prototype._indexCommand = function (type, tableName, columns) {
return this.formatter.wrap(indexName);
};


//Default implementation of setNullable. Overwrite on dialect-specific tablecompiler when needed
//(See postgres/mssql for reference)
TableCompiler.prototype.setNullable = function(column, nullable) {
let tableName = this.tableName();
let columnName = this.formatter.columnize(column);
return this.pushQuery({
sql: 'SELECT 1',
output: () => {
return this.client.queryBuilder().from(this.tableNameRaw).columnInfo(column)
.then((columnInfo) => {
if(isEmpty(columnInfo)) {
throw new Error(`.setNullable: Column ${columnName} does not exist in table ${tableName}.`)
}
let nullableType = nullable ? 'null' : 'not null';
let columnType = columnInfo.type + (columnInfo.maxLength ? `(${columnInfo.maxLength})` : '');
let defaultValue = (columnInfo.defaultValue !== null && columnInfo.defaultValue !== void 0) ? `default '${columnInfo.defaultValue}'` : '';
let sql = `alter table ${tableName} modify column ${columnName} ${columnType} ${nullableType} ${defaultValue}`;
return this.client.raw(sql);
});
}
});
};

module.exports = TableCompiler;
39 changes: 39 additions & 0 deletions test/integration/schema/index.js
Expand Up @@ -467,5 +467,44 @@ module.exports = function(knex) {
});
});

if(knex.client.dialect !== 'sqlite3') {
//Not supported by sqlite3
describe('setNullable', function() {


it('setNullable true & false', function() {
var tableName = 'setNullableTest';
var columnName = 'colname';
var getColInfo = function() { return knex(tableName).columnInfo(columnName); };

return knex.schema.dropTableIfExists(tableName)
.createTable(tableName, function(table) {
table.string(columnName).notNullable();
})
.then(getColInfo)
.then(function(columnInfo) {
expect(columnInfo.nullable).to.equal(false);
return knex.schema.table(tableName, function(table) {
table.setNullable(columnName, true);
});
})
.then(function() {
return getColInfo();
})
.then(function(columnInfo) {
expect(columnInfo.nullable).to.equal(true);
return knex.schema.table(tableName, function(table) {
table.setNullable(columnName, false);
});
})
.then(getColInfo)
.then(function(columnInfo) {
expect(columnInfo.nullable).to.equal(false);
});
});

});
}

});
};

0 comments on commit f3a0245

Please sign in to comment.