2
2
//!
3
3
//! Can only be instantiated by using Query::write_query
4
4
5
+ use crate :: query:: line_proto_term:: LineProtoTerm ;
5
6
use crate :: query:: { QueryType , ValidQuery } ;
6
7
use crate :: { Error , Query , Timestamp } ;
7
8
use std:: fmt:: { Display , Formatter } ;
8
9
9
10
// todo: batch write queries
10
11
11
12
pub trait WriteField {
12
- fn add_to_fields ( self , tag : String , fields : & mut Vec < ( String , String ) > ) ;
13
+ fn add_to_fields ( self , tag : String , fields : & mut Vec < ( String , Type ) > ) ;
13
14
}
14
15
15
16
impl < T : Into < Type > > WriteField for T {
16
- fn add_to_fields ( self , tag : String , fields : & mut Vec < ( String , String ) > ) {
17
+ fn add_to_fields ( self , tag : String , fields : & mut Vec < ( String , Type ) > ) {
17
18
let val: Type = self . into ( ) ;
18
- fields. push ( ( tag, val. to_string ( ) ) ) ;
19
+ fields. push ( ( tag, val) ) ;
19
20
}
20
21
}
21
22
22
23
impl < T : Into < Type > > WriteField for Option < T > {
23
- fn add_to_fields ( self , tag : String , fields : & mut Vec < ( String , String ) > ) {
24
+ fn add_to_fields ( self , tag : String , fields : & mut Vec < ( String , Type ) > ) {
24
25
if let Some ( val) = self {
25
26
val. add_to_fields ( tag, fields) ;
26
27
}
@@ -29,7 +30,7 @@ impl<T: Into<Type>> WriteField for Option<T> {
29
30
30
31
/// Internal Representation of a Write query that has not yet been built
31
32
pub struct WriteQuery {
32
- fields : Vec < ( String , String ) > ,
33
+ fields : Vec < ( String , Type ) > ,
33
34
tags : Vec < ( String , String ) > ,
34
35
measurement : String ,
35
36
timestamp : Timestamp ,
@@ -121,7 +122,7 @@ impl Display for Type {
121
122
Float ( x) => write ! ( f, "{}" , x) ,
122
123
SignedInteger ( x) => write ! ( f, "{}" , x) ,
123
124
UnsignedInteger ( x) => write ! ( f, "{}" , x) ,
124
- Text ( text) => write ! ( f, "\" {text}\" " , text = text) ,
125
+ Text ( text) => write ! ( f, "{text}" , text = text) ,
125
126
}
126
127
}
127
128
}
@@ -159,22 +160,35 @@ impl Query for WriteQuery {
159
160
let mut tags = self
160
161
. tags
161
162
. iter ( )
162
- . map ( |( tag, value) | format ! ( "{tag}={value}" , tag = tag, value = value) )
163
+ . map ( |( tag, value) | {
164
+ format ! (
165
+ "{tag}={value}" ,
166
+ tag = LineProtoTerm :: TagKey ( tag) . escape( ) ,
167
+ value = LineProtoTerm :: TagValue ( value) . escape( ) ,
168
+ )
169
+ } )
163
170
. collect :: < Vec < String > > ( )
164
171
. join ( "," ) ;
172
+
165
173
if !tags. is_empty ( ) {
166
174
tags. insert_str ( 0 , "," ) ;
167
175
}
168
176
let fields = self
169
177
. fields
170
178
. iter ( )
171
- . map ( |( field, value) | format ! ( "{field}={value}" , field = field, value = value) )
179
+ . map ( |( field, value) | {
180
+ format ! (
181
+ "{field}={value}" ,
182
+ field = LineProtoTerm :: FieldKey ( field) . escape( ) ,
183
+ value = LineProtoTerm :: FieldValue ( value) . escape( ) ,
184
+ )
185
+ } )
172
186
. collect :: < Vec < String > > ( )
173
187
. join ( "," ) ;
174
188
175
189
Ok ( ValidQuery ( format ! (
176
190
"{measurement}{tags} {fields}{time}" ,
177
- measurement = self . measurement,
191
+ measurement = LineProtoTerm :: Measurement ( & self . measurement) . escape ( ) ,
178
192
tags = tags,
179
193
fields = fields,
180
194
time = match self . timestamp {
@@ -207,7 +221,7 @@ mod tests {
207
221
. build ( ) ;
208
222
209
223
assert ! ( query. is_ok( ) , "Query was empty" ) ;
210
- assert_eq ! ( query. unwrap( ) , "weather temperature=82 11" ) ;
224
+ assert_eq ! ( query. unwrap( ) , "weather temperature=82i 11" ) ;
211
225
}
212
226
213
227
#[ test]
@@ -220,7 +234,7 @@ mod tests {
220
234
assert ! ( query. is_ok( ) , "Query was empty" ) ;
221
235
assert_eq ! (
222
236
query. unwrap( ) ,
223
- "weather temperature=82 ,wind_strength=3.7 11"
237
+ "weather temperature=82i ,wind_strength=3.7 11"
224
238
) ;
225
239
}
226
240
@@ -232,7 +246,7 @@ mod tests {
232
246
. build ( ) ;
233
247
234
248
assert ! ( query. is_ok( ) , "Query was empty" ) ;
235
- assert_eq ! ( query. unwrap( ) , "weather temperature=82 11" ) ;
249
+ assert_eq ! ( query. unwrap( ) , "weather temperature=82i 11" ) ;
236
250
}
237
251
238
252
#[ test]
@@ -255,7 +269,7 @@ mod tests {
255
269
assert ! ( query. is_ok( ) , "Query was empty" ) ;
256
270
assert_eq ! (
257
271
query. unwrap( ) ,
258
- "weather,location=\" us-midwest\" ,season=\" summer\" temperature=82 11"
272
+ "weather,location=us-midwest,season=summer temperature=82i 11"
259
273
) ;
260
274
}
261
275
@@ -270,4 +284,21 @@ mod tests {
270
284
271
285
assert_eq ! ( query. get_type( ) , QueryType :: WriteQuery ) ;
272
286
}
287
+
288
+ #[ test]
289
+ fn test_escaping ( ) {
290
+ let query = Query :: write_query ( Timestamp :: Hours ( 11 ) , "wea, ther=" )
291
+ . add_field ( "temperature" , 82 )
292
+ . add_field ( "\" temp=era,t ure\" " , r#"too"\\hot"# )
293
+ . add_field ( "float" , 82.0 )
294
+ . add_tag ( "location" , "us-midwest" )
295
+ . add_tag ( "loc, =\" ation" , "us, \" mid=west\" " )
296
+ . build ( ) ;
297
+
298
+ assert ! ( query. is_ok( ) , "Query was empty" ) ;
299
+ assert_eq ! (
300
+ query. unwrap( ) . get( ) ,
301
+ r#"wea\,\ ther=,location=us-midwest,loc\,\ \="ation=us\,\ "mid\=west" temperature=82i,"temp\=era\,t\ ure"="too\"\\\\hot",float=82 11"#
302
+ ) ;
303
+ }
273
304
}
0 commit comments