use crate::control::{Projection, ProjectionBinding, SchemaDef, SchemaSource};
use crate::query::QueryError;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ProjectionInfo {
pub projection: Projection,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub bindings: Vec<ProjectionBinding>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct SchemaInfo {
pub schema: SchemaDef,
#[serde(default)]
pub dropped: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GetProjection {
pub v: u32,
pub id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ListProjections {
pub v: u32,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub topics: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name_contains: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id_prefix: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub search: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct GetSchema {
pub v: u32,
pub id: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ListSchemas {
pub v: u32,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name_contains: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisterSchema {
pub v: u32,
pub source: SchemaSource,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<u32>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DecodeRecord {
pub v: u32,
pub id: u32,
#[serde(with = "crate::encoding::bin_bytes")]
pub payload: Vec<u8>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum BrowseReply {
Ok(BrowseOutcome),
Err(QueryError),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub enum BrowseOutcome {
Projections(Vec<ProjectionInfo>),
Projection(Option<ProjectionInfo>),
Schemas(Vec<SchemaInfo>),
Schema(Option<SchemaInfo>),
SchemaRegistered(u32),
Decoded(Option<serde_json::Value>),
}
#[cfg(all(test, feature = "cbor"))]
mod tests {
use super::*;
use crate::codes::QUERY_OP_VERSION;
use crate::content::ContentType;
use crate::control::ProjectionBinding;
use crate::framing::{decode_named, encode_named};
#[test]
fn given_a_browse_reply_when_round_tripped_then_should_preserve_projection_details() {
let info = ProjectionInfo {
projection: Projection::builder("order.v1")
.name("order")
.version(1)
.content_type(ContentType::Json)
.fields(["order_id", "amount"])
.build(),
bindings: vec![
ProjectionBinding::builder()
.source("shop", "orders")
.allow("order.v1")
.default_projection("order.v1")
.target_table("orders_rows")
.build(),
],
};
let reply = BrowseReply::Ok(BrowseOutcome::Projections(vec![info]));
let bytes = encode_named(&reply).expect("the reply serializes");
let back: BrowseReply = decode_named(&bytes).expect("the reply deserializes");
let BrowseReply::Ok(BrowseOutcome::Projections(list)) = back else {
panic!("expected an Ok(Projections) browse reply");
};
assert_eq!(list.len(), 1);
assert_eq!(list[0].projection.id.as_str(), "order.v1");
assert_eq!(list[0].projection.extraction.fields.len(), 2);
let targets = &list[0].bindings[0].targets;
assert_eq!(targets.len(), 1);
assert_eq!(targets[0].table, "orders_rows");
}
#[test]
fn given_a_decode_record_when_round_tripped_then_should_preserve_payload_bytes() {
let request = DecodeRecord {
v: QUERY_OP_VERSION,
id: 7,
payload: vec![0xff, 0x00, 0x10],
};
let bytes = encode_named(&request).expect("serializes");
let back: DecodeRecord = decode_named(&bytes).expect("deserializes");
assert_eq!(back.id, 7);
assert_eq!(back.payload, vec![0xff, 0x00, 0x10]);
}
}