reifydb_sub_server/binding.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4//! Dispatch bridge for Binding-driven calls.
5//!
6//! Synthesizes a `CALL ns::proc()` statement from a `Binding` + caller-supplied `Params`
7//! and routes it through the shared `dispatch::dispatch` pipeline. All three transport
8//! crates (HTTP, gRPC, WS) call this helper and wrap the returned `(Vec<Frame>, ExecutionMetrics)`
9//! in their own response envelope.
10
11#[cfg(not(reifydb_single_threaded))]
12use std::fmt::Write;
13
14#[cfg(not(reifydb_single_threaded))]
15use reifydb_core::{actors::server::Operation, metric::ExecutionMetrics};
16#[cfg(not(reifydb_single_threaded))]
17use reifydb_type::{
18 params::Params,
19 value::{frame::frame::Frame, identity::IdentityId},
20};
21
22#[cfg(not(reifydb_single_threaded))]
23use crate::{
24 dispatch::dispatch,
25 execute::ExecuteError,
26 interceptor::{RequestContext, RequestMetadata},
27 state::AppState,
28};
29
30/// Synthesize and dispatch `CALL {ns}::{proc}()` for a binding; parameters are resolved
31/// at execution time from `params` (no `$name` placeholders in the CALL text).
32///
33/// The caller is responsible for:
34/// - Resolving the binding and locating its procedure by `binding.procedure_id`.
35/// - Validating `params` against the procedure's declared parameter list (rejecting unknown keys, missing required,
36/// type-coercion failures) before calling here.
37/// - Building `RequestMetadata` from its transport-specific request.
38///
39/// Returns `(frames, metrics)` from the engine; each transport wraps it into its own
40/// response format based on `binding.format` and reads `metrics.total` / `metrics.fingerprint`
41/// for telemetry headers.
42#[cfg(not(reifydb_single_threaded))]
43pub async fn dispatch_binding(
44 state: &AppState,
45 namespace_path: &str,
46 procedure_name: &str,
47 params: Params,
48 identity: IdentityId,
49 metadata: RequestMetadata,
50) -> Result<(Vec<Frame>, ExecutionMetrics), ExecuteError> {
51 let mut call_text = String::with_capacity(8 + namespace_path.len() + procedure_name.len());
52 write!(&mut call_text, "CALL {}::{}()", namespace_path, procedure_name).unwrap();
53
54 let ctx = RequestContext {
55 identity,
56 operation: Operation::Command,
57 rql: call_text,
58 params,
59 metadata,
60 };
61
62 dispatch(state, ctx).await
63}