1pub mod kafka;
16pub mod object_store;
17
18use serde::{Deserialize, Serialize};
19use serde_with::with_prefix;
20
21pub use crate::options::kafka::KafkaWalOptions;
22pub use crate::options::object_store::ObjectStoreWalOptions;
23
24pub const WAL_OPTIONS_KEY: &str = "wal_options";
27
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
32#[serde(tag = "wal.provider", rename_all = "snake_case")]
33pub enum WalOptions {
34 #[default]
35 RaftEngine,
36 #[serde(with = "kafka_prefix")]
37 Kafka(KafkaWalOptions),
38 Noop,
39 #[serde(with = "object_store_prefix")]
40 ObjectStore(ObjectStoreWalOptions),
41}
42
43with_prefix!(kafka_prefix "wal.kafka.");
44with_prefix!(object_store_prefix "wal.object_store.");
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn test_serde_wal_options() {
52 let wal_options = WalOptions::RaftEngine;
54 let encoded = serde_json::to_string(&wal_options).unwrap();
55 let expected = r#"{"wal.provider":"raft_engine"}"#;
56 assert_eq!(&encoded, expected);
57
58 let decoded: WalOptions = serde_json::from_str(&encoded).unwrap();
59 assert_eq!(decoded, wal_options);
60
61 let wal_options = WalOptions::Kafka(KafkaWalOptions::new("test_topic".to_string()));
63 let encoded = serde_json::to_string(&wal_options).unwrap();
64 let expected = r#"{"wal.provider":"kafka","wal.kafka.topic":"test_topic"}"#;
65 assert_eq!(&encoded, expected);
66
67 let decoded: WalOptions = serde_json::from_str(&encoded).unwrap();
68 assert_eq!(decoded, wal_options);
69
70 let wal_options = WalOptions::Kafka(KafkaWalOptions {
71 topic: "test_topic".to_string(),
72 initial_pruned_entry_id: Some(42),
73 });
74 let encoded = serde_json::to_string(&wal_options).unwrap();
75 let expected = r#"{"wal.provider":"kafka","wal.kafka.topic":"test_topic","wal.kafka.initial_pruned_entry_id":42}"#;
76 assert_eq!(&encoded, expected);
77
78 let decoded: WalOptions = serde_json::from_str(&encoded).unwrap();
79 assert_eq!(decoded, wal_options);
80
81 let decoded: WalOptions =
82 serde_json::from_str(r#"{"wal.provider":"kafka","wal.kafka.topic":"test_topic"}"#)
83 .unwrap();
84 assert_eq!(
85 decoded,
86 WalOptions::Kafka(KafkaWalOptions::new("test_topic".to_string()))
87 );
88
89 let wal_options = WalOptions::Noop;
91 let encoded = serde_json::to_string(&wal_options).unwrap();
92 let expected = r#"{"wal.provider":"noop"}"#;
93 assert_eq!(&encoded, expected);
94
95 let decoded: WalOptions = serde_json::from_str(&encoded).unwrap();
96 assert_eq!(decoded, wal_options);
97
98 let wal_options = WalOptions::ObjectStore(ObjectStoreWalOptions::new("wal".to_string()));
99 let encoded = serde_json::to_string(&wal_options).unwrap();
100 let expected = r#"{"wal.provider":"object_store","wal.object_store.prefix":"wal"}"#;
101 assert_eq!(&encoded, expected);
102
103 let decoded: WalOptions = serde_json::from_str(&encoded).unwrap();
104 assert_eq!(decoded, wal_options);
105 }
106
107 #[test]
108 fn test_decode_persisted_wal_options() {
109 let cases = [
110 (r#"{"wal.provider":"raft_engine"}"#, WalOptions::RaftEngine),
111 (
112 r#"{"wal.provider":"kafka","wal.kafka.topic":"test_topic"}"#,
113 WalOptions::Kafka(KafkaWalOptions::new("test_topic".to_string())),
114 ),
115 (r#"{"wal.provider":"noop"}"#, WalOptions::Noop),
116 (
117 r#"{"wal.provider":"object_store","wal.object_store.prefix":"wal"}"#,
118 WalOptions::ObjectStore(ObjectStoreWalOptions::new("wal".to_string())),
119 ),
120 ];
121 for (encoded, expected) in cases {
122 let decoded: WalOptions = serde_json::from_str(encoded).unwrap();
123 assert_eq!(decoded, expected);
124 }
125
126 assert!(serde_json::from_str::<WalOptions>(r#"{"wal.provider":"unknown"}"#).is_err());
127 assert!(serde_json::from_str::<WalOptions>(r#"{"wal.provider":"object_store"}"#).is_err());
128 }
129}