datafusion_delta_sharing/securable.rs
1//! Delta Sharing shared object types
2
3use std::{fmt::Display, str::FromStr};
4
5use serde::{Deserialize, Serialize};
6
7use crate::error::DeltaSharingError;
8
9/// The type of a share as defined in the Delta Sharing protocol.
10///
11/// A share is a logical grouping to share with recipients. A share can be
12/// shared with one or multiple recipients. A recipient can access all
13/// resources in a share. A share may contain multiple schemas.
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
15#[serde(rename_all = "camelCase")]
16pub struct Share {
17 name: String,
18 id: Option<String>,
19}
20
21impl Share {
22 /// Create a new `Share` with the given `name` and `id`.
23 pub fn new<S: Into<String>>(name: S, id: Option<S>) -> Self {
24 Self {
25 name: name.into(),
26 id: id.map(Into::into),
27 }
28 }
29
30 /// Retrieve the name from `self`.
31 ///
32 /// # Example
33 ///
34 /// ```rust
35 /// use datafusion_delta_sharing::securable::Share;
36 ///
37 /// let share = Share::new("my-share", None);
38 /// assert_eq!(share.name(), "my-share");
39 /// ```
40 pub fn name(&self) -> &str {
41 self.name.as_ref()
42 }
43
44 /// Retrieve the id from `self`.
45 ///
46 /// # Example
47 ///
48 /// ```rust
49 /// use datafusion_delta_sharing::securable::Share;
50 ///
51 /// let share = Share::new("my-share", Some("my-share-id"));
52 /// assert_eq!(share.id(), Some("my-share-id"));
53 /// ```
54 pub fn id(&self) -> Option<&str> {
55 self.id.as_deref()
56 }
57}
58
59impl Display for Share {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 write!(f, "{}", self.name())
62 }
63}
64
65impl FromStr for Share {
66 type Err = DeltaSharingError;
67
68 fn from_str(s: &str) -> Result<Self, Self::Err> {
69 Ok(Share::new(s, None))
70 }
71}
72
73/// The type of a schema as defined in the Delta Sharing protocol.
74///
75/// A schema is a logical grouping of tables. A schema may contain multiple
76/// tables. A schema is defined within the context of a [`Share`].
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
78#[serde(rename_all = "camelCase")]
79pub struct Schema {
80 share: String,
81 name: String,
82}
83
84impl Schema {
85 /// Create a new `Schema` with the given [`Share`], `name` and `id`.
86 pub fn new(share_name: impl Into<String>, schema_name: impl Into<String>) -> Self {
87 Self {
88 share: share_name.into(),
89 name: schema_name.into(),
90 }
91 }
92
93 /// Returns the name of the share associated with `self`
94 ///
95 /// # Example
96 ///
97 /// ```rust
98 /// use datafusion_delta_sharing::securable::{Share, Schema};
99 ///
100 /// let schema = Schema::new("my-share", "my-schema");
101 /// assert_eq!(schema.share_name(), "my-share");
102 /// ```
103 pub fn share_name(&self) -> &str {
104 self.share.as_ref()
105 }
106
107 /// Returns the name of `self`
108 ///
109 /// # Example
110 ///
111 /// ```rust
112 /// use datafusion_delta_sharing::securable::{Schema};
113 ///
114 /// let schema = Schema::new("my-share", "my-schema");
115 /// assert_eq!(schema.name(), "my-schema");
116 /// ```
117 pub fn name(&self) -> &str {
118 self.name.as_ref()
119 }
120}
121
122impl Display for Schema {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 write!(f, "{}.{}", self.share_name(), self.name())
125 }
126}
127
128impl FromStr for Schema {
129 type Err = DeltaSharingError;
130
131 fn from_str(s: &str) -> Result<Self, Self::Err> {
132 let parts = s.split('.').collect::<Vec<_>>();
133 if parts.len() == 2 {
134 Ok(Schema::new(parts[0], parts[1]))
135 } else {
136 Err(DeltaSharingError::parse_securable(
137 "Schema must be of the form <share>.<schema>",
138 ))
139 }
140 }
141}
142
143/// The type of a table as defined in the Delta Sharing protocol.
144///
145/// A table is a Delta Lake table or a view on top of a Delta Lake table. A
146/// table is defined within the context of a [`Schema`].
147#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
148#[serde(rename_all = "camelCase")]
149pub struct Table {
150 name: String,
151 schema: String,
152 share: String,
153 share_id: Option<String>,
154 id: Option<String>,
155}
156
157impl Table {
158 /// Create a new `Table` with the given [`Schema`], `name`, `storage_path`,
159 /// `table_id` and `table_format`. Whenever the `table_id` is `None`, it
160 /// will default to `DELTA`
161 pub fn new(
162 share_name: impl Into<String>,
163 schema_name: impl Into<String>,
164 table_name: impl Into<String>,
165 share_id: Option<String>,
166 table_id: Option<String>,
167 ) -> Self {
168 Self {
169 name: table_name.into(),
170 schema: schema_name.into(),
171 share: share_name.into(),
172 share_id,
173 id: table_id,
174 }
175 }
176
177 /// Returns the name of the share associated with `self`
178 ///
179 /// # Example
180 ///
181 /// ```rust
182 /// use datafusion_delta_sharing::securable::{Share, Schema, Table};
183 ///
184 /// let table = Table::new("my-share", "my-schema", "my-table", None, None);
185 /// assert_eq!(table.share_name(), "my-share");
186 /// ```
187 pub fn share_name(&self) -> &str {
188 self.share.as_ref()
189 }
190
191 /// Returns the id of the share associated with `self`
192 ///
193 /// # Example
194 ///
195 /// ```rust
196 /// use datafusion_delta_sharing::securable::{Share, Schema, Table};
197 ///
198 /// let table = Table::new("my-share", "my-schema", "my-table", Some("my-share-id".to_string()), None);
199 /// assert_eq!(table.share_id(), Some("my-share-id"));
200 /// ```
201 pub fn share_id(&self) -> Option<&str> {
202 self.share_id.as_deref()
203 }
204
205 /// Returns the name of the schema associated with `self`
206 ///
207 /// # Example
208 ///
209 /// ```rust
210 /// use datafusion_delta_sharing::securable::{Share, Schema, Table};
211 ///
212 /// let table = Table::new("my-share", "my-schema", "my-table", None, None);
213 /// assert_eq!(table.schema_name(), "my-schema");
214 /// ```
215 pub fn schema_name(&self) -> &str {
216 self.schema.as_ref()
217 }
218
219 /// Returns the name of `self`
220 ///
221 /// # Example
222 ///
223 /// ```rust
224 /// use datafusion_delta_sharing::securable::{Share, Schema, Table};
225 ///
226 /// let table = Table::new("my-share", "my-schema", "my-table", None, None);
227 /// assert_eq!(table.name(), "my-table");
228 /// ```
229 pub fn name(&self) -> &str {
230 self.name.as_ref()
231 }
232
233 /// Returns the id of `self`
234 ///
235 /// # Example
236 ///
237 /// ```rust
238 /// use datafusion_delta_sharing::securable::{Share, Schema, Table};
239 ///
240 /// let table = Table::new("my-share", "my-schema", "my-table", None, Some("my-table-id".to_string()));
241 /// assert_eq!(table.id(), Some("my-table-id"));
242 /// ```
243 pub fn id(&self) -> Option<&str> {
244 self.id.as_deref()
245 }
246}
247
248impl Display for Table {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 write!(
251 f,
252 "{}.{}.{}",
253 self.share_name(),
254 self.schema_name(),
255 self.name()
256 )
257 }
258}
259
260impl FromStr for Table {
261 type Err = DeltaSharingError;
262
263 fn from_str(s: &str) -> Result<Self, Self::Err> {
264 let parts = s.split('.').collect::<Vec<_>>();
265 if parts.len() == 3 {
266 Ok(Table::new(parts[0], parts[1], parts[2], None, None))
267 } else {
268 Err(DeltaSharingError::parse_securable(
269 "Table must be of the form <share>.<schema>.<table>",
270 ))
271 }
272 }
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 #[test]
280 fn display_share() {
281 let share = Share::new("share", Some("id"));
282 assert_eq!(format!("{}", share), "share");
283 }
284
285 #[test]
286 fn parse_share() {
287 let share = "share".parse::<Share>().unwrap();
288 assert_eq!(share, Share::new("share", None));
289 }
290
291 #[test]
292 fn display_schema() {
293 let schema = Schema::new("share", "schema");
294 assert_eq!(format!("{}", schema), "share.schema");
295 }
296
297 #[test]
298 fn parse_schema() {
299 let schema = "share.schema".parse::<Schema>().unwrap();
300 assert_eq!(schema, Schema::new("share", "schema"));
301 }
302
303 #[test]
304 fn display_table() {
305 let table = Table::new("share", "schema", "table", None, None);
306 assert_eq!(format!("{}", table), "share.schema.table");
307 }
308
309 #[test]
310 fn parse_table() {
311 let table = "share.schema.table".parse::<Table>().unwrap();
312 assert_eq!(table, Table::new("share", "schema", "table", None, None));
313 }
314}