1
1
//! Service implementation for the `Clickhouse` sink.
2
2
3
+ use super :: config:: QuerySettingsConfig ;
3
4
use super :: sink:: PartitionKey ;
4
5
use crate :: {
5
6
http:: { Auth , HttpError } ,
@@ -67,6 +68,7 @@ pub(super) struct ClickhouseServiceRequestBuilder {
67
68
pub ( super ) date_time_best_effort : bool ,
68
69
pub ( super ) insert_random_shard : bool ,
69
70
pub ( super ) compression : Compression ,
71
+ pub ( super ) query_settings : QuerySettingsConfig ,
70
72
}
71
73
72
74
impl HttpServiceRequestBuilder < PartitionKey > for ClickhouseServiceRequestBuilder {
@@ -84,6 +86,7 @@ impl HttpServiceRequestBuilder<PartitionKey> for ClickhouseServiceRequestBuilder
84
86
self . skip_unknown_fields ,
85
87
self . date_time_best_effort ,
86
88
self . insert_random_shard ,
89
+ self . query_settings ,
87
90
) ?;
88
91
89
92
let auth: Option < Auth > = self . auth . clone ( ) ;
@@ -107,6 +110,18 @@ impl HttpServiceRequestBuilder<PartitionKey> for ClickhouseServiceRequestBuilder
107
110
}
108
111
}
109
112
113
+ fn append_param < T : ToString > ( uri : & mut String , key : & str , value : Option < T > ) {
114
+ if let Some ( val) = value {
115
+ uri. push_str ( & format ! ( "{}={}&" , key, val. to_string( ) ) ) ;
116
+ }
117
+ }
118
+ fn append_param_bool ( uri : & mut String , key : & str , value : Option < bool > ) {
119
+ if let Some ( val) = value {
120
+ uri. push_str ( & format ! ( "{}={}&" , key, if val { 1 } else { 0 } ) ) ;
121
+ }
122
+ }
123
+
124
+ #[ allow( clippy:: too_many_arguments) ]
110
125
fn set_uri_query (
111
126
uri : & Uri ,
112
127
database : & str ,
@@ -115,6 +130,7 @@ fn set_uri_query(
115
130
skip_unknown : Option < bool > ,
116
131
date_time_best_effort : bool ,
117
132
insert_random_shard : bool ,
133
+ query_settings : QuerySettingsConfig ,
118
134
) -> crate :: Result < Uri > {
119
135
let query = url:: form_urlencoded:: Serializer :: new ( String :: new ( ) )
120
136
. append_pair (
@@ -135,19 +151,45 @@ fn set_uri_query(
135
151
}
136
152
137
153
uri. push_str ( "?input_format_import_nested_json=1&" ) ;
138
- if let Some ( skip_unknown) = skip_unknown {
139
- if skip_unknown {
140
- uri. push_str ( "input_format_skip_unknown_fields=1&" ) ;
141
- } else {
142
- uri. push_str ( "input_format_skip_unknown_fields=0&" )
143
- }
144
- }
154
+ append_param_bool ( & mut uri, "input_format_skip_unknown_fields" , skip_unknown) ;
145
155
if date_time_best_effort {
146
156
uri. push_str ( "date_time_input_format=best_effort&" )
147
157
}
148
158
if insert_random_shard {
149
159
uri. push_str ( "insert_distributed_one_random_shard=1&" )
150
160
}
161
+ append_param_bool (
162
+ & mut uri,
163
+ "async_insert" ,
164
+ query_settings. async_insert_settings . enabled ,
165
+ ) ;
166
+ append_param_bool (
167
+ & mut uri,
168
+ "wait_for_async_insert" ,
169
+ query_settings. async_insert_settings . wait_for_processing ,
170
+ ) ;
171
+ append_param (
172
+ & mut uri,
173
+ "wait_for_async_insert_timeout" ,
174
+ query_settings
175
+ . async_insert_settings
176
+ . wait_for_processing_timeout ,
177
+ ) ;
178
+ append_param_bool (
179
+ & mut uri,
180
+ "async_insert_deduplicate" ,
181
+ query_settings. async_insert_settings . deduplicate ,
182
+ ) ;
183
+ append_param (
184
+ & mut uri,
185
+ "async_insert_max_data_size" ,
186
+ query_settings. async_insert_settings . max_data_size ,
187
+ ) ;
188
+ append_param (
189
+ & mut uri,
190
+ "async_insert_max_query_number" ,
191
+ query_settings. async_insert_settings . max_query_number ,
192
+ ) ;
151
193
uri. push_str ( query. as_str ( ) ) ;
152
194
153
195
uri. parse :: < Uri > ( )
@@ -158,6 +200,7 @@ fn set_uri_query(
158
200
#[ cfg( test) ]
159
201
mod tests {
160
202
use super :: * ;
203
+ use crate :: sinks:: clickhouse:: config:: * ;
161
204
162
205
#[ test]
163
206
fn encode_valid ( ) {
@@ -169,6 +212,7 @@ mod tests {
169
212
Some ( false ) ,
170
213
true ,
171
214
false ,
215
+ QuerySettingsConfig :: default ( ) ,
172
216
)
173
217
. unwrap ( ) ;
174
218
assert_eq ! ( uri. to_string( ) , "http://localhost:80/?\
@@ -185,6 +229,7 @@ mod tests {
185
229
Some ( false ) ,
186
230
false ,
187
231
false ,
232
+ QuerySettingsConfig :: default ( ) ,
188
233
)
189
234
. unwrap ( ) ;
190
235
assert_eq ! ( uri. to_string( ) , "http://localhost:80/?\
@@ -200,6 +245,7 @@ mod tests {
200
245
Some ( true ) ,
201
246
true ,
202
247
false ,
248
+ QuerySettingsConfig :: default ( ) ,
203
249
)
204
250
. unwrap ( ) ;
205
251
assert_eq ! ( uri. to_string( ) , "http://localhost:80/?\
@@ -216,11 +262,38 @@ mod tests {
216
262
None ,
217
263
true ,
218
264
false ,
265
+ QuerySettingsConfig :: default ( ) ,
266
+ )
267
+ . unwrap ( ) ;
268
+ assert_eq ! ( uri. to_string( ) , "http://localhost:80/?\
269
+ input_format_import_nested_json=1&\
270
+ date_time_input_format=best_effort&\
271
+ query=INSERT+INTO+%22my_database%22.%22my_%5C%22table%5C%22%22+FORMAT+JSONAsObject") ;
272
+
273
+ let uri = set_uri_query (
274
+ & "http://localhost:80" . parse ( ) . unwrap ( ) ,
275
+ "my_database" ,
276
+ "my_\" table\" " ,
277
+ Format :: JsonAsObject ,
278
+ None ,
279
+ true ,
280
+ false ,
281
+ QuerySettingsConfig {
282
+ async_insert_settings : AsyncInsertSettingsConfig {
283
+ enabled : Some ( true ) ,
284
+ wait_for_processing : Some ( true ) ,
285
+ wait_for_processing_timeout : Some ( 500 ) ,
286
+ ..AsyncInsertSettingsConfig :: default ( )
287
+ } ,
288
+ } ,
219
289
)
220
290
. unwrap ( ) ;
221
291
assert_eq ! ( uri. to_string( ) , "http://localhost:80/?\
222
292
input_format_import_nested_json=1&\
223
293
date_time_input_format=best_effort&\
294
+ async_insert=1&\
295
+ wait_for_async_insert=1&\
296
+ wait_for_async_insert_timeout=500&\
224
297
query=INSERT+INTO+%22my_database%22.%22my_%5C%22table%5C%22%22+FORMAT+JSONAsObject") ;
225
298
}
226
299
@@ -234,6 +307,7 @@ mod tests {
234
307
Some ( false ) ,
235
308
false ,
236
309
false ,
310
+ QuerySettingsConfig :: default ( ) ,
237
311
)
238
312
. unwrap_err ( ) ;
239
313
}
0 commit comments