faucet_sink_jsonl/
config.rs1use std::path::PathBuf;
4
5use faucet_core::DEFAULT_BATCH_SIZE;
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
11pub struct JsonlSinkConfig {
12 pub path: PathBuf,
14 #[serde(default)]
16 pub append: bool,
17 #[serde(default)]
19 pub pretty: bool,
20 #[serde(default = "default_batch_size")]
31 pub batch_size: usize,
32 #[cfg(feature = "compression")]
37 #[serde(default)]
38 pub compression: faucet_core::CompressionConfig,
39 #[cfg(feature = "encryption")]
46 #[serde(default, skip_serializing_if = "Option::is_none")]
47 pub encryption: Option<faucet_core::EncryptionSpec>,
48}
49
50fn default_batch_size() -> usize {
51 DEFAULT_BATCH_SIZE
52}
53
54impl JsonlSinkConfig {
55 pub fn new(path: impl Into<PathBuf>) -> Self {
57 Self {
58 path: path.into(),
59 append: false,
60 pretty: false,
61 batch_size: DEFAULT_BATCH_SIZE,
62 #[cfg(feature = "compression")]
63 compression: faucet_core::CompressionConfig::Auto,
64 #[cfg(feature = "encryption")]
65 encryption: None,
66 }
67 }
68
69 pub fn append(mut self, append: bool) -> Self {
71 self.append = append;
72 self
73 }
74
75 pub fn pretty(mut self, pretty: bool) -> Self {
78 self.pretty = pretty;
79 self
80 }
81
82 #[cfg(feature = "compression")]
84 pub fn compression(mut self, c: faucet_core::CompressionConfig) -> Self {
85 self.compression = c;
86 self
87 }
88
89 #[cfg(feature = "encryption")]
92 pub fn encryption(mut self, e: faucet_core::EncryptionSpec) -> Self {
93 self.encryption = Some(e);
94 self
95 }
96
97 pub fn with_batch_size(mut self, batch_size: usize) -> Self {
106 self.batch_size = batch_size;
107 self
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn default_config() {
117 let config = JsonlSinkConfig::new("/tmp/out.jsonl");
118 assert_eq!(config.path, PathBuf::from("/tmp/out.jsonl"));
119 assert!(!config.append);
120 assert!(!config.pretty);
121 }
122
123 #[test]
124 fn builder_methods() {
125 let config = JsonlSinkConfig::new("/tmp/out.jsonl")
126 .append(true)
127 .pretty(true);
128 assert!(config.append);
129 assert!(config.pretty);
130 }
131
132 #[test]
133 fn batch_size_defaults_to_default_batch_size() {
134 let config = JsonlSinkConfig::new("/tmp/out.jsonl");
135 assert_eq!(config.batch_size, faucet_core::DEFAULT_BATCH_SIZE);
136 }
137
138 #[test]
139 fn with_batch_size_overrides_default() {
140 let config = JsonlSinkConfig::new("/tmp/out.jsonl").with_batch_size(250);
141 assert_eq!(config.batch_size, 250);
142 }
143
144 #[test]
145 fn batch_size_zero_is_accepted_as_no_batching_sentinel() {
146 let config = JsonlSinkConfig::new("/tmp/out.jsonl").with_batch_size(0);
147 assert_eq!(config.batch_size, 0);
148 assert!(faucet_core::validate_batch_size(config.batch_size).is_ok());
149 }
150
151 #[test]
152 fn batch_size_above_max_is_rejected_by_validate_batch_size() {
153 let config =
154 JsonlSinkConfig::new("/tmp/out.jsonl").with_batch_size(faucet_core::MAX_BATCH_SIZE + 1);
155 assert!(faucet_core::validate_batch_size(config.batch_size).is_err());
156 }
157
158 #[test]
159 fn batch_size_deserializes_from_json() {
160 let json = r#"{
161 "path": "/tmp/out.jsonl",
162 "append": false,
163 "pretty": false,
164 "batch_size": 500
165 }"#;
166 let config: JsonlSinkConfig = serde_json::from_str(json).unwrap();
167 assert_eq!(config.batch_size, 500);
168 }
169
170 #[test]
171 fn batch_size_defaults_when_missing_in_json() {
172 let json = r#"{"path": "/tmp/out.jsonl"}"#;
173 let config: JsonlSinkConfig = serde_json::from_str(json).unwrap();
174 assert_eq!(config.batch_size, faucet_core::DEFAULT_BATCH_SIZE);
175 }
176}