Skip to content

Commit 9aba9ee

Browse files
authored
feat(relations): allow filtering on existence of nullable relation node (#90)
1 parent 344f2a2 commit 9aba9ee

File tree

6 files changed

+611
-261
lines changed

6 files changed

+611
-261
lines changed

README.md

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,24 @@ query {
367367
}
368368
```
369369

370+
A node passes the filter if a related node exists *and* the filter criteria for the related node are satisfied. (If a related node does not exist, the check fails.)
371+
372+
The `*Exists` Boolean field can be used to filter on the existence of a related node:
373+
374+
```graphql
375+
query {
376+
allPosts(filter: {
377+
personByAuthorIdExists: true
378+
}) {
379+
nodes {
380+
id
381+
}
382+
}
383+
}
384+
```
385+
386+
The `*Exists` Boolean field is only exposed on nullable relations. For example, if the `post.author_id` column is defined as `not null`, a related `person` always exists, so the `personByAuthorIdExists` field is not exposed.
387+
370388
</details>
371389

372390
<details>
@@ -378,13 +396,31 @@ query {
378396
```graphql
379397
query {
380398
allPeople(filter: {
381-
accountByPersonId: { status: { equalTo: ACTIVE } }
399+
accountByAccountId: { status: { equalTo: ACTIVE } }
382400
}) {
383401
...
384402
}
385403
}
386404
```
387405

406+
A node passes the filter if a related node exists *and* the filter criteria for the related node are satisfied. (If a related node does not exist, the check fails.)
407+
408+
The `*Exists` Boolean field can be used to filter on the existence of a related node:
409+
410+
```graphql
411+
query {
412+
allPeople(filter: {
413+
accountByAccountId: true
414+
}) {
415+
nodes {
416+
id
417+
}
418+
}
419+
}
420+
```
421+
422+
The `*Exists` Boolean field is only exposed on nullable relations. For example, if the `person.account_id` column is defined as `not null`, a related `account` always exists, so the `accountByAccountIdExists` field is not exposed.
423+
388424
</details>
389425

390426
<details>
@@ -406,32 +442,28 @@ query {
406442
}) {
407443
nodes {
408444
id
409-
createdAt
410445
}
411446
}
412447
}
413448
```
414449

415-
There is also an `exist` Boolean field for evaluating whether any related objects exist.
450+
The `*Exist` Boolean field can be used to filter on the existence of related records:
416451

417452
```graphql
418453
query {
419454
allPeople(filter: {
420-
postsByAuthorId: {
421-
exist: true
422-
}
455+
postsByAuthorIdExist: true
423456
}) {
424457
nodes {
425458
id
426-
createdAt
427459
}
428460
}
429461
}
430462
```
431463

432464
</details>
433465

434-
For additional examples, see the [tests](https://github.com/graphile-contrib/postgraphile-plugin-connection-filter/blob/master/__tests__/fixtures/queries/filters.graphql).
466+
For additional examples, see the [tests](https://github.com/graphile-contrib/postgraphile-plugin-connection-filter/blob/master/__tests__/fixtures/queries/).
435467

436468
## Plugin Options
437469

__tests__/fixtures/queries/relations.graphql

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
11
query {
2-
allSideAs_junctionsBySideAId_exist_true: allSideAs(filter: {junctionsBySideAId: {exist: true}}) { nodes { aId } }
3-
allSideBs_junctionsBySideBId_exist_true: allSideBs(filter: {junctionsBySideBId: {exist: true}}) { nodes { bId } }
2+
allSideAs_junctionsBySideAIdExist_false: allSideAs(filter: {junctionsBySideAIdExist: false}) { nodes { aId } }
3+
allSideAs_junctionsBySideAIdExist_true: allSideAs(filter: {junctionsBySideAIdExist: true}) { nodes { aId } }
4+
allSideBs_junctionsBySideBIdExist_false: allSideBs(filter: {junctionsBySideBIdExist: false}) { nodes { bId } }
5+
allSideBs_junctionsBySideBIdExist_true: allSideBs(filter: {junctionsBySideBIdExist: true}) { nodes { bId } }
46
backwardCompound_name_equalTo_backwardCompound12: allFilterables(filter: {backwardCompoundByBackwardCompound1AndBackwardCompound2: {name: {equalTo: "backwardCompound12"}}}) { ...textConnection }
7+
backwardCompoundExists_false: allFilterables(filter: {backwardCompoundByBackwardCompound1AndBackwardCompound2Exists: false}) { ...textConnection }
8+
backwardCompoundExists_true: allFilterables(filter: {backwardCompoundByBackwardCompound1AndBackwardCompound2Exists: true}) { ...textConnection }
59
backward_name_equalTo_backward2: allFilterables(filter: {backwardByFilterableId: {name: {equalTo: "backward2"}}}) { ...textConnection }
10+
backwardExists_false: allFilterables(filter: {backwardByFilterableIdExists: false}) { ...textConnection }
11+
backwardExists_true: allFilterables(filter: {backwardByFilterableIdExists: true}) { ...textConnection }
612
children_every_name_equalTo_child2: allFilterables(filter: {childrenByFilterableId: {every: {name: {equalTo: "child2"}}}}) { ...childrenConnection }
713
children_every_name_startsWith_c: allFilterables(filter: {childrenByFilterableId: {every: {name: {startsWith: "c"}}}}) { ...childrenConnection }
8-
children_every_name_startsWith_c_and_exist_true: allFilterables(filter: {childrenByFilterableId: {every: {name: {startsWith: "c"}}, exist: true}}) { ...childrenConnection }
9-
children_every_name_startsWith_c_and_exist_false: allFilterables(filter: {childrenByFilterableId: {every: {name: {startsWith: "c"}}, exist: false}}) { ...childrenConnection }
10-
children_exist_true: allFilterables(filter: {childrenByFilterableId: {exist: true}}) { ...childrenConnection }
11-
children_exist_false: allFilterables(filter: {childrenByFilterableId: {exist: false}}) { ...childrenConnection }
14+
children_every_name_startsWith_c_and_childrenExist_true: allFilterables(filter: {childrenByFilterableId: {every: {name: {startsWith: "c"}}}, childrenByFilterableIdExist: true}) { ...childrenConnection }
15+
children_every_name_startsWith_c_and_childrenExist_false: allFilterables(filter: {childrenByFilterableId: {every: {name: {startsWith: "c"}}}, childrenByFilterableIdExist: false}) { ...childrenConnection }
1216
children_some_name_equalTo_child2: allFilterables(filter: {childrenByFilterableId: {some: {name: {equalTo: "child2"}}}}) { ...childrenConnection }
1317
children_some_name_startsWith_c: allFilterables(filter: {childrenByFilterableId: {some: {name: {startsWith: "c"}}}}) { ...childrenConnection }
14-
children_some_name_startsWith_c_and_exist_true: allFilterables(filter: {childrenByFilterableId: {some: {name: {startsWith: "c"}}, exist: true}}) { ...childrenConnection }
15-
children_some_name_startsWith_c_and_exist_false: allFilterables(filter: {childrenByFilterableId: {some: {name: {startsWith: "c"}}, exist: false}}) { ...childrenConnection }
18+
children_some_name_startsWith_c_and_childrenExist_true: allFilterables(filter: {childrenByFilterableId: {some: {name: {startsWith: "c"}}}, childrenByFilterableIdExist: true}) { ...childrenConnection }
19+
children_some_name_startsWith_c_and_childrenExist_false: allFilterables(filter: {childrenByFilterableId: {some: {name: {startsWith: "c"}}}, childrenByFilterableIdExist: false}) { ...childrenConnection }
1620
children_none_name_equalTo_child2: allFilterables(filter: {childrenByFilterableId: {none: {name: {equalTo: "child2"}}}}) { ...childrenConnection }
1721
children_none_name_startsWith_c: allFilterables(filter: {childrenByFilterableId: {none: {name: {startsWith: "c"}}}}) { ...childrenConnection }
18-
children_none_name_startsWith_c_and_exist_true: allFilterables(filter: {childrenByFilterableId: {none: {name: {startsWith: "c"}}, exist: true}}) { ...childrenConnection }
19-
children_none_name_startsWith_c_and_exist_false: allFilterables(filter: {childrenByFilterableId: {none: {name: {startsWith: "c"}}, exist: false}}) { ...childrenConnection }
22+
children_none_name_startsWith_c_and_childrenExist_true: allFilterables(filter: {childrenByFilterableId: {none: {name: {startsWith: "c"}}}, childrenByFilterableIdExist: true}) { ...childrenConnection }
23+
children_none_name_startsWith_c_and_childrenExist_false: allFilterables(filter: {childrenByFilterableId: {none: {name: {startsWith: "c"}}}, childrenByFilterableIdExist: false}) { ...childrenConnection }
24+
childrenExist_false: allFilterables(filter: {childrenByFilterableIdExist: false}) { ...childrenConnection }
25+
childrenExist_true: allFilterables(filter: {childrenByFilterableIdExist: true}) { ...childrenConnection }
2026
forwardCompound_name_equalTo_forwardCompound12: allFilterables(filter: {forwardCompoundByForwardCompound1AndForwardCompound2: {name: {equalTo: "forwardCompound12"}}}) { ...textConnection }
27+
forwardCompoundExists_false: allFilterables(filter: {forwardCompoundByForwardCompound1AndForwardCompound2Exists: false}) { ...textConnection }
28+
forwardCompoundExists_true: allFilterables(filter: {forwardCompoundByForwardCompound1AndForwardCompound2Exists: true}) { ...textConnection }
2129
forward_name_equalTo_forward2: allFilterables(filter: {forwardByForwardId: {name: {equalTo: "forward2"}}}) { ...textConnection }
30+
forwardExists_false: allFilterables(filter: {forwardByForwardIdExists: false}) { ...textConnection }
31+
forwardExists_true: allFilterables(filter: {forwardByForwardIdExists: true}) { ...textConnection }
2232
parent_name_equalTo_parent2: allFilterables(filter: {parentByParentId: {name: {equalTo: "parent2"}}}) { ...textConnection }
33+
parentExists_false: allFilterables(filter: {parentByParentIdExists: false}) { ...textConnection }
34+
parentExists_true: allFilterables(filter: {parentByParentIdExists: true}) { ...textConnection }
2335
# the following should all fail due to null and empty object checks:
2436
x_backward_name_equalTo_null: allFilterables(filter: {backwardByFilterableId: {name: {equalTo: null}}}) { ...textConnection }
2537
x_backward_name_null: allFilterables(filter: {backwardByFilterableId: {name: null}}) { ...textConnection }
@@ -33,7 +45,7 @@ query {
3345
x_children_every_empty: allFilterables(filter: {childrenByFilterableId: {every: {}}}) { ...childrenConnection }
3446
x_children_null: allFilterables(filter: {childrenByFilterableId: null}) { ...childrenConnection }
3547
x_children_empty: allFilterables(filter: {childrenByFilterableId: {}}) { ...childrenConnection }
36-
x_children_exist_null: allFilterables(filter: {childrenByFilterableId: {exist: null}}) { ...childrenConnection }
48+
x_childrenExist_null: allFilterables(filter: {childrenByFilterableIdExist: null}) { ...childrenConnection }
3749
x_forward_name_equalTo_null: allFilterables(filter: {forwardByForwardId: {name: {equalTo: null}}}) { ...textConnection }
3850
x_forward_name_null: allFilterables(filter: {forwardByForwardId: {name: null}}) { ...textConnection }
3951
x_forward_name_empty: allFilterables(filter: {forwardByForwardId: {name: {}}}) { ...textConnection }

0 commit comments

Comments
 (0)