From 7030e0583cbd87ec3401ed5e33def13c70d00607 Mon Sep 17 00:00:00 2001 From: Oliver Rice Date: Thu, 6 Jun 2024 15:43:44 -0500 Subject: [PATCH] add support for IS filtering for ListFilter types --- docs/api.md | 1 + docs/assets/demo_schema.graphql | 10 ++ src/graphql.rs | 11 +++ test/expected/resolve_connection_filter.out | 86 ++++++++++++----- test/expected/resolve_graphiql_schema.out | 100 ++++++++++++++++++++ test/sql/resolve_connection_filter.sql | 18 +++- 6 files changed, 203 insertions(+), 23 deletions(-) diff --git a/docs/api.md b/docs/api.md index 5d8257b7..7f4ad124 100644 --- a/docs/api.md +++ b/docs/api.md @@ -587,6 +587,7 @@ Where the `Filter` type enumerates filterable fields and their associated containedBy: [String!] eq: [String!] overlaps: [String!] + is: FilterIs } ``` diff --git a/docs/assets/demo_schema.graphql b/docs/assets/demo_schema.graphql index 342d7eb4..fec2f4b5 100644 --- a/docs/assets/demo_schema.graphql +++ b/docs/assets/demo_schema.graphql @@ -133,6 +133,7 @@ input BigFloatListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } """An arbitrary size integer represented as a string""" @@ -160,6 +161,7 @@ input BigIntListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } type Blog implements Node { @@ -414,6 +416,7 @@ input BooleanListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } """ @@ -446,6 +449,7 @@ input DateListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } """A date and time""" @@ -473,6 +477,7 @@ input DatetimeListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } enum FilterIs { @@ -502,6 +507,7 @@ input FloatListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } """ @@ -533,6 +539,7 @@ input IntListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } """A Javascript Object Notation value serialized as a string""" @@ -783,6 +790,7 @@ input StringListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } """A time without date information""" @@ -810,6 +818,7 @@ input TimeListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } """A universally unique identifier""" @@ -833,4 +842,5 @@ input UUIDListFilter { contains: [BigFloat!] eq: [BigFloat!] overlaps: [BigFloat!] + is: FilterIs } diff --git a/src/graphql.rs b/src/graphql.rs index dc4aaccc..fd16448a 100644 --- a/src/graphql.rs +++ b/src/graphql.rs @@ -3608,11 +3608,22 @@ impl ___Type for FilterTypeType { FilterOp::ContainedBy, FilterOp::Equal, FilterOp::Overlap, + FilterOp::Is, ]; supported_ops .iter() .map(|op| match op { + FilterOp::Is => __InputValue { + name_: "is".to_string(), + type_: __Type::Enum(EnumType { + enum_: EnumSource::FilterIs, + schema: Arc::clone(&self.schema), + }), + description: None, + default_value: None, + sql_type: None, + }, _ => __InputValue { name_: op.to_string(), type_: __Type::List(ListType { diff --git a/test/expected/resolve_connection_filter.out b/test/expected/resolve_connection_filter.out index d6718db1..f8dd44bc 100644 --- a/test/expected/resolve_connection_filter.out +++ b/test/expected/resolve_connection_filter.out @@ -10,7 +10,8 @@ begin; values (1, true, 'foo', '1111111111', '{"customer", "priority"}'), (2, true, 'bar', null, '{"customer"}'), - (3, false, 'baz', '33333333333', '{"lead", "priority"}'); + (3, false, 'baz', '33333333333', '{"lead", "priority"}'), + (4, false, 'qui', '4585858', null); savepoint a; -- Filter by Int select jsonb_pretty( @@ -137,6 +138,11 @@ begin; "node": { + "id": 3+ } + + }, + + { + + "node": { + + "id": 4+ + } + } + ] + } + @@ -146,17 +152,17 @@ begin; -- filter = null is ignored select graphql.resolve($${accountCollection(filter: null) { edges { node { id } } }}$$); - resolve -------------------------------------------------------------------------------------------------------------- - {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}]}}} + resolve +---------------------------------------------------------------------------------------------------------------------------------- + {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}, {"node": {"id": 4}}]}}} (1 row) rollback to savepoint a; -- neq select graphql.resolve($${accountCollection(filter: {id: {neq: 2}}) { edges { node { id } } }}$$); - resolve ----------------------------------------------------------------------------------------- - {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 3}}]}}} + resolve +------------------------------------------------------------------------------------------------------------- + {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 3}}, {"node": {"id": 4}}]}}} (1 row) rollback to savepoint a; @@ -186,17 +192,17 @@ begin; rollback to savepoint a; -- gte select graphql.resolve($${accountCollection(filter: {id: {gte: 2}}) { edges { node { id } } }}$$); - resolve ----------------------------------------------------------------------------------------- - {"data": {"accountCollection": {"edges": [{"node": {"id": 2}}, {"node": {"id": 3}}]}}} + resolve +------------------------------------------------------------------------------------------------------------- + {"data": {"accountCollection": {"edges": [{"node": {"id": 2}}, {"node": {"id": 3}}, {"node": {"id": 4}}]}}} (1 row) rollback to savepoint a; -- gt select graphql.resolve($${accountCollection(filter: {id: {gt: 2}}) { edges { node { id } } }}$$); - resolve -------------------------------------------------------------------- - {"data": {"accountCollection": {"edges": [{"node": {"id": 3}}]}}} + resolve +---------------------------------------------------------------------------------------- + {"data": {"accountCollection": {"edges": [{"node": {"id": 3}}, {"node": {"id": 4}}]}}} (1 row) rollback to savepoint a; @@ -210,9 +216,9 @@ begin; rollback to savepoint a; -- is - is not null select graphql.resolve($${accountCollection(filter: {phone: {is: NOT_NULL}}) { edges { node { id } } }}$$); - resolve ----------------------------------------------------------------------------------------- - {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 3}}]}}} + resolve +------------------------------------------------------------------------------------------------------------- + {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 3}}, {"node": {"id": 4}}]}}} (1 row) rollback to savepoint a; @@ -412,6 +418,37 @@ begin; (1 row) rollback to savepoint a; + -- is - array column is NULL/NOT_NULL + select jsonb_pretty( + graphql.resolve($$ + { + accountCollection(filter: {tags: {is: NULL}}) { + edges { + node { + id + } + } + } + } + $$) + ); + jsonb_pretty +--------------------------------- + { + + "data": { + + "accountCollection": { + + "edges": [ + + { + + "node": { + + "id": 4+ + } + + } + + ] + + } + + } + + } +(1 row) + -- variable is - is null select graphql.resolve($$query AAA($nis: FilterIs) { accountCollection(filter: {phone: {is: $nis}}) { edges { node { id } } }}$$, '{"nis": "NULL"}'); resolve @@ -422,9 +459,9 @@ begin; rollback to savepoint a; -- variable is - absent treated as ignored / returns all select graphql.resolve($$query AAA($nis: FilterIs) { accountCollection(filter: {phone: {is: $nis}}) { edges { node { id } } }}$$, '{}'); - resolve -------------------------------------------------------------------------------------------------------------- - {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}]}}} + resolve +---------------------------------------------------------------------------------------------------------------------------------- + {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}, {"node": {"id": 4}}]}}} (1 row) rollback to savepoint a; @@ -478,9 +515,9 @@ begin; rollback to savepoint a; -- variable in - absent treated as ignored / returns all select graphql.resolve($$query AAA($nin: [String!]) { accountCollection(filter: {name: {in: $nin}}) { edges { node { id } } }}$$, '{}'); - resolve -------------------------------------------------------------------------------------------------------------- - {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}]}}} + resolve +---------------------------------------------------------------------------------------------------------------------------------- + {"data": {"accountCollection": {"edges": [{"node": {"id": 1}}, {"node": {"id": 2}}, {"node": {"id": 3}}, {"node": {"id": 4}}]}}} (1 row) rollback to savepoint a; @@ -960,6 +997,11 @@ begin; "node": { + "id": 3+ } + + }, + + { + + "node": { + + "id": 4+ + } + } + ] + } + diff --git a/test/expected/resolve_graphiql_schema.out b/test/expected/resolve_graphiql_schema.out index f5499335..cdc90b1e 100644 --- a/test/expected/resolve_graphiql_schema.out +++ b/test/expected/resolve_graphiql_schema.out @@ -1120,6 +1120,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -1318,6 +1328,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -3267,6 +3287,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -3477,6 +3507,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -3675,6 +3715,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -3897,6 +3947,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -4130,6 +4190,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -6302,6 +6372,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -6500,6 +6580,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + @@ -6658,6 +6748,16 @@ begin; "description": null, + "defaultValue": null + }, + + { + + "name": "is", + + "type": { + + "kind": "ENUM", + + "name": "FilterIs", + + "ofType": null + + }, + + "description": null, + + "defaultValue": null + + }, + { + "name": "overlaps", + "type": { + diff --git a/test/sql/resolve_connection_filter.sql b/test/sql/resolve_connection_filter.sql index 244a1771..3114601b 100644 --- a/test/sql/resolve_connection_filter.sql +++ b/test/sql/resolve_connection_filter.sql @@ -11,7 +11,8 @@ begin; values (1, true, 'foo', '1111111111', '{"customer", "priority"}'), (2, true, 'bar', null, '{"customer"}'), - (3, false, 'baz', '33333333333', '{"lead", "priority"}'); + (3, false, 'baz', '33333333333', '{"lead", "priority"}'), + (4, false, 'qui', '4585858', null); savepoint a; @@ -202,6 +203,21 @@ begin; ); rollback to savepoint a; + -- is - array column is NULL/NOT_NULL + select jsonb_pretty( + graphql.resolve($$ + { + accountCollection(filter: {tags: {is: NULL}}) { + edges { + node { + id + } + } + } + } + $$) + ); + -- variable is - is null select graphql.resolve($$query AAA($nis: FilterIs) { accountCollection(filter: {phone: {is: $nis}}) { edges { node { id } } }}$$, '{"nis": "NULL"}'); rollback to savepoint a;