Skip to content

Commit 4d67efc

Browse files
authored
feat(citext): allow filtering citext columns and add connectionFilterAdditionalInsensitiveOperators option (#98)
1 parent 76ccaba commit 4d67efc

24 files changed

+6860
-61
lines changed

README.md

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,46 @@ When using PostGraphile as a library, the following plugin options can be passed
471471

472472
<details>
473473

474+
<summary>connectionFilterAdditionalInsensitiveOperators</summary>
475+
476+
Expose additional case-insensitive operators for `String` fields:
477+
478+
```js
479+
postgraphile(pgConfig, schema, {
480+
graphileBuildOptions: {
481+
connectionFilterAdditionalInsensitiveOperators: true,
482+
},
483+
})
484+
```
485+
486+
The additional operators are:
487+
488+
- distinctFromInsensitive
489+
- equalToInsensitive
490+
- greaterThanInsensitive
491+
- greaterThanOrEqualToInsensitive
492+
- inInsensitive
493+
- lessThanInsensitive
494+
- lessThanOrEqualToInsensitive
495+
- notDistinctFromInsensitive
496+
- notEqualToInsensitive
497+
- notInInsensitive
498+
499+
The compiled SQL depends on the GraphQL operator used and the underlying PostgreSQL column type. Note that using case-insensitive operators with `text`/`varchar`/`char` columns will result in calling `lower()` on the operands, and using case-sensitive operators with `citext` columns will result in casting the operands to `text`.
500+
501+
For example, here is how the `equalTo`/`equalToInsensitive` operators compile to SQL:
502+
503+
| GraphQL operator | PostgreSQL column type | Compiled SQL |
504+
| ------------------ | ----------------------- | ------------------------ |
505+
| equalTo | `text`/`varchar`/`char` | <col> = $1 |
506+
| equalTo | `citext` | <col>::text = $1::text |
507+
| equalToInsensitive | `text`/`varchar`/`char` | lower(<col>) = lower($1) |
508+
| equalToInsensitive | `citext` | <col> = $1 |
509+
510+
</details>
511+
512+
<details>
513+
474514
<summary>connectionFilterAllowedOperators</summary>
475515

476516
Restrict filtering to specific operators:
@@ -495,8 +535,6 @@ postgraphile(pgConfig, schema, {
495535
})
496536
```
497537

498-
For a full list of the available operators, see the Comparison Operators table above.
499-
500538
</details>
501539

502540
<details>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
query citext($v2: String = "Test", $v3: String = "tEST") {
2+
distinctFromInsensitive: allFilterables(filter: { citext: { distinctFromInsensitive: $v2 } }) {
3+
...nodes
4+
}
5+
equalToInsensitive: allFilterables(filter: { citext: { equalToInsensitive: $v2 } }) {
6+
...nodes
7+
}
8+
greaterThanInsensitive: allFilterables(filter: { citext: { greaterThanInsensitive: $v2 } }) {
9+
...nodes
10+
}
11+
greaterThanOrEqualToInsensitive: allFilterables(
12+
filter: { citext: { greaterThanOrEqualToInsensitive: $v2 } }
13+
) {
14+
...nodes
15+
}
16+
inInsensitive: allFilterables(filter: { citext: { inInsensitive: [$v2, $v3] } }) {
17+
...nodes
18+
}
19+
lessThanInsensitive: allFilterables(filter: { citext: { lessThanInsensitive: $v2 } }) {
20+
...nodes
21+
}
22+
lessThanOrEqualToInsensitive: allFilterables(
23+
filter: { citext: { lessThanOrEqualToInsensitive: $v2 } }
24+
) {
25+
...nodes
26+
}
27+
notDistinctFromInsensitive: allFilterables(filter: { citext: { notDistinctFromInsensitive: $v2 } }) {
28+
...nodes
29+
}
30+
notEqualToInsensitive: allFilterables(filter: { citext: { notEqualToInsensitive: $v2 } }) {
31+
...nodes
32+
}
33+
notInInsensitive: allFilterables(filter: { citext: { notInInsensitive: [$v2] } }) {
34+
...nodes
35+
}
36+
}
37+
38+
fragment nodes on FilterablesConnection {
39+
nodes {
40+
id
41+
}
42+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
query text($v2: String = "Test", $v3: String = "tEST") {
2+
distinctFromInsensitive: allFilterables(filter: { text: { distinctFromInsensitive: $v2 } }) {
3+
...nodes
4+
}
5+
equalToInsensitive: allFilterables(filter: { text: { equalToInsensitive: $v2 } }) {
6+
...nodes
7+
}
8+
greaterThanInsensitive: allFilterables(filter: { text: { greaterThanInsensitive: $v2 } }) {
9+
...nodes
10+
}
11+
greaterThanOrEqualToInsensitive: allFilterables(
12+
filter: { text: { greaterThanOrEqualToInsensitive: $v2 } }
13+
) {
14+
...nodes
15+
}
16+
inInsensitive: allFilterables(filter: { text: { inInsensitive: [$v2, $v3] } }) {
17+
...nodes
18+
}
19+
lessThanInsensitive: allFilterables(filter: { text: { lessThanInsensitive: $v2 } }) {
20+
...nodes
21+
}
22+
lessThanOrEqualToInsensitive: allFilterables(
23+
filter: { text: { lessThanOrEqualToInsensitive: $v2 } }
24+
) {
25+
...nodes
26+
}
27+
notDistinctFromInsensitive: allFilterables(filter: { text: { notDistinctFromInsensitive: $v2 } }) {
28+
...nodes
29+
}
30+
notEqualToInsensitive: allFilterables(filter: { text: { notEqualToInsensitive: $v2 } }) {
31+
...nodes
32+
}
33+
notInInsensitive: allFilterables(filter: { text: { notInInsensitive: [$v2] } }) {
34+
...nodes
35+
}
36+
}
37+
38+
fragment nodes on FilterablesConnection {
39+
nodes {
40+
id
41+
}
42+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
query citextArray(
2+
$v2: [String] = ["Test", "tEST"]
3+
$v2_1: String = "Test"
4+
$v3: [String] = ["tEST", "test"]
5+
) {
6+
anyEqualTo: allArrayTypes(filter: { citextArray: { anyEqualTo: $v2_1 } }) {
7+
...nodes
8+
}
9+
anyGreaterThan: allArrayTypes(
10+
filter: { citextArray: { anyGreaterThan: $v2_1 } }
11+
) {
12+
...nodes
13+
}
14+
anyGreaterThanOrEqualTo: allArrayTypes(
15+
filter: { citextArray: { anyGreaterThanOrEqualTo: $v2_1 } }
16+
) {
17+
...nodes
18+
}
19+
anyLessThan: allArrayTypes(filter: { citextArray: { anyLessThan: $v2_1 } }) {
20+
...nodes
21+
}
22+
anyLessThanOrEqualTo: allArrayTypes(
23+
filter: { citextArray: { anyLessThanOrEqualTo: $v2_1 } }
24+
) {
25+
...nodes
26+
}
27+
anyNotEqualTo: allArrayTypes(
28+
filter: { citextArray: { anyNotEqualTo: $v2_1 } }
29+
) {
30+
...nodes
31+
}
32+
containedBy: allArrayTypes(filter: { citextArray: { containedBy: $v2 } }) {
33+
...nodes
34+
}
35+
contains: allArrayTypes(filter: { citextArray: { contains: $v3 } }) {
36+
...nodes
37+
}
38+
distinctFrom: allArrayTypes(filter: { citextArray: { distinctFrom: $v2 } }) {
39+
...nodes
40+
}
41+
equalTo: allArrayTypes(filter: { citextArray: { equalTo: $v2 } }) {
42+
...nodes
43+
}
44+
greaterThan: allArrayTypes(filter: { citextArray: { greaterThan: $v2 } }) {
45+
...nodes
46+
}
47+
greaterThanOrEqualTo: allArrayTypes(
48+
filter: { citextArray: { greaterThanOrEqualTo: $v2 } }
49+
) {
50+
...nodes
51+
}
52+
isNull: allArrayTypes(filter: { citextArray: { isNull: true } }) {
53+
...nodes
54+
}
55+
lessThan: allArrayTypes(filter: { citextArray: { lessThan: $v2 } }) {
56+
...nodes
57+
}
58+
lessThanOrEqualTo: allArrayTypes(
59+
filter: { citextArray: { lessThanOrEqualTo: $v2 } }
60+
) {
61+
...nodes
62+
}
63+
notDistinctFrom: allArrayTypes(
64+
filter: { citextArray: { notDistinctFrom: $v2 } }
65+
) {
66+
...nodes
67+
}
68+
notEqualTo: allArrayTypes(filter: { citextArray: { notEqualTo: $v2 } }) {
69+
...nodes
70+
}
71+
overlaps: allArrayTypes(filter: { citextArray: { overlaps: $v2 } }) {
72+
...nodes
73+
}
74+
}
75+
76+
fragment nodes on ArrayTypesConnection {
77+
nodes {
78+
id
79+
}
80+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
query citext($v2: String = "Test", $v3: String = "tEST") {
2+
distinctFrom: allFilterables(filter: { citext: { distinctFrom: $v2 } }) {
3+
...nodes
4+
}
5+
endsWith: allFilterables(filter: { citext: { endsWith: "T" } }) {
6+
...nodes
7+
}
8+
endsWithInsensitive: allFilterables(
9+
filter: { citext: { endsWithInsensitive: "T" } }
10+
) {
11+
...nodes
12+
}
13+
equalTo: allFilterables(filter: { citext: { equalTo: $v2 } }) {
14+
...nodes
15+
}
16+
greaterThan: allFilterables(filter: { citext: { greaterThan: $v2 } }) {
17+
...nodes
18+
}
19+
greaterThanOrEqualTo: allFilterables(
20+
filter: { citext: { greaterThanOrEqualTo: $v2 } }
21+
) {
22+
...nodes
23+
}
24+
in: allFilterables(filter: { citext: { in: [$v2, $v3] } }) {
25+
...nodes
26+
}
27+
includes: allFilterables(filter: { citext: { includes: "T" } }) {
28+
...nodes
29+
}
30+
includesInsensitive: allFilterables(
31+
filter: { citext: { includesInsensitive: "T" } }
32+
) {
33+
...nodes
34+
}
35+
isNull: allFilterables(filter: { citext: { isNull: true } }) {
36+
...nodes
37+
}
38+
lessThan: allFilterables(filter: { citext: { lessThan: $v2 } }) {
39+
...nodes
40+
}
41+
lessThanOrEqualTo: allFilterables(
42+
filter: { citext: { lessThanOrEqualTo: $v2 } }
43+
) {
44+
...nodes
45+
}
46+
like: allFilterables(filter: { citext: { like: "%ES%" } }) {
47+
...nodes
48+
}
49+
likeInsensitive: allFilterables(
50+
filter: { citext: { likeInsensitive: "%ES%" } }
51+
) {
52+
...nodes
53+
}
54+
notDistinctFrom: allFilterables(filter: { citext: { notDistinctFrom: $v2 } }) {
55+
...nodes
56+
}
57+
notEndsWith: allFilterables(filter: { citext: { notEndsWith: "T" } }) {
58+
...nodes
59+
}
60+
notEndsWithInsensitive: allFilterables(
61+
filter: { citext: { notEndsWithInsensitive: "T" } }
62+
) {
63+
...nodes
64+
}
65+
notEqualTo: allFilterables(filter: { citext: { notEqualTo: $v2 } }) {
66+
...nodes
67+
}
68+
notIn: allFilterables(filter: { citext: { notIn: [$v2] } }) {
69+
...nodes
70+
}
71+
notIncludes: allFilterables(filter: { citext: { notIncludes: "T" } }) {
72+
...nodes
73+
}
74+
notIncludesInsensitive: allFilterables(
75+
filter: { citext: { notIncludesInsensitive: "T" } }
76+
) {
77+
...nodes
78+
}
79+
notLike: allFilterables(filter: { citext: { notLike: "%ES%" } }) {
80+
...nodes
81+
}
82+
notLikeInsensitive: allFilterables(
83+
filter: { citext: { notLikeInsensitive: "%ES%" } }
84+
) {
85+
...nodes
86+
}
87+
notSimilarTo: allFilterables(
88+
filter: { citext: { notSimilarTo: "%(TE|ST)%" } }
89+
) {
90+
...nodes
91+
}
92+
notStartsWith: allFilterables(filter: { citext: { notStartsWith: "T" } }) {
93+
...nodes
94+
}
95+
notStartsWithInsensitive: allFilterables(
96+
filter: { citext: { notStartsWithInsensitive: "T" } }
97+
) {
98+
...nodes
99+
}
100+
similarTo: allFilterables(filter: { citext: { similarTo: "%(TE|ST)%" } }) {
101+
...nodes
102+
}
103+
startsWith: allFilterables(filter: { citext: { startsWith: "T" } }) {
104+
...nodes
105+
}
106+
startsWithInsensitive: allFilterables(
107+
filter: { citext: { startsWithInsensitive: "T" } }
108+
) {
109+
...nodes
110+
}
111+
}
112+
113+
fragment nodes on FilterablesConnection {
114+
nodes {
115+
id
116+
}
117+
}

0 commit comments

Comments
 (0)