@@ -920,5 +920,232 @@ module(`realm-endpoints/${basename(__filename)}`, function () {
920920 } ) ;
921921 } ) ;
922922 } ) ;
923+
924+ module ( "'in' filter (postgres)" , function ( ) {
925+ let testRealm : Realm ;
926+ let request : SuperTest < Test > ;
927+ let realmHref : string ;
928+ let searchPath : string ;
929+
930+ function onRealmSetup ( args : {
931+ testRealm : Realm ;
932+ request : SuperTest < Test > ;
933+ } ) {
934+ testRealm = args . testRealm ;
935+ request = args . request ;
936+ let realmURL = new URL ( testRealm . url ) ;
937+ realmHref = realmURL . href ;
938+ searchPath = `${ realmURL . pathname . replace ( / \/ $ / , '' ) } /_search` ;
939+ }
940+
941+ function personType ( ) {
942+ return {
943+ module : `${ realmHref } person` ,
944+ name : 'Person' ,
945+ } ;
946+ }
947+
948+ module ( 'public readable realm' , function ( hooks ) {
949+ setupPermissionedRealmCached ( hooks , {
950+ permissions : {
951+ '*' : [ 'read' ] ,
952+ } ,
953+ realmURL : testRealmURLFor ( 'in-test/' ) ,
954+ fileSystem : {
955+ 'person.gts' : `
956+ import { contains, field, CardDef, Component } from 'https://cardstack.com/base/card-api';
957+ import StringField from 'https://cardstack.com/base/string';
958+ export class Person extends CardDef {
959+ static displayName = 'Person';
960+ @field firstName = contains(StringField);
961+ @field city = contains(StringField);
962+ @field cardTitle = contains(StringField, {
963+ computeVia: function (this: Person) {
964+ return this.firstName;
965+ },
966+ });
967+ static isolated = class Isolated extends Component<typeof this> {
968+ <template><h1><@fields.firstName /></h1></template>
969+ };
970+ }
971+ ` ,
972+ 'mango.json' : {
973+ data : {
974+ type : 'card' ,
975+ attributes : { firstName : 'Mango' , city : 'Barksville' } ,
976+ meta : {
977+ adoptsFrom : { module : './person' , name : 'Person' } ,
978+ } ,
979+ } ,
980+ } ,
981+ 'vangogh.json' : {
982+ data : {
983+ type : 'card' ,
984+ attributes : { firstName : 'Van Gogh' , city : 'Barksville' } ,
985+ meta : {
986+ adoptsFrom : { module : './person' , name : 'Person' } ,
987+ } ,
988+ } ,
989+ } ,
990+ 'ringo.json' : {
991+ data : {
992+ type : 'card' ,
993+ attributes : { firstName : 'Ringo' , city : 'Waggington' } ,
994+ meta : {
995+ adoptsFrom : { module : './person' , name : 'Person' } ,
996+ } ,
997+ } ,
998+ } ,
999+ } ,
1000+ onRealmSetup,
1001+ } ) ;
1002+
1003+ test ( `can filter using 'in' with multiple values` , async function ( assert ) {
1004+ let response = await request
1005+ . post ( searchPath )
1006+ . set ( 'Accept' , 'application/vnd.card+json' )
1007+ . set ( 'X-HTTP-Method-Override' , 'QUERY' )
1008+ . send ( {
1009+ filter : {
1010+ on : personType ( ) ,
1011+ in : { firstName : [ 'Mango' , 'Ringo' ] } ,
1012+ } ,
1013+ } ) ;
1014+
1015+ assert . strictEqual ( response . status , 200 , 'HTTP 200 status' ) ;
1016+ assert . strictEqual (
1017+ response . body . meta . page . total ,
1018+ 2 ,
1019+ 'total count is correct' ,
1020+ ) ;
1021+ let ids = response . body . data . map ( ( d : any ) => d . id ) . sort ( ) ;
1022+ assert . deepEqual (
1023+ ids ,
1024+ [ `${ realmHref } mango` , `${ realmHref } ringo` ] ,
1025+ 'correct cards returned' ,
1026+ ) ;
1027+ } ) ;
1028+
1029+ test ( `can filter using 'in' with a single value` , async function ( assert ) {
1030+ let response = await request
1031+ . post ( searchPath )
1032+ . set ( 'Accept' , 'application/vnd.card+json' )
1033+ . set ( 'X-HTTP-Method-Override' , 'QUERY' )
1034+ . send ( {
1035+ filter : {
1036+ on : personType ( ) ,
1037+ in : { firstName : [ 'Mango' ] } ,
1038+ } ,
1039+ } ) ;
1040+
1041+ assert . strictEqual ( response . status , 200 , 'HTTP 200 status' ) ;
1042+ assert . strictEqual (
1043+ response . body . meta . page . total ,
1044+ 1 ,
1045+ 'total count is correct' ,
1046+ ) ;
1047+ assert . strictEqual (
1048+ response . body . data [ 0 ] . id ,
1049+ `${ realmHref } mango` ,
1050+ 'correct card returned' ,
1051+ ) ;
1052+ } ) ;
1053+
1054+ test ( `can filter using 'in' with an empty array` , async function ( assert ) {
1055+ let response = await request
1056+ . post ( searchPath )
1057+ . set ( 'Accept' , 'application/vnd.card+json' )
1058+ . set ( 'X-HTTP-Method-Override' , 'QUERY' )
1059+ . send ( {
1060+ filter : {
1061+ on : personType ( ) ,
1062+ in : { firstName : [ ] } ,
1063+ } ,
1064+ } ) ;
1065+
1066+ assert . strictEqual ( response . status , 200 , 'HTTP 200 status' ) ;
1067+ assert . strictEqual (
1068+ response . body . meta . page . total ,
1069+ 0 ,
1070+ 'returns no results for empty array' ,
1071+ ) ;
1072+ } ) ;
1073+
1074+ test ( `can filter using 'in' with null values` , async function ( assert ) {
1075+ let response = await request
1076+ . post ( searchPath )
1077+ . set ( 'Accept' , 'application/vnd.card+json' )
1078+ . set ( 'X-HTTP-Method-Override' , 'QUERY' )
1079+ . send ( {
1080+ filter : {
1081+ on : personType ( ) ,
1082+ in : { firstName : [ 'Mango' , null ] } ,
1083+ } ,
1084+ } ) ;
1085+
1086+ assert . strictEqual ( response . status , 200 , 'HTTP 200 status' ) ;
1087+ // Mango matches 'Mango', no cards have null firstName
1088+ assert . ok (
1089+ response . body . meta . page . total >= 1 ,
1090+ 'returns at least the matching card' ,
1091+ ) ;
1092+ let ids = response . body . data . map ( ( d : any ) => d . id ) ;
1093+ assert . ok (
1094+ ids . includes ( `${ realmHref } mango` ) ,
1095+ 'Mango is in the results' ,
1096+ ) ;
1097+ } ) ;
1098+
1099+ test ( `can filter using 'in' on a different field` , async function ( assert ) {
1100+ let response = await request
1101+ . post ( searchPath )
1102+ . set ( 'Accept' , 'application/vnd.card+json' )
1103+ . set ( 'X-HTTP-Method-Override' , 'QUERY' )
1104+ . send ( {
1105+ filter : {
1106+ on : personType ( ) ,
1107+ in : { city : [ 'Waggington' ] } ,
1108+ } ,
1109+ } ) ;
1110+
1111+ assert . strictEqual ( response . status , 200 , 'HTTP 200 status' ) ;
1112+ assert . strictEqual (
1113+ response . body . meta . page . total ,
1114+ 1 ,
1115+ 'total count is correct' ,
1116+ ) ;
1117+ assert . strictEqual (
1118+ response . body . data [ 0 ] . id ,
1119+ `${ realmHref } ringo` ,
1120+ 'correct card returned' ,
1121+ ) ;
1122+ } ) ;
1123+
1124+ test ( `can negate an 'in' filter with 'not'` , async function ( assert ) {
1125+ let response = await request
1126+ . post ( searchPath )
1127+ . set ( 'Accept' , 'application/vnd.card+json' )
1128+ . set ( 'X-HTTP-Method-Override' , 'QUERY' )
1129+ . send ( {
1130+ filter : {
1131+ on : personType ( ) ,
1132+ not : { in : { firstName : [ 'Mango' , 'Ringo' ] } } ,
1133+ } ,
1134+ } ) ;
1135+
1136+ assert . strictEqual ( response . status , 200 , 'HTTP 200 status' ) ;
1137+ assert . strictEqual (
1138+ response . body . meta . page . total ,
1139+ 1 ,
1140+ 'total count is correct' ,
1141+ ) ;
1142+ assert . strictEqual (
1143+ response . body . data [ 0 ] . id ,
1144+ `${ realmHref } vangogh` ,
1145+ 'correct card returned' ,
1146+ ) ;
1147+ } ) ;
1148+ } ) ;
1149+ } ) ;
9231150 } ) ;
9241151} ) ;
0 commit comments