Skip to main content

reifydb_client/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3#[cfg(feature = "grpc")]
4pub mod grpc;
5#[cfg(feature = "http")]
6pub mod http;
7#[cfg(any(feature = "http", feature = "ws"))]
8mod session;
9#[cfg(feature = "ws")]
10mod utils;
11#[cfg(feature = "ws")]
12pub mod ws;
13
14// Re-export client types
15#[cfg(feature = "grpc")]
16pub use grpc::{GrpcClient, GrpcSubscription};
17#[cfg(feature = "http")]
18pub use http::HttpClient;
19// Re-export derive macro
20pub use reifydb_client_derive::FromFrame;
21// Re-export commonly used types from reifydb-type
22pub use reifydb_type as r#type;
23#[cfg(any(feature = "http", feature = "ws"))]
24use reifydb_type::error::Diagnostic;
25pub use reifydb_type::{
26	params::Params,
27	value::{
28		Value,
29		frame::{
30			column::FrameColumn,
31			data::FrameColumnData,
32			extract::FrameError,
33			frame::Frame,
34			from_frame::FromFrameError,
35			row::{FrameRow, FrameRows},
36		},
37		ordered_f32::OrderedF32,
38		ordered_f64::OrderedF64,
39		try_from::{FromValueError, TryFromValue, TryFromValueCoerce},
40		r#type::Type,
41	},
42};
43#[cfg(any(feature = "http", feature = "ws"))]
44use serde::{Deserialize, Serialize};
45#[cfg(feature = "ws")]
46pub use ws::WsClient;
47
48/// Result type for admin operations
49#[derive(Debug)]
50pub struct AdminResult {
51	pub frames: Vec<Frame>,
52}
53
54/// Result type for command operations
55#[derive(Debug)]
56pub struct CommandResult {
57	pub frames: Vec<Frame>,
58}
59
60/// Result type for query operations
61#[derive(Debug)]
62pub struct QueryResult {
63	pub frames: Vec<Frame>,
64}
65
66#[cfg(any(feature = "http", feature = "ws"))]
67/// Wire format for a single typed value: `{"type": "Int2", "value": "1234"}`.
68#[derive(Debug, Serialize, Deserialize)]
69pub struct WireValue {
70	#[serde(rename = "type")]
71	pub type_name: String,
72	pub value: String,
73}
74
75#[cfg(any(feature = "http", feature = "ws"))]
76/// Wire format for query parameters.
77///
78/// Either positional or named:
79/// - Positional: `[{"type":"Int2","value":"1234"}, ...]`
80/// - Named: `{"key": {"type":"Int2","value":"1234"}, ...}`
81#[derive(Debug, Serialize, Deserialize)]
82#[serde(untagged)]
83pub enum WireParams {
84	Positional(Vec<WireValue>),
85	Named(std::collections::HashMap<String, WireValue>),
86}
87
88#[cfg(any(feature = "http", feature = "ws"))]
89fn value_to_wire(value: Value) -> WireValue {
90	let (type_name, value_str): (&str, String) = match &value {
91		Value::None {
92			..
93		} => ("None", "\u{27EA}none\u{27EB}".to_string()),
94		Value::Boolean(b) => ("Boolean", b.to_string()),
95		Value::Float4(f) => ("Float4", f.to_string()),
96		Value::Float8(f) => ("Float8", f.to_string()),
97		Value::Int1(i) => ("Int1", i.to_string()),
98		Value::Int2(i) => ("Int2", i.to_string()),
99		Value::Int4(i) => ("Int4", i.to_string()),
100		Value::Int8(i) => ("Int8", i.to_string()),
101		Value::Int16(i) => ("Int16", i.to_string()),
102		Value::Utf8(s) => ("Utf8", s.clone()),
103		Value::Uint1(u) => ("Uint1", u.to_string()),
104		Value::Uint2(u) => ("Uint2", u.to_string()),
105		Value::Uint4(u) => ("Uint4", u.to_string()),
106		Value::Uint8(u) => ("Uint8", u.to_string()),
107		Value::Uint16(u) => ("Uint16", u.to_string()),
108		Value::Uuid4(u) => ("Uuid4", u.to_string()),
109		Value::Uuid7(u) => ("Uuid7", u.to_string()),
110		Value::Date(d) => ("Date", d.to_string()),
111		Value::DateTime(dt) => ("DateTime", dt.to_string()),
112		Value::Time(t) => ("Time", t.to_string()),
113		Value::Duration(d) => ("Duration", d.to_iso_string()),
114		Value::Blob(b) => ("Blob", b.to_hex()),
115		Value::IdentityId(id) => ("IdentityId", id.to_string()),
116		Value::Int(i) => ("Int", i.to_string()),
117		Value::Uint(u) => ("Uint", u.to_string()),
118		Value::Decimal(d) => ("Decimal", d.to_string()),
119		Value::Any(v) => return value_to_wire(*v.clone()),
120		Value::DictionaryId(id) => ("DictionaryId", id.to_string()),
121		Value::Type(t) => ("Type", t.to_string()),
122		Value::List(items) => ("List", format!("{}", Value::List(items.clone()))),
123		Value::Record(fields) => ("Record", format!("{}", Value::Record(fields.clone()))),
124		Value::Tuple(items) => ("Tuple", format!("{}", Value::Tuple(items.clone()))),
125	};
126	WireValue {
127		type_name: type_name.to_string(),
128		value: value_str,
129	}
130}
131
132#[cfg(any(feature = "http", feature = "ws"))]
133pub fn params_to_wire(params: Params) -> Option<WireParams> {
134	match params {
135		Params::None => None,
136		Params::Positional(values) => {
137			Some(WireParams::Positional(values.into_iter().map(value_to_wire).collect()))
138		}
139		Params::Named(map) => {
140			Some(WireParams::Named(map.into_iter().map(|(k, v)| (k, value_to_wire(v))).collect()))
141		}
142	}
143}
144
145#[cfg(any(feature = "http", feature = "ws"))]
146#[derive(Debug, Serialize, Deserialize)]
147pub struct Request {
148	pub id: String,
149	#[serde(flatten)]
150	pub payload: RequestPayload,
151}
152
153#[cfg(any(feature = "http", feature = "ws"))]
154#[derive(Debug, Serialize, Deserialize)]
155#[serde(tag = "type", content = "payload")]
156pub enum RequestPayload {
157	Auth(AuthRequest),
158	Admin(AdminRequest),
159	Command(CommandRequest),
160	Query(QueryRequest),
161	Subscribe(SubscribeRequest),
162	Unsubscribe(UnsubscribeRequest),
163}
164
165#[cfg(any(feature = "http", feature = "ws"))]
166#[derive(Debug, Serialize, Deserialize)]
167pub struct AdminRequest {
168	pub statements: Vec<String>,
169	pub params: Option<WireParams>,
170}
171
172#[cfg(any(feature = "http", feature = "ws"))]
173#[derive(Debug, Serialize, Deserialize)]
174pub struct AuthRequest {
175	pub token: Option<String>,
176}
177
178#[cfg(any(feature = "http", feature = "ws"))]
179#[derive(Debug, Serialize, Deserialize)]
180pub struct CommandRequest {
181	pub statements: Vec<String>,
182	pub params: Option<WireParams>,
183}
184
185#[cfg(any(feature = "http", feature = "ws"))]
186#[derive(Debug, Serialize, Deserialize)]
187pub struct QueryRequest {
188	pub statements: Vec<String>,
189	pub params: Option<WireParams>,
190}
191
192#[cfg(any(feature = "http", feature = "ws"))]
193#[derive(Debug, Serialize, Deserialize)]
194pub struct SubscribeRequest {
195	pub query: String,
196}
197
198#[cfg(any(feature = "http", feature = "ws"))]
199#[derive(Debug, Serialize, Deserialize)]
200pub struct UnsubscribeRequest {
201	pub subscription_id: String,
202}
203
204#[cfg(any(feature = "http", feature = "ws"))]
205#[derive(Debug, Serialize, Deserialize)]
206pub struct Response {
207	pub id: String,
208	#[serde(flatten)]
209	pub payload: ResponsePayload,
210}
211
212#[cfg(any(feature = "http", feature = "ws"))]
213#[derive(Debug, Serialize, Deserialize)]
214#[serde(tag = "type", content = "payload")]
215pub enum ResponsePayload {
216	Auth(AuthResponse),
217	Err(ErrResponse),
218	Admin(AdminResponse),
219	Command(CommandResponse),
220	Query(QueryResponse),
221	Subscribed(SubscribedResponse),
222	Unsubscribed(UnsubscribedResponse),
223}
224
225#[cfg(any(feature = "http", feature = "ws"))]
226#[derive(Debug, Serialize, Deserialize)]
227pub struct AdminResponse {
228	pub content_type: String,
229	pub body: serde_json::Value,
230}
231
232#[cfg(any(feature = "http", feature = "ws"))]
233#[derive(Debug, Serialize, Deserialize)]
234pub struct AuthResponse {}
235
236#[cfg(any(feature = "http", feature = "ws"))]
237#[derive(Debug, Serialize, Deserialize)]
238pub struct ErrResponse {
239	pub diagnostic: Diagnostic,
240}
241
242#[cfg(any(feature = "http", feature = "ws"))]
243#[derive(Debug, Serialize, Deserialize)]
244pub struct CommandResponse {
245	pub content_type: String,
246	pub body: serde_json::Value,
247}
248
249#[cfg(any(feature = "http", feature = "ws"))]
250#[derive(Debug, Serialize, Deserialize)]
251pub struct QueryResponse {
252	pub content_type: String,
253	pub body: serde_json::Value,
254}
255
256#[cfg(any(feature = "http", feature = "ws"))]
257#[derive(Debug, Serialize, Deserialize)]
258pub struct SubscribedResponse {
259	pub subscription_id: String,
260}
261
262#[cfg(any(feature = "http", feature = "ws"))]
263#[derive(Debug, Serialize, Deserialize)]
264pub struct UnsubscribedResponse {
265	pub subscription_id: String,
266}
267
268#[cfg(any(feature = "http", feature = "ws"))]
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct WebsocketFrame {
271	pub row_numbers: Vec<u64>,
272	pub columns: Vec<WebsocketColumn>,
273}
274
275#[cfg(any(feature = "http", feature = "ws"))]
276#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct WebsocketColumn {
278	pub name: String,
279	pub r#type: Type,
280	pub data: Vec<String>,
281}
282
283#[cfg(any(feature = "http", feature = "ws"))]
284/// Server-initiated push message (no request id).
285#[derive(Debug, Serialize, Deserialize)]
286#[serde(tag = "type", content = "payload")]
287pub enum ServerPush {
288	Change(ChangePayload),
289}
290
291#[cfg(any(feature = "http", feature = "ws"))]
292/// Payload for subscription change notifications.
293#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct ChangePayload {
295	pub subscription_id: String,
296	pub content_type: String,
297	pub body: serde_json::Value,
298}