use serde::{ser::SerializeSeq, Serialize};
pub use crate::common::options::{CallbackMethod, CustomIntentMode, CustomTopicMode, Language};
#[derive(Debug, PartialEq, Clone)]
pub struct Options {
sentiment: Option<bool>,
summarize: Option<bool>,
topics: Option<bool>,
custom_topics: Vec<String>,
custom_topic_mode: Option<CustomTopicMode>,
intents: Option<bool>,
custom_intents: Vec<String>,
custom_intent_mode: Option<CustomIntentMode>,
language: Option<Language>,
tags: Vec<String>,
callback_method: Option<CallbackMethod>,
}
#[derive(Debug, PartialEq, Clone)]
pub struct OptionsBuilder(Options);
#[derive(Debug, PartialEq, Clone)]
pub(super) struct SerializableOptions<'a>(pub(super) &'a Options);
impl Options {
pub fn builder() -> OptionsBuilder {
OptionsBuilder::new()
}
pub fn urlencoded(&self) -> Result<String, serde_urlencoded::ser::Error> {
serde_urlencoded::to_string(SerializableOptions(self))
}
}
impl OptionsBuilder {
pub fn new() -> Self {
Self(Options {
sentiment: None,
summarize: None,
topics: None,
custom_topics: Vec::new(),
custom_topic_mode: None,
intents: None,
custom_intents: Vec::new(),
custom_intent_mode: None,
language: Some(Language::en),
tags: Vec::new(),
callback_method: None,
})
}
pub fn sentiment(mut self, sentiment: bool) -> Self {
self.0.sentiment = Some(sentiment);
self
}
pub fn summarize(mut self, summarize: bool) -> Self {
self.0.summarize = Some(summarize);
self
}
pub fn topics(mut self, topics: bool) -> Self {
self.0.topics = Some(topics);
self
}
pub fn custom_topic_mode(mut self, mode: CustomTopicMode) -> Self {
self.0.custom_topic_mode = Some(mode);
self
}
pub fn custom_topics<'a>(mut self, topics: impl IntoIterator<Item = &'a str>) -> Self {
self.0
.custom_topics
.extend(topics.into_iter().map(String::from));
self
}
pub fn intents(mut self, intents: bool) -> Self {
self.0.intents = Some(intents);
self
}
pub fn custom_intent_mode(mut self, mode: CustomIntentMode) -> Self {
self.0.custom_intent_mode = Some(mode);
self
}
pub fn custom_intents<'a>(mut self, intents: impl IntoIterator<Item = &'a str>) -> Self {
self.0
.custom_intents
.extend(intents.into_iter().map(String::from));
self
}
pub fn language(mut self, language: Language) -> Self {
self.0.language = Some(language);
self
}
pub fn tag<'a>(mut self, tags: impl IntoIterator<Item = &'a str>) -> Self {
self.0.tags.extend(tags.into_iter().map(String::from));
self
}
pub fn callback_method(mut self, callback_method: CallbackMethod) -> Self {
self.0.callback_method = Some(callback_method);
self
}
pub fn build(self) -> Options {
self.0
}
}
impl Default for OptionsBuilder {
fn default() -> Self {
Self::new()
}
}
impl Serialize for SerializableOptions<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = serializer.serialize_seq(None)?;
let Options {
sentiment,
summarize,
topics,
custom_topics,
custom_topic_mode,
intents,
custom_intents,
custom_intent_mode,
language,
tags,
callback_method,
} = self.0;
if let Some(sentiment) = sentiment {
seq.serialize_element(&("sentiment", sentiment))?;
}
if let Some(summarize) = summarize {
seq.serialize_element(&("summarize", summarize))?;
}
if let Some(topics) = topics {
seq.serialize_element(&("topics", topics))?;
}
if let Some(custom_topic_mode) = custom_topic_mode {
seq.serialize_element(&("custom_topic_mode", custom_topic_mode))?;
}
for custom_topic in custom_topics {
seq.serialize_element(&("custom_topic", custom_topic))?;
}
if let Some(intents) = intents {
seq.serialize_element(&("intents", intents))?;
}
if let Some(custom_intent_mode) = custom_intent_mode {
seq.serialize_element(&("custom_intent_mode", custom_intent_mode))?;
}
for custom_intent in custom_intents {
seq.serialize_element(&("custom_intent", custom_intent))?;
}
if let Some(language) = language {
seq.serialize_element(&("language", language.as_ref()))?;
}
for tag in tags {
seq.serialize_element(&("tag", tag))?;
}
if let Some(callback_method) = callback_method {
seq.serialize_element(&("callback_method", callback_method.as_str()))?;
}
seq.end()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serializes_flags_and_repeats() {
let options = Options::builder()
.sentiment(true)
.summarize(true)
.topics(true)
.custom_topics(["refund", "billing"])
.custom_topic_mode(CustomTopicMode::Strict)
.intents(true)
.language(Language::en)
.tag(["team:cx"])
.build();
assert_eq!(
options.urlencoded().unwrap(),
"sentiment=true&summarize=true&topics=true&custom_topic_mode=strict\
&custom_topic=refund&custom_topic=billing&intents=true&language=en&tag=team%3Acx"
);
}
#[test]
fn summarize_is_boolean_not_v2() {
let options = Options::builder().summarize(true).build();
assert_eq!(options.urlencoded().unwrap(), "summarize=true&language=en");
}
#[test]
fn default_options_send_language_en() {
let options = Options::builder().build();
assert_eq!(options.urlencoded().unwrap(), "language=en");
}
#[test]
fn callback_method_serializes_lowercase() {
let options = Options::builder()
.callback_method(CallbackMethod::PUT)
.build();
assert_eq!(
options.urlencoded().unwrap(),
"language=en&callback_method=put"
);
}
}