cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ntimof...@apache.org
Subject [cayenne] branch master updated: CAY-2378 Switch usage of SelectQuery to ObjectSelect internally
Date Mon, 12 Aug 2019 10:18:11 GMT
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 d6cf456  CAY-2378 Switch usage of SelectQuery to ObjectSelect internally
d6cf456 is described below

commit d6cf456121a0f38a42a036eb6fab2aaa59533d13
Author: Nikita Timofeev <stariy95@gmail.com>
AuthorDate: Mon Aug 12 13:18:02 2019 +0300

    CAY-2378 Switch usage of SelectQuery to ObjectSelect internally
---
 .../cayenne/CDOCollectionRelationshipIT.java       |  11 +-
 .../java/org/apache/cayenne/CayenneDOTestBase.java |  17 +--
 .../cayenne/CayenneDataObjectFlattenedRelIT.java   |  39 ++-----
 .../cayenne/CayenneDataObjectInContextIT.java      |  22 ++--
 .../apache/cayenne/access/jdbc/SelectActionIT.java |  22 ++--
 .../batch/SoftDeleteBatchTranslatorIT.java         |  33 +++---
 .../select/DefaultObjectSelectTranslatorIT.java    |   9 +-
 .../select/DefaultSelectTranslatorIT.java          | 119 ++++++++++-----------
 .../org/apache/cayenne/cache/QueryCacheIT.java     |  10 +-
 .../cayenne/dba/ConcurrentPkGeneratorIT.java       |   6 +-
 .../apache/cayenne/exp/ExpressionFactoryIT.java    |  15 +--
 .../java/org/apache/cayenne/exp/ExpressionIT.java  |  21 +---
 .../cayenne/exp/ParsedExpQualifierCompatIT.java    |  12 ++-
 .../apache/cayenne/exp/property/PathAliasesIT.java |  29 ++---
 .../cayenne/query/ObjectSelect_SubqueryIT.java     |  22 ++--
 .../org/apache/cayenne/query/QueryChainIT.java     |   8 +-
 .../org/apache/cayenne/query/SelectQueryIT.java    |   1 +
 .../org/apache/cayenne/tx/TransactionThreadIT.java |   9 +-
 .../org/apache/cayenne/unit/jira/CAY_115IT.java    |   5 +-
 .../org/apache/cayenne/unit/jira/CAY_194IT.java    |  13 +--
 20 files changed, 176 insertions(+), 247 deletions(-)

diff --git a/cayenne-server/src/test/java/org/apache/cayenne/CDOCollectionRelationshipIT.java b/cayenne-server/src/test/java/org/apache/cayenne/CDOCollectionRelationshipIT.java
index 13182d2..dc030b7 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/CDOCollectionRelationshipIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/CDOCollectionRelationshipIT.java
@@ -20,8 +20,8 @@ package org.apache.cayenne;
 
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.RefreshQuery;
-import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.relationships_collection_to_many.CollectionToMany;
@@ -93,11 +93,10 @@ public class CDOCollectionRelationshipIT extends ServerCase {
 
     @Test
     public void testReadToManyPrefetching() throws Exception {
-
-        SelectQuery query = new SelectQuery(CollectionToMany.class, ExpressionFactory
-                .matchDbExp(CollectionToMany.ID_PK_COLUMN, 1));
-        query.addPrefetch(CollectionToMany.TARGETS.disjoint());
-        CollectionToMany o1 = (CollectionToMany) Cayenne.objectForQuery(context, query);
+        CollectionToMany o1 = ObjectSelect.query(CollectionToMany.class)
+                .where(ExpressionFactory.matchDbExp(CollectionToMany.ID_PK_COLUMN, 1))
+                .prefetch(CollectionToMany.TARGETS.disjoint())
+                .selectOne(context);
 
         Collection<?> targets = o1.getTargets();
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDOTestBase.java b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDOTestBase.java
index c0abdf8..c05412e 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDOTestBase.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDOTestBase.java
@@ -20,8 +20,7 @@ package org.apache.cayenne;
  ****************************************************************/
 
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.testdo.testmap.PaintingInfo;
@@ -63,20 +62,14 @@ public abstract class CayenneDOTestBase extends ServerCase {
     }
 
     protected Painting fetchPainting() {
-        SelectQuery q = new SelectQuery("Painting", ExpressionFactory.matchExp(
-                "paintingTitle",
-                paintingName));
-        List<?> pts = context.performQuery(q);
-        return (pts.size() > 0) ? (Painting) pts.get(0) : null;
+        List<Painting> pts = ObjectSelect.query(Painting.class, Painting.PAINTING_TITLE.eq(paintingName)).select(context);
+        return (pts.size() > 0) ? pts.get(0) : null;
     }
 
     protected PaintingInfo fetchPaintingInfo() {
         // we are using "LIKE" comparison, since Sybase does not allow
         // "=" comparisons on "text" columns
-        SelectQuery q = new SelectQuery(PaintingInfo.class, ExpressionFactory.likeExp(
-                "textReview",
-                textReview));
-        List<?> pts = context.performQuery(q);
-        return (pts.size() > 0) ? (PaintingInfo) pts.get(0) : null;
+        List<PaintingInfo> pts = ObjectSelect.query(PaintingInfo.class, PaintingInfo.TEXT_REVIEW.like(textReview)).select(context);
+        return (pts.size() > 0) ? pts.get(0) : null;
     }
 }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectFlattenedRelIT.java b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectFlattenedRelIT.java
index a2535cd..c1db642 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectFlattenedRelIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectFlattenedRelIT.java
@@ -22,14 +22,12 @@ package org.apache.cayenne;
 import org.apache.cayenne.access.MockDataNode;
 import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.testmap.ArtGroup;
 import org.apache.cayenne.testdo.testmap.Artist;
 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;
@@ -130,14 +128,11 @@ public class CayenneDataObjectFlattenedRelIT extends ServerCase {
         Artist a1 = Cayenne.objectForPK(context, Artist.class, 33001);
         assertEquals(0, a1.getGroupArray().size());
 
-        SelectQuery q = new SelectQuery(ArtGroup.class, ExpressionFactory.matchExp(
-                "name",
-                "g1"));
-        List<?> results = context.performQuery(q);
+        List<ArtGroup> results = ObjectSelect.query(ArtGroup.class, ArtGroup.NAME.eq("g1")).select(context);
         assertEquals(1, results.size());
 
         assertFalse(context.hasChanges());
-        ArtGroup group = (ArtGroup) results.get(0);
+        ArtGroup group = results.get(0);
         a1.addToGroupArray(group);
         assertTrue(context.hasChanges());
 
@@ -166,13 +161,10 @@ public class CayenneDataObjectFlattenedRelIT extends ServerCase {
 
         Artist a1 = Cayenne.objectForPK(context, Artist.class, 33001);
 
-        SelectQuery q = new SelectQuery(ArtGroup.class, ExpressionFactory.matchExp(
-                "name",
-                "g1"));
-        List<?> results = context.performQuery(q);
+        List<ArtGroup> results = ObjectSelect.query(ArtGroup.class, ArtGroup.NAME.eq("g1")).select(context);
         assertEquals(1, results.size());
 
-        ArtGroup group = (ArtGroup) results.get(0);
+        ArtGroup group = results.get(0);
         a1.addToGroupArray(group);
 
         List<?> groupList = a1.getGroupArray();
@@ -242,22 +234,14 @@ public class CayenneDataObjectFlattenedRelIT extends ServerCase {
 
         Artist a1 = Cayenne.objectForPK(context, Artist.class, 33001);
 
-        SelectQuery q = new SelectQuery(ArtGroup.class, ExpressionFactory.matchExp(
-                "name",
-                "g1"));
-        List<?> results = context.performQuery(q);
+        List<ArtGroup> results = ObjectSelect.query(ArtGroup.class, ArtGroup.NAME.eq("g1")).select(context);;
         assertEquals(1, results.size());
 
-        ArtGroup group = (ArtGroup) results.get(0);
+        ArtGroup group = results.get(0);
         a1.addToGroupArray(group);
         group.removeFromArtistArray(a1);
 
-        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                context.commitChanges();
-            }
-        });
+        queryInterceptor.runWithQueriesBlocked(() -> context.commitChanges());
     }
 
     @Test
@@ -266,8 +250,7 @@ public class CayenneDataObjectFlattenedRelIT extends ServerCase {
 
         Artist a1 = Cayenne.objectForPK(context, Artist.class, 33001);
 
-        SelectQuery q = new SelectQuery(ArtGroup.class);
-        List<?> results = context.performQuery(q);
+        List<?> results = ObjectSelect.query(ArtGroup.class).select(context);
         assertEquals(2, results.size());
 
         ArtGroup g1 = (ArtGroup) results.get(0);
@@ -284,9 +267,7 @@ public class CayenneDataObjectFlattenedRelIT extends ServerCase {
                 runtime.getDataDomain().getDataNodes().iterator().next());
         try {
             context.commitChanges();
-
-        }
-        finally {
+        } finally {
             nodeWrapper.stopInterceptNode();
         }
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectInContextIT.java b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectInContextIT.java
index 5c704eb..3138132 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectInContextIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/CayenneDataObjectInContextIT.java
@@ -22,7 +22,7 @@ package org.apache.cayenne;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.testmap.Artist;
@@ -98,7 +98,7 @@ public class CayenneDataObjectInContextIT extends ServerCase {
 
         context.commitChanges();
 
-        List<Artist> artists = context.performQuery(new SelectQuery(Artist.class));
+        List<Artist> artists = ObjectSelect.query(Artist.class).select(context);
         assertEquals(3, artists.size());
     }
 
@@ -206,9 +206,7 @@ public class CayenneDataObjectInContextIT extends ServerCase {
 
         tArtist.insert(7, "m6");
 
-        SelectQuery q = new SelectQuery(Artist.class, Artist.ARTIST_NAME.eq("m6"));
-
-        List<Artist> artists = context.performQuery(q);
+        List<Artist> artists = ObjectSelect.query(Artist.class, Artist.ARTIST_NAME.eq("m6")).select(context);
         assertEquals(1, artists.size());
         Artist o1 = artists.get(0);
         assertNotNull(o1);
@@ -220,10 +218,8 @@ public class CayenneDataObjectInContextIT extends ServerCase {
 
         tArtist.insert(7, "m6");
 
-        SelectQuery q = new SelectQuery(Artist.class, Artist.ARTIST_NAME.eq("m6"));
-
-        Artist a1 = (Artist) Cayenne.objectForQuery(context, q);
-        Artist a2 = (Artist) Cayenne.objectForQuery(context, q);
+        Artist a1 = (Artist) Cayenne.objectForQuery(context, ObjectSelect.query(Artist.class, Artist.ARTIST_NAME.eq("m6")));
+        Artist a2 = (Artist) Cayenne.objectForQuery(context, ObjectSelect.query(Artist.class, Artist.ARTIST_NAME.eq("m6")));
 
         assertNotNull(a1);
         assertNotNull(a2);
@@ -255,11 +251,9 @@ public class CayenneDataObjectInContextIT extends ServerCase {
         tArtist.insert(7, "m6");
 
         // test versions assigned on fetch... clean up domain cache
+        Artist artist = ObjectSelect.query(Artist.class).selectFirst(context);
 
-        List<Artist> artists = context.performQuery(new SelectQuery(Artist.class));
-        Artist artist = artists.get(0);
-
-        assertFalse(DataObject.DEFAULT_VERSION == artist.getSnapshotVersion());
+        assertNotEquals(DataObject.DEFAULT_VERSION, artist.getSnapshotVersion());
         assertEquals(context
                 .getObjectStore()
                 .getCachedSnapshot(artist.getObjectId())
@@ -279,7 +273,7 @@ public class CayenneDataObjectInContextIT extends ServerCase {
         artist.setArtistName(artist.getArtistName() + "---");
         context.commitChanges();
 
-        assertFalse(oldVersion == artist.getSnapshotVersion());
+        assertNotEquals(oldVersion, artist.getSnapshotVersion());
         assertEquals(context
                 .getObjectStore()
                 .getCachedSnapshot(artist.getObjectId())
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionIT.java
index c7772b8..d93bf5b 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SelectActionIT.java
@@ -20,13 +20,9 @@ package org.apache.cayenne.access.jdbc;
 
 import java.util.List;
 
-import org.apache.cayenne.DataRow;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.query.ObjectSelect;
-import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.testdo.lob.ClobTestEntity;
 import org.apache.cayenne.testdo.lob.ClobTestRelation;
 import org.apache.cayenne.unit.UnitDbAdapter;
@@ -48,15 +44,15 @@ public class SelectActionIT extends ServerCaseContextsSync {
     private UnitDbAdapter accessStackAdapter;
 
     @Test
-    public void testFetchLimit_DistinctResultIterator() throws Exception {
+    public void testFetchLimit_DistinctResultIterator() {
         if (accessStackAdapter.supportsLobs()) {
 
             insertClobDb();
 
-            Expression qual = ExpressionFactory.exp("clobValue.value = 100");
-            SelectQuery select = new SelectQuery(ClobTestEntity.class, qual);
-            select.setFetchLimit(25);
-            List<DataRow> resultRows = context.performQuery(select);
+            List<ClobTestEntity> resultRows = ObjectSelect.query(ClobTestEntity.class)
+                    .where(ClobTestEntity.CLOB_VALUE.dot(ClobTestRelation.VALUE).eq(100))
+                    .limit(25)
+                    .select(context);
 
             assertNotNull(resultRows);
             assertEquals(25, resultRows.size());
@@ -64,7 +60,7 @@ public class SelectActionIT extends ServerCaseContextsSync {
     }
 
     @Test
-    public void testColumnSelect_DistinctResultIterator() throws Exception {
+    public void testColumnSelect_DistinctResultIterator() {
         if (accessStackAdapter.supportsLobs()) {
 
             insertClobDb();
@@ -86,19 +82,19 @@ public class SelectActionIT extends ServerCaseContextsSync {
             if (i < 20) {
                 obj = (ClobTestEntity) context.newObject("ClobTestEntity");
                 obj.setClobCol("a1" + i);
-                insetrClobRel(obj);
+                insertClobRel(obj);
             }
             else {
                 obj = (ClobTestEntity) context.newObject("ClobTestEntity");
                 obj.setClobCol("a2");
-                insetrClobRel(obj);
+                insertClobRel(obj);
             }
         }
 
         context.commitChanges();
     }
 
-    protected void insetrClobRel(ClobTestEntity clobId) {
+    protected void insertClobRel(ClobTestEntity clobId) {
         ClobTestRelation obj;
 
         for (int i = 0; i < 20; i++) {
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java
index 9e78ce7..d32b849 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/batch/SoftDeleteBatchTranslatorIT.java
@@ -25,12 +25,13 @@ import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.JdbcAdapter;
 import org.apache.cayenne.di.AdhocObjectFactory;
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.query.DeleteBatchQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.test.parallel.ParallelTestContainer;
 import org.apache.cayenne.testdo.soft_delete.SoftDelete;
 import org.apache.cayenne.unit.UnitDbAdapter;
@@ -75,12 +76,12 @@ public class SoftDeleteBatchTranslatorIT extends ServerCase {
     }
 
     @Test
-    public void testCreateSqlString() throws Exception {
+    public void testCreateSqlString() {
         DbEntity entity = context.getEntityResolver().getObjEntity(SoftDelete.class).getDbEntity();
 
         List<DbAttribute> idAttributes = Collections.singletonList(entity.getAttribute("ID"));
 
-        DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, Collections.<String> emptySet(), 1);
+        DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, Collections.emptySet(), 1);
         DeleteBatchTranslator builder = createTranslator(deleteQuery);
         String generatedSql = builder.getSql();
         assertNotNull(generatedSql);
@@ -88,7 +89,7 @@ public class SoftDeleteBatchTranslatorIT extends ServerCase {
     }
 
     @Test
-    public void testCreateSqlStringWithNulls() throws Exception {
+    public void testCreateSqlStringWithNulls() {
         DbEntity entity = context.getEntityResolver().getObjEntity(SoftDelete.class).getDbEntity();
 
         List<DbAttribute> idAttributes = Arrays.asList(entity.getAttribute("ID"), entity.getAttribute("NAME"));
@@ -103,7 +104,7 @@ public class SoftDeleteBatchTranslatorIT extends ServerCase {
     }
 
     @Test
-    public void testCreateSqlStringWithIdentifiersQuote() throws Exception {
+    public void testCreateSqlStringWithIdentifiersQuote() {
         DbEntity entity = context.getEntityResolver().getObjEntity(SoftDelete.class).getDbEntity();
         try {
 
@@ -111,8 +112,7 @@ public class SoftDeleteBatchTranslatorIT extends ServerCase {
 
             List<DbAttribute> idAttributes = Collections.singletonList(entity.getAttribute("ID"));
 
-            DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, Collections.<String> emptySet(),
-                    1);
+            DeleteBatchQuery deleteQuery = new DeleteBatchQuery(entity, idAttributes, Collections.emptySet(), 1);
             JdbcAdapter adapter = (JdbcAdapter) this.adapter;
             DeleteBatchTranslator builder = createTranslator(deleteQuery, adapter);
             String generatedSql = builder.getSql();
@@ -134,7 +134,6 @@ public class SoftDeleteBatchTranslatorIT extends ServerCase {
 
         final DbEntity entity = context.getEntityResolver().getObjEntity(SoftDelete.class).getDbEntity();
 
-        JdbcAdapter adapter = (JdbcAdapter) this.adapter;
         BatchTranslatorFactory oldFactory = dataNode.getBatchTranslatorFactory();
         try {
             dataNode.setBatchTranslatorFactory(new SoftDeleteTranslatorFactory());
@@ -143,17 +142,15 @@ public class SoftDeleteBatchTranslatorIT extends ServerCase {
             test.setName("SoftDeleteBatchQueryBuilderTest");
             context.commitChanges();
 
-            final SelectQuery query = new SelectQuery(SoftDelete.class);
-
             new ParallelTestContainer() {
 
                 @Override
-                protected void assertResult() throws Exception {
-                    query.setQualifier(ExpressionFactory.matchExp("name", test.getName()));
-                    assertEquals(1, context.performQuery(query).size());
+                protected void assertResult() {
+                    Expression exp = ExpressionFactory.matchExp("name", test.getName());
+                    assertEquals(1, ObjectSelect.query(SoftDelete.class, exp).selectCount(context));
 
-                    query.andQualifier(ExpressionFactory.matchDbExp("DELETED", true));
-                    assertEquals(0, context.performQuery(query).size());
+                    exp = ExpressionFactory.matchDbExp("DELETED", true);
+                    assertEquals(0, ObjectSelect.query(SoftDelete.class, exp).selectCount(context));
                 }
             }.runTest(200);
 
@@ -164,9 +161,9 @@ public class SoftDeleteBatchTranslatorIT extends ServerCase {
             new ParallelTestContainer() {
 
                 @Override
-                protected void assertResult() throws Exception {
-                    query.setQualifier(ExpressionFactory.matchExp("name", test.getName()));
-                    assertEquals(0, context.performQuery(query).size());
+                protected void assertResult() {
+                    Expression exp = ExpressionFactory.matchExp("name", test.getName());
+                    assertEquals(0, ObjectSelect.query(SoftDelete.class, exp).selectCount(context));
 
                     SQLTemplate template = new SQLTemplate(entity, "SELECT * FROM SOFT_DELETE");
                     template.setFetchingDataRows(true);
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/DefaultObjectSelectTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/DefaultObjectSelectTranslatorIT.java
index 71db432..da440fe 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/DefaultObjectSelectTranslatorIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/DefaultObjectSelectTranslatorIT.java
@@ -22,7 +22,7 @@ package org.apache.cayenne.access.translator.select;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
@@ -46,7 +46,7 @@ public class DefaultObjectSelectTranslatorIT extends ServerCase {
 
     @Test
     public void simpleSql() {
-        SelectQuery<Artist> select = SelectQuery.query(Artist.class);
+        ObjectSelect<Artist> select = ObjectSelect.query(Artist.class);
         DefaultSelectTranslator translator = new DefaultSelectTranslator(select, adapter, context.getEntityResolver());
 
         String sql = translator.getSql();
@@ -67,7 +67,7 @@ public class DefaultObjectSelectTranslatorIT extends ServerCase {
 
     @Test
     public void selectWithComplexWhere() {
-        SelectQuery<Artist> select = SelectQuery.query(Artist.class, Artist.ARTIST_NAME.eq("artist")
+        ObjectSelect<Artist> select = ObjectSelect.query(Artist.class, Artist.ARTIST_NAME.eq("artist")
                 .andExp(Artist.PAINTING_ARRAY.dot(Painting.PAINTING_TITLE).eq("painting")));
 
         DefaultSelectTranslator translator = new DefaultSelectTranslator(select, adapter, context.getEntityResolver());
@@ -96,8 +96,7 @@ public class DefaultObjectSelectTranslatorIT extends ServerCase {
 
     @Test
     public void selectWithJointPrefetch() {
-        SelectQuery<Painting> select = SelectQuery.query(Painting.class);
-        select.addPrefetch(Painting.TO_ARTIST.joint());
+        ObjectSelect<Painting> select = ObjectSelect.query(Painting.class).prefetch(Painting.TO_ARTIST.joint());
 
         DefaultSelectTranslator translator = new DefaultSelectTranslator(select, adapter, context.getEntityResolver());
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorIT.java
index 3574379..d4f54b2 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/translator/select/DefaultSelectTranslatorIT.java
@@ -28,13 +28,16 @@ import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.log.JdbcEventLogger;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.PrefetchTreeNode;
 import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.SortOrder;
 import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.testmap.ArtGroup;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.ArtistExhibit;
 import org.apache.cayenne.testdo.testmap.CompoundPainting;
+import org.apache.cayenne.testdo.testmap.Exhibit;
+import org.apache.cayenne.testdo.testmap.Gallery;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.unit.UnitDbAdapter;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
@@ -74,8 +77,8 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testCreateSqlString1() throws Exception {
 		// query with qualifier and ordering
-		SelectQuery<Artist> q = new SelectQuery<>(Artist.class, ExpressionFactory.likeExp("artistName", "a%"));
-		q.addOrdering("dateOfBirth", SortOrder.ASCENDING);
+		ObjectSelect<Artist> q = ObjectSelect.query(Artist.class, Artist.ARTIST_NAME.like("a%"))
+				.orderBy(Artist.DATE_OF_BIRTH.asc());
 
 		SelectTranslator defaultSelectTranslator = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
 		String generatedSql = defaultSelectTranslator.getSql();
@@ -95,12 +98,11 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testDbEntityQualifier() throws Exception {
 
-		SelectQuery<Artist> q = new SelectQuery<Artist>(Artist.class);
+		ObjectSelect<Artist> q = ObjectSelect.query(Artist.class);
 		final DbEntity entity = context.getEntityResolver().getDbEntity("ARTIST");
 		final DbEntity middleEntity = context.getEntityResolver().getDbEntity("ARTIST_GROUP");
 
-		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(),
-				dataNode.getEntityResolver());
+		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
 
 		entity.setQualifier(ExpressionFactory.exp("ARTIST_NAME = \"123\""));
 		middleEntity.setQualifier(ExpressionFactory.exp("GROUP_ID = 1987"));
@@ -129,14 +131,13 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testDbEntityQualifier_OuterJoin() throws Exception {
 
-		SelectQuery<Painting> q = SelectQuery.query(Painting.class);
-		q.addOrdering("toArtist+.artistName", SortOrder.ASCENDING);
+		ObjectSelect<Painting> q = ObjectSelect.query(Painting.class)
+				.orderBy(Painting.TO_ARTIST.outer().dot(Artist.ARTIST_NAME).asc());
 
 		final DbEntity entity = context.getEntityResolver().getDbEntity("ARTIST");
 		final DbEntity middleEntity = context.getEntityResolver().getDbEntity("ARTIST_GROUP");
 
-		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(),
-				dataNode.getEntityResolver());
+		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
 
 		entity.setQualifier(ExpressionFactory.exp("ARTIST_NAME = \"123\""));
 		middleEntity.setQualifier(ExpressionFactory.exp("GROUP_ID = 1987"));
@@ -166,14 +167,12 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testDbEntityQualifier_FlattenedRel() throws Exception {
 
-		SelectQuery<Artist> q = new SelectQuery<Artist>(Artist.class, ExpressionFactory.matchExp("groupArray.name",
-				"bar"));
+		ObjectSelect<Artist> q = ObjectSelect.query(Artist.class, Artist.GROUP_ARRAY.dot(ArtGroup.NAME).eq("bar"));
 
 		final DbEntity entity = context.getEntityResolver().getDbEntity("ARTIST");
 		final DbEntity middleEntity = context.getEntityResolver().getDbEntity("ARTIST_GROUP");
 
-		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(),
-				dataNode.getEntityResolver());
+		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
 
 		entity.setQualifier(ExpressionFactory.exp("ARTIST_NAME = \"123\""));
 		middleEntity.setQualifier(ExpressionFactory.exp("GROUP_ID = 1987"));
@@ -203,14 +202,12 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testDbEntityQualifier_RelatedMatch() throws Exception {
 
-		SelectQuery<Painting> q = new SelectQuery<>(Painting.class,
-				ExpressionFactory.matchExp("toArtist.artistName", "foo"));
+		ObjectSelect<Painting> q = ObjectSelect.query(Painting.class, Painting.TO_ARTIST.dot(Artist.ARTIST_NAME).eq("foo"));
 
 		final DbEntity entity = context.getEntityResolver().getDbEntity("ARTIST");
 		final DbEntity middleEntity = context.getEntityResolver().getDbEntity("ARTIST_GROUP");
 
-		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(),
-				dataNode.getEntityResolver());
+		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
 
 		entity.setQualifier(ExpressionFactory.exp("ARTIST_NAME = \"123\""));
 		middleEntity.setQualifier(ExpressionFactory.exp("GROUP_ID = 1987"));
@@ -240,13 +237,13 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	 * Tests query creation with "distinct" specified.
 	 */
 	@Test
+	@Deprecated
 	public void testCreateSqlString2() throws Exception {
 		// query with "distinct" set
 		SelectQuery<Artist> q = new SelectQuery<>(Artist.class);
 		q.setDistinct(true);
 
-		String generatedSql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver())
-				.getSql();
+		String generatedSql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver()).getSql();
 
 		// do some simple assertions to make sure all parts are in
 		assertNotNull(generatedSql);
@@ -260,13 +257,16 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	 */
 	@Test
 	public void testCreateSqlString5() throws Exception {
-		// query with qualifier and ordering
-		SelectQuery<ArtistExhibit> q = new SelectQuery<>(ArtistExhibit.class);
-		q.setQualifier(ExpressionFactory.likeExp("toArtist.artistName", "a%"));
-		q.andQualifier(ExpressionFactory.likeExp("toExhibit.toGallery.paintingArray.toArtist.artistName", "a%"));
-
-		String generatedSql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver())
-				.getSql();
+		ObjectSelect<ArtistExhibit> q = ObjectSelect.query(ArtistExhibit.class)
+				.where(ArtistExhibit.TO_ARTIST
+						.dot(Artist.ARTIST_NAME).like( "a%"))
+				.and(ArtistExhibit.TO_EXHIBIT
+						.dot(Exhibit.TO_GALLERY)
+						.dot(Gallery.PAINTING_ARRAY)
+						.dot(Painting.TO_ARTIST)
+						.dot(Artist.ARTIST_NAME).like("a%"));
+
+		String generatedSql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver()).getSql();
 		// logObj.warn("Query: " + generatedSql);
 
 		// do some simple assertions to make sure all parts are in
@@ -292,10 +292,9 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	 */
 	@Test
 	public void testCreateSqlString6() throws Exception {
-		// query with qualifier and ordering
-		SelectQuery<ArtistExhibit> q = new SelectQuery<>(ArtistExhibit.class);
-		q.setQualifier(ExpressionFactory.likeExp("toArtist.artistName", "a%"));
-		q.andQualifier(ExpressionFactory.likeExp("toArtist.paintingArray.paintingTitle", "p%"));
+		ObjectSelect<ArtistExhibit> q = ObjectSelect.query(ArtistExhibit.class)
+				.where(ArtistExhibit.TO_ARTIST.dot(Artist.ARTIST_NAME).like("a%"))
+				.and(ArtistExhibit.TO_ARTIST.dot(Artist.PAINTING_ARRAY).dot(Painting.PAINTING_TITLE).like("p%"));
 
 		String generatedSql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver())
 				.getSql();
@@ -321,9 +320,9 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	 */
 	@Test
 	public void testCreateSqlString7() throws Exception {
-		SelectQuery<Artist> q = new SelectQuery<>(Artist.class);
-		q.setQualifier(ExpressionFactory.greaterExp("dateOfBirth", new Date()));
-		q.andQualifier(ExpressionFactory.lessExp("dateOfBirth", new Date()));
+		ObjectSelect<Artist> q = ObjectSelect.query(Artist.class)
+				.where(Artist.DATE_OF_BIRTH.gt(new Date()))
+				.and(Artist.DATE_OF_BIRTH.lt(new Date()));
 
 		String generatedSql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver())
 				.getSql();
@@ -354,13 +353,11 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	 */
 	@Test
 	public void testCreateSqlString8() throws Exception {
-		SelectQuery<?> q = new SelectQuery<>();
-		q.setRoot(Painting.class);
-		q.setQualifier(ExpressionFactory.greaterExp("toArtist.dateOfBirth", new Date()));
-		q.andQualifier(ExpressionFactory.lessExp("toArtist.dateOfBirth", new Date()));
+		ObjectSelect<Painting> q = ObjectSelect.query(Painting.class)
+				.where(Painting.TO_ARTIST.dot(Artist.DATE_OF_BIRTH).gt(new Date()))
+				.and(Painting.TO_ARTIST.dot(Artist.DATE_OF_BIRTH).lt(new Date()));
 
-		String generatedSql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver())
-				.getSql();
+		String generatedSql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver()).getSql();
 
 		// do some simple assertions to make sure all parts are in
 		assertNotNull(generatedSql);
@@ -382,7 +379,7 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testCreateSqlString9() throws Exception {
 		// query for a compound ObjEntity with qualifier
-		SelectQuery<CompoundPainting> q = new SelectQuery<>(CompoundPainting.class, ExpressionFactory.likeExp("artistName", "a%"));
+		ObjectSelect<CompoundPainting> q = ObjectSelect.query(CompoundPainting.class, CompoundPainting.ARTIST_NAME.like("a%"));
 
 		String sql = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver()).getSql();
 
@@ -434,8 +431,7 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testCreateSqlString10() throws Exception {
 		// query with to-many joint prefetches
-		SelectQuery<Artist> q = new SelectQuery<>(Artist.class);
-		q.addPrefetch(Artist.PAINTING_ARRAY.joint());
+		ObjectSelect<Artist> q = ObjectSelect.query(Artist.class).prefetch(Artist.PAINTING_ARRAY.joint());
 
 		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(),
 				dataNode.getEntityResolver());
@@ -458,8 +454,9 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testCreateSqlString11() throws Exception {
 		// query with joint prefetches and other joins
-		SelectQuery<Artist> q = new SelectQuery<>(Artist.class, ExpressionFactory.exp("paintingArray.paintingTitle = 'a'"));
-		q.addPrefetch(Artist.PAINTING_ARRAY.joint());
+		ObjectSelect q = ObjectSelect.query(Artist.class)
+				.where(Artist.PAINTING_ARRAY.dot(Painting.PAINTING_TITLE).eq("a"))
+				.prefetch(Artist.PAINTING_ARRAY.joint());
 
 		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(),
 				dataNode.getEntityResolver());
@@ -473,8 +470,7 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testCreateSqlString12() throws Exception {
 		// query with to-one joint prefetches
-		SelectQuery<Painting> q = new SelectQuery<>(Painting.class);
-		q.addPrefetch(Painting.TO_ARTIST.joint());
+		ObjectSelect<Painting> q = ObjectSelect.query(Painting.class).prefetch(Painting.TO_ARTIST.joint());
 
 		SelectTranslator transl = new DefaultSelectTranslator(q, dataNode.getAdapter(),
 				dataNode.getEntityResolver());
@@ -498,9 +494,8 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	@Test
 	public void testCreateSqlString13() throws Exception {
 		// query with invalid joint prefetches
-		SelectQuery<Painting> q = new SelectQuery<>(Painting.class);
-		q.addPrefetch("invalid.invalid").setSemantics(PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
-
+		ObjectSelect<Painting> q = ObjectSelect.query(Painting.class)
+				.prefetch("invalid.invalid", PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
 		try {
 			new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver()).getSql();
 			fail("Invalid jointPrefetch must have thrown...");
@@ -513,10 +508,10 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	public void testCreateSqlStringWithQuoteSqlIdentifiers() throws Exception {
 
 		try {
-			SelectQuery<Artist> q = new SelectQuery<>(Artist.class);
+			ObjectSelect<Artist> q = ObjectSelect.query(Artist.class)
+					.orderBy(Artist.DATE_OF_BIRTH.asc());
 			DbEntity entity = context.getEntityResolver().getDbEntity("ARTIST");
 			entity.getDataMap().setQuotingSQLIdentifiers(true);
-			q.addOrdering("dateOfBirth", SortOrder.ASCENDING);
 
 			String charStart = unitAdapter.getIdentifiersStartQuote();
 			String charEnd = unitAdapter.getIdentifiersEndQuote();
@@ -550,11 +545,12 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	public void testCreateSqlStringWithQuoteSqlIdentifiers2() throws Exception {
 
 		try {
-			SelectQuery<Artist> q = new SelectQuery<>(Artist.class);
+			ObjectSelect<Artist> q = ObjectSelect.query(Artist.class)
+					.where(Artist.DATE_OF_BIRTH.gt(new Date()))
+					.and(Artist.DATE_OF_BIRTH.lt(new Date()));
+
 			DbEntity entity = context.getEntityResolver().getDbEntity("ARTIST");
 			entity.getDataMap().setQuotingSQLIdentifiers(true);
-			q.setQualifier(ExpressionFactory.greaterExp("dateOfBirth", new Date()));
-			q.andQualifier(ExpressionFactory.lessExp("dateOfBirth", new Date()));
 
 			String charStart = unitAdapter.getIdentifiersStartQuote();
 			String charEnd = unitAdapter.getIdentifiersEndQuote();
@@ -595,8 +591,9 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 		// query with joint prefetches and other joins
 		// and with QuoteSqlIdentifiers = true
 		try {
-			SelectQuery<Artist> q = new SelectQuery<>(Artist.class, ExpressionFactory.exp("paintingArray.paintingTitle = 'a'"));
-			q.addPrefetch(Artist.PAINTING_ARRAY.joint());
+			ObjectSelect<Artist> q = ObjectSelect.query(Artist.class)
+					.where(Artist.PAINTING_ARRAY.dot(Painting.PAINTING_TITLE).eq("a"))
+					.prefetch(Artist.PAINTING_ARRAY.joint());
 
 			DbEntity entity = context.getEntityResolver().getDbEntity("ARTIST");
 			entity.getDataMap().setQuotingSQLIdentifiers(true);
@@ -673,8 +670,7 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 		// query with to-one joint prefetches
 		// and with QuoteSqlIdentifiers = true
 		try {
-			SelectQuery<Painting> q = new SelectQuery<>(Painting.class);
-			q.addPrefetch(Painting.TO_ARTIST.joint());
+			ObjectSelect<Painting> q = ObjectSelect.query(Painting.class).prefetch(Painting.TO_ARTIST.joint());
 
 			DbEntity entity = context.getEntityResolver().getDbEntity("PAINTING");
 			entity.getDataMap().setQuotingSQLIdentifiers(true);
@@ -735,7 +731,7 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	 */
 	@Test
 	public void testBuildResultColumns1() throws Exception {
-		SelectQuery<Painting> q = new SelectQuery<>(Painting.class);
+		ObjectSelect<Painting> q = ObjectSelect.query(Painting.class);
 		SelectTranslator tr = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
 
 		tr.getSql();
@@ -765,8 +761,7 @@ public class DefaultSelectTranslatorIT extends ServerCase {
 	 */
 	@Test
 	public void testBuildResultColumns2() throws Exception {
-		SelectQuery<Painting> q = new SelectQuery<>(Painting.class);
-		q.addPrefetch(Painting.TO_ARTIST.joint());
+		ObjectSelect<Painting> q = ObjectSelect.query(Painting.class).prefetch(Painting.TO_ARTIST.joint());
 		SelectTranslator tr = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
 
 		tr.getSql();
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/cache/QueryCacheIT.java b/cayenne-server/src/test/java/org/apache/cayenne/cache/QueryCacheIT.java
index 29bca65..0f580ad 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/cache/QueryCacheIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/cache/QueryCacheIT.java
@@ -20,8 +20,7 @@ package org.apache.cayenne.cache;
 
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.query.QueryCacheStrategy;
-import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
@@ -48,10 +47,9 @@ public class QueryCacheIT extends ServerCase {
         a.setArtistName("artist");
         context1.commitChanges();
         
-        SelectQuery q = new SelectQuery(Artist.class);
-        q.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
-        List<Artist> result1 = context1.performQuery(q);
-        List<Artist> result2 = context2.performQuery(q);
+        ObjectSelect<Artist> q = ObjectSelect.query(Artist.class).localCache();
+        List<Artist> result1 = q.select(context1);
+        List<Artist> result2 = q.select(context2);
         
         assertNotSame(
                 result1.get(0).getObjectContext(), 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/dba/ConcurrentPkGeneratorIT.java b/cayenne-server/src/test/java/org/apache/cayenne/dba/ConcurrentPkGeneratorIT.java
index 92811c5..13532bf 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/dba/ConcurrentPkGeneratorIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/dba/ConcurrentPkGeneratorIT.java
@@ -24,7 +24,7 @@ import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.testdo.qualified.Qualified1;
 import org.apache.cayenne.unit.DerbyUnitDbAdapter;
 import org.apache.cayenne.unit.UnitDbAdapter;
@@ -84,7 +84,7 @@ public class ConcurrentPkGeneratorIT extends ServerCase {
 		
 		// clear out the table
 		ObjectContext context = runtime.newContext();
-		List<Qualified1> qualified1s = context.select(SelectQuery.query(Qualified1.class, null));
+		List<Qualified1> qualified1s = context.select(ObjectSelect.query(Qualified1.class));
 		context.deleteObjects(qualified1s);
 		context.commitChanges();
 		
@@ -124,7 +124,7 @@ public class ConcurrentPkGeneratorIT extends ServerCase {
 		}
 		
 		// check for gaps in the generated sequence numbers
-		qualified1s = context.select(SelectQuery.query(Qualified1.class, null));
+		qualified1s = context.select(ObjectSelect.query(Qualified1.class));
 		assertEquals(insertsPerThread * numThreads, qualified1s.size());
 
 		// PKs will be used in order most of the time, but the implementation doesn't guarantee it.
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryIT.java
index 3c6b8cb..c22b71d 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionFactoryIT.java
@@ -33,7 +33,6 @@ import java.util.List;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.query.ObjectSelect;
-import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.unit.UnitDbAdapter;
@@ -109,13 +108,11 @@ public class ExpressionFactoryIT extends ServerCase {
 		context.commitChanges();
 
 		Expression ex1 = ExpressionFactory.likeIgnoreCaseDbExp("ARTIST_NAME", "A*_1", '*');
-		SelectQuery<Artist> q1 = new SelectQuery<Artist>(Artist.class, ex1);
-		List<Artist> artists = context.select(q1);
+		List<Artist> artists = ObjectSelect.query(Artist.class, ex1).select(context);
 		assertEquals(1, artists.size());
 
 		Expression ex2 = ExpressionFactory.likeExp("artistName", "A*_2", '*');
-		SelectQuery<Artist> q2 = new SelectQuery<Artist>(Artist.class, ex2);
-		artists = context.select(q2);
+		artists = ObjectSelect.query(Artist.class, ex2).select(context);
 		assertEquals(1, artists.size());
 	}
 	
@@ -133,18 +130,16 @@ public class ExpressionFactoryIT extends ServerCase {
 		context.commitChanges();
 
 		Expression ex1 = ExpressionFactory.containsExp(Artist.ARTIST_NAME.getName(), "A_1");
-		SelectQuery<Artist> q1 = new SelectQuery<Artist>(Artist.class, ex1);
-		List<Artist> artists = context.select(q1);
+		List<Artist> artists = ObjectSelect.query(Artist.class, ex1).select(context);
 		assertEquals(1, artists.size());
 
 		Expression ex2 = ExpressionFactory.containsExp(Artist.ARTIST_NAME.getName(), "A%2");
-		SelectQuery<Artist> q2 = new SelectQuery<Artist>(Artist.class, ex2);
-		artists = context.select(q2);
+		artists = ObjectSelect.query(Artist.class, ex2).select(context);
 		assertEquals(1, artists.size());
 	}
 
 	@Test
-	public void testDifferentExpressionAPI() throws Exception {
+	public void testDifferentExpressionAPI() {
 		List<Artist> res;
 
 		// First version via expression string
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionIT.java
index 0f3d0e0..58a5da0 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/ExpressionIT.java
@@ -25,7 +25,6 @@ import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.configuration.server.ServerRuntime;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.query.ObjectSelect;
-import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.unit.UnitDbAdapter;
@@ -71,39 +70,27 @@ public class ExpressionIT extends ServerCase {
 
 		context.commitChanges();
 
-		SelectQuery<Painting> query = new SelectQuery<Painting>(Painting.class);
-		Expression e = Painting.TO_ARTIST.eq(a1);
-		query.setQualifier(e);
-
 		assertNotSame(context2, context);
 
-		List<Painting> objects = context2.select(query);
+		List<Painting> objects = ObjectSelect.query(Painting.class, Painting.TO_ARTIST.eq(a1)).select(context2);
 		assertEquals(1, objects.size());
 
 		// 2 same objects in different contexts
-		assertTrue(e.match(objects.get(0)));
+		assertTrue(Painting.TO_ARTIST.eq(a1).match(objects.get(0)));
 
 		// we change one object - so the objects are different now
 		// (PersistenceState different)
 		a1.setArtistName("newName");
 
-		SelectQuery<Painting> q2 = new SelectQuery<Painting>(Painting.class);
-		Expression ex2 = Painting.TO_ARTIST.eq(a1);
-		q2.setQualifier(ex2);
-
-		assertTrue(ex2.match(objects.get(0)));
+		assertTrue(Painting.TO_ARTIST.eq(a1).match(objects.get(0)));
 
 		Artist a2 = context.newObject(Artist.class);
 		a2.setArtistName("Equals");
 
 		context.commitChanges();
 
-		SelectQuery<Painting> q = new SelectQuery<Painting>(Painting.class);
-		Expression ex = Painting.TO_ARTIST.eq(a2);
-		q.setQualifier(ex);
-
 		// 2 different objects in different contexts
-		assertFalse(ex.match(objects.get(0)));
+		assertFalse(Painting.TO_ARTIST.eq(a2).match(objects.get(0)));
 	}
 
     @Test
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/ParsedExpQualifierCompatIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/ParsedExpQualifierCompatIT.java
index ed62dcd..c630364 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/ParsedExpQualifierCompatIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/ParsedExpQualifierCompatIT.java
@@ -21,6 +21,8 @@ package org.apache.cayenne.exp;
 
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.query.PrefetchTreeNode;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
@@ -80,12 +82,12 @@ public class ParsedExpQualifierCompatIT extends ServerCase {
         return execute(root, qualifier, null);
     }
 
-    private <T> List<T> execute(Class<T> root, Expression qualifier, String prefecth) {
-        SelectQuery query = new SelectQuery(root, qualifier);
-        if (prefecth != null) {
-            query.addPrefetch(prefecth);
+    private <T> List<T> execute(Class<T> root, Expression qualifier, String prefetch) {
+        ObjectSelect<T> query = ObjectSelect.query(root, qualifier);
+        if (prefetch != null) {
+            query.prefetch(prefetch, PrefetchTreeNode.DISJOINT_PREFETCH_SEMANTICS);
         }
-        return context.performQuery(query);
+        return query.select(context);
     }
 
     @Test
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
index 91ca804..ddf2b50 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/property/PathAliasesIT.java
@@ -32,7 +32,6 @@ import org.apache.cayenne.exp.parser.ASTEqual;
 import org.apache.cayenne.exp.parser.ASTObjPath;
 import org.apache.cayenne.exp.parser.ASTPath;
 import org.apache.cayenne.query.ObjectSelect;
-import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.testmap.Artist;
@@ -126,10 +125,9 @@ public class PathAliasesIT extends ServerCase {
     public void testEntityPropertyAliases() {
         Artist artist = Cayenne.objectForPK(context, Artist.class, 1);
 
-        SelectQuery<Painting> query = SelectQuery.query(Painting.class);
-        Expression expression = Painting.TO_ARTIST.alias("p1").eq(artist);
-        query.setQualifier(expression);
-        List<Painting> paintings = query.select(context);
+        List<Painting> paintings = ObjectSelect.query(Painting.class)
+                .where(Painting.TO_ARTIST.alias("p1").eq(artist))
+                .select(context);
         assertEquals(2, paintings.size());
         assertEquals("artist1", paintings.get(0).getToArtist().getArtistName());
         assertEquals("artist1", paintings.get(1).getToArtist().getArtistName());
@@ -137,13 +135,10 @@ public class PathAliasesIT extends ServerCase {
 
     @Test
     public void testAliases() {
-        SelectQuery<Artist> query1 = new SelectQuery<>(Artist.class);
-        Expression expression = ExpressionFactory.and(
-                Artist.PAINTING_ARRAY.alias("p1").dot(Painting.PAINTING_TITLE).eq("painting2"),
-                Artist.PAINTING_ARRAY.alias("p2").dot(Painting.PAINTING_TITLE).eq("painting4")
-        );
-        query1.setQualifier(expression);
-        List<Artist> artists = query1.select(context);
+        List<Artist> artists = ObjectSelect.query(Artist.class)
+                .where(Artist.PAINTING_ARRAY.alias("p1").dot(Painting.PAINTING_TITLE).eq("painting2"))
+                .and(Artist.PAINTING_ARRAY.alias("p2").dot(Painting.PAINTING_TITLE).eq("painting4"))
+                .select(context);
         assertEquals(1, artists.size());
         assertNotNull(artists.get(0));
         assertEquals("artist4", artists.get(0).getArtistName());
@@ -237,12 +232,10 @@ public class PathAliasesIT extends ServerCase {
         Painting painting2 = Cayenne.objectForPK(context, Painting.class, 2);
         Painting painting4 = Cayenne.objectForPK(context, Painting.class, 4);
 
-        SelectQuery<Artist> query = SelectQuery.query(Artist.class);
-        Expression e1 = ExpressionFactory.and(
-                ExpressionFactory.exp("paintingArray#p1 = $painting1", painting2),
-                ExpressionFactory.exp("paintingArray#p2 = $painting2", painting4));
-        query.setQualifier(e1);
-        List<Artist> artists = query.select(context);
+        List<Artist> artists = ObjectSelect.query(Artist.class)
+                .where(ExpressionFactory.exp("paintingArray#p1 = $painting1", painting2))
+                .and(ExpressionFactory.exp("paintingArray#p2 = $painting2", painting4))
+                .select(context);
         assertEquals(1, artists.size());
         assertEquals("artist4", artists.get(0).getArtistName());
     }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_SubqueryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_SubqueryIT.java
index 4cd6d38..a0ef35f 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_SubqueryIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/ObjectSelect_SubqueryIT.java
@@ -20,7 +20,6 @@
 package org.apache.cayenne.query;
 
 import java.util.Date;
-import java.util.List;
 
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.di.Inject;
@@ -76,6 +75,15 @@ public class ObjectSelect_SubqueryIT extends ServerCase {
     @Test
     public void selectQuery_simpleExists() {
         long count = ObjectSelect.query(Artist.class)
+                .where(ExpressionFactory.exists(ObjectSelect.query(Painting.class, Painting.PAINTING_TITLE.like("painting%"))))
+                .selectCount(context);
+        assertEquals(20L, count);
+    }
+
+    @Test
+    @Deprecated
+    public void selectQuery_simpleExistsSelectQuery() {
+        long count = ObjectSelect.query(Artist.class)
                 .where(ExpressionFactory.exists(SelectQuery.query(Painting.class, Painting.PAINTING_TITLE.like("painting%"))))
                 .selectCount(context);
         assertEquals(20L, count);
@@ -87,9 +95,7 @@ public class ObjectSelect_SubqueryIT extends ServerCase {
                 .andExp(Painting.PAINTING_TITLE.like("painting%"))
                 .andExp(Artist.ARTIST_NAME.enclosing().like("art%"));
 
-        SelectQuery<Painting> subQuery = SelectQuery.query(Painting.class, exp);
-        subQuery.setColumns(Painting.PAINTING_TITLE);
-
+        ColumnSelect<String> subQuery = ObjectSelect.columnQuery(Painting.class, Painting.PAINTING_TITLE).where(exp);
         long count = ObjectSelect.query(Artist.class)
                 .where(ExpressionFactory.exists(subQuery))
                 .selectCount(context);
@@ -99,9 +105,9 @@ public class ObjectSelect_SubqueryIT extends ServerCase {
     @Test
     public void selectQuery_twoLevelExists() {
         Expression exp = Painting.PAINTING_TITLE.like("painting%")
-                .andExp(ExpressionFactory.exists(SelectQuery.query(Gallery.class)));
+                .andExp(ExpressionFactory.exists(ObjectSelect.query(Gallery.class)));
         long count = ObjectSelect.query(Artist.class)
-                .where(ExpressionFactory.exists(SelectQuery.query(Painting.class, exp)))
+                .where(ExpressionFactory.exists(ObjectSelect.query(Painting.class, exp)))
                 .selectCount(context);
         assertEquals(20L, count);
     }
@@ -112,11 +118,11 @@ public class ObjectSelect_SubqueryIT extends ServerCase {
                 .andExp(Painting.TO_GALLERY.enclosing().eq(PropertyFactory.createSelf(Gallery.class)));
 
         Expression exp = Painting.PAINTING_TITLE.like("painting%")
-                .andExp(ExpressionFactory.exists(SelectQuery.query(Gallery.class, deepNestedExp)))
+                .andExp(ExpressionFactory.exists(ObjectSelect.query(Gallery.class, deepNestedExp)))
                 .andExp(Painting.TO_ARTIST.eq(PropertyFactory.createSelf(Artist.class).enclosing()));
 
         long count = ObjectSelect.query(Artist.class)
-                .where(ExpressionFactory.exists(SelectQuery.query(Painting.class, exp)))
+                .where(ExpressionFactory.exists(ObjectSelect.query(Painting.class, exp)))
                 .selectCount(context);
         assertEquals(5L, count);
     }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/QueryChainIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/QueryChainIT.java
index b836389..3a4a061 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/QueryChainIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/QueryChainIT.java
@@ -41,8 +41,8 @@ public class QueryChainIT extends ServerCase {
     public void testSelectQuery() {
 
         QueryChain chain = new QueryChain();
-        chain.addQuery(new SelectQuery<>(Artist.class));
-        chain.addQuery(new SelectQuery<>(Artist.class));
+        chain.addQuery(ObjectSelect.query(Artist.class));
+        chain.addQuery(ObjectSelect.query(Artist.class));
 
         QueryMetadata md = chain.getMetaData(runtime.getDataDomain().getEntityResolver());
 
@@ -55,10 +55,10 @@ public class QueryChainIT extends ServerCase {
     public void testSelectQueryDataRows() {
 
         QueryChain chain = new QueryChain();
-        SelectQuery<DataRow> q1 = SelectQuery.dataRowQuery(Artist.class);
+        ObjectSelect<DataRow> q1 = ObjectSelect.dataRowQuery(Artist.class);
         chain.addQuery(q1);
 
-        SelectQuery<DataRow> q2 = SelectQuery.dataRowQuery(Artist.class);
+        ObjectSelect<DataRow> q2 = ObjectSelect.dataRowQuery(Artist.class);
         chain.addQuery(q2);
 
         QueryMetadata md = chain.getMetaData(runtime.getDataDomain().getEntityResolver());
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/query/SelectQueryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/query/SelectQueryIT.java
index eea2399..4d6f4f3 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/SelectQueryIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/SelectQueryIT.java
@@ -57,6 +57,7 @@ import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.junit.Before;
 import org.junit.Test;
 
+@Deprecated
 @UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
 public class SelectQueryIT extends ServerCase {
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionThreadIT.java b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionThreadIT.java
index ed025c5..c0b95f8 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionThreadIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionThreadIT.java
@@ -22,7 +22,7 @@ package org.apache.cayenne.tx;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
@@ -47,14 +47,11 @@ public class TransactionThreadIT extends ServerCase {
         BaseTransaction.bindThreadTransaction(t);
 
         try {
-
-            SelectQuery q1 = new SelectQuery(Artist.class);
-            context.performQuery(q1);
+            ObjectSelect.query(Artist.class).select(context);
             assertEquals(1, t.getConnections().size());
 
             // delegate will fail if the second query opens a new connection
-            SelectQuery q2 = new SelectQuery(Artist.class);
-            context.performQuery(q2);
+            ObjectSelect.query(Artist.class).select(context);
 
             assertEquals(1, t.getConnections().size());
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/jira/CAY_115IT.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/jira/CAY_115IT.java
index 60f880b..e4df0f0 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/jira/CAY_115IT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/jira/CAY_115IT.java
@@ -23,6 +23,7 @@ import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
@@ -81,6 +82,7 @@ public class CAY_115IT extends ServerCase {
     }
 
     @Test
+    @Deprecated
     public void testDistinctClobFetch() throws Exception {
         if (!accessStackAdapter.supportsLobInsertsAsStrings()) {
             return;
@@ -111,8 +113,7 @@ public class CAY_115IT extends ServerCase {
         createDistinctClobFetchWithToManyJoin();
 
         Expression qual = ExpressionFactory.exp("details.name like 'cd%'");
-        SelectQuery query = new SelectQuery(ClobMaster.class, qual);
-        List<?> result = context.performQuery(query);
+        List<?> result = ObjectSelect.query(ClobMaster.class, qual).select(context);
 
         assertEquals(3, result.size());
     }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/jira/CAY_194IT.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/jira/CAY_194IT.java
index d894564..f05f50e 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/jira/CAY_194IT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/jira/CAY_194IT.java
@@ -21,9 +21,7 @@ package org.apache.cayenne.unit.jira;
 
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.relationships.ReflexiveAndToOne;
@@ -77,13 +75,11 @@ public class CAY_194IT extends ServerCase {
 
         context.commitChanges();
 
-        Expression qualifier = ExpressionFactory.matchExp("children", o2);
-        List<?> parents = SelectQuery.query(ReflexiveAndToOne.class, qualifier).select(context);
+        List<?> parents = ObjectSelect.query(ReflexiveAndToOne.class, ReflexiveAndToOne.CHILDREN.contains(o2)).select(context);
         assertEquals(1, parents.size());
         assertSame(o1, parents.get(0));
 
-        qualifier = ExpressionFactory.matchExp("children", o1);
-        parents = SelectQuery.query(ReflexiveAndToOne.class, qualifier).select(context);
+        parents = ObjectSelect.query(ReflexiveAndToOne.class, ReflexiveAndToOne.CHILDREN.contains(o1)).select(context);
         assertEquals(0, parents.size());
     }
 
@@ -101,8 +97,7 @@ public class CAY_194IT extends ServerCase {
 
         context.commitChanges();
 
-        Expression qualifier = ExpressionFactory.matchExp("toParent", o1);
-        List<ReflexiveAndToOne> children = SelectQuery.query(ReflexiveAndToOne.class, qualifier).select(context);
+        List<ReflexiveAndToOne> children = ObjectSelect.query(ReflexiveAndToOne.class, ReflexiveAndToOne.TO_PARENT.eq(o1)).select(context);
         assertEquals(1, children.size());
         assertSame(o2, children.get(0));
 


Mime
View raw message