mz_catalog_decode/
durable.rs1use mz_repr::Datum;
14use mz_repr::adt::jsonb::JsonbRef;
15use mz_repr::adt::mz_acl_item::{AclMode, MzAclItem};
16use mz_repr::adt::numeric;
17use mz_repr::role_id::RoleId;
18
19fn jsonb_datum_to_u64<'a>(d: Datum<'a>) -> Result<u64, String> {
21 let Datum::Numeric(n) = d else {
22 return Err("expected numeric value".into());
23 };
24
25 let mut cx = numeric::cx_datum();
26 cx.try_into_u64(n.0)
27 .map_err(|_| format!("number out of u64 range: {n}"))
28}
29
30fn jsonb_datum_to_acl_mode(d: Datum) -> Result<AclMode, String> {
36 let Datum::Map(dict) = d else {
37 return Err(format!("unexpected acl_mode: {d}"));
38 };
39 let mut bits = None;
40 for (key, val) in dict.iter() {
41 match key {
42 "bitflags" => bits = Some(jsonb_datum_to_u64(val)?),
43 other => return Err(format!("unexpected acl_mode field: {other}")),
44 }
45 }
46 let bits = bits.ok_or_else(|| "missing acl_mode bitflags".to_string())?;
47 AclMode::from_bits(bits).ok_or_else(|| format!("invalid acl_mode bitflags: {bits}"))
48}
49
50fn jsonb_datum_to_role_id(d: Datum) -> Result<RoleId, String> {
52 match d {
53 Datum::String("Public") => Ok(RoleId::Public),
54 Datum::String(other) => Err(format!("unexpected role ID variant: {other}")),
55 Datum::Map(dict) => {
56 let (key, val) = dict.iter().next().ok_or_else(|| "empty".to_string())?;
57 let n = jsonb_datum_to_u64(val)?;
58 match key {
59 "User" => Ok(RoleId::User(n)),
60 "System" => Ok(RoleId::System(n)),
61 "Predefined" => Ok(RoleId::Predefined(n)),
62 other => Err(format!("unexpected role ID variant: {other}")),
63 }
64 }
65 _ => Err("expected string or object".into()),
66 }
67}
68
69pub fn catalog_id(a: JsonbRef<'_>) -> Result<String, String> {
73 match a.into_datum() {
74 Datum::String(variant) => match variant {
76 "Explain" => Ok("e".to_string()),
77 "Public" => Ok("p".to_string()),
78 other => Err(format!("unexpected ID variant: {other}")),
79 },
80 Datum::Map(dict) => {
82 let (key, val) = dict.iter().next().ok_or_else(|| "empty".to_string())?;
83 let prefix = match key {
84 "IntrospectionSourceIndex" => "si",
85 "Predefined" => "g",
86 "System" => "s",
87 "Transient" => "t",
88 "User" => "u",
89 other => return Err(format!("unexpected ID variant: {other}")),
90 };
91 let n = jsonb_datum_to_u64(val)?;
92 Ok(format!("{prefix}{n}"))
93 }
94 _ => Err("expected string or object".into()),
95 }
96}
97
98pub fn privileges(a: JsonbRef<'_>) -> Result<Vec<MzAclItem>, String> {
100 let parse_one = |datum| match datum {
101 Datum::Map(dict) => {
102 let mut grantee = None;
103 let mut grantor = None;
104 let mut acl_mode = None;
105 for (key, val) in dict.iter() {
106 match key {
107 "grantee" => {
108 let id = jsonb_datum_to_role_id(val)?;
109 grantee = Some(id);
110 }
111 "grantor" => {
112 let id = jsonb_datum_to_role_id(val)?;
113 grantor = Some(id);
114 }
115 "acl_mode" => {
116 acl_mode = Some(jsonb_datum_to_acl_mode(val)?);
117 }
118 other => return Err(format!("unexpected privilege field: {other}")),
119 }
120 }
121 Ok(MzAclItem {
122 grantee: grantee.ok_or_else(|| format!("missing grantee: {dict:?}"))?,
123 grantor: grantor.ok_or_else(|| "missing grantor in privilege".to_string())?,
124 acl_mode: acl_mode.ok_or_else(|| "missing acl_mode in privilege".to_string())?,
125 })
126 }
127 other => Err(format!("expected object in array, found: {other}")),
128 };
129
130 match a.into_datum() {
131 Datum::List(list) => {
132 let mut result = Vec::new();
133 for item in list.iter() {
134 result.push(parse_one(item)?);
135 }
136 Ok(result)
137 }
138 _ => Err("expected array".to_string()),
139 }
140}
141
142pub fn acl_mode(a: JsonbRef<'_>) -> Result<AclMode, String> {
145 jsonb_datum_to_acl_mode(a.into_datum())
146}