#![allow(clippy::unwrap_used, clippy::panic)]
use std::collections::HashMap;
use super::*;
fn no_weights() -> HashMap<String, usize> {
HashMap::new()
}
fn score(projection: &DirectReadProjection) -> usize {
estimate_direct_read_cost("users", &no_weights(), projection)
}
fn page(limit: Option<u32>) -> usize {
limit.map_or(1, |l| {
usize::try_from(l).unwrap_or(usize::MAX).clamp(1, PAGINATION_MULTIPLIER_CEILING)
})
}
fn fan_out_total(projection: &DirectReadProjection) -> usize {
let own = score(&DirectReadProjection::flat(projection.leaf_fields, projection.limit));
let rows = page(projection.limit);
projection
.nested
.iter()
.fold(own, |acc, child| acc + rows * fan_out_total(child))
}
fn embed(
leaf_fields: usize,
limit: Option<u32>,
nested: Vec<DirectReadProjection>,
) -> DirectReadProjection {
DirectReadProjection {
leaf_fields,
limit,
nested,
}
}
#[test]
fn a_flat_projection_scores_what_the_bare_field_count_scored() {
assert_eq!(score(&DirectReadProjection::flat(1, Some(100))), 101);
assert_eq!(score(&DirectReadProjection::flat(2, Some(100))), 201);
assert_eq!(score(&DirectReadProjection::flat(3, Some(100))), 301);
assert_eq!(score(&DirectReadProjection::flat(2, Some(10_000))), 201);
assert_eq!(score(&DirectReadProjection::flat(2, Some(0))), 3);
assert_eq!(score(&DirectReadProjection::flat(2, None)), 3);
}
#[test]
fn a_projection_with_nothing_under_it_scores_one() {
assert_eq!(score(&DirectReadProjection::flat(0, Some(100))), 1);
assert_eq!(score(&DirectReadProjection::flat(0, None)), 1);
assert_eq!(score(&embed(0, Some(100), vec![])), 1);
}
#[test]
fn a_composed_embed_scores_what_its_fan_out_charges() {
let shapes = [
embed(1, Some(100), vec![embed(2, Some(100), vec![])]),
embed(1, Some(2), vec![embed(2, Some(2), vec![])]),
embed(0, Some(50), vec![embed(3, Some(10), vec![])]),
embed(2, Some(20), vec![embed(1, Some(5), vec![]), embed(4, Some(100), vec![])]),
embed(1, Some(10), vec![embed(1, Some(10), vec![embed(2, Some(10), vec![])])]),
embed(2, Some(10), vec![embed(1, None, vec![embed(1, Some(3), vec![])])]),
];
for shape in &shapes {
assert_eq!(
score(shape),
fan_out_total(shape),
"composed score must equal the fan-out's full-page total for {shape:?}"
);
}
}
#[test]
fn the_two_level_figure_is_stated_not_only_derived() {
let composed = embed(1, Some(100), vec![embed(2, Some(100), vec![])]);
assert_eq!(score(&composed), 20_201);
assert_eq!(101 + 100 * 201, 20_201);
}
#[test]
fn the_composed_score_is_the_document_paths_score() {
for (parent_fields, parent_page, child_fields, child_page) in [
(1_usize, 100_u32, 2_usize, 100_u32),
(3, 10, 1, 25),
(2, 7, 4, 1),
] {
let parent_sel = (0..parent_fields).map(|i| format!("f{i}")).collect::<Vec<_>>().join(" ");
let child_sel = (0..child_fields).map(|i| format!("g{i}")).collect::<Vec<_>>().join(" ");
let query = format!(
"{{ users(limit: {parent_page}) {{ {parent_sel} \
orders(limit: {child_page}) {{ {child_sel} }} }} }}"
);
let document = parse_graphql_document(&query).unwrap();
let document_score = estimate_query_cost(&document, &no_weights(), None);
let composed = embed(
parent_fields,
Some(parent_page),
vec![embed(child_fields, Some(child_page), vec![])],
);
assert_eq!(
score(&composed),
document_score,
"the same shape must cost the same whichever transport it arrived on ({query})"
);
}
}
#[test]
fn a_composed_embed_costs_more_than_the_parent_alone() {
let parent_only = DirectReadProjection::flat(1, Some(100));
let composed = embed(1, Some(100), vec![embed(2, Some(100), vec![])]);
assert!(
score(&composed) > score(&parent_only),
"an embed composed into the parent statement must be charged for"
);
}
#[test]
fn a_cost_weight_short_circuits_the_projection() {
let mut weights = HashMap::new();
weights.insert("users".to_string(), 7_usize);
let composed = embed(1, Some(100), vec![embed(2, Some(100), vec![])]);
assert_eq!(estimate_direct_read_cost("users", &weights, &composed), 7);
assert_eq!(estimate_direct_read_cost("orders", &weights, &composed), 20_201);
}