@@ -378,3 +378,182 @@ spec = describe "related queries" $ do
378
378
, matchHeaders = [ matchContentTypeJson
379
379
, " Content-Range" <:> " 0-1/952" ]
380
380
}
381
+
382
+ context " related conditions using the embed(column) syntax" $ do
383
+ it " works on a many-to-one relationship" $ do
384
+ get " /projects?select=name,clients()&clients(name)=eq.Microsoft" `shouldRespondWith`
385
+ [json |[
386
+ {"name":"Windows 7"},
387
+ {"name":"Windows 10"}
388
+ ]|]
389
+ { matchStatus = 200
390
+ , matchHeaders = [matchContentTypeJson]
391
+ }
392
+ get " /projects?select=name,computed_clients()&computed_clients(name)=eq.Apple" `shouldRespondWith`
393
+ [json |[
394
+ {"name":"IOS"},
395
+ {"name":"OSX"}
396
+ ]|]
397
+ { matchStatus = 200
398
+ , matchHeaders = [matchContentTypeJson]
399
+ }
400
+
401
+ it " works on a one-to-many relationship" $ do
402
+ get " /entities?select=name,child_entities()&child_entities(name)=like.child*" `shouldRespondWith`
403
+ [json |[
404
+ {"name":"entity 1"},
405
+ {"name":"entity 2"}
406
+ ]|]
407
+ { matchStatus = 200
408
+ , matchHeaders = [matchContentTypeJson]
409
+ }
410
+ get " /entities?select=name,child_entities()&child_entities(name)=like(any).{*1,*2}" `shouldRespondWith`
411
+ [json |[
412
+ {"name":"entity 1"}
413
+ ]|]
414
+ { matchStatus = 200
415
+ , matchHeaders = [matchContentTypeJson]
416
+ }
417
+
418
+ it " works on a many-to-many relationship" $ do
419
+ get " /users?select=name,tasks()&tasks(id)=eq.1" `shouldRespondWith`
420
+ [json |[
421
+ {"name":"Angela Martin"},
422
+ {"name":"Dwight Schrute"}
423
+ ]|]
424
+ { matchStatus = 200
425
+ , matchHeaders = [matchContentTypeJson]
426
+ }
427
+ get " /users?select=name,tasks()&tasks(id)=eq.7" `shouldRespondWith`
428
+ [json |[
429
+ {"name":"Michael Scott"}
430
+ ]|]
431
+ { matchStatus = 200
432
+ , matchHeaders = [matchContentTypeJson]
433
+ }
434
+ {- - TODO(draft): make nesting work
435
+ it "works on nested embeds" $ do
436
+ get "/entities?select=name,child_entities(name,grandchild_entities())&child_entities(grandchild_entities(name))=like.*1" `shouldRespondWith`
437
+ [json|[
438
+ {"name":"entity 1","child_entities":[{"name":"child entity 1"}, {"name":"child entity 2"}]}]|]
439
+ { matchStatus = 200
440
+ , matchHeaders = [matchContentTypeJson]
441
+ }
442
+ --}
443
+ it " can do an or across embeds" $
444
+ get " /client?select=*,clientinfo(),contact()&or=(clientinfo(other).like.*Main*,contact(name).like.*Tabby*)" `shouldRespondWith`
445
+ [json |[
446
+ {"id":1,"name":"Walmart"},
447
+ {"id":2,"name":"Target"}
448
+ ]|]
449
+ { matchStatus = 200
450
+ , matchHeaders = [matchContentTypeJson]
451
+ }
452
+
453
+ it " works when the embedding uses the column name" $ do
454
+ get " /projects?select=name,c_id:client_id,client_id(name)&client_id(name)=like.Apple" `shouldRespondWith`
455
+ [json |[
456
+ {"name":"IOS","c_id":2,"client_id":{"name":"Apple"}},
457
+ {"name":"OSX","c_id":2,"client_id":{"name":"Apple"}}
458
+ ]|]
459
+ { matchStatus = 200
460
+ , matchHeaders = [matchContentTypeJson]
461
+ }
462
+ get " /projects?select=name,client_id(name)&client_id(name)=like.Apple" `shouldRespondWith`
463
+ [json |[
464
+ {"name":"IOS","client_id":{"name":"Apple"}},
465
+ {"name":"OSX","client_id":{"name":"Apple"}}
466
+ ]|]
467
+ { matchStatus = 200
468
+ , matchHeaders = [matchContentTypeJson]
469
+ }
470
+
471
+ -- "?table=not.is.null" does a "table IS DISTINCT FROM NULL" instead of a "table IS NOT NULL"
472
+ -- https://github.com/PostgREST/postgrest/issues/2800#issuecomment-1720315818
473
+ it " embeds verifying that the entire target table row is not null" $ do
474
+ get " /table_b?select=name,table_a(name)&table_a(id)=eq(any).{1,2}" `shouldRespondWith`
475
+ [json |[
476
+ {"name":"Test 1","table_a":{"name":"Not null 1"}},
477
+ {"name":"Test 2","table_a":{"name":null}}
478
+ ]|]
479
+ { matchStatus = 200
480
+ , matchHeaders = [matchContentTypeJson]
481
+ }
482
+
483
+ it " works with count=exact" $ do
484
+ request methodGet " /projects?select=name,clients(name)&clients(id)=gt.0"
485
+ [(" Prefer" , " count=exact" )] " "
486
+ `shouldRespondWith`
487
+ [json |[
488
+ {"name":"Windows 7", "clients":{"name":"Microsoft"}},
489
+ {"name":"Windows 10", "clients":{"name":"Microsoft"}},
490
+ {"name":"IOS", "clients":{"name":"Apple"}},
491
+ {"name":"OSX", "clients":{"name":"Apple"}}
492
+ ]|]
493
+ { matchStatus = 200
494
+ , matchHeaders = [ matchContentTypeJson
495
+ , " Content-Range" <:> " 0-3/4" ]
496
+ }
497
+ request methodGet " /client?select=*,clientinfo(),contact()&or=(clientinfo(other).ilike.*main*,contact(name).ilike.*tabby*)"
498
+ [(" Prefer" , " count=exact" )] " "
499
+ `shouldRespondWith`
500
+ [json |[
501
+ {"id":1,"name":"Walmart"},
502
+ {"id":2,"name":"Target"}
503
+ ]|]
504
+ { matchStatus = 200
505
+ , matchHeaders = [ matchContentTypeJson
506
+ , " Content-Range" <:> " 0-1/2" ]
507
+ }
508
+
509
+ it " works with count=planned" $ do
510
+ request methodGet " /projects?select=name,clients(name)&clients(id)=gt.0"
511
+ [(" Prefer" , " count=planned" )] " "
512
+ `shouldRespondWith`
513
+ [json |[
514
+ {"name":"Windows 7", "clients":{"name":"Microsoft"}},
515
+ {"name":"Windows 10", "clients":{"name":"Microsoft"}},
516
+ {"name":"IOS", "clients":{"name":"Apple"}},
517
+ {"name":"OSX", "clients":{"name":"Apple"}}
518
+ ]|]
519
+ { matchStatus = 206
520
+ , matchHeaders = [ matchContentTypeJson
521
+ , " Content-Range" <:> " 0-3/400" ]
522
+ }
523
+ request methodGet " /client?select=*,clientinfo(),contact()&or=(clientinfo(other).ilike.*main*,contact(name).ilike.*tabby*)"
524
+ [(" Prefer" , " count=planned" )] " "
525
+ `shouldRespondWith`
526
+ [json |[
527
+ {"id":1,"name":"Walmart"},
528
+ {"id":2,"name":"Target"}
529
+ ]|]
530
+ { matchStatus = 206
531
+ , matchHeaders = [ matchContentTypeJson
532
+ , " Content-Range" <:> " 0-1/952" ]
533
+ }
534
+
535
+ it " works with count=estimated" $ do
536
+ request methodGet " /projects?select=name,clients(name)&clients(id)=gt.0"
537
+ [(" Prefer" , " count=estimated" )] " "
538
+ `shouldRespondWith`
539
+ [json |[
540
+ {"name":"Windows 7", "clients":{"name":"Microsoft"}},
541
+ {"name":"Windows 10", "clients":{"name":"Microsoft"}},
542
+ {"name":"IOS", "clients":{"name":"Apple"}},
543
+ {"name":"OSX", "clients":{"name":"Apple"}}
544
+ ]|]
545
+ { matchStatus = 206
546
+ , matchHeaders = [ matchContentTypeJson
547
+ , " Content-Range" <:> " 0-3/400" ]
548
+ }
549
+ request methodGet " /client?select=*,clientinfo(),contact()&or=(clientinfo(other).ilike.*main*,contact(name).ilike.*tabby*)"
550
+ [(" Prefer" , " count=estimated" )] " "
551
+ `shouldRespondWith`
552
+ [json |[
553
+ {"id":1,"name":"Walmart"},
554
+ {"id":2,"name":"Target"}
555
+ ]|]
556
+ { matchStatus = 206
557
+ , matchHeaders = [ matchContentTypeJson
558
+ , " Content-Range" <:> " 0-1/952" ]
559
+ }
0 commit comments