From f7a11135a5973a2eab184a1a9c9e64b7753da3d3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 23 Mar 2023 22:11:02 +1300 Subject: [PATCH 1/5] Refactor rename methods in LoadContext Rename internal methods only --- .../main/java/io/ebean/bean/BeanLoader.java | 2 +- .../io/ebean/bean/InterceptReadWrite.java | 4 +- .../java/io/ebean/bean/SingleBeanLoader.java | 2 +- .../io/ebeaninternal/api/LoadContext.java | 6 +- .../io/ebeaninternal/api/LoadManyBuffer.java | 10 ++-- .../io/ebeaninternal/api/LoadManyRequest.java | 10 ++-- .../server/core/OrmQueryRequest.java | 2 +- .../server/loadcontext/DLoadBaseContext.java | 14 ++--- .../server/loadcontext/DLoadBeanContext.java | 6 +- .../server/loadcontext/DLoadContext.java | 55 +++++++------------ .../server/loadcontext/DLoadManyContext.java | 26 ++++----- .../io/ebeaninternal/server/query/CQuery.java | 2 +- 12 files changed, 61 insertions(+), 78 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/bean/BeanLoader.java b/ebean-api/src/main/java/io/ebean/bean/BeanLoader.java index 5bfbfda08..19e784161 100644 --- a/ebean-api/src/main/java/io/ebean/bean/BeanLoader.java +++ b/ebean-api/src/main/java/io/ebean/bean/BeanLoader.java @@ -13,7 +13,7 @@ public interface BeanLoader { /** * Return the name of the associated Database. */ - String getName(); + String name(); /** * Invoke the lazy loading for this bean. diff --git a/ebean-api/src/main/java/io/ebean/bean/InterceptReadWrite.java b/ebean-api/src/main/java/io/ebean/bean/InterceptReadWrite.java index 6253dcde0..9f8767212 100644 --- a/ebean-api/src/main/java/io/ebean/bean/InterceptReadWrite.java +++ b/ebean-api/src/main/java/io/ebean/bean/InterceptReadWrite.java @@ -192,13 +192,13 @@ public final class InterceptReadWrite implements EntityBeanIntercept { public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) { this.beanLoader = beanLoader; this.persistenceContext = ctx; - this.ebeanServerName = beanLoader.getName(); + this.ebeanServerName = beanLoader.name(); } @Override public void setBeanLoader(BeanLoader beanLoader) { this.beanLoader = beanLoader; - this.ebeanServerName = beanLoader.getName(); + this.ebeanServerName = beanLoader.name(); } @Override diff --git a/ebean-api/src/main/java/io/ebean/bean/SingleBeanLoader.java b/ebean-api/src/main/java/io/ebean/bean/SingleBeanLoader.java index 73f3fe5d8..c9247ed3a 100644 --- a/ebean-api/src/main/java/io/ebean/bean/SingleBeanLoader.java +++ b/ebean-api/src/main/java/io/ebean/bean/SingleBeanLoader.java @@ -19,7 +19,7 @@ public abstract class SingleBeanLoader implements BeanLoader { } @Override - public String getName() { + public String name() { return database.name(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/LoadContext.java b/ebean-core/src/main/java/io/ebeaninternal/api/LoadContext.java index 9d70c448f..57a725f26 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/LoadContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/LoadContext.java @@ -16,7 +16,7 @@ public interface LoadContext { /** * Return the minimum batch size when using QueryIterator with query joins. */ - int getSecondaryQueriesMinBatchSize(); + int secondaryQueriesMinBatchSize(); /** * Execute any secondary (+query) queries if there are any defined. @@ -29,12 +29,12 @@ public interface LoadContext { /** * Return the node for a given path which is used by AutoTune profiling. */ - ObjectGraphNode getObjectGraphNode(String path); + ObjectGraphNode objectGraphNode(String path); /** * Return the persistence context used by this query and future lazy loading. */ - PersistenceContext getPersistenceContext(); + PersistenceContext persistenceContext(); /** * Register a Bean for lazy loading. diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/LoadManyBuffer.java b/ebean-core/src/main/java/io/ebeaninternal/api/LoadManyBuffer.java index 43bff710f..ccd7e9c88 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/LoadManyBuffer.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/LoadManyBuffer.java @@ -31,15 +31,15 @@ public interface LoadManyBuffer { */ boolean removeFromBuffer(BeanCollection collection); - BeanPropertyAssocMany getBeanProperty(); + BeanPropertyAssocMany beanProperty(); - ObjectGraphNode getObjectGraphNode(); + ObjectGraphNode objectGraphNode(); - BeanDescriptor getBeanDescriptor(); + BeanDescriptor descriptor(); - PersistenceContext getPersistenceContext(); + PersistenceContext persistenceContext(); - String getFullPath(); + String fullPath(); void configureQuery(SpiQuery query); diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/LoadManyRequest.java b/ebean-core/src/main/java/io/ebeaninternal/api/LoadManyRequest.java index 7aef79279..814cad7c1 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/LoadManyRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/LoadManyRequest.java @@ -50,11 +50,11 @@ public final class LoadManyRequest extends LoadRequest { @Override public Class beanType() { - return loadContext.getBeanDescriptor().type(); + return loadContext.descriptor().type(); } public String description() { - return loadContext.getFullPath(); + return loadContext.fullPath(); } private List parentIdList(SpiEbeanServer server) { @@ -82,7 +82,7 @@ public final class LoadManyRequest extends LoadRequest { } private BeanPropertyAssocMany many() { - return loadContext.getBeanProperty(); + return loadContext.beanProperty(); } public SpiQuery createQuery(SpiEbeanServer server) { @@ -100,7 +100,7 @@ public final class LoadManyRequest extends LoadRequest { } query.setLazyLoadForParents(many); many.addWhereParentIdIn(query, parentIdList(server), loadContext.isUseDocStore()); - query.setPersistenceContext(loadContext.getPersistenceContext()); + query.setPersistenceContext(loadContext.persistenceContext()); query.setLoadDescription(lazy ? "+lazy" : "+query", description()); if (lazy) { query.setLazyLoadBatchSize(loadContext.batchSize()); @@ -120,7 +120,7 @@ public final class LoadManyRequest extends LoadRequest { * After the query execution check for empty collections and load L2 cache if desired. */ public void postLoad() { - BeanDescriptor desc = loadContext.getBeanDescriptor(); + BeanDescriptor desc = loadContext.descriptor(); BeanPropertyAssocMany many = many(); // check for BeanCollection's that where never processed // in the +query or +lazy load due to no rows (predicates) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index 75b3cbf72..8c1813256 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -127,7 +127,7 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery * iteration is fine. */ public int secondaryQueriesMinBatchSize() { - return loadContext.getSecondaryQueriesMinBatchSize(); + return loadContext.secondaryQueriesMinBatchSize(); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java index 4ab63bec0..1cd3ef214 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java @@ -35,12 +35,12 @@ abstract class DLoadBaseContext { DLoadBaseContext(DLoadContext parent, BeanDescriptor desc, String path, OrmQueryProperties queryProps) { this.parent = parent; - this.serverName = parent.getEbeanServer().name(); + this.serverName = parent.server().name(); this.desc = desc; this.queryProps = queryProps; - this.fullPath = parent.getFullPath(path); + this.fullPath = parent.fullPath(path); this.hitCache = parent.isBeanCacheGet() && desc.isBeanCaching(); - this.objectGraphNode = parent.getObjectGraphNode(path); + this.objectGraphNode = parent.objectGraphNode(path); this.queryFetch = queryProps != null && queryProps.isQueryFetch(); this.batchSize = parent.batchSize(queryProps); } @@ -50,14 +50,14 @@ abstract class DLoadBaseContext { * set onto the secondary query. */ void setLabel(SpiQuery query) { - String label = parent.getPlanLabel(); + String label = parent.planLabel(); if (label != null) { - query.setProfilePath(label, fullPath, parent.getProfileLocation()); + query.setProfilePath(label, fullPath, parent.profileLocation()); } } - PersistenceContext getPersistenceContext() { - return parent.getPersistenceContext(); + PersistenceContext persistenceContext() { + return parent.persistenceContext(); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java index dc4555934..53c0c8110 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java @@ -71,7 +71,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext if (currentBuffer.isFull()) { currentBuffer = createBuffer(batchSize); } - ebi.setBeanLoader(currentBuffer, getPersistenceContext()); + ebi.setBeanLoader(currentBuffer, persistenceContext()); currentBuffer.add(ebi); } @@ -93,7 +93,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext if (bufferList != null) { for (LoadBuffer loadBuffer : bufferList) { if (!loadBuffer.batch.isEmpty()) { - parent.getEbeanServer().loadBean(new LoadBeanRequest(loadBuffer, parentRequest)); + parent.server().loadBean(new LoadBeanRequest(loadBuffer, parentRequest)); } if (forEach) { clear(); @@ -165,7 +165,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext } @Override - public String getName() { + public String name() { return context.serverName; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java index dd0cbc9f8..999cb927e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java @@ -2,24 +2,11 @@ package io.ebeaninternal.server.loadcontext; import io.ebean.CacheMode; import io.ebean.ProfileLocation; -import io.ebean.bean.BeanCollection; -import io.ebean.bean.CallOrigin; -import io.ebean.bean.EntityBeanIntercept; -import io.ebean.bean.ObjectGraphNode; -import io.ebean.bean.ObjectGraphOrigin; -import io.ebean.bean.PersistenceContext; -import io.ebeaninternal.api.LoadContext; -import io.ebeaninternal.api.LoadSecondaryQuery; -import io.ebeaninternal.api.SpiEbeanServer; -import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.api.SpiQuerySecondary; +import io.ebean.bean.*; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.autotune.ProfilingListener; import io.ebeaninternal.server.core.OrmQueryRequest; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.BeanPropertyAssoc; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; -import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; +import io.ebeaninternal.server.deploy.*; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.querydefn.OrmQueryProperties; @@ -127,14 +114,14 @@ public final class DLoadContext implements LoadContext { /** * Return the query plan label of the origin query. */ - String getPlanLabel() { + String planLabel() { return planLabel; } /** * Return the profile location of the origin query. */ - public ProfileLocation getProfileLocation() { + public ProfileLocation profileLocation() { return profileLocation; } @@ -179,7 +166,7 @@ public final class DLoadContext implements LoadContext { * Return the minimum batch size when using QueryIterator with query joins. */ @Override - public int getSecondaryQueriesMinBatchSize() { + public int secondaryQueriesMinBatchSize() { if (secQuery == null) { return -1; } @@ -201,7 +188,7 @@ public final class DLoadContext implements LoadContext { public void executeSecondaryQueries(OrmQueryRequest parentRequest, boolean forEach) { if (secQuery != null) { for (OrmQueryProperties aSecQuery : secQuery) { - LoadSecondaryQuery load = getLoadSecondaryQuery(aSecQuery.getPath()); + LoadSecondaryQuery load = loadSecondaryQuery(aSecQuery.getPath()); load.loadSecondaryQuery(parentRequest, forEach); } } @@ -210,13 +197,13 @@ public final class DLoadContext implements LoadContext { /** * Return the LoadBeanContext or LoadManyContext for the given path. */ - private LoadSecondaryQuery getLoadSecondaryQuery(String path) { + private LoadSecondaryQuery loadSecondaryQuery(String path) { LoadSecondaryQuery beanLoad = beanMap.get(path); return beanLoad == null ? manyMap.get(path) : beanLoad; } @Override - public ObjectGraphNode getObjectGraphNode(String path) { + public ObjectGraphNode objectGraphNode(String path) { return nodePathMap.computeIfAbsent(path, this::createObjectGraphNode); } @@ -231,7 +218,7 @@ public final class DLoadContext implements LoadContext { return new ObjectGraphNode(origin, path); } - String getFullPath(String path) { + String fullPath(String path) { if (relativePath == null) { return path; } else { @@ -239,7 +226,7 @@ public final class DLoadContext implements LoadContext { } } - SpiEbeanServer getEbeanServer() { + SpiEbeanServer server() { return ebeanServer; } @@ -252,23 +239,23 @@ public final class DLoadContext implements LoadContext { } @Override - public PersistenceContext getPersistenceContext() { + public PersistenceContext persistenceContext() { return persistenceContext; } @Override public void register(String path, EntityBeanIntercept ebi) { - getBeanContext(path).register(ebi); + beanContext(path).register(ebi); } @Override public void register(String path, EntityBeanIntercept ebi, BeanPropertyAssocOne property) { - getBeanContextWithInherit(path, property).register(ebi); + beanContextWithInherit(path, property).register(ebi); } @Override public void register(String path, BeanPropertyAssocMany many, BeanCollection bc) { - getManyContext(path, many).register(bc); + manyContext(path, many).register(bc); } int batchSize(OrmQueryProperties props) { @@ -279,14 +266,14 @@ public final class DLoadContext implements LoadContext { return batchSize == 0 ? defaultBatchSize : batchSize; } - DLoadBeanContext getBeanContext(String path) { + DLoadBeanContext beanContext(String path) { if (path == null) { return rootBeanContext; } return beanMap.computeIfAbsent(path, p -> createBeanContext(p, null)); } - DLoadBeanContext getBeanContextWithInherit(String path, BeanPropertyAssocOne property) { + DLoadBeanContext beanContextWithInherit(String path, BeanPropertyAssocOne property) { String key = path + ":" + property.targetDescriptor().name(); return beanMap.computeIfAbsent(key, p -> createBeanContext(property, path)); } @@ -300,7 +287,7 @@ public final class DLoadContext implements LoadContext { } } - DLoadManyContext getManyContext(String path, BeanPropertyAssocMany many) { + DLoadManyContext manyContext(String path, BeanPropertyAssocMany many) { return manyMap.computeIfAbsent(path, p -> createManyContext(p, many)); } @@ -309,12 +296,12 @@ public final class DLoadContext implements LoadContext { } private DLoadManyContext createManyContext(String path, OrmQueryProperties queryProps) { - BeanPropertyAssocMany p = (BeanPropertyAssocMany) getBeanProperty(rootDescriptor, path); + BeanPropertyAssocMany p = (BeanPropertyAssocMany) beanProperty(rootDescriptor, path); return new DLoadManyContext(this, p, path, queryProps); } private DLoadBeanContext createBeanContext(String path, OrmQueryProperties queryProps) { - BeanPropertyAssoc p = (BeanPropertyAssoc) getBeanProperty(rootDescriptor, path); + BeanPropertyAssoc p = (BeanPropertyAssoc) beanProperty(rootDescriptor, path); return new DLoadBeanContext(this, p.targetDescriptor(), path, queryProps); } @@ -322,7 +309,7 @@ public final class DLoadContext implements LoadContext { return new DLoadBeanContext(this, property.targetDescriptor(), path, null); } - private BeanProperty getBeanProperty(BeanDescriptor desc, String path) { + private BeanProperty beanProperty(BeanDescriptor desc, String path) { return desc.findPropertyFromPath(path); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java index c9c532ae2..cbe85ab5f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java @@ -1,10 +1,6 @@ package io.ebeaninternal.server.loadcontext; -import io.ebean.bean.BeanCollection; -import io.ebean.bean.BeanCollectionLoader; -import io.ebean.bean.EntityBean; -import io.ebean.bean.ObjectGraphNode; -import io.ebean.bean.PersistenceContext; +import io.ebean.bean.*; import io.ebeaninternal.api.LoadManyBuffer; import io.ebeaninternal.api.LoadManyContext; import io.ebeaninternal.api.LoadManyRequest; @@ -77,7 +73,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext public String getName() { - return parent.getEbeanServer().name(); + return parent.server().name(); } public void register(BeanCollection bc) { @@ -99,7 +95,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext for (LoadBuffer loadBuffer : bufferList) { if (loadBuffer.size() > 0) { LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest); - parent.getEbeanServer().loadMany(req); + parent.server().loadMany(req); } } if (forEach) { @@ -129,7 +125,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext this.context = context; // set the persistence context as at this moment in // case it changes as part of a findIterate etc - this.persistenceContext = context.getPersistenceContext(); + this.persistenceContext = context.persistenceContext(); this.batchSize = batchSize; } @@ -158,12 +154,12 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext abstract void clear(); @Override - public BeanPropertyAssocMany getBeanProperty() { + public BeanPropertyAssocMany beanProperty() { return context.property; } @Override - public ObjectGraphNode getObjectGraphNode() { + public ObjectGraphNode objectGraphNode() { return context.objectGraphNode; } @@ -178,17 +174,17 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext } @Override - public BeanDescriptor getBeanDescriptor() { + public BeanDescriptor descriptor() { return context.desc; } @Override - public PersistenceContext getPersistenceContext() { + public PersistenceContext persistenceContext() { return persistenceContext; } @Override - public String getFullPath() { + public String fullPath() { return context.fullPath; } @@ -205,14 +201,14 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext if (parentDesc.cacheManyPropLoad(context.property, bc, parentKey, context.parent.isReadOnly())) { // we loaded the bean collection from cache so remove it from the buffer if (removeFromBuffer(bc)) { - bc.setLoader(context.parent.getEbeanServer()); + bc.setLoader(context.parent.server()); } // find it using instance equality - avoiding equals() and potential deadlock issue return; } } - context.parent.getEbeanServer().loadMany(new LoadManyRequest(this, onlyIds, useCache, bc)); + context.parent.server().loadMany(new LoadManyRequest(this, onlyIds, useCache, bc)); // clear the buffer as all entries have been loaded clear(); } finally { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java index 6fc84bfb5..fd19f57d3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java @@ -661,7 +661,7 @@ public final class CQuery implements DbReadContext, CancelableQuery, SpiProfi @Override public void profileBean(EntityBeanIntercept ebi, String prefix) { - ObjectGraphNode node = request.loadContext().getObjectGraphNode(prefix); + ObjectGraphNode node = request.loadContext().objectGraphNode(prefix); ebi.setNodeUsageCollector(new NodeUsageCollector(node, profilingListener)); } From 9982fa3682a9452383bab436b2057afac41fcea6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 24 Mar 2023 17:37:34 +1300 Subject: [PATCH 2/5] Refactor SpiExpressionRequest split append() into append() and parse() - append() adds to the sql with NO parsing - parse() adds to the sql with parsing to replace logical bean paths into table alias placeholder + db column --- .../api/SpiExpressionRequest.java | 5 ++ .../server/deploy/BeanPropertyAssocMany.java | 2 +- .../expression/AllEqualsExpression.java | 8 +- .../server/expression/BetweenExpression.java | 2 +- .../expression/BetweenPropertyExpression.java | 8 +- .../CaseInsensitiveEqualExpression.java | 4 +- .../expression/DefaultExpressionRequest.java | 13 ++- .../expression/ExistsQueryExpression.java | 4 +- .../server/expression/IdExpression.java | 10 +-- .../server/expression/IdInExpression.java | 20 ++--- .../server/expression/InExpression.java | 7 +- .../server/expression/InPairsExpression.java | 7 +- .../server/expression/InRangeExpression.java | 2 +- .../server/expression/IsEmptyExpression.java | 7 +- .../server/expression/LikeExpression.java | 4 +- .../expression/NativeILikeExpression.java | 4 +- .../server/expression/NullExpression.java | 8 +- .../server/expression/RawExpression.java | 8 +- .../server/expression/SimpleExpression.java | 11 ++- .../server/expression/SubQueryExpression.java | 2 +- .../expression/platform/BaseDbExpression.java | 4 +- .../expression/platform/H2DbExpression.java | 2 +- .../expression/platform/HanaDbExpression.java | 8 +- .../platform/MariaDbExpression.java | 3 +- .../platform/MySqlDbExpression.java | 3 +- .../platform/OracleDbExpression.java | 7 +- .../platform/PostgresDbExpression.java | 24 +++--- .../platform/SqlServerDbExpression.java | 3 +- .../server/query/CQueryPredicates.java | 80 ++++--------------- .../expression/TDSpiExpressionRequest.java | 6 ++ 30 files changed, 97 insertions(+), 179 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java index e61c9479e..cd68c4a5c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java @@ -36,6 +36,11 @@ public interface SpiExpressionRequest { */ SpiExpressionRequest append(String sql); + /** + * Append to the expression sql with logical property parsing to db columns with logical path prefix. + */ + SpiExpressionRequest parse(String sql); + /** * Add an encryption key to bind to this request. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 0cd13f64b..bd80bc795 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -416,7 +416,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST public String assocIsEmpty(SpiExpressionRequest request, String path) { boolean softDelete = targetDescriptor.isSoftDelete(); boolean needsX2Table = softDelete || extraWhere() != null; - StringBuilder sb = new StringBuilder(50); + StringBuilder sb = new StringBuilder(50).append("from "); // use from to stop parsing on table name SpiQuery query = request.getQueryRequest().query(); if (hasJoinTable()) { sb.append(query.isAsDraft() ? intersectionDraftTable : intersectionPublishTable); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/AllEqualsExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/AllEqualsExpression.java index 52d31c6dc..944e3375b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/AllEqualsExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/AllEqualsExpression.java @@ -1,10 +1,6 @@ package io.ebeaninternal.server.expression; -import io.ebeaninternal.api.BindValuesKey; -import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.api.SpiExpressionValidation; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.el.ElPropertyDeploy; @@ -80,7 +76,7 @@ final class AllEqualsExpression extends NonPrepareExpression { if (count > 0) { request.append("and "); } - request.append(name(propName)); + request.parse(name(propName)); if (value == null) { request.append(" is null "); } else { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenExpression.java index 36b0260d0..e7f480cb7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenExpression.java @@ -52,7 +52,7 @@ final class BetweenExpression extends AbstractExpression { if (prop != null && prop.isDbEncrypted()) { pname = prop.beanProperty().decryptProperty(propName); } - request.append(pname).append(_BETWEEN); + request.parse(pname).append(_BETWEEN); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java index 0dfa1fc33..40f38428d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java @@ -1,11 +1,7 @@ package io.ebeaninternal.server.expression; import io.ebean.util.SplitName; -import io.ebeaninternal.api.BindValuesKey; -import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.api.SpiExpressionValidation; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.el.ElPropertyDeploy; @@ -85,7 +81,7 @@ final class BetweenPropertyExpression extends NonPrepareExpression { @Override public void addSql(SpiExpressionRequest request) { - request.append(" ?").append(BETWEEN).append(name(lowProperty)).append(" and ").append(name(highProperty)); + request.append(" ?").append(BETWEEN).parse(name(lowProperty)).append(" and ").parse(name(highProperty)); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java index 0d9f39fc5..d1010f501 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java @@ -52,9 +52,9 @@ final class CaseInsensitiveEqualExpression extends AbstractValueExpression { pname = prop.beanProperty().decryptProperty(propName); } if (not) { - request.append("lower(").append(pname).append(") != ?"); + request.append("lower(").parse(pname).append(") != ?"); } else { - request.append("lower(").append(pname).append(") = ?"); + request.append("lower(").parse(pname).append(") = ?"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java index d1b1f4040..8ce43712d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java @@ -2,12 +2,12 @@ package io.ebeaninternal.server.expression; import io.ebeaninternal.api.SpiExpressionList; import io.ebeaninternal.api.SpiExpressionRequest; +import io.ebeaninternal.server.bind.DataBind; import io.ebeaninternal.server.core.SpiOrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.DeployParser; import io.ebeaninternal.server.expression.platform.DbExpressionHandler; import io.ebeaninternal.server.persist.Binder; -import io.ebeaninternal.server.bind.DataBind; import java.sql.SQLException; import java.util.ArrayList; @@ -73,7 +73,6 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest { @Override public String parseDeploy(String logicalProp) { - String s = deployParser.getDeployWord(logicalProp); return s == null ? logicalProp : s; } @@ -120,6 +119,16 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest { return this; } + @Override + public SpiExpressionRequest parse(String expression) { + if (deployParser == null) { + sql.append(expression); + } else { + sql.append(deployParser.parse(expression)); + } + return this; + } + @Override public void addBindEncryptKey(Object bindValue) { bindValues.add(bindValue); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java index 4a8717e4c..30b40d53f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java @@ -95,9 +95,7 @@ final class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreE if (not) { request.append(" not"); } - request.append(" exists ("); - request.append(sql); - request.append(")"); + request.append(" exists (").parse(sql).append(")"); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java index 34e49bcc1..012cafad0 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java @@ -1,10 +1,6 @@ package io.ebeaninternal.server.expression; -import io.ebeaninternal.api.BindValuesKey; -import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.api.SpiExpressionValidation; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.deploy.BeanDescriptor; import java.io.IOException; @@ -62,11 +58,9 @@ final class IdExpression extends NonPrepareExpression implements SpiExpression { @Override public void addSql(SpiExpressionRequest request) { - DefaultExpressionRequest r = (DefaultExpressionRequest) request; String idSql = r.getBeanDescriptor().idBinderIdSql(null); - - request.append(idSql); + request.parse(idSql); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java index 6e5b5a62a..b3ad3c75a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java @@ -1,21 +1,13 @@ package io.ebeaninternal.server.expression; import io.ebean.event.BeanQueryRequest; -import io.ebeaninternal.api.BindValuesKey; -import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.api.SpiExpressionValidation; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.core.BindPadding; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.id.IdBinder; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Set; +import java.util.*; /** * In a collection of ID values. @@ -74,7 +66,6 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo return; } // Bind the ID values including EmbeddedId and multiple ID - DefaultExpressionRequest r = (DefaultExpressionRequest) request; BeanDescriptor descriptor = r.getBeanDescriptor(); IdBinder idBinder = descriptor.idBinder(); @@ -85,14 +76,13 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo * For use with deleting non-attached detail beans during stateless update. */ public void addSqlNoAlias(SpiExpressionRequest request) { - DefaultExpressionRequest r = (DefaultExpressionRequest) request; BeanDescriptor descriptor = r.getBeanDescriptor(); IdBinder idBinder = descriptor.idBinder(); if (idCollection.isEmpty()) { request.append(SQL_FALSE); // append false for this stage } else { - request.append(descriptor.idBinder().getBindIdInSql(null)); + request.parse(descriptor.idBinder().getBindIdInSql(null)); String inClause = idBinder.getIdInValueExpr(false, idCollection.size()); request.append(inClause); } @@ -106,10 +96,10 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo request.append(SQL_FALSE); // append false for this stage } else { if (idBinder.isComplexId()) { - request.append(descriptor.idBinderInLHSSql()); + request.parse(descriptor.idBinderInLHSSql()); request.append(idBinder.getIdInValueExpr(false, idCollection.size())); } else { - request.append(idBinder.getBeanProperty().name()); + request.parse(idBinder.getBeanProperty().name()); request.appendInExpression(false, idCollection); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InExpression.java index 127f849e9..02d301e6d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InExpression.java @@ -156,21 +156,20 @@ public final class InExpression extends AbstractExpression implements IdInCommon request.append(not ? SQL_TRUE : SQL_FALSE); return; } - ElPropertyValue prop = getElProp(request); if (prop != null) { if (prop.isAssocId()) { - request.append(prop.assocIdInExpr(propName)); + request.parse(prop.assocIdInExpr(propName)); request.append(prop.assocIdInValueExpr(not, bindValues.size())); return; } if (prop.isDbEncrypted()) { - request.append(prop.beanProperty().decryptProperty(propName)); + request.parse(prop.beanProperty().decryptProperty(propName)); request.appendInExpression(not, bindValues); return; } } - request.append(propName); + request.parse(propName); request.appendInExpression(not, bindValues); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java index 5066b4047..e654c7d92 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java @@ -85,14 +85,11 @@ final class InPairsExpression extends AbstractExpression { @Override public void addSql(SpiExpressionRequest request) { - if (entries.isEmpty()) { - String expr = not ? SQL_TRUE : SQL_FALSE; - request.append(expr); + request.append(not ? SQL_TRUE : SQL_FALSE); return; } - - request.append(request.getDbPlatformHandler().concat(property0, separator, property1, suffix)); + request.parse(request.getDbPlatformHandler().concat(property0, separator, property1, suffix)); request.appendInExpression(not, concatBindValues); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InRangeExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InRangeExpression.java index b0d2522c4..be455e71e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InRangeExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InRangeExpression.java @@ -55,7 +55,7 @@ final class InRangeExpression extends AbstractExpression { if (prop != null && prop.isDbEncrypted()) { pname = prop.beanProperty().decryptProperty(propName); } - request.append("(").append(pname).append(" >= ? and ").append(pname).append(" < ?)"); + request.append("(").parse(pname).append(" >= ? and ").parse(pname).append(" < ?)"); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IsEmptyExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IsEmptyExpression.java index e635d4ea0..de426f425 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IsEmptyExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IsEmptyExpression.java @@ -1,12 +1,12 @@ package io.ebeaninternal.server.expression; +import io.ebean.util.SplitName; import io.ebeaninternal.api.BindValuesKey; import io.ebeaninternal.api.ManyWhereJoins; import io.ebeaninternal.api.SpiExpression; import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.el.ElPropertyValue; -import io.ebean.util.SplitName; import java.io.IOException; @@ -78,13 +78,12 @@ final class IsEmptyExpression extends AbstractExpression { * Append an exists subQuery for the property. */ static void isEmptySql(SpiExpressionRequest request, ElPropertyValue prop, boolean empty, String propertyPath) { - if (empty) { request.append("not "); } request - .append("exists (select 1 from ") - .append(prop.assocIsEmpty(request, propertyPath)) + .append("exists (select 1 ") + .parse(prop.assocIsEmpty(request, propertyPath)) .append(")"); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/LikeExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/LikeExpression.java index e0b137154..e85d984d3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/LikeExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/LikeExpression.java @@ -44,9 +44,9 @@ final class LikeExpression extends AbstractValueExpression { pname = prop.beanProperty().decryptProperty(propName); } if (caseInsensitive) { - request.append("lower(").append(pname).append(")"); + request.append("lower(").parse(pname).append(")"); } else { - request.append(pname); + request.parse(pname); } if (type == LikeType.EQUAL_TO) { request.append(" = ?"); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NativeILikeExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NativeILikeExpression.java index 9977c92e2..9527e922d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NativeILikeExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NativeILikeExpression.java @@ -36,14 +36,12 @@ final class NativeILikeExpression extends AbstractExpression { @Override public void addSql(SpiExpressionRequest request) { - String pname = propName; ElPropertyValue prop = getElProp(request); if (prop != null && prop.isDbEncrypted()) { pname = prop.beanProperty().decryptProperty(propName); } - - request.append(pname).append(" ilike ?"); + request.parse(pname).append(" ilike ?"); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NullExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NullExpression.java index 0c3eb00b5..ab1f1a7c3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NullExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NullExpression.java @@ -57,18 +57,16 @@ final class NullExpression extends AbstractExpression { @Override public void addSql(SpiExpressionRequest request) { - if (assocMany) { - // translate to exists subquery + // translate to exists sub-query IsEmptyExpression.isEmptySql(request, elProperty, !notNull, propertyPath); return; } - String nullExpr = notNull ? " is not null" : " is null"; if (elProperty != null && elProperty.isAssocId()) { - request.append(elProperty.assocIdExpression(propName, nullExpr)); + request.parse(elProperty.assocIdExpression(propName, nullExpr)); } else { - request.append(propName).append(nullExpr); + request.parse(propName).append(nullExpr); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/RawExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/RawExpression.java index 53571cad7..72c968e28 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/RawExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/RawExpression.java @@ -1,10 +1,6 @@ package io.ebeaninternal.server.expression; -import io.ebeaninternal.api.BindValuesKey; -import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.api.SpiExpressionValidation; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.persist.MultiValueWrapper; @@ -57,7 +53,7 @@ final class RawExpression extends NonPrepareExpression { @Override public void addSql(SpiExpressionRequest request) { - request.append(sql); + request.parse(sql); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SimpleExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SimpleExpression.java index 5c3efb5e0..21b4a452c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SimpleExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SimpleExpression.java @@ -2,11 +2,11 @@ package io.ebeaninternal.server.expression; import io.ebean.bean.EntityBean; import io.ebean.plugin.ExpressionPath; +import io.ebeaninternal.api.BindValuesKey; +import io.ebeaninternal.api.NaturalKeyQueryData; import io.ebeaninternal.api.SpiExpression; import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.el.ElPropertyValue; -import io.ebeaninternal.api.BindValuesKey; -import io.ebeaninternal.api.NaturalKeyQueryData; import java.io.IOException; import java.util.Arrays; @@ -97,20 +97,19 @@ public final class SimpleExpression extends AbstractValueExpression { @Override public void addSql(SpiExpressionRequest request) { - ElPropertyValue prop = getElProp(request); if (prop != null) { if (prop.isAssocId()) { - request.append(prop.assocIdExpression(propName, type.bind())); + request.parse(prop.assocIdExpression(propName, type.bind())); return; } if (prop.isDbEncrypted()) { String dsql = prop.beanProperty().decryptProperty(propName); - request.append(dsql).append(type.bind()); + request.parse(dsql).append(type.bind()); return; } } - request.append(propName).append(type.bind()); + request.parse(propName).append(type.bind()); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java index 8a2ae7c80..aaa5a0eb6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java @@ -90,7 +90,7 @@ final class SubQueryExpression extends AbstractExpression implements Unsupported @Override public void addSql(SpiExpressionRequest request) { - request.append(propName).append(op.expression).append("(").append(sql).append(")"); + request.parse(propName).append(op.expression).append("(").parse(sql).append(")"); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java index a8d4d6adc..420e91451 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java @@ -11,7 +11,7 @@ abstract class BaseDbExpression implements DbExpressionHandler { @Override public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { String bitOp = bitOp(operator); - request.append("(").append(propName).append(" ").append(bitOp).append(" ? ").append(compare).append(" ?)"); + request.append("(").parse(propName).append(" ").append(bitOp).append(" ? ").append(compare).append(" ?)"); } private String bitOp(BitwiseOp operator) { @@ -30,7 +30,7 @@ abstract class BaseDbExpression implements DbExpressionHandler { */ protected void bitwiseFunction(SpiExpressionRequest request, String propName, BitwiseOp operator, String compare) { String funcName = functionName(operator); - request.append(funcName).append("(").append(propName).append(", ?) ").append(compare).append(" ?"); + request.append(funcName).append("(").parse(propName).append(", ?) ").append(compare).append(" ?"); } protected String functionName(BitwiseOp operator) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java index 60cb180d3..b3fcd3d37 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java @@ -11,6 +11,6 @@ final class H2DbExpression extends BasicDbExpression { @Override public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { String funcName = functionName(operator); - request.append(funcName).append("(").append(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)"); + request.append(funcName).append("(").parse(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java index 43919c1a0..1abd754f6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java @@ -16,13 +16,12 @@ final class HanaDbExpression extends BaseDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { - request.append("json_value(").append(propName).append(", '$.").append(path).append("')"); - request.append(operator.bind()); + request.append("json_value(").parse(propName).append(", '$.").append(path).append("')").append(operator.bind()); } @Override public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { - request.append("cardinality(").append(propName).append(")"); + request.append("cardinality(").parse(propName).append(")"); if (empty) { request.append(" = 0"); } else { @@ -51,8 +50,7 @@ final class HanaDbExpression extends BaseDbExpression { if (!contains) { request.append(" not "); } - request.append(" member of ").append(propName).append(")"); - + request.append(" member of ").parse(propName).append(")"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java index 8116b2c4e..d525ca152 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java @@ -10,7 +10,6 @@ final class MariaDbExpression extends BasicDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { - request.append("(").append(propName).append(" ->> '$.").append(path).append("')"); - request.append(operator.bind()); + request.append("(").parse(propName).append(" ->> '$.").append(path).append("')").append(operator.bind()); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java index b0721a44e..f4d9ba7ff 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java @@ -10,8 +10,7 @@ final class MySqlDbExpression extends BasicDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { - request.append("(").append(propName).append(" ->> '$.").append(path).append("')"); - request.append(operator.bind()); + request.append("(").parse(propName).append(" ->> '$.").append(path).append("')").append(operator.bind()); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java index f1fbaef7a..51412d05b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java @@ -17,12 +17,11 @@ final class OracleDbExpression extends BaseDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { if (operator == Op.EXISTS) { - request.append("json_exists(").append(propName).append(", '$.").append(path).append("')"); + request.append("json_exists(").parse(propName).append(", '$.").append(path).append("')"); } else if (operator == Op.NOT_EXISTS) { - request.append("not json_exists(").append(propName).append(", '$.").append(path).append("')"); + request.append("not json_exists(").parse(propName).append(", '$.").append(path).append("')"); } else { - request.append("json_value(").append(propName).append(", '$.").append(path).append("')"); - request.append(operator.bind()); + request.append("json_value(").parse(propName).append(", '$.").append(path).append("')").append(operator.bind()); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java index a3f044072..541228e1a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java @@ -15,27 +15,22 @@ final class PostgresDbExpression extends BaseDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { - StringBuilder sb = new StringBuilder(50); String[] paths = path.split("\\."); if (paths.length == 1) { // (t0.content ->> 'title') = 'Some value' - sb.append("(").append(propName).append(" ->> '").append(path).append("')"); - + request.append("(").parse(propName).append(" ->> '").append(path).append("')"); } else { // (t0.content #>> '{path,inner}') = 'Some value' - sb.append("(").append(propName).append(" #>> '{"); + request.append("(").parse(propName).append(" #>> '{"); for (int i = 0; i < paths.length; i++) { if (i > 0) { - sb.append(","); + request.append(","); } - sb.append(paths[i]); + request.append(paths[i]); } - sb.append("}')"); + request.append("}')"); } - - request.append(sb.toString()); - request.append(PostgresCast.cast(value)); - request.append(operator.bind()); + request.append(PostgresCast.cast(value)).append(operator.bind()); } @Override @@ -43,12 +38,11 @@ final class PostgresDbExpression extends BaseDbExpression { if (!contains) { request.append("not ("); } - request.append(propName).append(" @> array[?"); + request.parse(propName).append(" @> array[?"); for (int i = 1; i < values.length; i++) { request.append(",?"); } - request.append("]"); - request.append(PostgresCast.cast(values[0], true)); + request.append("]").append(PostgresCast.cast(values[0], true)); if (!contains) { request.append(")"); } @@ -56,7 +50,7 @@ final class PostgresDbExpression extends BaseDbExpression { @Override public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { - request.append("coalesce(cardinality(").append(propName).append("),0)"); + request.append("coalesce(cardinality(").parse(propName).append("),0)"); if (empty) { request.append(" = 0"); } else { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java index 78838a81e..afeae8be8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java @@ -11,8 +11,7 @@ final class SqlServerDbExpression extends BaseDbExpression { @Override public void json(final SpiExpressionRequest request, final String propName, final String path, final Op operator, final Object value) { - request.append("json_value(").append(propName).append(", '$.").append(path).append("')"); - request.append(operator.bind()); + request.append("json_value(").parse(propName).append(", '$.").append(path).append("')").append(operator.bind()); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java index 1577768c1..f40b6dffb 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java @@ -5,6 +5,7 @@ import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.CoreLog; import io.ebeaninternal.api.SpiExpressionList; import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.server.bind.DataBind; import io.ebeaninternal.server.core.OrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; @@ -14,7 +15,6 @@ import io.ebeaninternal.server.persist.Binder; import io.ebeaninternal.server.querydefn.OrmQueryProperties; import io.ebeaninternal.server.querydefn.OrmUpdateProperties; import io.ebeaninternal.server.rawsql.SpiRawSql; -import io.ebeaninternal.server.bind.DataBind; import io.ebeaninternal.server.util.BindParamsParser; import java.sql.Connection; @@ -47,26 +47,14 @@ public final class CQueryPredicates { private final Object idValue; private final BindParams bindParams; private DefaultExpressionRequest filterMany; - /** - * SQL generated from the where expressions. - */ - private String filterManyExprSql; /** * Bind values from the where expressions. */ private DefaultExpressionRequest where; - /** - * SQL generated from the where expressions. - */ - private String whereExprSql; /** * Bind values for having expression. */ private DefaultExpressionRequest having; - /** - * SQL generated from the having expression. - */ - private String havingExprSql; private String dbHaving; /** * logicalWhere with property names converted to db columns. @@ -190,70 +178,46 @@ public final class CQueryPredicates { buildUpdateClause(buildSql, deployParser); buildBindWhereRawSql(buildSql); + BeanPropertyAssocMany manyProperty = request.determineMany(); + if (buildSql) { + String logicalOrderBy = deriveOrderByWithMany(request.manyPropertyForOrderBy()); + if (logicalOrderBy != null) { + dbOrderBy = deployParser.parse(logicalOrderBy); + } + // create a copy of the includes required to support the orderBy + orderByIncludes = new HashSet<>(deployParser.getIncludes()); + } SpiExpressionList whereExp = query.getWhereExpressions(); if (whereExp != null) { this.where = new DefaultExpressionRequest(request, deployParser, binder, whereExp); if (buildSql) { - whereExprSql = where.buildSql(); + dbWhere = where.buildSql(); } } - BeanPropertyAssocMany manyProperty = request.determineMany(); if (manyProperty != null) { OrmQueryProperties chunk = query.getDetail().getChunk(manyProperty.name(), false); SpiExpressionList filterManyExpr = chunk.getFilterMany(); if (filterManyExpr != null) { this.filterMany = new DefaultExpressionRequest(request, deployParser, binder, filterManyExpr); if (buildSql) { - filterManyExprSql = filterMany.buildSql(); + dbFilterMany = filterMany.buildSql(); } } } - // having expression SpiExpressionList havingExpr = query.getHavingExpressions(); if (havingExpr != null) { this.having = new DefaultExpressionRequest(request, deployParser, binder, havingExpr); if (buildSql) { - havingExprSql = having.buildSql(); + dbHaving = having.buildSql(); } } if (buildSql) { - parsePropertiesToDbColumns(deployParser); + predicateIncludes = deployParser.getIncludes(); } } /** - * Parse/Convert property names to database columns in the where and order by - * clauses etc. - */ - private void parsePropertiesToDbColumns(DeployParser deployParser) { - // order by is dependent on the manyProperty (if there is one) - String logicalOrderBy = deriveOrderByWithMany(request.manyPropertyForOrderBy()); - if (logicalOrderBy != null) { - dbOrderBy = deployParser.parse(logicalOrderBy); - } - // create a copy of the includes required to support the orderBy - orderByIncludes = new HashSet<>(deployParser.getIncludes()); - dbWhere = deriveWhere(deployParser); - dbFilterMany = deriveFilterMany(deployParser); - dbHaving = deriveHaving(deployParser); - // all includes, including ones for manyWhere clause - predicateIncludes = deployParser.getIncludes(); - } - - private String deriveFilterMany(DeployParser deployParser) { - if (isEmpty(filterManyExprSql)) { - return null; - } else { - return deployParser.parse(filterManyExprSql); - } - } - - private String deriveWhere(DeployParser deployParser) { - return parse(whereExprSql, deployParser); - } - - /** - * Replace the table alias place holders. + * Replace the table alias place-holders. */ void parseTableAlias(SqlTreeAlias alias) { if (dbWhere != null) { @@ -272,20 +236,6 @@ public final class CQueryPredicates { } } - private boolean isEmpty(String s) { - return s == null || s.isEmpty(); - } - - private String parse(String expr, DeployParser deployParser) { - if (expr == null) return ""; - if (expr.isEmpty()) return expr; - return deployParser.parse(expr); - } - - private String deriveHaving(DeployParser deployParser) { - return parse(havingExprSql, deployParser); - } - private String parseOrderBy() { OrderBy orderBy = query.getOrderBy(); if (orderBy == null) { diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java index 5bd44e3de..a84d3b046 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java @@ -49,6 +49,12 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest { return this; } + @Override + public SpiExpressionRequest parse(String expression) { + sql.append(expression); + return this; + } + @Override public void addBindEncryptKey(Object encryptKey) { From 9ff240dc103adc815fc2fe30a57021c206fa442f Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 24 Mar 2023 19:35:11 +1300 Subject: [PATCH 3/5] Refactor SpiExpressionRequest split parse() into property() and path() to have fast path property() uses a fast path for the common case that the expression is a bean property path. This will then fall back to using parse() when that isn't the case. --- .../api/SpiExpressionRequest.java | 14 +++++++-- .../server/deploy/DeployParser.java | 24 ++++++++++---- .../server/deploy/DeployPropertyParser.java | 4 +-- .../deploy/DeployPropertyParserMap.java | 4 +-- .../server/deploy/DeployUpdateParser.java | 6 ++-- .../deploy/meta/DeployBeanDescriptor.java | 31 +++---------------- .../expression/AllEqualsExpression.java | 2 +- .../server/expression/BetweenExpression.java | 2 +- .../expression/BetweenPropertyExpression.java | 2 +- .../CaseInsensitiveEqualExpression.java | 4 +-- .../expression/DefaultExpressionRequest.java | 16 ++++++++-- .../server/expression/IdInExpression.java | 7 ++--- .../server/expression/InExpression.java | 2 +- .../server/expression/InRangeExpression.java | 2 +- .../server/expression/LikeExpression.java | 4 +-- .../expression/NativeILikeExpression.java | 2 +- .../server/expression/NullExpression.java | 2 +- .../server/expression/SimpleExpression.java | 2 +- .../server/expression/SubQueryExpression.java | 2 +- .../expression/platform/BaseDbExpression.java | 8 ++--- .../expression/platform/H2DbExpression.java | 4 +-- .../expression/platform/HanaDbExpression.java | 6 ++-- .../platform/MariaDbExpression.java | 2 +- .../platform/MySqlDbExpression.java | 2 +- .../platform/OracleDbExpression.java | 6 ++-- .../platform/PostgresDbExpression.java | 8 ++--- .../platform/SqlServerDbExpression.java | 2 +- .../deploy/DeployPropertyParserTest.java | 3 ++ .../expression/TDSpiExpressionRequest.java | 10 ++++-- 29 files changed, 99 insertions(+), 84 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java index cd68c4a5c..98bef6433 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java @@ -32,14 +32,22 @@ public interface SpiExpressionRequest { SpiOrmQueryRequest getQueryRequest(); /** - * Append to the expression sql. + * Append to the expression sql without any parsing. */ - SpiExpressionRequest append(String sql); + SpiExpressionRequest append(String expression); + + /** + * Append to the expression sql with logical property parsing to db columns with logical path prefix. + *

+ * This is a fast path case when expression is a bean property path and falls back to using parse() + * when that isn't the case. + */ + SpiExpressionRequest property(String expression); /** * Append to the expression sql with logical property parsing to db columns with logical path prefix. */ - SpiExpressionRequest parse(String sql); + SpiExpressionRequest parse(String expression); /** * Add an encryption key to bind to this request. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java index 184e7ad18..0a0d45a90 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java @@ -46,7 +46,7 @@ public abstract class DeployParser { protected abstract String convertWord(); - public abstract String getDeployWord(String expression); + public abstract String deployWord(String expression); /** * Return the join includes. @@ -57,14 +57,26 @@ public abstract class DeployParser { this.encrypted = encrypted; } - public String parse(String source) { - if (source == null) { + /** + * Fast path parse() which first checks that the source is a bean property. + */ + public String property(String expression) { + String deployWord = deployWord(expression); + if (deployWord != null) { + return deployWord; + } + // fallback to use parse() + return parse(expression); + } + + public String parse(String expression) { + if (expression == null) { return null; } pos = -1; - this.source = source; - this.sourceLength = source.length(); - this.sb = new StringBuilder(source.length() + 20); + this.source = expression; + this.sourceLength = expression.length(); + this.sb = new StringBuilder(expression.length() + 20); while (nextWord()) { if (skipWordConvert()) { sb.append(word); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java index a964ef1ee..dfc2affa5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java @@ -55,7 +55,7 @@ public final class DeployPropertyParser extends DeployParser { } @Override - public String getDeployWord(String expression) { + public String deployWord(String expression) { ElPropertyDeploy elProp = beanDescriptor.elPropertyDeploy(expression); if (elProp == null) { return null; @@ -70,7 +70,7 @@ public final class DeployPropertyParser extends DeployParser { @Override public String convertWord() { - String r = getDeployWord(word); + String r = deployWord(word); return r == null ? word : r; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java index cd0ded26e..7ee0372cf 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java @@ -25,12 +25,12 @@ public class DeployPropertyParserMap extends DeployParser { @Override public String convertWord() { - String r = getDeployWord(word); + String r = deployWord(word); return r == null ? word : r; } @Override - public String getDeployWord(String expression) { + public String deployWord(String expression) { return map.get(expression); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java index a59269eed..9fa25380c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java @@ -25,7 +25,7 @@ public final class DeployUpdateParser extends DeployParser { @Override public String convertWord() { - String dbWord = getDeployWord(word); + String dbWord = deployWord(word); if (dbWord != null) { return dbWord; } @@ -62,7 +62,7 @@ public final class DeployUpdateParser extends DeployParser { start = dotPos + 1; String remainder = currentWord.substring(start); - String dbWord = getDeployWord(remainder); + String dbWord = deployWord(remainder); if (dbWord != null) { // we have found a match for the remainder localBuffer.append(dbWord); @@ -72,7 +72,7 @@ public final class DeployUpdateParser extends DeployParser { } @Override - public String getDeployWord(String expression) { + public String deployWord(String expression) { if (expression.equalsIgnoreCase(beanDescriptor.name())) { return beanDescriptor.baseTable(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index dfeacbd83..97df0a16d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -8,31 +8,14 @@ import io.ebean.config.DatabaseConfig; import io.ebean.config.TableName; import io.ebean.config.dbplatform.IdType; import io.ebean.config.dbplatform.PlatformIdGenerator; -import io.ebean.event.BeanFindController; -import io.ebean.event.BeanPersistController; -import io.ebean.event.BeanPersistListener; -import io.ebean.event.BeanPostConstructListener; -import io.ebean.event.BeanPostLoad; -import io.ebean.event.BeanQueryAdapter; +import io.ebean.event.*; import io.ebean.event.changelog.ChangeLogFilter; import io.ebean.text.PathProperties; import io.ebean.util.SplitName; import io.ebeaninternal.api.ConcurrencyMode; import io.ebeaninternal.server.core.CacheOptions; import io.ebeaninternal.server.deploy.BeanDescriptor.EntityType; -import io.ebeaninternal.server.deploy.BeanDescriptorManager; -import io.ebeaninternal.server.deploy.ChainedBeanPersistController; -import io.ebeaninternal.server.deploy.ChainedBeanPersistListener; -import io.ebeaninternal.server.deploy.ChainedBeanPostConstructListener; -import io.ebeaninternal.server.deploy.ChainedBeanPostLoad; -import io.ebeaninternal.server.deploy.ChainedBeanQueryAdapter; -import io.ebeaninternal.server.deploy.DeployPropertyParserMap; -import io.ebeaninternal.server.deploy.IdentityMode; -import io.ebeaninternal.server.deploy.IndexDefinition; -import io.ebeaninternal.server.deploy.InheritInfo; -import io.ebeaninternal.server.deploy.PartitionMeta; -import io.ebeaninternal.server.deploy.TableJoin; -import io.ebeaninternal.server.deploy.TablespaceMeta; +import io.ebeaninternal.server.deploy.*; import io.ebeaninternal.server.deploy.parse.DeployBeanInfo; import io.ebeaninternal.server.idgen.UuidV1IdGenerator; import io.ebeaninternal.server.idgen.UuidV1RndIdGenerator; @@ -41,13 +24,7 @@ import io.ebeaninternal.server.rawsql.SpiRawSql; import javax.persistence.Entity; import javax.persistence.MappedSuperclass; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Describes Beans including their deployment information. @@ -1102,7 +1079,7 @@ public class DeployBeanDescriptor { } @Override - public String getDeployWord(String expression) { + public String deployWord(String expression) { return descriptor.getDeployWord(expression); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/AllEqualsExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/AllEqualsExpression.java index 944e3375b..81e386b70 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/AllEqualsExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/AllEqualsExpression.java @@ -76,7 +76,7 @@ final class AllEqualsExpression extends NonPrepareExpression { if (count > 0) { request.append("and "); } - request.parse(name(propName)); + request.property(name(propName)); if (value == null) { request.append(" is null "); } else { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenExpression.java index e7f480cb7..aab1c549b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenExpression.java @@ -52,7 +52,7 @@ final class BetweenExpression extends AbstractExpression { if (prop != null && prop.isDbEncrypted()) { pname = prop.beanProperty().decryptProperty(propName); } - request.parse(pname).append(_BETWEEN); + request.property(pname).append(_BETWEEN); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java index 40f38428d..0c860636a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BetweenPropertyExpression.java @@ -81,7 +81,7 @@ final class BetweenPropertyExpression extends NonPrepareExpression { @Override public void addSql(SpiExpressionRequest request) { - request.append(" ?").append(BETWEEN).parse(name(lowProperty)).append(" and ").parse(name(highProperty)); + request.append(" ?").append(BETWEEN).property(name(lowProperty)).append(" and ").property(name(highProperty)); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java index d1010f501..09f505ba4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/CaseInsensitiveEqualExpression.java @@ -52,9 +52,9 @@ final class CaseInsensitiveEqualExpression extends AbstractValueExpression { pname = prop.beanProperty().decryptProperty(propName); } if (not) { - request.append("lower(").parse(pname).append(") != ?"); + request.append("lower(").property(pname).append(") != ?"); } else { - request.append("lower(").parse(pname).append(") = ?"); + request.append("lower(").property(pname).append(") = ?"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java index 8ce43712d..3083b8418 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java @@ -73,7 +73,7 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest { @Override public String parseDeploy(String logicalProp) { - String s = deployParser.getDeployWord(logicalProp); + String s = deployParser.deployWord(logicalProp); return s == null ? logicalProp : s; } @@ -114,8 +114,18 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest { * Append text the underlying sql expression. */ @Override - public SpiExpressionRequest append(String sqlExpression) { - sql.append(sqlExpression); + public SpiExpressionRequest append(String expression) { + sql.append(expression); + return this; + } + + @Override + public SpiExpressionRequest property(String expression) { + if (deployParser == null) { + sql.append(expression); + } else { + sql.append(deployParser.property(expression)); + } return this; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java index b3ad3c75a..dccc11f35 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java @@ -82,9 +82,8 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo if (idCollection.isEmpty()) { request.append(SQL_FALSE); // append false for this stage } else { - request.parse(descriptor.idBinder().getBindIdInSql(null)); - String inClause = idBinder.getIdInValueExpr(false, idCollection.size()); - request.append(inClause); + request.property(descriptor.idBinder().getBindIdInSql(null)); + request.append(idBinder.getIdInValueExpr(false, idCollection.size())); } } @@ -99,7 +98,7 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo request.parse(descriptor.idBinderInLHSSql()); request.append(idBinder.getIdInValueExpr(false, idCollection.size())); } else { - request.parse(idBinder.getBeanProperty().name()); + request.property(idBinder.getBeanProperty().name()); request.appendInExpression(false, idCollection); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InExpression.java index 02d301e6d..272286b70 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InExpression.java @@ -169,7 +169,7 @@ public final class InExpression extends AbstractExpression implements IdInCommon return; } } - request.parse(propName); + request.property(propName); request.appendInExpression(not, bindValues); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InRangeExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InRangeExpression.java index be455e71e..ec0348e4b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InRangeExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InRangeExpression.java @@ -55,7 +55,7 @@ final class InRangeExpression extends AbstractExpression { if (prop != null && prop.isDbEncrypted()) { pname = prop.beanProperty().decryptProperty(propName); } - request.append("(").parse(pname).append(" >= ? and ").parse(pname).append(" < ?)"); + request.append("(").property(pname).append(" >= ? and ").property(pname).append(" < ?)"); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/LikeExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/LikeExpression.java index e85d984d3..3027eed5a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/LikeExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/LikeExpression.java @@ -44,9 +44,9 @@ final class LikeExpression extends AbstractValueExpression { pname = prop.beanProperty().decryptProperty(propName); } if (caseInsensitive) { - request.append("lower(").parse(pname).append(")"); + request.append("lower(").property(pname).append(")"); } else { - request.parse(pname); + request.property(pname); } if (type == LikeType.EQUAL_TO) { request.append(" = ?"); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NativeILikeExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NativeILikeExpression.java index 9527e922d..d14b8f83d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NativeILikeExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NativeILikeExpression.java @@ -41,7 +41,7 @@ final class NativeILikeExpression extends AbstractExpression { if (prop != null && prop.isDbEncrypted()) { pname = prop.beanProperty().decryptProperty(propName); } - request.parse(pname).append(" ilike ?"); + request.property(pname).append(" ilike ?"); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NullExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NullExpression.java index ab1f1a7c3..ca1f347d0 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/NullExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/NullExpression.java @@ -66,7 +66,7 @@ final class NullExpression extends AbstractExpression { if (elProperty != null && elProperty.isAssocId()) { request.parse(elProperty.assocIdExpression(propName, nullExpr)); } else { - request.parse(propName).append(nullExpr); + request.property(propName).append(nullExpr); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SimpleExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SimpleExpression.java index 21b4a452c..93b1953c8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SimpleExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SimpleExpression.java @@ -109,7 +109,7 @@ public final class SimpleExpression extends AbstractValueExpression { return; } } - request.parse(propName).append(type.bind()); + request.property(propName).append(type.bind()); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java index aaa5a0eb6..21fd33c8b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java @@ -90,7 +90,7 @@ final class SubQueryExpression extends AbstractExpression implements Unsupported @Override public void addSql(SpiExpressionRequest request) { - request.parse(propName).append(op.expression).append("(").parse(sql).append(")"); + request.property(propName).append(op.expression).append("(").parse(sql).append(")"); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java index 420e91451..b17fbf533 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java @@ -10,8 +10,8 @@ abstract class BaseDbExpression implements DbExpressionHandler { @Override public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { - String bitOp = bitOp(operator); - request.append("(").parse(propName).append(" ").append(bitOp).append(" ? ").append(compare).append(" ?)"); + final String bitOp = bitOp(operator); + request.append("(").property(propName).append(" ").append(bitOp).append(" ? ").append(compare).append(" ?)"); } private String bitOp(BitwiseOp operator) { @@ -29,8 +29,8 @@ abstract class BaseDbExpression implements DbExpressionHandler { * Common alternative where the bitwise operation is a function (specifically bitand is used - H2 and Oracle). */ protected void bitwiseFunction(SpiExpressionRequest request, String propName, BitwiseOp operator, String compare) { - String funcName = functionName(operator); - request.append(funcName).append("(").parse(propName).append(", ?) ").append(compare).append(" ?"); + final String funcName = functionName(operator); + request.append(funcName).append("(").property(propName).append(", ?) ").append(compare).append(" ?"); } protected String functionName(BitwiseOp operator) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java index b3fcd3d37..e94e94e3a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java @@ -10,7 +10,7 @@ final class H2DbExpression extends BasicDbExpression { @Override public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { - String funcName = functionName(operator); - request.append(funcName).append("(").parse(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)"); + final String funcName = functionName(operator); + request.append(funcName).append("(").property(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java index 1abd754f6..bc582e51c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java @@ -16,12 +16,12 @@ final class HanaDbExpression extends BaseDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { - request.append("json_value(").parse(propName).append(", '$.").append(path).append("')").append(operator.bind()); + request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind()); } @Override public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { - request.append("cardinality(").parse(propName).append(")"); + request.append("cardinality(").property(propName).append(")"); if (empty) { request.append(" = 0"); } else { @@ -50,7 +50,7 @@ final class HanaDbExpression extends BaseDbExpression { if (!contains) { request.append(" not "); } - request.append(" member of ").parse(propName).append(")"); + request.append(" member of ").property(propName).append(")"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java index d525ca152..0d5cc3ff6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java @@ -10,6 +10,6 @@ final class MariaDbExpression extends BasicDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { - request.append("(").parse(propName).append(" ->> '$.").append(path).append("')").append(operator.bind()); + request.append("(").property(propName).append(" ->> '$.").append(path).append("')").append(operator.bind()); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java index f4d9ba7ff..ca37679f9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java @@ -10,7 +10,7 @@ final class MySqlDbExpression extends BasicDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { - request.append("(").parse(propName).append(" ->> '$.").append(path).append("')").append(operator.bind()); + request.append("(").property(propName).append(" ->> '$.").append(path).append("')").append(operator.bind()); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java index 51412d05b..d51fbc23a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java @@ -17,11 +17,11 @@ final class OracleDbExpression extends BaseDbExpression { @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { if (operator == Op.EXISTS) { - request.append("json_exists(").parse(propName).append(", '$.").append(path).append("')"); + request.append("json_exists(").property(propName).append(", '$.").append(path).append("')"); } else if (operator == Op.NOT_EXISTS) { - request.append("not json_exists(").parse(propName).append(", '$.").append(path).append("')"); + request.append("not json_exists(").property(propName).append(", '$.").append(path).append("')"); } else { - request.append("json_value(").parse(propName).append(", '$.").append(path).append("')").append(operator.bind()); + request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind()); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java index 541228e1a..66d3da284 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java @@ -18,10 +18,10 @@ final class PostgresDbExpression extends BaseDbExpression { String[] paths = path.split("\\."); if (paths.length == 1) { // (t0.content ->> 'title') = 'Some value' - request.append("(").parse(propName).append(" ->> '").append(path).append("')"); + request.append("(").property(propName).append(" ->> '").append(path).append("')"); } else { // (t0.content #>> '{path,inner}') = 'Some value' - request.append("(").parse(propName).append(" #>> '{"); + request.append("(").property(propName).append(" #>> '{"); for (int i = 0; i < paths.length; i++) { if (i > 0) { request.append(","); @@ -38,7 +38,7 @@ final class PostgresDbExpression extends BaseDbExpression { if (!contains) { request.append("not ("); } - request.parse(propName).append(" @> array[?"); + request.property(propName).append(" @> array[?"); for (int i = 1; i < values.length; i++) { request.append(",?"); } @@ -50,7 +50,7 @@ final class PostgresDbExpression extends BaseDbExpression { @Override public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { - request.append("coalesce(cardinality(").parse(propName).append("),0)"); + request.append("coalesce(cardinality(").property(propName).append("),0)"); if (empty) { request.append(" = 0"); } else { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java index afeae8be8..c84482374 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java @@ -11,7 +11,7 @@ final class SqlServerDbExpression extends BaseDbExpression { @Override public void json(final SpiExpressionRequest request, final String propName, final String path, final Op operator, final Object value) { - request.append("json_value(").parse(propName).append(", '$.").append(path).append("')").append(operator.bind()); + request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind()); } @Override diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java index c26379261..00f0281be 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java @@ -26,11 +26,13 @@ public class DeployPropertyParserTest extends BaseTest { @Test public void depth1_path() { + Assertions.assertThat(parser().property("billingAddress.city")).isEqualTo("${billingAddress}city"); Assertions.assertThat(parser().parse("billingAddress.city")).isEqualTo("${billingAddress}city"); } @Test public void depth2_path() { + Assertions.assertThat(parser().property("max(billingAddress.country.name)")).isEqualTo("max(${billingAddress.country}name)"); Assertions.assertThat(parser().parse("max(billingAddress.country.name)")).isEqualTo("max(${billingAddress.country}name)"); } @@ -69,6 +71,7 @@ public class DeployPropertyParserTest extends BaseTest { @Test public void unknown_path() { + Assertions.assertThat(parser().property(" foo ")).isEqualTo(" foo "); Assertions.assertThat(parser().parse(" foo ")).isEqualTo(" foo "); } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java index a84d3b046..d4d3f53e1 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java @@ -44,8 +44,14 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest { } @Override - public SpiExpressionRequest append(String sqlExpression) { - sql.append(sqlExpression); + public SpiExpressionRequest append(String expression) { + sql.append(expression); + return this; + } + + @Override + public SpiExpressionRequest property(String expression) { + sql.append(expression); return this; } From a68665a37edcfc15b36a80a371f09fe4e09ccd39 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 24 Mar 2023 19:57:21 +1300 Subject: [PATCH 4/5] Refactor rename methods on SpiExpressionRequest, DeployParser etc --- .../ebeaninternal/api/SpiExpressionRequest.java | 10 +++++----- .../server/deploy/BeanPropertyAssocMany.java | 2 +- .../ebeaninternal/server/deploy/DeployParser.java | 2 +- .../server/deploy/DeployPropertyParser.java | 4 ++-- .../server/deploy/DeployPropertyParserMap.java | 2 +- .../server/deploy/DeployUpdateParser.java | 2 +- .../server/deploy/FormulaPropertyPath.java | 2 +- .../server/deploy/IntersectionRow.java | 4 ++-- .../server/expression/AbstractExpression.java | 8 ++------ .../expression/ArrayContainsExpression.java | 2 +- .../server/expression/ArrayIsEmptyExpression.java | 2 +- .../server/expression/BitwiseExpression.java | 2 +- .../expression/DefaultExpressionRequest.java | 12 ++++++------ .../server/expression/IdExpression.java | 9 ++------- .../server/expression/IdInExpression.java | 15 +++++---------- .../server/expression/InPairsExpression.java | 2 +- .../server/expression/JsonPathExpression.java | 4 +--- .../server/query/CQueryPredicates.java | 6 +++--- .../server/expression/BetweenExpressionTest.java | 2 +- .../expression/BetweenPropertyExpressionTest.java | 2 +- .../server/expression/InRangeExpressionTest.java | 2 +- .../server/expression/LogicExpressionTest.java | 2 +- .../server/expression/NullExpressionTest.java | 8 ++++---- .../server/expression/TDSpiExpressionRequest.java | 10 +++++----- .../expression/platform/HanaDbExpressionTest.java | 12 ++++++------ .../platform/MySqlDbExpressionTest.java | 2 +- 26 files changed, 57 insertions(+), 73 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java index 98bef6433..e7d44b8f9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java @@ -14,7 +14,7 @@ public interface SpiExpressionRequest { /** * Return the DB specific handler for JSON and ARRAY expressions. */ - DbExpressionHandler getDbPlatformHandler(); + DbExpressionHandler platformHandler(); /** * Parse the logical property name to the deployment name. @@ -24,12 +24,12 @@ public interface SpiExpressionRequest { /** * Return the bean descriptor for the root type. */ - BeanDescriptor getBeanDescriptor(); + BeanDescriptor descriptor(); /** * Return the associated QueryRequest. */ - SpiOrmQueryRequest getQueryRequest(); + SpiOrmQueryRequest queryRequest(); /** * Append to the expression sql without any parsing. @@ -62,12 +62,12 @@ public interface SpiExpressionRequest { /** * Return the accumulated expression sql for all expressions in this request. */ - String getSql(); + String sql(); /** * Return the ordered list of bind values for all expressions in this request. */ - List getBindValues(); + List bindValues(); /** * Increments the parameter index and returns that value. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index bd80bc795..d2eb29063 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -417,7 +417,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST boolean softDelete = targetDescriptor.isSoftDelete(); boolean needsX2Table = softDelete || extraWhere() != null; StringBuilder sb = new StringBuilder(50).append("from "); // use from to stop parsing on table name - SpiQuery query = request.getQueryRequest().query(); + SpiQuery query = request.queryRequest().query(); if (hasJoinTable()) { sb.append(query.isAsDraft() ? intersectionDraftTable : intersectionPublishTable); } else { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java index 0a0d45a90..582562a5e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java @@ -51,7 +51,7 @@ public abstract class DeployParser { /** * Return the join includes. */ - public abstract Set getIncludes(); + public abstract Set includes(); public void setEncrypted(boolean encrypted) { this.encrypted = encrypted; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java index dfc2affa5..2cdb5d5d2 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java @@ -37,12 +37,12 @@ public final class DeployPropertyParser extends DeployParser { /** * Return the first property found by the parser. */ - public ElPropertyDeploy getFirstProp() { + public ElPropertyDeploy firstProp() { return firstProp; } @Override - public Set getIncludes() { + public Set includes() { return includes; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java index 7ee0372cf..d1c7e7efd 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java @@ -19,7 +19,7 @@ public class DeployPropertyParserMap extends DeployParser { * Returns null for raw sql queries. */ @Override - public Set getIncludes() { + public Set includes() { return Collections.emptySet(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java index 9fa25380c..65c57cba5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DeployUpdateParser.java @@ -19,7 +19,7 @@ public final class DeployUpdateParser extends DeployParser { * Return null as not used for updates. */ @Override - public Set getIncludes() { + public Set includes() { return null; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java index 82493154b..40db63c8d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java @@ -48,7 +48,7 @@ final class FormulaPropertyPath { parsed = parsed.replace("${}", "${" + path + "}"); } this.parsedAggregation = buildFormula(parsed); - this.firstProp = parser.getFirstProp(); + this.firstProp = parser.firstProp(); } private void parseSuffix(String suffix) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/IntersectionRow.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/IntersectionRow.java index f5480ac77..d4021adea 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/IntersectionRow.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/IntersectionRow.java @@ -82,9 +82,9 @@ public final class IntersectionRow { idIn.addSqlNoAlias(er); idIn.addBindValues(er); sb.append(" and not ( "); - sb.append(er.getSql()); + sb.append(er.sql()); sb.append(" ) "); - List bindValues = er.getBindValues(); + List bindValues = er.bindValues(); for (Object bindValue : bindValues) { bindParams.setParameter(++count, bindValue); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/AbstractExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/AbstractExpression.java index 3909877d6..08deef5ea 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/AbstractExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/AbstractExpression.java @@ -2,11 +2,7 @@ package io.ebeaninternal.server.expression; import io.ebean.event.BeanQueryRequest; import io.ebean.util.SplitName; -import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.api.NaturalKeyQueryData; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.api.SpiExpressionValidation; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.el.ElPropertyDeploy; import io.ebeaninternal.server.el.ElPropertyValue; @@ -102,6 +98,6 @@ abstract class AbstractExpression implements SpiExpression { } protected final ElPropertyValue getElProp(SpiExpressionRequest request) { - return request.getBeanDescriptor().elGetValue(propName); + return request.descriptor().elGetValue(propName); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ArrayContainsExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ArrayContainsExpression.java index 34fec6037..3c55023dd 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ArrayContainsExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ArrayContainsExpression.java @@ -68,7 +68,7 @@ final class ArrayContainsExpression extends AbstractExpression { @Override public void addSql(SpiExpressionRequest request) { - request.getDbPlatformHandler().arrayContains(request, propName, contains, values); + request.platformHandler().arrayContains(request, propName, contains, values); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ArrayIsEmptyExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ArrayIsEmptyExpression.java index 2234f9500..3757643c2 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ArrayIsEmptyExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ArrayIsEmptyExpression.java @@ -45,7 +45,7 @@ final class ArrayIsEmptyExpression extends AbstractExpression { @Override public void addSql(SpiExpressionRequest request) { - request.getDbPlatformHandler().arrayIsEmpty(request, propName, empty); + request.platformHandler().arrayIsEmpty(request, propName, empty); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java index 04f6f0f2a..0f93dc73f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java @@ -48,7 +48,7 @@ final class BitwiseExpression extends AbstractExpression { @Override public void addSql(SpiExpressionRequest request) { // Use DB specific expression handling - request.getDbPlatformHandler().bitwise(request, propName, operator, flags, compare, match); + request.platformHandler().bitwise(request, propName, operator, flags, compare, match); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java index 3083b8418..b2f193f24 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java @@ -67,7 +67,7 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest { } @Override - public DbExpressionHandler getDbPlatformHandler() { + public DbExpressionHandler platformHandler() { return binder.getDbExpressionHandler(); } @@ -101,12 +101,12 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest { } @Override - public BeanDescriptor getBeanDescriptor() { + public BeanDescriptor descriptor() { return beanDescriptor; } @Override - public SpiOrmQueryRequest getQueryRequest() { + public SpiOrmQueryRequest queryRequest() { return queryRequest; } @@ -162,17 +162,17 @@ public final class DefaultExpressionRequest implements SpiExpressionRequest { } } - public String getBindLog() { + public String bindLog() { return bindLog == null ? "" : bindLog.toString(); } @Override - public String getSql() { + public String sql() { return sql.toString(); } @Override - public List getBindValues() { + public List bindValues() { return bindValues; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java index 012cafad0..f66ecd0ab 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdExpression.java @@ -46,21 +46,16 @@ final class IdExpression extends NonPrepareExpression implements SpiExpression { @Override public void addBindValues(SpiExpressionRequest request) { - // 'flatten' EmbeddedId and multiple ID cases // into an array of the underlying scalar field values - DefaultExpressionRequest r = (DefaultExpressionRequest) request; - Object[] bindIdValues = r.getBeanDescriptor().bindIdValues(value); - for (Object bindIdValue : bindIdValues) { + for (Object bindIdValue : request.descriptor().bindIdValues(value)) { request.addBindValue(bindIdValue); } } @Override public void addSql(SpiExpressionRequest request) { - DefaultExpressionRequest r = (DefaultExpressionRequest) request; - String idSql = r.getBeanDescriptor().idBinderIdSql(null); - request.parse(idSql); + request.parse(request.descriptor().idBinderIdSql(null)); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java index dccc11f35..82553d001 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/IdInExpression.java @@ -66,34 +66,29 @@ public final class IdInExpression extends NonPrepareExpression implements IdInCo return; } // Bind the ID values including EmbeddedId and multiple ID - DefaultExpressionRequest r = (DefaultExpressionRequest) request; - BeanDescriptor descriptor = r.getBeanDescriptor(); - IdBinder idBinder = descriptor.idBinder(); - idBinder.addIdInBindValues(request, idCollection); + request.descriptor().idBinder().addIdInBindValues(request, idCollection); } /** * For use with deleting non-attached detail beans during stateless update. */ public void addSqlNoAlias(SpiExpressionRequest request) { - DefaultExpressionRequest r = (DefaultExpressionRequest) request; - BeanDescriptor descriptor = r.getBeanDescriptor(); - IdBinder idBinder = descriptor.idBinder(); if (idCollection.isEmpty()) { request.append(SQL_FALSE); // append false for this stage } else { + final BeanDescriptor descriptor = request.descriptor(); request.property(descriptor.idBinder().getBindIdInSql(null)); - request.append(idBinder.getIdInValueExpr(false, idCollection.size())); + request.append(descriptor.idBinder().getIdInValueExpr(false, idCollection.size())); } } @Override public void addSql(SpiExpressionRequest request) { - BeanDescriptor descriptor = request.getBeanDescriptor(); - IdBinder idBinder = descriptor.idBinder(); if (idCollection.isEmpty()) { request.append(SQL_FALSE); // append false for this stage } else { + final BeanDescriptor descriptor = request.descriptor(); + final IdBinder idBinder = descriptor.idBinder(); if (idBinder.isComplexId()) { request.parse(descriptor.idBinderInLHSSql()); request.append(idBinder.getIdInValueExpr(false, idCollection.size())); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java index e654c7d92..077c253a9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java @@ -89,7 +89,7 @@ final class InPairsExpression extends AbstractExpression { request.append(not ? SQL_TRUE : SQL_FALSE); return; } - request.parse(request.getDbPlatformHandler().concat(property0, separator, property1, suffix)); + request.parse(request.platformHandler().concat(property0, separator, property1, suffix)); request.appendInExpression(not, concatBindValues); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JsonPathExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JsonPathExpression.java index a6e8f128b..f2af9a83e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JsonPathExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JsonPathExpression.java @@ -97,14 +97,12 @@ final class JsonPathExpression extends AbstractExpression { @Override public void addSql(SpiExpressionRequest request) { - // Use DB specific expression handling (Postgres and Oracle supported) - request.getDbPlatformHandler().json(request, propName, path, operator, value); + request.platformHandler().json(request, propName, path, operator, value); } @Override public void addBindValues(SpiExpressionRequest request) { - if (value != null) { // value is null for EXISTS/NOT EXISTS request.addBindValue(value); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java index f40b6dffb..4058e00fc 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java @@ -185,7 +185,7 @@ public final class CQueryPredicates { dbOrderBy = deployParser.parse(logicalOrderBy); } // create a copy of the includes required to support the orderBy - orderByIncludes = new HashSet<>(deployParser.getIncludes()); + orderByIncludes = new HashSet<>(deployParser.includes()); } SpiExpressionList whereExp = query.getWhereExpressions(); if (whereExp != null) { @@ -212,7 +212,7 @@ public final class CQueryPredicates { } } if (buildSql) { - predicateIncludes = deployParser.getIncludes(); + predicateIncludes = deployParser.includes(); } } @@ -303,7 +303,7 @@ public final class CQueryPredicates { * Return the bind values for the where expression. */ public List whereExprBindValues() { - return where == null ? Collections.emptyList() : where.getBindValues(); + return where == null ? Collections.emptyList() : where.bindValues(); } /** diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/BetweenExpressionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/BetweenExpressionTest.java index f9ebea4c9..e9660e294 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/BetweenExpressionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/BetweenExpressionTest.java @@ -15,7 +15,7 @@ public class BetweenExpressionTest extends BaseExpressionTest { BetweenExpression exp = new BetweenExpression("startDate", 1, 2); exp.addSql(expReq); - assertThat(expReq.getSql()).isEqualTo("startDate between ? and ?"); + assertThat(expReq.sql()).isEqualTo("startDate between ? and ?"); } @Test diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/BetweenPropertyExpressionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/BetweenPropertyExpressionTest.java index c1f4d3751..c042efdbb 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/BetweenPropertyExpressionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/BetweenPropertyExpressionTest.java @@ -15,7 +15,7 @@ public class BetweenPropertyExpressionTest extends BaseExpressionTest { public void sqlExpression() { TDSpiExpressionRequest request = new TDSpiExpressionRequest(null); exp("a", "b", 10).addSql(request); - Assertions.assertThat(request.getSql()).isEqualTo(" ? between a and b"); + Assertions.assertThat(request.sql()).isEqualTo(" ? between a and b"); } @Test diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/InRangeExpressionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/InRangeExpressionTest.java index 921581333..46b6acd14 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/InRangeExpressionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/InRangeExpressionTest.java @@ -15,7 +15,7 @@ public class InRangeExpressionTest extends BaseExpressionTest { InRangeExpression exp = new InRangeExpression("startDate", 1, 2); exp.addSql(expReq); - assertThat(expReq.getSql()).isEqualTo("(startDate >= ? and startDate < ?)"); + assertThat(expReq.sql()).isEqualTo("(startDate >= ? and startDate < ?)"); } @Test diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/LogicExpressionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/LogicExpressionTest.java index 2ddbd367e..b4c7b910f 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/LogicExpressionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/LogicExpressionTest.java @@ -29,7 +29,7 @@ public class LogicExpressionTest extends BaseExpressionTest { LogicExpression and = and(eq("a", 10), eq("b", 10)); and.addSql(expReq); - assertThat(expReq.getSql()).isEqualTo("(a = ? and b = ?)"); + assertThat(expReq.sql()).isEqualTo("(a = ? and b = ?)"); } @Test diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/NullExpressionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/NullExpressionTest.java index 302ea3f9e..0c0ef4f2e 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/NullExpressionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/NullExpressionTest.java @@ -22,7 +22,7 @@ public class NullExpressionTest extends BaseExpressionTest { nullExp("id", true).addSql(expReq); - assertThat(expReq.getSql()).isEqualTo("id is not null"); + assertThat(expReq.sql()).isEqualTo("id is not null"); } @Test @@ -32,7 +32,7 @@ public class NullExpressionTest extends BaseExpressionTest { nullExp("id", false).addSql(expReq); - assertThat(expReq.getSql()).isEqualTo("id is null"); + assertThat(expReq.sql()).isEqualTo("id is null"); } @Test @@ -42,7 +42,7 @@ public class NullExpressionTest extends BaseExpressionTest { nullExp("customer", true).addSql(expReq); - assertThat(expReq.getSql()).isEqualTo("customer.id is not null"); + assertThat(expReq.sql()).isEqualTo("customer.id is not null"); } @Test @@ -52,7 +52,7 @@ public class NullExpressionTest extends BaseExpressionTest { nullExp("customer", false).addSql(expReq); - assertThat(expReq.getSql()).isEqualTo("customer.id is null"); + assertThat(expReq.sql()).isEqualTo("customer.id is null"); } @Test diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java index d4d3f53e1..1581954bb 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java @@ -24,7 +24,7 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest { } @Override - public DbExpressionHandler getDbPlatformHandler() { + public DbExpressionHandler platformHandler() { return null; } @@ -34,12 +34,12 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest { } @Override - public BeanDescriptor getBeanDescriptor() { + public BeanDescriptor descriptor() { return descriptor; } @Override - public SpiOrmQueryRequest getQueryRequest() { + public SpiOrmQueryRequest queryRequest() { return null; } @@ -72,12 +72,12 @@ public class TDSpiExpressionRequest implements SpiExpressionRequest { } @Override - public String getSql() { + public String sql() { return sql.toString(); } @Override - public ArrayList getBindValues() { + public ArrayList bindValues() { return null; } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/platform/HanaDbExpressionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/platform/HanaDbExpressionTest.java index 0daf5ea9f..368695ff0 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/platform/HanaDbExpressionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/platform/HanaDbExpressionTest.java @@ -15,7 +15,7 @@ public class HanaDbExpressionTest { SpiExpressionRequest request = new DefaultExpressionRequest(null); expression.arrayContains(request, "arrayproperty", true, "v1", "v2", "v3"); assertEquals("(? member of arrayproperty) and (? member of arrayproperty) and (? member of arrayproperty)", - request.getSql()); + request.sql()); } @Test @@ -24,28 +24,28 @@ public class HanaDbExpressionTest { expression.arrayContains(request, "arrayproperty", false, "v1", "v2", "v3"); assertEquals( "(? not member of arrayproperty) and (? not member of arrayproperty) and (? not member of arrayproperty)", - request.getSql()); + request.sql()); } @Test public void testArrayContainsEmpty() { SpiExpressionRequest request = new DefaultExpressionRequest(null); expression.arrayContains(request, "arrayproperty", true); - assertEquals("", request.getSql()); + assertEquals("", request.sql()); } @Test public void testArrayIsEmpty() { SpiExpressionRequest request = new DefaultExpressionRequest(null); expression.arrayIsEmpty(request, "arrayproperty", true); - assertEquals("cardinality(arrayproperty) = 0", request.getSql()); + assertEquals("cardinality(arrayproperty) = 0", request.sql()); } @Test public void testArrayIsNotEmpty() { SpiExpressionRequest request = new DefaultExpressionRequest(null); expression.arrayIsEmpty(request, "arrayproperty", false); - assertEquals("cardinality(arrayproperty) <> 0", request.getSql()); + assertEquals("cardinality(arrayproperty) <> 0", request.sql()); } @Test @@ -64,6 +64,6 @@ public class HanaDbExpressionTest { public void testJson() { SpiExpressionRequest request = new DefaultExpressionRequest(null); expression.json(request, "jsonproperty", "path", Op.EQ, "val"); - assertEquals("json_value(jsonproperty, '$.path') = ?", request.getSql()); + assertEquals("json_value(jsonproperty, '$.path') = ?", request.sql()); } } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/platform/MySqlDbExpressionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/platform/MySqlDbExpressionTest.java index 032075298..a63fe1ba1 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/platform/MySqlDbExpressionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/platform/MySqlDbExpressionTest.java @@ -15,6 +15,6 @@ public class MySqlDbExpressionTest { public void testJson() { SpiExpressionRequest request = new DefaultExpressionRequest(null); expression.json(request, "jsonproperty", "path", Op.EQ, "val"); - assertEquals("(jsonproperty ->> '$.path') = ?", request.getSql()); + assertEquals("(jsonproperty ->> '$.path') = ?", request.sql()); } } From 79fd689e9a84455da9b4760def06ed4c28085fd8 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 24 Mar 2023 22:38:52 +1300 Subject: [PATCH 5/5] Add support for raw SQL SubQuery expressions IN,EQ,NE,GT,GE,LT,LE,EXISTS,Not IN, Not EXISTS For these expressions the SQL SubQuery is not parsed by ebean and just used as is. --- .../main/java/io/ebean/ExpressionFactory.java | 94 +++++++++++++++- .../main/java/io/ebean/ExpressionList.java | 88 +++++++++++++++ .../expression/DefaultExpressionFactory.java | 73 ++++++++++-- .../expression/DefaultExpressionList.java | 94 +++++++++------- .../expression/ExistsQueryExpression.java | 4 +- .../expression/ExistsSqlQueryExpression.java | 106 ++++++++++++++++++ .../server/expression/JunctionExpression.java | 90 +++++++++------ .../server/expression/SubQueryExpression.java | 21 +--- .../server/expression/SubQueryOp.java | 17 +++ .../expression/SubQueryRawExpression.java | 61 ++++++++++ .../expression/InQueryExpressionTest.java | 4 +- .../io/ebean/typequery/PBaseComparable.java | 44 ++++++++ .../io/ebean/typequery/PBaseValueEqual.java | 44 ++++++++ .../java/io/ebean/typequery/TQRootBean.java | 22 ++++ .../test/java/org/querytest/QOrderTest.java | 102 +++++++++++++++++ .../org/tests/query/TestWhereRawClause.java | 93 ++++++++++++++- 16 files changed, 844 insertions(+), 113 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsSqlQueryExpression.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryOp.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryRawExpression.java diff --git a/ebean-api/src/main/java/io/ebean/ExpressionFactory.java b/ebean-api/src/main/java/io/ebean/ExpressionFactory.java index da84e2836..e81f81636 100644 --- a/ebean-api/src/main/java/io/ebean/ExpressionFactory.java +++ b/ebean-api/src/main/java/io/ebean/ExpressionFactory.java @@ -1,10 +1,6 @@ package io.ebean; -import io.ebean.search.Match; -import io.ebean.search.MultiMatch; -import io.ebean.search.TextCommonTerms; -import io.ebean.search.TextQueryString; -import io.ebean.search.TextSimple; +import io.ebean.search.*; import java.util.Collection; import java.util.Map; @@ -423,6 +419,94 @@ public interface ExpressionFactory { */ Expression inOrEmpty(String propertyName, Collection values); + /** + * EXISTS a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression exists(String sqlSubQuery, Object... bindValues); + + /** + * Not EXISTS a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression notExists(String sqlSubQuery, Object... bindValues); + + /** + * IN a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Not IN a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Equal To a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Not Equal To a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Greater Than or Equal To a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Greater Than a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Less Than or Equal To a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Less Than a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + Expression ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + /** * Not In - property has a value in the array of values. */ diff --git a/ebean-api/src/main/java/io/ebean/ExpressionList.java b/ebean-api/src/main/java/io/ebean/ExpressionList.java index 211da6664..4d0a2fc18 100644 --- a/ebean-api/src/main/java/io/ebean/ExpressionList.java +++ b/ebean-api/src/main/java/io/ebean/ExpressionList.java @@ -1141,6 +1141,94 @@ public interface ExpressionList { */ ExpressionList inPairs(Pairs pairs); + /** + * EXISTS a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList exists(String sqlSubQuery, Object... bindValues); + + /** + * Not EXISTS a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList notExists(String sqlSubQuery, Object... bindValues); + + /** + * IN a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Not IN a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Equal To a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Not Equal To a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Greater Than a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Greater Than or Equal To a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Less Than a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + + /** + * Less Than or Equal To a raw SQL SubQuery. + * + * @param propertyName The bean property + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + ExpressionList leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues); + /** * In - using a subQuery. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java index b6cc327db..1ad8a9014 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java @@ -5,7 +5,6 @@ import io.ebean.bean.EntityBean; import io.ebean.search.*; import io.ebeaninternal.api.SpiExpressionFactory; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.expression.SubQueryExpression.SQOp; import io.ebeaninternal.server.grammer.EqlParser; import java.util.Arrays; @@ -149,7 +148,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { @Override public Expression eq(String propertyName, Query subQuery) { - return new SubQueryExpression(SQOp.EQ, propertyName, (SpiQuery) subQuery); + return new SubQueryExpression(SubQueryOp.EQ, propertyName, (SpiQuery) subQuery); } /** @@ -170,7 +169,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { @Override public Expression ne(String propertyName, Query subQuery) { - return new SubQueryExpression(SQOp.NE, propertyName, (SpiQuery) subQuery); + return new SubQueryExpression(SubQueryOp.NE, propertyName, (SpiQuery) subQuery); } /** @@ -260,7 +259,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { @Override public Expression gt(String propertyName, Query subQuery) { - return new SubQueryExpression(SQOp.GT, propertyName, (SpiQuery) subQuery); + return new SubQueryExpression(SubQueryOp.GT, propertyName, (SpiQuery) subQuery); } /** @@ -286,7 +285,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { @Override public Expression ge(String propertyName, Query subQuery) { - return new SubQueryExpression(SQOp.GE, propertyName, (SpiQuery) subQuery); + return new SubQueryExpression(SubQueryOp.GE, propertyName, (SpiQuery) subQuery); } /** @@ -313,7 +312,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { @Override public Expression lt(String propertyName, Query subQuery) { - return new SubQueryExpression(SQOp.LT, propertyName, (SpiQuery) subQuery); + return new SubQueryExpression(SubQueryOp.LT, propertyName, (SpiQuery) subQuery); } /** @@ -326,7 +325,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { @Override public Expression le(String propertyName, Query subQuery) { - return new SubQueryExpression(SQOp.LE, propertyName, (SpiQuery) subQuery); + return new SubQueryExpression(SubQueryOp.LE, propertyName, (SpiQuery) subQuery); } /** @@ -480,12 +479,68 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { return new InExpression(propertyName, values, false); } + /** + * In - using a subQuery. + */ + @Override + public Expression exists(String subQuery, Object... bindValues) { + return new ExistsSqlQueryExpression(false, subQuery, bindValues); + } + + /** + * In - using a subQuery. + */ + @Override + public Expression notExists(String subQuery, Object... bindValues) { + return new ExistsSqlQueryExpression(true, subQuery, bindValues); + } + /** * In - using a subQuery. */ @Override public Expression in(String propertyName, Query subQuery) { - return new SubQueryExpression(SQOp.IN, propertyName, (SpiQuery) subQuery); + return new SubQueryExpression(SubQueryOp.IN, propertyName, (SpiQuery) subQuery); + } + + @Override + public Expression inSubQuery(String propertyName, String subQuery, Object... bindValues) { + return new SubQueryRawExpression(SubQueryOp.IN, propertyName, subQuery, bindValues); + } + + @Override + public Expression notInSubQuery(String propertyName, String subQuery, Object... bindValues) { + return new SubQueryRawExpression(SubQueryOp.NOTIN, propertyName, subQuery, bindValues); + } + + @Override + public Expression eqSubQuery(String propertyName, String subQuery, Object... bindValues) { + return new SubQueryRawExpression(SubQueryOp.EQ, propertyName, subQuery, bindValues); + } + + @Override + public Expression neSubQuery(String propertyName, String subQuery, Object... bindValues) { + return new SubQueryRawExpression(SubQueryOp.NE, propertyName, subQuery, bindValues); + } + + @Override + public Expression geSubQuery(String propertyName, String subQuery, Object... bindValues) { + return new SubQueryRawExpression(SubQueryOp.GE, propertyName, subQuery, bindValues); + } + + @Override + public Expression gtSubQuery(String propertyName, String subQuery, Object... bindValues) { + return new SubQueryRawExpression(SubQueryOp.GT, propertyName, subQuery, bindValues); + } + + @Override + public Expression leSubQuery(String propertyName, String subQuery, Object... bindValues) { + return new SubQueryRawExpression(SubQueryOp.LE, propertyName, subQuery, bindValues); + } + + @Override + public Expression ltSubQuery(String propertyName, String subQuery, Object... bindValues) { + return new SubQueryRawExpression(SubQueryOp.LT, propertyName, subQuery, bindValues); } /** @@ -527,7 +582,7 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { */ @Override public Expression notIn(String propertyName, Query subQuery) { - return new SubQueryExpression(SQOp.NOTIN, propertyName, (SpiQuery) subQuery); + return new SubQueryExpression(SubQueryOp.NOTIN, propertyName, (SpiQuery) subQuery); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java index 3e25abe1b..3a015e0fa 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java @@ -2,51 +2,16 @@ package io.ebeaninternal.server.expression; import io.avaje.lang.NonNullApi; import io.avaje.lang.Nullable; -import io.ebean.CacheMode; -import io.ebean.CountDistinctOrder; -import io.ebean.DtoQuery; -import io.ebean.Expression; -import io.ebean.ExpressionFactory; -import io.ebean.ExpressionList; -import io.ebean.FetchGroup; -import io.ebean.FetchPath; -import io.ebean.FutureIds; -import io.ebean.FutureList; -import io.ebean.FutureRowCount; -import io.ebean.Junction; -import io.ebean.OrderBy; -import io.ebean.PagedList; -import io.ebean.Pairs; -import io.ebean.Query; -import io.ebean.QueryIterator; -import io.ebean.Transaction; -import io.ebean.UpdateQuery; -import io.ebean.Version; +import io.ebean.*; import io.ebean.event.BeanQueryRequest; -import io.ebean.search.Match; -import io.ebean.search.MultiMatch; -import io.ebean.search.TextCommonTerms; -import io.ebean.search.TextQueryString; -import io.ebean.search.TextSimple; -import io.ebeaninternal.api.BindValuesKey; -import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.api.NaturalKeyQueryData; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionList; -import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.api.SpiExpressionValidation; -import io.ebeaninternal.api.SpiJunction; +import io.ebean.search.*; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.deploy.BeanDescriptor; import java.io.IOException; import java.sql.Connection; import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; @@ -953,6 +918,57 @@ public class DefaultExpressionList implements SpiExpressionList { return add(expr.inPairs(pairs)); } + + @Override + public ExpressionList exists(String sqlSubQuery, Object... bindValues) { + return add(expr.exists(sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList notExists(String sqlSubQuery, Object... bindValues) { + return add(expr.notExists(sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return add(expr.inSubQuery(propertyName, sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return add(expr.notInSubQuery(propertyName, sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return add(expr.eqSubQuery(propertyName, sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return add(expr.neSubQuery(propertyName, sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return add(expr.gtSubQuery(propertyName, sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return add(expr.geSubQuery(propertyName, sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return add(expr.ltSubQuery(propertyName, sqlSubQuery, bindValues)); + } + + @Override + public ExpressionList leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return add(expr.leSubQuery(propertyName, sqlSubQuery, bindValues)); + } + @Override public ExpressionList in(String propertyName, Query subQuery) { return add(expr.in(propertyName, subQuery)); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java index 30b40d53f..60b831dc7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsQueryExpression.java @@ -93,9 +93,9 @@ final class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreE @Override public void addSql(SpiExpressionRequest request) { if (not) { - request.append(" not"); + request.append("not "); } - request.append(" exists (").parse(sql).append(")"); + request.append("exists (").parse(sql).append(")"); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsSqlQueryExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsSqlQueryExpression.java new file mode 100644 index 000000000..7f09de4c5 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/ExistsSqlQueryExpression.java @@ -0,0 +1,106 @@ +package io.ebeaninternal.server.expression; + +import io.ebean.event.BeanQueryRequest; +import io.ebeaninternal.api.*; +import io.ebeaninternal.server.deploy.BeanDescriptor; + +import java.util.Arrays; + +final class ExistsSqlQueryExpression implements SpiExpression, UnsupportedDocStoreExpression { + + private final boolean not; + private final String subQuery; + private final Object[] bindParams; + + ExistsSqlQueryExpression(boolean not, String subQuery, Object[] bindParams) { + this.not = not; + this.subQuery = subQuery; + this.bindParams = bindParams; + } + + @Override + public void prefixProperty(String path) { + // do nothing + } + + @Override + public boolean naturalKey(NaturalKeyQueryData data) { + // can't use naturalKey cache + return false; + } + + @Override + public void simplify() { + // do nothing + } + + @Override + public void writeDocQuery(DocQueryContext context) { + throw new IllegalStateException("Not supported"); + } + + @Override + public Object getIdEqualTo(String idName) { + // always return null for this expression + return null; + } + + @Override + public void prepareExpression(BeanQueryRequest request) { + // do nothing + } + + @Override + public SpiExpression copyForPlanKey() { + return this; + } + + @Override + public void queryPlanHash(StringBuilder builder) { + builder.append("ExistsSqlQuery[").append(" not:").append(not); + builder.append(" sql:").append(subQuery).append(" ?:").append(bindParams.length).append("]"); + } + + @Override + public void queryBindKey(BindValuesKey key) { + for (Object value : bindParams) { + key.add(value); + } + } + + @Override + public void addSql(SpiExpressionRequest request) { + if (not) { + request.append("not "); + } + request.append("exists (").parse(subQuery).append(")"); + } + + @Override + public void addBindValues(SpiExpressionRequest request) { + for (Object bindParam : bindParams) { + request.addBindValue(bindParam); + } + } + + @Override + public boolean isSameByBind(SpiExpression other) { + final ExistsSqlQueryExpression that = (ExistsSqlQueryExpression) other; + return Arrays.equals(bindParams, that.bindParams); + } + + @Override + public String nestedPath(BeanDescriptor desc) { + return null; + } + + @Override + public void containsMany(BeanDescriptor desc, ManyWhereJoins whereManyJoins) { + // Nothing to do for exists expression + } + + @Override + public void validate(SpiExpressionValidation validation) { + // Nothing to do for exists expression + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java index 01ee2147f..87d6ae331 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java @@ -2,48 +2,16 @@ package io.ebeaninternal.server.expression; import io.avaje.lang.NonNullApi; import io.avaje.lang.Nullable; -import io.ebean.CacheMode; -import io.ebean.CountDistinctOrder; -import io.ebean.DtoQuery; -import io.ebean.Expression; -import io.ebean.ExpressionList; -import io.ebean.FetchGroup; -import io.ebean.FetchPath; -import io.ebean.FutureIds; -import io.ebean.FutureList; -import io.ebean.FutureRowCount; -import io.ebean.Junction; -import io.ebean.OrderBy; -import io.ebean.PagedList; -import io.ebean.Pairs; -import io.ebean.Query; -import io.ebean.QueryIterator; -import io.ebean.Transaction; -import io.ebean.UpdateQuery; -import io.ebean.Version; +import io.ebean.*; import io.ebean.event.BeanQueryRequest; -import io.ebean.search.Match; -import io.ebean.search.MultiMatch; -import io.ebean.search.TextCommonTerms; -import io.ebean.search.TextQueryString; -import io.ebean.search.TextSimple; -import io.ebeaninternal.api.BindValuesKey; -import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.api.NaturalKeyQueryData; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.api.SpiExpressionValidation; -import io.ebeaninternal.api.SpiJunction; +import io.ebean.search.*; +import io.ebeaninternal.api.*; import io.ebeaninternal.server.deploy.BeanDescriptor; import java.io.IOException; import java.sql.Connection; import java.sql.Timestamp; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; @@ -762,6 +730,56 @@ final class JunctionExpression implements SpiJunction, SpiExpression, Expr return exprList.in(propertyName, subQuery); } + @Override + public ExpressionList exists(String sqlSubQuery, Object... bindValues) { + return exprList.exists(sqlSubQuery, bindValues); + } + + @Override + public ExpressionList notExists(String sqlSubQuery, Object... bindValues) { + return exprList.notExists(sqlSubQuery, bindValues); + } + + @Override + public ExpressionList inSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return exprList.inSubQuery(propertyName, sqlSubQuery, bindValues); + } + + @Override + public ExpressionList notInSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return exprList.notInSubQuery(propertyName, sqlSubQuery, bindValues); + } + + @Override + public ExpressionList eqSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return exprList.eqSubQuery(propertyName, sqlSubQuery, bindValues); + } + + @Override + public ExpressionList neSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return exprList.neSubQuery(propertyName, sqlSubQuery, bindValues); + } + + @Override + public ExpressionList gtSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return exprList.gtSubQuery(propertyName, sqlSubQuery, bindValues); + } + + @Override + public ExpressionList geSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return exprList.geSubQuery(propertyName, sqlSubQuery, bindValues); + } + + @Override + public ExpressionList ltSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return exprList.ltSubQuery(propertyName, sqlSubQuery, bindValues); + } + + @Override + public ExpressionList leSubQuery(String propertyName, String sqlSubQuery, Object... bindValues) { + return exprList.leSubQuery(propertyName, sqlSubQuery, bindValues); + } + @Override public ExpressionList notIn(String propertyName, Collection values) { return exprList.notIn(propertyName, values); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java index 21fd33c8b..ff60d7479 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryExpression.java @@ -12,33 +12,18 @@ import java.util.List; */ final class SubQueryExpression extends AbstractExpression implements UnsupportedDocStoreExpression { - enum SQOp { - EQ(" = "), - NE(" <> "), - GT(" > "), - GE(" >= "), - LT(" < "), - LE(" <= "), - IN(" in "), - NOTIN(" not in "); - final String expression; - SQOp(String expression) { - this.expression = expression; - } - } - - private final SQOp op; + private final SubQueryOp op; private final SpiQuery subQuery; private List bindParams; private String sql; - SubQueryExpression(SQOp op, String propertyName, SpiQuery subQuery) { + SubQueryExpression(SubQueryOp op, String propertyName, SpiQuery subQuery) { super(propertyName); this.op = op; this.subQuery = subQuery; } - SubQueryExpression(SQOp op, String propertyName, String sql, List bindParams) { + SubQueryExpression(SubQueryOp op, String propertyName, String sql, List bindParams) { super(propertyName); this.op = op; this.subQuery = null; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryOp.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryOp.java new file mode 100644 index 000000000..2ea6a7f1a --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryOp.java @@ -0,0 +1,17 @@ +package io.ebeaninternal.server.expression; + +enum SubQueryOp { + EQ(" = "), + NE(" <> "), + GT(" > "), + GE(" >= "), + LT(" < "), + LE(" <= "), + IN(" in "), + NOTIN(" not in "); + final String expression; + + SubQueryOp(String expression) { + this.expression = expression; + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryRawExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryRawExpression.java new file mode 100644 index 000000000..007386d5b --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/SubQueryRawExpression.java @@ -0,0 +1,61 @@ +package io.ebeaninternal.server.expression; + +import io.ebeaninternal.api.BindValuesKey; +import io.ebeaninternal.api.SpiExpression; +import io.ebeaninternal.api.SpiExpressionRequest; + +import java.util.Arrays; + +/** + * Raw SQL based Sub-Query expression. + */ +final class SubQueryRawExpression extends AbstractExpression implements UnsupportedDocStoreExpression { + + private final SubQueryOp op; + private final String subQuery; + private final Object[] bindParams; + + SubQueryRawExpression(SubQueryOp op, String propertyName, String subQuery, Object[] bindParams) { + super(propertyName); + this.op = op; + this.subQuery = subQuery; + this.bindParams = bindParams; + } + + @Override + public void writeDocQuery(DocQueryContext context) { + throw new IllegalStateException("Not supported"); + } + + @Override + public void queryPlanHash(StringBuilder builder) { + builder.append("SubQueryRaw[").append(propName).append(op.expression) + .append(" subQuery:").append(subQuery) + .append(" ?:").append(bindParams.length).append("]"); + } + + @Override + public void queryBindKey(BindValuesKey key) { + for (Object value : bindParams) { + key.add(value); + } + } + + @Override + public void addSql(SpiExpressionRequest request) { + request.property(propName).append(op.expression).append("(").append(subQuery).append(")"); + } + + @Override + public void addBindValues(SpiExpressionRequest request) { + for (Object bindParam : bindParams) { + request.addBindValue(bindParam); + } + } + + @Override + public boolean isSameByBind(SpiExpression other) { + final SubQueryRawExpression that = (SubQueryRawExpression) other; + return Arrays.equals(bindParams, that.bindParams); + } +} diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/expression/InQueryExpressionTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/expression/InQueryExpressionTest.java index 48adbdd1d..29e60ae13 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/expression/InQueryExpressionTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/expression/InQueryExpressionTest.java @@ -13,14 +13,14 @@ import static org.mockito.Mockito.verify; public class InQueryExpressionTest extends BaseExpressionTest { private SubQueryExpression exp(String propertyName, boolean not, String sql, Object... bindValues) { - var op = not ? SubQueryExpression.SQOp.NOTIN : SubQueryExpression.SQOp.IN; + var op = not ? SubQueryOp.NOTIN : SubQueryOp.IN; return new SubQueryExpression(op, propertyName, sql, Arrays.asList(bindValues)); } @Test void copy_subQuery_expectNewInstance() { SpiQuery subQuery = mock(SpiQuery.class); - var orig = new SubQueryExpression(SubQueryExpression.SQOp.IN, "name", subQuery); + var orig = new SubQueryExpression(SubQueryOp.IN, "name", subQuery); SpiExpression copy = orig.copy(); assertThat(copy).isNotSameAs(orig); verify(subQuery).copy(); diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/PBaseComparable.java b/ebean-querybean/src/main/java/io/ebean/typequery/PBaseComparable.java index dfdac7cad..0514f7ada 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/PBaseComparable.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/PBaseComparable.java @@ -413,4 +413,48 @@ public abstract class PBaseComparable extends PBaseValueEqual { expr().gt(_name, subQuery); return _root; } + + /** + * Less Than or Equal To a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R leSubQuery(String sqlSubQuery, Object... bindValues) { + expr().leSubQuery(_name, sqlSubQuery, bindValues); + return _root; + } + + /** + * Less Than a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R ltSubQuery(String sqlSubQuery, Object... bindValues) { + expr().ltSubQuery(_name, sqlSubQuery, bindValues); + return _root; + } + + /** + * Greater Than or Equal To a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R geSubQuery(String sqlSubQuery, Object... bindValues) { + expr().geSubQuery(_name, sqlSubQuery, bindValues); + return _root; + } + + /** + * Greater Than a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R gtSubQuery(String sqlSubQuery, Object... bindValues) { + expr().gtSubQuery(_name, sqlSubQuery, bindValues); + return _root; + } } diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/PBaseValueEqual.java b/ebean-querybean/src/main/java/io/ebean/typequery/PBaseValueEqual.java index 1f25c916e..de6d563bd 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/PBaseValueEqual.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/PBaseValueEqual.java @@ -301,6 +301,50 @@ public abstract class PBaseValueEqual extends TQPropertyBase { return _root; } + /** + * IN a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R inSubQuery(String sqlSubQuery, Object... bindValues) { + expr().inSubQuery(_name, sqlSubQuery, bindValues); + return _root; + } + + /** + * Not IN a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R notInSubQuery(String sqlSubQuery, Object... bindValues) { + expr().notInSubQuery(_name, sqlSubQuery, bindValues); + return _root; + } + + /** + * Equal To a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R eqSubQuery(String sqlSubQuery, Object... bindValues) { + expr().eqSubQuery(_name, sqlSubQuery, bindValues); + return _root; + } + + /** + * Not Equal To a raw SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R neSubQuery(String sqlSubQuery, Object... bindValues) { + expr().neSubQuery(_name, sqlSubQuery, bindValues); + return _root; + } + /** * Property is equal to the result of a sub-query. * diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java index 8ba6e51f7..847ff86b0 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java @@ -733,6 +733,28 @@ public abstract class TQRootBean { return root; } + /** + * EXISTS using a SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R exists(String sqlSubQuery, Object... bindValues) { + query().where().exists(sqlSubQuery, bindValues); + return root; + } + + /** + * Not EXISTS using a SQL SubQuery. + * + * @param sqlSubQuery The SQL SubQuery + * @param bindValues Optional bind values if the SubQuery uses {@code ? } bind values. + */ + public final R notExists(String sqlSubQuery, Object... bindValues) { + query().where().notExists(sqlSubQuery, bindValues); + return root; + } + /** * Execute using "for update" clause which results in the DB locking the record. */ diff --git a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java index 935327359..bcfa451ec 100644 --- a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java @@ -268,6 +268,84 @@ public class QOrderTest { assertThat(sql).isEqualTo("select t0.id, t0.status from o_order t0 join be_customer t1 on t1.id = t0.customer_id where (coalesce(t1.version,0) > ? or t0.id < ?)"); } + @Test + void geSqlSubQuery() { + var c = QCustomer.alias(); + + var query = new QCustomer() + .select(c.id) + .registered.geSubQuery("select max(o.order_date) as foo from o_order o") + .query(); + query.findList(); + + assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered >= (select max(o.order_date) as foo from o_order o)"); + } + + @Test + void gtSqlSubQuery() { + var c = QCustomer.alias(); + + var query = new QCustomer() + .select(c.id) + .registered.gtSubQuery("select max(o.order_date) as foo from o_order o") + .query(); + query.findList(); + + assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered > (select max(o.order_date) as foo from o_order o)"); + } + + @Test + void leSqlSubQuery() { + var c = QCustomer.alias(); + + var query = new QCustomer() + .select(c.id) + .registered.leSubQuery("select max(o.order_date) as foo from o_order o") + .query(); + query.findList(); + + assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <= (select max(o.order_date) as foo from o_order o)"); + } + + @Test + void ltSqlSubQuery() { + var c = QCustomer.alias(); + + var query = new QCustomer() + .select(c.id) + .registered.ltSubQuery("select max(o.order_date) as foo from o_order o") + .query(); + query.findList(); + + assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered < (select max(o.order_date) as foo from o_order o)"); + } + + @Test + void eqSqlSubQuery() { + var c = QCustomer.alias(); + + var query = new QCustomer() + .select(c.id) + .registered.eqSubQuery("select max(o.order_date) as foo from o_order o") + .query(); + query.findList(); + + assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered = (select max(o.order_date) as foo from o_order o)"); + } + + @Test + void neSqlSubQuery() { + var c = QCustomer.alias(); + + var query = new QCustomer() + .select(c.id) + .registered.neSubQuery("select max(o.order_date) as foo from o_order o") + .query(); + query.findList(); + + assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <> (select max(o.order_date) as foo from o_order o)"); + } + @Test void geSubQuery() { var c = QCustomer.alias(); @@ -394,6 +472,30 @@ public class QOrderTest { assertThat(sql).contains(" exists (select 1 from o_order_detail od where od.order_qty > ? and od.id = t1.id)"); } + @Test + void sqlSubQueryExists() { + Query query = new QOrder() + .exists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10) + .orderBy("orderDate").query(); + + query.findList(); + + String sql = query.getGeneratedSql(); + assertThat(sql).contains(" exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id) order by t0.order_date"); + } + + @Test + void sqlSubQueryNotExists() { + Query query = new QOrder() + .notExists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10) + .orderBy("orderDate").query(); + + query.findList(); + + String sql = query.getGeneratedSql(); + assertThat(sql).contains(" not exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id) order by t0.order_date"); + } + @Test void subQueryNotExists() { Query subQuery = new QOrderDetail() diff --git a/ebean-test/src/test/java/org/tests/query/TestWhereRawClause.java b/ebean-test/src/test/java/org/tests/query/TestWhereRawClause.java index 7c2b36603..7de9f77f6 100644 --- a/ebean-test/src/test/java/org/tests/query/TestWhereRawClause.java +++ b/ebean-test/src/test/java/org/tests/query/TestWhereRawClause.java @@ -1,12 +1,12 @@ package org.tests.query; -import io.ebean.xtest.BaseTestCase; import io.ebean.DB; import io.ebean.Expr; import io.ebean.Query; -import io.ebean.xtest.ForPlatform; import io.ebean.annotation.Platform; import io.ebean.test.LoggedSql; +import io.ebean.xtest.BaseTestCase; +import io.ebean.xtest.ForPlatform; import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.Order; @@ -187,4 +187,93 @@ public class TestWhereRawClause extends BaseTestCase { .findList(); } + + @Test + void testSqlSubQueryExists() { + ResetBasicData.reset(); + + LoggedSql.start(); + DB.find(Order.class) + .select("id") + .where() + .exists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10) + .findList(); + + DB.find(Order.class) + .select("id") + .where() + .notExists("select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id", 10) + .findList(); + + List sql = LoggedSql.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("select t0.id from o_order t0 where exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id)"); + assertThat(sql.get(1)).contains("select t0.id from o_order t0 where not exists (select 1 from o_order_detail od where od.order_qty > ? and od.order_id = t0.id)"); + } + + @Test + void testSqlSubQueryExpressions() { + ResetBasicData.reset(); + + LoggedSql.start(); + DB.find(Customer.class) + .select("name") + .where() + .inSubQuery("id", "select c.id as id from o_customer c") + .findList(); + + DB.find(Customer.class) + .select("name") + .where() + .notInSubQuery("id", "select c.id as id from o_customer c") + .findList(); + + DB.find(Customer.class) + .select("name") + .where() + .eqSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob") + .findList(); + + DB.find(Customer.class) + .select("name") + .where() + .neSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob") + .findList(); + + DB.find(Customer.class) + .select("name") + .where() + .gtSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob") + .findList(); + + DB.find(Customer.class) + .select("name") + .where() + .geSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob") + .findList(); + + DB.find(Customer.class) + .select("name") + .where() + .ltSubQuery("id", "select c.id as id from o_customer c where c.name = ?", "Rob") + .findList(); + + DB.find(Customer.class) + .select("name") + .where() + .leSubQuery("id", "select c.id as id from o_customer c where c.name = ? and 1 = ?", "Rob", 1) + .like("name", "R%") + .findList(); + + List sql = LoggedSql.stop(); + assertThat(sql).hasSize(8); + assertThat(sql.get(0)).contains("select t0.id, t0.name from o_customer t0 where t0.id in (select c.id as id from o_customer c)"); + assertThat(sql.get(1)).contains("select t0.id, t0.name from o_customer t0 where t0.id not in (select c.id as id from o_customer c)"); + assertThat(sql.get(2)).contains("select t0.id, t0.name from o_customer t0 where t0.id = (select c.id as id from o_customer c where c.name = ?)"); + assertThat(sql.get(3)).contains("select t0.id, t0.name from o_customer t0 where t0.id <> (select c.id as id from o_customer c where c.name = ?)"); + assertThat(sql.get(4)).contains("select t0.id, t0.name from o_customer t0 where t0.id > (select c.id as id from o_customer c where c.name = ?)"); + assertThat(sql.get(5)).contains("select t0.id, t0.name from o_customer t0 where t0.id >= (select c.id as id from o_customer c where c.name = ?)"); + assertThat(sql.get(6)).contains("select t0.id, t0.name from o_customer t0 where t0.id < (select c.id as id from o_customer c where c.name = ?)"); + assertThat(sql.get(7)).contains("select t0.id, t0.name from o_customer t0 where t0.id <= (select c.id as id from o_customer c where c.name = ? and 1 = ?)"); + } }