Skip to main content

riffdb_client_rust/generated/
mod.rs

1//! Stable boundary for compiler-generated Rust command modules.
2
3use std::error::Error;
4use std::fmt;
5
6use riffdb_proto::{app::v1 as app_v1, v1};
7use riffdb_types::RequestId;
8
9use crate::{
10    ApplicationClientError, ApplicationEvent, ApplicationEventConsumer, ApplicationLiveQueryUpdate,
11    ApplicationReactiveOperation, CommandShapeError, IdempotentCommand, NamedQuery,
12    NamedQueryResult, QueryOptions,
13};
14
15/// One exact generated durable event-stream selection and decoder.
16pub trait GeneratedEventConsumer {
17    /// Closed generated event union.
18    type Event;
19
20    /// Constructs the exact immutable consumer selection.
21    fn event_consumer(self) -> Result<ApplicationEventConsumer, ApplicationClientError>;
22
23    /// Decodes one already authorized selected event by symbolic names only.
24    fn decode_event(event: ApplicationEvent) -> Result<Self::Event, ApplicationClientError>;
25}
26
27/// One exact generated live named-query watch and closed update decoder.
28pub trait GeneratedLiveQuery {
29    /// Closed generated update union.
30    type Update;
31
32    /// Constructs the exact immutable watch operation.
33    fn live_operation(self) -> Result<ApplicationReactiveOperation, ApplicationClientError>;
34
35    /// Decodes one structurally checked application-safe update.
36    fn decode_update(
37        update: ApplicationLiveQueryUpdate,
38    ) -> Result<Self::Update, ApplicationClientError>;
39}
40
41/// One exact named query shape emitted from an immutable query module.
42pub trait GeneratedQuery {
43    /// The generated declared-result union.
44    type Output;
45
46    /// Constructs the exact module-pinned symbolic request.
47    fn named_query(self, options: QueryOptions) -> Result<NamedQuery, ApplicationClientError>;
48
49    /// Decodes one identity-checked name-addressed response.
50    fn decode_result(response: NamedQueryResult) -> Result<Self::Output, ApplicationClientError>;
51
52    /// Decodes the compiler-sealed positional arm without constructing generic
53    /// per-row maps. Only cover-eligible generated operations override this.
54    fn decode_compact_result(
55        _outcome: String,
56        _response: app_v1::CompactResultField,
57    ) -> Result<Self::Output, ApplicationClientError> {
58        Err(ApplicationClientError::InvalidResponse)
59    }
60
61    /// Decodes the compiler-sealed canonical-column arm directly into the
62    /// generated result without constructing generic value or row maps.
63    fn decode_packed_result(
64        _outcome: String,
65        _response: app_v1::PackedResultField,
66    ) -> Result<Self::Output, ApplicationClientError> {
67        Err(ApplicationClientError::InvalidResponse)
68    }
69}
70
71/// One command shape emitted from a checked contract bundle.
72///
73/// Implementations contain only value-shape ergonomics. The server remains
74/// authoritative for schema validation and every database guarantee.
75pub trait GeneratedCommand {
76    /// The generated declared-outcome enum.
77    type Outcome;
78
79    /// Constructs the immutable generic transport command.
80    fn idempotent_command(&self) -> Result<IdempotentCommand, GeneratedCommandError>;
81
82    /// Constructs same-key outcome recovery from this typed command input.
83    ///
84    /// The generated implementation owns the schema binding between the
85    /// command input's idempotency field and this recovery request.
86    fn outcome_request(
87        &self,
88        request_id: RequestId,
89    ) -> Result<v1::GetOutcomeRequest, GeneratedCommandError>;
90
91    /// Decodes a structurally checked Execute response into the generated outcome.
92    fn decode_outcome(
93        &self,
94        response: &v1::ExecuteCommandResponse,
95    ) -> Result<Self::Outcome, GeneratedCommandError>;
96
97    /// Derives compiler-owned successor revisions for successful checked
98    /// workflow mutations.
99    ///
100    /// Ordinary commands return no revisions. Generated workflow bindings
101    /// override this method and derive each successor from the exact observed
102    /// revision that the server accepted. The response outcome gates the
103    /// derivation, so stale or illegal business outcomes never manufacture a
104    /// revision.
105    fn workflow_successor_revisions(
106        &self,
107        _response: &v1::ExecuteCommandResponse,
108    ) -> Result<Vec<WorkflowSuccessorRevision>, GeneratedCommandError> {
109        Ok(Vec::new())
110    }
111}
112
113/// Successor revision produced by one checked workflow binding mutation.
114#[derive(Clone, Debug, Eq, PartialEq)]
115pub struct WorkflowSuccessorRevision {
116    binding: &'static str,
117    revision: u64,
118}
119
120impl WorkflowSuccessorRevision {
121    /// Constructs compiler-generated successor evidence.
122    #[must_use]
123    pub const fn generated(binding: &'static str, revision: u64) -> Self {
124        Self { binding, revision }
125    }
126
127    /// Exact source binding whose entity revision advanced.
128    #[must_use]
129    pub const fn binding(&self) -> &'static str {
130        self.binding
131    }
132
133    /// Exact successor revision after the successful command.
134    #[must_use]
135    pub const fn revision(&self) -> u64 {
136        self.revision
137    }
138}
139
140/// Closed reason for a generated, exact local collection-budget refusal.
141#[derive(Clone, Copy, Debug, Eq, PartialEq)]
142pub enum GeneratedInputBudgetCause {
143    /// The submitted collection is below its minimum or above its maximum.
144    CollectionCount,
145    /// One bounded string or byte leaf exceeds its declared maximum.
146    IndividualValueBytes,
147    /// The sum of canonical element encodings exceeds the compiled aggregate.
148    AggregateCanonicalElementBytes,
149}
150
151impl GeneratedInputBudgetCause {
152    /// Stable application-facing cause tag.
153    #[must_use]
154    pub const fn as_str(self) -> &'static str {
155        match self {
156            Self::CollectionCount => "collection_count",
157            Self::IndividualValueBytes => "individual_value_bytes",
158            Self::AggregateCanonicalElementBytes => "aggregate_canonical_element_bytes",
159        }
160    }
161}
162
163/// Symbolic, value-free path for one generated collection-budget refusal.
164#[derive(Clone, Copy, Debug, Eq, PartialEq)]
165pub struct GeneratedInputBudgetError {
166    cause: GeneratedInputBudgetCause,
167    collection: &'static str,
168    index: Option<usize>,
169    leaf: Option<&'static str>,
170}
171
172impl GeneratedInputBudgetError {
173    /// Constructs one compiler-emitted local budget refusal.
174    #[must_use]
175    pub const fn new(
176        cause: GeneratedInputBudgetCause,
177        collection: &'static str,
178        index: Option<usize>,
179        leaf: Option<&'static str>,
180    ) -> Self {
181        Self {
182            cause,
183            collection,
184            index,
185            leaf,
186        }
187    }
188
189    /// Closed cause tag.
190    #[must_use]
191    pub const fn cause(&self) -> GeneratedInputBudgetCause {
192        self.cause
193    }
194
195    /// Symbolic collection field.
196    #[must_use]
197    pub const fn collection(&self) -> &'static str {
198        self.collection
199    }
200
201    /// Submitted element index, when the refusal identifies one element.
202    #[must_use]
203    pub const fn index(&self) -> Option<usize> {
204        self.index
205    }
206
207    /// Symbolic bounded leaf, when the refusal identifies one leaf.
208    #[must_use]
209    pub const fn leaf(&self) -> Option<&'static str> {
210        self.leaf
211    }
212}
213
214/// A closed failure in generated shape-only code.
215#[derive(Clone, Copy, Debug, Eq, PartialEq)]
216pub enum GeneratedCommandError {
217    /// Typed input could not form the frozen generic command envelope.
218    InvalidInputShape,
219    /// A successful response did not match the generated declared-outcome union.
220    InvalidOutcomeShape,
221    /// Exact typed local collection-budget preflight refused the command.
222    InputBudget(GeneratedInputBudgetError),
223}
224
225impl GeneratedCommandError {
226    /// Constructs one compiler-emitted local budget refusal.
227    #[must_use]
228    pub const fn input_budget(
229        cause: GeneratedInputBudgetCause,
230        collection: &'static str,
231        index: Option<usize>,
232        leaf: Option<&'static str>,
233    ) -> Self {
234        Self::InputBudget(GeneratedInputBudgetError::new(
235            cause, collection, index, leaf,
236        ))
237    }
238}
239
240impl From<CommandShapeError> for GeneratedCommandError {
241    fn from(_: CommandShapeError) -> Self {
242        Self::InvalidInputShape
243    }
244}
245
246impl fmt::Display for GeneratedCommandError {
247    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
248        formatter.write_str(match self {
249            Self::InvalidInputShape => "generated command input is invalid",
250            Self::InvalidOutcomeShape => "generated command outcome is invalid",
251            Self::InputBudget(_) => "generated command input exceeds its compiled budget",
252        })
253    }
254}
255
256impl Error for GeneratedCommandError {}
257
258/// Generated ergonomic bindings for the canonical POC contract.
259pub mod legal_spend;