diff --git a/agrest-cayenne/src/test/java/io/agrest/cayenne/GET/ExpIT.java b/agrest-cayenne/src/test/java/io/agrest/cayenne/GET/ExpIT.java index 5a385452c..b855f1420 100644 --- a/agrest-cayenne/src/test/java/io/agrest/cayenne/GET/ExpIT.java +++ b/agrest-cayenne/src/test/java/io/agrest/cayenne/GET/ExpIT.java @@ -16,6 +16,7 @@ import jakarta.ws.rs.core.Configuration; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.UriInfo; + import java.time.LocalDateTime; public class ExpIT extends MainDbTest { @@ -379,6 +380,30 @@ public void like_SingleChar_Pattern_Escape() { .wasOk().bodyEquals(1, "{\"id\":4}"); } + @Test + public void exists_Path_Relationship() { + + tester.e2().insertColumns("id_", "name") + .values(1, "qwe") + .values(2, "try") + .exec(); + + tester.e3().insertColumns("id_", "name", "e2_id") + .values(1, "xxx", 1) + .values(2, "yxy", 2) + .values(3, "y_y", 2) + .values(4, "y_ay", null) + .exec(); + + tester.target("/e3") + .queryParam("include", "id") + .queryParam("exp", "exists e2") + .queryParam("sort", "id") + .get() + .wasOk() + .bodyEquals(3, "{\"id\":1}", "{\"id\":2}", "{\"id\":3}"); + } + @Test public void like_MultiChar_Pattern_Escape() { diff --git a/agrest-cayenne/src/test/java/io/agrest/cayenne/processor/CayenneQueryAssemblerTest.java b/agrest-cayenne/src/test/java/io/agrest/cayenne/processor/CayenneQueryAssemblerTest.java index 7b10f9480..65584fb23 100644 --- a/agrest-cayenne/src/test/java/io/agrest/cayenne/processor/CayenneQueryAssemblerTest.java +++ b/agrest-cayenne/src/test/java/io/agrest/cayenne/processor/CayenneQueryAssemblerTest.java @@ -15,6 +15,7 @@ import io.agrest.runtime.processor.select.SelectContext; import org.apache.cayenne.di.Injector; import org.apache.cayenne.exp.Expression; +import org.apache.cayenne.exp.ExpressionException; import org.apache.cayenne.exp.ExpressionFactory; import org.apache.cayenne.query.ObjectSelect; import org.junit.jupiter.api.Test; @@ -129,6 +130,23 @@ public void createRootQuery_Qualifier_Exists() { assertEquals(expectedQ1.andExp(ExpressionFactory.notExists(ObjectSelect.query(E3.class).column(E3.E5))), q2.getWhere()); } + @Test + public void createRootQuery_Qualifier_Exists_Invalid_Condition() { + RootResourceEntity entity = getResourceEntity(E3.class); + + SelectContext c = new SelectContext<>( + E3.class, + new RequestSchema(mock(AgSchema.class)), + mock(AgRequestBuilder.class), + PathChecker.ofDefault(), + mock(Injector.class)); + + c.setEntity(entity); + + entity.andExp(Exp.exists("name = 'test1'")); + assertThrows(ExpressionException.class, () -> queryAssembler.createRootQuery(c)); + } + @Test public void createRootQuery_ById() { diff --git a/agrest-engine/src/test/java/io/agrest/exp/parser/ExpExistsTest.java b/agrest-engine/src/test/java/io/agrest/exp/parser/ExpExistsTest.java index d88120f0d..bc453023a 100644 --- a/agrest-engine/src/test/java/io/agrest/exp/parser/ExpExistsTest.java +++ b/agrest-engine/src/test/java/io/agrest/exp/parser/ExpExistsTest.java @@ -28,7 +28,7 @@ public void parsedToString(String expString, String expected) { } @ParameterizedTest - @ValueSource(strings = {"exists", "exists()"}) + @ValueSource(strings = {"exists", "exists()", "exists (name == 'test')"}) public void parseInvalidGrammar(String expString) { assertThrows(AgException.class, () -> Exp.parse(expString)); } diff --git a/agrest-engine/src/test/java/io/agrest/exp/parser/ExpNotExistsTest.java b/agrest-engine/src/test/java/io/agrest/exp/parser/ExpNotExistsTest.java index 86e26c117..77eedc56d 100644 --- a/agrest-engine/src/test/java/io/agrest/exp/parser/ExpNotExistsTest.java +++ b/agrest-engine/src/test/java/io/agrest/exp/parser/ExpNotExistsTest.java @@ -31,7 +31,7 @@ public void parsedToString(String expString, String expected) { } @ParameterizedTest - @ValueSource(strings = {"not exists", "not exists()"}) + @ValueSource(strings = {"not exists", "not exists()", "not exists (name == 'test')"}) public void parseInvalidGrammar(String expString) { assertThrows(AgException.class, () -> Exp.parse(expString)); }