@@ -472,10 +472,14 @@ PRIMARY KEY (Int32Column)
472472 await new YdbCommand ( ydbConnection ) { CommandText = $ "DROP TABLE { tableName } " } . ExecuteNonQueryAsync ( ) ;
473473 }
474474
475- public static TheoryData < object , IList > NotNullListParams => new ( )
475+ private static readonly DateTime SomeTimestamp = DateTime . Parse ( "2025-11-02T18:47:14.112353" ) ;
476+ private static readonly DateTime SomeDatetime = DateTime . Parse ( "2025-11-02T18:47" ) ;
477+ private static readonly DateTime SomeDate = DateTime . Parse ( "2025-11-02" ) ;
478+
479+ public static TheoryData < YdbDbType , IList > ListParams => new ( )
476480 {
477- { YdbDbType . Bool , new List < bool > { false , true } } ,
478- { YdbDbType . Bool , ( bool [ ] ) [ false , true ] } ,
481+ { YdbDbType . Bool , new List < bool > { false , true , false } } ,
482+ { YdbDbType . Bool , ( bool [ ] ) [ false , true , false ] } ,
479483 { YdbDbType . Int8 , new List < sbyte > { 1 , 2 , 3 } } ,
480484 { YdbDbType . Int8 , new sbyte [ ] { 1 , 2 , 3 } } ,
481485 { YdbDbType . Int16 , new List < short > { 1 , 2 , 3 } } ,
@@ -495,62 +499,24 @@ PRIMARY KEY (Int32Column)
495499 { YdbDbType . Float , new float [ ] { 1 , 2 , 3 } } ,
496500 { YdbDbType . Double , new List < double > { 1 , 2 , 3 } } ,
497501 { YdbDbType . Double , new double [ ] { 1 , 2 , 3 } } ,
498- { " Decimal(22, 9)" , new List < decimal > { 1 , 2 , 3 } } ,
499- { " Decimal(22, 9)" , new decimal [ ] { 1 , 2 , 3 } } ,
502+ { YdbDbType . Decimal , new List < decimal > { 1 , 2 , 3 } } ,
503+ { YdbDbType . Decimal , new decimal [ ] { 1 , 2 , 3 } } ,
500504 { YdbDbType . Text , new List < string > { "1" , "2" , "3" } } ,
501505 { YdbDbType . Text , ( string [ ] ) [ "1" , "2" , "3" ] } ,
502506 { YdbDbType . Bytes , new List < byte [ ] > { new byte [ ] { 1 , 1 } , new byte [ ] { 2 , 2 } , new byte [ ] { 3 , 3 } } } ,
503507 { YdbDbType . Bytes , ( byte [ ] [ ] ) [ [ 1 , 1 ] , [ 2 , 2 ] , [ 3 , 3 ] ] } ,
504508 {
505509 YdbDbType . Timestamp ,
506- new List < DateTime > { DateTime . Now . AddDays ( 1 ) , DateTime . Now . AddDays ( 2 ) , DateTime . Now . AddDays ( 3 ) }
510+ new List < DateTime > { SomeTimestamp . AddDays ( 1 ) , SomeTimestamp . AddDays ( 2 ) , SomeTimestamp . AddDays ( 3 ) }
507511 } ,
508512 {
509513 YdbDbType . Timestamp ,
510- ( DateTime [ ] ) [ DateTime . Now . AddDays ( 1 ) , DateTime . Now . AddDays ( 2 ) , DateTime . Now . AddDays ( 3 ) ]
514+ ( DateTime [ ] ) [ SomeTimestamp . AddDays ( 1 ) , SomeTimestamp . AddDays ( 2 ) , SomeTimestamp . AddDays ( 3 ) ]
511515 } ,
512- {
513- YdbDbType . Interval , ( TimeSpan [ ] ) [ TimeSpan . FromDays ( 1 ) , TimeSpan . FromDays ( 2 ) , TimeSpan . FromDays ( 3 ) ]
514- }
515- } ;
516-
517- [ Theory ]
518- [ MemberData ( nameof ( NotNullListParams ) ) ]
519- public async Task YdbParameter_WhenListOrArrayParams_AutoCastYdbList ( object dbType , IList list )
520- {
521- await using var ydbConnection = await CreateOpenConnectionAsync ( ) ;
522- var testTable = $ "auto_cast_ydb_list_{ Guid . NewGuid ( ) } ";
523- await new YdbCommand ( ydbConnection )
524- { CommandText = $ "CREATE TABLE `{ testTable } `(id Uuid, type { dbType } , PRIMARY KEY(id));" }
525- . ExecuteNonQueryAsync ( ) ;
526- await new YdbCommand ( ydbConnection )
527- {
528- CommandText =
529- $ "INSERT INTO `{ testTable } `(id, type) " +
530- "SELECT id, type FROM AS_TABLE(ListMap($list, ($x) -> { RETURN <|id: RandomUuid($x), type: $x|> }));" ,
531- Parameters = { new YdbParameter ( "list" , list ) }
532- } . ExecuteNonQueryAsync ( ) ;
533-
534- var readerAsync = await new YdbCommand ( ydbConnection )
535- {
536- CommandText = $ "SELECT type FROM `{ testTable } ` WHERE type IN $list ORDER BY type",
537- Parameters = { new YdbParameter ( "list" , list ) }
538- } . ExecuteReaderAsync ( ) ;
539-
540- foreach ( var id in list )
541- {
542- await readerAsync . ReadAsync ( ) ;
543- Assert . Equal ( id , readerAsync . GetValue ( 0 ) ) ;
544- }
545-
546- Assert . False ( await readerAsync . ReadAsync ( ) ) ;
547- await new YdbCommand ( ydbConnection ) { CommandText = $ "DROP TABLE `{ testTable } `" } . ExecuteNonQueryAsync ( ) ;
548- }
549-
550- public static TheoryData < object , IList > NullListParams => new ( )
551- {
552- { YdbDbType . Bool , new List < bool ? > { false , true , null } } ,
553- { YdbDbType . Bool , ( bool ? [ ] ) [ false , true , null ] } ,
516+ { YdbDbType . Interval , new List < TimeSpan > { TimeSpan . FromDays ( 1 ) , TimeSpan . FromDays ( 2 ) , TimeSpan . FromDays ( 3 ) } } ,
517+ { YdbDbType . Interval , ( TimeSpan [ ] ) [ TimeSpan . FromDays ( 1 ) , TimeSpan . FromDays ( 2 ) , TimeSpan . FromDays ( 3 ) ] } ,
518+ { YdbDbType . Bool , new List < bool ? > { false , true , false , null } } ,
519+ { YdbDbType . Bool , ( bool ? [ ] ) [ false , true , false , null ] } ,
554520 { YdbDbType . Int8 , new List < sbyte ? > { 1 , 2 , 3 , null } } ,
555521 { YdbDbType . Int8 , new sbyte ? [ ] { 1 , 2 , 3 , null } } ,
556522 { YdbDbType . Int16 , new List < short ? > { 1 , 2 , 3 , null } } ,
@@ -570,27 +536,149 @@ public async Task YdbParameter_WhenListOrArrayParams_AutoCastYdbList(object dbTy
570536 { YdbDbType . Float , new float ? [ ] { 1 , 2 , 3 , null } } ,
571537 { YdbDbType . Double , new List < double ? > { 1 , 2 , 3 , null } } ,
572538 { YdbDbType . Double , new double ? [ ] { 1 , 2 , 3 , null } } ,
573- { " Decimal(22, 9)" , new List < decimal ? > { 1 , 2 , 3 , null } } ,
574- { " Decimal(22, 9)" , new decimal ? [ ] { 1 , 2 , 3 , null } } ,
539+ { YdbDbType . Decimal , new List < decimal ? > { 1 , 2 , 3 , null } } ,
540+ { YdbDbType . Decimal , new decimal ? [ ] { 1 , 2 , 3 , null } } ,
575541 { YdbDbType . Text , new List < string ? > { "1" , "2" , "3" , null } } ,
576542 { YdbDbType . Text , ( string ? [ ] ) [ "1" , "2" , "3" , null ] } ,
577543 { YdbDbType . Bytes , new List < byte [ ] ? > { new byte [ ] { 1 , 1 } , new byte [ ] { 2 , 2 } , new byte [ ] { 3 , 3 } , null } } ,
578544 { YdbDbType . Bytes , ( byte [ ] ? [ ] ) [ [ 1 , 1 ] , [ 2 , 2 ] , [ 3 , 3 ] , null ] } ,
579545 {
580546 YdbDbType . Timestamp ,
581- ( DateTime ? [ ] ) [ DateTime . Now . AddDays ( 1 ) , DateTime . Now . AddDays ( 2 ) , DateTime . Now . AddDays ( 3 ) , null ]
547+ new List < DateTime ? > { SomeTimestamp . AddDays ( 1 ) , SomeTimestamp . AddDays ( 2 ) , SomeTimestamp . AddDays ( 3 ) , null }
548+ } ,
549+ {
550+ YdbDbType . Timestamp ,
551+ ( DateTime ? [ ] ) [ SomeTimestamp . AddDays ( 1 ) , SomeTimestamp . AddDays ( 2 ) , SomeTimestamp . AddDays ( 3 ) , null ]
552+ } ,
553+ {
554+ YdbDbType . Interval ,
555+ new List < TimeSpan ? > { TimeSpan . FromDays ( 1 ) , TimeSpan . FromDays ( 2 ) , TimeSpan . FromDays ( 3 ) , null }
582556 } ,
583557 { YdbDbType . Interval , ( TimeSpan ? [ ] ) [ TimeSpan . FromDays ( 1 ) , TimeSpan . FromDays ( 2 ) , TimeSpan . FromDays ( 3 ) , null ] }
584558 } ;
585559
560+ public static TheoryData < YdbDbType , IList > ExtraParams = new ( )
561+ {
562+ {
563+ YdbDbType . Timestamp64 , new List < DateTime >
564+ { SomeTimestamp . AddYears ( - 100 ) , SomeTimestamp . AddYears ( 200 ) , SomeTimestamp . AddYears ( - 300 ) }
565+ } ,
566+ {
567+ YdbDbType . Timestamp64 ,
568+ ( DateTime [ ] ) [ SomeTimestamp . AddYears ( - 100 ) , SomeTimestamp . AddYears ( 200 ) , SomeTimestamp . AddYears ( - 300 ) ]
569+ } ,
570+ {
571+ YdbDbType . Timestamp64 , new List < DateTime ? >
572+ { SomeTimestamp . AddYears ( - 100 ) , SomeTimestamp . AddYears ( 200 ) , SomeTimestamp . AddYears ( - 300 ) , null }
573+ } ,
574+ {
575+ YdbDbType . Timestamp64 ,
576+ ( DateTime ? [ ] ) [ SomeTimestamp . AddYears ( - 100 ) , SomeTimestamp . AddYears ( 200 ) , SomeTimestamp . AddYears ( - 300 ) , null ]
577+ } ,
578+ {
579+ YdbDbType . Datetime64 , new List < DateTime >
580+ { SomeDatetime . AddYears ( - 100 ) , SomeDatetime . AddYears ( 200 ) , SomeDatetime . AddYears ( - 300 ) }
581+ } ,
582+ {
583+ YdbDbType . Datetime64 ,
584+ ( DateTime [ ] ) [ SomeDatetime . AddYears ( - 100 ) , SomeDatetime . AddYears ( 200 ) , SomeDatetime . AddYears ( - 300 ) ]
585+ } ,
586+ {
587+ YdbDbType . Datetime64 , new List < DateTime ? >
588+ { SomeDatetime . AddYears ( - 100 ) , SomeDatetime . AddYears ( 200 ) , SomeDatetime . AddYears ( - 300 ) , null }
589+ } ,
590+ {
591+ YdbDbType . Datetime64 ,
592+ ( DateTime ? [ ] ) [ SomeDatetime . AddYears ( - 100 ) , SomeDatetime . AddYears ( 200 ) , SomeDatetime . AddYears ( - 300 ) , null ]
593+ } ,
594+ {
595+ YdbDbType . Date32 , new List < DateTime >
596+ { SomeDate . AddYears ( - 100 ) , SomeDate . AddDays ( 200 ) , SomeDate . AddDays ( - 300 ) }
597+ } ,
598+ {
599+ YdbDbType . Date32 ,
600+ ( DateTime [ ] ) [ SomeDate . AddYears ( - 100 ) , SomeDate . AddDays ( 200 ) , SomeDate . AddDays ( - 300 ) ]
601+ } ,
602+ {
603+ YdbDbType . Date32 , new List < DateTime ? >
604+ { SomeDate . AddYears ( - 100 ) , SomeDate . AddDays ( 200 ) , SomeDate . AddDays ( - 300 ) , null }
605+ } ,
606+ {
607+ YdbDbType . Date32 ,
608+ ( DateTime ? [ ] ) [ SomeDate . AddYears ( - 100 ) , SomeDate . AddDays ( 200 ) , SomeDate . AddDays ( - 300 ) , null ]
609+ } ,
610+ {
611+ YdbDbType . Datetime , new List < DateTime >
612+ { SomeDatetime . AddYears ( 1 ) , SomeTimestamp . AddYears ( 2 ) , SomeTimestamp . AddYears ( 3 ) }
613+ } ,
614+ {
615+ YdbDbType . Datetime ,
616+ ( DateTime [ ] ) [ SomeDatetime . AddYears ( 1 ) , SomeTimestamp . AddYears ( 2 ) , SomeTimestamp . AddYears ( 3 ) ]
617+ } ,
618+ {
619+ YdbDbType . Datetime , new List < DateTime ? >
620+ { SomeDatetime . AddYears ( 1 ) , SomeTimestamp . AddYears ( 2 ) , SomeTimestamp . AddYears ( 3 ) , null }
621+ } ,
622+ {
623+ YdbDbType . Datetime ,
624+ ( DateTime ? [ ] ) [ SomeDatetime . AddYears ( 1 ) , SomeTimestamp . AddYears ( 2 ) , SomeTimestamp . AddYears ( 3 ) , null ]
625+ } ,
626+ { YdbDbType . Date , new List < DateTime > { SomeDate . AddYears ( 1 ) , SomeDate . AddYears ( 2 ) , SomeDate . AddYears ( 3 ) } } ,
627+ {
628+ YdbDbType . Date ,
629+ ( DateTime [ ] ) [ SomeDate . AddYears ( 1 ) , SomeDate . AddYears ( 2 ) , SomeDate . AddYears ( 3 ) ]
630+ } ,
631+ {
632+ YdbDbType . Date ,
633+ new List < DateTime ? > { SomeDate . AddYears ( 1 ) , SomeDate . AddYears ( 2 ) , SomeDate . AddYears ( 3 ) , null }
634+ } ,
635+ {
636+ YdbDbType . Date ,
637+ ( DateTime ? [ ] ) [ SomeDate . AddYears ( 1 ) , SomeDate . AddYears ( 2 ) , SomeDate . AddYears ( 3 ) , null ]
638+ } ,
639+ {
640+ YdbDbType . Interval64 ,
641+ new List < TimeSpan ? > { TimeSpan . FromDays ( - 1 ) , TimeSpan . FromDays ( 2 ) , TimeSpan . FromDays ( - 3 ) , null }
642+ } ,
643+ {
644+ YdbDbType . Interval64 ,
645+ ( TimeSpan ? [ ] ) [ TimeSpan . FromDays ( - 1 ) , TimeSpan . FromDays ( 2 ) , TimeSpan . FromDays ( - 3 ) , null ]
646+ } ,
647+ {
648+ YdbDbType . Json ,
649+ new List < string ? > { "{\" type\" : \" json1\" }" , "{\" type\" : \" json2\" }" , "{\" type\" : \" json3\" }" , null }
650+ } ,
651+ {
652+ YdbDbType . Json ,
653+ ( string ? [ ] ) [ "{\" type\" : \" json1\" }" , "{\" type\" : \" json2\" }" , "{\" type\" : \" json3\" }" , null ]
654+ } ,
655+ {
656+ YdbDbType . JsonDocument ,
657+ new List < string ? > { "{\" type\" : \" json1\" }" , "{\" type\" : \" json2\" }" , "{\" type\" : \" json3\" }" , null }
658+ } ,
659+ {
660+ YdbDbType . JsonDocument ,
661+ ( string ? [ ] ) [ "{\" type\" : \" json1\" }" , "{\" type\" : \" json2\" }" , "{\" type\" : \" json3\" }" , null ]
662+ } ,
663+ {
664+ YdbDbType . Yson ,
665+ new List < byte [ ] ? > { "{a=1u}"u8 . ToArray ( ) , "{a=2u}"u8 . ToArray ( ) , null }
666+ } ,
667+ {
668+ YdbDbType . Yson ,
669+ ( byte [ ] ? [ ] ) [ "{a=1u}"u8 . ToArray ( ) , "{a=2u}"u8 . ToArray ( ) , null ]
670+ }
671+ } ;
672+
586673 [ Theory ]
587- [ MemberData ( nameof ( NullListParams ) ) ]
588- public async Task YdbParameter_WhenNullableListOrArrayParams_AutoCastYdbList ( object dbType , IList list )
674+ [ MemberData ( nameof ( ListParams ) ) ]
675+ public async Task YdbParameter_SetValue_ArrayOrList_ConvertsToYdbList ( YdbDbType ydbDbType , IList list )
589676 {
590677 await using var ydbConnection = await CreateOpenConnectionAsync ( ) ;
591- var testTable = $ "auto_cast_ydb_nullable_list_{ Guid . NewGuid ( ) } ";
678+ var testTable = $ "auto_cast_ydb_list_{ Guid . NewGuid ( ) } ";
679+ var dbTypeStr = ydbDbType == YdbDbType . Decimal ? "Decimal(22, 9)" : ydbDbType . ToString ( ) ;
592680 await new YdbCommand ( ydbConnection )
593- { CommandText = $ "CREATE TABLE `{ testTable } `(id Uuid, type { dbType } , PRIMARY KEY(id));" }
681+ { CommandText = $ "CREATE TABLE `{ testTable } `(id Uuid, type { dbTypeStr } , PRIMARY KEY(id));" }
594682 . ExecuteNonQueryAsync ( ) ;
595683 await new YdbCommand ( ydbConnection )
596684 {
@@ -606,8 +694,59 @@ public async Task YdbParameter_WhenNullableListOrArrayParams_AutoCastYdbList(obj
606694 Parameters = { new YdbParameter ( "list" , list ) }
607695 } . ExecuteScalarAsync ( ) ;
608696
609- Assert . Equal ( ( ulong ) list . Count - 1 , count ) ;
697+ Assert . Equal ( 3ul , count ) ;
698+ Assert . Equal ( list . Count , await new YdbCommand ( ydbConnection )
699+ { CommandText = $ "SELECT COUNT(*) FROM `{ testTable } `" } . ExecuteNonQueryAsync ( ) ) ;
610700
611701 await new YdbCommand ( ydbConnection ) { CommandText = $ "DROP TABLE `{ testTable } `" } . ExecuteNonQueryAsync ( ) ;
612702 }
703+
704+ [ Theory ]
705+ [ MemberData ( nameof ( ListParams ) ) ]
706+ [ MemberData ( nameof ( ExtraParams ) ) ]
707+ public async Task YdbParameter_Value_WithYdbDbTypeList_ProducesListOfSpecifiedType ( YdbDbType ydbDbType , IList list )
708+ {
709+ await using var ydbConnection = await CreateOpenConnectionAsync ( ) ;
710+ var testTable = $ "ydb_list_{ Guid . NewGuid ( ) } ";
711+ var dbTypeStr = ydbDbType == YdbDbType . Decimal ? "Decimal(22, 9)" : ydbDbType . ToString ( ) ;
712+ await new YdbCommand ( ydbConnection )
713+ { CommandText = $ "CREATE TABLE `{ testTable } `(id Uuid, type { dbTypeStr } , PRIMARY KEY(id));" }
714+ . ExecuteNonQueryAsync ( ) ;
715+ await new YdbCommand ( ydbConnection )
716+ {
717+ CommandText =
718+ $ "INSERT INTO `{ testTable } `(id, type) " +
719+ "SELECT id, type FROM AS_TABLE(ListMap($list, ($x) -> { RETURN <|id: RandomUuid($x), type: $x|> }));" ,
720+ Parameters = { new YdbParameter ( "list" , YdbDbType . List | ydbDbType , list ) }
721+ } . ExecuteNonQueryAsync ( ) ;
722+
723+ if ( ydbDbType is not ( YdbDbType . Json or YdbDbType . JsonDocument or YdbDbType . Yson ) )
724+ {
725+ Assert . Equal ( 3ul , await new YdbCommand ( ydbConnection )
726+ {
727+ CommandText = $ "SELECT COUNT(*) FROM `{ testTable } ` WHERE type IN $list",
728+ Parameters = { new YdbParameter ( "list" , YdbDbType . List | ydbDbType , list ) }
729+ } . ExecuteScalarAsync ( ) ) ;
730+ }
731+
732+ Assert . Equal ( ( ulong ) list . Count , await new YdbCommand ( ydbConnection )
733+ { CommandText = $ "SELECT COUNT(*) FROM `{ testTable } `" } . ExecuteScalarAsync ( ) ) ;
734+
735+ await new YdbCommand ( ydbConnection ) { CommandText = $ "DROP TABLE `{ testTable } `" } . ExecuteNonQueryAsync ( ) ;
736+ }
737+
738+
739+ [ Fact ]
740+ public void YdbParameter_SetValue_ListOrArray_InvalidInputs_Throws ( )
741+ {
742+ Assert . Equal ( "Writing value of 'System.Object[]' is not supported for parameters having YdbDbType 'List<Bool>'" ,
743+ Assert . Throws < InvalidOperationException > ( ( ) =>
744+ new YdbParameter ( "list" , YdbDbType . List | YdbDbType . Bool , new object [ ] { true , false , "string" } )
745+ . TypedValue ) . Message ) ;
746+
747+ Assert . Equal (
748+ "Writing value of 'System.Object[]' is not supported for parameters having YdbDbType 'List<Decimal>'" ,
749+ Assert . Throws < InvalidOperationException > ( ( ) => new YdbParameter ( "list" ,
750+ YdbDbType . List | YdbDbType . Decimal , new object [ ] { 1.0m , false , 2.0m } ) . TypedValue ) . Message ) ;
751+ }
613752}
0 commit comments