#[derive(Debug, PartialEq)]
pub enum SearchParseError {
Kind(String),
Term(String),
}
impl std::fmt::Display for SearchParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
SearchParseError::Kind(s) => write!(f, "Invalid search kind: {}", s),
SearchParseError::Term(s) => write!(f, "Invalid search term: {}", s),
}
}
}
impl std::error::Error for SearchParseError {}
#[derive(Debug, PartialEq)]
pub enum Search<T> {
Partial(T),
Exact(T),
NoSearch,
}
impl<T: std::str::FromStr> Search<T> {
pub fn from_query(query: &str) -> Result<Search<T>, SearchParseError> {
let mut query_iter = query.split(',');
let kind = query_iter.next().map(|s| s.trim());
let term = query_iter.next().map(|s| s.trim());
match (kind, term) {
(Some("partial"), Some(s)) => s
.trim()
.parse()
.map(|p| Search::Partial(p))
.map_err(|_| SearchParseError::Term(s.to_owned())),
(Some("exact"), Some(s)) => s
.trim()
.parse()
.map(|p| Search::Exact(p))
.map_err(|_| SearchParseError::Term(s.to_owned())),
(Some("partial"), None) => Err(SearchParseError::Term("".to_owned())),
(Some("exact"), None) => Err(SearchParseError::Term("".to_owned())),
(Some(k), Some(_)) => Err(SearchParseError::Kind(k.to_owned())),
(Some(k), None) => Err(SearchParseError::Kind(k.to_owned())),
(None, Some(_)) => Err(SearchParseError::Kind("".to_owned())),
(None, None) => Err(SearchParseError::Kind("".to_owned())),
}
}
}
#[test]
fn parse_search_partial_search_works() {
let s = Search::from_query(" partial , hello ");
assert_eq!(s, Ok(Search::Partial("hello".to_owned())));
}
#[test]
fn parse_search_exact_search_works() {
let s = Search::from_query(" exact, hello ");
assert_eq!(s, Ok(Search::Exact("hello".to_owned())));
}
#[test]
fn parse_search_invalid_kind_with_term_fails() {
let s: Result<Search<String>, _> = Search::from_query("hello, bye");
assert_eq!(s, Err(SearchParseError::Kind("hello".to_owned())));
}
#[test]
fn parse_search_no_kind_with_term_fails() {
let s: Result<Search<String>, _> = Search::from_query(", bye");
assert_eq!(s, Err(SearchParseError::Kind("".to_owned())));
}
#[test]
fn parse_search_partial_with_no_term_fails() {
let s: Result<Search<String>, _> = Search::from_query(" partial");
assert_eq!(s, Err(SearchParseError::Term("".to_owned())));
}
#[test]
fn parse_search_exact_with_no_term_fails() {
let s: Result<Search<String>, _> = Search::from_query(" exact");
assert_eq!(s, Err(SearchParseError::Term("".to_owned())));
}
#[test]
fn parse_search_invalid_with_no_term_fails() {
let s: Result<Search<String>, _> = Search::from_query("hello");
assert_eq!(s, Err(SearchParseError::Kind("hello".to_owned())));
}
#[test]
fn parse_search_empty_string_fails() {
let s: Result<Search<String>, _> = Search::from_query("");
assert_eq!(s, Err(SearchParseError::Kind("".to_owned())));
}
#[derive(Debug, PartialEq)]
pub enum NullableSearch<T> {
Partial(T),
Exact(T),
Some,
None,
NoSearch,
}
impl<T: std::str::FromStr> NullableSearch<T> {
pub fn from_query(query: &str) -> Result<NullableSearch<T>, SearchParseError> {
let mut query_iter = query.split(',');
let kind = query_iter.next().map(|s| s.trim());
let term = query_iter.next().map(|s| s.trim());
match (kind, term) {
(Some("partial"), Some(s)) => s
.trim()
.parse()
.map(|p| NullableSearch::Partial(p))
.map_err(|_| SearchParseError::Term(s.to_owned())),
(Some("exact"), Some(s)) => s
.trim()
.parse()
.map(|p| NullableSearch::Exact(p))
.map_err(|_| SearchParseError::Term(s.to_owned())),
(Some("some"), None) => Ok(NullableSearch::Some),
(Some("none"), None) => Ok(NullableSearch::None),
(Some("partial"), None) => Err(SearchParseError::Term("".to_owned())),
(Some("exact"), None) => Err(SearchParseError::Term("".to_owned())),
(Some("some"), Some(s)) => Err(SearchParseError::Term(s.to_owned())),
(Some("none"), Some(s)) => Err(SearchParseError::Term(s.to_owned())),
(Some(k), Some(_)) => Err(SearchParseError::Kind(k.to_owned())),
(Some(k), None) => Err(SearchParseError::Kind(k.to_owned())),
(None, Some(_)) => Err(SearchParseError::Kind("".to_owned())),
(None, None) => Err(SearchParseError::Kind("".to_owned())),
}
}
}
#[test]
fn parse_nullable_search_partial_search_works() {
let s = NullableSearch::from_query(" partial , hello ");
assert_eq!(s, Ok(NullableSearch::Partial("hello".to_owned())));
}
#[test]
fn parse_nullable_search_exact_search_works() {
let s = NullableSearch::from_query(" exact, hello ");
assert_eq!(s, Ok(NullableSearch::Exact("hello".to_owned())));
}
#[test]
fn parse_nullable_search_some_works() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query(" some ");
assert_eq!(s, Ok(NullableSearch::Some));
}
#[test]
fn parse_nullable_search_none_works() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query(" none ");
assert_eq!(s, Ok(NullableSearch::None));
}
#[test]
fn parse_nullable_search_some_with_term_fails() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query(" some, hello");
assert_eq!(s, Err(SearchParseError::Term("hello".to_owned())));
}
#[test]
fn parse_nullable_search_none_with_term_fails() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query(" none, hello");
assert_eq!(s, Err(SearchParseError::Term("hello".to_owned())));
}
#[test]
fn parse_nullable_search_invalid_kind_with_term_fails() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query("hello, bye");
assert_eq!(s, Err(SearchParseError::Kind("hello".to_owned())));
}
#[test]
fn parse_nullable_search_no_kind_with_term_fails() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query(", bye");
assert_eq!(s, Err(SearchParseError::Kind("".to_owned())));
}
#[test]
fn parse_nullable_search_partial_with_no_term_fails() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query(" partial");
assert_eq!(s, Err(SearchParseError::Term("".to_owned())));
}
#[test]
fn parse_nullable_search_exact_with_no_term_fails() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query(" exact");
assert_eq!(s, Err(SearchParseError::Term("".to_owned())));
}
#[test]
fn parse_nullable_search_invalid_with_no_term_fails() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query("hello");
assert_eq!(s, Err(SearchParseError::Kind("hello".to_owned())));
}
#[test]
fn parse_nullable_search_empty_string_fails() {
let s: Result<NullableSearch<String>, _> = NullableSearch::from_query("");
assert_eq!(s, Err(SearchParseError::Kind("".to_owned())));
}