Skip to main content

antecedent_core/query/
target.rs

1//! Query submodule.
2//!
3//! SPDX-License-Identifier: MIT OR Apache-2.0
4
5use std::sync::Arc;
6
7use crate::ids::{DistributionRef, EnvironmentId};
8
9use super::error::QueryError;
10
11/// Portable predicate over units/rows.
12///
13/// [`Self::Rows`] is evaluated directly; [`Self::Named`] resolves through
14/// [`super::PopulationRegistry`].
15#[derive(Clone, Debug, Eq, PartialEq, Hash)]
16#[non_exhaustive]
17pub enum PredicateExpr {
18    /// Registry-named predicate resolved by callers.
19    Named(Arc<str>),
20    /// Explicit row indices into the bound tabular view.
21    Rows(Arc<[usize]>),
22}
23
24impl PredicateExpr {
25    /// Named registry predicate.
26    #[must_use]
27    pub fn named(id: impl Into<Arc<str>>) -> Self {
28        Self::Named(id.into())
29    }
30
31    /// Explicit row subset.
32    #[must_use]
33    pub fn rows(rows: impl Into<Arc<[usize]>>) -> Self {
34        Self::Rows(rows.into())
35    }
36
37    /// Validate predicate geometry (non-empty name / rows).
38    ///
39    /// # Errors
40    ///
41    /// Empty name or empty row set.
42    pub fn validate(&self) -> Result<(), QueryError> {
43        match self {
44            Self::Named(name) => {
45                if name.is_empty() {
46                    Err(QueryError::EmptyPredicateName)
47                } else {
48                    Ok(())
49                }
50            }
51            Self::Rows(rows) => {
52                if rows.is_empty() {
53                    Err(QueryError::EmptyPopulationRows)
54                } else {
55                    Ok(())
56                }
57            }
58        }
59    }
60}
61
62/// Target population for an effect query.
63#[derive(Clone, Debug, Eq, PartialEq, Hash)]
64#[non_exhaustive]
65pub enum TargetPopulation {
66    /// All observed units.
67    AllObserved,
68    /// Treated units only.
69    Treated,
70    /// Untreated units only.
71    Untreated,
72    /// Environment-restricted population.
73    Environment(EnvironmentId),
74    /// Predicate-selected units ([`PredicateExpr`]).
75    Predicate(PredicateExpr),
76    /// Custom target distribution handle (weights via [`super::PopulationRegistry`]).
77    CustomDistribution(DistributionRef),
78}
79
80impl TargetPopulation {
81    /// Validate population geometry for Planned / structured variants.
82    ///
83    /// # Errors
84    ///
85    /// Empty predicate name or empty row set.
86    pub fn validate(&self) -> Result<(), QueryError> {
87        match self {
88            Self::Predicate(expr) => expr.validate(),
89            Self::AllObserved
90            | Self::Treated
91            | Self::Untreated
92            | Self::Environment(_)
93            | Self::CustomDistribution(_) => Ok(()),
94        }
95    }
96}