Skip to main content

live_feed/
builder.rs

1//! Builders for [`FeedDescriptor`] and [`FeedManifest`].
2
3use live_data::{
4    Capabilities, FeedDescriptor, FeedManifest, FormatPreference, TransportTag, WireSchema,
5};
6
7use crate::validate::{ValidationError, validate_descriptor};
8
9/// Builder for a [`FeedDescriptor`].
10#[derive(Debug, Clone)]
11pub struct FeedDescriptorBuilder {
12    name: String,
13    schema: WireSchema,
14    transports: Vec<TransportTag>,
15    formats: Vec<FormatPreference>,
16    capabilities: Capabilities,
17    event_time_key: Option<String>,
18    tags: Vec<String>,
19    description: Option<String>,
20}
21
22impl FeedDescriptorBuilder {
23    pub fn new(name: impl Into<String>, schema: WireSchema) -> Self {
24        Self {
25            name: name.into(),
26            schema,
27            transports: Vec::new(),
28            formats: Vec::new(),
29            capabilities: Capabilities::minimal(),
30            event_time_key: None,
31            tags: Vec::new(),
32            description: None,
33        }
34    }
35
36    /// Add a single transport. Duplicate calls with the same tag are
37    /// idempotent.
38    pub fn transport(mut self, t: TransportTag) -> Self {
39        if !self.transports.contains(&t) {
40            self.transports.push(t);
41        }
42        self
43    }
44
45    pub fn transports<I: IntoIterator<Item = TransportTag>>(mut self, ts: I) -> Self {
46        for t in ts {
47            self = self.transport(t);
48        }
49        self
50    }
51
52    pub fn format(mut self, f: FormatPreference) -> Self {
53        if !self.formats.contains(&f) {
54            self.formats.push(f);
55        }
56        self
57    }
58
59    pub fn formats<I: IntoIterator<Item = FormatPreference>>(mut self, fs: I) -> Self {
60        for f in fs {
61            self = self.format(f);
62        }
63        self
64    }
65
66    pub fn capabilities(mut self, c: Capabilities) -> Self {
67        self.capabilities = c;
68        self
69    }
70
71    pub fn event_time_key(mut self, k: impl Into<String>) -> Self {
72        self.event_time_key = Some(k.into());
73        self
74    }
75
76    pub fn tag(mut self, t: impl Into<String>) -> Self {
77        let t = t.into();
78        if !self.tags.contains(&t) {
79            self.tags.push(t);
80        }
81        self
82    }
83
84    pub fn description(mut self, d: impl Into<String>) -> Self {
85        self.description = Some(d.into());
86        self
87    }
88
89    /// Validate and produce the descriptor.
90    pub fn build(self) -> Result<FeedDescriptor, ValidationError> {
91        let descriptor = FeedDescriptor {
92            name: self.name,
93            schema: self.schema,
94            transports: self.transports,
95            formats: self.formats,
96            capabilities: self.capabilities,
97            event_time_key: self.event_time_key,
98            tags: self.tags,
99            description: self.description,
100        };
101        validate_descriptor(&descriptor)?;
102        Ok(descriptor)
103    }
104}
105
106/// Builder for a [`FeedManifest`].
107///
108/// Manifests track insertion order so the consumer sees feeds in the
109/// order the publisher declared them.
110#[derive(Debug, Clone)]
111pub struct FeedManifestBuilder {
112    server_version: String,
113    feeds: Vec<FeedDescriptor>,
114}
115
116impl FeedManifestBuilder {
117    pub fn new(server_version: impl Into<String>) -> Self {
118        Self { server_version: server_version.into(), feeds: Vec::new() }
119    }
120
121    pub fn feed(mut self, d: FeedDescriptor) -> Self {
122        self.feeds.push(d);
123        self
124    }
125
126    pub fn feeds<I: IntoIterator<Item = FeedDescriptor>>(mut self, ds: I) -> Self {
127        for d in ds {
128            self.feeds.push(d);
129        }
130        self
131    }
132
133    pub fn build(self) -> FeedManifest {
134        FeedManifest::new(self.server_version, self.feeds)
135    }
136}