#![allow(clippy::unwrap_used)]
use std::collections::{BTreeMap, HashMap};
use serde_json::json;
use super::{SubSelect, default_embed_page, selections};
use crate::routes::rest::params::{EmbeddedSpec, SelectEntry};
fn embedded(name: &str) -> EmbeddedSpec {
EmbeddedSpec {
relationship: name.to_string(),
rename: None,
fields: vec![],
}
}
#[test]
fn a_sub_select_separates_fields_embeds_and_counts() {
let split = SubSelect::split(&[
SelectEntry::Field("id".to_string()),
SelectEntry::Embedded(embedded("author")),
SelectEntry::Count("comments".to_string()),
SelectEntry::Field("title".to_string()),
]);
assert_eq!(split.fields, vec!["id".to_string(), "title".to_string()]);
assert_eq!(split.embeds.len(), 1);
assert_eq!(split.embeds[0].relationship, "author");
assert_eq!(split.counts, vec!["comments".to_string()]);
}
#[test]
fn a_count_only_sub_select_yields_a_count_and_no_fields() {
let split = SubSelect::split(&[SelectEntry::Count("comments".to_string())]);
assert!(split.fields.is_empty());
assert!(split.embeds.is_empty());
assert_eq!(split.counts, vec!["comments".to_string()]);
}
#[test]
fn an_empty_sub_select_yields_nothing() {
assert_eq!(SubSelect::split(&[]), SubSelect::default());
}
fn posts_with_comments() -> (Vec<EmbeddedSpec>, Vec<String>) {
let posts = EmbeddedSpec {
relationship: "posts".to_string(),
rename: None,
fields: vec![
SelectEntry::Field("id".to_string()),
SelectEntry::Embedded(EmbeddedSpec {
relationship: "comments".to_string(),
rename: None,
fields: vec![SelectEntry::Field("id".to_string())],
}),
SelectEntry::Count("comments".to_string()),
],
};
(vec![posts], vec!["posts".to_string()])
}
#[test]
fn a_nested_selection_reaches_the_engine_whole() {
let (embeds, counts) = posts_with_comments();
let (embeds, counts) = selections(&embeds, &counts, &HashMap::new(), &BTreeMap::new(), 50);
assert_eq!(embeds.len(), 1);
let posts = &embeds[0];
assert_eq!(posts.fields, vec!["id".to_string()]);
assert_eq!(posts.embeds.len(), 1, "the nested embed (#864)");
assert_eq!(posts.embeds[0].relationship, "comments");
assert_eq!(posts.counts.len(), 1, "the nested count (#1267)");
assert_eq!(posts.counts[0].output_key, "comments_count");
assert_eq!(counts.len(), 1);
assert_eq!(counts[0].output_key, "posts_count");
assert_eq!(
(posts.limit, posts.embeds[0].limit),
(Some(50), Some(50)),
"a level no page names gets the default"
);
}
#[test]
fn a_top_level_filter_narrows_the_embed_and_its_count_alike() {
let (embeds, counts) = posts_with_comments();
let filters = HashMap::from([("posts".to_string(), json!({"status": {"eq": "published"}}))]);
let (embeds, counts) = selections(&embeds, &counts, &filters, &BTreeMap::new(), 50);
assert_eq!(embeds[0].filter, Some(json!({"status": {"eq": "published"}})));
assert_eq!(counts[0].filter, embeds[0].filter);
}
#[test]
fn a_nested_level_is_given_no_filter_even_one_named_like_it() {
let (embeds, counts) = posts_with_comments();
let filters = HashMap::from([("comments".to_string(), json!({"id": {"eq": 1}}))]);
let (embeds, _) = selections(&embeds, &counts, &filters, &BTreeMap::new(), 50);
assert_eq!(embeds[0].embeds[0].filter, None);
assert_eq!(embeds[0].counts[0].filter, None);
}
#[test]
fn a_rename_is_the_output_key() {
let spec = EmbeddedSpec {
relationship: "fk_user".to_string(),
rename: Some("author".to_string()),
fields: Vec::new(),
};
let (embeds, _) = selections(&[spec], &[], &HashMap::new(), &BTreeMap::new(), 50);
assert_eq!(embeds[0].relationship, "fk_user");
assert_eq!(embeds[0].output_key, "author");
}
#[test]
fn a_page_reaches_only_the_level_its_path_names() {
let limits = |pages: &[(&str, u32)]| {
let (embeds, counts) = posts_with_comments();
let pages = pages.iter().map(|(p, n)| ((*p).to_string(), *n)).collect();
let (embeds, _) = selections(&embeds, &counts, &HashMap::new(), &pages, 50);
(embeds[0].limit, embeds[0].embeds[0].limit)
};
assert_eq!(limits(&[("posts.comments", 5)]), (Some(50), Some(5)));
assert_eq!(limits(&[("posts", 200)]), (Some(200), Some(50)));
assert_eq!(limits(&[("comments", 7)]), (Some(50), Some(50)));
}
#[test]
fn the_default_embed_page_is_its_own_setting_capped_by_the_ceiling() {
use fraiseql_core::schema::RestConfig;
assert_eq!(default_embed_page(&RestConfig::default()), 50, "not max_page_size (1 000)");
let low_ceiling = RestConfig {
max_page_size: 20,
..RestConfig::default()
};
assert_eq!(default_embed_page(&low_ceiling), 20);
}