use serde::Serialize;
use serde_json::Value;
use std::collections::BTreeMap;
use crate::SwapType;
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct HxLocation {
path: String,
#[serde(skip_serializing_if = "Option::is_none")]
target: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
source: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
event: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
swap: Option<String>,
#[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
headers: BTreeMap<String, String>,
#[serde(skip_serializing_if = "Option::is_none")]
values: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
handler: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
select: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
push: Option<Value>,
#[serde(skip_serializing_if = "Option::is_none")]
replace: Option<String>,
}
impl HxLocation {
pub fn new(path: impl Into<String>) -> Self {
HxLocation {
path: path.into(),
target: None,
source: None,
event: None,
swap: None,
headers: BTreeMap::new(),
values: None,
handler: None,
select: None,
push: None,
replace: None,
}
}
pub fn target(mut self, selector: impl Into<String>) -> Self {
self.target = Some(selector.into());
self
}
pub fn source(mut self, selector: impl Into<String>) -> Self {
self.source = Some(selector.into());
self
}
pub fn event(mut self, event: impl Into<String>) -> Self {
self.event = Some(event.into());
self
}
pub fn swap(mut self, swap: SwapType) -> Self {
self.swap = Some(swap.to_string());
self
}
pub fn handler(mut self, handler: impl Into<String>) -> Self {
self.handler = Some(handler.into());
self
}
pub fn select(mut self, selector: impl Into<String>) -> Self {
self.select = Some(selector.into());
self
}
pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
self.headers.insert(name.into(), value.into());
self
}
pub fn headers<I, K, V>(mut self, headers: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
K: Into<String>,
V: Into<String>,
{
self.headers
.extend(headers.into_iter().map(|(k, v)| (k.into(), v.into())));
self
}
pub fn values<T>(mut self, values: T) -> serde_json::Result<Self>
where
T: Serialize,
{
self.values = Some(serde_json::to_value(values)?);
Ok(self)
}
pub fn disable_push(mut self) -> Self {
self.push = Some(Value::Bool(false));
self
}
pub fn push_path(mut self, path: impl Into<String>) -> Self {
self.push = Some(Value::String(path.into()));
self
}
pub fn replace(mut self, path: impl Into<String>) -> Self {
self.replace = Some(path.into());
self
}
pub(crate) fn into_header_value(self) -> String {
serde_json::to_string(&self).expect("HxLocation serialization failed")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Serialize)]
struct Payload<'a> {
id: u32,
name: &'a str,
}
#[test]
fn values_accepts_serializable_types() {
let location = HxLocation::new("/path")
.values(Payload {
id: 7,
name: "demo",
})
.expect("serialization should succeed");
let serialized = location.into_header_value();
let parsed: Value = serde_json::from_str(&serialized).unwrap();
assert_eq!(parsed["path"], "/path");
assert_eq!(parsed["values"]["id"], 7);
assert_eq!(parsed["values"]["name"], "demo");
}
}