Skip to content

Commit

Permalink
GET with includes can't match children to parent when parent has a c…
Browse files Browse the repository at this point in the history
…ompound key #684
  • Loading branch information
andrus committed Jul 9, 2024
1 parent c1580e0 commit c18df59
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;

public class GET_IncludeIT extends DbTest {

Expand Down
32 changes: 30 additions & 2 deletions agrest-cayenne/src/test/java/io/agrest/cayenne/GET_Related_IT.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
import io.agrest.cayenne.cayenne.main.E18;
import io.agrest.cayenne.cayenne.main.E2;
import io.agrest.cayenne.cayenne.main.E3;
import io.agrest.cayenne.cayenne.main.E32;
import io.agrest.cayenne.cayenne.main.E33;
import io.agrest.cayenne.unit.AgCayenneTester;
import io.agrest.cayenne.unit.DbTest;
import io.bootique.junit5.BQTestTool;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import javax.ws.rs.GET;
Expand All @@ -28,8 +31,7 @@ public class GET_Related_IT extends DbTest {

@BQTestTool
static final AgCayenneTester tester = tester(Resource.class)
.entities(E2.class, E3.class, E17.class, E18.class)
.entitiesAndDependencies(E12.class, E13.class)
.entitiesAndDependencies(E2.class, E3.class, E17.class, E18.class, E12.class, E13.class, E32.class, E33.class)
.build();

@Test
Expand Down Expand Up @@ -134,6 +136,26 @@ public void testToManyJoin() {
.bodyEquals(1, "{\"id\":{\"e12_id\":12,\"e13_id\":16},\"e12\":{\"id\":12},\"e13\":{\"id\":16}}");
}

@Test
@Disabled("This is a problem in 4.x, that was fixed in 5.x")
public void testCompoundRootKey() {

tester.e33().insertColumns("p_id", "name")
.values(11, "n33_1")
.values(12, "n33_2").exec();

tester.e32().insertColumns("p_id", "s_id", "t_id", "name")
.values(11, 101, 1001, "n32_1")
.values(12, 102, 1002, "n32_2").exec();

tester.target("/e32")
.queryParam("include", "e33")
.get()
.wasOk()
.bodyEquals(2, "{\"id\":{\"p_id\":11,\"s_id\":101,\"t_id\":1001},\"e33\":{},\"name\":\"n32_1\"}," +
"{\"id\":{\"p_id\":12,\"s_id\":102,\"t_id\":1002},\"e33\":{},\"name\":\"n32_2\"}");
}

@Path("")
public static class Resource {

Expand Down Expand Up @@ -183,5 +205,11 @@ public DataResponse<E18> getChildren(

return Ag.select(E18.class, config).parent(E17.class, parentIds, E17.E18S.getName()).uri(uriInfo).get();
}

@GET
@Path("e32")
public DataResponse<E32> getE32(@Context UriInfo uriInfo) {
return Ag.select(E32.class, config).uri(uriInfo).get();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.agrest.cayenne.cayenne.main;

import io.agrest.cayenne.cayenne.main.auto._E32;

public class E32 extends _E32 {

private static final long serialVersionUID = 1L;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.agrest.cayenne.cayenne.main;

import io.agrest.cayenne.cayenne.main.auto._E33;

public class E33 extends _E33 {

private static final long serialVersionUID = 1L;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package io.agrest.cayenne.cayenne.main.auto;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.property.EntityProperty;
import org.apache.cayenne.exp.property.PropertyFactory;
import org.apache.cayenne.exp.property.StringProperty;

import io.agrest.cayenne.cayenne.main.E33;

/**
* Class _E32 was generated by Cayenne.
* It is probably a good idea to avoid changing this class manually,
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
public abstract class _E32 extends BaseDataObject {

private static final long serialVersionUID = 1L;

public static final String S_ID_PK_COLUMN = "s_id";
public static final String P_ID_PK_COLUMN = "p_id";
public static final String T_ID_PK_COLUMN = "t_id";

public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
public static final EntityProperty<E33> E33 = PropertyFactory.createEntity("e33", E33.class);

protected String name;

protected Object e33;

public void setName(String name) {
beforePropertyWrite("name", this.name, name);
this.name = name;
}

public String getName() {
beforePropertyRead("name");
return this.name;
}

public void setE33(E33 e33) {
setToOneTarget("e33", e33, true);
}

public E33 getE33() {
return (E33)readProperty("e33");
}

@Override
public Object readPropertyDirectly(String propName) {
if(propName == null) {
throw new IllegalArgumentException();
}

switch(propName) {
case "name":
return this.name;
case "e33":
return this.e33;
default:
return super.readPropertyDirectly(propName);
}
}

@Override
public void writePropertyDirectly(String propName, Object val) {
if(propName == null) {
throw new IllegalArgumentException();
}

switch (propName) {
case "name":
this.name = (String)val;
break;
case "e33":
this.e33 = val;
break;
default:
super.writePropertyDirectly(propName, val);
}
}

private void writeObject(ObjectOutputStream out) throws IOException {
writeSerialized(out);
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
readSerialized(in);
}

@Override
protected void writeState(ObjectOutputStream out) throws IOException {
super.writeState(out);
out.writeObject(this.name);
out.writeObject(this.e33);
}

@Override
protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
super.readState(in);
this.name = (String)in.readObject();
this.e33 = in.readObject();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.agrest.cayenne.cayenne.main.auto;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.apache.cayenne.BaseDataObject;
import org.apache.cayenne.exp.property.PropertyFactory;
import org.apache.cayenne.exp.property.StringProperty;

/**
* Class _E33 was generated by Cayenne.
* It is probably a good idea to avoid changing this class manually,
* since it may be overwritten next time code is regenerated.
* If you need to make any customizations, please use subclass.
*/
public abstract class _E33 extends BaseDataObject {

private static final long serialVersionUID = 1L;

public static final String P_ID_PK_COLUMN = "p_id";

public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);

protected String name;


public void setName(String name) {
beforePropertyWrite("name", this.name, name);
this.name = name;
}

public String getName() {
beforePropertyRead("name");
return this.name;
}

@Override
public Object readPropertyDirectly(String propName) {
if(propName == null) {
throw new IllegalArgumentException();
}

switch(propName) {
case "name":
return this.name;
default:
return super.readPropertyDirectly(propName);
}
}

@Override
public void writePropertyDirectly(String propName, Object val) {
if(propName == null) {
throw new IllegalArgumentException();
}

switch (propName) {
case "name":
this.name = (String)val;
break;
default:
super.writePropertyDirectly(propName, val);
}
}

private void writeObject(ObjectOutputStream out) throws IOException {
writeSerialized(out);
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
readSerialized(in);
}

@Override
protected void writeState(ObjectOutputStream out) throws IOException {
super.writeState(out);
out.writeObject(this.name);
}

@Override
protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
super.readState(in);
this.name = (String)in.readObject();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@ public Table e31() {
return db.getTable("e31");
}

public Table e32() {
return db.getTable("e32");
}

public Table e33() {
return db.getTable("e33");
}

protected CayenneTester getCayenneInScope() {
return Objects.requireNonNull(cayenneInScope, "Not in test scope");
}
Expand Down
40 changes: 40 additions & 0 deletions agrest-cayenne/src/test/resources/datamap.map.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,16 @@
<db-attribute name="id" type="BIGINT" isPrimaryKey="true" isMandatory="true"/>
<db-attribute name="name" type="VARCHAR" length="100"/>
</db-entity>
<db-entity name="e32">
<db-attribute name="name" type="VARCHAR" length="100"/>
<db-attribute name="p_id" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
<db-attribute name="s_id" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
<db-attribute name="t_id" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
</db-entity>
<db-entity name="e33">
<db-attribute name="name" type="VARCHAR" length="100"/>
<db-attribute name="p_id" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
</db-entity>
<db-entity name="e4">
<db-attribute name="c_boolean" type="BOOLEAN"/>
<db-attribute name="c_date" type="DATE"/>
Expand Down Expand Up @@ -299,6 +309,12 @@
<obj-attribute name="id" type="java.lang.Long" db-attribute-path="id"/>
<obj-attribute name="name" type="java.lang.String" db-attribute-path="name"/>
</obj-entity>
<obj-entity name="E32" className="io.agrest.cayenne.cayenne.main.E32" dbEntityName="e32">
<obj-attribute name="name" type="java.lang.String" db-attribute-path="name"/>
</obj-entity>
<obj-entity name="E33" className="io.agrest.cayenne.cayenne.main.E33" dbEntityName="e33">
<obj-attribute name="name" type="java.lang.String" db-attribute-path="name"/>
</obj-entity>
<obj-entity name="E4" className="io.agrest.cayenne.cayenne.main.E4" dbEntityName="e4">
<obj-attribute name="cBoolean" type="java.lang.Boolean" db-attribute-path="c_boolean"/>
<obj-attribute name="cDate" type="java.util.Date" db-attribute-path="c_date"/>
Expand Down Expand Up @@ -402,6 +418,12 @@
<db-relationship name="e5" source="e3" target="e5">
<db-attribute-pair source="e5_id" target="id"/>
</db-relationship>
<db-relationship name="e33" source="e32" target="e33">
<db-attribute-pair source="p_id" target="p_id"/>
</db-relationship>
<db-relationship name="e32s" source="e33" target="e32" toDependentPK="true" toMany="true">
<db-attribute-pair source="p_id" target="p_id"/>
</db-relationship>
<db-relationship name="e15e5" source="e5" target="e15_e5" toDependentPK="true" toMany="true">
<db-attribute-pair source="id" target="e5_id"/>
</db-relationship>
Expand Down Expand Up @@ -442,17 +464,35 @@
<obj-relationship name="e23" source="E26" target="E23" deleteRule="Nullify" db-relationship-path="e23"/>
<obj-relationship name="e2" source="E3" target="E2" deleteRule="Nullify" db-relationship-path="e2"/>
<obj-relationship name="e5" source="E3" target="E5" deleteRule="Nullify" db-relationship-path="e5"/>
<obj-relationship name="e33" source="E32" target="E33" deleteRule="Nullify" db-relationship-path="e33"/>
<obj-relationship name="e15s" source="E5" target="E15" db-relationship-path="e15e5.e15"/>
<obj-relationship name="e3s" source="E5" target="E3" deleteRule="Deny" db-relationship-path="e2s"/>
<obj-relationship name="e8" source="E7" target="E8" deleteRule="Nullify" db-relationship-path="e8"/>
<obj-relationship name="e7s" source="E8" target="E7" deleteRule="Deny" db-relationship-path="e7s"/>
<obj-relationship name="e9" source="E8" target="E9" deleteRule="Nullify" db-relationship-path="e9"/>
<obj-relationship name="e8" source="E9" target="E8" deleteRule="Nullify" db-relationship-path="e8"/>
<dbImport xmlns="http://cayenne.apache.org/schema/10/dbimport">
<tableTypes>
<tableType>TABLE</tableType>
<tableType>VIEW</tableType>
</tableTypes>
<forceDataMapCatalog>false</forceDataMapCatalog>
<forceDataMapSchema>false</forceDataMapSchema>
<namingStrategy>org.apache.cayenne.dbsync.naming.DefaultObjectNameGenerator</namingStrategy>
<skipPrimaryKeyLoading>false</skipPrimaryKeyLoading>
<skipRelationshipsLoading>false</skipRelationshipsLoading>
<useJava7Types>false</useJava7Types>
<usePrimitives>true</usePrimitives>
</dbImport>
<cgen xmlns="http://cayenne.apache.org/schema/10/cgen">
<destDir>../java</destDir>
<mode>entity</mode>
<template>templates/v4_1/subclass.vm</template>
<superTemplate>templates/v4_1/superclass.vm</superTemplate>
<embeddableTemplate>templates/v4_1/embeddable-subclass.vm</embeddableTemplate>
<embeddableSuperTemplate>templates/v4_1/embeddable-superclass.vm</embeddableSuperTemplate>
<queryTemplate>templates/v4_1/datamap-subclass.vm</queryTemplate>
<querySuperTemplate>templates/v4_1/datamap-superclass.vm</querySuperTemplate>
<outputPattern>*.java</outputPattern>
<makePairs>true</makePairs>
<usePkgPath>true</usePkgPath>
Expand Down
Loading

0 comments on commit c18df59

Please sign in to comment.