diff --git a/src/test/java/com/avaje/tests/family/TestInheritance.java b/src/test/java/com/avaje/tests/family/TestInheritance.java new file mode 100644 index 000000000..f5ac950c0 --- /dev/null +++ b/src/test/java/com/avaje/tests/family/TestInheritance.java @@ -0,0 +1,133 @@ + +package com.avaje.tests.family; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Test; + +import com.avaje.tests.lib.EbeanTestCase; +import com.avaje.tests.model.family.ChildPerson; +import com.avaje.tests.model.family.GrandParentPerson; +import com.avaje.tests.model.family.ParentPerson; + + + +public class TestInheritance extends EbeanTestCase { + + + @Test + public void testInheritance() { + + ChildPerson child1 = new ChildPerson(); + child1.setAge(13); + child1.setName("Fred"); + + ChildPerson child2 = new ChildPerson(); + child2.setAge(8); + child2.setFamilyName("Baz"); + child2.setName("Julia"); + + ChildPerson child3 = new ChildPerson(); + child3.setAge(36); + child3.setName("Roland"); + + ParentPerson parent1 = new ParentPerson(); + parent1.setAge(40); + parent1.setName("Maria"); + parent1.setFamilyName("Bar"); + parent1.getChildren().add(child1); + parent1.getChildren().add(child2); + + ParentPerson parent2 = new ParentPerson(); + parent2.setAge(50); + parent2.setName("Sandra"); + parent2.getChildren().add(child3); + parent2.setAddress("Berlin"); + + + ParentPerson parent3 = new ParentPerson(); + parent3.setAge(60); + parent3.setName("Michael"); + + GrandParentPerson grandparent1 = new GrandParentPerson(); + grandparent1.setAge(65); + grandparent1.setName("Josef"); + grandparent1.setFamilyName("Foo"); + grandparent1.setAddress("Munich"); + + grandparent1.getChildren().add(parent1); + grandparent1.getChildren().add(parent2); + grandparent1.getChildren().add(parent3); + + getServer().save(grandparent1); + // Test setup complete, so retrieve bean from db + grandparent1 = getServer().find(GrandParentPerson.class).setId(grandparent1.getIdentifier()).findUnique(); + + assertNotNull(grandparent1); + // check if aggregation works + assertEquals(3, grandparent1.getChildCount().intValue()); + assertEquals(150, grandparent1.getTotalAge().intValue()); + + // check normal properties + assertEquals("Josef", grandparent1.getName()); + assertEquals("Foo", grandparent1.getFamilyName()); + assertEquals("Munich", grandparent1.getAddress()); + + // now check children of grandparent + parent1 = grandparent1.getChildren().get(0); + parent2 = grandparent1.getChildren().get(1); + parent3 = grandparent1.getChildren().get(2); + + assertNotNull(parent1); + assertNotNull(parent2); + assertNotNull(parent3); + // parent1 + assertEquals("Maria", parent1.getName()); + assertEquals("Bar", parent1.getFamilyName()); // overwritten family name + assertEquals("Bar", parent1.getEffectiveFamilyName()); // test inheritance + assertNull(parent1.getAddress()); // no alternative address set + assertEquals("Munich", parent1.getEffectiveAddress()); // -> inherit munich + assertEquals(2, parent1.getChildCount().intValue()); + assertEquals(21, parent1.getTotalAge().intValue()); + + // parent2 + assertEquals("Sandra", parent2.getName()); + assertNull(parent2.getFamilyName()); + assertEquals("Foo", parent2.getEffectiveFamilyName()); + assertEquals("Berlin", parent2.getAddress()); + assertEquals("Berlin", parent2.getEffectiveAddress()); + assertEquals(1, parent2.getChildCount().intValue()); + assertEquals(36, parent2.getTotalAge().intValue()); + + // parent3 + assertEquals("Michael", parent3.getName()); + assertNull(parent3.getFamilyName()); + assertEquals("Foo", parent3.getEffectiveFamilyName()); + assertNull(parent3.getAddress()); + assertEquals("Munich", parent3.getEffectiveAddress()); + assertEquals(0, parent3.getChildCount().intValue()); + assertEquals(0, parent3.getTotalAge().intValue()); + + + child1 = parent1.getChildren().get(0); + child2 = parent1.getChildren().get(1); + + child3 = parent2.getChildren().get(0); + + assertNotNull(child1); + assertNotNull(child2); + assertNotNull(child3); + + assertEquals("Bar", child1.getEffectiveFamilyName()); + assertEquals("Munich", child1.getEffectiveAddress()); + + assertEquals("Baz", child2.getEffectiveFamilyName()); + assertEquals("Munich", child2.getEffectiveAddress()); + + assertEquals("Foo", child3.getEffectiveFamilyName()); + assertEquals("Berlin", child3.getEffectiveAddress()); + + } +} diff --git a/src/test/java/com/avaje/tests/model/family/ChildPerson.java b/src/test/java/com/avaje/tests/model/family/ChildPerson.java new file mode 100644 index 000000000..67b0d2b16 --- /dev/null +++ b/src/test/java/com/avaje/tests/model/family/ChildPerson.java @@ -0,0 +1,66 @@ + +package com.avaje.tests.model.family; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; + +import com.avaje.ebean.annotation.Formula; + +@Entity +public class ChildPerson extends InheritablePerson { + + private static final String PARENTS_JOIN = "join parent_person j1 on j1.identifier = ${ta}.parent_identifier " + + "join grand_parent_person j2 on j2.identifier = j1.parent_identifier"; + + @ManyToOne(cascade = CascadeType.ALL) + private ParentPerson parent; + + private String familyName; + + private String address; + + //@Coalesce({ "familyName", "parent.familyName", "parent.parent.familyName" }) + @Formula(select = "coalesce(${ta}.family_name, j1.family_name, j2.family_name)", join = PARENTS_JOIN ) + private String effectiveFamilyName; + + //@Coalesce({ "address", "parent.address", "parent.parent.address" }) + @Formula(select = "coalesce(${ta}.address, j1.address, j2.address)", join = PARENTS_JOIN ) + private String effectiveAddress; + + + public ParentPerson getParent() { + return parent; + } + + public void setParent(ParentPerson parent) { + this.parent = parent; + } + + public String getFamilyName() { + return familyName; + } + + public void setFamilyName(String familyName) { + this.familyName = familyName; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getEffectiveFamilyName() { + return effectiveFamilyName; + } + + public String getEffectiveAddress() { + return effectiveAddress; + } + + + +} diff --git a/src/test/java/com/avaje/tests/model/family/GrandParentPerson.java b/src/test/java/com/avaje/tests/model/family/GrandParentPerson.java new file mode 100644 index 000000000..41277d016 --- /dev/null +++ b/src/test/java/com/avaje/tests/model/family/GrandParentPerson.java @@ -0,0 +1,70 @@ + +package com.avaje.tests.model.family; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.OneToMany; + +import com.avaje.ebean.annotation.Formula; + +@Entity +public class GrandParentPerson extends InheritablePerson { + + @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) + private List children = new ArrayList<>(); + + // This rather complex formulas should be built later by CustomAnnotationParser + private static final String PARENT_PERSON_AGGREGATE_JOIN = "left join " + + "(select parent_identifier, count(*) as child_count, sum(age) as child_age from parent_person group by parent_identifier) " + + "as f1 on f1.parent_identifier = ${ta}.identifier"; + + //@Count("children") + @Formula(select = "coalesce(f1.child_count, 0)", join = PARENT_PERSON_AGGREGATE_JOIN ) + private Integer childCount; + + //@Sum("children.age") + @Formula(select = "coalesce(f1.child_age, 0)", join = PARENT_PERSON_AGGREGATE_JOIN ) + private Integer totalAge; + + private String familyName; + + private String address; + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + + public Integer getTotalAge() { + return totalAge; + } + + public String getFamilyName() { + return familyName; + } + + public void setFamilyName(String familyName) { + this.familyName = familyName; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public Integer getChildCount() { + return childCount; + } + + +} diff --git a/src/test/java/com/avaje/tests/model/family/InheritablePerson.java b/src/test/java/com/avaje/tests/model/family/InheritablePerson.java new file mode 100644 index 000000000..a76b1200c --- /dev/null +++ b/src/test/java/com/avaje/tests/model/family/InheritablePerson.java @@ -0,0 +1,43 @@ + +package com.avaje.tests.model.family; + +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +@MappedSuperclass +public abstract class InheritablePerson { + + @Id + private Integer identifier; + + private String name; + + private Integer age; + + public Integer getIdentifier() { + return identifier; + } + + public void setIdentifier(Integer identifier) { + this.identifier = identifier; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + + +} diff --git a/src/test/java/com/avaje/tests/model/family/ParentPerson.java b/src/test/java/com/avaje/tests/model/family/ParentPerson.java new file mode 100644 index 000000000..38aa9e3ea --- /dev/null +++ b/src/test/java/com/avaje/tests/model/family/ParentPerson.java @@ -0,0 +1,96 @@ + +package com.avaje.tests.model.family; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +import com.avaje.ebean.annotation.Formula; + + +@Entity +public class ParentPerson extends InheritablePerson { + + //This rather complex formulas should be built later by CustomAnnotationParser + private static final String CHILD_PERSON_AGGREGATE_JOIN = "left join " + + "(select parent_identifier, count(*) as child_count, sum(age) as child_age from child_person group by parent_identifier) " + + "as f1 on f1.parent_identifier = ${ta}.identifier"; + + private static final String GRAND_PARENT_PERSON_JOIN = "join grand_parent_person j1 on j1.identifier = ${ta}.parent_identifier"; + + @ManyToOne(cascade = CascadeType.ALL) + private GrandParentPerson parent; + + @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) + private List children = new ArrayList<>(); + + //@Count("children") + @Formula(select = "coalesce(f1.child_count, 0)", join = CHILD_PERSON_AGGREGATE_JOIN ) + private Integer childCount; + + //@Sum("children.age") + @Formula(select = "coalesce(f1.child_age, 0)", join = CHILD_PERSON_AGGREGATE_JOIN ) + private Integer totalAge; + + private String familyName; + + private String address; + + //@Coalesce({ "familyName", "parent.familyName" }) + @Formula(select = "coalesce(${ta}.family_name, j1.family_name)", join = GRAND_PARENT_PERSON_JOIN ) + private String effectiveFamilyName; + + //@Coalesce({ "address", "parent.address" }) + @Formula(select = "coalesce(${ta}.address, j1.address)", join = GRAND_PARENT_PERSON_JOIN ) + private String effectiveAddress; + + public GrandParentPerson getParent() { + return parent; + } + + public void setParent(GrandParentPerson parent) { + this.parent = parent; + } + + public String getFamilyName() { + return familyName; + } + + public void setFamilyName(String familyName) { + this.familyName = familyName; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public List getChildren() { + return children; + } + + public Integer getChildCount() { + return childCount; + } + + public Integer getTotalAge() { + return totalAge; + } + + public String getEffectiveFamilyName() { + return effectiveFamilyName; + } + + public String getEffectiveAddress() { + return effectiveAddress; + } + + +}