1#![expect(clippy::derive_partial_eq_without_eq)]
16#![warn(clippy::large_futures, clippy::large_stack_frames)]
17#![feature(coroutines)]
18#![feature(proc_macro_hygiene)]
19#![feature(stmt_expr_attributes)]
20#![feature(trait_alias)]
21#![feature(type_alias_impl_trait)]
22#![feature(associated_type_defaults)]
23#![feature(iter_from_coroutine)]
24#![feature(iterator_try_collect)]
25#![feature(try_blocks)]
26#![feature(error_generic_member_access)]
27#![feature(negative_impls)]
28#![feature(register_tool)]
29#![feature(never_type)]
30#![feature(map_try_insert)]
31#![register_tool(rw)]
32#![recursion_limit = "256"]
33#![feature(min_specialization)]
34#![feature(custom_inner_attributes)]
35#![feature(iter_array_chunks)]
36
37use std::time::Duration;
38
39use duration_str::parse_std;
40use serde::de;
41
42pub mod aws_utils;
43
44pub mod allow_alter_on_fly_fields;
45
46mod enforce_secret;
47pub mod error;
48mod macros;
49
50pub mod parser;
51pub mod schema;
52pub mod sink;
53pub mod source;
54
55pub mod connector_common;
56
57pub use paste::paste;
58pub use risingwave_jni_core::{call_method, call_static_method, jvm_runtime};
59
60mod with_options;
61pub use with_options::{Get, GetKeyIter, WithOptionsSecResolved, WithPropertiesExt};
62
63#[cfg(test)]
64mod with_options_test;
65
66pub const AUTO_SCHEMA_CHANGE_KEY: &str = "auto.schema.change";
67pub const SINK_CREATE_TABLE_IF_NOT_EXISTS_KEY: &str = "create_table_if_not_exists";
68pub const SINK_TARGET_TABLE_NAME: &str = "table.name";
69pub const SINK_INTERMEDIATE_TABLE_NAME: &str = "intermediate.table.name";
70
71pub(crate) fn deserialize_u32_from_string<'de, D>(deserializer: D) -> Result<u32, D::Error>
72where
73 D: de::Deserializer<'de>,
74{
75 let s: String = de::Deserialize::deserialize(deserializer)?;
76 s.parse().map_err(|_| {
77 de::Error::invalid_value(
78 de::Unexpected::Str(&s),
79 &"integer greater than or equal to 0",
80 )
81 })
82}
83
84pub(crate) fn deserialize_optional_string_seq_from_string<'de, D>(
85 deserializer: D,
86) -> std::result::Result<Option<Vec<String>>, D::Error>
87where
88 D: de::Deserializer<'de>,
89{
90 let s: Option<String> = de::Deserialize::deserialize(deserializer)?;
91 if let Some(s) = s {
92 let s = s.to_ascii_lowercase();
93 let s = s.split(',').map(|s| s.trim().to_owned()).collect();
94 Ok(Some(s))
95 } else {
96 Ok(None)
97 }
98}
99
100pub(crate) fn deserialize_optional_u64_seq_from_string<'de, D>(
101 deserializer: D,
102) -> std::result::Result<Option<Vec<u64>>, D::Error>
103where
104 D: de::Deserializer<'de>,
105{
106 let s: Option<String> = de::Deserialize::deserialize(deserializer)?;
107 if let Some(s) = s {
108 let numbers = s
109 .split(',')
110 .map(|s| s.trim().parse())
111 .collect::<Result<Vec<u64>, _>>()
112 .map_err(|_| de::Error::invalid_value(de::Unexpected::Str(&s), &"invalid number"));
113 Ok(Some(numbers?))
114 } else {
115 Ok(None)
116 }
117}
118
119pub(crate) fn deserialize_bool_from_string<'de, D>(deserializer: D) -> Result<bool, D::Error>
120where
121 D: de::Deserializer<'de>,
122{
123 let s: String = de::Deserialize::deserialize(deserializer)?;
124 let s = s.to_ascii_lowercase();
125 match s.as_str() {
126 "true" => Ok(true),
127 "false" => Ok(false),
128 _ => Err(de::Error::invalid_value(
129 de::Unexpected::Str(&s),
130 &"true or false",
131 )),
132 }
133}
134
135pub(crate) fn deserialize_optional_bool_from_string<'de, D>(
136 deserializer: D,
137) -> std::result::Result<Option<bool>, D::Error>
138where
139 D: de::Deserializer<'de>,
140{
141 let s: Option<String> = de::Deserialize::deserialize(deserializer)?;
142 if let Some(s) = s {
143 let s = s.to_ascii_lowercase();
144 match s.as_str() {
145 "true" => Ok(Some(true)),
146 "false" => Ok(Some(false)),
147 _ => Err(de::Error::invalid_value(
148 de::Unexpected::Str(&s),
149 &"true or false",
150 )),
151 }
152 } else {
153 Ok(None)
154 }
155}
156
157pub(crate) fn deserialize_duration_from_string<'de, D>(
158 deserializer: D,
159) -> Result<Duration, D::Error>
160where
161 D: de::Deserializer<'de>,
162{
163 let s: String = de::Deserialize::deserialize(deserializer)?;
164 parse_std(&s).map_err(|_| de::Error::invalid_value(
165 de::Unexpected::Str(&s),
166 &"The String value unit support for one of:[“y”,“mon”,“w”,“d”,“h”,“m”,“s”, “ms”, “µs”, “ns”]",
167 ))
168}
169
170pub(crate) fn deserialize_optional_duration_from_string<'de, D>(
171 deserializer: D,
172) -> Result<Option<Duration>, D::Error>
173where
174 D: de::Deserializer<'de>,
175{
176 let s: Option<String> = de::Deserialize::deserialize(deserializer)?;
177 if let Some(s) = s {
178 let duration = parse_std(&s).map_err(|_| de::Error::invalid_value(
179 de::Unexpected::Str(&s),
180 &"The String value unit support for one of:[“y”,“mon”,“w”,“d”,“h”,“m”,“s”, “ms”, “µs”, “ns”]",
181 ))?;
182 Ok(Some(duration))
183 } else {
184 Ok(None)
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use expect_test::expect_file;
191
192 use crate::with_options_test::{
193 generate_allow_alter_on_fly_fields_combined, generate_iceberg_engine_fields,
194 generate_with_options_yaml_connection, generate_with_options_yaml_sink,
195 generate_with_options_yaml_source,
196 };
197
198 #[test]
202 fn test_with_options_yaml_up_to_date() {
203 expect_file!("../with_options_source.yaml").assert_eq(&generate_with_options_yaml_source());
204
205 expect_file!("../with_options_sink.yaml").assert_eq(&generate_with_options_yaml_sink());
206
207 expect_file!("../with_options_connection.yaml")
208 .assert_eq(&generate_with_options_yaml_connection());
209 }
210
211 #[test]
213 fn test_allow_alter_on_fly_fields_rust_up_to_date() {
214 expect_file!("../src/allow_alter_on_fly_fields.rs")
215 .assert_eq(&generate_allow_alter_on_fly_fields_combined());
216 }
217
218 #[test]
220 fn test_iceberg_engine_fields_rust_up_to_date() {
221 expect_file!("../src/sink/iceberg/engine_options.rs")
222 .assert_eq(&generate_iceberg_engine_fields());
223 }
224
225 mod serde {
227 #![expect(dead_code)]
228
229 use std::collections::BTreeMap;
230
231 use expect_test::expect;
232 use serde::Deserialize;
233
234 #[test]
242 fn test_outer_deny() {
243 #[derive(Deserialize, Debug)]
244 #[serde(deny_unknown_fields)]
245 struct FlattenMap {
246 #[serde(flatten)]
247 flatten: BTreeMap<String, String>,
248 }
249 #[derive(Deserialize, Debug)]
250 #[serde(deny_unknown_fields)]
251 struct FlattenStruct {
252 #[serde(flatten)]
253 flatten_struct: Inner,
254 }
255
256 #[derive(Deserialize, Debug)]
257 #[serde(deny_unknown_fields)]
258 struct FlattenBoth {
259 #[serde(flatten)]
260 flatten: BTreeMap<String, String>,
261 #[serde(flatten)]
262 flatten_struct: Inner,
263 }
264
265 #[derive(Deserialize, Debug)]
266 struct Inner {
267 a: Option<String>,
268 b: Option<String>,
269 }
270
271 let json = r#"{
272 "a": "b"
273 }"#;
274 let foo: Result<FlattenMap, _> = serde_json::from_str(json);
275 let foo1: Result<FlattenStruct, _> = serde_json::from_str(json);
276 let foo2: Result<FlattenBoth, _> = serde_json::from_str(json);
277
278 expect![[r#"
280 Err(
281 Error("unknown field `a`", line: 3, column: 13),
282 )
283 "#]]
284 .assert_debug_eq(&foo);
285
286 expect![[r#"
288 Ok(
289 FlattenStruct {
290 flatten_struct: Inner {
291 a: Some(
292 "b",
293 ),
294 b: None,
295 },
296 },
297 )
298 "#]]
299 .assert_debug_eq(&foo1);
300 let foo11: Result<FlattenStruct, _> =
302 serde_json::from_str(r#"{ "a": "b", "unknown":1 }"#);
303 expect_test::expect![[r#"
304 Err(
305 Error("unknown field `unknown`", line: 1, column: 25),
306 )
307 "#]]
308 .assert_debug_eq(&foo11);
309
310 expect![[r#"
312 Ok(
313 FlattenBoth {
314 flatten: {
315 "a": "b",
316 },
317 flatten_struct: Inner {
318 a: Some(
319 "b",
320 ),
321 b: None,
322 },
323 },
324 )
325 "#]]
326 .assert_debug_eq(&foo2);
327
328 let foo21: Result<FlattenBoth, _> =
329 serde_json::from_str(r#"{ "a": "b", "unknown":1 }"#);
330 expect_test::expect![[r#"
331 Err(
332 Error("invalid type: integer `1`, expected a string", line: 1, column: 25),
333 )
334 "#]]
335 .assert_debug_eq(&foo21);
336 let foo22: Result<FlattenBoth, _> =
338 serde_json::from_str(r#"{ "a": "b", "unknown":"1" }"#);
339 expect_test::expect![[r#"
340 Err(
341 Error("unknown field `unknown`", line: 1, column: 27),
342 )
343 "#]]
344 .assert_debug_eq(&foo22);
345 }
346
347 #[test]
348 fn test_inner_deny() {
349 #[derive(Deserialize, Debug)]
351 struct FlattenStruct {
352 #[serde(flatten)]
353 flatten_struct: Inner,
354 }
355 #[derive(Deserialize, Debug)]
356 #[serde(deny_unknown_fields)]
357 struct Inner {
358 a: Option<String>,
359 b: Option<String>,
360 }
361
362 let json = r#"{
363 "a": "b", "unknown":1
364 }"#;
365 let foo: Result<FlattenStruct, _> = serde_json::from_str(json);
366 expect_test::expect![[r#"
370 Ok(
371 FlattenStruct {
372 flatten_struct: Inner {
373 a: Some(
374 "b",
375 ),
376 b: None,
377 },
378 },
379 )
380 "#]]
381 .assert_debug_eq(&foo);
382 }
383
384 #[test]
385 fn test_multiple_flatten() {
386 #[derive(Deserialize, Debug)]
387 struct Foo {
388 #[serde(flatten)]
390 flatten_struct: Inner1,
391
392 #[serde(flatten)]
394 flatten_map1: BTreeMap<String, String>,
395
396 #[serde(flatten)]
397 flatten_map2: BTreeMap<String, String>,
398
399 #[serde(flatten)]
400 flatten_struct2: Inner2,
401 }
402
403 #[derive(Deserialize, Debug)]
404 #[serde(deny_unknown_fields)]
405 struct Inner1 {
406 a: Option<String>,
407 b: Option<String>,
408 }
409 #[derive(Deserialize, Debug)]
410 struct Inner11 {
411 c: Option<String>,
412 }
413 #[derive(Deserialize, Debug)]
414 #[serde(deny_unknown_fields)]
415 struct Inner2 {
416 c: Option<String>,
417 }
418
419 let json = r#"{
420 "a": "b", "c":"d"
421 }"#;
422 let foo2: Result<Foo, _> = serde_json::from_str(json);
423
424 expect![[r#"
427 Ok(
428 Foo {
429 flatten_struct: Inner1 {
430 a: Some(
431 "b",
432 ),
433 b: None,
434 },
435 flatten_map1: {
436 "c": "d",
437 },
438 flatten_map2: {
439 "c": "d",
440 },
441 flatten_struct2: Inner2 {
442 c: Some(
443 "d",
444 ),
445 },
446 },
447 )
448 "#]]
449 .assert_debug_eq(&foo2);
450 }
451
452 #[test]
453 fn test_nested_flatten() {
454 #[derive(Deserialize, Debug)]
455 #[serde(deny_unknown_fields)]
456 struct Outer {
457 #[serde(flatten)]
458 inner: Inner,
459 }
460
461 #[derive(Deserialize, Debug)]
462 struct Inner {
463 a: Option<String>,
464 b: Option<String>,
465 #[serde(flatten)]
466 nested: InnerInner,
467 }
468
469 #[derive(Deserialize, Debug)]
470 struct InnerInner {
471 c: Option<String>,
472 }
473
474 let json = r#"{ "a": "b", "unknown":"1" }"#;
475
476 let foo: Result<Outer, _> = serde_json::from_str(json);
477
478 expect_test::expect![[r#"
480 Err(
481 Error("unknown field `a`", line: 1, column: 27),
482 )
483 "#]]
484 .assert_debug_eq(&foo);
485
486 #[derive(Deserialize, Debug)]
489 struct Outer2 {
490 #[serde(flatten)]
491 inner: Inner,
492 #[serde(flatten)]
494 map: BTreeMap<String, String>,
495 }
496 let foo2: Result<Outer2, _> = serde_json::from_str(json);
497 expect_test::expect![[r#"
498 Ok(
499 Outer2 {
500 inner: Inner {
501 a: Some(
502 "b",
503 ),
504 b: None,
505 nested: InnerInner {
506 c: None,
507 },
508 },
509 map: {
510 "a": "b",
511 "unknown": "1",
512 },
513 },
514 )
515 "#]]
516 .assert_debug_eq(&foo2);
517 }
518
519 #[test]
520 fn test_flatten_option() {
521 #[derive(Deserialize, Debug)]
522 struct Foo {
523 #[serde(flatten)]
525 flatten_struct: Option<Inner1>,
526
527 #[serde(flatten)]
529 flatten_map1: Option<BTreeMap<String, String>>,
530
531 #[serde(flatten)]
533 flatten_struct2: Option<Inner2>,
534
535 #[serde(flatten)]
538 flatten_struct3: Option<Inner3>,
539 }
540
541 #[derive(Deserialize, Debug)]
542 struct Inner1 {
543 a: Option<String>,
544 b: Option<String>,
545 }
546 #[derive(Deserialize, Debug)]
547 struct Inner11 {
548 c: Option<String>,
549 }
550
551 #[derive(Deserialize, Debug)]
552 struct Inner2 {
553 c: Option<String>,
554 d: String,
555 }
556
557 #[derive(Deserialize, Debug)]
558 struct Inner3 {
559 e: Option<String>,
560 f: String,
561 }
562
563 let json = r#"{
564 "a": "b", "c": "d", "f": "g"
565 }"#;
566 let foo: Result<Foo, _> = serde_json::from_str(json);
567 expect![[r#"
568 Ok(
569 Foo {
570 flatten_struct: Some(
571 Inner1 {
572 a: Some(
573 "b",
574 ),
575 b: None,
576 },
577 ),
578 flatten_map1: Some(
579 {
580 "c": "d",
581 "f": "g",
582 },
583 ),
584 flatten_struct2: None,
585 flatten_struct3: Some(
586 Inner3 {
587 e: None,
588 f: "g",
589 },
590 ),
591 },
592 )
593 "#]]
594 .assert_debug_eq(&foo);
595 }
596 }
597}