1#![cfg_attr(not(debug_assertions), deny(clippy::disallowed_methods))]
4#![cfg_attr(debug_assertions, warn(clippy::disallowed_methods))]
5#![allow(clippy::tabs_in_doc_comments)]
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
8#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
9#[cfg_attr(any(feature = "http", feature = "ws"), serde(rename_all = "lowercase"))]
10pub enum WireFormat {
11 #[default]
12 Frames,
13 Rbcf,
14}
15
16#[cfg(any(feature = "ws", feature = "grpc"))]
17mod changes;
18#[cfg(any(feature = "ws", feature = "grpc"))]
19pub mod client;
20#[cfg(all(feature = "dst", reifydb_single_threaded))]
21pub mod dst;
22#[cfg(any(feature = "http", feature = "ws", feature = "grpc"))]
23pub mod error;
24#[cfg(feature = "grpc")]
25pub mod grpc;
26#[cfg(feature = "http")]
27pub mod http;
28#[cfg(any(feature = "ws", feature = "grpc"))]
29mod reconnect;
30#[cfg(any(feature = "http", feature = "ws"))]
31mod session;
32#[cfg(any(feature = "ws", feature = "grpc", all(feature = "dst", reifydb_single_threaded)))]
33pub mod subscription;
34#[cfg(feature = "ws")]
35mod utils;
36#[cfg(feature = "ws")]
37pub mod ws;
38
39#[cfg(any(feature = "http", feature = "ws"))]
40use std::collections::HashMap;
41#[cfg(any(feature = "http", feature = "ws", feature = "grpc"))]
42use std::sync::Arc;
43
44#[cfg(all(feature = "dst", reifydb_single_threaded))]
45pub use dst::DstClient;
46#[cfg(any(feature = "http", feature = "ws", feature = "grpc"))]
47pub use error::ClientError;
48#[cfg(feature = "grpc")]
49pub use grpc::{
50 BatchFramesEnvelope, BatchGrpcSubscription, BatchMemberHandle, BatchStreamEvent, GrpcChange, GrpcClient,
51 GrpcClientOptions, GrpcSubscription, RawChangePayload,
52};
53#[cfg(feature = "http")]
54pub use http::HttpClient;
55pub use reifydb_client_derive::FromFrame;
56pub use reifydb_value as value;
57#[cfg(any(feature = "ws", feature = "grpc"))]
58use reifydb_value::error::Error;
59pub use reifydb_value::{
60 params::Params,
61 value::{
62 Value,
63 frame::{
64 column::FrameColumn,
65 data::FrameColumnData,
66 extract::FrameError,
67 frame::Frame,
68 from_frame::FromFrameError,
69 row::{FrameRow, FrameRows},
70 },
71 iso::{IsoDate, IsoDateTime, IsoDuration, IsoTime},
72 ordered_f32::OrderedF32,
73 ordered_f64::OrderedF64,
74 try_from::{FromValueError, TryFromValue, TryFromValueCoerce},
75 value_type::ValueType,
76 },
77};
78#[cfg(any(feature = "http", feature = "ws"))]
79use serde::{Deserialize, Serialize};
80use serde_json::Value as JsonValue;
81#[cfg(any(feature = "ws", feature = "grpc", all(feature = "dst", reifydb_single_threaded)))]
82pub use subscription::{BatchItem, HydrationConfig, Linger, SubscriptionConfig, Throttle, build_subscription_rql};
83#[cfg(feature = "ws")]
84pub use ws::{WsBatchSubscription, WsClient, WsClientOptions};
85
86#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
87#[derive(Debug, Clone)]
88pub struct ResponseMeta {
89 pub fingerprint: String,
90 pub duration: String,
91}
92
93#[derive(Debug)]
94pub struct AdminResult {
95 pub frames: Vec<Frame>,
96 pub meta: Option<ResponseMeta>,
97}
98
99#[derive(Debug)]
100pub struct CommandResult {
101 pub frames: Vec<Frame>,
102 pub meta: Option<ResponseMeta>,
103}
104
105#[derive(Debug)]
106pub struct QueryResult {
107 pub frames: Vec<Frame>,
108 pub meta: Option<ResponseMeta>,
109}
110
111#[derive(Debug, Clone)]
112pub struct LoginResult {
113 pub token: String,
114 pub identity: String,
115}
116
117#[cfg(any(feature = "ws", feature = "grpc"))]
118pub fn connection_lost_error() -> Error {
119 ClientError::ConnectionLost.into()
120}
121
122#[cfg(any(feature = "ws", feature = "grpc"))]
127#[derive(Clone)]
128pub struct ReconnectOptions {
129 pub max_reconnect_attempts: u32,
130 pub reconnect_delay_ms: u64,
131 pub connect_timeout_ms: u64,
132 pub on_disconnect: Option<Arc<dyn Fn() + Send + Sync>>,
133 pub on_reconnect: Option<Arc<dyn Fn() + Send + Sync>>,
134}
135
136#[cfg(any(feature = "ws", feature = "grpc"))]
137impl Default for ReconnectOptions {
138 fn default() -> Self {
139 Self {
140 max_reconnect_attempts: 5,
141 reconnect_delay_ms: 1000,
142 connect_timeout_ms: 30_000,
143 on_disconnect: None,
144 on_reconnect: None,
145 }
146 }
147}
148
149#[cfg(any(feature = "http", feature = "ws"))]
150#[derive(Debug, Serialize, Deserialize)]
152pub struct WireValue {
153 #[serde(rename = "type")]
154 pub type_name: String,
155 pub value: String,
156}
157
158#[cfg(any(feature = "http", feature = "ws"))]
159#[derive(Debug, Serialize, Deserialize)]
161#[serde(untagged)]
162pub enum WireParams {
163 Positional(Vec<WireValue>),
164 Named(HashMap<String, WireValue>),
165}
166
167#[cfg(any(feature = "http", feature = "ws"))]
168fn value_to_wire(value: Value) -> WireValue {
169 let (type_name, value_str): (&str, String) = match &value {
170 Value::None {
171 ..
172 } => ("None", "\u{27EA}none\u{27EB}".to_string()),
173 Value::Boolean(b) => ("Boolean", b.to_string()),
174 Value::Float4(f) => ("Float4", f.to_string()),
175 Value::Float8(f) => ("Float8", f.to_string()),
176 Value::Int1(i) => ("Int1", i.to_string()),
177 Value::Int2(i) => ("Int2", i.to_string()),
178 Value::Int4(i) => ("Int4", i.to_string()),
179 Value::Int8(i) => ("Int8", i.to_string()),
180 Value::Int16(i) => ("Int16", i.to_string()),
181 Value::Utf8(s) => ("Utf8", s.clone()),
182 Value::Uint1(u) => ("Uint1", u.to_string()),
183 Value::Uint2(u) => ("Uint2", u.to_string()),
184 Value::Uint4(u) => ("Uint4", u.to_string()),
185 Value::Uint8(u) => ("Uint8", u.to_string()),
186 Value::Uint16(u) => ("Uint16", u.to_string()),
187 Value::Uuid4(u) => ("Uuid4", u.to_string()),
188 Value::Uuid7(u) => ("Uuid7", u.to_string()),
189 Value::Date(d) => ("Date", d.to_string()),
190 Value::DateTime(dt) => ("DateTime", dt.to_string()),
191 Value::Time(t) => ("Time", t.to_string()),
192 Value::Duration(d) => ("Duration", d.to_iso_string()),
193 Value::Blob(b) => ("Blob", b.to_hex()),
194 Value::IdentityId(id) => ("IdentityId", id.to_string()),
195 Value::Int(i) => ("Int", i.to_string()),
196 Value::Uint(u) => ("Uint", u.to_string()),
197 Value::Decimal(d) => ("Decimal", d.to_string()),
198 Value::Any(v) => return value_to_wire(*v.clone()),
199 Value::DictionaryId(id) => ("DictionaryId", id.to_string()),
200 Value::Type(t) => ("ValueType", t.to_string()),
201 Value::List(items) => ("List", format!("{}", Value::List(items.clone()))),
202 Value::Record(fields) => ("Record", format!("{}", Value::Record(fields.clone()))),
203 Value::Tuple(items) => ("Tuple", format!("{}", Value::Tuple(items.clone()))),
204 };
205 WireValue {
206 type_name: type_name.to_string(),
207 value: value_str,
208 }
209}
210
211#[cfg(any(feature = "http", feature = "ws"))]
212pub fn params_to_wire(params: Params) -> Option<WireParams> {
213 match params {
214 Params::None => None,
215 Params::Positional(values) => Some(WireParams::Positional(
216 Arc::unwrap_or_clone(values).into_iter().map(value_to_wire).collect(),
217 )),
218 Params::Named(map) => Some(WireParams::Named(
219 Arc::unwrap_or_clone(map).into_iter().map(|(k, v)| (k, value_to_wire(v))).collect(),
220 )),
221 }
222}
223
224#[cfg(any(feature = "http", feature = "ws"))]
225#[derive(Debug, Serialize, Deserialize)]
226pub struct Request {
227 pub id: String,
228 #[serde(flatten)]
229 pub payload: RequestPayload,
230}
231
232#[cfg(any(feature = "http", feature = "ws"))]
233#[derive(Debug, Serialize, Deserialize)]
234#[serde(tag = "type", content = "payload")]
235pub enum RequestPayload {
236 Auth(AuthRequest),
237 Admin(AdminRequest),
238 Command(CommandRequest),
239 Query(QueryRequest),
240 Subscribe(SubscribeRequest),
241 Unsubscribe(UnsubscribeRequest),
242 BatchSubscribe(BatchSubscribeRequest),
243 BatchUnsubscribe(BatchUnsubscribeRequest),
244 Call(CallRequest),
245 Logout,
246}
247
248#[cfg(any(feature = "http", feature = "ws"))]
249#[derive(Debug, Serialize, Deserialize)]
250pub struct AdminRequest {
251 pub rql: String,
252 pub params: Option<WireParams>,
253 #[serde(skip_serializing_if = "Option::is_none")]
254 pub format: Option<WireFormat>,
255}
256
257#[cfg(any(feature = "http", feature = "ws"))]
258#[derive(Debug, Serialize, Deserialize)]
259pub struct AuthRequest {
260 #[serde(skip_serializing_if = "Option::is_none")]
261 pub token: Option<String>,
262 #[serde(skip_serializing_if = "Option::is_none")]
263 pub method: Option<String>,
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub credentials: Option<HashMap<String, String>>,
266}
267
268#[cfg(any(feature = "http", feature = "ws"))]
269#[derive(Debug, Serialize, Deserialize)]
270pub struct CommandRequest {
271 pub rql: String,
272 pub params: Option<WireParams>,
273 #[serde(skip_serializing_if = "Option::is_none")]
274 pub format: Option<WireFormat>,
275}
276
277#[cfg(any(feature = "http", feature = "ws"))]
278#[derive(Debug, Serialize, Deserialize)]
279pub struct QueryRequest {
280 pub rql: String,
281 pub params: Option<WireParams>,
282 #[serde(skip_serializing_if = "Option::is_none")]
283 pub format: Option<WireFormat>,
284}
285
286#[cfg(any(feature = "http", feature = "ws"))]
287#[derive(Debug, Serialize, Deserialize)]
288pub struct SubscribeRequest {
289 pub rql: String,
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub format: Option<WireFormat>,
292}
293
294#[cfg(any(feature = "http", feature = "ws"))]
295#[derive(Debug, Serialize, Deserialize)]
296pub struct UnsubscribeRequest {
297 pub subscription_id: String,
298}
299
300#[cfg(any(feature = "http", feature = "ws"))]
301#[derive(Debug, Serialize, Deserialize)]
302pub struct BatchSubscribeRequest {
303 pub queries: Vec<String>,
304 #[serde(skip_serializing_if = "Option::is_none")]
305 pub format: Option<WireFormat>,
306}
307
308#[cfg(any(feature = "http", feature = "ws"))]
309#[derive(Debug, Serialize, Deserialize)]
310pub struct BatchUnsubscribeRequest {
311 pub batch_id: String,
312}
313
314#[cfg(any(feature = "http", feature = "ws"))]
315#[derive(Debug, Serialize, Deserialize)]
316pub struct CallRequest {
317 pub name: String,
318 pub params: Option<WireParams>,
319 #[serde(skip_serializing_if = "Option::is_none")]
320 pub format: Option<WireFormat>,
321}
322
323#[cfg(any(feature = "http", feature = "ws"))]
324#[derive(Debug, Serialize, Deserialize)]
325pub struct Response {
326 pub id: String,
327 #[serde(flatten)]
328 pub payload: ResponsePayload,
329}
330
331#[cfg(any(feature = "http", feature = "ws"))]
332#[derive(Debug, Serialize, Deserialize)]
333#[serde(tag = "type", content = "payload")]
334pub enum ResponsePayload {
335 Auth(AuthResponse),
336 Err(ErrResponse),
337 Admin(AdminResponse),
338 Command(CommandResponse),
339 Query(QueryResponse),
340 Subscribed(SubscribedResponse),
341 Unsubscribed(UnsubscribedResponse),
342 BatchSubscribed(BatchSubscribedResponse),
343 BatchUnsubscribed(BatchUnsubscribedResponse),
344 Call(CallResponse),
345 Logout(LogoutResponsePayload),
346}
347
348#[cfg(any(feature = "http", feature = "ws"))]
349#[derive(Debug, Serialize, Deserialize)]
350pub struct AdminResponse {
351 pub content_type: String,
352 pub body: JsonValue,
353 #[serde(default)]
354 pub meta: Option<ResponseMeta>,
355}
356
357#[cfg(any(feature = "http", feature = "ws"))]
358use reifydb_value::error::Diagnostic;
359
360#[cfg(any(feature = "http", feature = "ws"))]
361#[derive(Debug, Serialize, Deserialize)]
362pub struct AuthResponse {
363 #[serde(skip_serializing_if = "Option::is_none")]
364 pub status: Option<String>,
365 #[serde(skip_serializing_if = "Option::is_none")]
366 pub token: Option<String>,
367 #[serde(skip_serializing_if = "Option::is_none")]
368 pub identity: Option<String>,
369}
370
371#[cfg(any(feature = "http", feature = "ws"))]
372#[derive(Debug, Serialize, Deserialize)]
373pub struct ErrResponse {
374 pub diagnostic: Diagnostic,
375}
376
377#[cfg(any(feature = "http", feature = "ws"))]
378#[derive(Debug, Serialize, Deserialize)]
379pub struct CommandResponse {
380 pub content_type: String,
381 pub body: JsonValue,
382 #[serde(default)]
383 pub meta: Option<ResponseMeta>,
384}
385
386#[cfg(any(feature = "http", feature = "ws"))]
387#[derive(Debug, Serialize, Deserialize)]
388pub struct QueryResponse {
389 pub content_type: String,
390 pub body: JsonValue,
391 #[serde(default)]
392 pub meta: Option<ResponseMeta>,
393}
394
395#[cfg(any(feature = "http", feature = "ws"))]
396#[derive(Debug, Serialize, Deserialize)]
397pub struct CallResponse {
398 pub content_type: String,
399 pub body: JsonValue,
400 #[serde(default)]
401 pub meta: Option<ResponseMeta>,
402}
403
404#[cfg(any(feature = "http", feature = "ws"))]
405#[derive(Debug, Serialize, Deserialize)]
406pub struct SubscribedResponse {
407 pub subscription_id: String,
408}
409
410#[cfg(any(feature = "http", feature = "ws"))]
411#[derive(Debug, Serialize, Deserialize)]
412pub struct UnsubscribedResponse {
413 pub subscription_id: String,
414}
415
416#[cfg(any(feature = "http", feature = "ws"))]
417#[derive(Debug, Serialize, Deserialize)]
418pub struct BatchSubscribedResponse {
419 pub batch_id: String,
420 pub members: Vec<BatchMemberInfo>,
421}
422
423#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
424#[derive(Debug, Clone)]
425pub struct BatchMemberInfo {
426 pub index: usize,
427 pub subscription_id: String,
428}
429
430#[cfg(any(feature = "http", feature = "ws"))]
431#[derive(Debug, Serialize, Deserialize)]
432pub struct BatchUnsubscribedResponse {
433 pub batch_id: String,
434}
435
436#[cfg(any(feature = "http", feature = "ws"))]
437#[derive(Debug, Serialize, Deserialize)]
438pub struct LogoutResponsePayload {
439 pub status: String,
440}
441
442#[cfg(any(feature = "http", feature = "ws"))]
443#[derive(Debug, Serialize, Deserialize)]
444#[serde(tag = "type", content = "payload")]
445pub enum ServerPush {
446 Change(WireChangePayload),
447 BatchChange(WireBatchChangePayload),
448 BatchMemberClosed(BatchMemberClosedPayload),
449 BatchClosed(BatchClosedPayload),
450}
451
452#[cfg(any(feature = "http", feature = "ws"))]
453#[derive(Debug, Clone, Serialize, Deserialize)]
454pub struct WireChangePayload {
455 pub subscription_id: String,
456 pub content_type: String,
457 pub body: JsonValue,
458}
459
460#[cfg(any(feature = "http", feature = "ws"))]
461#[derive(Debug, Clone, Serialize, Deserialize)]
462pub struct WireBatchChangePayload {
463 pub batch_id: String,
464 pub entries: Vec<WireBatchChangeEntry>,
465}
466
467#[cfg(any(feature = "http", feature = "ws"))]
468#[derive(Debug, Clone, Serialize, Deserialize)]
469pub struct WireBatchChangeEntry {
470 pub subscription_id: String,
471 pub content_type: String,
472 pub body: JsonValue,
473}
474
475#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
476#[derive(Debug, Clone, Copy, PartialEq, Eq)]
477pub enum ChangeKind {
478 Insert,
479 Update,
480 Remove,
481}
482
483#[derive(Debug, Clone)]
486pub struct FrameChange {
487 pub kind: ChangeKind,
488 pub frame: Frame,
489}
490
491#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
492#[derive(Debug, Clone)]
493pub struct ChangePayload {
494 pub subscription_id: String,
495 pub content_type: String,
496 pub body: JsonValue,
497 #[cfg_attr(any(feature = "http", feature = "ws"), serde(skip, default))]
498 pub changes: Vec<FrameChange>,
499}
500
501#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
502#[derive(Debug, Clone)]
503pub struct BatchChangePayload {
504 pub batch_id: String,
505 pub entries: Vec<BatchChangeEntry>,
506}
507
508#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
509#[derive(Debug, Clone)]
510pub struct BatchChangeEntry {
511 pub subscription_id: String,
512 pub content_type: String,
513 pub body: JsonValue,
514 #[cfg_attr(any(feature = "http", feature = "ws"), serde(skip, default))]
515 pub changes: Vec<FrameChange>,
516 #[cfg_attr(any(feature = "http", feature = "ws"), serde(skip, default))]
517 pub decode_error: Option<String>,
518}
519
520#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
521#[derive(Debug, Clone)]
522pub struct BatchMemberClosedPayload {
523 pub batch_id: String,
524 pub subscription_id: String,
525}
526
527#[cfg_attr(any(feature = "http", feature = "ws"), derive(Serialize, Deserialize))]
528#[derive(Debug, Clone)]
529pub struct BatchClosedPayload {
530 pub batch_id: String,
531}
532
533#[derive(Debug, Clone)]
534pub enum BatchPushEvent {
535 Change(BatchChangePayload),
536 MemberClosed(BatchMemberClosedPayload),
537 Closed(BatchClosedPayload),
538}