diff --git a/ebean-api/src/main/java/io/ebean/DInTuples.java b/ebean-api/src/main/java/io/ebean/DInTuples.java index b244d8459..6f6e67672 100644 --- a/ebean-api/src/main/java/io/ebean/DInTuples.java +++ b/ebean-api/src/main/java/io/ebean/DInTuples.java @@ -1,27 +1,32 @@ package io.ebean; +import io.ebean.service.SpiInTuples; + import java.util.ArrayList; import java.util.Collections; import java.util.List; /** - * + * Default implementation of SpiInTuples. */ -final class DInTuples implements InTuples { +final class DInTuples implements SpiInTuples { private final String[] properties; - private final List entries = new ArrayList<>(); + private final int propertyCount; + private final List entries = new ArrayList<>(); DInTuples(String[] properties) { this.properties = properties; + this.propertyCount = properties.length; } - /** - */ @Override public InTuples add(Object... values) { - entries.add(new DEntry(values)); + if (values.length != propertyCount) { + throw new IllegalArgumentException("Require " + propertyCount + " values but got " + values.length); + } + entries.add(values); return this; } @@ -37,26 +42,8 @@ final class DInTuples implements InTuples { * Return all the value pairs. */ @Override - public List entries() { + public List entries() { return Collections.unmodifiableList(entries); } - /** - * A pair of 2 value objects. - *

- * Used to support inPairs() expression. - */ - static final class DEntry implements InTuples.Entry { - - private final Object[] vals; - - DEntry(Object[] vals) { - this.vals = vals; - } - - @Override - public Object[] values() { - return vals; - } - } } diff --git a/ebean-api/src/main/java/io/ebean/InTuples.java b/ebean-api/src/main/java/io/ebean/InTuples.java index 2ee158fcb..174702956 100644 --- a/ebean-api/src/main/java/io/ebean/InTuples.java +++ b/ebean-api/src/main/java/io/ebean/InTuples.java @@ -29,28 +29,8 @@ public interface InTuples { } /** - * Add a tuple entry. + * Add a tuple entry. All values must be non-null. */ InTuples add(Object... values); - /** - * Return the properties of the tuples. - */ - String[] properties(); - - /** - * Return all the tuple entries. - */ - List entries(); - - /** - * A tuple entry. - */ - interface Entry { - - /** - * Return all the values for this entry. - */ - Object[] values(); - } } diff --git a/ebean-api/src/main/java/io/ebean/service/SpiInTuples.java b/ebean-api/src/main/java/io/ebean/service/SpiInTuples.java new file mode 100644 index 000000000..abdda4f9b --- /dev/null +++ b/ebean-api/src/main/java/io/ebean/service/SpiInTuples.java @@ -0,0 +1,22 @@ +package io.ebean.service; + +import io.ebean.InTuples; + +import java.util.List; + +/** + * Internal extension to InTuples. + */ +public interface SpiInTuples extends InTuples { + + /** + * Return the properties of the tuples. + */ + String[] properties(); + + /** + * Return all the tuple entries. + */ + List entries(); + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InTuplesExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InTuplesExpression.java index e8f10fe22..09d7eb011 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/InTuplesExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/InTuplesExpression.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.expression; import io.ebean.InTuples; +import io.ebean.service.SpiInTuples; import io.ebeaninternal.api.BindValuesKey; import io.ebeaninternal.api.NaturalKeyQueryData; import io.ebeaninternal.api.SpiExpression; @@ -8,18 +9,21 @@ import io.ebeaninternal.api.SpiExpressionRequest; import java.util.List; +import static java.util.Objects.requireNonNull; + final class InTuplesExpression extends AbstractExpression { private final boolean not; private final String[] properties; - private final List entries; + private final List entries; InTuplesExpression(InTuples pairs, boolean not) { - super(pairs.properties()[0]); - this.properties = pairs.properties(); + super(""); + SpiInTuples inTuples = (SpiInTuples)pairs; + this.properties = inTuples.properties(); // the entries might be modified on cache hit. - this.entries = pairs.entries(); + this.entries = inTuples.entries(); this.not = not; } @@ -35,9 +39,10 @@ final class InTuplesExpression extends AbstractExpression { @Override public void addBindValues(SpiExpressionRequest request) { - for (InTuples.Entry entry : entries) { - for (Object val : entry.values()) { - request.addBindValue(val); + for (Object[] entry : entries) { + for (Object value : entry) { + requireNonNull(value); + request.addBindValue(value); } } } @@ -48,7 +53,6 @@ final class InTuplesExpression extends AbstractExpression { request.append(not ? SQL_TRUE : SQL_FALSE); return; } - request.append("("); for (int i = 0; i < properties.length; i++) { if (i > 0) { @@ -97,9 +101,9 @@ final class InTuplesExpression extends AbstractExpression { @Override public void queryBindKey(BindValuesKey key) { key.add(entries.size()); - for (InTuples.Entry entry : entries) { - for (Object val : entry.values()) { - key.add(val); + for (Object[] entry : entries) { + for (Object value : entry) { + key.add(value); } } } diff --git a/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java b/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java index 389e0a114..53aeec226 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java +++ b/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java @@ -1,6 +1,8 @@ package org.tests.model.basic.cache; import io.ebean.InTuples; +import io.ebean.annotation.Platform; +import io.ebean.service.SpiInTuples; import io.ebean.xtest.BaseTestCase; import io.ebean.CacheMode; import io.ebean.DB; @@ -9,6 +11,7 @@ import io.ebean.cache.ServerCache; import io.ebean.cache.ServerCacheManager; import io.ebean.cache.ServerCacheStatistics; import io.ebean.test.LoggedSql; +import io.ebean.xtest.IgnorePlatform; import org.junit.jupiter.api.Test; import java.util.List; @@ -422,6 +425,7 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { } } + @IgnorePlatform({Platform.SQLSERVER, Platform.DB2}) @Test public void findList_inTuples_noCache() { setup(); @@ -443,7 +447,9 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { List sql = LoggedSql.stop(); - assertThat(tuples.entries()).hasSize(3); + SpiInTuples spiTuples = (SpiInTuples)tuples; + assertThat(spiTuples.properties()).containsOnly("sku", "code"); + assertThat(spiTuples.entries()).hasSize(3); assertThat(list).hasSize(3); assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku,t0.code) in ((?,?),(?,?),(?,?)) order by t0.sku desc;"); }