@@ -866,5 +866,105 @@ describe('MysqlQueryService', () => {
866866 expect ( service . query ) . toHaveBeenCalledWith ( `SELECT * FROM reputation_reward_rate WHERE faction = ${ id } ` ) ;
867867 expect ( service [ 'cache' ] . size ) . toBe ( 1 ) ;
868868 } ) ;
869+
870+ describe ( 'copy query helpers' , ( ) => {
871+ it ( 'toSqlValue should format numbers and strings correctly' , ( ) => {
872+ expect ( ( service as any ) . toSqlValue ( 123 ) ) . toEqual ( '123' ) ;
873+ expect ( ( service as any ) . toSqlValue ( '456' ) ) . toEqual ( '456' ) ;
874+ expect ( ( service as any ) . toSqlValue ( "Anub'Rekhan" ) ) . toEqual ( "'Anub\\'Rekhan'" ) ;
875+ } ) ;
876+
877+ it ( 'getCopyVarsSet should return proper SET statements' , ( ) => {
878+ expect ( service . getCopyVarsSet ( 10 , 20 ) ) . toEqual ( 'SET @SOURCE = 10;\nSET @ENTRY = 20;\n' ) ;
879+ } ) ;
880+
881+ it ( 'getCopyQuery should generate temporary table copy SQL' , ( ) => {
882+ const q = service . getCopyQuery ( 't' , 10 , 20 , 'id' ) ;
883+ expect ( q ) . toEqual (
884+ 'DELETE FROM `t` WHERE `id` = 20;\n' +
885+ 'CREATE TEMPORARY TABLE temp_copy_table AS\n' +
886+ ' SELECT * FROM `t` WHERE `id` = 10;\n' +
887+ 'UPDATE temp_copy_table SET `id` = 20;\n' +
888+ 'INSERT INTO `t` SELECT * FROM temp_copy_table;\n' +
889+ 'DROP TEMPORARY TABLE temp_copy_table;\n' ,
890+ ) ;
891+ } ) ;
892+
893+ it ( 'getCopyQueryRaw should generate INSERT ... SELECT SQL with explicit columns' , ( ) => {
894+ const q = service . getCopyQueryRaw ( 't' , 10 , 20 , 'id' , [ 'a' , 'b' , 'id' ] ) ;
895+ expect ( q ) . toEqual (
896+ 'DELETE FROM `t` WHERE `id` = 20;\n' +
897+ 'INSERT INTO `t` (`a`, `b`, `id`)\n' +
898+ ' SELECT `a`, `b`, 20 AS `id`\n' +
899+ ' FROM `t`\n' +
900+ ' WHERE `id` = 10;\n' ,
901+ ) ;
902+ } ) ;
903+
904+ it ( 'getCopyQueryRawWithValues should return only delete for empty rows and full insert for values' , ( ) => {
905+ const empty = service . getCopyQueryRawWithValues ( 't' , [ ] , 20 , 'id' , [ 'id' , 'a' , 'b' ] ) ;
906+ expect ( empty ) . toEqual ( 'DELETE FROM `t` WHERE `id` = 20;\n' ) ;
907+
908+ const rows = [
909+ { id : 1 , a : 'x' , b : null } ,
910+ { id : 2 , a : "Anub'Rekhan" , b : 3 } ,
911+ ] ;
912+
913+ const full = service . getCopyQueryRawWithValues ( 't' , rows , 20 , 'id' , [ 'id' , 'a' , 'b' ] ) ;
914+ expect ( full ) . toEqual (
915+ 'DELETE FROM `t` WHERE `id` = 20;\n' +
916+ 'INSERT INTO `t` (`id`, `a`, `b`) VALUES\n' +
917+ "(20, 'x', NULL),\n" +
918+ "(20, 'Anub\\'Rekhan', 3);\n" ,
919+ ) ;
920+ } ) ;
921+ } ) ;
922+
923+ describe ( 'copy query helpers using vars' , ( ) => {
924+ it ( 'getCopyQuery should use @SOURCE and @ENTRY when useVars is true' , ( ) => {
925+ const q = service . getCopyQuery ( 't' , 10 , 20 , 'id' , true ) ;
926+ expect ( q ) . toContain ( 'WHERE `id` = @ENTRY' ) ;
927+ expect ( q ) . toContain ( 'WHERE `id` = @SOURCE' ) ;
928+ } ) ;
929+
930+ it ( 'getCopyQueryRaw should use @ENTRY when useVars is true' , ( ) => {
931+ const q = service . getCopyQueryRaw ( 't' , 10 , 20 , 'id' , [ 'a' , 'id' ] , true ) ;
932+ expect ( q ) . toContain ( 'SELECT `a`, @ENTRY AS `id`' ) ;
933+ expect ( q ) . toContain ( 'WHERE `id` = @SOURCE' ) ;
934+ } ) ;
935+
936+ it ( 'getCopyQueryRawWithValues should use @ENTRY when useVars is true' , ( ) => {
937+ const rows = [ { id : 1 , a : 'x' } ] ;
938+ const q = service . getCopyQueryRawWithValues ( 't' , rows , 20 , 'id' , [ 'id' , 'a' ] , true ) ;
939+ expect ( q ) . toContain ( 'DELETE FROM `t` WHERE `id` = @ENTRY;' ) ;
940+ expect ( q ) . toContain ( 'INSERT INTO `t` (`id`, `a`)' ) ;
941+ expect ( q ) . toContain ( '(@ENTRY,' ) ;
942+ } ) ;
943+ } ) ;
944+
945+ it ( 'getRowsCount should call queryValue with COUNT SQL and return observable' , ( ) => {
946+ // `queryValue` is already spied in the surrounding beforeEach; reuse and change its return
947+ ( service . queryValue as jasmine . Spy ) . and . returnValue ( of ( 42 ) ) ;
948+ service . getRowsCount ( 't' , 'id' , 123 ) . subscribe ( ( res ) => {
949+ expect ( res ) . toEqual ( 42 ) ;
950+ } ) ;
951+ expect ( service . queryValue as jasmine . Spy ) . toHaveBeenCalledWith ( 'SELECT COUNT(1) AS v FROM `t` WHERE `id` = 123;\n' ) ;
952+ } ) ;
953+
954+ it ( 'getCopyQueryRawWithValues should derive columns from first row when columns param is empty' , ( ) => {
955+ const rows = [
956+ { id : 1 , a : 'x' , b : null , c : 7 } ,
957+ { id : 2 , a : "Anub'Rekhan" , b : 3 , c : 8 } ,
958+ ] ;
959+
960+ // pass undefined columns so implementation derives them from rows[0]
961+ const full = service . getCopyQueryRawWithValues ( 't' , rows , 20 , 'id' , undefined as any ) ;
962+
963+ // columns order derived from Object.keys(rows[0]) can vary, but ensure key patterns exist
964+ expect ( full ) . toContain ( 'DELETE FROM `t` WHERE `id` = 20;\n' ) ;
965+ expect ( full ) . toContain ( 'INSERT INTO `t`' ) ;
966+ expect ( full ) . toContain ( "(20, 'x'" ) ;
967+ expect ( full ) . toContain ( "(20, 'Anub\\'Rekhan'" ) ;
968+ } ) ;
869969 } ) ;
870970} ) ;
0 commit comments