use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
pub use super::common::{
DreamConfiguration, PeerCardConfiguration, ReasoningConfiguration, SummaryConfiguration,
};
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Workspace {
pub id: String,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub metadata: HashMap<String, serde_json::Value>,
#[serde(default)]
pub configuration: WorkspaceConfiguration,
pub created_at: DateTime<Utc>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct WorkspaceConfiguration {
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning: Option<ReasoningConfiguration>,
#[serde(skip_serializing_if = "Option::is_none")]
pub peer_card: Option<PeerCardConfiguration>,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<SummaryConfiguration>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dream: Option<DreamConfiguration>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, bon::Builder)]
#[builder(on(String, into))]
#[builder(finish_fn = build)]
pub struct WorkspaceCreate {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub configuration: Option<WorkspaceConfiguration>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, bon::Builder)]
#[builder(on(String, into))]
#[builder(finish_fn = build)]
pub struct WorkspaceUpdate {
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "double_option"
)]
pub metadata: Option<Option<HashMap<String, serde_json::Value>>>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "double_option"
)]
pub configuration: Option<Option<WorkspaceConfiguration>>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, bon::Builder)]
#[builder(on(String, into))]
#[builder(finish_fn = build)]
pub struct WorkspaceGet {
#[serde(skip_serializing_if = "Option::is_none")]
pub filters: Option<HashMap<String, serde_json::Value>>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WorkspaceMetadataSet {
pub metadata: HashMap<String, serde_json::Value>,
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WorkspaceConfigurationSet {
pub configuration: serde_json::Value,
}
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WorkspaceSearchRequest {
pub query: String,
pub limit: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub filters: Option<HashMap<String, serde_json::Value>>,
}
pub type WorkspacePage = super::pagination::Page<Workspace>;
mod double_option {
#![allow(clippy::option_option, clippy::ref_option)]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub(super) fn serialize<T, S>(v: &Option<Option<T>>, s: S) -> Result<S::Ok, S::Error>
where
T: Serialize,
S: Serializer,
{
match v {
Some(inner) => inner.serialize(s),
None => s.serialize_none(),
}
}
pub(super) fn deserialize<'de, T, D>(d: D) -> Result<Option<Option<T>>, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
Option::<T>::deserialize(d).map(Some)
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use super::*;
#[test]
fn workspace_update_explicit_null_metadata_roundtrips() {
let body = WorkspaceUpdate {
metadata: Some(None),
configuration: None,
};
let json = serde_json::to_value(&body).unwrap();
assert_eq!(json, serde_json::json!({ "metadata": null }));
let back: WorkspaceUpdate = serde_json::from_value(json).unwrap();
assert_eq!(back.metadata, Some(None));
assert_eq!(back.configuration, None);
}
#[test]
fn workspace_update_omitted_metadata_is_outer_none() {
let back: WorkspaceUpdate = serde_json::from_value(serde_json::json!({})).unwrap();
assert_eq!(back.metadata, None);
assert_eq!(back.configuration, None);
}
}