ahri_tre_app/service/
study_context.rs1use super::*;
2use ahri_tre_protocol::{
3 PublicUuid,
4 refs::{ObjectKind, ObjectRef, ObjectSelector, decode_scoped_integer_ref},
5};
6
7impl AppService {
8 pub async fn resolve_session_study(
12 &self,
13 datastore_id: uuid::Uuid,
14 explicit: Option<ahri_tre_protocol::study::StudySelector>,
15 current: Option<ObjectRef>,
16 ) -> Result<ObjectRef, ahri_tre_protocol::ProtocolError> {
17 use ahri_tre_protocol::{domain::DomainSelector, study::StudySelector};
18 let (study, domain) = match explicit {
19 Some(StudySelector::Id { study }) => {
20 (ObjectSelector::Reference { reference: study }, None)
21 }
22 Some(StudySelector::Name { domain, name }) => (
23 ObjectSelector::Name { name },
24 domain.map(|domain| match domain {
25 DomainSelector::Id { domain } => {
26 ObjectSelector::Reference { reference: domain }
27 }
28 DomainSelector::Name { name } => ObjectSelector::Name { name },
29 }),
30 ),
31 None => (
32 ObjectSelector::Reference {
33 reference: current.ok_or_else(|| {
34 ahri_tre_protocol::ProtocolError::new(
35 ahri_tre_protocol::ProtocolErrorCode::PreconditionFailed,
36 "Current study is required",
37 )
38 .with_target("current_study")
39 })?,
40 },
41 None,
42 ),
43 };
44 self.resolve_study_context(datastore_id, study, domain)
45 .await
46 .map(|(study, _)| study)
47 .map_err(crate::projections::study_context_protocol_error)
48 }
49
50 pub async fn resolve_study_context(
53 &self,
54 datastore_id: uuid::Uuid,
55 study: ObjectSelector,
56 domain: Option<ObjectSelector>,
57 ) -> Result<(ObjectRef, String), AppError> {
58 let check = |reference: ObjectRef, kind| {
59 if reference.kind != kind {
60 Err(AppError::Validation(
61 "Object reference has the wrong kind".into(),
62 ))
63 } else if reference.datastore_id.as_uuid() != datastore_id {
64 Err(AppError::Conflict(
65 "Object reference disagrees with Study context".into(),
66 ))
67 } else {
68 Ok(reference.id)
69 }
70 };
71 let domain = domain
72 .map(|domain| {
73 Ok(match domain {
74 ObjectSelector::Name { name } => DomainSelector::Name { name: name.into() },
75 ObjectSelector::Reference { reference } => DomainSelector::Id {
76 domain_id: ahri_tre_types::DomainId(
77 decode_scoped_integer_ref(
78 "domain",
79 check(reference, ObjectKind::Domain)?,
80 )
81 .ok_or_else(|| {
82 AppError::Validation("Invalid Domain reference".into())
83 })?,
84 ),
85 },
86 })
87 })
88 .transpose()?;
89 let selector = match study {
90 ObjectSelector::Name { name } => StudySelector::Name {
91 domain: None,
92 name: name.into(),
93 },
94 ObjectSelector::Reference { reference } => StudySelector::Id {
95 study_id: ahri_tre_types::StudyId(check(reference, ObjectKind::Study)?.as_uuid()),
96 },
97 };
98 let study = self
99 .resolve_study_selector(selector, "Current study")
100 .await?;
101 if let Some(domain) = domain {
102 let domain = self.resolve_domain_selector(domain, "Study Domain").await?;
103 self.ensure_study_domain(study.study_id, domain.domain_id, "Current study")
104 .await
105 .map_err(|error| match error {
106 AppError::Validation(_) => {
107 AppError::Conflict("Domain is not linked to the Study".into())
108 }
109 error => error,
110 })?;
111 }
112 Ok((
116 ObjectRef {
117 datastore_id: PublicUuid::from_uuid(datastore_id),
118 kind: ObjectKind::Study,
119 id: PublicUuid::from_uuid(study.study_id.0),
120 },
121 study.name.as_str().to_owned(),
122 ))
123 }
124}