2014-09-01 17:18:45 +02:00
/*global describe, expect, it*/
2016-09-13 18:12:23 -04:00
/*eslint no-var:0, max-len:0 */
2014-09-01 17:18:45 +02:00
'use strict' ;
2018-07-09 08:10:34 -04:00
var Knex = require ( '../../../knex' ) ;
2016-05-26 16:56:15 -07:00
var _ = require ( 'lodash' ) ;
2016-11-29 10:13:30 +02:00
var Promise = require ( 'bluebird' ) ;
2013-09-12 01:00:44 -04:00
2016-05-26 16:56:15 -07:00
module . exports = function ( knex ) {
2018-07-09 08:10:34 -04:00
describe ( 'Additional' , function ( ) {
describe ( 'Custom response processing' , ( ) => {
2017-10-12 18:16:15 +03:00
before ( 'setup custom response handler' , ( ) => {
2018-02-01 23:41:01 +01:00
knex . client . config . postProcessResponse = ( response , queryContext ) => {
2018-07-09 08:10:34 -04:00
response . callCount = response . callCount ? response . callCount + 1 : 1 ;
2018-02-01 23:41:01 +01:00
response . queryContext = queryContext ;
2017-10-12 18:16:15 +03:00
return response ;
} ;
} ) ;
after ( 'restore client configuration' , ( ) => {
knex . client . config . postProcessResponse = null ;
} ) ;
it ( 'should process normal response' , ( ) => {
2018-07-09 08:10:34 -04:00
return knex ( 'accounts' )
. limit ( 1 )
. then ( ( res ) => {
expect ( res . callCount ) . to . equal ( 1 ) ;
} ) ;
2017-10-12 18:16:15 +03:00
} ) ;
2018-02-01 23:41:01 +01:00
it ( 'should pass query context to the custom handler' , ( ) => {
return knex ( 'accounts' )
. queryContext ( 'the context' )
. limit ( 1 )
2018-07-09 08:10:34 -04:00
. then ( ( res ) => {
2018-02-01 23:41:01 +01:00
expect ( res . queryContext ) . to . equal ( 'the context' ) ;
} ) ;
} ) ;
2017-10-12 18:16:15 +03:00
it ( 'should process raw response' , ( ) => {
2018-07-09 08:10:34 -04:00
return knex . raw ( 'select * from ??' , [ 'accounts' ] ) . then ( ( res ) => {
2018-02-01 23:41:01 +01:00
expect ( res . callCount ) . to . equal ( 1 ) ;
2017-10-12 18:16:15 +03:00
} ) ;
} ) ;
2018-02-01 23:41:01 +01:00
it ( 'should pass query context for raw responses' , ( ) => {
2018-07-09 08:10:34 -04:00
return knex
. raw ( 'select * from ??' , [ 'accounts' ] )
2018-02-01 23:41:01 +01:00
. queryContext ( 'the context' )
2018-07-09 08:10:34 -04:00
. then ( ( res ) => {
2018-02-01 23:41:01 +01:00
expect ( res . queryContext ) . to . equal ( 'the context' ) ;
} ) ;
} ) ;
2017-10-12 18:16:15 +03:00
it ( 'should process response done in transaction' , ( ) => {
2018-07-09 08:10:34 -04:00
return knex
. transaction ( ( trx ) => {
return trx ( 'accounts' )
. limit ( 1 )
. then ( ( res ) => {
expect ( res . callCount ) . to . equal ( 1 ) ;
return res ;
} ) ;
} )
. then ( ( res ) => {
2017-10-12 18:16:15 +03:00
expect ( res . callCount ) . to . equal ( 1 ) ;
} ) ;
} ) ;
2018-02-01 23:41:01 +01:00
it ( 'should pass query context for responses from transactions' , ( ) => {
2018-07-09 08:10:34 -04:00
return knex
. transaction ( ( trx ) => {
return trx ( 'accounts' )
. queryContext ( 'the context' )
. limit ( 1 )
. then ( ( res ) => {
expect ( res . queryContext ) . to . equal ( 'the context' ) ;
return res ;
} ) ;
} )
. then ( ( res ) => {
expect ( res . queryContext ) . to . equal ( 'the context' ) ;
} ) ;
2018-02-01 23:41:01 +01:00
} ) ;
2017-10-12 18:16:15 +03:00
} ) ;
2018-01-03 00:05:48 +02:00
describe ( 'columnInfo with wrapIdentifier and postProcessResponse' , ( ) => {
before ( 'setup hooks' , ( ) => {
knex . client . config . postProcessResponse = ( response ) => {
return _ . mapKeys ( response , ( val , key ) => {
return _ . camelCase ( key ) ;
} ) ;
} ;
knex . client . config . wrapIdentifier = ( id , origImpl ) => {
return origImpl ( _ . snakeCase ( id ) ) ;
} ;
} ) ;
after ( 'restore client configuration' , ( ) => {
knex . client . config . postProcessResponse = null ;
knex . client . config . wrapIdentifier = null ;
} ) ;
it ( 'should work using camelCased table name' , ( ) => {
2018-07-09 08:10:34 -04:00
return knex ( 'testTableTwo' )
. columnInfo ( )
. then ( ( res ) => {
expect ( Object . keys ( res ) ) . to . have . all . members ( [
'id' ,
'accountId' ,
'details' ,
'status' ,
'jsonData' ,
] ) ;
} ) ;
2018-01-03 00:05:48 +02:00
} ) ;
it ( 'should work using snake_cased table name' , ( ) => {
2018-07-09 08:10:34 -04:00
return knex ( 'test_table_two' )
. columnInfo ( )
. then ( ( res ) => {
expect ( Object . keys ( res ) ) . to . have . all . members ( [
'id' ,
'accountId' ,
'details' ,
'status' ,
'jsonData' ,
] ) ;
} ) ;
2018-01-03 00:05:48 +02:00
} ) ;
} ) ;
2018-06-05 15:31:09 +03:00
// TODO: This doesn't work on oracle yet.
2018-07-08 14:10:51 +03:00
if ( [ 'pg' , 'mssql' ] . includes ( knex . client . driverName ) ) {
2018-06-05 15:31:09 +03:00
describe ( 'returning with wrapIdentifier and postProcessResponse`' , ( ) => {
let origHooks = { } ;
before ( 'setup custom hooks' , ( ) => {
2018-07-09 08:10:34 -04:00
origHooks . postProcessResponse =
knex . client . config . postProcessResponse ;
2018-06-05 15:31:09 +03:00
origHooks . wrapIdentifier = knex . client . config . wrapIdentifier ;
// Add `_foo` to each identifier.
knex . client . config . postProcessResponse = ( res ) => {
if ( Array . isArray ( res ) ) {
2018-07-09 08:10:34 -04:00
return res . map ( ( it ) => {
2018-06-05 15:31:09 +03:00
if ( typeof it === 'object' ) {
return _ . mapKeys ( it , ( value , key ) => {
return key + '_foo' ;
} ) ;
} else {
return it ;
}
2018-07-09 08:10:34 -04:00
} ) ;
2018-06-05 15:31:09 +03:00
} else {
return res ;
}
} ;
// Remove `_foo` from the end of each identifier.
knex . client . config . wrapIdentifier = ( id ) => {
return id . substring ( 0 , id . length - 4 ) ;
} ;
} ) ;
after ( 'restore hooks' , ( ) => {
2018-07-09 08:10:34 -04:00
knex . client . config . postProcessResponse =
origHooks . postProcessResponse ;
2018-06-05 15:31:09 +03:00
knex . client . config . wrapIdentifier = origHooks . wrapIdentifier ;
} ) ;
it ( 'should return the correct column when a single property is given to returning' , ( ) => {
return knex ( 'accounts_foo' )
. insert ( { balance _foo : 123 } )
2018-07-09 08:10:34 -04:00
. returning ( 'balance_foo' )
. then ( ( res ) => {
2018-06-05 15:31:09 +03:00
expect ( res ) . to . eql ( [ 123 ] ) ;
} ) ;
} ) ;
it ( 'should return the correct columns when multiple properties are given to returning' , ( ) => {
return knex ( 'accounts_foo' )
. insert ( { balance _foo : 123 , email _foo : 'foo@bar.com' } )
2018-07-09 08:10:34 -04:00
. returning ( [ 'balance_foo' , 'email_foo' ] )
. then ( ( res ) => {
expect ( res ) . to . eql ( [
{ balance _foo : 123 , email _foo : 'foo@bar.com' } ,
] ) ;
2018-06-05 15:31:09 +03:00
} ) ;
} ) ;
} ) ;
}
2017-02-03 18:54:15 -06:00
it ( 'should forward the .get() function from bluebird' , function ( ) {
2018-07-09 08:10:34 -04:00
return knex ( 'accounts' )
. select ( )
. limit ( 1 )
. then ( function ( accounts ) {
var firstAccount = accounts [ 0 ] ;
return knex ( 'accounts' )
. select ( )
. limit ( 1 )
. get ( 0 )
. then ( function ( account ) {
expect ( account . id == firstAccount . id ) ;
} ) ;
2017-02-03 18:54:15 -06:00
} ) ;
} ) ;
it ( 'should forward the .mapSeries() function from bluebird' , function ( ) {
2018-07-09 08:10:34 -04:00
var asyncTask = function ( ) {
return new Promise ( function ( resolve , reject ) {
2017-02-03 18:54:15 -06:00
var output = asyncTask . num ++ ;
2018-07-09 08:10:34 -04:00
setTimeout ( function ( ) {
2017-02-03 18:54:15 -06:00
resolve ( output ) ;
2018-07-09 08:10:34 -04:00
} , Math . random ( ) * 200 ) ;
2017-02-03 18:54:15 -06:00
} ) ;
} ;
asyncTask . num = 1 ;
var returnedValues = [ ] ;
2018-07-09 08:10:34 -04:00
return knex ( 'accounts' )
. select ( )
. limit ( 3 )
. mapSeries ( function ( account ) {
return asyncTask ( ) . then ( function ( number ) {
returnedValues . push ( number ) ;
} ) ;
} )
. then ( function ( ) {
expect ( returnedValues [ 0 ] == 1 ) ;
expect ( returnedValues [ 1 ] == 2 ) ;
expect ( returnedValues [ 2 ] == 3 ) ;
2017-02-03 18:54:15 -06:00
} ) ;
} ) ;
it ( 'should forward the .delay() function from bluebird' , function ( ) {
2018-07-09 08:10:34 -04:00
var startTime = new Date ( ) . valueOf ( ) ;
return knex ( 'accounts' )
. select ( )
. limit ( 1 )
. delay ( 300 )
. then ( function ( accounts ) {
expect ( new Date ( ) . valueOf ( ) - startTime > 300 ) ;
} ) ;
2017-02-03 18:54:15 -06:00
} ) ;
2013-09-12 01:00:44 -04:00
it ( 'should truncate a table with truncate' , function ( ) {
return knex ( 'test_table_two' )
. truncate ( )
2013-12-27 14:44:21 -05:00
. testSql ( function ( tester ) {
tester ( 'mysql' , 'truncate `test_table_two`' ) ;
2018-06-29 10:47:06 +03:00
tester ( 'pg' , 'truncate "test_table_two" restart identity' ) ;
2018-02-03 08:33:02 -05:00
tester ( 'pg-redshift' , 'truncate "test_table_two"' ) ;
2018-07-09 08:10:34 -04:00
tester ( 'sqlite3' , 'delete from `test_table_two`' ) ;
tester ( 'oracledb' , 'truncate table "test_table_two"' ) ;
2015-12-09 17:53:53 -06:00
tester ( 'mssql' , 'truncate table [test_table_two]' ) ;
2013-12-27 14:44:21 -05:00
} )
2017-11-24 08:00:20 +01:00
. then ( ( ) => {
2013-09-12 01:00:44 -04:00
return knex ( 'test_table_two' )
. select ( '*' )
2018-07-09 08:10:34 -04:00
. then ( ( resp ) => {
2013-09-12 01:00:44 -04:00
expect ( resp ) . to . have . length ( 0 ) ;
} ) ;
2017-11-24 08:00:20 +01:00
} )
. then ( ( ) => {
// Insert new data after truncate and make sure ids restart at 1.
// This doesn't currently work on oracle, where the created sequence
// needs to be manually reset.
2018-04-04 18:43:39 -04:00
// On redshift, one would need to create an entirely new table and do
// `insert into ... (select ...); alter table rename...`
2018-07-09 08:10:34 -04:00
if (
/oracle/i . test ( knex . client . driverName ) ||
/redshift/i . test ( knex . client . driverName )
) {
return ;
}
return knex ( 'test_table_two' )
. insert ( { status : 1 } )
. then ( ( res ) => {
2018-04-04 18:43:39 -04:00
return knex ( 'test_table_two' )
. select ( 'id' )
. first ( )
2018-07-09 08:10:34 -04:00
. then ( ( res ) => {
expect ( res ) . to . be . an ( 'object' ) ;
2018-04-04 18:43:39 -04:00
expect ( res . id ) . to . equal ( 1 ) ;
} ) ;
} ) ;
2013-09-12 01:00:44 -04:00
} ) ;
} ) ;
it ( 'should allow raw queries directly with `knex.raw`' , function ( ) {
var tables = {
mysql : 'SHOW TABLES' ,
2014-06-09 16:27:03 -04:00
mysql2 : 'SHOW TABLES' ,
2018-07-09 08:10:34 -04:00
pg :
"SELECT table_name FROM information_schema.tables WHERE table_schema='public'" ,
'pg-redshift' :
"SELECT table_name FROM information_schema.tables WHERE table_schema='public'" ,
2014-08-11 12:25:39 +02:00
sqlite3 : "SELECT name FROM sqlite_master WHERE type='table';" ,
2018-07-09 08:10:34 -04:00
oracledb : 'select TABLE_NAME from USER_TABLES' ,
mssql :
"SELECT table_name FROM information_schema.tables WHERE table_schema='dbo'" ,
2013-09-12 01:00:44 -04:00
} ;
2018-07-08 14:10:51 +03:00
return knex . raw ( tables [ knex . client . driverName ] ) . testSql ( function ( tester ) {
tester ( knex . client . driverName , tables [ knex . client . driverName ] ) ;
2013-12-27 14:44:21 -05:00
} ) ;
2013-09-12 01:00:44 -04:00
} ) ;
it ( 'should allow using the primary table as a raw statement' , function ( ) {
2018-07-09 08:10:34 -04:00
expect ( knex ( knex . raw ( 'raw_table_name' ) ) . toQuery ( ) ) . to . equal (
'select * from raw_table_name'
) ;
2014-04-21 23:08:59 -04:00
} ) ;
2013-09-12 01:00:44 -04:00
2014-07-03 11:59:29 +02:00
it ( 'should allow using .fn-methods to create raw statements' , function ( ) {
expect ( knex . fn . now ( ) . prototype === knex . raw ( ) . prototype ) ;
expect ( knex . fn . now ( ) . toQuery ( ) ) . to . equal ( 'CURRENT_TIMESTAMP' ) ;
2018-07-19 10:46:23 -04:00
expect ( knex . fn . now ( 6 ) . toQuery ( ) ) . to . equal ( 'CURRENT_TIMESTAMP(6)' ) ;
2014-07-03 11:59:29 +02:00
} ) ;
2014-04-21 23:08:59 -04:00
it ( 'gets the columnInfo' , function ( ) {
2018-07-09 08:10:34 -04:00
return knex ( 'datatype_test' )
. columnInfo ( )
. testSql ( function ( tester ) {
tester (
'mysql' ,
'select * from information_schema.columns where table_name = ? and table_schema = ?' ,
null ,
{
enum _value : {
defaultValue : null ,
maxLength : 1 ,
nullable : true ,
type : 'enum' ,
} ,
uuid : {
defaultValue : null ,
maxLength : 36 ,
nullable : false ,
type : 'char' ,
} ,
2014-04-21 23:08:59 -04:00
}
2018-07-09 08:10:34 -04:00
) ;
tester (
'pg' ,
'select * from information_schema.columns where table_name = ? and table_catalog = ? and table_schema = current_schema()' ,
null ,
{
enum _value : {
defaultValue : null ,
maxLength : null ,
nullable : true ,
type : 'text' ,
} ,
uuid : {
defaultValue : null ,
maxLength : null ,
nullable : false ,
type : 'uuid' ,
} ,
}
) ;
tester (
'pg-redshift' ,
'select * from information_schema.columns where table_name = ? and table_catalog = ? and table_schema = current_schema()' ,
null ,
{
enum _value : {
defaultValue : null ,
maxLength : 255 ,
nullable : true ,
type : 'character varying' ,
} ,
uuid : {
defaultValue : null ,
maxLength : 36 ,
nullable : false ,
type : 'character' ,
} ,
}
) ;
tester ( 'sqlite3' , 'PRAGMA table_info(`datatype_test`)' , [ ] , {
enum _value : {
2018-07-08 14:10:51 +03:00
defaultValue : null ,
2018-07-09 08:10:34 -04:00
maxLength : null ,
2014-08-11 12:25:39 +02:00
nullable : true ,
2018-07-09 08:10:34 -04:00
type : 'text' ,
2014-08-11 12:25:39 +02:00
} ,
2018-07-09 08:10:34 -04:00
uuid : {
2018-07-08 14:10:51 +03:00
defaultValue : null ,
2018-07-09 08:10:34 -04:00
maxLength : '36' ,
2014-08-11 12:25:39 +02:00
nullable : false ,
2018-07-09 08:10:34 -04:00
type : 'char' ,
2015-12-09 17:53:53 -06:00
} ,
} ) ;
2018-07-09 08:10:34 -04:00
tester (
'oracledb' ,
"select * from xmltable( '/ROWSET/ROW'\n passing dbms_xmlgen.getXMLType('\n select char_col_decl_length, column_name, data_type, data_default, nullable\n from user_tab_columns where table_name = ''datatype_test'' ')\n columns\n CHAR_COL_DECL_LENGTH number, COLUMN_NAME varchar2(200), DATA_TYPE varchar2(106),\n DATA_DEFAULT clob, NULLABLE varchar2(1))" ,
[ ] ,
{
enum _value : {
defaultValue : null ,
nullable : true ,
maxLength : 1 ,
type : 'VARCHAR2' ,
} ,
uuid : {
defaultValue : null ,
nullable : false ,
maxLength : 36 ,
type : 'CHAR' ,
} ,
}
) ;
tester (
'mssql' ,
"select * from information_schema.columns where table_name = ? and table_catalog = ? and table_schema = 'dbo'" ,
[ 'datatype_test' , 'knex_test' ] ,
{
enum _value : {
defaultValue : null ,
maxLength : 100 ,
nullable : true ,
type : 'nvarchar' ,
} ,
uuid : {
defaultValue : null ,
maxLength : null ,
nullable : false ,
type : 'uniqueidentifier' ,
} ,
}
) ;
} ) ;
2013-09-12 01:00:44 -04:00
} ) ;
2018-06-29 10:47:06 +03:00
it ( 'gets the columnInfo with columntype' , function ( ) {
2018-07-09 08:10:34 -04:00
return knex ( 'datatype_test' )
. columnInfo ( 'uuid' )
. testSql ( function ( tester ) {
tester (
'mysql' ,
'select * from information_schema.columns where table_name = ? and table_schema = ?' ,
null ,
{
defaultValue : null ,
maxLength : 36 ,
nullable : false ,
type : 'char' ,
}
) ;
tester (
'pg' ,
'select * from information_schema.columns where table_name = ? and table_catalog = ? and table_schema = current_schema()' ,
null ,
{
defaultValue : null ,
maxLength : null ,
nullable : false ,
type : 'uuid' ,
}
) ;
tester (
'pg-redshift' ,
'select * from information_schema.columns where table_name = ? and table_catalog = ? and table_schema = current_schema()' ,
null ,
{
defaultValue : null ,
maxLength : 36 ,
nullable : false ,
type : 'character' ,
}
) ;
tester ( 'sqlite3' , 'PRAGMA table_info(`datatype_test`)' , [ ] , {
2018-07-08 14:10:51 +03:00
defaultValue : null ,
2018-07-09 08:10:34 -04:00
maxLength : '36' ,
2018-07-08 14:10:51 +03:00
nullable : false ,
2018-07-09 08:10:34 -04:00
type : 'char' ,
2015-12-09 17:53:53 -06:00
} ) ;
2018-07-09 08:10:34 -04:00
tester (
'oracledb' ,
"select * from xmltable( '/ROWSET/ROW'\n passing dbms_xmlgen.getXMLType('\n select char_col_decl_length, column_name, data_type, data_default, nullable\n from user_tab_columns where table_name = ''datatype_test'' ')\n columns\n CHAR_COL_DECL_LENGTH number, COLUMN_NAME varchar2(200), DATA_TYPE varchar2(106),\n DATA_DEFAULT clob, NULLABLE varchar2(1))" ,
[ ] ,
{
defaultValue : null ,
maxLength : 36 ,
nullable : false ,
type : 'CHAR' ,
}
) ;
tester (
'mssql' ,
"select * from information_schema.columns where table_name = ? and table_catalog = ? and table_schema = 'dbo'" ,
null ,
{
defaultValue : null ,
maxLength : null ,
nullable : false ,
type : 'uniqueidentifier' ,
}
) ;
} ) ;
2014-08-11 12:25:39 +02:00
} ) ;
2014-06-03 14:21:31 -04:00
2017-10-23 09:13:09 +03:00
it ( '#2184 - should properly escape table name for SQLite columnInfo' , function ( ) {
2018-07-08 14:10:51 +03:00
if ( knex . client . driverName !== 'sqlite3' ) {
2017-10-23 09:13:09 +03:00
return ;
}
2018-07-09 08:10:34 -04:00
return knex . schema
. dropTableIfExists ( 'group' )
2017-10-23 09:13:09 +03:00
. then ( function ( ) {
return knex . schema . createTable ( 'group' , function ( table ) {
table . integer ( 'foo' ) ;
} ) ;
} )
. then ( function ( ) {
return knex ( 'group' ) . columnInfo ( ) ;
} )
. then ( function ( columnInfo ) {
expect ( columnInfo ) . to . deep . equal ( {
foo : {
type : 'integer' ,
maxLength : null ,
nullable : true ,
defaultValue : null ,
} ,
} ) ;
} ) ;
} ) ;
2014-04-16 01:23:50 -04:00
it ( 'should allow renaming a column' , function ( ) {
2018-07-09 08:10:34 -04:00
var countColumn ;
2018-07-08 14:10:51 +03:00
switch ( knex . client . driverName ) {
2018-07-09 08:10:34 -04:00
case 'oracledb' :
countColumn = 'COUNT(*)' ;
break ;
case 'mssql' :
countColumn = '' ;
break ;
default :
countColumn = 'count(*)' ;
break ;
2015-12-09 17:53:53 -06:00
}
2018-07-09 08:10:34 -04:00
var count ,
inserts = [ ] ;
2015-12-09 17:53:53 -06:00
_ . times ( 40 , function ( i ) {
2018-07-09 08:10:34 -04:00
inserts . push ( {
email : 'email' + i ,
first _name : 'Test' ,
last _name : 'Data' ,
2013-09-12 01:00:44 -04:00
} ) ;
} ) ;
2018-07-09 08:10:34 -04:00
return knex ( 'accounts' )
. insert ( inserts )
. then ( function ( ) {
return knex . count ( '*' ) . from ( 'accounts' ) ;
} )
. then ( function ( resp ) {
count = resp [ 0 ] [ countColumn ] ;
return knex . schema
. table ( 'accounts' , function ( t ) {
t . renameColumn ( 'about' , 'about_col' ) ;
} )
. testSql ( function ( tester ) {
tester ( 'mysql' , [ 'show fields from `accounts` where field = ?' ] ) ;
tester ( 'pg' , [
'alter table "accounts" rename "about" to "about_col"' ,
] ) ;
tester ( 'pg-redshift' , [
'alter table "accounts" rename "about" to "about_col"' ,
] ) ;
tester ( 'sqlite3' , [ 'PRAGMA table_info(`accounts`)' ] ) ;
tester ( 'oracledb' , [
'DECLARE PK_NAME VARCHAR(200); IS_AUTOINC NUMBER := 0; BEGIN EXECUTE IMMEDIATE (\'ALTER TABLE "accounts" RENAME COLUMN "about" TO "about_col"\'); SELECT COUNT(*) INTO IS_AUTOINC from "USER_TRIGGERS" where trigger_name = \'accounts_autoinc_trg\'; IF (IS_AUTOINC > 0) THEN SELECT cols.column_name INTO PK_NAME FROM all_constraints cons, all_cons_columns cols WHERE cons.constraint_type = \'P\' AND cons.constraint_name = cols.constraint_name AND cons.owner = cols.owner AND cols.table_name = \'accounts\'; IF (\'about_col\' = PK_NAME) THEN EXECUTE IMMEDIATE (\'DROP TRIGGER "accounts_autoinc_trg"\'); EXECUTE IMMEDIATE (\'create or replace trigger "accounts_autoinc_trg" BEFORE INSERT on "accounts" for each row declare checking number := 1; begin if (:new."about_col" is null) then while checking >= 1 loop select "accounts_seq".nextval into :new."about_col" from dual; select count("about_col") into checking from "accounts" where "about_col" = :new."about_col"; end loop; end if; end;\'); end if; end if;END;' ,
] ) ;
tester ( 'mssql' , [ "exec sp_rename ?, ?, 'COLUMN'" ] ) ;
} ) ;
} )
. then ( function ( ) {
return knex . count ( '*' ) . from ( 'accounts' ) ;
} )
. then ( function ( resp ) {
expect ( resp [ 0 ] [ countColumn ] ) . to . equal ( count ) ;
} )
. then ( function ( ) {
return knex ( 'accounts' ) . select ( 'about_col' ) ;
} )
. then ( function ( ) {
return knex . schema . table ( 'accounts' , function ( t ) {
t . renameColumn ( 'about_col' , 'about' ) ;
} ) ;
} )
. then ( function ( ) {
return knex . count ( '*' ) . from ( 'accounts' ) ;
} )
. then ( function ( resp ) {
expect ( resp [ 0 ] [ countColumn ] ) . to . equal ( count ) ;
} ) ;
2013-09-12 01:00:44 -04:00
} ) ;
2014-06-09 15:28:22 -04:00
it ( 'should allow dropping a column' , function ( ) {
2016-10-14 17:00:39 +02:00
var countColumn ;
2018-07-08 14:10:51 +03:00
switch ( knex . client . driverName ) {
2018-07-09 08:10:34 -04:00
case 'oracledb' :
countColumn = 'COUNT(*)' ;
break ;
case 'mssql' :
countColumn = '' ;
break ;
default :
countColumn = 'count(*)' ;
break ;
2014-08-11 12:25:39 +02:00
}
2015-12-09 17:53:53 -06:00
var count ;
2018-07-09 08:10:34 -04:00
return knex
. count ( '*' )
. from ( 'accounts' )
. then ( function ( resp ) {
count = resp [ 0 ] [ countColumn ] ;
} )
. then ( function ( ) {
return knex . schema
. table ( 'accounts' , function ( t ) {
t . dropColumn ( 'first_name' ) ;
} )
. testSql ( function ( tester ) {
tester ( 'mysql' , [ 'alter table `accounts` drop `first_name`' ] ) ;
tester ( 'pg' , [ 'alter table "accounts" drop column "first_name"' ] ) ;
tester ( 'pg-redshift' , [
'alter table "accounts" drop column "first_name"' ,
] ) ;
tester ( 'sqlite3' , [ 'PRAGMA table_info(`accounts`)' ] ) ;
tester ( 'oracledb' , [
'alter table "accounts" drop ("first_name")' ,
] ) ;
//tester('oracledb', ['alter table "accounts" drop ("first_name")']);
tester ( 'mssql' , [
'ALTER TABLE [accounts] DROP COLUMN [first_name]' ,
] ) ;
} ) ;
} )
. then ( function ( ) {
return knex
. select ( '*' )
. from ( 'accounts' )
. first ( ) ;
} )
. then ( function ( resp ) {
expect ( _ . keys ( resp ) . sort ( ) ) . to . eql ( [
'about' ,
'balance' ,
'created_at' ,
'email' ,
'id' ,
'last_name' ,
'logins' ,
'phone' ,
'updated_at' ,
] ) ;
} )
. then ( function ( ) {
return knex . count ( '*' ) . from ( 'accounts' ) ;
} )
. then ( function ( resp ) {
expect ( resp [ 0 ] [ countColumn ] ) . to . equal ( count ) ;
2014-06-09 15:28:22 -04:00
} ) ;
} ) ;
2016-05-26 11:06:33 -07:00
it ( '.timeout() should throw TimeoutError' , function ( ) {
2018-07-08 14:10:51 +03:00
var driverName = knex . client . driverName ;
2018-07-09 08:10:34 -04:00
if ( driverName === 'sqlite3' ) {
return ;
} //TODO -- No built-in support for sleeps
if ( /redshift/ . test ( driverName ) ) {
return ;
}
2016-03-08 13:07:50 +01:00
var testQueries = {
2018-07-08 14:10:51 +03:00
pg : function ( ) {
2016-03-08 13:07:50 +01:00
return knex . raw ( 'SELECT pg_sleep(1)' ) ;
} ,
2018-07-08 14:10:51 +03:00
mysql : function ( ) {
2016-03-08 13:07:50 +01:00
return knex . raw ( 'SELECT SLEEP(1)' ) ;
} ,
2018-07-08 14:10:51 +03:00
mysql2 : function ( ) {
2016-03-08 13:07:50 +01:00
return knex . raw ( 'SELECT SLEEP(1)' ) ;
} ,
mssql : function ( ) {
2018-07-09 08:10:34 -04:00
return knex . raw ( "WAITFOR DELAY '00:00:01'" ) ;
2016-03-08 13:07:50 +01:00
} ,
2018-07-08 14:10:51 +03:00
oracledb : function ( ) {
2016-10-14 17:00:39 +02:00
return knex . raw ( 'begin dbms_lock.sleep(1); end;' ) ;
2018-07-09 08:10:34 -04:00
} ,
2016-03-08 13:07:50 +01:00
} ;
2016-02-15 17:06:08 +01:00
2018-07-09 08:10:34 -04:00
if ( ! testQueries . hasOwnProperty ( driverName ) ) {
2018-07-08 14:10:51 +03:00
throw new Error ( 'Missing test query for driver: ' + driverName ) ;
2016-03-08 13:07:50 +01:00
}
2018-07-08 14:10:51 +03:00
var query = testQueries [ driverName ] ( ) ;
2016-03-08 13:07:50 +01:00
2018-07-09 08:10:34 -04:00
return query
. timeout ( 200 )
2016-02-15 17:06:08 +01:00
. then ( function ( ) {
expect ( true ) . to . equal ( false ) ;
} )
. catch ( function ( error ) {
expect ( _ . pick ( error , 'timeout' , 'name' , 'message' ) ) . to . deep . equal ( {
2016-10-14 17:00:39 +02:00
timeout : 200 ,
2018-07-09 08:10:34 -04:00
name : 'TimeoutError' ,
message :
'Defined query timeout of 200ms exceeded when running query.' ,
2016-02-15 17:06:08 +01:00
} ) ;
2018-07-09 08:10:34 -04:00
} ) ;
2016-05-26 11:06:33 -07:00
} ) ;
it ( '.timeout(ms, {cancel: true}) should throw TimeoutError and cancel slow query' , function ( ) {
2018-07-08 14:10:51 +03:00
var driverName = knex . client . driverName ;
2018-07-09 08:10:34 -04:00
if ( driverName === 'sqlite3' ) {
return ;
} //TODO -- No built-in support for sleeps
if ( /redshift/ . test ( driverName ) ) {
return ;
}
2016-05-26 11:06:33 -07:00
// There's unexpected behavior caused by knex releasing a connection back
// to the pool because of a timeout when a long query is still running.
// A subsequent query will acquire the connection (still in-use) and hang
// until the first query finishes. Setting a sleep time longer than the
// mocha timeout exposes this behavior.
var testQueries = {
2018-07-08 14:10:51 +03:00
pg : function ( ) {
2016-05-26 11:06:33 -07:00
return knex . raw ( 'SELECT pg_sleep(10)' ) ;
} ,
2018-07-08 14:10:51 +03:00
mysql : function ( ) {
2016-05-26 11:06:33 -07:00
return knex . raw ( 'SELECT SLEEP(10)' ) ;
} ,
2018-07-08 14:10:51 +03:00
mysql2 : function ( ) {
2016-05-26 11:06:33 -07:00
return knex . raw ( 'SELECT SLEEP(10)' ) ;
} ,
mssql : function ( ) {
2018-07-09 08:10:34 -04:00
return knex . raw ( "WAITFOR DELAY '00:00:10'" ) ;
2016-05-26 11:06:33 -07:00
} ,
2018-07-08 14:10:51 +03:00
oracledb : function ( ) {
2016-10-14 17:00:39 +02:00
return knex . raw ( 'begin dbms_lock.sleep(10); end;' ) ;
2018-07-09 08:10:34 -04:00
} ,
2016-05-26 11:06:33 -07:00
} ;
2018-07-09 08:10:34 -04:00
if ( ! testQueries . hasOwnProperty ( driverName ) ) {
2018-07-08 14:10:51 +03:00
throw new Error ( 'Missing test query for driverName: ' + driverName ) ;
2016-05-26 11:06:33 -07:00
}
2018-07-08 14:10:51 +03:00
var query = testQueries [ driverName ] ( ) ;
2016-05-26 11:06:33 -07:00
2016-05-26 16:56:15 -07:00
function addTimeout ( ) {
2018-07-09 08:10:34 -04:00
return query . timeout ( 200 , { cancel : true } ) ;
2016-05-26 16:56:15 -07:00
}
2016-05-26 11:06:33 -07:00
2018-07-01 23:06:26 +03:00
// Only mysql query cancelling supported for now
2018-07-09 08:10:34 -04:00
if ( ! _ . startsWith ( driverName , 'mysql' ) ) {
expect ( addTimeout ) . to . throw (
'Query cancelling not supported for this dialect'
) ;
2016-05-26 11:06:33 -07:00
return ;
}
return addTimeout ( )
. then ( function ( ) {
expect ( true ) . to . equal ( false ) ;
} )
. catch ( function ( error ) {
expect ( _ . pick ( error , 'timeout' , 'name' , 'message' ) ) . to . deep . equal ( {
2016-10-14 17:00:39 +02:00
timeout : 200 ,
2018-07-09 08:10:34 -04:00
name : 'TimeoutError' ,
message :
'Defined query timeout of 200ms exceeded when running query.' ,
2016-05-26 11:06:33 -07:00
} ) ;
// Ensure sleep command is removed.
// This query will hang if a connection gets released back to the pool
2017-10-12 18:16:15 +03:00
// too early.
2016-11-29 10:13:30 +02:00
// 50ms delay since killing query doesn't seem to have immediate effect to the process listing
2018-07-09 08:10:34 -04:00
return Promise . resolve ( )
. then ( )
. delay ( 50 )
. then ( function ( ) {
2016-11-29 10:13:30 +02:00
return knex . raw ( 'SHOW PROCESSLIST' ) ;
} )
2016-05-26 11:06:33 -07:00
. then ( function ( results ) {
var processes = results [ 0 ] ;
2018-07-09 08:10:34 -04:00
var sleepProcess = _ . find ( processes , {
Info : 'SELECT SLEEP(10)' ,
} ) ;
2016-05-26 11:06:33 -07:00
expect ( sleepProcess ) . to . equal ( undefined ) ;
} ) ;
2016-02-15 17:06:08 +01:00
} ) ;
} ) ;
2016-05-26 16:56:15 -07:00
it ( '.timeout(ms, {cancel: true}) should throw error if cancellation cannot acquire connection' , function ( ) {
2018-07-01 23:06:26 +03:00
// Only mysql query cancelling supported for now
2018-07-08 14:10:51 +03:00
var driverName = knex . client . config . driverName ;
2018-07-09 08:10:34 -04:00
if ( ! _ . startsWith ( driverName , 'mysql' ) ) {
2016-09-13 18:12:23 -04:00
return ;
}
2016-05-26 16:56:15 -07:00
//To make this test easier, I'm changing the pool settings to max 1.
var knexConfig = _ . clone ( knex . client . config ) ;
knexConfig . pool . min = 0 ;
knexConfig . pool . max = 1 ;
var knexDb = new Knex ( knexConfig ) ;
2018-07-09 08:10:34 -04:00
return knexDb
. raw ( 'SELECT SLEEP(1)' )
. timeout ( 1 , { cancel : true } )
. then (
function ( ) {
throw new Error ( "Shouldn't have gotten here." ) ;
} ,
function ( error ) {
expect ( _ . pick ( error , 'timeout' , 'name' , 'message' ) ) . to . deep . equal ( {
timeout : 1 ,
name : 'TimeoutError' ,
message :
'After query timeout of 1ms exceeded, cancelling of query failed.' ,
} ) ;
}
)
. finally ( ( ) => knexDb . destroy ( ) ) ;
2016-05-26 16:56:15 -07:00
} ) ;
2016-02-26 19:51:35 +01:00
it ( 'Event: query-response' , function ( ) {
var queryCount = 0 ;
2016-03-24 18:59:37 +01:00
var onQueryResponse = function ( response , obj , builder ) {
2016-02-26 19:51:35 +01:00
queryCount ++ ;
2016-02-26 20:32:34 +01:00
expect ( response ) . to . be . an ( 'array' ) ;
2016-02-26 20:01:18 +01:00
expect ( obj ) . to . be . an ( 'object' ) ;
expect ( obj . _ _knexUid ) . to . be . a ( 'string' ) ;
2016-06-17 09:53:54 -07:00
expect ( obj . _ _knexQueryUid ) . to . be . a ( 'string' ) ;
2016-02-26 20:01:18 +01:00
expect ( builder ) . to . be . an ( 'object' ) ;
2016-03-24 18:59:37 +01:00
} ;
knex . on ( 'query-response' , onQueryResponse ) ;
2016-02-26 19:51:35 +01:00
2018-07-09 08:10:34 -04:00
return knex ( 'accounts' )
. select ( )
2016-03-24 18:59:37 +01:00
. on ( 'query-response' , onQueryResponse )
. then ( function ( ) {
2016-02-26 19:51:35 +01:00
return knex . transaction ( function ( tr ) {
2018-07-09 08:10:34 -04:00
return tr ( 'accounts' )
. select ( )
. on ( 'query-response' , onQueryResponse ) ; //Transactions should emit the event as well
} ) ;
2016-02-26 19:51:35 +01:00
} )
2016-03-24 18:59:37 +01:00
. then ( function ( ) {
2017-10-12 18:16:15 +03:00
knex . removeListener ( 'query-response' , onQueryResponse ) ;
2016-03-24 18:59:37 +01:00
expect ( queryCount ) . to . equal ( 4 ) ;
2018-07-09 08:10:34 -04:00
} ) ;
2016-03-24 18:59:37 +01:00
} ) ;
it ( 'Event: query-error' , function ( ) {
var queryCount = 0 ;
var onQueryError = function ( error , obj ) {
queryCount ++ ;
expect ( obj ) . to . be . an ( 'object' ) ;
expect ( obj . _ _knexUid ) . to . be . a ( 'string' ) ;
2016-06-17 09:53:54 -07:00
expect ( obj . _ _knexQueryUid ) . to . be . a ( 'string' ) ;
2016-03-24 18:59:37 +01:00
expect ( error ) . to . be . an ( 'object' ) ;
} ;
knex . on ( 'query-error' , onQueryError ) ;
2018-07-09 08:10:34 -04:00
return knex
. raw ( 'Broken query' )
2016-03-24 18:59:37 +01:00
. on ( 'query-error' , onQueryError )
. then ( function ( ) {
expect ( true ) . to . equal ( false ) ; //Should not be resolved
} )
. catch ( function ( ) {
2017-10-12 18:16:15 +03:00
knex . removeListener ( 'query-error' , onQueryError ) ;
2016-02-26 19:51:35 +01:00
expect ( queryCount ) . to . equal ( 2 ) ;
2018-07-09 08:10:34 -04:00
} ) ;
2016-02-26 19:51:35 +01:00
} ) ;
2018-02-19 10:13:10 +01:00
it ( 'Event: start' , function ( ) {
return knex ( 'accounts' )
2018-07-09 08:10:34 -04:00
. insert ( { last _name : 'Start event test' } )
2018-02-19 10:13:10 +01:00
. then ( function ( ) {
var queryBuilder = knex ( 'accounts' ) . select ( ) ;
queryBuilder . on ( 'start' , function ( builder ) {
//Alter builder prior to compilation
//Select only one row
2018-07-09 08:10:34 -04:00
builder . where ( 'last_name' , 'Start event test' ) . first ( ) ;
2018-02-19 10:13:10 +01:00
} ) ;
2018-07-09 08:10:34 -04:00
return queryBuilder ;
2018-02-19 10:13:10 +01:00
} )
. then ( function ( row ) {
expect ( row ) . to . exist ;
2018-06-29 10:47:06 +03:00
expect ( row . last _name ) . to . equal ( 'Start event test' ) ;
2018-02-19 10:13:10 +01:00
} ) ;
} ) ;
2018-07-09 08:10:34 -04:00
it ( "Event 'query' should not emit native sql string" , function ( ) {
2018-04-12 09:17:45 +02:00
var builder = knex ( 'accounts' )
. where ( 'id' , 1 )
. select ( ) ;
2018-07-09 08:10:34 -04:00
builder . on ( 'query' , function ( obj ) {
var native = builder . toSQL ( ) . toNative ( ) . sql ;
var sql = builder . toSQL ( ) . sql ;
2018-04-12 09:17:45 +02:00
2018-07-09 08:10:34 -04:00
//Only assert if they diff to begin with.
//IE Maria does not diff
if ( native !== sql ) {
expect ( obj . sql ) . to . not . equal ( builder . toSQL ( ) . toNative ( ) . sql ) ;
expect ( obj . sql ) . to . equal ( builder . toSQL ( ) . sql ) ;
}
} ) ;
2018-04-12 09:17:45 +02:00
return builder ;
} ) ;
2018-07-09 08:10:34 -04:00
describe ( 'async stack traces' , function ( ) {
2018-04-25 23:11:24 +02:00
before ( ( ) => {
2018-07-09 08:10:34 -04:00
knex . client . config . asyncStackTraces = true ;
} ) ;
2018-04-25 23:11:24 +02:00
after ( ( ) => {
2018-07-09 08:10:34 -04:00
delete knex . client . config . asyncStackTraces ;
} ) ;
2018-04-25 23:11:24 +02:00
it ( 'should capture stack trace on query builder instantiation' , ( ) => {
return knex ( 'some_nonexisten_table' )
2018-07-09 08:10:34 -04:00
. select ( )
. catch ( ( err ) => {
expect ( err . stack . split ( '\n' ) [ 1 ] ) . to . match (
/at Function\.queryBuilder \(/
) ; // the index 1 might need adjustment if the code is refactored
expect ( typeof err . originalStack ) . to . equal ( 'string' ) ;
} ) ;
} ) ;
2018-04-25 23:11:24 +02:00
it ( 'should capture stack trace on raw query' , ( ) => {
return knex . raw ( 'select * from some_nonexisten_table' ) . catch ( ( err ) => {
2018-07-09 08:10:34 -04:00
expect ( err . stack . split ( '\n' ) [ 2 ] ) . to . match ( /at Function\.raw \(/ ) ; // the index 2 might need adjustment if the code is refactored
expect ( typeof err . originalStack ) . to . equal ( 'string' ) ;
} ) ;
} ) ;
2018-04-25 23:11:24 +02:00
it ( 'should capture stack trace on schema builder' , ( ) => {
2018-07-09 08:10:34 -04:00
return knex . schema
. renameTable ( 'some_nonexisten_table' , 'whatever' )
. catch ( ( err ) => {
expect ( err . stack . split ( '\n' ) [ 1 ] ) . to . match ( /client\.schemaBuilder/ ) ; // the index 1 might need adjustment if the code is refactored
expect ( typeof err . originalStack ) . to . equal ( 'string' ) ;
} ) ;
} ) ;
} ) ;
2018-04-25 23:11:24 +02:00
2018-05-29 17:42:03 +02:00
it ( 'Overwrite knex.logger functions using config' , ( ) => {
var knexConfig = _ . clone ( knex . client . config ) ;
var callCount = 0 ;
var assertCall = function ( expectedMessage , message ) {
expect ( message ) . to . equal ( expectedMessage ) ;
callCount ++ ;
} ;
knexConfig . log = {
warn : assertCall . bind ( null , 'test' ) ,
error : assertCall . bind ( null , 'test' ) ,
debug : assertCall . bind ( null , 'test' ) ,
2018-07-09 08:10:34 -04:00
deprecate : assertCall . bind (
null ,
'test is deprecated, please use test2'
) ,
2018-05-29 17:42:03 +02:00
} ;
//Sqlite warning message
knexConfig . useNullAsDefault = true ;
var knexDb = new Knex ( knexConfig ) ;
knexDb . client . logger . warn ( 'test' ) ;
knexDb . client . logger . error ( 'test' ) ;
knexDb . client . logger . debug ( 'test' ) ;
knexDb . client . logger . deprecate ( 'test' , 'test2' ) ;
expect ( callCount ) . to . equal ( 4 ) ;
} ) ;
2013-09-12 01:00:44 -04:00
} ) ;
2014-08-21 23:39:12 +02:00
} ;