Skip to main content

icydb_core/db/query/
read_intent.rs

1//! Module: query::read_intent
2//! Responsibility: hardcoded read-intent caps for public semantic terminals.
3//! Does not own: planner proof, executor routing, or public policy builders.
4//! Boundary: one internal authority for engine-owned read-intent limits.
5
6use crate::db::query::admission::DEFAULT_BOUNDED_READ_MAX_ROWS;
7use candid::CandidType;
8use serde::Deserialize;
9
10pub(in crate::db::query) const PUBLIC_PAGE_DEFAULT_ROWS: u32 = DEFAULT_BOUNDED_READ_MAX_ROWS;
11pub(in crate::db::query) const PUBLIC_PAGE_MAX_ROWS: u32 = DEFAULT_BOUNDED_READ_MAX_ROWS;
12pub(in crate::db::query) const COMPLETE_SMALL_MAX_ROWS: u32 = DEFAULT_BOUNDED_READ_MAX_ROWS;
13pub(in crate::db::query) const COMPLETE_SMALL_LOOKAHEAD_ROWS: u32 = 1;
14pub(in crate::db::query) const COMPLETE_SMALL_EXECUTION_LIMIT: u32 =
15    COMPLETE_SMALL_MAX_ROWS + COMPLETE_SMALL_LOOKAHEAD_ROWS;
16pub(in crate::db::query) const ADMIN_BATCH_ROWS: u32 = DEFAULT_BOUNDED_READ_MAX_ROWS;
17
18/// Semantic read intent selected by a caller-facing terminal.
19///
20/// This is diagnostic metadata only. It does not grant access, choose planner
21/// routes, or configure admission policy.
22#[derive(CandidType, Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)]
23pub enum ReadIntentKind {
24    /// No semantic read intent was attached to this diagnostic payload.
25    #[default]
26    Unspecified,
27
28    /// Low-level execution over the effective bounded row window.
29    BoundedRowWindow,
30
31    /// Boolean existence check.
32    ExistenceCheck,
33
34    /// Request-owned public cursor page.
35    PublicPage,
36
37    /// Complete small-set read that fails instead of silently truncating.
38    CompleteSmallSet,
39
40    /// Exact aggregate terminal such as count, sum, min, max, or average.
41    ExactAggregate,
42
43    /// Trusted/admin cursor batch with engine-owned batch size.
44    TrustedAdminBatch,
45}
46
47/// Internal public-page request shape.
48///
49/// The requested limit is a caller preference, not a custom policy. IcyDB
50/// clamps it to the engine-owned public page cap before admission/execution.
51#[derive(Clone, Debug, Default, Eq, PartialEq)]
52pub(in crate::db::query) struct PageRequest {
53    limit: Option<u32>,
54    cursor: Option<String>,
55}
56
57impl PageRequest {
58    /// Build a first-page request with one requested page size.
59    #[must_use]
60    pub(in crate::db::query) const fn first(limit: u32) -> Self {
61        Self {
62            limit: Some(limit),
63            cursor: None,
64        }
65    }
66
67    /// Build a continuation request with one requested page size and cursor.
68    #[must_use]
69    pub(in crate::db::query) fn next(limit: u32, cursor: impl Into<String>) -> Self {
70        Self {
71            limit: Some(limit),
72            cursor: Some(cursor.into()),
73        }
74    }
75
76    pub(in crate::db::query) const fn effective_limit(&self) -> u32 {
77        match self.limit {
78            Some(0) => 1,
79            Some(limit) if limit > PUBLIC_PAGE_MAX_ROWS => PUBLIC_PAGE_MAX_ROWS,
80            Some(limit) => limit,
81            None => PUBLIC_PAGE_DEFAULT_ROWS,
82        }
83    }
84
85    pub(in crate::db::query) fn into_cursor(self) -> Option<String> {
86        self.cursor
87    }
88}
89
90/// Request-owned trusted/admin batch continuation shape.
91///
92/// The batch size is engine-owned. Callers may only supply an opaque cursor
93/// for continuation, and the terminal remains gated to trusted read lanes.
94#[derive(Clone, Debug, Default, Eq, PartialEq)]
95pub struct AdminBatchRequest {
96    cursor: Option<String>,
97}
98
99impl AdminBatchRequest {
100    /// Build a first-batch request.
101    #[must_use]
102    pub const fn new() -> Self {
103        Self { cursor: None }
104    }
105
106    /// Build a continuation request with an opaque cursor.
107    #[must_use]
108    pub fn next(cursor: impl Into<String>) -> Self {
109        Self {
110            cursor: Some(cursor.into()),
111        }
112    }
113
114    pub(in crate::db::query) fn into_cursor(self) -> Option<String> {
115        self.cursor
116    }
117}