2020-12-28 16:55:08 +02:00
'use strict' ;
const { expect } = require ( 'chai' ) ;
const { TEST _TIMESTAMP } = require ( '../../util/constants' ) ;
2021-03-08 07:16:07 -05:00
const { isMssql } = require ( '../../util/db-helpers' ) ;
2021-10-02 23:45:17 +03:00
const {
dropTables ,
createAccounts ,
createTestTableTwo ,
} = require ( '../../util/tableCreatorHelper' ) ;
const {
insertAccounts ,
insertTestTableTwoData ,
} = require ( '../../util/dataInsertHelper' ) ;
2020-12-28 16:55:08 +02:00
module . exports = function ( knex ) {
describe ( 'Deletes with Triggers' , function ( ) {
// Trigger options
const triggerOptions = { includeTriggerModifications : true } ;
before ( function ( ) {
2021-03-08 07:16:07 -05:00
if ( ! isMssql ( knex ) ) {
2020-12-28 16:55:08 +02:00
this . skip ( 'This test is MSSQL only' ) ;
}
} ) ;
2021-10-02 23:45:17 +03:00
before ( async ( ) => {
await dropTables ( knex ) ;
await createAccounts ( knex ) ;
await createTestTableTwo ( knex ) ;
await insertAccounts ( knex ) ;
await insertTestTableTwoData ( knex ) ;
} ) ;
2020-12-28 16:55:08 +02:00
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 ( ) {
2021-03-08 07:16:07 -05:00
if ( ! isMssql ( knex ) ) {
2020-12-28 16:55:08 +02:00
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 ( ) {
2021-03-08 07:16:07 -05:00
if ( ! isMssql ( knex ) ) {
2020-12-28 16:55:08 +02:00
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 ( ) {
2021-03-08 07:16:07 -05:00
if ( ! isMssql ( knex ) ) {
2020-12-28 16:55:08 +02:00
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 ,
} ,
]
) ;
} ) ;
} ) ;
} ) ;
2021-07-13 09:41:16 +03:00
it ( 'should handle delete with join and trigger options' , function ( ) {
return knex ( 'test_table_two' )
. join ( 'accounts' , 'accounts.id' , 'test_table_two.account_id' )
. where ( { 'accounts.email' : 'test3@example.com' } )
. del ( '*' , triggerOptions )
. testSql ( function ( tester ) {
tester (
'mssql' ,
'select top(0) [t].* into #out from [test_table_two] as t left join [test_table_two] on 0=1;delete [test_table_two] output deleted.* into #out from [test_table_two] inner join [accounts] on [accounts].[id] = [test_table_two].[account_id] where [accounts].[email] = ?; select * from #out; drop table #out;' ,
[ 'test3@example.com' ] ,
2021-10-02 23:45:17 +03:00
[ { id : 3 , account _id : 3 , details : '' , status : 1 } ]
2021-07-13 09:41:16 +03:00
) ;
} ) ;
} ) ;
2020-12-28 16:55:08 +02:00
} ) ;
} ;