From b56d68dac7f6d1b304cdd6c1443b97615ccd3253 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 12 Feb 2021 22:17:04 +1300 Subject: [PATCH 1/6] #2157 - ManyToMany mapping to itself results in broken generated SQL DDL when not defining @JoinTable. --- .../deploy/parse/AnnotationAssocManys.java | 13 +++--- .../tests/model/interfaces/SelfManyMany.java | 40 +++++++++++++++++++ .../tests/model/interfaces/TestSelfMany.java | 15 +++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 ebean-core/src/test/java/org/tests/model/interfaces/SelfManyMany.java create mode 100644 ebean-core/src/test/java/org/tests/model/interfaces/TestSelfMany.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index 91c949a0f..b3346562b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -5,7 +5,6 @@ import io.ebean.annotation.FetchPreference; import io.ebean.annotation.HistoryExclude; import io.ebean.annotation.Where; import io.ebean.bean.BeanCollection.ModifyListenMode; -import io.ebean.config.BeanNotRegisteredException; import io.ebean.config.NamingConvention; import io.ebean.config.TableName; import io.ebean.core.type.ScalarType; @@ -140,15 +139,15 @@ class AnnotationAssocManys extends AnnotationAssoc { JoinTable joinTable = get(prop, JoinTable.class); if (joinTable != null) { if (prop.isManyToMany()) { - // expected this readJoinTable(joinTable, prop); - } else { // OneToMany with @JoinTable prop.setO2mJoinTable(); readJoinTable(joinTable, prop); manyToManyDefaultJoins(prop); } + } else if (prop.isManyToMany()) { + checkSelfManyToMany(prop); } if (prop.getMappedBy() != null) { @@ -181,6 +180,12 @@ class AnnotationAssocManys extends AnnotationAssoc { } } + private void checkSelfManyToMany(DeployBeanPropertyAssocMany prop) { + if (prop.getTargetType().equals(descriptor.getBeanType())) { + throw new IllegalStateException("@ManyToMany mapping for " + prop.getFullBeanName() + " requires explicit @JoinTable with joinColumns & inverseJoinColumns. Refer issue #2157"); + } + } + @SuppressWarnings("unchecked") private void readElementCollection(DeployBeanPropertyAssocMany prop, ElementCollection elementCollection) { @@ -430,7 +435,6 @@ class AnnotationAssocManys extends AnnotationAssoc { } private void readToMany(ManyToMany propAnn, DeployBeanPropertyAssocMany manyProp) { - manyProp.setMappedBy(propAnn.mappedBy()); manyProp.setFetchType(propAnn.fetch()); setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo()); @@ -442,7 +446,6 @@ class AnnotationAssocManys extends AnnotationAssoc { } private void readToOne(OneToMany propAnn, DeployBeanPropertyAssocMany manyProp) { - manyProp.setMappedBy(propAnn.mappedBy()); manyProp.setFetchType(propAnn.fetch()); setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo()); diff --git a/ebean-core/src/test/java/org/tests/model/interfaces/SelfManyMany.java b/ebean-core/src/test/java/org/tests/model/interfaces/SelfManyMany.java new file mode 100644 index 000000000..6cfc52193 --- /dev/null +++ b/ebean-core/src/test/java/org/tests/model/interfaces/SelfManyMany.java @@ -0,0 +1,40 @@ +package org.tests.model.interfaces; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import java.util.List; + +@Entity +public class SelfManyMany { + + @Id + private long id; + + private final String name; + + @ManyToMany + // requires explicit @JoinTable + @JoinTable(name = "self_many_bridge", + joinColumns = @JoinColumn(name = "self_1_id"), + inverseJoinColumns = @JoinColumn(name = "self_2_id")) + private List related; + + public SelfManyMany(String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public List getRelated() { + return related; + } +} diff --git a/ebean-core/src/test/java/org/tests/model/interfaces/TestSelfMany.java b/ebean-core/src/test/java/org/tests/model/interfaces/TestSelfMany.java new file mode 100644 index 000000000..e12c47cfd --- /dev/null +++ b/ebean-core/src/test/java/org/tests/model/interfaces/TestSelfMany.java @@ -0,0 +1,15 @@ +package org.tests.model.interfaces; + +import io.ebean.BaseTestCase; +import io.ebean.DB; +import org.junit.Test; + +public class TestSelfMany extends BaseTestCase { + + @Test + public void self_manyToMany() { + + SelfManyMany m = new SelfManyMany("1"); + DB.save(m); + } +} From 8e59e729836b30b800388e872e1ab5bd9febe28b Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 12 Feb 2021 22:27:34 +1300 Subject: [PATCH 2/6] [maven-release-plugin] prepare release ebean-parent-12.6.7 --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 8 ++++---- ebean/pom.xml | 12 ++++++------ kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 66 insertions(+), 66 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 4150e1cb3..c8deead0b 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 5892fda8e..a395c314f 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.5 + ebean-parent-12.6.7 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index b3b611006..62659400e 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-api - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-core-type - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-ddl-generator - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-externalmapping-api - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-externalmapping-xml - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-autotune - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-querybean - 12.6.7-SNAPSHOT + 12.6.7 io.ebean querybean-generator - 12.6.7-SNAPSHOT + 12.6.7 provided io.ebean kotlin-querybean-generator - 12.6.7-SNAPSHOT + 12.6.7 provided io.ebean ebean-test - 12.6.7-SNAPSHOT + 12.6.7 test io.ebean ebean-postgis - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-redis - 12.6.7-SNAPSHOT + 12.6.7 diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 18e8f5bb8..a71c04bf9 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean-core-type @@ -21,7 +21,7 @@ io.ebean ebean-api - 12.6.7-SNAPSHOT + 12.6.7 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 1c5a407b8..364fdf595 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.5 + ebean-parent-12.6.7 @@ -92,19 +92,19 @@ io.ebean ebean-api - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-core-type - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-externalmapping-api - 12.6.7-SNAPSHOT + 12.6.7 diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index c6039a3ca..944e11a68 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean ddl generation @@ -29,14 +29,14 @@ io.ebean ebean-core-type - 12.6.7-SNAPSHOT + 12.6.7 provided io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index b7229936c..328c54828 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index 7364bff24..e39745b97 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.5 + ebean-parent-12.6.7 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.6.7-SNAPSHOT + 12.6.7 @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 test io.ebean ebean-ddl-generator - 12.6.7-SNAPSHOT + 12.6.7 test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 1240f27fe..4220db482 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean postgis @@ -24,7 +24,7 @@ io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 provided @@ -75,7 +75,7 @@ io.ebean ebean-test - 12.6.7-SNAPSHOT + 12.6.7 test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 3cd58500d..0c5680377 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.5 + ebean-parent-12.6.7 ebean querybean @@ -27,7 +27,7 @@ io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 provided @@ -67,14 +67,14 @@ io.ebean ebean-ddl-generator - 12.6.7-SNAPSHOT + 12.6.7 test io.ebean querybean-generator - 12.6.7-SNAPSHOT + 12.6.7 test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 35d45e38a..f61e43f24 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.6.7-SNAPSHOT + 12.6.7 provided io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 provided io.ebean ebean-querybean - 12.6.7-SNAPSHOT + 12.6.7 test io.ebean querybean-generator - 12.6.7-SNAPSHOT + 12.6.7 test io.ebean ebean-test - 12.6.7-SNAPSHOT + 12.6.7 test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 0c3632dd5..228fc07be 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.5 + ebean-parent-12.6.7 ebean test @@ -43,14 +43,14 @@ io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 provided io.ebean ebean-ddl-generator - 12.6.7-SNAPSHOT + 12.6.7 diff --git a/ebean/pom.xml b/ebean/pom.xml index 5732d2910..a90702613 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 ebean composite @@ -22,34 +22,34 @@ io.ebean ebean-api - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-querybean - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-ddl-generator - 12.6.7-SNAPSHOT + 12.6.7 io.ebean ebean-autotune - 12.6.7-SNAPSHOT + 12.6.7 diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 5d6336d29..ff0e16f82 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.6.7-SNAPSHOT + 12.6.7 test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.6.7-SNAPSHOT + 12.6.7 test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.6.7-SNAPSHOT + 12.6.7 test diff --git a/pom.xml b/pom.xml index c9e885454..6bb866ed8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.6.7-SNAPSHOT + 12.6.7 pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.5 + ebean-parent-12.6.7 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 52c966bea..59e057294 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7-SNAPSHOT + 12.6.7 querybean generator From 5b98d8d9c294cf88a52c0dcb7f724ef268204f14 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 12 Feb 2021 22:27:45 +1300 Subject: [PATCH 3/6] [maven-release-plugin] prepare for next development iteration --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 8 ++++---- ebean/pom.xml | 12 ++++++------ kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 66 insertions(+), 66 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index c8deead0b..c5f36193b 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index a395c314f..b50be9b0d 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.7 + ebean-parent-12.6.5 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 62659400e..6a18b3017 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-api - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-core-type - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-ddl-generator - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-externalmapping-api - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-externalmapping-xml - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-autotune - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-querybean - 12.6.7 + 12.6.8-SNAPSHOT io.ebean querybean-generator - 12.6.7 + 12.6.8-SNAPSHOT provided io.ebean kotlin-querybean-generator - 12.6.7 + 12.6.8-SNAPSHOT provided io.ebean ebean-test - 12.6.7 + 12.6.8-SNAPSHOT test io.ebean ebean-postgis - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-redis - 12.6.7 + 12.6.8-SNAPSHOT diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index a71c04bf9..50d80ce17 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean-core-type @@ -21,7 +21,7 @@ io.ebean ebean-api - 12.6.7 + 12.6.8-SNAPSHOT diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 364fdf595..082cb17aa 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.7 + ebean-parent-12.6.5 @@ -92,19 +92,19 @@ io.ebean ebean-api - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-core-type - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-externalmapping-api - 12.6.7 + 12.6.8-SNAPSHOT diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 944e11a68..c343386bf 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean ddl generation @@ -29,14 +29,14 @@ io.ebean ebean-core-type - 12.6.7 + 12.6.8-SNAPSHOT provided io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index 328c54828..fd23c73a2 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index e39745b97..806a215df 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.7 + ebean-parent-12.6.5 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.6.7 + 12.6.8-SNAPSHOT @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT test io.ebean ebean-ddl-generator - 12.6.7 + 12.6.8-SNAPSHOT test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 4220db482..a6a88a75f 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean postgis @@ -24,7 +24,7 @@ io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT provided @@ -75,7 +75,7 @@ io.ebean ebean-test - 12.6.7 + 12.6.8-SNAPSHOT test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 0c5680377..edcd84379 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.7 + ebean-parent-12.6.5 ebean querybean @@ -27,7 +27,7 @@ io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT provided @@ -67,14 +67,14 @@ io.ebean ebean-ddl-generator - 12.6.7 + 12.6.8-SNAPSHOT test io.ebean querybean-generator - 12.6.7 + 12.6.8-SNAPSHOT test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index f61e43f24..e76555b30 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.6.7 + 12.6.8-SNAPSHOT provided io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT provided io.ebean ebean-querybean - 12.6.7 + 12.6.8-SNAPSHOT test io.ebean querybean-generator - 12.6.7 + 12.6.8-SNAPSHOT test io.ebean ebean-test - 12.6.7 + 12.6.8-SNAPSHOT test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 228fc07be..6809737df 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.7 + ebean-parent-12.6.5 ebean test @@ -43,14 +43,14 @@ io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT provided io.ebean ebean-ddl-generator - 12.6.7 + 12.6.8-SNAPSHOT diff --git a/ebean/pom.xml b/ebean/pom.xml index a90702613..5c0714030 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT ebean composite @@ -22,34 +22,34 @@ io.ebean ebean-api - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-querybean - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-ddl-generator - 12.6.7 + 12.6.8-SNAPSHOT io.ebean ebean-autotune - 12.6.7 + 12.6.8-SNAPSHOT diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index ff0e16f82..7e37844df 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.6.7 + 12.6.8-SNAPSHOT test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.6.7 + 12.6.8-SNAPSHOT test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.6.7 + 12.6.8-SNAPSHOT test diff --git a/pom.xml b/pom.xml index 6bb866ed8..6222be793 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.6.7 + 12.6.8-SNAPSHOT pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.7 + ebean-parent-12.6.5 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 59e057294..adee59843 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.6.7 + 12.6.8-SNAPSHOT querybean generator From 2073fefc92c18e68d0d7db49cc894d7f06e1ae48 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 12 Feb 2021 23:12:32 +1300 Subject: [PATCH 4/6] #2162 - Change ebean artifact such that ebean-ddl-generator is a dependency of ebean-test and ebean-autotune optional --- ebean/pom.xml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/ebean/pom.xml b/ebean/pom.xml index 5c0714030..9cc0b0a60 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -38,20 +38,6 @@ 12.6.8-SNAPSHOT - - - io.ebean - ebean-ddl-generator - 12.6.8-SNAPSHOT - - - - - io.ebean - ebean-autotune - 12.6.8-SNAPSHOT - - From 758f84f573e4d00e2d5ecf2aecfe482c12cd471b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sn=C5=8Dwball?= Date: Fri, 12 Feb 2021 23:56:04 +0100 Subject: [PATCH 5/6] Ignore special kotlin collection types (#2130) Kotlin prefers(emits compiler warnings if not) the built-in types e.g. Set and MutableSet instead of the java.util.* variety. This patch removes the imports for those, so the built-in varieties are used. --- .../generator/SimpleQueryBeanWriter.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java index 8524a59f9..ee21711d2 100644 --- a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java +++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java @@ -8,6 +8,9 @@ import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -42,6 +45,23 @@ class SimpleQueryBeanWriter { "kotlin.Char" }; + // These are special classes under Kotlin, and are auto-imported, same as + // java.lang under Java + private static final Set kotlinBlackListedImports = Collections.unmodifiableSet( + new HashSet<>( + Arrays.asList( + "java.util.ArrayList", + "java.util.HashMap", + "java.util.HashSet", + "java.util.LinkedHashMap", + "java.util.LinkedHashSet", + "java.util.List", + "java.util.Map", + "java.util.Set" + ) + ) + ); + private final Set importTypes = new TreeSet<>(); private final List properties = new ArrayList<>(); @@ -158,6 +178,7 @@ class SimpleQueryBeanWriter { importTypes.add(kotlinTypes[i]); } } + importTypes.removeAll(kotlinBlackListedImports); } private boolean isEntity() { From 8ac54678562c8783ed673b0ad3f0bc1d27193ed1 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 13 Feb 2021 11:58:00 +1300 Subject: [PATCH 6/6] Improve internal calculation of orm query plan hash key (Require use of inline hints like +query(50) to be comma delimited with properties) (#2159) * WIP Tidy DefaultOrmQuery planDescription() * WIP Tidy DefaultOrmQuery planDescription() * Refactor OrmQueryPropertiesParser with hints requiring comma delimiting (previously didn't) * Refactor OrmQueryPropertiesParser (reuse inputProperties) and DRawSqlColumnsParser (to return Set) * Refactor OrmQueryPropertiesParser - remove JunkMain * Refactor OrmQueryDetail, OrmQueryProperties - properties --- .../autotune/service/ProfileOriginTest.java | 10 +- .../server/query/SqlTreeBuilder.java | 2 +- .../server/querydefn/DefaultOrmQuery.java | 46 +++--- .../server/querydefn/OrmQueryDetail.java | 15 +- .../server/querydefn/OrmQueryPlanKey.java | 2 +- .../server/querydefn/OrmQueryProperties.java | 85 +++------- .../querydefn/OrmQueryPropertiesParser.java | 147 +++++------------- .../server/rawsql/DRawSqlColumnsParser.java | 7 +- .../server/util/DSelectColumnsParser.java | 11 +- .../java/io/ebean/plugin/BeanTypeTest.java | 2 +- .../OrmQueryPropertiesParserTest.java | 37 +++-- .../querydefn/OrmQueryPropertiesTest.java | 4 +- .../server/util/DSelectColumnsParserTest.java | 16 +- .../org/tests/batchload/TestQueryJoin.java | 2 +- 14 files changed, 137 insertions(+), 249 deletions(-) diff --git a/ebean-autotune/src/test/java/io/ebeaninternal/server/autotune/service/ProfileOriginTest.java b/ebean-autotune/src/test/java/io/ebeaninternal/server/autotune/service/ProfileOriginTest.java index 4bc86f6b4..ec0a09596 100644 --- a/ebean-autotune/src/test/java/io/ebeaninternal/server/autotune/service/ProfileOriginTest.java +++ b/ebean-autotune/src/test/java/io/ebeaninternal/server/autotune/service/ProfileOriginTest.java @@ -30,7 +30,7 @@ public class ProfileOriginTest extends BaseTestCase { OrmQueryDetail detail = po.buildDetail(desc); - assertThat(detail.asString().trim()).isEqualTo("fetch customer (name)"); + assertThat(detail.asStringDebug().trim()).isEqualTo("fetch customer (name)"); } @Test @@ -49,7 +49,7 @@ public class ProfileOriginTest extends BaseTestCase { OrmQueryDetail detail = po.buildDetail(desc); - assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (name)"); + assertThat(detail.asStringDebug()).isEqualTo("select (orderDate) fetch customer (name)"); } @Test @@ -67,7 +67,7 @@ public class ProfileOriginTest extends BaseTestCase { OrmQueryDetail detail = po.buildDetail(desc); - assertThat(detail.asString().trim()).isEqualTo("select (orderDate,customer)"); + assertThat(detail.asStringDebug().trim()).isEqualTo("select (orderDate,customer)"); } @Test @@ -90,7 +90,7 @@ public class ProfileOriginTest extends BaseTestCase { OrmQueryDetail detail = po.buildDetail(desc); - assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (billingAddress)"); + assertThat(detail.asStringDebug()).isEqualTo("select (orderDate) fetch customer (billingAddress)"); } @@ -119,7 +119,7 @@ public class ProfileOriginTest extends BaseTestCase { po.collectUsageInfo(c); OrmQueryDetail detail = po.buildDetail(desc); - assertThat(detail.asString()).isEqualTo("fetch customer (name,note) fetch customer.billingAddress (line1)"); + assertThat(detail.asStringDebug()).isEqualTo("fetch customer (name,note) fetch customer.billingAddress (line1)"); } private NodeUsageCollector node(String path) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index d9386ed9b..065884b54 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -452,7 +452,7 @@ public final class SqlTreeBuilder { // Also note that this can include transient properties. // This makes sense for transient properties used to // hold sum() count() type values (with SqlSelect) - final Set selectInclude = queryProps.getSelectInclude(); + final Set selectInclude = queryProps.getIncluded(); for (String propName : selectInclude) { if (!propName.isEmpty()) { addProperty(selectProps, desc, queryProps, propName); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 2f73bceb7..364f6ab93 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1136,81 +1136,81 @@ public class DefaultOrmQuery implements SpiQuery { private String planDescription() { StringBuilder sb = new StringBuilder(300); if (type != null) { - sb.append("t:").append(type.ordinal()); + sb.append(type.ordinal()); } if (useDocStore) { - sb.append(",ds:"); + sb.append("/ds"); } if (beanDescriptor.getDiscValue() != null) { - sb.append(",disc:").append(beanDescriptor.getDiscValue()); + sb.append("/dv").append(beanDescriptor.getDiscValue()); } if (temporalMode != SpiQuery.TemporalMode.CURRENT) { - sb.append(",temp:").append(temporalMode.ordinal()); + sb.append("/tm").append(temporalMode.ordinal()); if (versionsStart != null) { - sb.append(",vb:"); + sb.append("v"); } } if (forUpdate != null) { - sb.append(",forUpd:").append(forUpdate.ordinal()); + sb.append("/fu").append(forUpdate.ordinal()); if (lockType != null) { - sb.append(",lt:").append(lockType.ordinal()); + sb.append("t").append(lockType.ordinal()); } } if (id != null) { - sb.append(",id:"); + sb.append("/id"); } if (manualId) { - sb.append(",manId:"); + sb.append("/md"); } if (distinct) { - sb.append(",dist:"); + sb.append("/dt"); } if (allowLoadErrors) { - sb.append(",allowLoadErrors:"); + sb.append("/ae"); } if (disableLazyLoading) { - sb.append(",disLazy:"); + sb.append("/dl"); } if (baseTable != null) { - sb.append(",baseTable:").append(baseTable); + sb.append("/bt").append(baseTable); } if (rootTableAlias != null) { - sb.append(",root:").append(rootTableAlias); + sb.append("/ra").append(rootTableAlias); } if (orderBy != null) { - sb.append(",orderBy:").append(orderBy.toStringFormat()); + sb.append("/ob").append(orderBy.toStringFormat()); } if (m2mIncludeJoin != null) { - sb.append(",m2m:").append(m2mIncludeJoin.getTable()); + sb.append("/m2").append(m2mIncludeJoin.getTable()); } if (mapKey != null) { - sb.append(",mapKey:").append(mapKey); + sb.append("/mk").append(mapKey); } if (countDistinctOrder != null) { - sb.append(",countDistOrd:").append(countDistinctOrder.name()); + sb.append("/cd").append(countDistinctOrder.name()); } if (detail != null) { - sb.append(" detail["); + sb.append("/d["); detail.queryPlanHash(sb); sb.append("]"); } if (bindParams != null) { - sb.append(" bindParams["); + sb.append("/b["); bindParams.buildQueryPlanHash(sb); sb.append("]"); } if (whereExpressions != null) { - sb.append(" where["); + sb.append("/w["); whereExpressions.queryPlanHash(sb); sb.append("]"); } if (havingExpressions != null) { - sb.append(" having["); + sb.append("/h["); havingExpressions.queryPlanHash(sb); sb.append("]"); } if (updateProperties != null) { - sb.append(" update["); + sb.append("/u["); updateProperties.buildQueryPlanHash(sb); sb.append("]"); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java index 1310b709a..b8837111e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java @@ -106,25 +106,20 @@ public class OrmQueryDetail implements Serializable { return p1 == null ? p2 == null : p1.isSameByAutoTune(p2); } - @Override - public String toString() { - return asString(); - } - /** * Return the detail in string form. */ - public String asString() { + public String asStringDebug() { StringBuilder sb = new StringBuilder(); if (!baseProps.isEmpty()) { - baseProps.append("select ", sb); + baseProps.asStringDebug("select ", sb); } if (fetchPaths != null) { for (OrmQueryProperties join : fetchPaths.values()) { if (sb.length() > 0) { sb.append(" "); } - join.append("fetch ", sb); + join.asStringDebug("fetch ", sb); } } return sb.toString(); @@ -150,7 +145,7 @@ public class OrmQueryDetail implements Serializable { * Set the base query properties to be empty. */ public void setEmptyBase() { - this.baseProps = new OrmQueryProperties(null, new LinkedHashSet<>()); + this.baseProps = new OrmQueryProperties(null, Collections.emptySet()); } /** @@ -316,7 +311,7 @@ public class OrmQueryDetail implements Serializable { if (addId) { parentProp = new OrmQueryProperties(parentPath, assocOne.getTargetIdProperty()); } else { - parentProp = new OrmQueryProperties(parentPath, new LinkedHashSet<>()); + parentProp = new OrmQueryProperties(parentPath, Collections.emptySet()); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java index c083eb3d5..3a9ac8e33 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java @@ -29,7 +29,7 @@ class OrmQueryPlanKey implements CQueryPlanKey { @Override public CQueryPlanKey withDeleteByIds() { - return new OrmQueryPlanKey(description + ":deleteByIds", 0, 0, null); + return new OrmQueryPlanKey(description + "/deleteByIds", 0, 0, null); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java index 805c3bf68..bbbc425de 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryProperties.java @@ -30,12 +30,8 @@ public class OrmQueryProperties implements Serializable { private final String parentPath; private final String path; - - private final String rawProperties; - private final String trimmedProperties; - - private final LinkedHashSet included; - + private final String properties; + private final Set included; private final FetchConfig fetchConfig; /** @@ -84,8 +80,7 @@ public class OrmQueryProperties implements Serializable { public OrmQueryProperties(String path) { this.path = path; this.parentPath = SplitName.parent(path); - this.rawProperties = null; - this.trimmedProperties = null; + this.properties = null; this.included = null; this.fetchConfig = DEFAULT_FETCH; } @@ -100,8 +95,7 @@ public class OrmQueryProperties implements Serializable { this.path = path; this.parentPath = SplitName.parent(path); - this.rawProperties = rawProperties; - this.trimmedProperties = response.properties; + this.properties = response.properties; this.included = response.included; this.cache = response.cache; this.readOnly = response.readOnly; @@ -115,39 +109,17 @@ public class OrmQueryProperties implements Serializable { } } - public OrmQueryProperties(String path, LinkedHashSet parsedProperties) { - if (parsedProperties == null) { - throw new IllegalArgumentException("parsedProperties is null"); - } - + public OrmQueryProperties(String path, Set included) { this.path = path; this.parentPath = SplitName.parent(path); // for rawSql parsedProperties can be empty (when only fetching Id property) - this.included = parsedProperties; - this.rawProperties = join(parsedProperties); - this.trimmedProperties = rawProperties; + this.included = included; + this.properties = String.join(",", included); this.cache = false; this.readOnly = false; this.fetchConfig = DEFAULT_FETCH; } - /** - * Join the set of properties into a comma delimited string. - */ - private String join(LinkedHashSet parsedProperties) { - StringBuilder sb = new StringBuilder(50); - boolean first = true; - for (String property : parsedProperties) { - if (first) { - first = false; - } else { - sb.append(","); - } - sb.append(property); - } - return sb.toString(); - } - /** * Copy constructor. */ @@ -155,8 +127,7 @@ public class OrmQueryProperties implements Serializable { this.fetchConfig = sourceFetchConfig; this.parentPath = source.parentPath; this.path = source.path; - this.rawProperties = source.rawProperties; - this.trimmedProperties = source.trimmedProperties; + this.properties = source.properties; this.cache = source.cache; this.readOnly = source.readOnly; this.filterMany = source.filterMany; @@ -240,8 +211,8 @@ public class OrmQueryProperties implements Serializable { @SuppressWarnings("unchecked") public void configureBeanQuery(SpiQuery query) { - if (trimmedProperties != null && !trimmedProperties.isEmpty()) { - query.select(trimmedProperties); + if (properties != null && !properties.isEmpty()) { + query.select(properties); } if (filterMany != null) { @@ -268,7 +239,7 @@ public class OrmQueryProperties implements Serializable { } public boolean hasSelectClause() { - if ("*".equals(trimmedProperties)) { + if ("*".equals(properties)) { // explicitly selected all properties return true; } @@ -280,25 +251,17 @@ public class OrmQueryProperties implements Serializable { * Return true if the properties and configuration are empty. */ public boolean isEmpty() { - return rawProperties == null || rawProperties.isEmpty(); + return properties == null || properties.isEmpty(); } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(40); - append("", sb); - return sb.toString(); - } - - public String append(String prefix, StringBuilder sb) { + public void asStringDebug(String prefix, StringBuilder sb) { sb.append(prefix); if (path != null) { sb.append(path).append(" "); } if (!isEmpty()) { - sb.append("(").append(rawProperties).append(")"); + sb.append("(").append(properties).append(")"); } - return sb.toString(); } boolean isChild(OrmQueryProperties possibleChild) { @@ -319,7 +282,7 @@ public class OrmQueryProperties implements Serializable { * Return the raw properties. */ public String getProperties() { - return rawProperties; + return properties; } /** @@ -350,10 +313,6 @@ public class OrmQueryProperties implements Serializable { includedBeanJoin.add(propertyName); } - public Set getSelectInclude() { - return included; - } - public Set getSelectQueryJoin() { return secondaryQueryJoins; } @@ -373,7 +332,6 @@ public class OrmQueryProperties implements Serializable { } boolean isIncluded(String propName) { - if (includedBeanJoin != null && includedBeanJoin.contains(propName)) { return false; } @@ -474,24 +432,21 @@ public class OrmQueryProperties implements Serializable { * Calculate the query plan hash. */ public void queryPlanHash(StringBuilder builder) { - - builder.append("qpp["); + builder.append("p["); builder.append(path); if (included != null){ - builder.append(" included:").append(included); + builder.append("/i").append(included); } if (secondaryQueryJoins != null) { - builder.append(" secondary:").append(secondaryQueryJoins); + builder.append("/s").append(secondaryQueryJoins); } - if (filterMany != null) { - builder.append(" filterMany["); + builder.append("/f["); filterMany.queryPlanHash(builder); builder.append("]"); } - if (fetchConfig != null) { - builder.append(" config:").append(fetchConfig.hashCode()); + builder.append("/c:").append(fetchConfig.hashCode()); } builder.append("]"); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java index 5c03e0a33..9350baf2b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java @@ -3,8 +3,8 @@ package io.ebeaninternal.server.querydefn; import io.ebean.FetchConfig; import io.ebeaninternal.server.util.DSelectColumnsParser; -import java.util.LinkedHashSet; -import java.util.List; +import java.util.Iterator; +import java.util.Set; /** * Parses the path properties string. @@ -22,9 +22,9 @@ class OrmQueryPropertiesParser { final boolean cache; final FetchConfig fetchConfig; final String properties; - final LinkedHashSet included; + final Set included; - Response(boolean readOnly, boolean cache, int queryFetchBatch, int lazyFetchBatch, String properties, LinkedHashSet included) { + Response(boolean readOnly, boolean cache, int queryFetchBatch, int lazyFetchBatch, String properties, Set included) { this.readOnly = readOnly; this.cache = cache; this.properties = properties; @@ -53,9 +53,7 @@ class OrmQueryPropertiesParser { return new OrmQueryPropertiesParser(rawProperties).parse(); } - private String inputProperties; - - private String outputProperties = ""; + private final String inputProperties; private boolean allProperties; private boolean readOnly; private boolean cache; @@ -70,124 +68,61 @@ class OrmQueryPropertiesParser { * Parse the raw string properties input. */ private Response parse() { - if (inputProperties == null || inputProperties.isEmpty()) { return EMPTY; } - int pos = inputProperties.indexOf("+readonly"); - if (pos > -1) { - inputProperties = inputProperties.replace("+readonly", ""); - readOnly = true; - } - pos = inputProperties.indexOf("+cache"); - if (pos > -1) { - inputProperties = inputProperties.replace("+cache", ""); - cache = true; - } - pos = inputProperties.indexOf("+query"); - if (pos > -1) { - queryFetchBatch = parseBatchHint(pos, "+query"); - } - pos = inputProperties.indexOf("+lazy"); - if (pos > -1) { - lazyFetchBatch = parseBatchHint(pos, "+lazy"); - } - - LinkedHashSet included = parseIncluded(); - String properties = (allProperties) ? "*" : outputProperties; - return new Response(readOnly, cache, queryFetchBatch, lazyFetchBatch, properties, included); - } - - /** - * Parse the include separating by comma or semicolon. - */ - private LinkedHashSet parseIncluded() { - - inputProperties = inputProperties.trim(); - if (inputProperties.isEmpty()) { - // default properties - return null; - } if (inputProperties.equals("*")) { // explicit all properties allProperties = true; - return null; + return new Response(readOnly, cache, queryFetchBatch, lazyFetchBatch, "*", null); } - - List res = splitRawSelect(inputProperties); - - StringBuilder sb = new StringBuilder(70); - LinkedHashSet propertySet = new LinkedHashSet<>(res.size() * 2); - - int count = 0; - String temp; - for (String re : res) { - temp = re.trim(); - if (!temp.isEmpty()) { - if (count > 0) { - sb.append(","); - } - sb.append(temp); - propertySet.add(temp); - count++; + boolean hints = false; + Set fields = splitRawSelect(inputProperties); + final Iterator iterator = fields.iterator(); + while (iterator.hasNext()) { + String val = iterator.next(); + if (val.startsWith("+")) { + hints = true; + iterator.remove(); + parseHint(val); + } else if (val.equals("*")) { + allProperties = true; } } - - if (propertySet.isEmpty()) { - // default properties - return null; + String properties = allProperties ? "*" : hints ? String.join(",", fields) : inputProperties; + if (fields.isEmpty()) { + fields = null; } + return new Response(readOnly, cache, queryFetchBatch, lazyFetchBatch, properties, fields); + } - if (propertySet.contains("*")) { - // explicit all properties - allProperties = true; - return null; + private void parseHint(String val) { + if (val.equals("+readonly")) { + readOnly = true; + } else if (val.equals("+cache")) { + cache = true; + } else if (val.startsWith("+query")) { + queryFetchBatch = parseBatch(val); + } else if (val.startsWith("+lazy")) { + lazyFetchBatch = parseBatch(val); } + } - // partial properties - outputProperties = sb.toString(); - return propertySet; + private int parseBatch(String val) { + if (val.endsWith(")")) { + int start = val.lastIndexOf('('); + if (start > 0) { + return Integer.parseInt(val.substring(start + 1, val.length() - 1)); + } + } + return 0; } /** * Split allowing 'dynamic function based properties'. */ - private List splitRawSelect(String inputProperties) { + private Set splitRawSelect(String inputProperties) { return DSelectColumnsParser.parse(inputProperties); } - private int parseBatchHint(int pos, String option) { - - int startPos = pos + option.length(); - int endPos = findEndPos(startPos, inputProperties); - if (endPos == -1) { - inputProperties = inputProperties.replace(option, ""); - return 0; - - } else { - - String batchParam = inputProperties.substring(startPos + 1, endPos); - - if (endPos + 1 >= inputProperties.length()) { - inputProperties = inputProperties.substring(0, pos); - } else { - inputProperties = inputProperties.substring(0, pos) + inputProperties.substring(endPos + 1); - } - return Integer.parseInt(batchParam); - } - } - - private int findEndPos(int pos, String props) { - - if (pos < props.length()) { - if (props.charAt(pos) == '(') { - int endPara = props.indexOf(')', pos + 1); - if (endPara == -1) { - throw new RuntimeException("Error could not find ')' in " + props + " after position " + pos); - } - return endPara; - } - } - return -1; - } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlColumnsParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlColumnsParser.java index 2ee3b354d..74c02badd 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlColumnsParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlColumnsParser.java @@ -6,6 +6,7 @@ import io.ebeaninternal.server.util.DSelectColumnsParser; import javax.persistence.PersistenceException; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.regex.Pattern; /** @@ -28,11 +29,8 @@ final class DRawSqlColumnsParser { } private ColumnMapping parse() { - - List columnList = DSelectColumnsParser.parse(sqlSelect); - + Set columnList = DSelectColumnsParser.parse(sqlSelect); List columns = new ArrayList<>(columnList.size()); - for (String rawColumn : columnList) { columns.add(parseColumn(rawColumn)); } @@ -40,7 +38,6 @@ final class DRawSqlColumnsParser { } private ColumnMapping.Column parseColumn(String colInfo) { - String[] split = COLINFO_SPLIT.split(colInfo); if (split.length > 1) { ArrayList tmp = new ArrayList<>(split.length); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/util/DSelectColumnsParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/util/DSelectColumnsParser.java index c172f92b2..b4ec33a67 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/util/DSelectColumnsParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/util/DSelectColumnsParser.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.util; -import java.util.ArrayList; -import java.util.List; +import java.util.LinkedHashSet; +import java.util.Set; /** * Splits a select clause into 'logical columns' taking into account functions and quotes. @@ -14,7 +14,7 @@ public final class DSelectColumnsParser { private int pos; - public static List parse(String sqlSelect) { + public static Set parse(String sqlSelect) { return new DSelectColumnsParser(sqlSelect).parse(); } @@ -23,9 +23,8 @@ public final class DSelectColumnsParser { this.end = selectClause.length(); } - private List parse() { - - ArrayList columns = new ArrayList<>(); + private Set parse() { + LinkedHashSet columns = new LinkedHashSet<>(); while (pos <= end) { columns.add(nextColumnInfo()); } diff --git a/ebean-core/src/test/java/io/ebean/plugin/BeanTypeTest.java b/ebean-core/src/test/java/io/ebean/plugin/BeanTypeTest.java index 2b880805a..820e89408 100644 --- a/ebean-core/src/test/java/io/ebean/plugin/BeanTypeTest.java +++ b/ebean-core/src/test/java/io/ebean/plugin/BeanTypeTest.java @@ -177,7 +177,7 @@ public class BeanTypeTest { beanType(Order.class).docStore().applyPath(orderQuery); OrmQueryDetail detail = orderQuery.getDetail(); - assertThat(detail.getChunk("customer", false).getSelectInclude()).containsExactly("id", "name"); + assertThat(detail.getChunk("customer", false).getIncluded()).containsExactly("id", "name"); } @Test(expected = IllegalStateException.class) diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParserTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParserTest.java index f15cffc38..cc715509d 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParserTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParserTest.java @@ -15,7 +15,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_empty() throws Exception { + public void when_empty() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse(""); assertAllDefaults(res); @@ -23,7 +23,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasStar() throws Exception { + public void when_hasStar() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("*"); assertAllDefaults(res); @@ -31,7 +31,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasCache() throws Exception { + public void when_hasCache() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+cache"); assertThat(res.cache).isTrue(); @@ -39,7 +39,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasCache_first() throws Exception { + public void when_hasCache_first() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+cache,id"); assertThat(res.cache).isTrue(); @@ -47,7 +47,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasCache_last() throws Exception { + public void when_hasCache_last() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+cache"); assertThat(res.cache).isTrue(); @@ -55,7 +55,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasCache_middle() throws Exception { + public void when_hasCache_middle() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+cache, id"); assertThat(res.cache).isTrue(); @@ -63,7 +63,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasReadOnly() throws Exception { + public void when_hasReadOnly() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+readonly"); assertThat(res.readOnly).isTrue(); @@ -71,7 +71,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasLazy() throws Exception { + public void when_hasLazy() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy"); assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(0); @@ -79,7 +79,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasLazyValue() throws Exception { + public void when_hasLazyValue() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy(20)"); assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(20); @@ -87,7 +87,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasLazyValue_last() throws Exception { + public void when_hasLazyValue_last() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("name,+lazy(20)"); assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(20); @@ -95,7 +95,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_hasLazyValue_first() throws Exception { + public void when_hasLazyValue_first() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+lazy(20),id,name"); assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(20); @@ -103,7 +103,7 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_allProperties() throws Exception { + public void when_allProperties() { OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("+query(4),+lazy(5)"); assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(5); @@ -111,14 +111,21 @@ public class OrmQueryPropertiesParserTest { } @Test - public void when_everything_set() throws Exception { + public void when_everything_set() { - OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("id, name +readonly +lazy(20) +query(30) +cache"); + OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("id, name, +readonly ,+lazy(20), +query(30) ,+cache"); + assertThat(res.included).containsExactly("id", "name"); assertThat(res.fetchConfig.getLazyBatchSize()).isEqualTo(20); assertThat(res.fetchConfig.getQueryBatchSize()).isEqualTo(30); assertThat(res.readOnly).isTrue(); assertThat(res.cache).isTrue(); - assertThat(res.included).containsExactly("id", "name"); + } + + @Test + public void when_formula() { + + OrmQueryPropertiesParser.Response res = OrmQueryPropertiesParser.parse("a,MD5(id::text) as b,c"); + assertThat(res.included).containsExactly("a", "MD5(id::text) as b", "c"); } private void assertAllDefaults(OrmQueryPropertiesParser.Response res) { diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesTest.java index 547ea5966..196eb09a5 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesTest.java @@ -10,11 +10,11 @@ public class OrmQueryPropertiesTest { String append(String prefix, OrmQueryProperties p1) { StringBuilder sb = new StringBuilder(); - p1.append(prefix, sb); + p1.asStringDebug(prefix, sb); return sb.toString(); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = NullPointerException.class) public void construct_with_propertySet_when_null() { new OrmQueryProperties(null, (LinkedHashSet) null); } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/util/DSelectColumnsParserTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/util/DSelectColumnsParserTest.java index 0b30e225c..cc9234925 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/util/DSelectColumnsParserTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/util/DSelectColumnsParserTest.java @@ -2,7 +2,7 @@ package io.ebeaninternal.server.util; import org.junit.Test; -import java.util.List; +import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; @@ -11,49 +11,49 @@ public class DSelectColumnsParserTest { @Test public void parse() { - List cols = DSelectColumnsParser.parse("a,MD5(id::text) as b,c"); + Set cols = DSelectColumnsParser.parse("a,MD5(id::text) as b,c"); assertThat(cols).containsExactly("a", "MD5(id::text) as b", "c"); } @Test public void whitespace_is_trimmed() { - List cols = DSelectColumnsParser.parse("a , MD5(id::text) as b , c "); + Set cols = DSelectColumnsParser.parse("a , MD5(id::text) as b , c "); assertThat(cols).containsExactly("a", "MD5(id::text) as b", "c"); } @Test public void nestedFunctions() { - List cols = DSelectColumnsParser.parse("a , concat(id,'sd',inner(foo)) as b , c "); + Set cols = DSelectColumnsParser.parse("a , concat(id,'sd',inner(foo)) as b , c "); assertThat(cols).containsExactly("a", "concat(id,'sd',inner(foo)) as b", "c"); } @Test public void basic() { - List cols = DSelectColumnsParser.parse("name , status , billingAddress "); + Set cols = DSelectColumnsParser.parse("name , status , billingAddress "); assertThat(cols).containsExactly("name", "status", "billingAddress"); } @Test public void basic_noWhitespace() { - List cols = DSelectColumnsParser.parse("a,b,c"); + Set cols = DSelectColumnsParser.parse("a,b,c"); assertThat(cols).containsExactly("a", "b", "c"); } @Test public void formula_noWhitespace() { - List cols = DSelectColumnsParser.parse("a,concat(x,y),c"); + Set cols = DSelectColumnsParser.parse("a,concat(x,y),c"); assertThat(cols).containsExactly("a", "concat(x,y)", "c"); } @Test public void with_logicalCast_andAsAlias() { - List cols = DSelectColumnsParser.parse("name , concat(status,'-end')::String as fullName , billingAddress "); + Set cols = DSelectColumnsParser.parse("name , concat(status,'-end')::String as fullName , billingAddress "); assertThat(cols).containsExactly("name", "concat(status,'-end')::String as fullName", "billingAddress"); } diff --git a/ebean-core/src/test/java/org/tests/batchload/TestQueryJoin.java b/ebean-core/src/test/java/org/tests/batchload/TestQueryJoin.java index 1cbe7fd48..81bac2193 100644 --- a/ebean-core/src/test/java/org/tests/batchload/TestQueryJoin.java +++ b/ebean-core/src/test/java/org/tests/batchload/TestQueryJoin.java @@ -28,7 +28,7 @@ public class TestQueryJoin extends BaseTestCase { Query query = Ebean.find(Order.class).select("status") // .join("details","+query(10)") - .fetch("customer", "+lazy(10) name, status").fetch("customer.contacts").order().asc("id"); + .fetch("customer", "+lazy(10), name, status").fetch("customer.contacts").order().asc("id"); // .join("customer.billingAddress"); List list = query.findList();