This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new e76287c  CAY-2651 Support multiple IDs in the SelectById query
e76287c is described below

commit e76287c9fb22a06e0bbb0062e0464bc60fa5fdc6
Author: Nikita Timofeev <stari...@gmail.com>
AuthorDate: Wed Mar 11 16:07:29 2020 +0300

    CAY-2651 Support multiple IDs in the SelectById query
---
 RELEASE-NOTES.txt                                  |   1 +
 .../{SelectByIdTest.java => SelectById_IT.java}    |  19 +-
 .../java/org/apache/cayenne/query/SelectById.java  | 272 +++++++++++++++------
 .../org/apache/cayenne/query/SelectById_RunIT.java | 187 ++++++++++----
 4 files changed, 360 insertions(+), 119 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index fa40183..5827792 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -56,6 +56,7 @@ CAY-2611 Exclude system catalogs and schemas when run 
dbImport without config
 CAY-2612 Modeler: add lazy-loading to dbImport tab
 CAY-2645 Modeler: DbImport tree highlight improvement
 CAY-2650 Support using generated primary keys along with batch inserts
+CAY-2651 Support multiple IDs in the SelectById query
 
 Bug Fixes:
 
diff --git 
a/cayenne-client/src/test/java/org/apache/cayenne/query/SelectByIdTest.java 
b/cayenne-client/src/test/java/org/apache/cayenne/query/SelectById_IT.java
similarity index 70%
rename from 
cayenne-client/src/test/java/org/apache/cayenne/query/SelectByIdTest.java
rename to 
cayenne-client/src/test/java/org/apache/cayenne/query/SelectById_IT.java
index 6f44f70..2589203 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/query/SelectByIdTest.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/query/SelectById_IT.java
@@ -22,12 +22,21 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 
+import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.remote.hessian.service.HessianUtil;
 import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.junit.Test;
 
-public class SelectByIdTest {
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class SelectById_IT extends ServerCase {
+
+       @Inject
+       private EntityResolver resolver;
 
        @Test
        public void testSerializabilityWithHessian() throws Exception {
@@ -38,7 +47,11 @@ public class SelectByIdTest {
                SelectById<?> c1 = (SelectById<?>) clone;
 
                assertNotSame(o, c1);
-               assertEquals(o.entityType, c1.entityType);
-               assertEquals(o.singleId, c1.singleId);
+
+               ObjEntity artistEntity = resolver.getObjEntity(Artist.class);
+
+               assertEquals(artistEntity, o.root.resolve(resolver));
+               assertEquals(o.root.resolve(resolver), 
c1.root.resolve(resolver));
+               assertEquals(o.idSpec.getQualifier(artistEntity), 
c1.idSpec.getQualifier(artistEntity));
        }
 }
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SelectById.java 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SelectById.java
index a15ec2f..949efdb 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SelectById.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SelectById.java
@@ -29,15 +29,17 @@ import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.ObjEntity;
 
+import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
-import static java.util.Collections.singletonMap;
-import static org.apache.cayenne.exp.ExpressionFactory.matchAllDbExp;
+import static org.apache.cayenne.exp.ExpressionFactory.*;
 
 /**
- * A query to select single objects by id.
+ * A query to select objects by id.
  * 
  * @since 4.0
  */
@@ -45,88 +47,135 @@ public class SelectById<T> extends IndirectQuery 
implements Select<T> {
 
        private static final long serialVersionUID = -6589464349051607583L;
 
-       // type is not same as T, as T maybe be DataRow or scalar
-       // either type or entity name is specified, but not both
-       Class<?> entityType;
-       String entityName;
+       final QueryRoot root;
+       final IdSpec idSpec;
+       final boolean fetchingDataRows;
 
-       // only one of the two id forms is provided, but not both
-       Object singleId;
-       Map<String, ?> mapId;
-
-       boolean fetchingDataRows;
        QueryCacheStrategy cacheStrategy;
        String cacheGroup;
        PrefetchTreeNode prefetches;
 
        public static <T> SelectById<T> query(Class<T> entityType, Object id) {
-               SelectById<T> q = new SelectById<>();
-
-               q.entityType = entityType;
-               q.singleId = id;
-               q.fetchingDataRows = false;
-
-               return q;
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new SingleScalarIdSpec(id);
+               return new SelectById<>(root, idSpec);
        }
 
        public static <T> SelectById<T> query(Class<T> entityType, Map<String, 
?> id) {
-               SelectById<T> q = new SelectById<>();
-
-               q.entityType = entityType;
-               q.mapId = id;
-               q.fetchingDataRows = false;
-
-               return q;
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new SingleMapIdSpec(id);
+               return new SelectById<>(root, idSpec);
        }
 
        public static <T> SelectById<T> query(Class<T> entityType, ObjectId id) 
{
                checkObjectId(id);
+               QueryRoot root = resolver -> 
resolver.getObjEntity(id.getEntityName());
+               IdSpec idSpec = new SingleMapIdSpec(id.getIdSnapshot());
+               return new SelectById<>(root, idSpec);
+       }
 
-               SelectById<T> q = new SelectById<>();
-
-               q.entityName = id.getEntityName();
-               q.mapId = id.getIdSnapshot();
-               q.fetchingDataRows = false;
+       /**
+        * @since 4.2
+        */
+       public static <T> SelectById<T> query(Class<T> entityType, Object 
firstId, Object... otherIds) {
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new MultiScalarIdSpec(firstId, otherIds);
+               return new SelectById<>(root, idSpec);
+       }
 
-               return q;
+       /**
+        * @since 4.2
+        */
+       public static <T> SelectById<T> query(Class<T> entityType, 
Collection<Object> ids) {
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new MultiScalarIdSpec(ids);
+               return new SelectById<>(root, idSpec);
        }
 
-       public static SelectById<DataRow> dataRowQuery(Class<?> entityType, 
Object id) {
-               SelectById<DataRow> q = new SelectById<>();
+       /**
+        * @since 4.2
+        */
+       @SafeVarargs
+       public static <T> SelectById<T> query(Class<T> entityType, Map<String, 
?> firstId, Map<String, ?>... otherIds) {
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new MultiMapIdSpec(firstId, otherIds);
+               return new SelectById<>(root, idSpec);
+       }
 
-               q.entityType = entityType;
-               q.singleId = id;
-               q.fetchingDataRows = true;
+       /**
+        * @since 4.2
+        */
+       public static <T> SelectById<T> query(Class<T> entityType, ObjectId 
firstId, ObjectId... otherIds) {
+               checkObjectId(firstId);
+               for(ObjectId id : otherIds) {
+                       checkObjectId(id, firstId.getEntityName());
+               }
 
-               return q;
+               QueryRoot root = resolver -> 
resolver.getObjEntity(firstId.getEntityName());
+               IdSpec idSpec = new MultiMapIdSpec(firstId, otherIds);
+               return new SelectById<>(root, idSpec);
        }
 
-       public static SelectById<DataRow> dataRowQuery(Class<?> entityType, 
Map<String, Object> id) {
-               SelectById<DataRow> q = new SelectById<>();
-
-               q.entityType = entityType;
-               q.mapId = id;
-               q.fetchingDataRows = true;
+       public static SelectById<DataRow> dataRowQuery(Class<?> entityType, 
Object id) {
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new SingleScalarIdSpec(id);
+               return new SelectById<>(root, idSpec, true);
+       }
 
-               return q;
+       public static SelectById<DataRow> dataRowQuery(Class<?> entityType, 
Map<String, ?> id) {
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new SingleMapIdSpec(id);
+               return new SelectById<>(root, idSpec, true);
        }
 
        public static SelectById<DataRow> dataRowQuery(ObjectId id) {
                checkObjectId(id);
+               QueryRoot root = resolver -> 
resolver.getObjEntity(id.getEntityName());
+               IdSpec idSpec = new SingleMapIdSpec(id.getIdSnapshot());
+               return new SelectById<>(root, idSpec, true);
+       }
 
-               SelectById<DataRow> q = new SelectById<>();
-
-               q.entityName = id.getEntityName();
-               q.mapId = id.getIdSnapshot();
-               q.fetchingDataRows = true;
+       /**
+        * @since 4.2
+        */
+       public static SelectById<DataRow> dataRowQuery(Class<?> entityType, 
Object firstId, Object... otherIds) {
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new MultiScalarIdSpec(firstId, otherIds);
+               return new SelectById<>(root, idSpec, true);
+       }
 
-               return q;
+       /**
+        * @since 4.2
+        */
+       @SafeVarargs
+       public static SelectById<DataRow> dataRowQuery(Class<?> entityType, 
Map<String, ?> firstId, Map<String, ?>... otherIds) {
+               QueryRoot root = resolver -> resolver.getObjEntity(entityType, 
true);
+               IdSpec idSpec = new MultiMapIdSpec(firstId, otherIds);
+               return new SelectById<>(root, idSpec, true);
        }
 
-       private static void checkObjectId(ObjectId id) {
-               if (id.isTemporary() && !id.isReplacementIdAttached()) {
-                       throw new CayenneRuntimeException("Can't build a query 
for temporary id: %s", id);
+       /**
+        * @since 4.2
+        */
+       public static SelectById<DataRow> dataRowQuery(ObjectId firstId, 
ObjectId... otherIds) {
+               checkObjectId(firstId);
+               for(ObjectId id : otherIds) {
+                       checkObjectId(id, firstId.getEntityName());
                }
+
+               QueryRoot root = resolver -> 
resolver.getObjEntity(firstId.getEntityName());
+               IdSpec idSpec = new MultiMapIdSpec(firstId, otherIds);
+               return new SelectById<>(root, idSpec, true);
+       }
+
+       protected SelectById(QueryRoot root, IdSpec idSpec, boolean 
fetchingDataRows) {
+               this.root = root;
+               this.idSpec = idSpec;
+               this.fetchingDataRows = fetchingDataRows;
+       }
+
+       protected SelectById(QueryRoot root, IdSpec idSpec) {
+               this(root, idSpec, false);
        }
 
        @Override
@@ -284,14 +333,12 @@ public class SelectById<T> extends IndirectQuery 
implements Select<T> {
        @SuppressWarnings("deprecation")
        @Override
        protected Query createReplacementQuery(EntityResolver resolver) {
-
-               ObjEntity entity = resolveEntity(resolver);
-               Map<String, ?> id = resolveId(entity);
+               ObjEntity entity = root.resolve(resolver);
 
                SelectQuery<Object> query = new SelectQuery<>();
                query.setRoot(entity);
                query.setFetchingDataRows(fetchingDataRows);
-               query.setQualifier(matchAllDbExp(id, Expression.EQUAL_TO));
+               query.setQualifier(idSpec.getQualifier(entity));
 
                // note on caching... this hits query cache instead of object 
cache...
                // until we merge the two this may result in not using the cache
@@ -303,31 +350,112 @@ public class SelectById<T> extends IndirectQuery 
implements Select<T> {
                return query;
        }
 
-       protected Map<String, ?> resolveId(ObjEntity entity) {
+       private static String resolveSinglePkName(ObjEntity entity) {
+               Collection<String> pkAttributes = entity.getPrimaryKeyNames();
+               if(pkAttributes.size() == 1) {
+                       return pkAttributes.iterator().next();
+               }
+               throw new CayenneRuntimeException("PK contains %d columns, 
expected 1.",  pkAttributes.size());
+       }
 
-               if (singleId == null && mapId == null) {
-                       throw new CayenneRuntimeException("Misconfigured query. 
Either singleId or mapId must be set");
+       private static void checkObjectId(ObjectId id) {
+               if (id.isTemporary() && !id.isReplacementIdAttached()) {
+                       throw new CayenneRuntimeException("Can't build a query 
for a temporary id: %s", id);
                }
+       }
 
-               if (mapId != null) {
-                       return mapId;
+       private static void checkObjectId(ObjectId id, String entityName) {
+               checkObjectId(id);
+               if(!entityName.equals(id.getEntityName())) {
+                       throw new CayenneRuntimeException("Can't build a query 
with mixed object types for given ObjectIds");
                }
+       }
 
-               Collection<String> pkAttributes = entity.getPrimaryKeyNames();
-               if (pkAttributes.size() != 1) {
-                       throw new CayenneRuntimeException("PK contains %d 
columns, expected 1.",  pkAttributes.size());
+       @SafeVarargs
+       private static <E, R> Collection<R> foldArguments(Function<E, R> 
mapper, E first, E... other) {
+               List<R> result = new ArrayList<>();
+               result.add(mapper.apply(first));
+               for(E next : other) {
+                       result.add(mapper.apply(next));
+               }
+               return result;
+       }
+
+       protected interface QueryRoot extends Serializable {
+               ObjEntity resolve(EntityResolver resolver);
+       }
+
+       protected interface IdSpec extends Serializable{
+               Expression getQualifier(ObjEntity entity);
+       }
+
+       protected static class SingleScalarIdSpec implements IdSpec {
+
+               private final Object id;
+
+               protected SingleScalarIdSpec(Object id) {
+                       this.id = id;
                }
 
-               String pk = pkAttributes.iterator().next();
-               return singletonMap(pk, singleId);
+               @Override
+               public Expression getQualifier(ObjEntity entity) {
+                       return matchDbExp(resolveSinglePkName(entity), id);
+               }
        }
 
-       protected ObjEntity resolveEntity(EntityResolver resolver) {
+       protected static class MultiScalarIdSpec implements IdSpec {
 
-               if (entityName == null && entityType == null) {
-                       throw new CayenneRuntimeException("Misconfigured query. 
Either entityName or entityType must be set");
+               private final Collection<Object> ids;
+
+               protected MultiScalarIdSpec(Object firstId, Object... otherIds) 
{
+                       this.ids = foldArguments(Function.identity(), firstId, 
otherIds);
                }
 
-               return entityName != null ? resolver.getObjEntity(entityName) : 
resolver.getObjEntity(entityType, true);
+               protected MultiScalarIdSpec(Collection<Object> ids) {
+                       this.ids = ids;
+               }
+
+               @Override
+               public Expression getQualifier(ObjEntity entity) {
+                       return inDbExp(resolveSinglePkName(entity), ids);
+               }
+       }
+
+       protected static class SingleMapIdSpec implements IdSpec {
+
+               private final Map<String, ?> id;
+
+               protected SingleMapIdSpec(Map<String, ?> id) {
+                       this.id = id;
+               }
+
+               @Override
+               public Expression getQualifier(ObjEntity entity) {
+                       return matchAllDbExp(id, Expression.EQUAL_TO);
+               }
+       }
+
+       protected static class MultiMapIdSpec implements IdSpec {
+
+               private final Collection<Map<String, ?>> ids;
+
+               @SafeVarargs
+               protected MultiMapIdSpec(Map<String, ?> firstId, Map<String, 
?>... otherIds) {
+                       this.ids = foldArguments(Function.identity(), firstId, 
otherIds);
+               }
+
+               protected MultiMapIdSpec(ObjectId firstId, ObjectId... 
otherIds) {
+                       this.ids = foldArguments(ObjectId::getIdSnapshot, 
firstId, otherIds);
+               }
+
+               @Override
+               public Expression getQualifier(ObjEntity entity) {
+                       List<Expression> expressions = new ArrayList<>();
+                       for(Map<String, ?> id : ids) {
+                               expressions.add(matchAllDbExp(id, 
Expression.EQUAL_TO));
+                       }
+
+                       return or(expressions);
+               }
        }
 }
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/query/SelectById_RunIT.java 
b/cayenne-server/src/test/java/org/apache/cayenne/query/SelectById_RunIT.java
index 9dfc5db..74dd0f4 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/query/SelectById_RunIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/query/SelectById_RunIT.java
@@ -18,13 +18,11 @@
  ****************************************************************/
 package org.apache.cayenne.query;
 
-import static java.util.Collections.singletonMap;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-
 import java.sql.Types;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.ObjectContext;
@@ -36,13 +34,16 @@ import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.unit.di.DataChannelInterceptor;
-import org.apache.cayenne.unit.di.UnitTestClosure;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.junit.Before;
 import org.junit.Test;
 
+import static java.util.Collections.singletonMap;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.*;
+
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
 public class SelectById_RunIT extends ServerCase {
 
@@ -85,7 +86,27 @@ public class SelectById_RunIT extends ServerCase {
                assertNotNull(a2);
                assertEquals("artist2", a2.getArtistName());
        }
-       
+
+       @Test
+       public void testIntPkMulti() throws Exception {
+               createTwoArtists();
+
+               List<Artist> artists = SelectById.query(Artist.class, 2, 3)
+                               .select(context);
+               assertEquals(2, artists.size());
+               assertThat(artists.get(0), instanceOf(Artist.class));
+       }
+
+       @Test
+       public void testIntPkCollection() throws Exception {
+               createTwoArtists();
+
+               List<Artist> artists = SelectById.query(Artist.class, 
Arrays.asList(1, 2, 3, 4, 5))
+                               .select(context);
+               assertEquals(2, artists.size());
+               assertThat(artists.get(0), instanceOf(Artist.class));
+       }
+
        @Test
        public void testIntPk_SelectFirst() throws Exception {
                createTwoArtists();
@@ -113,6 +134,19 @@ public class SelectById_RunIT extends ServerCase {
        }
 
        @Test
+       public void testMapPkMulti() throws Exception {
+               createTwoArtists();
+
+               Map<String, ?> id2 = 
Collections.singletonMap(Artist.ARTIST_ID_PK_COLUMN, 2);
+               Map<String, ?> id3 = 
Collections.singletonMap(Artist.ARTIST_ID_PK_COLUMN, 3);
+
+               List<Artist> artists = SelectById.query(Artist.class, id2, id3)
+                               .select(context);
+               assertEquals(2, artists.size());
+               assertThat(artists.get(0), instanceOf(Artist.class));
+       }
+
+       @Test
        public void testObjectIdPk() throws Exception {
                createTwoArtists();
 
@@ -128,6 +162,19 @@ public class SelectById_RunIT extends ServerCase {
        }
 
        @Test
+       public void testObjectIdPkMulti() throws Exception {
+               createTwoArtists();
+
+               ObjectId oid2 = ObjectId.of("Artist", 
Artist.ARTIST_ID_PK_COLUMN, 2);
+               ObjectId oid3 = ObjectId.of("Artist", 
Artist.ARTIST_ID_PK_COLUMN, 3);
+
+               List<Artist> artists = SelectById.query(Artist.class, oid2, 
oid3)
+                               .select(context);
+               assertEquals(2, artists.size());
+               assertThat(artists.get(0), instanceOf(Artist.class));
+       }
+
+       @Test
        public void testDataRowIntPk() throws Exception {
                createTwoArtists();
 
@@ -141,6 +188,73 @@ public class SelectById_RunIT extends ServerCase {
        }
 
        @Test
+       public void testDataRowMapPk() throws Exception {
+               createTwoArtists();
+
+               Map<String, ?> id3 = 
Collections.singletonMap(Artist.ARTIST_ID_PK_COLUMN, 3);
+               DataRow a3 = SelectById.dataRowQuery(Artist.class, 
id3).selectOne(context);
+               assertNotNull(a3);
+               assertEquals("artist3", a3.get("ARTIST_NAME"));
+
+               Map<String, ?> id2 = 
Collections.singletonMap(Artist.ARTIST_ID_PK_COLUMN, 2);
+               DataRow a2 = SelectById.dataRowQuery(Artist.class, 
id2).selectOne(context);
+               assertNotNull(a2);
+               assertEquals("artist2", a2.get("ARTIST_NAME"));
+       }
+
+       @Test
+       public void testDataRowObjectIdPk() throws Exception {
+               createTwoArtists();
+
+               ObjectId oid3 = ObjectId.of("Artist", 
Artist.ARTIST_ID_PK_COLUMN, 3);
+               DataRow a3 = SelectById.dataRowQuery(oid3).selectOne(context);
+               assertNotNull(a3);
+               assertEquals("artist3", a3.get("ARTIST_NAME"));
+
+               ObjectId oid2 = ObjectId.of("Artist", 
Artist.ARTIST_ID_PK_COLUMN, 2);
+               DataRow a2 = SelectById.dataRowQuery(oid2).selectOne(context);
+               assertNotNull(a2);
+               assertEquals("artist2", a2.get("ARTIST_NAME"));
+       }
+
+       @Test
+       public void testDataRowIntPkMulti() throws Exception {
+               createTwoArtists();
+
+               List<DataRow> artists = SelectById.dataRowQuery(Artist.class, 
2, 3)
+                               .select(context);
+               assertEquals(2, artists.size());
+               assertThat(artists.get(0), instanceOf(DataRow.class));
+       }
+
+       @Test
+       public void testDataRowMapPkMulti() throws Exception {
+               createTwoArtists();
+
+               ObjectId oid2 = ObjectId.of("Artist", 
Artist.ARTIST_ID_PK_COLUMN, 2);
+               ObjectId oid3 = ObjectId.of("Artist", 
Artist.ARTIST_ID_PK_COLUMN, 3);
+
+               List<DataRow> artists = SelectById.dataRowQuery(oid2, oid3)
+                               .select(context);
+               assertEquals(2, artists.size());
+               assertThat(artists.get(0), instanceOf(DataRow.class));
+       }
+
+       @Test
+       public void testDataRowObjectIdPkMulti() throws Exception {
+               createTwoArtists();
+
+               Map<String, ?> id2 = 
Collections.singletonMap(Artist.ARTIST_ID_PK_COLUMN, 2);
+               Map<String, ?> id3 = 
Collections.singletonMap(Artist.ARTIST_ID_PK_COLUMN, 3);
+
+               List<DataRow> artists = SelectById.dataRowQuery(Artist.class, 
id2, id3)
+                               .select(context);
+               assertEquals(2, artists.size());
+               assertThat(artists.get(0), instanceOf(DataRow.class));
+       }
+
+
+       @Test
        public void testMetadataCacheKey() throws Exception {
                SelectById<Painting> q1 = SelectById.query(Painting.class, 
4).localCache();
                QueryMetadata md1 = q1.getMetaData(resolver);
@@ -170,13 +284,13 @@ public class SelectById_RunIT extends ServerCase {
                assertNotEquals(md1.getCacheKey(), md4.getCacheKey());
 
                SelectById<Painting> q5 = SelectById
-                               .query(Painting.class, ObjectId.of("Painting", 
Painting.PAINTING_ID_PK_COLUMN, 4)).localCache();
+                               .query(Painting.class, ObjectId.of("Painting", 
Painting.PAINTING_ID_PK_COLUMN, 4))
+                               .localCache();
                QueryMetadata md5 = q5.getMetaData(resolver);
                assertNotNull(md5);
                assertNotNull(md5.getCacheKey());
 
-               // this query is just a different form of q1, so should hit the 
same
-               // cache entry
+               // this query is just a different form of q1, so should hit the 
same cache entry
                assertEquals(md1.getCacheKey(), md5.getCacheKey());
        }
 
@@ -186,34 +300,21 @@ public class SelectById_RunIT extends ServerCase {
 
                final Artist[] a3 = new Artist[1];
 
-               assertEquals(1, interceptor.runWithQueryCounter(new 
UnitTestClosure() {
-
-                       @Override
-                       public void execute() {
-                               a3[0] = SelectById.query(Artist.class, 
3).localCache("g1").selectOne(context);
-                               assertNotNull(a3[0]);
-                               assertEquals("artist3", a3[0].getArtistName());
-                       }
+               assertEquals(1, interceptor.runWithQueryCounter(() -> {
+                       a3[0] = SelectById.query(Artist.class, 
3).localCache("g1").selectOne(context);
+                       assertNotNull(a3[0]);
+                       assertEquals("artist3", a3[0].getArtistName());
                }));
 
-               interceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-                       @Override
-                       public void execute() {
-                               Artist a3cached = 
SelectById.query(Artist.class, 3).localCache("g1").selectOne(context);
-                               assertSame(a3[0], a3cached);
-                       }
+               interceptor.runWithQueriesBlocked(() -> {
+                       Artist a3cached = SelectById.query(Artist.class, 
3).localCache("g1").selectOne(context);
+                       assertSame(a3[0], a3cached);
                });
 
                context.performGenericQuery(new RefreshQuery("g1"));
 
-               assertEquals(1, interceptor.runWithQueryCounter(new 
UnitTestClosure() {
-
-                       @Override
-                       public void execute() {
-                               SelectById.query(Artist.class, 
3).localCache("g1").selectOne(context);
-                       }
-               }));
+               assertEquals(1, interceptor.runWithQueryCounter(() ->
+                               SelectById.query(Artist.class, 
3).localCache("g1").selectOne(context)));
        }
 
        @Test
@@ -222,19 +323,17 @@ public class SelectById_RunIT extends ServerCase {
                tPainting.insert(45, 3, "One");
                tPainting.insert(48, 3, "Two");
 
-               final Artist a3 = SelectById.query(Artist.class, 
3).prefetch(Artist.PAINTING_ARRAY.joint()).selectOne(context);
-
-               interceptor.runWithQueriesBlocked(new UnitTestClosure() {
+               final Artist a3 = SelectById.query(Artist.class, 3)
+                               .prefetch(Artist.PAINTING_ARRAY.joint())
+                               .selectOne(context);
 
-                       @Override
-                       public void execute() {
-                               assertNotNull(a3);
-                               assertEquals("artist3", a3.getArtistName());
-                               assertEquals(2, a3.getPaintingArray().size());
+               interceptor.runWithQueriesBlocked(() -> {
+                       assertNotNull(a3);
+                       assertEquals("artist3", a3.getArtistName());
+                       assertEquals(2, a3.getPaintingArray().size());
 
-                               a3.getPaintingArray().get(0).getPaintingTitle();
-                               a3.getPaintingArray().get(1).getPaintingTitle();
-                       }
+                       a3.getPaintingArray().get(0).getPaintingTitle();
+                       a3.getPaintingArray().get(1).getPaintingTitle();
                });
        }
 }

Reply via email to