sofie_db/children/
through.rs1use sofie_core::{Error, Result, SqlType, SqlValue, Uuid};
2
3use crate::aggregate::{table, uuid_equals};
4use crate::condition::Kind;
5use crate::{
6 Aggregate, Column, Condition, Context, Dialect, ExpectedRows, Id, Query, Read, Source, Step,
7};
8
9#[must_use]
10pub fn owned_through<A: Aggregate, P: Aggregate>(
11 parent: Column<A, Id<P>>,
12 owner: Uuid,
13) -> Option<Condition<A>> {
14 let owned_parents = P::owned_by(owner)?;
15 Some(crate::in_select(parent, P::ID, owned_parents))
16}
17
18pub(crate) fn ownership_check<A: Aggregate>(id: Uuid, owner: Uuid, dialect: &dyn Dialect) -> Step {
19 let table = table::<A>();
20 let mut params = Vec::new();
21 let mut sql = format!("SELECT 1 FROM {} WHERE ", table.qualified(dialect));
22 match A::owned_by(owner) {
23 Some(condition) => condition.kind.render_into(dialect, &mut params, &mut sql),
24 None => sql.push_str("(1 = 0)"),
25 }
26 sql.push_str(" AND ");
27 sql.push_str(&crate::sql::equals(
28 dialect,
29 "id",
30 SqlValue::Uuid(id),
31 &mut params,
32 ));
33 Step::Statement {
34 sql,
35 params,
36 expect_rows: Some(ExpectedRows::or_not_found(1)),
37 }
38}
39
40pub(crate) fn within_parents<S: Source, C: Context>(mut query: Query<S>, context: &C) -> Query<S> {
42 for field in S::Base::FIELDS {
43 let [column] = field.columns else { continue };
44 if column.ty != SqlType::Uuid || field.name == S::Base::NAME {
45 continue;
46 }
47 if let Ok(parent) = context.bound(field.name) {
48 let column = crate::sql::column_name(field.name, column);
49 query = query.where_(Condition::new(uuid_equals(&column, parent)));
50 }
51 }
52 query
53}
54
55pub async fn refuse_parent_beyond_reach<A: Aggregate>(
58 read: &Read,
59 field: &str,
60 parent: Uuid,
61) -> Result<()> {
62 let Some(owner) = read.owner() else {
63 return Ok(());
64 };
65 if A::OWNER != Some(field) {
66 return Ok(());
67 }
68 let Some(Kind::InSelect(owned_parents)) = A::owned_by(owner).map(|owned| owned.kind) else {
69 return Ok(());
70 };
71 let mut params = Vec::new();
72 let mut sql = "SELECT 1 WHERE ".to_owned();
73 owned_parents.render_holding(
74 &SqlValue::Uuid(parent),
75 read.dialect(),
76 &mut params,
77 &mut sql,
78 );
79 let found = read
80 .decoded(&sql, ¶ms, 1, vec![None], |_| Ok(()))
81 .await?;
82 if found.is_empty() {
83 return Err(Error::NotFound);
84 }
85 Ok(())
86}