surrealdb_core/iam/entities/resources/
resource.rs1use revision::revisioned;
2use std::{
3 collections::{HashMap, HashSet},
4 str::FromStr,
5};
6
7use super::Level;
8
9use cedar_policy::{Entity, EntityId, EntityTypeName, EntityUid, RestrictedExpression};
10use serde::{Deserialize, Serialize};
11
12#[revisioned(revision = 3)]
13#[derive(Clone, Default, Debug, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
14#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
15#[non_exhaustive]
16pub enum ResourceKind {
17 #[default]
18 Any,
19 Namespace,
20 Database,
21 Record,
22 Table,
23 Document,
24 Option,
25 Function,
26 Analyzer,
27 Parameter,
28 Model,
29 Event,
30 Field,
31 Index,
32 Access,
33 #[revision(start = 2)]
34 Config(ConfigKind),
35 #[revision(start = 3)]
36 Api,
37
38 Actor,
40}
41
42#[revisioned(revision = 1)]
43#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
44#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
45#[non_exhaustive]
46pub enum ConfigKind {
47 GraphQL,
48 Api,
49}
50
51impl std::fmt::Display for ResourceKind {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 match self {
54 ResourceKind::Any => write!(f, "Any"),
55 ResourceKind::Namespace => write!(f, "Namespace"),
56 ResourceKind::Database => write!(f, "Database"),
57 ResourceKind::Record => write!(f, "Record"),
58 ResourceKind::Table => write!(f, "Table"),
59 ResourceKind::Document => write!(f, "Document"),
60 ResourceKind::Option => write!(f, "Option"),
61 ResourceKind::Function => write!(f, "Function"),
62 ResourceKind::Api => write!(f, "Api"),
63 ResourceKind::Analyzer => write!(f, "Analyzer"),
64 ResourceKind::Parameter => write!(f, "Parameter"),
65 ResourceKind::Model => write!(f, "Model"),
66 ResourceKind::Event => write!(f, "Event"),
67 ResourceKind::Field => write!(f, "Field"),
68 ResourceKind::Index => write!(f, "Index"),
69 ResourceKind::Access => write!(f, "Access"),
70 ResourceKind::Actor => write!(f, "Actor"),
71 ResourceKind::Config(c) => write!(f, "Config::{c}"),
72 }
73 }
74}
75
76impl std::fmt::Display for ConfigKind {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 ConfigKind::GraphQL => write!(f, "GraphQL"),
80 ConfigKind::Api => write!(f, "API"),
81 }
82 }
83}
84
85impl ResourceKind {
86 pub fn on_level(self, level: Level) -> Resource {
88 Resource::new("".into(), self, level)
89 }
90
91 pub fn on_root(self) -> Resource {
92 self.on_level(Level::Root)
93 }
94
95 pub fn on_ns(self, ns: &str) -> Resource {
96 self.on_level((ns,).into())
97 }
98
99 pub fn on_db(self, ns: &str, db: &str) -> Resource {
100 self.on_level((ns, db).into())
101 }
102
103 pub fn on_record(self, ns: &str, db: &str, rid: &str) -> Resource {
104 self.on_level((ns, db, rid).into())
105 }
106}
107
108#[revisioned(revision = 1)]
109#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
110#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
111#[non_exhaustive]
112pub struct Resource(String, ResourceKind, Level);
113
114impl std::fmt::Display for Resource {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 let Resource(id, kind, level) = self;
117 write!(f, "{}{}:\"{}\"", level, kind, id)
118 }
119}
120
121impl Resource {
122 pub fn new(id: String, kind: ResourceKind, level: Level) -> Self {
123 Self(id, kind, level)
124 }
125
126 pub fn id(&self) -> &str {
127 &self.0
128 }
129
130 pub fn kind(&self) -> &ResourceKind {
131 &self.1
132 }
133
134 pub fn level(&self) -> &Level {
135 &self.2
136 }
137
138 pub fn cedar_attrs(&self) -> HashMap<String, RestrictedExpression> {
140 [("type", self.kind().into()), ("level", self.level().into())]
141 .into_iter()
142 .map(|(x, v)| (x.into(), v))
143 .collect()
144 }
145
146 pub fn cedar_parents(&self) -> HashSet<EntityUid> {
147 HashSet::from([self.level().into()])
148 }
149
150 pub fn cedar_entities(&self) -> Vec<Entity> {
151 let mut entities = Vec::new();
152
153 entities.push(self.into());
154 entities.extend(self.level().cedar_entities());
155
156 entities
157 }
158}
159
160impl std::convert::From<&Resource> for EntityUid {
161 fn from(res: &Resource) -> Self {
162 EntityUid::from_type_name_and_id(
163 EntityTypeName::from_str(&res.kind().to_string()).unwrap(),
164 EntityId::from_str(res.id()).unwrap(),
165 )
166 }
167}
168
169impl std::convert::From<&Resource> for Entity {
170 fn from(res: &Resource) -> Self {
171 Entity::new(res.into(), res.cedar_attrs(), res.cedar_parents())
172 }
173}
174
175impl std::convert::From<&Resource> for RestrictedExpression {
176 fn from(res: &Resource) -> Self {
177 format!("{}", EntityUid::from(res)).parse().unwrap()
178 }
179}
180
181impl std::convert::From<&ResourceKind> for RestrictedExpression {
182 fn from(kind: &ResourceKind) -> Self {
183 RestrictedExpression::new_string(kind.to_string())
184 }
185}