11using System ;
22using System . Collections . Generic ;
33using System . Collections . ObjectModel ;
4+ using System . Globalization ;
45using System . Linq ;
6+ using System . Text ;
57using System . Text . RegularExpressions ;
68
79namespace Typesense ;
@@ -93,6 +95,7 @@ public VectorQuery(float[] vector, string vectorFieldName, string? id = null, in
9395 ExtraParams = extraParams ?? new ( ) ;
9496 }
9597
98+ private static readonly Regex VectorQueryStringRegex = new ( @"(.+):\((\[.*?\])(\s*,[^)]+)*\)" , RegexOptions . Compiled , TimeSpan . FromSeconds ( 1 ) ) ;
9699 /// <summary>
97100 /// Parses a query and initializes the related object members.
98101 /// </summary>
@@ -101,9 +104,7 @@ public VectorQuery(float[] vector, string vectorFieldName, string? id = null, in
101104 private void ParseQuery ( string query )
102105 {
103106 // First parse the portion of the string inside the vec property - "vec:([0.96826, 0.94, 0.39557, 0.306488], k:100, flat_search_cutoff: 20)"
104- var pattern = @"(.+):\((\[.*?\])(\s*,[^)]+)*\)" ;
105-
106- var match = Regex . Match ( query , pattern ) ;
107+ var match = VectorQueryStringRegex . Match ( query ) ;
107108 if ( ! match . Success )
108109 throw new ArgumentException ( "Malformed vector query string." ) ;
109110
@@ -121,10 +122,10 @@ private void ParseQuery(string query)
121122 {
122123 // Get the float array query portion
123124 _vector = vectorMatch
124- . Split ( "," )
125+ . Split ( ',' , StringSplitOptions . TrimEntries )
125126 . Select ( x =>
126127 {
127- if ( ! float . TryParse ( x . Trim ( ) , out float result ) )
128+ if ( ! float . TryParse ( x , NumberStyles . Float , CultureInfo . InvariantCulture , out float result ) )
128129 throw new ArgumentException (
129130 "Malformed vector query string: one of the vector values is not a float." ) ;
130131
@@ -134,14 +135,11 @@ private void ParseQuery(string query)
134135
135136 // Commas are always used as a delimiter inside the list of parameters
136137 var qParams = match . Groups [ 3 ] . Value
137- . Split ( "," )
138- . Select ( x => x . Trim ( ) )
139- . Where ( x => ! string . IsNullOrEmpty ( x ) )
140- . ToList ( ) ;
138+ . Split ( ',' , StringSplitOptions . TrimEntries | StringSplitOptions . RemoveEmptyEntries ) ;
141139
142140 foreach ( var param in qParams )
143141 {
144- var kvp = param . Split ( ':' ) . Select ( x => x . Trim ( ) ) . ToArray ( ) ;
142+ var kvp = param . Split ( ':' , StringSplitOptions . TrimEntries ) ;
145143
146144 if ( kvp . Length != 2 )
147145 throw new ArgumentException ( $ "Malformed vector query string at parameter '{ param } '") ;
@@ -186,29 +184,34 @@ private void ParseQuery(string query)
186184 /// <returns>The vector-search query string.</returns>
187185 public virtual string ToQuery ( )
188186 {
189- var qParams = new List < string > ( ) ;
190-
187+ StringBuilder queryStringBuilder = new ( VectorFieldName ) ;
188+ queryStringBuilder . Append ( ":([" ) ;
191189 // Float vector is required, even if empty
192- var qry = string . Join ( "," , _vector ) ;
193- qParams . Add ( $ "[{ qry } ]") ;
190+ for ( var index = 0 ; index < _vector . Length ; index ++ )
191+ {
192+ if ( index != 0 )
193+ queryStringBuilder . Append ( ',' ) ;
194+ queryStringBuilder . Append ( _vector [ index ] . ToString ( "R" , CultureInfo . InvariantCulture ) ) ;
195+ }
196+ queryStringBuilder . Append ( ']' ) ;
194197
195198 // All other parameters are optional
199+ // note that the only delimiter for all type/value pairs is a comma and there is no need to surround string values with quotations
196200 if ( Id != null )
197- qParams . Add ( $ " id:{ Id } " ) ;
201+ queryStringBuilder . Append ( ", id:" ) . Append ( Id ) ;
198202
199203 if ( K != null )
200- qParams . Add ( $ "k: { K } " ) ;
204+ queryStringBuilder . Append ( ",k:" ) . Append ( K ) ;
201205
202206 if ( FlatSearchCutoff != null )
203- qParams . Add ( $ " flat_search_cutoff:{ FlatSearchCutoff } " ) ;
207+ queryStringBuilder . Append ( ", flat_search_cutoff:" ) . Append ( FlatSearchCutoff ) ;
204208
205209 // Allow for additional parameters if provided
206- qParams . AddRange ( ExtraParams . Select ( kvp => $ "{ kvp . Key } :{ kvp . Value } ") ) ;
210+ foreach ( var ( key , value ) in ExtraParams )
211+ queryStringBuilder . Append ( ',' ) . Append ( key ) . Append ( ':' ) . Append ( value ) ;
207212
208- // Build the final query - note that the only delimiter for all type/value pairs is a comma and there is no
209- // need to surround string values with quotations
210- var query = string . Join ( "," , qParams ) ;
213+ queryStringBuilder . Append ( ')' ) ;
211214
212- return $ " { VectorFieldName } :( { query } )" ;
215+ return queryStringBuilder . ToString ( ) ;
213216 }
214217}
0 commit comments