Skip to main content

datafusion_odata/
metadata.rs

1// <edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" Version="1.0">
2//   <edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="1.0" m:MaxDataServiceVersion="3.0">
3//     <Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm" Namespace="NorthwindModel">
4//       <EntityType Name="Employee">
5//         <Key>
6//           <PropertyRef Name="EmployeeID"/>
7//         </Key>
8//         <Property Name="LastName" Type="Edm.String" Nullable="false" MaxLength="20" FixedLength="false" Unicode="true"/>
9
10use datafusion::arrow::datatypes::DataType;
11
12use crate::error::UnsupportedDataType;
13
14#[derive(Debug, serde::Serialize)]
15pub struct Edmx {
16    #[serde(rename = "edmx:DataServices")]
17    pub ds: DataServices,
18    #[serde(rename = "@xmlns:edmx")]
19    pub ns_edmx: String,
20    #[serde(rename = "@Version")]
21    pub version: String,
22}
23
24impl Edmx {
25    pub fn new(ds: DataServices) -> Self {
26        Self {
27            ds,
28            ns_edmx: "http://schemas.microsoft.com/ado/2007/06/edmx".to_string(),
29            version: "1.0".to_string(),
30        }
31    }
32}
33
34#[derive(Debug, serde::Serialize)]
35pub struct DataServices {
36    #[serde(rename = "Schema")]
37    pub schemas: Vec<Schema>,
38    #[serde(rename = "@xmlns:m")]
39    pub ns_m: String,
40    #[serde(rename = "@m:DataServiceVersion")]
41    pub version: String,
42    #[serde(rename = "@m:MaxDataServiceVersion")]
43    pub max_version: String,
44}
45
46impl DataServices {
47    pub fn new(schemas: Vec<Schema>) -> Self {
48        Self {
49            schemas,
50            ns_m: "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata".to_string(),
51            version: "3.0".to_string(),
52            max_version: "3.0".to_string(),
53        }
54    }
55}
56
57#[derive(Debug, serde::Serialize)]
58pub struct Schema {
59    #[serde(rename = "@Namespace")]
60    pub namespace: String,
61    #[serde(rename = "EntityType")]
62    pub entity_types: Vec<EntityType>,
63    #[serde(rename = "EntityContainer")]
64    pub entity_containers: Vec<EntityContainer>,
65    #[serde(rename = "@xmlns")]
66    pub ns: String,
67}
68
69impl Schema {
70    pub fn new(
71        namespace: String,
72        entity_types: Vec<EntityType>,
73        entity_containers: Vec<EntityContainer>,
74    ) -> Self {
75        Self {
76            namespace,
77            entity_types,
78            entity_containers,
79            ns: "http://schemas.microsoft.com/ado/2009/11/edm".to_string(),
80        }
81    }
82}
83
84#[derive(Debug, serde::Serialize)]
85pub struct EntityType {
86    #[serde(rename = "@Name")]
87    pub name: String,
88    #[serde(rename = "Key")]
89    pub key: EntityKey,
90    #[serde(rename = "Property")]
91    pub properties: Vec<Property>,
92}
93
94#[derive(Debug, serde::Serialize)]
95pub struct EntityKey {
96    #[serde(rename = "PropertyRef")]
97    key: Vec<PropertyRef>,
98}
99
100impl EntityKey {
101    pub fn new(key: Vec<PropertyRef>) -> Self {
102        Self { key }
103    }
104}
105
106#[derive(Debug, serde::Serialize)]
107pub struct PropertyRef {
108    #[serde(rename = "@Name")]
109    pub name: String,
110}
111
112/// See: https://www.odata.org/documentation/odata-version-3-0/common-schema-definition-language-csdl/
113#[derive(Debug, serde::Serialize)]
114pub struct Property {
115    #[serde(rename = "@Name")]
116    pub name: String,
117    #[serde(rename = "@Type")]
118    pub typ: String,
119    #[serde(rename = "@Nullable")]
120    pub nullable: bool,
121    #[serde(rename = "@FixedLength")]
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub fixed_length: Option<bool>,
124    #[serde(rename = "@Unicode")]
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub unicode: Option<bool>,
127}
128
129impl Property {
130    pub fn primitive(name: impl Into<String>, typ: impl Into<String>, nullable: bool) -> Self {
131        Self {
132            name: name.into(),
133            typ: typ.into(),
134            nullable,
135            fixed_length: None,
136            unicode: None,
137        }
138    }
139
140    pub fn string(name: impl Into<String>, typ: impl Into<String>, nullable: bool) -> Self {
141        Self {
142            name: name.into(),
143            typ: typ.into(),
144            nullable,
145            fixed_length: Some(false),
146            unicode: Some(true),
147        }
148    }
149}
150
151// <EntityContainer Name="DemoService" m:IsDefaultEntityContainer="true">
152//   <EntitySet Name="Products" EntityType="ODataDemo.Product"/>
153
154#[derive(Debug, serde::Serialize)]
155pub struct EntityContainer {
156    #[serde(rename = "@Name")]
157    pub name: String,
158    #[serde(rename = "@m:IsDefaultEntityContainer")]
159    pub is_default: bool,
160    #[serde(rename = "EntitySet")]
161    pub entity_set: Vec<EntitySet>,
162}
163
164#[derive(Debug, serde::Serialize)]
165pub struct EntitySet {
166    #[serde(rename = "@Name")]
167    pub name: String,
168    #[serde(rename = "@EntityType")]
169    pub entity_type: String,
170}
171
172///////////////////////////////////////////////////////////////////////////////
173
174// See: https://www.odata.org/documentation/odata-version-3-0/common-schema-definition-language-csdl/
175pub fn to_edm_type(dt: &DataType) -> std::result::Result<&'static str, UnsupportedDataType> {
176    match dt {
177        DataType::Boolean => Ok("Edm.Boolean"),
178        // TODO: Use Edm.Byte / Edm.SByte?
179        DataType::Int8 => Ok("Edm.Int16"),
180        DataType::Int16 => Ok("Edm.Int16"),
181        DataType::Int32 => Ok("Edm.Int32"),
182        DataType::Int64 => Ok("Edm.Int64"),
183        // TODO: Use Edm.Byte / Edm.SByte?
184        DataType::UInt8 => Ok("Edm.Int16"),
185        DataType::UInt16 => Ok("Edm.Int16"),
186        DataType::UInt32 => Ok("Edm.Int32"),
187        DataType::UInt64 => Ok("Edm.Int64"),
188        DataType::Utf8 | DataType::Utf8View => Ok("Edm.String"),
189        DataType::LargeUtf8 => Ok("Edm.String"),
190        DataType::Float16 => Ok("Edm.Single"),
191        DataType::Float32 => Ok("Edm.Single"),
192        DataType::Float64 => Ok("Edm.Double"),
193        DataType::Timestamp(_, None) => Ok("Edm.DateTime"),
194        DataType::Timestamp(_, Some(_)) => Ok("Edm.DateTimeOffset"),
195        DataType::Date32 => Ok("Edm.DateTime"),
196        DataType::Date64 => Ok("Edm.DateTime"),
197        DataType::Null
198        | DataType::Time32(_)
199        | DataType::Time64(_)
200        | DataType::Duration(_)
201        | DataType::Interval(_)
202        | DataType::Binary
203        | DataType::BinaryView
204        | DataType::FixedSizeBinary(_)
205        | DataType::LargeBinary
206        | DataType::List(_)
207        | DataType::FixedSizeList(_, _)
208        | DataType::LargeList(_)
209        | DataType::ListView(_)
210        | DataType::LargeListView(_)
211        | DataType::Struct(_)
212        | DataType::Union(_, _)
213        | DataType::Dictionary(_, _)
214        | DataType::Decimal32(_, _)
215        | DataType::Decimal64(_, _)
216        | DataType::Decimal128(_, _)
217        | DataType::Decimal256(_, _)
218        | DataType::Map(_, _)
219        | DataType::RunEndEncoded(_, _) => Err(UnsupportedDataType::new(dt.clone())),
220    }
221}