Skip to main content

drive/query/drive_document_having_query/mode_detection/
mod.rs

1//! Request-shape validation for the having-range query, and the versioned
2//! `(select, group_by, having, order_by, limit)` → [`DocumentHavingMode`]
3//! resolution — including the operator → inclusive-bounds translation
4//! that turns a `HAVING <agg> <op> <value>` clause into an
5//! [`AxisRangeBounds`].
6//!
7//! Pure functions on the request shape — no Drive, no contract, no
8//! indexes. Available under `server` and `verify` for the same reason as
9//! [`super::super::drive_document_ranked_query::mode_detection`]: both
10//! sides must agree on which requests are well-formed and on the exact
11//! bounds a well-formed one resolves to, because the verifier rebuilds
12//! the bounded traversal from those bounds and re-executes the proof
13//! against it.
14//!
15//! Versioned through
16//! `platform_version.drive.methods.document.query.detect_having_mode` —
17//! the accepted grammar is a consensus-adjacent contract on the query
18//! surface, so relaxing it later (multi-clause `HAVING`, `IN`, a
19//! pagination cursor) lands behind a method-version bump.
20
21use super::super::drive_document_ranked_query::RankedPaginationInputs;
22use super::{AxisRangeBounds, DocumentHavingMode, MAX_HAVING_LIMIT};
23use crate::error::query::QuerySyntaxError;
24use crate::error::Error;
25use crate::query::having::HavingClause;
26use crate::query::projection::SelectProjection;
27use crate::query::{OrderClause, WhereClause};
28use dpp::version::PlatformVersion;
29
30/// Versioned entry point. Routes through
31/// `platform_version.drive.methods.document.query.detect_having_mode`;
32/// today only `0` is defined and maps to [`detect_having_mode_v0`]
33/// verbatim.
34///
35/// # Parameters
36///
37/// * `select`: The selected aggregate (`COUNT(*)`, `SUM(f)` or `AVG(f)`).
38/// * `group_by`: The `GROUP BY` properties; exactly one is accepted.
39/// * `having`: The `HAVING` clauses; exactly one, on the selected aggregate, is accepted.
40/// * `order_by`: The `ORDER BY` clauses; at most one, naming the selected aggregate.
41/// * `where_clauses`: The `WHERE` clauses pinning the covering index's leading properties.
42/// * `pagination`: The request's limit, offset and whether it carried a start cursor.
43/// * `platform_version`: The platform version.
44///
45/// # Returns
46///
47/// * `Ok(DocumentHavingMode)` with the inclusive bounds, the direction, the limit, the group
48///   property, the aggregate field and the prefix pins.
49/// * `Err(Error)` with a query syntax error when the method version is unknown or the request
50///   falls outside the accepted grammar.
51#[allow(clippy::too_many_arguments)]
52pub fn detect_having_mode(
53    select: &SelectProjection,
54    group_by: &[String],
55    having: &[HavingClause],
56    order_by: &[OrderClause],
57    where_clauses: &[WhereClause],
58    pagination: RankedPaginationInputs,
59    platform_version: &PlatformVersion,
60) -> Result<DocumentHavingMode, Error> {
61    match platform_version
62        .drive
63        .methods
64        .document
65        .query
66        .detect_having_mode
67    {
68        0 => detect_having_mode_v0(
69            select,
70            group_by,
71            having,
72            order_by,
73            where_clauses,
74            pagination,
75        ),
76        version => Err(Error::Query(QuerySyntaxError::Unsupported(format!(
77            "detect_having_mode: unknown method version {version}; only 0 is supported"
78        )))),
79    }
80}
81
82mod v0;
83// Re-exported so the dispatcher's callers (`drive_dispatcher`, the
84// test suites) keep addressing the frozen grammar by its old path.
85pub use v0::detect_having_mode_v0;