mirror of
https://github.com/knex/knex.git
synced 2025-07-12 11:30:34 +00:00
269 lines
8.4 KiB
JavaScript
269 lines
8.4 KiB
JavaScript
![]() |
'use strict';
|
||
|
|
||
|
const { expect } = require('chai');
|
||
|
const { TEST_TIMESTAMP } = require('../../util/constants');
|
||
|
|
||
|
module.exports = function (knex) {
|
||
|
describe('Deletes with Triggers', function () {
|
||
|
// Trigger options
|
||
|
const triggerOptions = { includeTriggerModifications: true };
|
||
|
|
||
|
before(function () {
|
||
|
if (knex.client.driverName !== 'mssql') {
|
||
|
this.skip('This test is MSSQL only');
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Trigger Specific Tests', function () {
|
||
|
// Reused variables
|
||
|
// Table Names
|
||
|
const primaryTable = 'test_return_with_trigger_primary';
|
||
|
const secondaryTable = 'test_return_with_trigger_secondary';
|
||
|
|
||
|
// Foreign Key Column Names
|
||
|
const primaryLink = 'foreign_id';
|
||
|
const secondaryLink = 'looping_id';
|
||
|
|
||
|
// Trigger Name
|
||
|
const triggerName = 'tr_test_delete_with_trigger';
|
||
|
|
||
|
// Create proper environment for tests
|
||
|
before(async function () {
|
||
|
if (knex.client.driverName !== 'mssql') {
|
||
|
this.skip('This test is MSSQL only');
|
||
|
}
|
||
|
|
||
|
await knex.schema.hasTable('users').then(async function (exists) {
|
||
|
if (exists) {
|
||
|
await knex.schema.dropTable(primaryTable);
|
||
|
await knex.schema.dropTable(secondaryTable);
|
||
|
}
|
||
|
|
||
|
// Create tables
|
||
|
await knex.schema.createTable(primaryTable, function (table) {
|
||
|
table.increments().primary();
|
||
|
table.string('data').defaultsTo('');
|
||
|
table.integer(primaryLink).nullable();
|
||
|
});
|
||
|
|
||
|
await knex.schema.createTable(secondaryTable, function (table) {
|
||
|
table.increments().primary();
|
||
|
table.string('data').defaultsTo('');
|
||
|
table.integer(secondaryLink).nullable();
|
||
|
});
|
||
|
|
||
|
await knex.raw(`
|
||
|
CREATE TRIGGER [dbo].[${triggerName}] ON [dbo].[${secondaryTable}]
|
||
|
AFTER DELETE
|
||
|
AS
|
||
|
BEGIN
|
||
|
SET NOCOUNT ON;
|
||
|
|
||
|
BEGIN
|
||
|
delete ${primaryTable}
|
||
|
from ${primaryTable} as pt
|
||
|
inner join deleted as d
|
||
|
on pt.id = d.${secondaryLink}
|
||
|
END
|
||
|
END
|
||
|
`);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// Clean-up test specific tables
|
||
|
after(async function () {
|
||
|
if (knex.client.driverName !== 'mssql') {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Drop table (Trigger is removed with table)
|
||
|
await knex.schema.dropTable(primaryTable);
|
||
|
await knex.schema.dropTable(secondaryTable);
|
||
|
});
|
||
|
|
||
|
// Reset tables for each test
|
||
|
beforeEach(async function () {
|
||
|
// "Truncate" tables instead of recreate for each test for speed gains
|
||
|
await knex.raw(`
|
||
|
delete from ${primaryTable} dbcc checkident('${primaryTable}', reseed, 0);
|
||
|
delete from ${secondaryTable} dbcc checkident('${secondaryTable}', reseed, 0);
|
||
|
`);
|
||
|
});
|
||
|
|
||
|
it('#4152 Should allow returns with deletes on tables with triggers', async function () {
|
||
|
let reachedEnd = false;
|
||
|
|
||
|
await knex.transaction(async function () {
|
||
|
let insertedId;
|
||
|
let deletedId;
|
||
|
|
||
|
async function insertWithReturn() {
|
||
|
const insertPrimary = {
|
||
|
data: 'Testing Data',
|
||
|
};
|
||
|
|
||
|
const insertSecondary = {
|
||
|
data: 'Test Linking',
|
||
|
};
|
||
|
|
||
|
// Setup primary table for trigger use case
|
||
|
const primaryId = await knex(primaryTable).insert(
|
||
|
[insertPrimary],
|
||
|
['id'],
|
||
|
triggerOptions
|
||
|
);
|
||
|
insertSecondary[secondaryLink] = primaryId[0];
|
||
|
|
||
|
// Insert to table with trigger to test delete
|
||
|
insertedId = (
|
||
|
await knex(secondaryTable).insert(
|
||
|
[insertSecondary],
|
||
|
['id'],
|
||
|
triggerOptions
|
||
|
)
|
||
|
)[0];
|
||
|
}
|
||
|
|
||
|
async function deleteTriggerTable() {
|
||
|
// Test returning value from delete statement on a table with a trigger
|
||
|
deletedId = (
|
||
|
await knex(secondaryTable)
|
||
|
.whereRaw(`id = ${insertedId}`)
|
||
|
.delete(['id'], triggerOptions)
|
||
|
)[0];
|
||
|
}
|
||
|
|
||
|
await insertWithReturn();
|
||
|
await deleteTriggerTable();
|
||
|
|
||
|
expect(Number.parseInt(deletedId)).to.be.finite;
|
||
|
|
||
|
reachedEnd = true;
|
||
|
});
|
||
|
|
||
|
expect(reachedEnd).to.be.true;
|
||
|
});
|
||
|
|
||
|
it('#4152 Should allow returns with deletes on tables with triggers using returning function', async function () {
|
||
|
let reachedEnd = false;
|
||
|
|
||
|
await knex.transaction(async function () {
|
||
|
let insertedId;
|
||
|
let deletedId;
|
||
|
|
||
|
async function insertWithReturn() {
|
||
|
const insertPrimary = {
|
||
|
data: 'Testing Data',
|
||
|
};
|
||
|
|
||
|
const insertSecondary = {
|
||
|
data: 'Test Linking',
|
||
|
};
|
||
|
|
||
|
// Setup primary table for trigger use case
|
||
|
const primaryId = await knex(primaryTable).insert(
|
||
|
[insertPrimary],
|
||
|
['id'],
|
||
|
triggerOptions
|
||
|
);
|
||
|
insertSecondary[secondaryLink] = primaryId[0];
|
||
|
|
||
|
// Insert to table with trigger to test delete
|
||
|
insertedId = (
|
||
|
await knex(secondaryTable).insert(
|
||
|
[insertSecondary],
|
||
|
['id'],
|
||
|
triggerOptions
|
||
|
)
|
||
|
)[0];
|
||
|
}
|
||
|
|
||
|
async function deleteTriggerTable() {
|
||
|
// Test returning value from delete statement on a table with a trigger
|
||
|
deletedId = (
|
||
|
await knex(secondaryTable)
|
||
|
.whereRaw(`id = ${insertedId}`)
|
||
|
.returning(['id'], triggerOptions)
|
||
|
.delete()
|
||
|
)[0];
|
||
|
}
|
||
|
|
||
|
await insertWithReturn();
|
||
|
await deleteTriggerTable();
|
||
|
|
||
|
expect(Number.parseInt(deletedId)).to.be.finite;
|
||
|
|
||
|
reachedEnd = true;
|
||
|
});
|
||
|
|
||
|
expect(reachedEnd).to.be.true;
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Re-test all Delete Functions with trigger option and returns', function () {
|
||
|
before(async function () {
|
||
|
if (knex.client.driverName !== 'mssql') {
|
||
|
this.skip('This test is MSSQL only');
|
||
|
}
|
||
|
|
||
|
// Reset all table data to original stats of original tests
|
||
|
});
|
||
|
|
||
|
it('should allow returning for deletes in postgresql and mssql', function () {
|
||
|
return knex('accounts')
|
||
|
.where('id', 2)
|
||
|
.del('*', triggerOptions)
|
||
|
.testSql(function (tester) {
|
||
|
tester('mysql', 'delete from `accounts` where `id` = ?', [2], 1);
|
||
|
tester(
|
||
|
'pg',
|
||
|
'delete from "accounts" where "id" = ? returning *',
|
||
|
[2],
|
||
|
[
|
||
|
{
|
||
|
id: '2',
|
||
|
first_name: 'Test',
|
||
|
last_name: 'User',
|
||
|
email: 'test2@example.com',
|
||
|
logins: 1,
|
||
|
balance: 0,
|
||
|
about: 'Lorem ipsum Dolore labore incididunt enim.',
|
||
|
created_at: TEST_TIMESTAMP,
|
||
|
updated_at: TEST_TIMESTAMP,
|
||
|
phone: null,
|
||
|
},
|
||
|
]
|
||
|
);
|
||
|
tester(
|
||
|
'pg-redshift',
|
||
|
'delete from "accounts" where "id" = ?',
|
||
|
[2],
|
||
|
1
|
||
|
);
|
||
|
tester('sqlite3', 'delete from `accounts` where `id` = ?', [2], 1);
|
||
|
tester('oracledb', 'delete from "accounts" where "id" = ?', [2], 1);
|
||
|
tester(
|
||
|
'mssql',
|
||
|
'select top(0) [t].* into #out from [accounts] as t left join [accounts] on 0=1;delete from [accounts] output deleted.* into #out where [id] = ?; select * from #out; drop table #out;',
|
||
|
[2],
|
||
|
[
|
||
|
{
|
||
|
id: '2',
|
||
|
first_name: 'Test',
|
||
|
last_name: 'User',
|
||
|
email: 'test2@example.com',
|
||
|
logins: 1,
|
||
|
balance: 0,
|
||
|
about: 'Lorem ipsum Dolore labore incididunt enim.',
|
||
|
created_at: TEST_TIMESTAMP,
|
||
|
updated_at: TEST_TIMESTAMP,
|
||
|
phone: null,
|
||
|
},
|
||
|
]
|
||
|
);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
};
|