Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added setNullable support to SQLite #4684

Merged
merged 3 commits into from
Sep 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 34 additions & 0 deletions lib/dialects/sqlite3/schema/ddl.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,40 @@ class SQLite3_DDL {
);
}

setNullable(column, isNullable) {
return this.client.transaction(
kibertoad marked this conversation as resolved.
Show resolved Hide resolved
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
Original file line number Diff line number Diff line change
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()})`,
aidenfoxx marked this conversation as resolved.
Show resolved Hide resolved
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
Original file line number Diff line number Diff line change
@@ -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