Repository: cayenne
Updated Branches:
  refs/heads/master 14e9dc3bd -> 8f16b6072


CAY-1966 SQLTemplate/SQLSelect positional parameter binding

    * positional parameter bindings in SQLSelect


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/8f16b607
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/8f16b607
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/8f16b607

Branch: refs/heads/master
Commit: 8f16b60728ac7bb0b54497053d91c6cd5c566359
Parents: 14e9dc3
Author: aadamchik <[email protected]>
Authored: Sun Nov 2 22:59:04 2014 +0300
Committer: aadamchik <[email protected]>
Committed: Sun Nov 2 23:17:15 2014 +0300

----------------------------------------------------------------------
 .../org/apache/cayenne/query/SQLSelect.java     |  48 +++-
 .../org/apache/cayenne/query/SQLTemplate.java   |  11 +-
 .../org/apache/cayenne/query/SQLSelectIT.java   | 250 ++++++++++---------
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |   1 +
 4 files changed, 179 insertions(+), 131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/8f16b607/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
index fc413fa..5509cb4 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLSelect.java
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.query;
 
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -90,6 +92,7 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
        protected QueryCacheStrategy cacheStrategy;
        protected String[] cacheGroups;
        protected Map<String, Object> params;
+       protected List<Object> positionalParams;
        protected CapsStrategy columnNameCaps;
        protected int limit;
        protected int offset;
@@ -103,7 +106,6 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
        public SQLSelect(Class<T> persistentType, String sql) {
                this.persistentType = persistentType;
                this.sqlBuffer = sql != null ? new StringBuilder(sql) : new 
StringBuilder();
-               this.params = new HashMap<String, Object>();
                this.limit = QueryMetadata.FETCH_LIMIT_DEFAULT;
                this.offset = QueryMetadata.FETCH_OFFSET_DEFAULT;
                this.pageSize = QueryMetadata.PAGE_SIZE_DEFAULT;
@@ -148,26 +150,48 @@ public class SQLSelect<T> extends IndirectQuery 
implements Select<T> {
        }
 
        public SQLSelect<T> params(String name, Object value) {
-               params.put(name, value);
-               this.replacementQuery = null;
+               params(Collections.singletonMap(name, value));
                return this;
        }
 
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public SQLSelect<T> params(Map<String, ?> parameters) {
-               Map bareMap = parameters;
-               parameters.putAll(bareMap);
+
+               if (this.params == null) {
+                       this.params = new HashMap<String, Object>(parameters);
+               } else {
+                       Map bareMap = parameters;
+                       this.params.putAll(bareMap);
+               }
+
                this.replacementQuery = null;
+
+               // since named parameters are specified, resetting positional
+               // parameters
+               this.positionalParams = null;
+               return this;
+       }
+
+       public SQLSelect<T> paramsArray(Object... params) {
+               return paramsList(params != null ? Arrays.asList(params) : 
null);
+       }
+
+       public SQLSelect<T> paramsList(List<Object> params) {
+               // since named parameters are specified, resetting positional
+               // parameters
+               this.params = null;
+
+               this.positionalParams = params;
                return this;
        }
 
        /**
-        * Returns a mutable map of parameters that will be bound to SQL. A 
caller
-        * is free to add/remove parameters from the returned map as needed.
+        * Returns an immmutable map of parameters that will be bound to SQL. A
+        * caller is free to add/remove parameters from the returned map as 
needed.
         * Alternatively one may use chained {@link #params(String, Object)}
         */
        public Map<String, Object> getParams() {
-               return params;
+               return params != null ? params : Collections.<String, Object> 
emptyMap();
        }
 
        @Override
@@ -195,7 +219,13 @@ public class SQLSelect<T> extends IndirectQuery implements 
Select<T> {
                template.setDefaultTemplate(getSql());
                template.setCacheGroups(cacheGroups);
                template.setCacheStrategy(cacheStrategy);
-               template.setParams(params);
+
+               if (positionalParams != null) {
+                       template.setParamsArray(positionalParams);
+               } else {
+                       template.setParams(params);
+               }
+
                template.setColumnNamesCapitalization(columnNameCaps);
                template.setFetchLimit(limit);
                template.setFetchOffset(offset);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8f16b607/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java 
b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
index dd4b176..0241975 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
@@ -19,6 +19,7 @@
 
 package org.apache.cayenne.query;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -357,11 +358,17 @@ public class SQLTemplate extends AbstractQuery implements 
ParameterizedQuery, XM
         * @since 4.0
         */
        public void setParamsArray(Object... params) {
+               setParamsList(params != null ? Arrays.asList(params) : null);
+       }
+
+       /**
+        * @since 4.0
+        */
+       public void setParamsList(List<Object> params) {
                // since positional parameters are specified, resetting named
                // parameters
                this.parameters = null;
-
-               this.positionalParams = params != null ? Arrays.asList(params) 
: null;
+               this.positionalParams = params != null ? new 
ArrayList<Object>(params) : null;
        }
 
        /**

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8f16b607/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java 
b/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java
index bf5d66b..0d7acf0 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/query/SQLSelectIT.java
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.query;
 
+import java.util.List;
+
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.di.Inject;
@@ -27,187 +29,195 @@ import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
 
-import java.util.List;
-
 @UseServerRuntime(ServerCase.TESTMAP_PROJECT)
 public class SQLSelectIT extends ServerCase {
 
-    @Inject
-    private DataContext context;
+       @Inject
+       private DataContext context;
+
+       @Inject
+       private DBHelper dbHelper;
+
+       @Override
+       protected void setUpAfterInjection() throws Exception {
+               dbHelper.deleteAll("PAINTING_INFO");
+               dbHelper.deleteAll("PAINTING");
+               dbHelper.deleteAll("ARTIST_EXHIBIT");
+               dbHelper.deleteAll("ARTIST_GROUP");
+               dbHelper.deleteAll("ARTIST");
+       }
+
+       protected void createArtistsDataSet() throws Exception {
+               TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
+               tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH");
+
+               long dateBase = System.currentTimeMillis();
 
-    @Inject
-    private DBHelper dbHelper;
+               for (int i = 1; i <= 20; i++) {
+                       tArtist.insert(i, "artist" + i, new 
java.sql.Date(dateBase + 10000 * i));
+               }
+       }
 
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-        dbHelper.deleteAll("PAINTING_INFO");
-        dbHelper.deleteAll("PAINTING");
-        dbHelper.deleteAll("ARTIST_EXHIBIT");
-        dbHelper.deleteAll("ARTIST_GROUP");
-        dbHelper.deleteAll("ARTIST");
-    }
+       public void test_DataRows_DataMapNameRoot() throws Exception {
 
-    protected void createArtistsDataSet() throws Exception {
-        TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
-        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH");
+               createArtistsDataSet();
 
-        long dateBase = System.currentTimeMillis();
+               SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("tstmap", 
"SELECT * FROM ARTIST");
+               assertTrue(q1.isFetchingDataRows());
 
-        for (int i = 1; i <= 20; i++) {
-            tArtist.insert(i, "artist" + i, new java.sql.Date(dateBase + 10000 
* i));
-        }
-    }
+               List<DataRow> result = context.select(q1);
+               assertEquals(20, result.size());
+               assertTrue(result.get(0) instanceof DataRow);
+       }
 
-    public void test_DataRows_DataMapNameRoot() throws Exception {
+       public void test_DataRows_DefaultRoot() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("tstmap", "SELECT * 
FROM ARTIST");
-        assertTrue(q1.isFetchingDataRows());
+               SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST");
+               assertTrue(q1.isFetchingDataRows());
 
-        List<DataRow> result = context.select(q1);
-        assertEquals(20, result.size());
-        assertTrue(result.get(0) instanceof DataRow);
-    }
+               List<DataRow> result = context.select(q1);
+               assertEquals(20, result.size());
+               assertTrue(result.get(0) instanceof DataRow);
+       }
 
-    public void test_DataRows_DefaultRoot() throws Exception {
+       public void test_DataRows_ClassRoot() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("SELECT * FROM ARTIST");
-        assertTrue(q1.isFetchingDataRows());
+               SQLSelect<Artist> q1 = SQLSelect.query(Artist.class, "SELECT * 
FROM ARTIST");
+               assertFalse(q1.isFetchingDataRows());
+               List<Artist> result = context.select(q1);
+               assertEquals(20, result.size());
+               assertTrue(result.get(0) instanceof Artist);
+       }
 
-        List<DataRow> result = context.select(q1);
-        assertEquals(20, result.size());
-        assertTrue(result.get(0) instanceof DataRow);
-    }
+       public void test_DataRows_ClassRoot_Parameters() throws Exception {
 
-    public void test_DataRows_ClassRoot() throws Exception {
+               createArtistsDataSet();
 
-        createArtistsDataSet();
+               SQLSelect<Artist> q1 = SQLSelect.query(Artist.class, "SELECT * 
FROM ARTIST WHERE ARTIST_NAME = #bind($a)");
+               q1.params("a", "artist3");
 
-        SQLSelect<Artist> q1 = SQLSelect.query(Artist.class, "SELECT * FROM 
ARTIST");
-        assertFalse(q1.isFetchingDataRows());
-        List<Artist> result = context.select(q1);
-        assertEquals(20, result.size());
-        assertTrue(result.get(0) instanceof Artist);
-    }
+               assertFalse(q1.isFetchingDataRows());
+               Artist a = context.selectOne(q1);
+               assertEquals("artist3", a.getArtistName());
+       }
 
-    public void test_DataRows_ClassRoot_Parameters() throws Exception {
+       public void test_DataRows_ClassRoot_Bind() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        SQLSelect<Artist> q1 = SQLSelect.query(Artist.class, "SELECT * FROM 
ARTIST WHERE ARTIST_NAME = #bind($a)");
-        q1.getParams().put("a", "artist3");
+               SQLSelect<Artist> q1 = SQLSelect.query(Artist.class,
+                               "SELECT * FROM ARTIST WHERE ARTIST_NAME = 
#bind($a) OR ARTIST_NAME = #bind($b)");
+               q1.params("a", "artist3").params("b", "artist4");
 
-        assertFalse(q1.isFetchingDataRows());
-        Artist a = context.selectOne(q1);
-        assertEquals("artist3", a.getArtistName());
-    }
+               List<Artist> result = context.select(q1);
+               assertEquals(2, result.size());
+       }
 
-    public void test_DataRows_ClassRoot_Bind() throws Exception {
+       public void test_DataRows_ColumnNameCaps() throws Exception {
 
-        createArtistsDataSet();
+               SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST WHERE ARTIST_NAME = 'artist2'");
+               q1.upperColumnNames();
 
-        SQLSelect<Artist> q1 = SQLSelect.query(Artist.class,
-                "SELECT * FROM ARTIST WHERE ARTIST_NAME = #bind($a) OR 
ARTIST_NAME = #bind($b)");
-        q1.params("a", "artist3").params("b", "artist4");
+               SQLTemplate r1 = (SQLTemplate) 
q1.getReplacementQuery(context.getEntityResolver());
+               assertEquals(CapsStrategy.UPPER, 
r1.getColumnNamesCapitalization());
 
-        List<Artist> result = context.select(q1);
-        assertEquals(2, result.size());
-    }
+               q1.lowerColumnNames();
+               SQLTemplate r2 = (SQLTemplate) 
q1.getReplacementQuery(context.getEntityResolver());
+               assertEquals(CapsStrategy.LOWER, 
r2.getColumnNamesCapitalization());
+       }
 
-    public void test_DataRows_ColumnNameCaps() throws Exception {
+       public void test_DataRows_FetchLimit() throws Exception {
 
-        SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("SELECT * FROM ARTIST 
WHERE ARTIST_NAME = 'artist2'");
-        q1.upperColumnNames();
+               createArtistsDataSet();
 
-        SQLTemplate r1 = (SQLTemplate) 
q1.getReplacementQuery(context.getEntityResolver());
-        assertEquals(CapsStrategy.UPPER, r1.getColumnNamesCapitalization());
+               SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST");
+               q1.limit(5);
 
-        q1.lowerColumnNames();
-        SQLTemplate r2 = (SQLTemplate) 
q1.getReplacementQuery(context.getEntityResolver());
-        assertEquals(CapsStrategy.LOWER, r2.getColumnNamesCapitalization());
-    }
+               assertEquals(5, context.select(q1).size());
+       }
 
-    public void test_DataRows_FetchLimit() throws Exception {
+       public void test_DataRows_FetchOffset() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("SELECT * FROM ARTIST");
-        q1.limit(5);
+               SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST");
+               q1.offset(4);
 
-        assertEquals(5, context.select(q1).size());
-    }
+               assertEquals(16, context.select(q1).size());
+       }
 
-    public void test_DataRows_FetchOffset() throws Exception {
+       public void test_Append() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        SQLSelect<DataRow> q1 = SQLSelect.dataRowQuery("SELECT * FROM ARTIST");
-        q1.offset(4);
+               SQLSelect<Artist> q1 = SQLSelect.query(Artist.class, "SELECT * 
FROM ARTIST")
+                               .append(" WHERE ARTIST_NAME = 
#bind($a)").params("a", "artist3");
 
-        assertEquals(16, context.select(q1).size());
-    }
+               List<Artist> result = context.select(q1);
+               assertEquals(1, result.size());
+       }
 
-    public void test_Append() throws Exception {
+       public void test_Select() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        SQLSelect<Artist> q1 = SQLSelect.query(Artist.class, "SELECT * FROM 
ARTIST")
-                .append(" WHERE ARTIST_NAME = #bind($a)").params("a", 
"artist3");
+               List<Artist> result = SQLSelect.query(Artist.class, "SELECT * 
FROM ARTIST WHERE ARTIST_NAME = #bind($a)")
+                               .params("a", "artist3").select(context);
 
-        List<Artist> result = context.select(q1);
-        assertEquals(1, result.size());
-    }
+               assertEquals(1, result.size());
+       }
 
-    public void test_Select() throws Exception {
+       public void test_SelectOne() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        List<Artist> result = SQLSelect.query(Artist.class, "SELECT * FROM 
ARTIST WHERE ARTIST_NAME = #bind($a)")
-                .params("a", "artist3").select(context);
+               Artist a = SQLSelect.query(Artist.class, "SELECT * FROM ARTIST 
WHERE ARTIST_NAME = #bind($a)")
+                               .params("a", "artist3").selectOne(context);
 
-        assertEquals(1, result.size());
-    }
+               assertEquals("artist3", a.getArtistName());
+       }
 
-    public void test_SelectOne() throws Exception {
+       public void test_SelectLong() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        Artist a = SQLSelect.query(Artist.class, "SELECT * FROM ARTIST WHERE 
ARTIST_NAME = #bind($a)")
-                .params("a", "artist3").selectOne(context);
+               long id = SQLSelect.scalarQuery(Long.class, "SELECT ARTIST_ID 
FROM ARTIST WHERE ARTIST_NAME = #bind($a)")
+                               .params("a", "artist3").selectOne(context);
 
-        assertEquals("artist3", a.getArtistName());
-    }
+               assertEquals(3l, id);
+       }
 
-    public void test_SelectLong() throws Exception {
+       public void test_SelectLongArray() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        long id = SQLSelect.scalarQuery(Long.class, "SELECT ARTIST_ID FROM 
ARTIST WHERE ARTIST_NAME = #bind($a)")
-                .params("a", "artist3").selectOne(context);
+               List<Long> ids = SQLSelect.scalarQuery(Long.class, "SELECT 
ARTIST_ID FROM ARTIST ORDER BY ARTIST_ID").select(
+                               context);
 
-        assertEquals(3l, id);
-    }
+               assertEquals(20, ids.size());
+               assertEquals(2l, ids.get(1).longValue());
+       }
 
-    public void test_SelectLongArray() throws Exception {
+       public void test_SelectCount() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        List<Long> ids = SQLSelect.scalarQuery(Long.class, "SELECT ARTIST_ID 
FROM ARTIST ORDER BY ARTIST_ID").select(
-                context);
+               int c = SQLSelect.scalarQuery(Integer.class, "SELECT 
#result('COUNT(*)' 'int') FROM ARTIST").selectOne(context);
 
-        assertEquals(20, ids.size());
-        assertEquals(2l, ids.get(1).longValue());
-    }
+               assertEquals(20, c);
+       }
 
-    public void test_SelectCount() throws Exception {
+       public void testSQLTemplate_PositionalParams() throws Exception {
 
-        createArtistsDataSet();
+               createArtistsDataSet();
 
-        int c = SQLSelect.scalarQuery(Integer.class, "SELECT 
#result('COUNT(*)' 'int') FROM ARTIST").selectOne(context);
+               Long id = SQLSelect.scalarQuery(Long.class, "SELECT ARTIST_ID 
FROM ARTIST WHERE ARTIST_NAME = #bind($a)")
+                               .paramsArray("artist3").selectOne(context);
 
-        assertEquals(20, c);
-    }
+               assertEquals(3l, id.longValue());
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8f16b607/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt 
b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index 75c7756..ea1e1fd 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -69,6 +69,7 @@ CAY-1958 SelectById - a new full-featured select query to get 
objects by id
 CAY-1960 ExpressionFactory.exp(..) , and(..), or(..)
 CAY-1962 Implement CayenneTable column resize on double-click on the header 
separator
 CAY-1965 Change version from 3.2 to 4.0
+CAY-1966 SQLTemplate/SQLSelect positional parameter binding
 CAY-1967 Deprecate SQLTemplate parameter batches
 
 Bug Fixes:

Reply via email to