uqa_storage/catalog/
schema.rs1use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use uqa_core::catalog_schema::SchemaRow as LegacySchemaRow;
9pub use uqa_core::catalog_schema::{
10 BoundSchemaRow, SchemaAclEntry, SchemaPrivileges, SchemaTupleIdentity,
11};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum SchemaRow {
16 Bound(BoundSchemaRow),
17 Legacy(LegacySchemaRow),
18}
19
20impl SchemaRow {
21 pub fn name(&self) -> &str {
22 match self {
23 Self::Bound(row) => &row.name,
24 Self::Legacy(row) => &row.name,
25 }
26 }
27
28 pub fn legacy(name: impl Into<String>) -> Self {
29 Self::Legacy(LegacySchemaRow::legacy(name))
30 }
31
32 pub fn bootstrap(name: impl Into<String>) -> Self {
33 Self::Bound(BoundSchemaRow::bootstrap(name))
34 }
35}
36
37impl From<BoundSchemaRow> for SchemaRow {
38 fn from(row: BoundSchemaRow) -> Self {
39 Self::Bound(row)
40 }
41}
42
43impl Serialize for SchemaRow {
44 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
45 #[derive(Serialize)]
46 struct Bound<'a> {
47 schema_security_format: u32,
48 #[serde(flatten)]
49 row: &'a BoundSchemaRow,
50 }
51 match self {
52 Self::Legacy(row) => row.serialize(serializer),
53 Self::Bound(row) => {
54 if row.tuple.is_some_and(|tuple| !tuple.is_valid()) {
55 return Err(serde::ser::Error::custom(
56 "invalid schema catalog tuple identity",
57 ));
58 }
59 Bound {
60 schema_security_format: if row.tuple.is_some() { 2 } else { 1 },
61 row,
62 }
63 .serialize(serializer)
64 }
65 }
66 }
67}
68
69impl<'de> Deserialize<'de> for SchemaRow {
70 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
71 use serde::de::Error;
72 let value = serde_json::Value::deserialize(deserializer)?;
73 if let Some(version) = value.get("schema_security_format") {
74 let version = version.as_u64();
75 if !matches!(version, Some(1 | 2)) {
76 return Err(D::Error::custom("unsupported schema security format"));
77 }
78 if version == Some(1) && value.get("tuple").is_some() {
79 return Err(D::Error::custom(
80 "legacy schema security contains a tuple identity",
81 ));
82 }
83 let row: BoundSchemaRow = serde_json::from_value(value).map_err(D::Error::custom)?;
84 if version == Some(2) && !row.tuple.is_some_and(SchemaTupleIdentity::is_valid) {
85 return Err(D::Error::custom("invalid schema catalog tuple identity"));
86 }
87 Ok(Self::Bound(row))
88 } else {
89 if value.get("tuple").is_some() {
90 return Err(D::Error::custom(
91 "schema tuple identity has no format marker",
92 ));
93 }
94 serde_json::from_value(value)
95 .map(Self::Legacy)
96 .map_err(D::Error::custom)
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests;