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