33// See the LICENSE file in the project root for more information
44
55using System ;
6- using System . Collections . Generic ;
7- using System . Linq ;
6+ using System . Collections ;
87using System . Runtime . Serialization ;
8+ using System . Text ;
99using Elastic . Transport . Extensions ;
1010
1111namespace Elastic . Transport ;
@@ -22,59 +22,113 @@ public sealed class UrlFormatter : IFormatProvider, ICustomFormatter
2222 public UrlFormatter ( ITransportConfiguration settings ) => _settings = settings ;
2323
2424 /// <inheritdoc cref="ICustomFormatter.Format"/>>
25- public string Format ( string format , object arg , IFormatProvider formatProvider )
25+ public string Format ( string ? format , object ? arg , IFormatProvider ? formatProvider )
2626 {
2727 if ( arg == null ) throw new ArgumentNullException ( ) ;
2828
29- if ( format == "r" ) return arg . ToString ( ) ;
29+ if ( format == "r" ) return arg . ToString ( ) ?? string . Empty ;
3030
3131 var value = CreateString ( arg , _settings ) ;
3232 if ( value . IsNullOrEmpty ( ) && ! format . IsNullOrEmpty ( ) )
3333 throw new ArgumentException ( $ "The parameter: { format } to the url is null or empty") ;
3434
35- return value . IsNullOrEmpty ( ) ? string . Empty : Uri . EscapeDataString ( value ) ;
35+ return string . IsNullOrEmpty ( value ) ? string . Empty : Uri . EscapeDataString ( value ) ;
3636 }
3737
3838 /// <inheritdoc cref="IFormatProvider.GetFormat"/>
39- public object GetFormat ( Type formatType ) => formatType == typeof ( ICustomFormatter ) ? this : null ;
39+ public object ? GetFormat ( Type formatType ) => formatType == typeof ( ICustomFormatter ) ? this : null ;
4040
4141 /// <inheritdoc cref="CreateString(object, ITransportConfiguration)"/>
42- public string CreateString ( object value ) => CreateString ( value , _settings ) ;
42+ public string ? CreateString ( object ? value ) => CreateString ( value , _settings ) ;
4343
4444 /// <summary> Creates a query string representation for <paramref name="value"/> </summary>
45- public static string ? CreateString ( object ? value , ITransportConfiguration settings )
45+ public static string ? CreateString ( object ? value , ITransportConfiguration settings ) =>
46+ value switch
47+ {
48+ null => null ,
49+ string s => s ,
50+ string [ ] ss => string . Join ( "," , ss ) ,
51+ Enum e => e . GetStringValue ( ) ,
52+ bool b => b ? "true" : "false" ,
53+ DateTimeOffset offset => offset . ToString ( "o" ) ,
54+ TimeSpan timeSpan => timeSpan . ToTimeUnit ( ) ,
55+ // Special handling to support non-zero based arrays
56+ Array pns => CreateStringFromArray ( pns , settings ) ,
57+ // Performance optimization for directly indexable collections
58+ IList pns => CreateStringFromIList ( pns , settings ) ,
59+ // Generic implementation for all other collections
60+ IEnumerable pns => CreateStringFromIEnumerable ( pns , settings ) ,
61+ _ => ResolveUrlParameterOrDefault ( value , settings )
62+ } ;
63+
64+ private static string CreateStringFromArray ( Array value , ITransportConfiguration settings )
4665 {
47- switch ( value )
66+ switch ( value . Length )
67+ {
68+ case 0 :
69+ return string . Empty ;
70+ case 1 :
71+ return ResolveUrlParameterOrDefault ( value . GetValue ( value . GetLowerBound ( 0 ) ) , settings ) ;
72+ }
73+
74+ var sb = new StringBuilder ( ) ;
75+
76+ for ( var i = value . GetLowerBound ( 0 ) ; i <= value . GetUpperBound ( 0 ) ; ++ i )
4877 {
49- case null : return null ;
50- case string s : return s ;
51- case string [ ] ss : return string . Join ( "," , ss ) ;
52- case Enum e : return e . GetStringValue ( ) ;
53- case bool b : return b ? "true" : "false" ;
54- case DateTimeOffset offset : return offset . ToString ( "o" ) ;
55- case IEnumerable < object > pns :
56- return CreateStringFromIEnumerable ( pns , settings ) ;
57-
58- case Array pns :
59- return CreateStringFromIEnumerable ( ConvertArrayToEnumerable ( pns ) , settings ) ;
60-
61- case TimeSpan timeSpan : return timeSpan . ToTimeUnit ( ) ;
62- default :
63- return ResolveUrlParameterOrDefault ( value , settings ) ;
78+ if ( sb . Length != 0 )
79+ sb . Append ( ',' ) ;
80+
81+ sb . Append ( ResolveUrlParameterOrDefault ( value . GetValue ( i ) , settings ) ) ;
6482 }
83+
84+ return sb . ToString ( ) ;
6585 }
6686
67- private static string CreateStringFromIEnumerable ( IEnumerable < object > value , ITransportConfiguration settings ) =>
68- string . Join ( "," , value . Select ( o => ResolveUrlParameterOrDefault ( o , settings ) ) ) ;
87+ private static string CreateStringFromIList ( IList value , ITransportConfiguration settings )
88+ {
89+ switch ( value . Count )
90+ {
91+ case 0 :
92+ return string . Empty ;
93+ case 1 :
94+ return ResolveUrlParameterOrDefault ( value [ 0 ] , settings ) ;
95+ }
96+
97+ var sb = new StringBuilder ( ) ;
6998
70- private static IEnumerable < object > ConvertArrayToEnumerable ( Array array )
99+ for ( var i = 0 ; i < value . Count ; ++ i )
100+ {
101+ if ( sb . Length != 0 )
102+ sb . Append ( ',' ) ;
103+
104+ sb . Append ( ResolveUrlParameterOrDefault ( value [ i ] , settings ) ) ;
105+ }
106+
107+ return sb . ToString ( ) ;
108+ }
109+
110+ private static string CreateStringFromIEnumerable ( IEnumerable value , ITransportConfiguration settings )
71111 {
72- for ( var i = array . GetLowerBound ( 0 ) ; i <= array . GetUpperBound ( 0 ) ; i ++ )
73- yield return array . GetValue ( i ) ;
112+ var sb = new StringBuilder ( ) ;
113+
114+ foreach ( var v in value )
115+ {
116+ if ( sb . Length != 0 )
117+ sb . Append ( ',' ) ;
118+
119+ sb . Append ( ResolveUrlParameterOrDefault ( v , settings ) ) ;
120+ }
121+
122+ return sb . ToString ( ) ;
74123 }
75124
76- private static string ResolveUrlParameterOrDefault ( object value , ITransportConfiguration settings ) =>
77- value is IUrlParameter urlParam ? urlParam . GetString ( settings ) : GetEnumMemberName ( value ) ?? value . ToString ( ) ;
125+ private static string ResolveUrlParameterOrDefault ( object ? value , ITransportConfiguration settings ) =>
126+ value switch
127+ {
128+ null => string . Empty ,
129+ IUrlParameter urlParam => urlParam . GetString ( settings ) ,
130+ _ => GetEnumMemberName ( value ) ?? value . ToString ( ) ?? string . Empty
131+ } ;
78132
79133 private static string ? GetEnumMemberName ( object value )
80134 {
0 commit comments