Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 125 additions & 23 deletions store/test-store/tests/graphql/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ async fn insert_test_entities(
vec![
entity! { is => id: "m3", name: "Tom", mainBand: "b2", bands: vec!["b1", "b2"], favoriteCount: 5, birthDate: timestamp.clone(), vid: 2i64 },
entity! { is => id: "m4", name: "Valerie", bands: Vec::<String>::new(), favoriteCount: 20, birthDate: timestamp.clone(), vid: 3i64 },
entity! { is => id: "m5", name: "Paul", mainBand: "b2", bands: vec!["b2"], favoriteCount: 2 , birthDate: timestamp.clone(), vid: 4i64 },
],
)];
let entities1 = insert_ops(&manifest.schema, entities1);
Expand Down Expand Up @@ -771,7 +772,8 @@ fn can_query_one_to_one_relationship() {
object! { name: "John", mainBand: object! { name: "The Musicians" }, favoriteCount: "10", birthDate: "1710837304040956" },
object! { name: "Lisa", mainBand: object! { name: "The Musicians" }, favoriteCount: "100", birthDate: "1710837304040956" },
object! { name: "Tom", mainBand: object! { name: "The Amateurs" }, favoriteCount: "5", birthDate: "1710837304040956" },
object! { name: "Valerie", mainBand: r::Value::Null, favoriteCount: "20", birthDate: "1710837304040956" }
object! { name: "Valerie", mainBand: r::Value::Null, favoriteCount: "20", birthDate: "1710837304040956" },
object! { name: "Paul", mainBand: object! { name: "The Amateurs" }, favoriteCount: "2", birthDate: "1710837304040956" }
],
songStats: vec![
object! {
Expand Down Expand Up @@ -815,7 +817,8 @@ fn can_filter_by_timestamp() {
object! { name: "John" },
object! { name: "Lisa" },
object! { name: "Tom" },
object! { name: "Valerie" }
object! { name: "Valerie" },
object! { name: "Paul" },
],
};
let data = extract_data!(result).unwrap();
Expand Down Expand Up @@ -868,6 +871,9 @@ fn can_query_one_to_many_relationships_in_both_directions() {
object! {
name: "Valerie", writtenSongs: Vec::<String>::new()
},
object! {
name: "Paul", writtenSongs: Vec::<String>::new()
},
]
};

Expand Down Expand Up @@ -906,15 +912,16 @@ fn can_query_many_to_many_relationship() {

let the_amateurs = object! {
name: "The Amateurs",
members: members(vec![ "John", "Tom" ])
members: members(vec![ "John", "Tom", "Paul" ])
};

let exp = object! {
musicians: vec![
object! { name: "John", bands: vec![ the_musicians.clone(), the_amateurs.clone() ]},
object! { name: "Lisa", bands: vec![ the_musicians.clone() ] },
object! { name: "Tom", bands: vec![ the_musicians, the_amateurs ] },
object! { name: "Valerie", bands: Vec::<String>::new() }
object! { name: "Tom", bands: vec![ the_musicians, the_amateurs.clone() ] },
object! { name: "Valerie", bands: Vec::<String>::new() },
object! { name: "Paul", bands: vec![ the_amateurs ] }
]
};

Expand Down Expand Up @@ -996,10 +1003,12 @@ fn can_query_with_sorting_by_child_entity() {
object! { name: "Valerie", mainBand: r::Value::Null },
object! { name: "Lisa", mainBand: object! { name: "The Musicians" } },
object! { name: "John", mainBand: object! { name: "The Musicians" } },
object! { name: "Paul", mainBand: object! { name: "The Amateurs"} },
object! { name: "Tom", mainBand: object! { name: "The Amateurs"} },
],
asc: vec![
object! { name: "Tom", mainBand: object! { name: "The Amateurs"} },
object! { name: "Paul", mainBand: object! { name: "The Amateurs"} },
object! { name: "John", mainBand: object! { name: "The Musicians" } },
object! { name: "Lisa", mainBand: object! { name: "The Musicians" } },
object! { name: "Valerie", mainBand: r::Value::Null },
Expand Down Expand Up @@ -1307,7 +1316,8 @@ fn can_query_with_child_filter_on_list_type_field() {
let exp = object! {
musicians: vec![
object! { name: "John", bands: vec![ the_musicians.clone(), the_amateurs.clone() ]},
object! { name: "Tom", bands: vec![ the_musicians, the_amateurs ] },
object! { name: "Tom", bands: vec![ the_musicians, the_amateurs.clone() ] },
object! { name: "Paul", bands: vec![ the_amateurs ] },
]
};

Expand Down Expand Up @@ -1352,7 +1362,8 @@ fn can_query_with_child_filter_on_named_type_field() {
run_query(QUERY, |result, _| {
let exp = object! {
musicians: vec![
object! { name: "Tom", mainBand: object! { id: "b2"} }
object! { name: "Tom", mainBand: object! { id: "b2"} },
object! { name: "Paul", mainBand: object! { id: "b2"} }
]
};

Expand Down Expand Up @@ -1703,7 +1714,7 @@ fn skip_directive_works_with_query_variables() {

run_query((QUERY, object! { skip: true }), |result, _| {
// Assert that only names are returned
let musicians: Vec<_> = ["John", "Lisa", "Tom", "Valerie"]
let musicians: Vec<_> = ["John", "Lisa", "Tom", "Valerie", "Paul"]
.into_iter()
.map(|name| object! { name: name })
.collect();
Expand All @@ -1719,7 +1730,8 @@ fn skip_directive_works_with_query_variables() {
object! { id: "m1", name: "John" },
object! { id: "m2", name: "Lisa"},
object! { id: "m3", name: "Tom" },
object! { id: "m4", name: "Valerie" }
object! { id: "m4", name: "Valerie" },
object! { id: "m5", name: "Paul" }
]
};
let data = extract_data!(result).unwrap();
Expand All @@ -1745,7 +1757,8 @@ fn include_directive_works_with_query_variables() {
object! { id: "m1", name: "John" },
object! { id: "m2", name: "Lisa"},
object! { id: "m3", name: "Tom" },
object! { id: "m4", name: "Valerie" }
object! { id: "m4", name: "Valerie" },
object! { id: "m5", name: "Paul" }
]
};
let data = extract_data!(result).unwrap();
Expand All @@ -1754,7 +1767,7 @@ fn include_directive_works_with_query_variables() {

run_query((QUERY, object! { include: false }), |result, _| {
// Assert that only names are returned
let musicians: Vec<_> = ["John", "Lisa", "Tom", "Valerie"]
let musicians: Vec<_> = ["John", "Lisa", "Tom", "Valerie", "Paul"]
.into_iter()
.map(|name| object! { name: name })
.collect();
Expand Down Expand Up @@ -1894,7 +1907,7 @@ fn skip_is_nullable() {
";

run_query(QUERY, |result, _| {
let musicians: Vec<_> = ["John", "Lisa", "Tom", "Valerie"]
let musicians: Vec<_> = ["John", "Lisa", "Tom", "Valerie", "Paul"]
.into_iter()
.map(|name| object! { name: name })
.collect();
Expand All @@ -1915,7 +1928,7 @@ fn first_is_nullable() {
";

run_query(QUERY, |result, _| {
let musicians: Vec<_> = ["John", "Lisa", "Tom", "Valerie"]
let musicians: Vec<_> = ["John", "Lisa", "Tom", "Valerie", "Paul"]
.into_iter()
.map(|name| object! { name: name })
.collect();
Expand Down Expand Up @@ -1992,7 +2005,8 @@ fn can_filter_by_relationship_fields() {

let exp = object! {
musicians: vec![
object! { id: "m3", name: "Tom", mainBand: object! { id: "b2"} }
object! { id: "m3", name: "Tom", mainBand: object! { id: "b2"} },
object! { id: "m5", name: "Paul", mainBand: object! { id: "b2"} }
],
bands: vec![
object! {
Expand Down Expand Up @@ -2074,6 +2088,10 @@ fn can_use_nested_filter() {
object! {
name: "Valerie",
bands: Vec::<r::Value>::new(),
},
object! {
name: "Paul",
bands: vec![ object! { id: "b2" }]
}
]
};
Expand All @@ -2096,7 +2114,7 @@ fn ignores_invalid_field_arguments() {
// Without validations
Ok(Some(r::Value::Object(obj))) => match obj.get("musicians").unwrap() {
r::Value::List(lst) => {
assert_eq!(4, lst.len());
assert_eq!(5, lst.len());
}
_ => panic!("expected a list of values"),
},
Expand Down Expand Up @@ -2202,6 +2220,7 @@ fn missing_variable() {
object! { id: "m2" },
object! { id: "m3" },
object! { id: "m4" },
object! { id: "m5" },
]
};

Expand Down Expand Up @@ -2232,6 +2251,7 @@ fn missing_variable() {
object! { id: "m2" },
object! { id: "m3" },
object! { id: "m4" },
object! { id: "m5" },
]
};

Expand Down Expand Up @@ -2326,13 +2346,15 @@ fn query_at_block() {
up to block number 2 and data for block number 3 is therefore not yet available";
const BLOCK_HASH_NOT_FOUND: &str = "no block with that hash found";

let all_musicians = vec!["m1", "m2", "m3", "m4", "m5"];

musicians_at("number: 7000", Err(BLOCK_NOT_INDEXED), "n7000");
musicians_at("number: 0", Ok(vec!["m1", "m2"]), "n0");
musicians_at("number: 1", Ok(vec!["m1", "m2", "m3", "m4"]), "n1");
musicians_at("number: 1", Ok(all_musicians.clone()), "n1");

musicians_at(&hash(&BLOCKS[0]), Ok(vec!["m1", "m2"]), "h0");
musicians_at(&hash(&BLOCKS[1]), Ok(vec!["m1", "m2", "m3", "m4"]), "h1");
musicians_at(&hash(&BLOCKS[2]), Ok(vec!["m1", "m2", "m3", "m4"]), "h2");
musicians_at(&hash(&BLOCKS[1]), Ok(all_musicians.clone()), "h1");
musicians_at(&hash(&BLOCKS[2]), Ok(all_musicians.clone()), "h2");
musicians_at(&hash(&BLOCKS[3]), Err(BLOCK_NOT_INDEXED2), "h3");
musicians_at(&hash(&BLOCKS[4]), Err(BLOCK_HASH_NOT_FOUND), "h4");
}
Expand Down Expand Up @@ -2371,17 +2393,19 @@ fn query_at_block_with_vars() {
up to block number 2 and data for block number 3 is therefore not yet available";
const BLOCK_HASH_NOT_FOUND: &str = "no block with that hash found";

let all_musicians = vec!["m1", "m2", "m3", "m4", "m5"];

musicians_at_nr(7000, Err(BLOCK_NOT_INDEXED), "n7000");
musicians_at_nr(0, Ok(vec!["m1", "m2"]), "n0");
musicians_at_nr(1, Ok(vec!["m1", "m2", "m3", "m4"]), "n1");
musicians_at_nr(1, Ok(all_musicians.clone()), "n1");

musicians_at_nr_gte(7000, Err(BLOCK_NOT_INDEXED), "ngte7000");
musicians_at_nr_gte(0, Ok(vec!["m1", "m2", "m3", "m4"]), "ngte0");
musicians_at_nr_gte(1, Ok(vec!["m1", "m2", "m3", "m4"]), "ngte1");
musicians_at_nr_gte(0, Ok(all_musicians.clone()), "ngte0");
musicians_at_nr_gte(1, Ok(all_musicians.clone()), "ngte1");

musicians_at_hash(&BLOCKS[0], Ok(vec!["m1", "m2"]), "h0");
musicians_at_hash(&BLOCKS[1], Ok(vec!["m1", "m2", "m3", "m4"]), "h1");
musicians_at_hash(&BLOCKS[2], Ok(vec!["m1", "m2", "m3", "m4"]), "h2");
musicians_at_hash(&BLOCKS[1], Ok(all_musicians.clone()), "h1");
musicians_at_hash(&BLOCKS[2], Ok(all_musicians.clone()), "h2");
musicians_at_hash(&BLOCKS[3], Err(BLOCK_NOT_INDEXED2), "h3");
musicians_at_hash(&BLOCKS[4], Err(BLOCK_HASH_NOT_FOUND), "h4");
}
Expand Down Expand Up @@ -2822,6 +2846,7 @@ fn can_query_with_or_and_filter() {
musicians: vec![
object! { name: "John", id: "m1" },
object! { name: "Tom", id: "m3" },
object! { name: "Paul", id: "m5" },
],
};
let data = extract_data!(result).unwrap();
Expand All @@ -2847,6 +2872,7 @@ fn can_query_with_or_explicit_and_filter() {
musicians: vec![
object! { name: "John", id: "m1" },
object! { name: "Tom", id: "m3" },
object! { name: "Paul", id: "m5" },
],
};
let data = extract_data!(result).unwrap();
Expand Down Expand Up @@ -3049,3 +3075,79 @@ fn simple_aggregation() {
assert_eq!(data, exp);
})
}

/// Check that if we have entities where a related entity is null, followed
/// by one where it is not null that the children are joined correctly to
/// their respective parent
Comment on lines +3079 to +3081
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curios, why a null would cause an issue, Was there a bug that recently got fixed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh, I don't remember why I wrote that test, and it passed for me on master on the first try. I just figured it doesn't hurt to have this test either way

#[test]
fn children_are_joined_correctly() {
// Get just the `id` for the `mainBand` and `bands`
const QUERY1: &str = "
query {
musicians {
id
mainBand { id }
bands { id }
}
}
";

// Get the `id` and one more attribute for the `mainBand` and `bands`
const QUERY2: &str = "
query {
musicians {
id
mainBand { id name }
bands { id name }
}
}
";

run_query(QUERY1, |result, _| {
fn b1() -> r::Value {
object! { id: "b1" }
}
fn b2() -> r::Value {
object! { id: "b2" }
}
let null = r::Value::Null;
let none = Vec::<r::Value>::new();

let exp = object! {
musicians: vec![
object! { id: "m1", mainBand: b1(), bands: vec![ b1(), b2() ] },
object! { id: "m2", mainBand: b1(), bands: vec![ b1() ] },
object! { id: "m3", mainBand: b2(), bands: vec![ b1(), b2() ] },
object! { id: "m4", mainBand: null, bands: none },
object! { id: "m5", mainBand: b2(), bands: vec![ b2() ] },
],
};

let data = extract_data!(result).unwrap();
assert_eq!(data, exp);
});

run_query(QUERY2, |result, _| {
fn b1() -> r::Value {
object! { id: "b1", name: "The Musicians" }
}
fn b2() -> r::Value {
object! { id: "b2", name: "The Amateurs" }
}
let null = r::Value::Null;
let none = Vec::<r::Value>::new();

let exp = object! {
musicians: vec![
object! { id: "m1", mainBand: b1(), bands: vec![ b1(), b2() ] },
object! { id: "m2", mainBand: b1(), bands: vec![ b1() ] },
object! { id: "m3", mainBand: b2(), bands: vec![ b1(), b2() ] },
object! { id: "m4", mainBand: null, bands: none },
object! { id: "m5", mainBand: b2(), bands: vec![ b2() ] },
],
};

let data = extract_data!(result).unwrap();
assert_eq!(data, exp);
});
}
Loading