@@ -724,4 +724,142 @@ describe('connection string auth - tedious', () => {
724724 }
725725 } )
726726 } )
727+
728+ describe ( 'TVP declaration with schema' , ( ) => {
729+ const tds = require ( 'tedious' )
730+
731+ it ( 'documents upstream tedious bug: schema missing from TVP declaration' , ( ) => {
732+ const tvp = new sql . Table ( 'AI.UDT_StringArray' )
733+ tvp . columns . add ( 'Name' , sql . NVarChar ( 128 ) , { nullable : false } )
734+ tvp . rows . add ( 'TestValue1' )
735+
736+ const tvpValue = {
737+ name : tvp . name ,
738+ schema : tvp . schema ,
739+ columns : [ ] ,
740+ rows : tvp . rows
741+ }
742+
743+ // tedious's own TVP type does NOT include schema in declaration
744+ const req = new tds . Request ( 'SELECT 1' )
745+ req . addParameter ( 'InputList' , tds . TYPES . TVP , tvpValue )
746+ const paramsStr = req . makeParamsParameter ( req . parameters )
747+ assert . strictEqual ( paramsStr , '@InputList UDT_StringArray readonly' ,
748+ 'tedious itself does not include schema - this documents the upstream bug' )
749+ } )
750+
751+ it ( 'schema-aware TVP type includes schema in declaration' , ( ) => {
752+ const tvp = new sql . Table ( 'AI.UDT_StringArray' )
753+ tvp . columns . add ( 'Name' , sql . NVarChar ( 128 ) , { nullable : false } )
754+ tvp . rows . add ( 'TestValue1' )
755+
756+ const tvpValue = {
757+ name : tvp . name ,
758+ schema : tvp . schema ,
759+ columns : [ ] ,
760+ rows : tvp . rows
761+ }
762+
763+ assert . strictEqual ( tvp . name , 'UDT_StringArray' )
764+ assert . strictEqual ( tvp . schema , 'AI' )
765+
766+ // Use the patched SchemaAwareTVP type from lib/tedious/request.js
767+ // Since it's not exported, recreate the same pattern to verify behavior
768+ const SchemaAwareTVP = Object . create ( tds . TYPES . TVP , {
769+ declaration : {
770+ value : function ( parameter ) {
771+ const value = parameter . value
772+ if ( value && value . schema ) {
773+ return value . schema + '.' + value . name + ' readonly'
774+ }
775+ return value . name + ' readonly'
776+ } ,
777+ writable : true ,
778+ configurable : true
779+ }
780+ } )
781+
782+ const req = new tds . Request ( 'SELECT 1' )
783+ req . addParameter ( 'InputList' , SchemaAwareTVP , tvpValue )
784+ const paramsStr = req . makeParamsParameter ( req . parameters )
785+ assert . strictEqual ( paramsStr , '@InputList AI.UDT_StringArray readonly' )
786+ } )
787+
788+ it ( 'schema-aware TVP works without schema' , ( ) => {
789+ const tvp = new sql . Table ( 'UDT_StringArray' )
790+ tvp . columns . add ( 'Name' , sql . NVarChar ( 128 ) , { nullable : false } )
791+
792+ const tvpValue = {
793+ name : tvp . name ,
794+ schema : tvp . schema ,
795+ columns : [ ] ,
796+ rows : tvp . rows
797+ }
798+
799+ assert . strictEqual ( tvp . name , 'UDT_StringArray' )
800+ assert . strictEqual ( tvp . schema , null )
801+
802+ const SchemaAwareTVP = Object . create ( tds . TYPES . TVP , {
803+ declaration : {
804+ value : function ( parameter ) {
805+ const value = parameter . value
806+ if ( value && value . schema ) {
807+ return value . schema + '.' + value . name + ' readonly'
808+ }
809+ return value . name + ' readonly'
810+ } ,
811+ writable : true ,
812+ configurable : true
813+ }
814+ } )
815+
816+ const req = new tds . Request ( 'SELECT 1' )
817+ req . addParameter ( 'InputList' , SchemaAwareTVP , tvpValue )
818+ const paramsStr = req . makeParamsParameter ( req . parameters )
819+ assert . strictEqual ( paramsStr , '@InputList UDT_StringArray readonly' )
820+ } )
821+
822+ it ( 'schema-aware TVP inherits generateTypeInfo from tedious TVP' , ( ) => {
823+ const SchemaAwareTVP = Object . create ( tds . TYPES . TVP , {
824+ declaration : {
825+ value : function ( parameter ) {
826+ const value = parameter . value
827+ if ( value && value . schema ) {
828+ return value . schema + '.' + value . name + ' readonly'
829+ }
830+ return value . name + ' readonly'
831+ } ,
832+ writable : true ,
833+ configurable : true
834+ }
835+ } )
836+
837+ // Verify it inherits all other methods from tedious TVP
838+ assert . strictEqual ( SchemaAwareTVP . id , tds . TYPES . TVP . id )
839+ assert . strictEqual ( SchemaAwareTVP . type , tds . TYPES . TVP . type )
840+ assert . strictEqual ( SchemaAwareTVP . name , tds . TYPES . TVP . name )
841+ assert . strictEqual ( SchemaAwareTVP . generateTypeInfo , tds . TYPES . TVP . generateTypeInfo )
842+ assert . strictEqual ( SchemaAwareTVP . generateParameterLength , tds . TYPES . TVP . generateParameterLength )
843+ assert . strictEqual ( SchemaAwareTVP . generateParameterData , tds . TYPES . TVP . generateParameterData )
844+ assert . strictEqual ( SchemaAwareTVP . validate , tds . TYPES . TVP . validate )
845+ // declaration is overridden
846+ assert . notStrictEqual ( SchemaAwareTVP . declaration , tds . TYPES . TVP . declaration )
847+ } )
848+ } )
849+
850+ describe ( 'msnodesqlv8 TVP declaration' , ( ) => {
851+ const { declare, TYPES } = require ( '../../lib/datatypes' )
852+
853+ it ( 'includes schema in TVP declaration when tvpType is schema-qualified' , ( ) => {
854+ // msnodesqlv8 uses declare() from datatypes.js, which uses tvpType
855+ // When tvpType includes the schema, the declaration is correct
856+ const result = declare ( TYPES . TVP , { tvpType : 'AI.UDT_StringArray' } )
857+ assert . strictEqual ( result , 'AI.UDT_StringArray readonly' )
858+ } )
859+
860+ it ( 'works without schema in tvpType' , ( ) => {
861+ const result = declare ( TYPES . TVP , { tvpType : 'UDT_StringArray' } )
862+ assert . strictEqual ( result , 'UDT_StringArray readonly' )
863+ } )
864+ } )
727865} )
0 commit comments