Skip to content

Commit 84ae4aa

Browse files
committed
Add more tests for aggregate
1 parent 3c02ab0 commit 84ae4aa

File tree

2 files changed

+530
-31
lines changed

2 files changed

+530
-31
lines changed

test/expected/aggregate.out

Lines changed: 287 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,25 @@ begin;
2424
-- 5 Accounts
2525
insert into public.account(email, created_at)
2626
values
27-
('[email protected]', now()),
28-
('[email protected]', now()),
29-
('[email protected]', now()),
30-
('[email protected]', now()),
31-
('[email protected]', now());
27+
('[email protected]', NOW() - INTERVAL '5 days'),
28+
('[email protected]', NOW() - INTERVAL '4 days'),
29+
('[email protected]', NOW() - INTERVAL '3 days'),
30+
('[email protected]', NOW() - INTERVAL '2 days'),
31+
('[email protected]', NOW() - INTERVAL '1 day');
3232
insert into blog(owner_id, name, description, created_at)
3333
values
34-
((select id from account where email ilike 'a%'), 'A: Blog 1', 'a desc1', now()),
35-
((select id from account where email ilike 'a%'), 'A: Blog 2', 'a desc2', now()),
36-
((select id from account where email ilike 'a%'), 'A: Blog 3', 'a desc3', now()),
37-
((select id from account where email ilike 'b%'), 'B: Blog 3', 'b desc1', now());
34+
((select id from account where email ilike 'a%'), 'A: Blog 1', 'a desc1', NOW() - INTERVAL '10 days'),
35+
((select id from account where email ilike 'a%'), 'A: Blog 2', 'a desc2', NOW() - INTERVAL '9 days'),
36+
((select id from account where email ilike 'a%'), 'A: Blog 3', 'a desc3', NOW() - INTERVAL '8 days'),
37+
((select id from account where email ilike 'b%'), 'B: Blog 3', 'b desc1', NOW() - INTERVAL '7 days');
3838
insert into blog_post (blog_id, title, body, tags, status, created_at)
3939
values
40-
((SELECT id FROM blog WHERE name = 'A: Blog 1'), 'Post 1 in A Blog 1', 'Content for post 1 in A Blog 1', '{"tech", "update"}', 'RELEASED', NOW()),
41-
((SELECT id FROM blog WHERE name = 'A: Blog 1'), 'Post 2 in A Blog 1', 'Content for post 2 in A Blog 1', '{"announcement", "tech"}', 'PENDING', NOW()),
42-
((SELECT id FROM blog WHERE name = 'A: Blog 2'), 'Post 1 in A Blog 2', 'Content for post 1 in A Blog 2', '{"personal"}', 'RELEASED', NOW()),
43-
((SELECT id FROM blog WHERE name = 'A: Blog 2'), 'Post 2 in A Blog 2', 'Content for post 2 in A Blog 2', '{"update"}', 'RELEASED', NOW()),
44-
((SELECT id FROM blog WHERE name = 'A: Blog 3'), 'Post 1 in A Blog 3', 'Content for post 1 in A Blog 3', '{"travel", "adventure"}', 'PENDING', NOW()),
45-
((SELECT id FROM blog WHERE name = 'B: Blog 3'), 'Post 1 in B Blog 3', 'Content for post 1 in B Blog 3', '{"tech", "review"}', 'RELEASED', NOW()),
40+
((SELECT id FROM blog WHERE name = 'A: Blog 1'), 'Post 1 in A Blog 1', 'Content for post 1 in A Blog 1', '{"tech", "update"}', 'RELEASED', NOW() - INTERVAL '30 days'),
41+
((SELECT id FROM blog WHERE name = 'A: Blog 1'), 'Post 2 in A Blog 1', 'Content for post 2 in A Blog 1', '{"announcement", "tech"}', 'PENDING', NOW() - INTERVAL '25 days'),
42+
((SELECT id FROM blog WHERE name = 'A: Blog 2'), 'Post 1 in A Blog 2', 'Content for post 1 in A Blog 2', '{"personal"}', 'RELEASED', NOW() - INTERVAL '20 days'),
43+
((SELECT id FROM blog WHERE name = 'A: Blog 2'), 'Post 2 in A Blog 2', 'Content for post 2 in A Blog 2', '{"update"}', 'RELEASED', NOW() - INTERVAL '15 days'),
44+
((SELECT id FROM blog WHERE name = 'A: Blog 3'), 'Post 1 in A Blog 3', 'Content for post 1 in A Blog 3', '{"travel", "adventure"}', 'PENDING', NOW() - INTERVAL '10 days'),
45+
((SELECT id FROM blog WHERE name = 'B: Blog 3'), 'Post 1 in B Blog 3', 'Content for post 1 in B Blog 3', '{"tech", "review"}', 'RELEASED', NOW() - INTERVAL '5 days'),
4646
((SELECT id FROM blog WHERE name = 'B: Blog 3'), 'Post 2 in B Blog 3', 'Content for post 2 in B Blog 3', '{"coding", "tutorial"}', 'PENDING', NOW());
4747
comment on table blog_post is e'@graphql({"totalCount": {"enabled": true}})';
4848
-- Test Case 1: Basic Count on accountCollection
@@ -220,9 +220,280 @@ begin;
220220
}
221221
}
222222
}
223-
$$);
223+
$$);
224+
resolve
225+
---------------------------------------------------------------
226+
{"data": {"blogPostCollection": {"aggregate": {"count": 7}}}}
227+
(1 row)
228+
229+
-- Test Case 10: Min/Max on non-numeric fields (string, datetime)
230+
select graphql.resolve($$
231+
query {
232+
blogCollection {
233+
aggregate {
234+
min {
235+
name
236+
description
237+
createdAt
238+
}
239+
max {
240+
name
241+
description
242+
createdAt
243+
}
244+
}
245+
}
246+
}
247+
$$);
248+
resolve
249+
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
250+
{"data": {"blogCollection": {"aggregate": {"max": {"name": "B: Blog 3", "createdAt": "2025-04-25T22:04:39.666373", "description": "b desc1"}, "min": {"name": "A: Blog 1", "createdAt": "2025-04-22T22:04:39.666373", "description": "a desc1"}}}}}
251+
(1 row)
252+
253+
-- Test Case 11: Aggregation with relationships (nested queries)
254+
select graphql.resolve($$
255+
query {
256+
accountCollection {
257+
edges {
258+
node {
259+
email
260+
blogCollection {
261+
aggregate {
262+
count
263+
sum {
264+
id
265+
}
266+
}
267+
}
268+
}
269+
}
270+
}
271+
}
272+
$$);
273+
resolve
274+
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
275+
{"data": {"accountCollection": {"edges": [{"node": {"email": "[email protected]", "blogCollection": {"aggregate": {"sum": {"id": 6}, "count": 3}}}}, {"node": {"email": "[email protected]", "blogCollection": {"aggregate": {"sum": {"id": 4}, "count": 1}}}}, {"node": {"email": "[email protected]", "blogCollection": {"aggregate": {"sum": {"id": null}, "count": 0}}}}, {"node": {"email": "[email protected]", "blogCollection": {"aggregate": {"sum": {"id": null}, "count": 0}}}}, {"node": {"email": "[email protected]", "blogCollection": {"aggregate": {"sum": {"id": null}, "count": 0}}}}]}}}
276+
(1 row)
277+
278+
-- Test Case 12: Combination of aggregates in a complex query
279+
select graphql.resolve($$
280+
query {
281+
blogCollection {
282+
edges {
283+
node {
284+
name
285+
blogPostCollection {
286+
aggregate {
287+
count
288+
min {
289+
createdAt
290+
}
291+
max {
292+
createdAt
293+
}
294+
}
295+
}
296+
}
297+
}
298+
aggregate {
299+
count
300+
min {
301+
id
302+
createdAt
303+
}
304+
max {
305+
id
306+
createdAt
307+
}
308+
sum {
309+
id
310+
}
311+
avg {
312+
id
313+
}
314+
}
315+
}
316+
}
317+
$$);
318+
resolve
319+
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
320+
{"data": {"blogCollection": {"edges": [{"node": {"name": "A: Blog 1", "blogPostCollection": {"aggregate": {"max": {"createdAt": "2025-04-07T22:04:39.666373"}, "min": {"createdAt": "2025-04-02T22:04:39.666373"}, "count": 2}}}}, {"node": {"name": "A: Blog 2", "blogPostCollection": {"aggregate": {"max": {"createdAt": "2025-04-17T22:04:39.666373"}, "min": {"createdAt": "2025-04-12T22:04:39.666373"}, "count": 2}}}}, {"node": {"name": "A: Blog 3", "blogPostCollection": {"aggregate": {"max": {"createdAt": "2025-04-22T22:04:39.666373"}, "min": {"createdAt": "2025-04-22T22:04:39.666373"}, "count": 1}}}}, {"node": {"name": "B: Blog 3", "blogPostCollection": {"aggregate": {"max": {"createdAt": "2025-05-02T22:04:39.666373"}, "min": {"createdAt": "2025-04-27T22:04:39.666373"}, "count": 2}}}}], "aggregate": {"avg": {"id": 2.5}, "max": {"id": 4, "createdAt": "2025-04-25T22:04:39.666373"}, "min": {"id": 1, "createdAt": "2025-04-22T22:04:39.666373"}, "sum": {"id": 10}, "count": 4}}}}
321+
(1 row)
322+
323+
-- Test Case 13: Complex filters with aggregates using AND/OR/NOT
324+
select graphql.resolve($$
325+
query {
326+
blogPostCollection(
327+
filter: {
328+
or: [
329+
{status: {eq: RELEASED}},
330+
{title: {startsWith: "Post"}}
331+
]
332+
}
333+
) {
334+
aggregate {
335+
count
336+
}
337+
}
338+
}
339+
$$);
224340
resolve
225341
---------------------------------------------------------------
226342
{"data": {"blogPostCollection": {"aggregate": {"count": 7}}}}
227343
(1 row)
228344

345+
select graphql.resolve($$
346+
query {
347+
blogPostCollection(
348+
filter: {
349+
and: [
350+
{status: {eq: PENDING}},
351+
{not: {blogId: {eq: 4}}}
352+
]
353+
}
354+
) {
355+
aggregate {
356+
count
357+
}
358+
}
359+
}
360+
$$);
361+
resolve
362+
---------------------------------------------------------------
363+
{"data": {"blogPostCollection": {"aggregate": {"count": 2}}}}
364+
(1 row)
365+
366+
-- Test Case 14: Array field aggregation (on tags array)
367+
select graphql.resolve($$
368+
query {
369+
blogPostCollection(
370+
filter: {
371+
tags: {contains: "tech"}
372+
}
373+
) {
374+
aggregate {
375+
count
376+
}
377+
}
378+
}
379+
$$);
380+
resolve
381+
---------------------------------------------------------------
382+
{"data": {"blogPostCollection": {"aggregate": {"count": 3}}}}
383+
(1 row)
384+
385+
-- Test Case 15: UUID field aggregation
386+
-- This test verifies that UUID fields are intentionally excluded from min/max aggregation.
387+
-- UUIDs don't have a meaningful natural ordering for aggregation purposes, so they're explicitly
388+
-- excluded from the list of types that can be aggregated with min/max.
389+
select graphql.resolve($$
390+
query {
391+
blogPostCollection {
392+
aggregate {
393+
min {
394+
id
395+
}
396+
max {
397+
id
398+
}
399+
}
400+
}
401+
}
402+
$$);
403+
resolve
404+
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
405+
{"data": null, "errors": [{"message": "UUID fields (like \"id\") are not supported for min/max aggregation because they don't have a meaningful natural ordering"}]}
406+
(1 row)
407+
408+
-- Test Case 16: Edge case - Empty result set with aggregates
409+
select graphql.resolve($$
410+
query {
411+
blogPostCollection(
412+
filter: {
413+
title: {eq: "This title does not exist"}
414+
}
415+
) {
416+
aggregate {
417+
count
418+
min {
419+
createdAt
420+
}
421+
max {
422+
createdAt
423+
}
424+
}
425+
}
426+
}
427+
$$);
428+
resolve
429+
-----------------------------------------------------------------------------------------------------------------------
430+
{"data": {"blogPostCollection": {"aggregate": {"max": {"createdAt": null}, "min": {"createdAt": null}, "count": 0}}}}
431+
(1 row)
432+
433+
-- Test Case 17: Filtering on aggregate results (verify all posts with RELEASED status)
434+
select graphql.resolve($$
435+
query {
436+
blogPostCollection(
437+
filter: {status: {eq: RELEASED}}
438+
) {
439+
aggregate {
440+
count
441+
}
442+
}
443+
}
444+
$$);
445+
resolve
446+
---------------------------------------------------------------
447+
{"data": {"blogPostCollection": {"aggregate": {"count": 4}}}}
448+
(1 row)
449+
450+
-- Test Case 18: Aggregates on filtered relationships
451+
select graphql.resolve($$
452+
query {
453+
blogCollection {
454+
edges {
455+
node {
456+
name
457+
blogPostCollection(
458+
filter: {status: {eq: RELEASED}}
459+
) {
460+
aggregate {
461+
count
462+
}
463+
}
464+
}
465+
}
466+
}
467+
}
468+
$$);
469+
resolve
470+
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
471+
{"data": {"blogCollection": {"edges": [{"node": {"name": "A: Blog 1", "blogPostCollection": {"aggregate": {"count": 1}}}}, {"node": {"name": "A: Blog 2", "blogPostCollection": {"aggregate": {"count": 2}}}}, {"node": {"name": "A: Blog 3", "blogPostCollection": {"aggregate": {"count": 0}}}}, {"node": {"name": "B: Blog 3", "blogPostCollection": {"aggregate": {"count": 1}}}}]}}}
472+
(1 row)
473+
474+
-- Test Case 19: Check aggregates work with pagination (should ignore pagination for aggregates)
475+
select graphql.resolve($$
476+
query {
477+
blogPostCollection(first: 2, offset: 1) {
478+
edges {
479+
node {
480+
title
481+
}
482+
}
483+
aggregate {
484+
count
485+
min {
486+
createdAt
487+
}
488+
max {
489+
createdAt
490+
}
491+
}
492+
}
493+
}
494+
$$);
495+
resolve
496+
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
497+
{"data": {"blogPostCollection": {"edges": [{"node": {"title": "Post 2 in A Blog 1"}}, {"node": {"title": "Post 1 in A Blog 3"}}], "aggregate": {"max": {"createdAt": "2025-05-02T22:04:39.666373"}, "min": {"createdAt": "2025-04-02T22:04:39.666373"}, "count": 7}}}}
498+
(1 row)
499+

0 commit comments

Comments
 (0)