1use crate::catalog_role::{BoundAclEntry, RoleIdentity};
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(deny_unknown_fields)]
15pub struct SchemaTupleIdentity {
16 pub oid: i64,
17 pub object_id: [u8; 16],
18 pub revision: [u8; 16],
19}
20
21impl SchemaTupleIdentity {
22 pub fn is_valid(self) -> bool {
23 u32::try_from(self.oid).is_ok_and(|oid| oid != 0)
24 && self.object_id != [0; 16]
25 && self.revision != [0; 16]
26 }
27
28 pub fn initial(oid: u32) -> Self {
30 let mut object_id = [0; 16];
31 object_id[..4].copy_from_slice(&2615_u32.to_be_bytes());
32 object_id[12..].copy_from_slice(&oid.to_be_bytes());
33 Self {
34 oid: i64::from(oid),
35 object_id,
36 revision: object_id,
37 }
38 }
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43pub struct BoundSchemaRow {
44 pub name: String,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub tuple: Option<SchemaTupleIdentity>,
47 pub role_owner: RoleIdentity,
48 pub acl: Option<Vec<BoundAclEntry<SchemaPrivileges>>>,
49}
50
51impl BoundSchemaRow {
52 pub fn bootstrap(name: impl Into<String>) -> Self {
53 let name = name.into();
54 let owner = RoleIdentity::BOOTSTRAP;
55 let acl = (name == "public").then(|| {
56 vec![
57 BoundAclEntry {
58 role: Some(owner),
59 grantor: owner,
60 privileges: SchemaPrivileges::ALL,
61 grant_options: SchemaPrivileges::default(),
62 },
63 BoundAclEntry {
64 role: None,
65 grantor: owner,
66 privileges: SchemaPrivileges {
67 usage: true,
68 create: false,
69 },
70 grant_options: SchemaPrivileges::default(),
71 },
72 ]
73 });
74 Self {
75 name,
76 tuple: None,
77 role_owner: owner,
78 acl,
79 }
80 }
81}
82
83#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
85pub struct SchemaPrivileges {
86 #[serde(default)]
87 pub usage: bool,
88 #[serde(default)]
89 pub create: bool,
90}
91
92impl SchemaPrivileges {
93 pub const ALL: Self = Self {
94 usage: true,
95 create: true,
96 };
97
98 #[must_use]
99 pub const fn is_empty(self) -> bool {
100 !self.usage && !self.create
101 }
102
103 #[must_use]
104 pub const fn intersects(self, other: Self) -> bool {
105 self.usage && other.usage || self.create && other.create
106 }
107
108 pub fn insert(&mut self, other: Self) {
109 self.usage |= other.usage;
110 self.create |= other.create;
111 }
112
113 pub fn remove(&mut self, other: Self) {
114 self.usage &= !other.usage;
115 self.create &= !other.create;
116 }
117}
118
119#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub struct SchemaAclEntry {
122 pub role: crate::catalog_acl::AclGrantee,
123 #[serde(default, skip_serializing_if = "Option::is_none")]
125 pub grantor: Option<String>,
126 #[serde(default)]
127 pub privileges: SchemaPrivileges,
128 #[serde(default)]
129 pub grant_options: SchemaPrivileges,
130}
131
132#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
134pub struct SchemaRow {
135 pub name: String,
136 #[serde(default = "default_schema_role_owner")]
138 pub role_owner: String,
139 #[serde(default, skip_serializing_if = "Option::is_none")]
141 pub acl: Option<Vec<SchemaAclEntry>>,
142}
143
144impl SchemaRow {
145 #[must_use]
146 pub fn legacy(name: impl Into<String>) -> Self {
147 let name = name.into();
148 let acl = (name == "public").then(|| {
149 vec![
150 SchemaAclEntry {
151 role: "uqa".into(),
152 grantor: Some("uqa".into()),
153 privileges: SchemaPrivileges::ALL,
154 grant_options: SchemaPrivileges::default(),
155 },
156 SchemaAclEntry {
157 role: crate::catalog_acl::AclGrantee::Public,
158 grantor: Some("uqa".into()),
159 privileges: SchemaPrivileges {
160 usage: true,
161 create: false,
162 },
163 grant_options: SchemaPrivileges::default(),
164 },
165 ]
166 });
167 Self {
168 name,
169 role_owner: default_schema_role_owner(),
170 acl,
171 }
172 }
173}
174
175fn default_schema_role_owner() -> String {
176 "uqa".into()
177}