use crate::error::LingerError;
use crate::RequestId;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;
#[derive(Clone, Debug, Default, Serialize, PartialEq)]
#[non_exhaustive]
pub struct CreateConversationRequest {
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub metadata: BTreeMap<String, String>,
#[serde(flatten)]
pub extra: BTreeMap<String, Value>,
}
impl CreateConversationRequest {
pub fn builder() -> CreateConversationRequestBuilder {
CreateConversationRequestBuilder::default()
}
}
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct CreateConversationRequestBuilder {
metadata: BTreeMap<String, String>,
extra: BTreeMap<String, Value>,
}
impl CreateConversationRequestBuilder {
pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metadata.insert(key.into(), value.into());
self
}
pub fn extra(mut self, name: impl Into<String>, value: Value) -> Self {
self.extra.insert(name.into(), value);
self
}
pub fn build(self) -> Result<CreateConversationRequest, LingerError> {
validate_metadata(&self.metadata)?;
validate_extra_fields(&self.extra)?;
Ok(CreateConversationRequest {
metadata: self.metadata,
extra: self.extra,
})
}
}
#[derive(Clone, Debug, Default, Serialize, PartialEq)]
#[non_exhaustive]
pub struct ModifyConversationRequest {
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub metadata: BTreeMap<String, String>,
}
impl ModifyConversationRequest {
pub fn builder() -> ModifyConversationRequestBuilder {
ModifyConversationRequestBuilder::default()
}
}
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct ModifyConversationRequestBuilder {
metadata: BTreeMap<String, String>,
}
impl ModifyConversationRequestBuilder {
pub fn metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.metadata.insert(key.into(), value.into());
self
}
pub fn build(self) -> Result<ModifyConversationRequest, LingerError> {
validate_metadata(&self.metadata)?;
Ok(ModifyConversationRequest {
metadata: self.metadata,
})
}
}
#[derive(Clone, Debug, Serialize, PartialEq)]
#[non_exhaustive]
pub struct CreateConversationItemRequest {
pub item: Value,
}
impl CreateConversationItemRequest {
pub fn builder() -> CreateConversationItemRequestBuilder {
CreateConversationItemRequestBuilder::default()
}
}
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct CreateConversationItemRequestBuilder {
item: Option<Value>,
}
impl CreateConversationItemRequestBuilder {
pub fn item(mut self, item: Value) -> Self {
self.item = Some(item);
self
}
pub fn build(self) -> Result<CreateConversationItemRequest, LingerError> {
let item = self
.item
.filter(|value| !value.is_null())
.ok_or_else(|| LingerError::invalid_config("item is required"))?;
Ok(CreateConversationItemRequest { item })
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct Conversation {
pub id: String,
pub object: String,
#[serde(default)]
pub created_at: Option<u64>,
#[serde(default)]
pub metadata: BTreeMap<String, String>,
#[serde(flatten)]
pub extra: BTreeMap<String, Value>,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl Conversation {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct ConversationItem {
pub id: String,
pub object: String,
#[serde(default)]
pub created_at: Option<u64>,
#[serde(flatten)]
pub extra: BTreeMap<String, Value>,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl ConversationItem {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[non_exhaustive]
pub struct ConversationItemPage {
pub object: String,
#[serde(default)]
pub data: Vec<ConversationItem>,
#[serde(default)]
pub first_id: Option<String>,
#[serde(default)]
pub last_id: Option<String>,
pub has_more: bool,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl ConversationItemPage {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct ConversationDeletion {
pub id: String,
pub object: String,
pub deleted: bool,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl ConversationDeletion {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct ConversationItemDeletion {
pub id: String,
pub object: String,
pub deleted: bool,
#[serde(skip)]
request_id: Option<RequestId>,
}
impl ConversationItemDeletion {
pub(crate) fn with_request_id(mut self, request_id: Option<RequestId>) -> Self {
self.request_id = request_id;
self
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
}
fn validate_metadata(metadata: &BTreeMap<String, String>) -> Result<(), LingerError> {
for key in metadata.keys() {
if key.trim().is_empty() {
return Err(LingerError::invalid_config(
"metadata keys must not be empty",
));
}
}
Ok(())
}
fn validate_extra_fields(extra: &BTreeMap<String, Value>) -> Result<(), LingerError> {
for (key, value) in extra {
if key.trim().is_empty() {
return Err(LingerError::invalid_config(
"extra field names must not be empty",
));
}
if value.is_null() {
return Err(LingerError::invalid_config(format!(
"extra field {key} must not be null"
)));
}
}
Ok(())
}