Skip to content

Commit 5728b97

Browse files
breken-aiclaude
andcommitted
fix: ignore and/or filters whose entries are all empty
`filter: {or: [{}]}` (or `and`, or an entry whose only operator comes from an omitted variable) dropped each empty entry but still pushed the compound filter, which transpiled to `()` and failed with a SQL syntax error. Skip the compound filter when no entries remain, the same way an empty list is already ignored. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent f46687d commit 5728b97

3 files changed

Lines changed: 297 additions & 0 deletions

File tree

‎src/builder.rs‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,12 @@ fn create_filters(
12431243
}
12441244
}
12451245

1246+
// Every entry was empty, so the whole `and`/`or` is ignored like an empty list.
1247+
// Pushing it would transpile to `()`, which is invalid SQL
1248+
if compound_filters.is_empty() {
1249+
continue;
1250+
}
1251+
12461252
let filter_builder = if k == AND_FILTER_NAME {
12471253
FilterBuilderElem::Compound(Box::new(CompoundFilterBuilder::And(
12481254
compound_filters,
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
begin;
2+
create table account(
3+
id serial primary key,
4+
email varchar(255) not null
5+
);
6+
insert into public.account(email)
7+
values
8+
('aardvark@x.com'),
9+
('bat@x.com'),
10+
('cat@x.com');
11+
-- `or` with only an empty entry is ignored
12+
select jsonb_pretty(
13+
graphql.resolve($$
14+
{
15+
accountCollection(filter: {or: [{}]}) {
16+
edges { node { id } }
17+
}
18+
}
19+
$$)
20+
);
21+
jsonb_pretty
22+
---------------------------------
23+
{ +
24+
"data": { +
25+
"accountCollection": { +
26+
"edges": [ +
27+
{ +
28+
"node": { +
29+
"id": 1+
30+
} +
31+
}, +
32+
{ +
33+
"node": { +
34+
"id": 2+
35+
} +
36+
}, +
37+
{ +
38+
"node": { +
39+
"id": 3+
40+
} +
41+
} +
42+
] +
43+
} +
44+
} +
45+
}
46+
(1 row)
47+
48+
-- `and` with only an empty entry is ignored
49+
select jsonb_pretty(
50+
graphql.resolve($$
51+
{
52+
accountCollection(filter: {and: [{}]}) {
53+
edges { node { id } }
54+
}
55+
}
56+
$$)
57+
);
58+
jsonb_pretty
59+
---------------------------------
60+
{ +
61+
"data": { +
62+
"accountCollection": { +
63+
"edges": [ +
64+
{ +
65+
"node": { +
66+
"id": 1+
67+
} +
68+
}, +
69+
{ +
70+
"node": { +
71+
"id": 2+
72+
} +
73+
}, +
74+
{ +
75+
"node": { +
76+
"id": 3+
77+
} +
78+
} +
79+
] +
80+
} +
81+
} +
82+
}
83+
(1 row)
84+
85+
-- an `or` entry whose only operator comes from an omitted variable is ignored
86+
select jsonb_pretty(
87+
graphql.resolve($$
88+
query AccountsByEmail($email: String) {
89+
accountCollection(filter: {or: [{email: {eq: $email}}]}) {
90+
edges { node { id } }
91+
}
92+
}
93+
$$,
94+
variables := '{}'
95+
)
96+
);
97+
jsonb_pretty
98+
---------------------------------
99+
{ +
100+
"data": { +
101+
"accountCollection": { +
102+
"edges": [ +
103+
{ +
104+
"node": { +
105+
"id": 1+
106+
} +
107+
}, +
108+
{ +
109+
"node": { +
110+
"id": 2+
111+
} +
112+
}, +
113+
{ +
114+
"node": { +
115+
"id": 3+
116+
} +
117+
} +
118+
] +
119+
} +
120+
} +
121+
}
122+
(1 row)
123+
124+
-- empty entries next to a real one still leave the real one in place
125+
select jsonb_pretty(
126+
graphql.resolve($$
127+
{
128+
accountCollection(filter: {or: [{}, {id: {eq: 2}}]}) {
129+
edges { node { id } }
130+
}
131+
}
132+
$$)
133+
);
134+
jsonb_pretty
135+
---------------------------------
136+
{ +
137+
"data": { +
138+
"accountCollection": { +
139+
"edges": [ +
140+
{ +
141+
"node": { +
142+
"id": 2+
143+
} +
144+
} +
145+
] +
146+
} +
147+
} +
148+
}
149+
(1 row)
150+
151+
-- nested: `not` around an `or` of empty entries is ignored
152+
select jsonb_pretty(
153+
graphql.resolve($$
154+
{
155+
accountCollection(filter: {not: {or: [{}]}}) {
156+
edges { node { id } }
157+
}
158+
}
159+
$$)
160+
);
161+
jsonb_pretty
162+
---------------------------------
163+
{ +
164+
"data": { +
165+
"accountCollection": { +
166+
"edges": [ +
167+
{ +
168+
"node": { +
169+
"id": 1+
170+
} +
171+
}, +
172+
{ +
173+
"node": { +
174+
"id": 2+
175+
} +
176+
}, +
177+
{ +
178+
"node": { +
179+
"id": 3+
180+
} +
181+
} +
182+
] +
183+
} +
184+
} +
185+
}
186+
(1 row)
187+
188+
-- same on a mutation filter: nothing is filtered out, so every row is updated
189+
select jsonb_pretty(
190+
graphql.resolve($$
191+
mutation {
192+
updateAccountCollection(set: {email: "x@x.com"}, filter: {or: [{}]}, atMost: 10) {
193+
affectedCount
194+
}
195+
}
196+
$$)
197+
);
198+
jsonb_pretty
199+
--------------------------------------
200+
{ +
201+
"data": { +
202+
"updateAccountCollection": {+
203+
"affectedCount": 3 +
204+
} +
205+
} +
206+
}
207+
(1 row)
208+
209+
rollback;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
begin;
2+
3+
create table account(
4+
id serial primary key,
5+
email varchar(255) not null
6+
);
7+
8+
insert into public.account(email)
9+
values
10+
('aardvark@x.com'),
11+
('bat@x.com'),
12+
('cat@x.com');
13+
14+
-- `or` with only an empty entry is ignored
15+
select jsonb_pretty(
16+
graphql.resolve($$
17+
{
18+
accountCollection(filter: {or: [{}]}) {
19+
edges { node { id } }
20+
}
21+
}
22+
$$)
23+
);
24+
25+
-- `and` with only an empty entry is ignored
26+
select jsonb_pretty(
27+
graphql.resolve($$
28+
{
29+
accountCollection(filter: {and: [{}]}) {
30+
edges { node { id } }
31+
}
32+
}
33+
$$)
34+
);
35+
36+
-- an `or` entry whose only operator comes from an omitted variable is ignored
37+
select jsonb_pretty(
38+
graphql.resolve($$
39+
query AccountsByEmail($email: String) {
40+
accountCollection(filter: {or: [{email: {eq: $email}}]}) {
41+
edges { node { id } }
42+
}
43+
}
44+
$$,
45+
variables := '{}'
46+
)
47+
);
48+
49+
-- empty entries next to a real one still leave the real one in place
50+
select jsonb_pretty(
51+
graphql.resolve($$
52+
{
53+
accountCollection(filter: {or: [{}, {id: {eq: 2}}]}) {
54+
edges { node { id } }
55+
}
56+
}
57+
$$)
58+
);
59+
60+
-- nested: `not` around an `or` of empty entries is ignored
61+
select jsonb_pretty(
62+
graphql.resolve($$
63+
{
64+
accountCollection(filter: {not: {or: [{}]}}) {
65+
edges { node { id } }
66+
}
67+
}
68+
$$)
69+
);
70+
71+
-- same on a mutation filter: nothing is filtered out, so every row is updated
72+
select jsonb_pretty(
73+
graphql.resolve($$
74+
mutation {
75+
updateAccountCollection(set: {email: "x@x.com"}, filter: {or: [{}]}, atMost: 10) {
76+
affectedCount
77+
}
78+
}
79+
$$)
80+
);
81+
82+
rollback;

0 commit comments

Comments
 (0)