Skip to content

Commit 4bf21f3

Browse files
committed
graphql: Allow gt/lt comparisons with Bytes fields
Fixes #4282
1 parent 5c53812 commit 4bf21f3

File tree

3 files changed

+59
-5
lines changed

3 files changed

+59
-5
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Fields of type `Bytes` can now use less than and greater than filters [#4285](https://github.com/graphprotocol/graph-node/pull/4285)
6+
57
#### Upgrade notes
68

79
- This release includes a **determinism fix** that should affect very few subgraphs on the network (currently only two). There was an issue that if a subgraph manifest had one data source with no contract address, listening to the same events or calls of another data source that has a specified address, the handlers for those would be called twice. With the fix, this will happen no more, the handler will be called just once like it should.

graphql/src/schema/api.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,18 @@ fn field_scalar_filter_input_values(
291291
match field_type.name.as_ref() {
292292
"BigInt" => vec!["", "not", "gt", "lt", "gte", "lte", "in", "not_in"],
293293
"Boolean" => vec!["", "not", "in", "not_in"],
294-
"Bytes" => vec!["", "not", "in", "not_in", "contains", "not_contains"],
294+
"Bytes" => vec![
295+
"",
296+
"not",
297+
"gt",
298+
"lt",
299+
"gte",
300+
"lte",
301+
"in",
302+
"not_in",
303+
"contains",
304+
"not_contains",
305+
],
295306
"BigDecimal" => vec!["", "not", "gt", "lt", "gte", "lte", "in", "not_in"],
296307
"ID" => vec!["", "not", "gt", "lt", "gte", "lte", "in", "not_in"],
297308
"Int" => vec!["", "not", "gt", "lt", "gte", "lte", "in", "not_in"],

graphql/tests/query.rs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ fn test_schema(id: DeploymentHash, id_type: IdType) -> Schema {
170170
171171
type Song @entity {
172172
id: @ID@!
173+
sid: String!
173174
title: String!
174175
writtenBy: Musician!
175176
publisher: Publisher!
@@ -289,10 +290,10 @@ async fn insert_test_entities(
289290
entity! { __typename: "Publisher", id: "0xb1" },
290291
entity! { __typename: "Band", id: "b1", name: "The Musicians", originalSongs: vec![s[1], s[2]] },
291292
entity! { __typename: "Band", id: "b2", name: "The Amateurs", originalSongs: vec![s[1], s[3], s[4]] },
292-
entity! { __typename: "Song", id: s[1], title: "Cheesy Tune", publisher: "0xb1", writtenBy: "m1", media: vec![md[1], md[2]] },
293-
entity! { __typename: "Song", id: s[2], title: "Rock Tune", publisher: "0xb1", writtenBy: "m2", media: vec![md[3], md[4]] },
294-
entity! { __typename: "Song", id: s[3], title: "Pop Tune", publisher: "0xb1", writtenBy: "m1", media: vec![md[5]] },
295-
entity! { __typename: "Song", id: s[4], title: "Folk Tune", publisher: "0xb1", writtenBy: "m3", media: vec![md[6]] },
293+
entity! { __typename: "Song", id: s[1], sid: "s1", title: "Cheesy Tune", publisher: "0xb1", writtenBy: "m1", media: vec![md[1], md[2]] },
294+
entity! { __typename: "Song", id: s[2], sid: "s2", title: "Rock Tune", publisher: "0xb1", writtenBy: "m2", media: vec![md[3], md[4]] },
295+
entity! { __typename: "Song", id: s[3], sid: "s3", title: "Pop Tune", publisher: "0xb1", writtenBy: "m1", media: vec![md[5]] },
296+
entity! { __typename: "Song", id: s[4], sid: "s4", title: "Folk Tune", publisher: "0xb1", writtenBy: "m3", media: vec![md[6]] },
296297
entity! { __typename: "SongStat", id: s[1], played: 10 },
297298
entity! { __typename: "SongStat", id: s[2], played: 15 },
298299
entity! { __typename: "BandReview", id: "r1", body: "Bad musicians", band: "b1", author: "u1" },
@@ -403,6 +404,16 @@ impl From<&str> for QueryArgs {
403404
}
404405
}
405406

407+
impl From<String> for QueryArgs {
408+
fn from(query: String) -> Self {
409+
QueryArgs {
410+
query,
411+
variables: None,
412+
max_complexity: None,
413+
}
414+
}
415+
}
416+
406417
impl From<(&str, r::Value)> for QueryArgs {
407418
fn from((query, vars): (&str, r::Value)) -> Self {
408419
let vars = match vars {
@@ -2286,3 +2297,33 @@ fn trace_works() {
22862297
assert!(!trace.is_none(), "result has a trace");
22872298
})
22882299
}
2300+
2301+
/// Check that various comparisons against `id` work as expected. This also
2302+
/// serves as a test that they work for `String` as well as `Bytes` fields
2303+
/// in general
2304+
#[test]
2305+
fn can_compare_id() {
2306+
// For each entry `(cond, sids)` in this array, check that a query with
2307+
// a where clause `cond` returns a list of songs whose `sid` are the
2308+
// ones listed in `sids`
2309+
let checks = [
2310+
("id_gt: @S2@", vec!["s3", "s4"]),
2311+
("id_gte: @S2@", vec!["s2", "s3", "s4"]),
2312+
("id_lt: @S2@", vec!["s1"]),
2313+
("id_lte: @S2@", vec!["s1", "s2"]),
2314+
("id_not: @S2@", vec!["s1", "s3", "s4"]),
2315+
];
2316+
2317+
for (cond, sids) in checks {
2318+
let query = format!("query {{ songs(where: {{ {cond} }}) {{ sid }} }}");
2319+
let sids: Vec<_> = sids
2320+
.iter()
2321+
.map(|sid| object! { sid: sid.to_string() })
2322+
.collect();
2323+
let exp = object! { songs: sids };
2324+
run_query(query, move |result, id_type| {
2325+
let data = extract_data!(result).unwrap();
2326+
assert_eq!(data, exp, "check {} for {:?} ids", cond, id_type);
2327+
})
2328+
}
2329+
}

0 commit comments

Comments
 (0)