1use crate::ctx::Context;
2use crate::dbs::Options;
3use crate::doc::CursorDoc;
4use crate::err::Error;
5use crate::iam::Action;
6use crate::iam::ResourceKind;
7use crate::sql::{Base, Ident, Object, Value, Version};
8use crate::sys::INFORMATION;
9
10use reblessive::tree::Stk;
11use revision::revisioned;
12use serde::{Deserialize, Serialize};
13use std::fmt;
14use std::sync::Arc;
15
16#[revisioned(revision = 5)]
17#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
18#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
19#[non_exhaustive]
20pub enum InfoStatement {
21 #[revision(override(revision = 2, discriminant = 1), override(revision = 3, discriminant = 1))]
24 Root(#[revision(start = 2)] bool),
25
26 #[revision(override(revision = 2, discriminant = 3), override(revision = 3, discriminant = 3))]
27 Ns(#[revision(start = 2)] bool),
28
29 #[revision(override(revision = 2, discriminant = 5), override(revision = 3, discriminant = 5))]
30 Db(#[revision(start = 2)] bool, #[revision(start = 5)] Option<Version>),
31
32 #[revision(override(revision = 2, discriminant = 7), override(revision = 3, discriminant = 7))]
33 Tb(Ident, #[revision(start = 2)] bool, #[revision(start = 5)] Option<Version>),
34
35 #[revision(override(revision = 2, discriminant = 9), override(revision = 3, discriminant = 9))]
36 User(Ident, Option<Base>, #[revision(start = 2)] bool),
37
38 #[revision(start = 3)]
39 #[revision(override(revision = 3, discriminant = 10))]
40 Index(Ident, Ident, bool),
41}
42
43impl InfoStatement {
44 pub(crate) async fn compute(
46 &self,
47 stk: &mut Stk,
48 ctx: &Context,
49 opt: &Options,
50 _doc: Option<&CursorDoc>,
51 ) -> Result<Value, Error> {
52 match self {
53 InfoStatement::Root(structured) => {
54 opt.is_allowed(Action::View, ResourceKind::Any, &Base::Root)?;
56 let txn = ctx.tx();
58 Ok(match structured {
60 true => Value::from(map! {
61 "accesses".to_string() => process(txn.all_root_accesses().await?.iter().map(|v| v.redacted()).collect()),
62 "namespaces".to_string() => process(txn.all_ns().await?),
63 "nodes".to_string() => process(txn.all_nodes().await?),
64 "system".to_string() => system().await,
65 "users".to_string() => process(txn.all_root_users().await?),
66 }),
67 false => Value::from(map! {
68 "accesses".to_string() => {
69 let mut out = Object::default();
70 for v in txn.all_root_accesses().await?.iter().map(|v| v.redacted()) {
71 out.insert(v.name.to_raw(), v.to_string().into());
72 }
73 out.into()
74 },
75 "namespaces".to_string() => {
76 let mut out = Object::default();
77 for v in txn.all_ns().await?.iter() {
78 out.insert(v.name.to_raw(), v.to_string().into());
79 }
80 out.into()
81 },
82 "nodes".to_string() => {
83 let mut out = Object::default();
84 for v in txn.all_nodes().await?.iter() {
85 out.insert(v.id.to_string(), v.to_string().into());
86 }
87 out.into()
88 },
89 "system".to_string() => system().await,
90 "users".to_string() => {
91 let mut out = Object::default();
92 for v in txn.all_root_users().await?.iter() {
93 out.insert(v.name.to_raw(), v.to_string().into());
94 }
95 out.into()
96 }
97 }),
98 })
99 }
100 InfoStatement::Ns(structured) => {
101 opt.is_allowed(Action::View, ResourceKind::Any, &Base::Ns)?;
103 let ns = opt.ns()?;
105 let txn = ctx.tx();
107 Ok(match structured {
109 true => Value::from(map! {
110 "accesses".to_string() => process(txn.all_ns_accesses(ns).await?.iter().map(|v| v.redacted()).collect()),
111 "databases".to_string() => process(txn.all_db(ns).await?),
112 "users".to_string() => process(txn.all_ns_users(ns).await?),
113 }),
114 false => Value::from(map! {
115 "accesses".to_string() => {
116 let mut out = Object::default();
117 for v in txn.all_ns_accesses(ns).await?.iter().map(|v| v.redacted()) {
118 out.insert(v.name.to_raw(), v.to_string().into());
119 }
120 out.into()
121 },
122 "databases".to_string() => {
123 let mut out = Object::default();
124 for v in txn.all_db(ns).await?.iter() {
125 out.insert(v.name.to_raw(), v.to_string().into());
126 }
127 out.into()
128 },
129 "users".to_string() => {
130 let mut out = Object::default();
131 for v in txn.all_ns_users(ns).await?.iter() {
132 out.insert(v.name.to_raw(), v.to_string().into());
133 }
134 out.into()
135 },
136 }),
137 })
138 }
139 InfoStatement::Db(structured, version) => {
140 opt.is_allowed(Action::View, ResourceKind::Any, &Base::Db)?;
142 let (ns, db) = opt.ns_db()?;
144 let version = match version {
146 Some(v) => Some(v.compute(stk, ctx, opt, None).await?),
147 _ => None,
148 };
149 let txn = ctx.tx();
151 Ok(match structured {
153 true => Value::from(map! {
154 "accesses".to_string() => process(txn.all_db_accesses(ns, db).await?.iter().map(|v| v.redacted()).collect()),
155 "apis".to_string() => process(txn.all_db_apis(ns, db).await?),
156 "analyzers".to_string() => process(txn.all_db_analyzers(ns, db).await?),
157 "functions".to_string() => process(txn.all_db_functions(ns, db).await?),
158 "models".to_string() => process(txn.all_db_models(ns, db).await?),
159 "params".to_string() => process(txn.all_db_params(ns, db).await?),
160 "tables".to_string() => process(txn.all_tb(ns, db, version).await?),
161 "users".to_string() => process(txn.all_db_users(ns, db).await?),
162 "configs".to_string() => process(txn.all_db_configs(ns, db).await?),
163 }),
164 false => Value::from(map! {
165 "accesses".to_string() => {
166 let mut out = Object::default();
167 for v in txn.all_db_accesses(ns, db).await?.iter().map(|v| v.redacted()) {
168 out.insert(v.name.to_raw(), v.to_string().into());
169 }
170 out.into()
171 },
172 "apis".to_string() => {
173 let mut out = Object::default();
174 for v in txn.all_db_apis(ns, db).await?.iter() {
175 out.insert(v.path.to_string(), v.to_string().into());
176 }
177 out.into()
178 },
179 "analyzers".to_string() => {
180 let mut out = Object::default();
181 for v in txn.all_db_analyzers( ns, db).await?.iter() {
182 out.insert(v.name.to_raw(), v.to_string().into());
183 }
184 out.into()
185 },
186 "functions".to_string() => {
187 let mut out = Object::default();
188 for v in txn.all_db_functions(ns, db).await?.iter() {
189 out.insert(v.name.to_raw(), v.to_string().into());
190 }
191 out.into()
192 },
193 "models".to_string() => {
194 let mut out = Object::default();
195 for v in txn.all_db_models(ns, db).await?.iter() {
196 out.insert(v.name.to_raw(), v.to_string().into());
197 }
198 out.into()
199 },
200 "params".to_string() => {
201 let mut out = Object::default();
202 for v in txn.all_db_params(ns, db).await?.iter() {
203 out.insert(v.name.to_raw(), v.to_string().into());
204 }
205 out.into()
206 },
207 "tables".to_string() => {
208 let mut out = Object::default();
209 for v in txn.all_tb(ns, db, version).await?.iter() {
210 out.insert(v.name.to_raw(), v.to_string().into());
211 }
212 out.into()
213 },
214 "users".to_string() => {
215 let mut out = Object::default();
216 for v in txn.all_db_users(ns, db).await?.iter() {
217 out.insert(v.name.to_raw(), v.to_string().into());
218 }
219 out.into()
220 },
221 "configs".to_string() => {
222 let mut out = Object::default();
223 for v in txn.all_db_configs(ns, db).await?.iter() {
224 out.insert(v.inner.name(), v.to_string().into());
225 }
226 out.into()
227 },
228 }),
229 })
230 }
231 InfoStatement::Tb(tb, structured, version) => {
232 opt.is_allowed(Action::View, ResourceKind::Any, &Base::Db)?;
234 let (ns, db) = opt.ns_db()?;
236 let version = match version {
238 Some(v) => Some(v.compute(stk, ctx, opt, None).await?),
239 _ => None,
240 };
241 let txn = ctx.tx();
243 Ok(match structured {
245 true => Value::from(map! {
246 "events".to_string() => process(txn.all_tb_events(ns, db, tb).await?),
247 "fields".to_string() => process(txn.all_tb_fields(ns, db, tb, version).await?),
248 "indexes".to_string() => process(txn.all_tb_indexes(ns, db, tb).await?),
249 "lives".to_string() => process(txn.all_tb_lives(ns, db, tb).await?),
250 "tables".to_string() => process(txn.all_tb_views(ns, db, tb).await?),
251 }),
252 false => Value::from(map! {
253 "events".to_string() => {
254 let mut out = Object::default();
255 for v in txn.all_tb_events(ns, db, tb).await?.iter() {
256 out.insert(v.name.to_raw(), v.to_string().into());
257 }
258 out.into()
259 },
260 "fields".to_string() => {
261 let mut out = Object::default();
262 for v in txn.all_tb_fields(ns, db, tb, version).await?.iter() {
263 out.insert(v.name.to_string(), v.to_string().into());
264 }
265 out.into()
266 },
267 "indexes".to_string() => {
268 let mut out = Object::default();
269 for v in txn.all_tb_indexes(ns, db, tb).await?.iter() {
270 out.insert(v.name.to_raw(), v.to_string().into());
271 }
272 out.into()
273 },
274 "lives".to_string() => {
275 let mut out = Object::default();
276 for v in txn.all_tb_lives(ns, db, tb).await?.iter() {
277 out.insert(v.id.to_raw(), v.to_string().into());
278 }
279 out.into()
280 },
281 "tables".to_string() => {
282 let mut out = Object::default();
283 for v in txn.all_tb_views(ns, db, tb).await?.iter() {
284 out.insert(v.name.to_raw(), v.to_string().into());
285 }
286 out.into()
287 },
288 }),
289 })
290 }
291 InfoStatement::User(user, base, structured) => {
292 let base = base.clone().unwrap_or(opt.selected_base()?);
294 opt.is_allowed(Action::View, ResourceKind::Actor, &base)?;
296 let txn = ctx.tx();
298 let res = match base {
300 Base::Root => txn.get_root_user(user).await?,
301 Base::Ns => txn.get_ns_user(opt.ns()?, user).await?,
302 Base::Db => {
303 let (ns, db) = opt.ns_db()?;
304 txn.get_db_user(ns, db, user).await?
305 }
306 _ => return Err(Error::InvalidLevel(base.to_string())),
307 };
308 Ok(match structured {
310 true => res.as_ref().clone().structure(),
311 false => Value::from(res.to_string()),
312 })
313 }
314 #[allow(unused_variables)]
315 InfoStatement::Index(index, table, _structured) => {
316 opt.is_allowed(Action::View, ResourceKind::Actor, &Base::Db)?;
318 let txn = ctx.tx();
320 #[cfg(not(target_family = "wasm"))]
322 if let Some(ib) = ctx.get_index_builder() {
323 let (ns, db) = opt.ns_db()?;
325 let res = txn.get_tb_index(ns, db, table, index).await?;
326 let status = ib.get_status(ns, db, &res).await;
327 let mut out = Object::default();
328 out.insert("building".to_string(), status.into());
329 return Ok(out.into());
330 }
331 Ok(Object::default().into())
332 }
333 }
334 }
335}
336
337impl fmt::Display for InfoStatement {
338 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
339 match self {
340 Self::Root(false) => f.write_str("INFO FOR ROOT"),
341 Self::Root(true) => f.write_str("INFO FOR ROOT STRUCTURE"),
342 Self::Ns(false) => f.write_str("INFO FOR NAMESPACE"),
343 Self::Ns(true) => f.write_str("INFO FOR NAMESPACE STRUCTURE"),
344 Self::Db(false, ref v) => match v {
345 Some(ref v) => write!(f, "INFO FOR DATABASE VERSION {v}"),
346 None => f.write_str("INFO FOR DATABASE"),
347 },
348 Self::Db(true, ref v) => match v {
349 Some(ref v) => write!(f, "INFO FOR DATABASE VERSION {v} STRUCTURE"),
350 None => f.write_str("INFO FOR DATABASE STRUCTURE"),
351 },
352 Self::Tb(ref t, false, ref v) => match v {
353 Some(ref v) => write!(f, "INFO FOR TABLE {t} VERSION {v}"),
354 None => write!(f, "INFO FOR TABLE {t}"),
355 },
356
357 Self::Tb(ref t, true, ref v) => match v {
358 Some(ref v) => write!(f, "INFO FOR TABLE {t} VERSION {v} STRUCTURE"),
359 None => write!(f, "INFO FOR TABLE {t} STRUCTURE"),
360 },
361 Self::User(ref u, ref b, false) => match b {
362 Some(ref b) => write!(f, "INFO FOR USER {u} ON {b}"),
363 None => write!(f, "INFO FOR USER {u}"),
364 },
365 Self::User(ref u, ref b, true) => match b {
366 Some(ref b) => write!(f, "INFO FOR USER {u} ON {b} STRUCTURE"),
367 None => write!(f, "INFO FOR USER {u} STRUCTURE"),
368 },
369 Self::Index(ref i, ref t, false) => write!(f, "INFO FOR INDEX {i} ON {t}"),
370 Self::Index(ref i, ref t, true) => write!(f, "INFO FOR INDEX {i} ON {t} STRUCTURE"),
371 }
372 }
373}
374
375pub(crate) trait InfoStructure {
376 fn structure(self) -> Value;
377}
378
379impl InfoStatement {
380 pub(crate) fn structurize(self) -> Self {
381 match self {
382 InfoStatement::Root(_) => InfoStatement::Root(true),
383 InfoStatement::Ns(_) => InfoStatement::Ns(true),
384 InfoStatement::Db(_, v) => InfoStatement::Db(true, v),
385 InfoStatement::Tb(t, _, v) => InfoStatement::Tb(t, true, v),
386 InfoStatement::User(u, b, _) => InfoStatement::User(u, b, true),
387 InfoStatement::Index(i, t, _) => InfoStatement::Index(i, t, true),
388 }
389 }
390
391 pub(crate) fn versionize(self, v: Version) -> Self {
392 match self {
393 InfoStatement::Db(s, _) => InfoStatement::Db(s, Some(v)),
394 InfoStatement::Tb(t, s, _) => InfoStatement::Tb(t, s, Some(v)),
395 _ => self,
396 }
397 }
398}
399
400fn process<T>(a: Arc<[T]>) -> Value
401where
402 T: InfoStructure + Clone,
403{
404 Value::Array(a.iter().cloned().map(InfoStructure::structure).collect())
405}
406
407async fn system() -> Value {
408 let info = INFORMATION.lock().await;
409 Value::from(map! {
410 "available_parallelism".to_string() => info.available_parallelism.into(),
411 "cpu_usage".to_string() => info.cpu_usage.into(),
412 "load_average".to_string() => info.load_average.to_vec().into(),
413 "memory_usage".to_string() => info.memory_usage.into(),
414 "physical_cores".to_string() => info.physical_cores.into(),
415 "memory_allocated".to_string() => info.memory_allocated.into(),
416 "threads".to_string() => info.threads.into(),
417 })
418}