1use crate::control::{Projection, ProjectionBinding, SchemaDef, SchemaSource};
2use crate::query::QueryError;
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
9pub struct ProjectionInfo {
10 pub projection: Projection,
11 #[serde(default, skip_serializing_if = "Vec::is_empty")]
12 pub bindings: Vec<ProjectionBinding>,
13}
14
15#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
21pub struct SchemaInfo {
22 pub schema: SchemaDef,
23 #[serde(default)]
24 pub dropped: bool,
25}
26
27#[derive(Clone, Debug, Serialize, Deserialize)]
29pub struct GetProjection {
30 pub v: u32,
31 pub id: String,
32}
33
34#[derive(Clone, Debug, Serialize, Deserialize)]
41pub struct ListProjections {
42 pub v: u32,
43 #[serde(default, skip_serializing_if = "Vec::is_empty")]
44 pub topics: Vec<String>,
45 #[serde(default, skip_serializing_if = "Option::is_none")]
46 pub name_contains: Option<String>,
47 #[serde(default, skip_serializing_if = "Option::is_none")]
48 pub id_prefix: Option<String>,
49 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub search: Option<String>,
51}
52
53#[derive(Clone, Debug, Serialize, Deserialize)]
55pub struct GetSchema {
56 pub v: u32,
57 pub id: u32,
58}
59
60#[derive(Clone, Debug, Serialize, Deserialize)]
66pub struct ListSchemas {
67 pub v: u32,
68 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub name_contains: Option<String>,
70}
71
72#[derive(Clone, Debug, Serialize, Deserialize)]
78pub struct RegisterSchema {
79 pub v: u32,
80 pub source: SchemaSource,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
82 pub name: Option<String>,
83 #[serde(default, skip_serializing_if = "Option::is_none")]
84 pub version: Option<u32>,
85}
86
87#[derive(Clone, Debug, Serialize, Deserialize)]
92pub struct DecodeRecord {
93 pub v: u32,
94 pub id: u32,
95 #[serde(with = "crate::encoding::bin_bytes")]
96 pub payload: Vec<u8>,
97}
98
99#[derive(Clone, Debug, Serialize, Deserialize)]
101#[non_exhaustive]
102pub enum BrowseReply {
103 Ok(BrowseOutcome),
104 Err(QueryError),
105}
106
107#[derive(Clone, Debug, Serialize, Deserialize)]
109#[non_exhaustive]
110pub enum BrowseOutcome {
111 Projections(Vec<ProjectionInfo>),
113 Projection(Option<ProjectionInfo>),
115 Schemas(Vec<SchemaInfo>),
117 Schema(Option<SchemaInfo>),
119 SchemaRegistered(u32),
122 Decoded(Option<serde_json::Value>),
127}
128
129#[cfg(all(test, feature = "cbor"))]
130mod tests {
131 use super::*;
132 use crate::codes::QUERY_OP_VERSION;
133 use crate::content::ContentType;
134 use crate::control::ProjectionBinding;
135 use crate::framing::{decode_named, encode_named};
136
137 #[test]
138 fn given_a_browse_reply_when_round_tripped_then_should_preserve_projection_details() {
139 let info = ProjectionInfo {
140 projection: Projection::builder("order.v1")
141 .name("order")
142 .version(1)
143 .content_type(ContentType::Json)
144 .fields(["order_id", "amount"])
145 .build(),
146 bindings: vec![
147 ProjectionBinding::builder()
148 .source("shop", "orders")
149 .allow("order.v1")
150 .default_projection("order.v1")
151 .target_table("orders_rows")
152 .build(),
153 ],
154 };
155 let reply = BrowseReply::Ok(BrowseOutcome::Projections(vec![info]));
156 let bytes = encode_named(&reply).expect("the reply serializes");
157 let back: BrowseReply = decode_named(&bytes).expect("the reply deserializes");
158 let BrowseReply::Ok(BrowseOutcome::Projections(list)) = back else {
159 panic!("expected an Ok(Projections) browse reply");
160 };
161 assert_eq!(list.len(), 1);
162 assert_eq!(list[0].projection.id.as_str(), "order.v1");
163 assert_eq!(list[0].projection.extraction.fields.len(), 2);
164 let targets = &list[0].bindings[0].targets;
165 assert_eq!(targets.len(), 1);
166 assert_eq!(targets[0].table, "orders_rows");
167 }
168
169 #[test]
170 fn given_a_decode_record_when_round_tripped_then_should_preserve_payload_bytes() {
171 let request = DecodeRecord {
172 v: QUERY_OP_VERSION,
173 id: 7,
174 payload: vec![0xff, 0x00, 0x10],
175 };
176 let bytes = encode_named(&request).expect("serializes");
177 let back: DecodeRecord = decode_named(&bytes).expect("deserializes");
178 assert_eq!(back.id, 7);
179 assert_eq!(back.payload, vec![0xff, 0x00, 0x10]);
180 }
181}