Skip to main content

sofie_db/
context.rs

1use serde_json::Value;
2use sofie_core::{Clock, Error, Result, Uuid};
3
4use crate::{Aggregate, Db, Id, InputValue, Reach, Read, Select, Source, optional_lone_value};
5
6pub trait Resolve<C>: Sized {
7    fn resolve(context: &mut C) -> impl Future<Output = Result<Self>> + Send;
8}
9
10pub trait Context: Send {
11    fn db(&self) -> &Db;
12
13    fn reach(&self) -> Reach;
14
15    /// The only way a handler gets a `Read`, so it never reaches further than its context.
16    fn read(&self) -> Read {
17        Read::within(self.db(), self.reach())
18    }
19
20    fn clock(&self) -> Clock {
21        self.db().clock()
22    }
23
24    fn bound(&self, name: &str) -> Result<Uuid> {
25        Err(Error::internal_message(format!(
26            "nothing here names a record, so it cannot take a `{name}`"
27        )))
28    }
29
30    fn input(&mut self) -> Result<Value> {
31        Err(Error::internal_message(
32            "nothing here carries an input, so it cannot take one",
33        ))
34    }
35
36    fn event(&self, name: &str) -> Result<Value> {
37        Err(Error::internal_message(format!(
38            "only a listener receives an event, so it cannot take a `{name}`"
39        )))
40    }
41}
42
43/// A GET's context leaves it out, so a GET cannot take a write-side argument.
44pub trait Writes: Context {}
45
46/// Named by the route segment after the aggregate, and within the parents the context names.
47pub async fn bind<S: Source, C: Context>(context: &mut C) -> Result<S> {
48    let id: Id<S::Base> = Id::from_uuid(context.bound(<S::Base as Aggregate>::NAME)?);
49    let query = S::query().where_(<S::Base as Aggregate>::ID.eq(id));
50    #[cfg(feature = "children")]
51    let query = crate::children::through::within_parents(query, context);
52    query.first(&context.read()).await?.ok_or(Error::NotFound)
53}
54
55impl<C: Context> Resolve<C> for Read {
56    fn resolve(context: &mut C) -> impl Future<Output = Result<Self>> + Send {
57        std::future::ready(Ok(context.read()))
58    }
59}
60
61impl<C: Context> Resolve<C> for Clock {
62    fn resolve(context: &mut C) -> impl Future<Output = Result<Self>> + Send {
63        std::future::ready(Ok(context.clock()))
64    }
65}
66
67impl<C: Writes, V: InputValue + Send> Resolve<C> for Option<V> {
68    fn resolve(context: &mut C) -> impl Future<Output = Result<Self>> + Send {
69        std::future::ready(context.input().and_then(optional_lone_value))
70    }
71}