use crate::queries::ir::Nesting;
pub fn split(name: &str, prefix: Option<&str>) -> (Nesting, String) {
if let Some(p) = prefix {
if let Some(rest) = name.strip_prefix(p)
&& !rest.is_empty()
{
let base = p.trim_end_matches(['.', '_']).to_owned();
let nesting = if p.ends_with('.') {
Nesting::ToMany(base)
} else {
Nesting::ToOne(base)
};
return (nesting, rest.to_owned());
}
return (Nesting::Flat, name.to_owned());
}
if let Some((head, rest)) = name.split_once("__")
&& !head.is_empty()
&& !rest.is_empty()
{
return (Nesting::ToOne(head.to_owned()), rest.to_owned());
}
if let Some((head, rest)) = name.split_once('.')
&& !head.is_empty()
&& !rest.is_empty()
{
return (Nesting::ToMany(head.to_owned()), rest.to_owned());
}
(Nesting::Flat, name.to_owned())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_defaults_are_double_underscore_for_to_one_and_dot_for_to_many() {
assert_eq!(split("title", None), (Nesting::Flat, "title".to_owned()));
assert_eq!(
split("author__name", None),
(Nesting::ToOne("author".to_owned()), "name".to_owned())
);
assert_eq!(
split("tags.name", None),
(Nesting::ToMany("tags".to_owned()), "name".to_owned())
);
}
#[test]
fn a_prefix_annotation_switches_both() {
assert_eq!(
split("videos.id", Some("videos.")),
(Nesting::ToMany("videos".to_owned()), "id".to_owned())
);
assert_eq!(
split("owner_id", Some("videos.")),
(Nesting::Flat, "owner_id".to_owned()),
"a column outside the prefix stays flat, even with `_` in its name"
);
assert_eq!(
split("author_name", Some("author_")),
(Nesting::ToOne("author".to_owned()), "name".to_owned())
);
}
#[test]
fn a_leading_or_trailing_separator_is_not_a_split() {
assert_eq!(split("__x", None), (Nesting::Flat, "__x".to_owned()));
assert_eq!(split("x__", None), (Nesting::Flat, "x__".to_owned()));
}
}