diff --git a/ebean-api/src/main/java/io/ebean/DtoQuery.java b/ebean-api/src/main/java/io/ebean/DtoQuery.java index 853cfccb6..7de6c2694 100644 --- a/ebean-api/src/main/java/io/ebean/DtoQuery.java +++ b/ebean-api/src/main/java/io/ebean/DtoQuery.java @@ -2,6 +2,8 @@ package io.ebean; import io.avaje.lang.NonNullApi; import io.avaje.lang.Nullable; + +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.function.Consumer; @@ -127,6 +129,13 @@ public interface DtoQuery extends CancelableQuery { */ DtoQuery setParameter(String name, Object value); + /** + * Bind the named multi-value array parameter which we would use with Postgres ANY. + *

+ * For Postgres this binds an ARRAY rather than expands into multiple bind values. + */ + DtoQuery setArrayParameter(String name, Collection values); + /** * Bind the parameter by its index position (1 based like JDBC). */ diff --git a/ebean-api/src/main/java/io/ebean/SqlUpdate.java b/ebean-api/src/main/java/io/ebean/SqlUpdate.java index 927050d3f..9ce704922 100644 --- a/ebean-api/src/main/java/io/ebean/SqlUpdate.java +++ b/ebean-api/src/main/java/io/ebean/SqlUpdate.java @@ -1,5 +1,7 @@ package io.ebean; +import java.util.Collection; + /** * A SqlUpdate for executing insert update or delete statements. *

@@ -324,6 +326,13 @@ public interface SqlUpdate { */ SqlUpdate setParameter(String name, Object param); + /** + * Bind the named multi-value array parameter which we would use with Postgres ANY. + *

+ * For Postgres this binds an ARRAY rather than expands into multiple bind values. + */ + SqlUpdate setArrayParameter(String name, Collection values); + /** * Set a named parameter that has a null value. Exactly the same as * {@link #setNullParameter(String, int)}. diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java b/ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java index 151a0b899..ca813ae14 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java @@ -223,6 +223,15 @@ public final class BindParams implements Serializable { return p; } + /** + * Set a named In parameter that is multi-valued. + */ + public Param setArrayParameter(String name, Collection value) { + Param p = getParam(name); + p.setInValue(new MultiValueWrapper(value)); + return p; + } + /** * Set an encryption key as a bind value. *

diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java index 3f2e97893..222f00b9a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -24,6 +24,7 @@ import io.ebeaninternal.server.querydefn.OrmUpdateProperties; import io.ebeaninternal.server.rawsql.SpiRawSql; import java.sql.Timestamp; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -399,6 +400,11 @@ public interface SpiQuery extends Query, SpiQueryFetch, TxnProfileEventCod List getSoftDeletePredicates(); + /** + * Bind the named multi-value array parameter which we would use with Postgres ANY. + */ + void setArrayParameter(String name, Collection values); + /** * Return a copy of the query. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java index 8f66ae6eb..756c5665f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java @@ -331,6 +331,12 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate { return this; } + @Override + public SqlUpdate setArrayParameter(String name, Collection values) { + bindParams.setArrayParameter(name, values); + return this; + } + @Override public SqlUpdate setNull(String name, int jdbcType) { bindParams.setNullParameter(name, jdbcType); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java index 5b3c49aac..8120aa093 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java @@ -14,6 +14,7 @@ import io.ebeaninternal.server.dto.DtoMappingRequest; import io.ebeaninternal.server.dto.DtoQueryPlan; import javax.annotation.Nullable; +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.function.Consumer; @@ -148,6 +149,16 @@ public final class DefaultDtoQuery extends AbstractQuery implements SpiDtoQue return this; } + @Override + public DtoQuery setArrayParameter(String paramName, Collection values) { + if (ormQuery != null) { + ormQuery.setArrayParameter(paramName, values); + } else { + bindParams.setArrayParameter(paramName, values); + } + return this; + } + @Override public DtoQuery setParameters(Object... values) { if (ormQuery != null) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 908490080..5b700d3f6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1586,6 +1586,17 @@ public final class DefaultOrmQuery extends AbstractQuery implements SpiQuery< return this; } + @Override + public void setArrayParameter(String name, Collection values) { + if (namedParams != null) { + throw new IllegalStateException("setArrayParameter() not supported when EQL parsed query"); + } + if (bindParams == null) { + bindParams = new BindParams(); + } + bindParams.setArrayParameter(name, values); + } + @Override public boolean checkPagingOrderBy() { return orderById && !useDocStore; diff --git a/ebean-test/src/test/java/io/ebean/DtoQueryTest.java b/ebean-test/src/test/java/io/ebean/DtoQueryTest.java index 53b2b4ca4..f41928909 100644 --- a/ebean-test/src/test/java/io/ebean/DtoQueryTest.java +++ b/ebean-test/src/test/java/io/ebean/DtoQueryTest.java @@ -208,19 +208,33 @@ public class DtoQueryTest extends BaseTestCase { ResetBasicData.reset(); + LoggedSql.start(); List ids = Arrays.asList(1, 2); - List list = server().findDto(DCust.class, "select id, name from o_customer where id = any(?)") + List list = DB.findDto(DCust.class, "select id, name from o_customer where id = any(?)") .setParameter(ids) .findList(); assertThat(list).isNotEmpty(); - list = server().findDto(DCust.class, "select id, name from o_customer where id in (:idList)") + List list1 = DB.findDto(DCust.class, "select id, name from o_customer where id in (:idList)") .setParameter("idList", ids) .findList(); - assertThat(list).isNotEmpty(); + assertThat(list1).isNotEmpty(); + + + List list2 = DB.findDto(DCust.class, "select id, name from o_customer where id = any(:idList)") + .setArrayParameter("idList", ids) + .findList(); + + assertThat(list2).isNotEmpty(); + + List sql = LoggedSql.stop(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains(" id = any(?)"); + assertThat(sql.get(1)).contains(" id in (?,?)"); + assertThat(sql.get(2)).contains(" id = any(?)"); } @ForPlatform(Platform.POSTGRES) diff --git a/ebean-test/src/test/java/org/tests/model/array/TestDbArray_basic.java b/ebean-test/src/test/java/org/tests/model/array/TestDbArray_basic.java index 4afc1d098..0a4b1a0fb 100644 --- a/ebean-test/src/test/java/org/tests/model/array/TestDbArray_basic.java +++ b/ebean-test/src/test/java/org/tests/model/array/TestDbArray_basic.java @@ -335,7 +335,7 @@ public class TestDbArray_basic extends BaseTestCase { // javax.persistence.PersistenceException: // ERROR: syntax error at or near "$2" SqlUpdate update2 = DB.sqlUpdate("UPDATE earray_bean SET phone_numbers = :pns") - .setParameter("pns", phNumbers); + .setArrayParameter("pns", phNumbers); update2.execute(); found = DB.find(EArrayBean.class, bean.getId()); diff --git a/ebean-test/src/test/resources/ebean.properties b/ebean-test/src/test/resources/ebean.properties index 0fc9586f9..ffaa4a3d1 100644 --- a/ebean-test/src/test/resources/ebean.properties +++ b/ebean-test/src/test/resources/ebean.properties @@ -22,7 +22,7 @@ ebean.ddl.generate=true ebean.ddl.run=true ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp} ebean.packages=org.tests,org.etest -datasource.default=h2 +datasource.default=pg #datasource.h2.capturestacktrace=true ebean.dumpMetricsOnShutdown=true