Skip to content

Commit

Permalink
Added setNullable support to SQLite (knex#4684)
Browse files Browse the repository at this point in the history
  • Loading branch information
aidenfoxx authored and rustyconover committed Oct 18, 2021
1 parent 8e6d5ec commit e4bd9b9
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 5 deletions.
34 changes: 34 additions & 0 deletions lib/dialects/sqlite3/schema/ddl.js
Expand Up @@ -344,6 +344,40 @@ class SQLite3_DDL {
);
}

setNullable(column, isNullable) {
return this.client.transaction(
async (trx) => {
this.trx = trx;

const { createTable, createIndices } = await this.getTableSql();

const parsedTable = parseCreateTable(createTable);
const parsedColumn = parsedTable.columns.find((c) =>
isEqualId(column, c.name)
);

if (!parsedColumn) {
throw new Error(
`.setNullable: Column ${column} does not exist in table ${this.tableName()}.`
);
}

parsedColumn.constraints.notnull = isNullable
? null
: { name: null, conflict: null };

parsedColumn.constraints.null = isNullable
? parsedColumn.constraints.null
: null;

const newTable = compileCreateTable(parsedTable, this.wrap);

return this.generateAlterCommands(newTable, createIndices);
},
{ connection: this.connection }
);
}

async alter(newSql, createIndices, columns) {
await this.createNewTable(newSql);
await this.copyData(columns);
Expand Down
12 changes: 10 additions & 2 deletions lib/dialects/sqlite3/schema/sqlite-tablecompiler.js
Expand Up @@ -266,8 +266,16 @@ class TableCompiler_SQLite3 extends TableCompiler {
}

_setNullableState(column, isNullable) {
const fnCalled = isNullable ? '.setNullable' : '.dropNullable';
throw new Error(`${fnCalled} is not supported for SQLite.`);
const compiler = this;

this.pushQuery({
sql: `PRAGMA table_info(${this.tableName()})`,
statementsProducer(pragma, connection) {
return compiler.client
.ddl(compiler, pragma, connection)
.setNullable(column, isNullable);
},
});
}

dropColumn() {
Expand Down
34 changes: 31 additions & 3 deletions test/integration2/schema/set-nullable.spec.js
@@ -1,6 +1,7 @@
const chai = require('chai');
chai.use(require('chai-as-promised'));
const expect = chai.expect;
const sinon = require('sinon');
const {
isSQLite,
isPostgreSQL,
Expand All @@ -16,13 +17,12 @@ describe('Schema', () => {
let knex;

before(function () {
sinon.stub(Math, 'random').returns(0.1);
knex = getKnexForDb(db);
if (isSQLite(knex)) {
return this.skip();
}
});

after(() => {
sinon.restore();
return knex.destroy();
});

Expand All @@ -38,6 +38,31 @@ describe('Schema', () => {
});

describe('setNullable', () => {
it('should generate correct SQL for set nullable operation', async () => {
const builder = knex.schema.table('primary_table', (table) => {
table.setNullable('id_not_nullable');
});
const queries = await builder.generateDdlCommands();

if (isSQLite(knex)) {
expect(queries.sql).to.eql([
'CREATE TABLE `_knex_temp_alter111` (`id_nullable` integer NULL, `id_not_nullable` integer)',
'INSERT INTO _knex_temp_alter111 SELECT * FROM primary_table;',
'DROP TABLE "primary_table"',
'ALTER TABLE "_knex_temp_alter111" RENAME TO "primary_table"',
]);
}

if (isPostgreSQL(knex)) {
expect(queries.sql).to.eql([
{
bindings: [],
sql: 'alter table "primary_table" alter column "id_not_nullable" drop not null',
},
]);
}
});

it('sets column to be nullable', async () => {
await knex.schema.table('primary_table', (table) => {
table.setNullable('id_not_nullable');
Expand All @@ -63,6 +88,9 @@ describe('Schema', () => {
errorMessage = 'cannot be null';
} else if (isOracle(knex)) {
errorMessage = 'ORA-01400: cannot insert NULL into';
} else if (isSQLite(knex)) {
errorMessage =
'insert into `primary_table` (`id_not_nullable`, `id_nullable`) values (1, NULL) - SQLITE_CONSTRAINT: NOT NULL constraint failed: primary_table.id_nullable';
}

await expect(
Expand Down

0 comments on commit e4bd9b9

Please sign in to comment.