You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/11/02 16:36:52 UTC
[1/6] CAY-1966 SQLTemplate/SQLSelect positional parameter binding
Repository: cayenne
Updated Branches:
refs/heads/master d3c5b72d1 -> 617628c7f
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java
new file mode 100644
index 0000000..3c291b8
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java
@@ -0,0 +1,188 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.velocity;
+
+import org.apache.cayenne.DataRow;
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.MockOperationObserver;
+import org.apache.cayenne.access.jdbc.SQLTemplateAction;
+import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.dba.JdbcAdapter;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.CapsStrategy;
+import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.test.jdbc.DBHelper;
+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.sql.Connection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Test for Result directive to check if we could use ResultDitrective optionally.
+ */
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class ResultDirectiveIT extends ServerCase {
+
+ @Inject
+ private ServerRuntime runtime;
+
+ @Inject
+ private DBHelper dbHelper;
+
+ @Inject
+ private JdbcAdapter dbAdapter;
+
+ @Override
+ protected void setUpAfterInjection() throws Exception {
+ dbHelper.deleteAll("PAINTING_INFO");
+ dbHelper.deleteAll("PAINTING");
+ dbHelper.deleteAll("PAINTING1");
+ dbHelper.deleteAll("ARTIST_EXHIBIT");
+ dbHelper.deleteAll("ARTIST_GROUP");
+ dbHelper.deleteAll("ARTIST");
+ dbHelper.deleteAll("EXHIBIT");
+ dbHelper.deleteAll("GALLERY");
+ }
+
+ public void testWithoutResultDirective() throws Exception {
+ String sql = "SELECT ARTIST_ID, ARTIST_NAME FROM ARTIST";
+ Map<String, Object> artist = insertArtist();
+ Map<String, Object> selectResult = selectForQuery(sql);
+
+ assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
+ assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME"));
+ }
+
+ public void testWithOnlyResultDirective() throws Exception {
+ String sql = "SELECT #result('ARTIST_ID' 'java.lang.Integer'),"
+ + " #result('ARTIST_NAME' 'java.lang.String')"
+ + " FROM ARTIST";
+ Map<String, Object> artist = insertArtist();
+ Map<String, Object> selectResult = selectForQuery(sql);
+
+ assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
+ assertEquals(artist.get("ARTIST_NAME"), selectResult
+ .get("ARTIST_NAME")
+ .toString()
+ .trim());
+ }
+
+ public void testWithMixedDirectiveUse1() throws Exception {
+ String sql = "SELECT ARTIST_ID,"
+ + " #result('ARTIST_NAME' 'java.lang.String')"
+ + " FROM ARTIST";
+ Map<String, Object> artist = insertArtist();
+ Map<String, Object> selectResult = selectForQuery(sql);
+
+ assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
+ assertEquals(artist.get("ARTIST_NAME"), selectResult
+ .get("ARTIST_NAME")
+ .toString()
+ .trim());
+ }
+
+ public void testWithMixedDirectiveUse2() throws Exception {
+ String sql = "SELECT #result('ARTIST_ID' 'java.lang.Integer'),"
+ + " ARTIST_NAME "
+ + " FROM ARTIST";
+ Map<String, Object> artist = insertArtist();
+ Map<String, Object> selectResult = selectForQuery(sql);
+
+ assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
+ assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME"));
+ }
+
+ private Map<String, Object> selectForQuery(String sql) {
+ SQLTemplate template = new SQLTemplate(Artist.class, sql);
+ template.setColumnNamesCapitalization(CapsStrategy.UPPER);
+ MockOperationObserver observer = new MockOperationObserver();
+ runtime.getDataDomain().performQueries(
+ Collections.singletonList(template),
+ observer);
+
+ List<Map<String, Object>> data = observer.rowsForQuery(template);
+ assertEquals(1, data.size());
+ Map<String, Object> row = data.get(0);
+ return row;
+ }
+
+ /**
+ * Inserts one Artist
+ *
+ * @return Inserted Artist as a DataRow
+ */
+ private Map<String, Object> insertArtist() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Integer(1));
+ parameters.put("name", "ArtistToTestResult");
+ String templateString = "INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME, DATE_OF_BIRTH) "
+ + "VALUES (#bind($id), #bind($name), #bind($dob))";
+
+ SQLTemplate template = new SQLTemplate(Object.class, templateString);
+
+ template.setParameters(parameters);
+
+ DataNode node = new DataNode();
+ node.setEntityResolver(runtime.getDataDomain().getEntityResolver());
+ node.setRowReaderFactory(mock(RowReaderFactory.class));
+ node.setAdapter(dbAdapter);
+
+ SQLTemplateAction action = new SQLTemplateAction(template, node);
+
+ Connection c = runtime
+ .getDataDomain()
+ .getDataNodes()
+ .iterator()
+ .next()
+ .getDataSource()
+ .getConnection();
+ try {
+ MockOperationObserver observer = new MockOperationObserver();
+ action.performAction(c, observer);
+
+ int[] batches = observer.countsForQuery(template);
+ assertNotNull(batches);
+ assertEquals(1, batches.length);
+ assertEquals(1, batches[0]);
+ }
+ finally {
+ c.close();
+ }
+
+ MockOperationObserver observer = new MockOperationObserver();
+ SelectQuery query = new SelectQuery(Artist.class);
+ runtime
+ .getDataDomain()
+ .performQueries(Collections.singletonList(query), observer);
+
+ List<?> data = observer.rowsForQuery(query);
+ assertEquals(1, data.size());
+ DataRow row = (DataRow) data.get(0);
+ return row;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorChainTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorChainTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorChainTest.java
new file mode 100644
index 0000000..d0e812a
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorChainTest.java
@@ -0,0 +1,221 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import org.apache.cayenne.access.jdbc.SQLStatement;
+import org.apache.cayenne.velocity.SQLTemplateProcessor;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class SQLTemplateProcessorChainTest {
+
+ @Test
+ public void testProcessTemplateNoChunks() throws Exception {
+ // whatever is inside the chain, it should render as empty if there
+ // is no chunks...
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
+ "#chain(' AND ') #end",
+ Collections.EMPTY_MAP);
+
+ assertEquals("", compiled.getSql());
+
+ compiled = new SQLTemplateProcessor().processTemplate(
+ "#chain(' AND ') garbage #end",
+ Collections.EMPTY_MAP);
+
+ assertEquals("", compiled.getSql());
+
+ compiled = new SQLTemplateProcessor().processTemplate(
+ "#chain(' AND ' 'PREFIX') #end",
+ Collections.EMPTY_MAP);
+
+ assertEquals("", compiled.getSql());
+ compiled = new SQLTemplateProcessor().processTemplate(
+ "#chain(' AND ' 'PREFIX') garbage #end",
+ Collections.EMPTY_MAP);
+
+ assertEquals("", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateFullChain() throws Exception {
+ String template = "#chain(' OR ')"
+ + "#chunk($a)$a#end"
+ + "#chunk($b)$b#end"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ Map map = new HashMap();
+ map.put("a", "[A]");
+ map.put("b", "[B]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
+ assertEquals("[A] OR [B] OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateFullChainAndPrefix() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk($a)$a#end"
+ + "#chunk($b)$b#end"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ Map map = new HashMap();
+ map.put("a", "[A]");
+ map.put("b", "[B]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
+ assertEquals("WHERE [A] OR [B] OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplatePartialChainMiddle() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk($a)$a#end"
+ + "#chunk($b)$b#end"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ Map map = new HashMap();
+ map.put("a", "[A]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
+ assertEquals("WHERE [A] OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplatePartialChainStart() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk($a)$a#end"
+ + "#chunk($b)$b#end"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ Map map = new HashMap();
+ map.put("b", "[B]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
+ assertEquals("WHERE [B] OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplatePartialChainEnd() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk($a)$a#end"
+ + "#chunk($b)$b#end"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ Map map = new HashMap();
+ map.put("a", "[A]");
+ map.put("b", "[B]");
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
+ assertEquals("WHERE [A] OR [B]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateChainWithGarbage() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk($a)$a#end"
+ + " some other stuff"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ Map map = new HashMap();
+ map.put("a", "[A]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
+ assertEquals("WHERE [A] some other stuff OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateChainUnconditionalChunks() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk()C1#end"
+ + "#chunk()C2#end"
+ + "#chunk()C3#end"
+ + "#end";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
+ template,
+ Collections.EMPTY_MAP);
+ assertEquals("WHERE C1 OR C2 OR C3", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateEmptyChain() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk($a)$a#end"
+ + "#chunk($b)$b#end"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
+ template,
+ Collections.EMPTY_MAP);
+ assertEquals("", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateWithFalseOrZero1() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk($a)[A]#end"
+ + "#chunk($b)[B]#end"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ Map map = new HashMap();
+ map.put("a", false);
+ map.put("b", 0);
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
+ assertEquals("WHERE [A] OR [B]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateWithFalseOrZero2() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')"
+ + "#chunk($a)$a#end"
+ + "#chunk($b)$b#end"
+ + "#chunk($c)$c#end"
+ + "#end";
+
+ Map map = new HashMap();
+ map.put("a", false);
+ map.put("b", 0);
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
+ assertEquals("WHERE false OR 0", compiled.getSql());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorSelectTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorSelectTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorSelectTest.java
new file mode 100644
index 0000000..3481982
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorSelectTest.java
@@ -0,0 +1,112 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import org.apache.cayenne.access.jdbc.ColumnDescriptor;
+import org.apache.cayenne.access.jdbc.SQLStatement;
+import org.apache.cayenne.velocity.SQLTemplateProcessor;
+import org.junit.Test;
+
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class SQLTemplateProcessorSelectTest {
+
+ @Test
+ public void testProcessTemplateUnchanged() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
+ sqlTemplate,
+ Collections.EMPTY_MAP);
+
+ assertEquals(sqlTemplate, compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ assertEquals(0, compiled.getResultColumns().length);
+ }
+
+ @Test
+ public void testProcessSelectTemplate1() throws Exception {
+ String sqlTemplate = "SELECT #result('A') FROM ME";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
+ sqlTemplate,
+ Collections.EMPTY_MAP);
+
+ assertEquals("SELECT A FROM ME", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ assertEquals(1, compiled.getResultColumns().length);
+ assertEquals("A", compiled.getResultColumns()[0].getName());
+ assertNull(compiled.getResultColumns()[0].getJavaClass());
+ }
+
+ @Test
+ public void testProcessSelectTemplate2() throws Exception {
+ String sqlTemplate = "SELECT #result('A' 'String') FROM ME";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
+ sqlTemplate,
+ Collections.EMPTY_MAP);
+
+ assertEquals("SELECT A FROM ME", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ assertEquals(1, compiled.getResultColumns().length);
+ assertEquals("A", compiled.getResultColumns()[0].getName());
+ assertEquals("java.lang.String", compiled.getResultColumns()[0].getJavaClass());
+ }
+
+ @Test
+ public void testProcessSelectTemplate3() throws Exception {
+ String sqlTemplate = "SELECT #result('A' 'String' 'B') FROM ME";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
+ sqlTemplate,
+ Collections.EMPTY_MAP);
+
+ assertEquals("SELECT A AS B FROM ME", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ assertEquals(1, compiled.getResultColumns().length);
+ ColumnDescriptor column = compiled.getResultColumns()[0];
+ assertEquals("A", column.getName());
+ assertEquals("B", column.getDataRowKey());
+ assertEquals("java.lang.String", column.getJavaClass());
+ }
+
+ @Test
+ public void testProcessSelectTemplate4() throws Exception {
+ String sqlTemplate = "SELECT #result('A'), #result('B'), #result('C') FROM ME";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
+ sqlTemplate,
+ Collections.EMPTY_MAP);
+
+ assertEquals("SELECT A, B, C FROM ME", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ assertEquals(3, compiled.getResultColumns().length);
+ assertEquals("A", compiled.getResultColumns()[0].getName());
+ assertEquals("B", compiled.getResultColumns()[1].getName());
+ assertEquals("C", compiled.getResultColumns()[2].getName());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorTest.java
new file mode 100644
index 0000000..89f48dc
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorTest.java
@@ -0,0 +1,235 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Types;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.DataObject;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.cayenne.access.jdbc.SQLStatement;
+import org.junit.Test;
+
+public class SQLTemplateProcessorTest {
+
+ @Test
+ public void testProcessTemplateUnchanged1() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate,
+ Collections.<String, Object> emptyMap());
+
+ assertEquals(sqlTemplate, compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ }
+
+ @Test
+ public void testProcessTemplateUnchanged2() throws Exception {
+ String sqlTemplate = "SELECT a.b as XYZ FROM $SYSTEM_TABLE";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate,
+ Collections.<String, Object> emptyMap());
+
+ assertEquals(sqlTemplate, compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ }
+
+ @Test
+ public void testProcessTemplateSimpleDynamicContent() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE $a";
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE VALUE_OF_A", compiled.getSql());
+
+ // bindings are not populated, since no "bind" macro is used.
+ assertEquals(0, compiled.getBindings().length);
+ }
+
+ @Test
+ public void testProcessTemplateBind() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE "
+ + "COLUMN1 = #bind($a 'VARCHAR') AND COLUMN2 = #bind($b 'INTEGER')";
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN1 = ? AND COLUMN2 = ?", compiled.getSql());
+ assertEquals(2, compiled.getBindings().length);
+ assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
+ assertBindingValue(null, compiled.getBindings()[1]);
+ }
+
+ @Test
+ public void testProcessTemplateBindGuessVarchar() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($a)";
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingType(Types.VARCHAR, compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateBindGuessInteger() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($a)";
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", 4);
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingType(Types.INTEGER, compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateBindEqual() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN #bindEqual($a 'VARCHAR')";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate,
+ Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN IS NULL", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+
+ compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN = ?", compiled.getSql());
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateBindNotEqual() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN #bindNotEqual($a 'VARCHAR')";
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate,
+ Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN IS NOT NULL", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+
+ compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN <> ?", compiled.getSql());
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateID() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($helper.cayenneExp($a, 'db:ID_COLUMN'))";
+
+ DataObject dataObject = new CayenneDataObject();
+ dataObject.setObjectId(new ObjectId("T", "ID_COLUMN", 5));
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", dataObject);
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN1 = ?", compiled.getSql());
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingValue(new Integer(5), compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateNotEqualID() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE "
+ + "COLUMN1 #bindNotEqual($helper.cayenneExp($a, 'db:ID_COLUMN1')) "
+ + "AND COLUMN2 #bindNotEqual($helper.cayenneExp($a, 'db:ID_COLUMN2'))";
+
+ Map<String, Object> idMap = new HashMap<String, Object>();
+ idMap.put("ID_COLUMN1", new Integer(3));
+ idMap.put("ID_COLUMN2", "aaa");
+ ObjectId id = new ObjectId("T", idMap);
+ DataObject dataObject = new CayenneDataObject();
+ dataObject.setObjectId(id);
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", dataObject);
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN1 <> ? AND COLUMN2 <> ?", compiled.getSql());
+ assertEquals(2, compiled.getBindings().length);
+ assertBindingValue(new Integer(3), compiled.getBindings()[0]);
+ assertBindingValue("aaa", compiled.getBindings()[1]);
+ }
+
+ @Test
+ public void testProcessTemplateConditions() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME #if($a) WHERE COLUMN1 > #bind($a)#end";
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN1 > ?", compiled.getSql());
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
+
+ compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT * FROM ME ", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ }
+
+ @Test
+ public void testProcessTemplateBindCollection() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN IN (#bind($list 'VARCHAR'))";
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("list", Arrays.asList("a", "b", "c"));
+ SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN IN (?,?,?)", compiled.getSql());
+ assertEquals(3, compiled.getBindings().length);
+
+ compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
+ assertBindingValue("a", compiled.getBindings()[0]);
+ assertBindingValue("b", compiled.getBindings()[1]);
+ assertBindingValue("c", compiled.getBindings()[2]);
+ }
+
+ protected void assertBindingValue(Object expectedValue, Object binding) {
+ assertTrue("Not a binding!", binding instanceof ParameterBinding);
+ assertEquals(expectedValue, ((ParameterBinding) binding).getValue());
+ }
+
+ protected void assertBindingType(int expectedType, Object binding) {
+ assertTrue("Not a binding!", binding instanceof ParameterBinding);
+ assertEquals(expectedType, ((ParameterBinding) binding).getJdbcType());
+ }
+
+ protected void assertBindingPrecision(int expectedPrecision, Object binding) {
+ assertTrue("Not a binding!", binding instanceof ParameterBinding);
+ assertEquals(expectedPrecision, ((ParameterBinding) binding).getScale());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateResourceManagerTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateResourceManagerTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateResourceManagerTest.java
new file mode 100644
index 0000000..725788c
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateResourceManagerTest.java
@@ -0,0 +1,77 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.Reader;
+
+import org.apache.velocity.Template;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.parser.node.SimpleNode;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.runtime.resource.ResourceManager;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SQLTemplateResourceManagerTest {
+
+ private SQLTemplateResourceManager rm;
+
+ @Before
+ public void before() throws Exception {
+
+ RuntimeServices rs = mock(RuntimeServices.class);
+ when(rs.parse(any(Reader.class), anyString(), anyBoolean())).thenReturn(new SimpleNode(1));
+ when(rs.parse(any(Reader.class), anyString())).thenReturn(new SimpleNode(1));
+
+ this.rm = new SQLTemplateResourceManager();
+ rm.initialize(rs);
+ }
+
+ @Test
+ public void testFetResource() throws Exception {
+
+ Resource resource = rm.getResource("abc", ResourceManager.RESOURCE_TEMPLATE, RuntimeConstants.ENCODING_DEFAULT);
+
+ assertTrue(resource instanceof Template);
+
+ // must be cached...
+ assertSame(resource,
+ rm.getResource("abc", ResourceManager.RESOURCE_TEMPLATE, RuntimeConstants.ENCODING_DEFAULT));
+
+ // new resource must be different
+ assertNotSame(resource,
+ rm.getResource("xyz", ResourceManager.RESOURCE_TEMPLATE, RuntimeConstants.ENCODING_DEFAULT));
+
+ // after clearing cache, resource must be refreshed
+ rm.clearCache();
+ assertNotSame(resource,
+ rm.getResource("abc", ResourceManager.RESOURCE_TEMPLATE, RuntimeConstants.ENCODING_DEFAULT));
+ }
+}
[3/6] git commit: CAY-1966 SQLTemplate/SQLSelect positional parameter
binding
Posted by aa...@apache.org.
CAY-1966 SQLTemplate/SQLSelect positional parameter binding
* new org.apache.cayenne.velocity package
* generics fixes in unit tests
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/c8709542
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/c8709542
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/c8709542
Branch: refs/heads/master
Commit: c870954210bbe2838b49acd13ea3f4455c4e44fb
Parents: d3c5b72
Author: aadamchik <aa...@apache.org>
Authored: Sun Nov 2 15:49:38 2014 +0300
Committer: aadamchik <aa...@apache.org>
Committed: Sun Nov 2 16:10:21 2014 +0300
----------------------------------------------------------------------
.../cayenne/access/jdbc/BindDirective.java | 175 ------------
.../cayenne/access/jdbc/BindEqualDirective.java | 56 ----
.../access/jdbc/BindNotEqualDirective.java | 55 ----
.../access/jdbc/BindObjectEqualDirective.java | 163 -----------
.../jdbc/BindObjectNotEqualDirective.java | 69 -----
.../cayenne/access/jdbc/ChainDirective.java | 112 --------
.../cayenne/access/jdbc/ChunkDirective.java | 75 ------
.../cayenne/access/jdbc/ResultDirective.java | 205 --------------
.../cayenne/access/jdbc/SQLTemplateAction.java | 1 +
.../access/jdbc/SQLTemplateProcessor.java | 168 ------------
.../access/jdbc/SQLTemplateRenderingUtils.java | 37 ---
.../access/jdbc/SQLTemplateResourceManager.java | 106 --------
.../apache/cayenne/velocity/BindDirective.java | 176 ++++++++++++
.../cayenne/velocity/BindEqualDirective.java | 57 ++++
.../cayenne/velocity/BindNotEqualDirective.java | 56 ++++
.../velocity/BindObjectEqualDirective.java | 164 ++++++++++++
.../velocity/BindObjectNotEqualDirective.java | 70 +++++
.../apache/cayenne/velocity/ChainDirective.java | 112 ++++++++
.../apache/cayenne/velocity/ChunkDirective.java | 75 ++++++
.../cayenne/velocity/ResultDirective.java | 206 ++++++++++++++
.../cayenne/velocity/SQLTemplateProcessor.java | 155 +++++++++++
.../velocity/SQLTemplateRenderingUtils.java | 37 +++
.../velocity/SQLTemplateResourceManager.java | 106 ++++++++
.../cayenne/access/jdbc/BindDirectiveIT.java | 267 ------------------
.../access/jdbc/MockupRuntimeServices.java | 42 ---
.../cayenne/access/jdbc/ResultDirectiveIT.java | 187 -------------
.../jdbc/SQLTemplateProcessorChainTest.java | 219 ---------------
.../jdbc/SQLTemplateProcessorSelectTest.java | 109 --------
.../access/jdbc/SQLTemplateProcessorTest.java | 260 ------------------
.../jdbc/SQLTemplateResourceManagerTest.java | 65 -----
.../cayenne/velocity/BindDirectiveIT.java | 268 +++++++++++++++++++
.../cayenne/velocity/ResultDirectiveIT.java | 188 +++++++++++++
.../velocity/SQLTemplateProcessorChainTest.java | 221 +++++++++++++++
.../SQLTemplateProcessorSelectTest.java | 112 ++++++++
.../velocity/SQLTemplateProcessorTest.java | 235 ++++++++++++++++
.../SQLTemplateResourceManagerTest.java | 77 ++++++
36 files changed, 2316 insertions(+), 2370 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindDirective.java
deleted file mode 100644
index 59245a5..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindDirective.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Collection;
-import java.util.Iterator;
-
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.util.ConversionUtil;
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-import org.apache.velocity.runtime.directive.Directive;
-import org.apache.velocity.runtime.parser.node.Node;
-
-/**
- * A custom Velocity directive to create a PreparedStatement parameter text. There are the
- * following possible invocation formats inside the template:
- *
- * <pre>
- * #bind(value) - e.g. #bind($xyz)
- * #bind(value jdbc_type_name) - e.g. #bind($xyz 'VARCHAR'). This is the most common and useful form.
- * #bind(value jdbc_type_name, scale) - e.g. #bind($xyz 'VARCHAR' 2)
- * </pre>
- * <p>
- * Other examples:
- * </p>
- * <p>
- * <strong>Binding literal parameter value:</strong>
- * </p>
- * <p>
- * <code>"WHERE SOME_COLUMN > #bind($xyz)"</code> produces
- * <code>"WHERE SOME_COLUMN > ?"</code> and also places the value of the "xyz" parameter
- * in the context "bindings" collection.
- * </p>
- * <p>
- * <strong>Binding ID column of a DataObject value:</strong>
- * </p>
- * <p>
- * <code>"WHERE ID_COL1 = #bind($helper.cayenneExp($xyz, 'db:ID_COL2'))
- * AND ID_COL2 = #bind($helper.cayenneExp($xyz, 'db:ID_COL2'))"</code> produces <code>"WHERE ID_COL1 = ? AND ID_COL2 = ?"</code> and also places the
- * values of id columns of the DataObject parameter "xyz" in the context "bindings"
- * collection.
- * </p>
- *
- * @since 1.1
- */
-public class BindDirective extends Directive {
-
- @Override
- public String getName() {
- return "bind";
- }
-
- @Override
- public int getType() {
- return LINE;
- }
-
- /**
- * Extracts the value of the object property to render and passes control to
- * {@link #render(InternalContextAdapter, Writer, ParameterBinding)} to do the actual
- * rendering.
- */
- @Override
- public boolean render(InternalContextAdapter context, Writer writer, Node node)
- throws IOException, ResourceNotFoundException, ParseErrorException,
- MethodInvocationException {
-
- Object value = getChild(context, node, 0);
- Object type = getChild(context, node, 1);
- int scale = ConversionUtil.toInt(getChild(context, node, 2), -1);
- String typeString = type != null ? type.toString() : null;
-
- if (value instanceof Collection) {
- Iterator<?> it = ((Collection) value).iterator();
- while (it.hasNext()) {
- render(context, writer, node, it.next(), typeString, scale);
-
- if (it.hasNext()) {
- writer.write(',');
- }
- }
- }
- else {
- render(context, writer, node, value, typeString, scale);
- }
-
- return true;
- }
-
- /**
- * @since 3.0
- */
- protected void render(
- InternalContextAdapter context,
- Writer writer,
- Node node,
- Object value,
- String typeString,
- int scale) throws IOException, ParseErrorException {
-
- int jdbcType = TypesMapping.NOT_DEFINED;
- if (typeString != null) {
- jdbcType = TypesMapping.getSqlTypeByName(typeString);
- }
- else if (value != null) {
- jdbcType = TypesMapping.getSqlTypeByJava(value.getClass());
- } else {
- // value is null, set JDBC type to NULL
- jdbcType = TypesMapping.getSqlTypeByName(TypesMapping.SQL_NULL);
- }
-
- if (jdbcType == TypesMapping.NOT_DEFINED) {
- throw new ParseErrorException("Can't determine JDBC type of binding ("
- + value
- + ", "
- + typeString
- + ") at line "
- + node.getLine()
- + ", column "
- + node.getColumn());
- }
-
- render(context, writer, new ParameterBinding(value, jdbcType, scale));
- }
-
- protected void render(
- InternalContextAdapter context,
- Writer writer,
- ParameterBinding binding) throws IOException {
-
- bind(context, binding);
- writer.write('?');
- }
-
- protected Object getChild(InternalContextAdapter context, Node node, int i)
- throws MethodInvocationException {
- return (i >= 0 && i < node.jjtGetNumChildren()) ? node.jjtGetChild(i).value(
- context) : null;
- }
-
- /**
- * Adds value to the list of bindings in the context.
- */
- protected void bind(InternalContextAdapter context, ParameterBinding binding) {
-
- Collection bindings = (Collection) context.getInternalUserContext().get(
- SQLTemplateProcessor.BINDINGS_LIST_KEY);
-
- if (bindings != null) {
- bindings.add(binding);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindEqualDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindEqualDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindEqualDirective.java
deleted file mode 100644
index 773daa6..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindEqualDirective.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.velocity.context.InternalContextAdapter;
-
-/**
- * A custom Velocity directive to create a PreparedStatement parameter text
- * for "= ?". If null value is encountered, generated text will look like "IS NULL".
- * Usage in Velocity template is "WHERE SOME_COLUMN #bindEqual($xyz)".
- *
- * @since 1.1
- */
-public class BindEqualDirective extends BindDirective {
-
- @Override
- public String getName() {
- return "bindEqual";
- }
-
- @Override
- protected void render(
- InternalContextAdapter context,
- Writer writer,
- ParameterBinding binding)
- throws IOException {
-
- if (binding.getValue() != null) {
- bind(context, binding);
- writer.write("= ?");
- }
- else {
- writer.write("IS NULL");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindNotEqualDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindNotEqualDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindNotEqualDirective.java
deleted file mode 100644
index ee54602..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindNotEqualDirective.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.velocity.context.InternalContextAdapter;
-
-/**
- * A custom Velocity directive to create a PreparedStatement parameter text for "<>?".
- * If null value is encountered, generated text will look like "IS NOT NULL". Usage in
- * Velocity template is "WHERE SOME_COLUMN #bindNotEqual($xyz)".
- *
- * @since 1.1
- */
-public class BindNotEqualDirective extends BindDirective {
-
- @Override
- public String getName() {
- return "bindNotEqual";
- }
-
- @Override
- protected void render(
- InternalContextAdapter context,
- Writer writer,
- ParameterBinding binding) throws IOException {
-
- if (binding.getValue() != null) {
- bind(context, binding);
- writer.write("<> ?");
- }
- else {
- writer.write("IS NOT NULL");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindObjectEqualDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindObjectEqualDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindObjectEqualDirective.java
deleted file mode 100644
index f35906c..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindObjectEqualDirective.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-package org.apache.cayenne.access.jdbc;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.sql.Types;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-import org.apache.velocity.runtime.parser.node.Node;
-
-/**
- * A custom Velocity directive to create a set of SQL conditions to match an ObjectId of
- * an object. Usage in Velocity template is "WHERE #bindObjectEqual($object)" or "WHERE
- * #bindObjectEqual($object $columns $idValues)".
- *
- * @since 3.0
- */
-public class BindObjectEqualDirective extends BindDirective {
-
- @Override
- public String getName() {
- return "bindObjectEqual";
- }
-
- @Override
- public boolean render(InternalContextAdapter context, Writer writer, Node node)
- throws IOException, ResourceNotFoundException, ParseErrorException,
- MethodInvocationException {
-
- Object object = getChild(context, node, 0);
- Map idMap = toIdMap(object);
-
- Object sqlColumns = getChild(context, node, 1);
- Object idColumns = getChild(context, node, 2);
-
- if (idMap == null) {
- // assume null object, and bind all null values
-
- if (sqlColumns == null || idColumns == null) {
- throw new ParseErrorException("Invalid parameters. "
- + "Either object has to be set "
- + "or sqlColumns and idColumns or both.");
- }
-
- idMap = Collections.EMPTY_MAP;
- }
- else if (sqlColumns == null || idColumns == null) {
- // infer SQL columns from ID columns
- sqlColumns = idMap.keySet().toArray();
- idColumns = sqlColumns;
- }
-
- Object[] sqlColumnsArray = toArray(sqlColumns);
- Object[] idColumnsArray = toArray(idColumns);
-
- if (sqlColumnsArray.length != idColumnsArray.length) {
- throw new ParseErrorException(
- "SQL columns and ID columns arrays have different sizes.");
- }
-
- for (int i = 0; i < sqlColumnsArray.length; i++) {
-
- Object value = idMap.get(idColumnsArray[i]);
-
- int jdbcType = (value != null) ? TypesMapping.getSqlTypeByJava(value
- .getClass()) : Types.INTEGER;
-
- renderColumn(context, writer, sqlColumnsArray[i], i);
- writer.write(' ');
- render(context, writer, new ParameterBinding(value, jdbcType, -1));
- }
-
- return true;
- }
-
- protected Object[] toArray(Object columns) {
- if (columns instanceof Collection) {
- return ((Collection) columns).toArray();
- }
- else if (columns.getClass().isArray()) {
- return (Object[]) columns;
- }
- else {
- return new Object[] {
- columns
- };
- }
- }
-
- protected Map toIdMap(Object object) throws ParseErrorException {
- if (object instanceof Persistent) {
- return ((Persistent) object).getObjectId().getIdSnapshot();
- }
- else if (object instanceof ObjectId) {
- return ((ObjectId) object).getIdSnapshot();
- }
- else if(object instanceof Map) {
- return (Map) object;
- }
- else if (object != null) {
- throw new ParseErrorException(
- "Invalid object parameter, expected Persistent or ObjectId or null: "
- + object);
- }
- else {
- return null;
- }
- }
-
- protected void renderColumn(
- InternalContextAdapter context,
- Writer writer,
- Object columnName,
- int columnIndex) throws IOException {
-
- if (columnIndex > 0) {
- writer.write(" AND ");
- }
-
- writer.write(columnName.toString());
- }
-
- @Override
- protected void render(
- InternalContextAdapter context,
- Writer writer,
- ParameterBinding binding) throws IOException {
-
- if (binding.getValue() != null) {
- bind(context, binding);
- writer.write("= ?");
- }
- else {
- writer.write("IS NULL");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindObjectNotEqualDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindObjectNotEqualDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindObjectNotEqualDirective.java
deleted file mode 100644
index 0a51eed..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/BindObjectNotEqualDirective.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-package org.apache.cayenne.access.jdbc;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.velocity.context.InternalContextAdapter;
-
-/**
- * A custom Velocity directive to create a set of SQL conditions to check unequality of an
- * ObjectId of an object. Usage in Velocity template is "WHERE
- * #bindObjectNotEqual($object)" or "WHERE #bindObjectNotEqual($object $columns
- * $idValues)".
- *
- * @since 3.0
- */
-public class BindObjectNotEqualDirective extends BindObjectEqualDirective {
-
- @Override
- public String getName() {
- return "bindObjectNotEqual";
- }
-
- @Override
- protected void renderColumn(
- InternalContextAdapter context,
- Writer writer,
- Object columnName,
- int columnIndex) throws IOException {
-
- if (columnIndex > 0) {
- writer.write(" OR ");
- }
-
- writer.write(columnName.toString());
- }
-
- @Override
- protected void render(
- InternalContextAdapter context,
- Writer writer,
- ParameterBinding binding) throws IOException {
-
- if (binding.getValue() != null) {
- bind(context, binding);
- writer.write("<> ?");
- }
- else {
- writer.write("IS NOT NULL");
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ChainDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ChainDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ChainDirective.java
deleted file mode 100644
index 30a7816..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ChainDirective.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-import org.apache.velocity.runtime.directive.Directive;
-import org.apache.velocity.runtime.parser.node.ASTDirective;
-import org.apache.velocity.runtime.parser.node.Node;
-
-/**
- * A custom Velocity directive to conditionally join a number of {@link ChunkDirective chunks}.
- * Usage of chain is the following:
- *
- * <pre>
- * #chain(operator) - e.g. #chain(' AND ')
- * #chain(operator prefix) - e.g. #chain(' AND ' 'WHERE ')</pre>
- *
- * <p><code>operator</code> (e.g. AND, OR, etc.) is used to join chunks that are included
- * in a chain. <code>prefix</code> is inserted if a chain contains at least one chunk.
- * </p>
- *
- * @since 1.1
- */
-public class ChainDirective extends Directive {
-
- @Override
- public String getName() {
- return "chain";
- }
-
- @Override
- public int getType() {
- return BLOCK;
- }
-
- @Override
- public boolean render(InternalContextAdapter context, Writer writer, Node node)
- throws
- IOException,
- ResourceNotFoundException,
- ParseErrorException,
- MethodInvocationException {
-
- int size = node.jjtGetNumChildren();
- if (size == 0) {
- return true;
- }
-
- // BLOCK is the last child
- Node block = node.jjtGetChild(node.jjtGetNumChildren() - 1);
- String join = (size > 1) ? (String) node.jjtGetChild(0).value(context) : "";
- String prefix = (size > 2) ? (String) node.jjtGetChild(1).value(context) : "";
-
- // if there is a conditional prefix, use a separate buffer ofr children
- StringWriter childWriter = new StringWriter(30);
-
- int len = block.jjtGetNumChildren();
- int includedChunks = 0;
- for (int i = 0; i < len; i++) {
- Node child = block.jjtGetChild(i);
-
- // if this is a "chunk", evaluate its expression and prepend join if included...
- if (child instanceof ASTDirective
- && "chunk".equals(((ASTDirective) child).getDirectiveName())) {
-
- if (child.jjtGetNumChildren() < 2
- || child.jjtGetChild(0).value(context) != null) {
-
- if (includedChunks > 0) {
- childWriter.write(join);
- }
-
- includedChunks++;
- }
- }
-
- child.render(context, childWriter);
- }
-
- if (includedChunks > 0) {
- childWriter.flush();
- writer.write(prefix);
- writer.write(childWriter.toString());
- }
-
- return true;
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ChunkDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ChunkDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ChunkDirective.java
deleted file mode 100644
index fb7c870..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ChunkDirective.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-import org.apache.velocity.runtime.directive.Directive;
-import org.apache.velocity.runtime.parser.node.Node;
-
-/**
- * A custom Velocity directive to describe a conditional chunk of a {@link ChainDirective chain}.
- * Usage of chunk is the following:
- *
- * <pre>
- * #chunk()...#end - e.g. #chunk()A = 5#end
- * #chunk($paramKey)...#end - e.g. #chunk($a)A = $a#end
- * </pre>
- * <p>
- * If context contains paramKey and it's value isn't null, chunk is included in the
- * chain, and if it is not the first chunk, it is prefixed with chain join (OR/AND).
- * If context doesn't contain paramKey or it's value is null, chunk is skipped.
- * @since 1.1
- */
-public class ChunkDirective extends Directive {
-
- @Override
- public String getName() {
- return "chunk";
- }
-
- @Override
- public int getType() {
- return BLOCK;
- }
-
- @Override
- public boolean render(InternalContextAdapter context, Writer writer, Node node)
- throws IOException, ResourceNotFoundException, ParseErrorException,
- MethodInvocationException {
-
- // first child is an expression, second is BLOCK
- if (node.jjtGetNumChildren() > 1 && node.jjtGetChild(0).value(context) == null) {
- // skip this chunk
- return false;
- }
-
- // BLOCK is the last child
- Node block = node.jjtGetChild(node.jjtGetNumChildren() - 1);
- block.render(context, writer);
- return true;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ResultDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ResultDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ResultDirective.java
deleted file mode 100644
index c24804a..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/ResultDirective.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.sql.Date;
-import java.sql.Time;
-import java.sql.Timestamp;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.velocity.context.InternalContextAdapter;
-import org.apache.velocity.exception.MethodInvocationException;
-import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-import org.apache.velocity.runtime.directive.Directive;
-import org.apache.velocity.runtime.parser.node.Node;
-import org.apache.cayenne.util.Util;
-
-/**
- * A custom Velocity directive to describe a ResultSet column. There are the following
- * possible invocation formats inside the template:
- *
- * <pre>
- * #result(column_name) - e.g. #result('ARTIST_ID')
- * #result(column_name java_type) - e.g. #result('ARTIST_ID' 'String')
- * #result(column_name java_type column_alias) - e.g. #result('ARTIST_ID' 'String' 'ID')
- * #result(column_name java_type column_alias data_row_key) - e.g. #result('ARTIST_ID' 'String' 'ID' 'toArtist.ID')
- * </pre>
- *
- * <p>
- * 'data_row_key' is needed if SQL 'column_alias' is not appropriate as a DataRow key on
- * the Cayenne side. One common case when this happens is when a DataRow retrieved from a
- * query is mapped using joint prefetch keys. In this case DataRow must use DB_PATH
- * expressions for joint column keys, and their format is incompatible with most databases
- * alias format.
- * </p>
- * <p>
- * Most common Java types used in JDBC can be specified without a package. This includes
- * all numeric types, primitives, String, SQL dates, BigDecimal and BigInteger.
- * </p>
- *
- * @since 1.1
- */
-public class ResultDirective extends Directive {
-
- private static final Map<String, String> typesGuess;
-
- static {
- // init default types
- typesGuess = new HashMap<String, String>();
-
- // primitives
- typesGuess.put("long", Long.class.getName());
- typesGuess.put("double", Double.class.getName());
- typesGuess.put("byte", Byte.class.getName());
- typesGuess.put("boolean", Boolean.class.getName());
- typesGuess.put("float", Float.class.getName());
- typesGuess.put("short", Short.class.getName());
- typesGuess.put("int", Integer.class.getName());
-
- // numeric
- typesGuess.put("Long", Long.class.getName());
- typesGuess.put("Double", Double.class.getName());
- typesGuess.put("Byte", Byte.class.getName());
- typesGuess.put("Boolean", Boolean.class.getName());
- typesGuess.put("Float", Float.class.getName());
- typesGuess.put("Short", Short.class.getName());
- typesGuess.put("Integer", Integer.class.getName());
-
- // other
- typesGuess.put("String", String.class.getName());
- typesGuess.put("Date", Date.class.getName());
- typesGuess.put("Time", Time.class.getName());
- typesGuess.put("Timestamp", Timestamp.class.getName());
- typesGuess.put("BigDecimal", BigDecimal.class.getName());
- typesGuess.put("BigInteger", BigInteger.class.getName());
- }
-
- @Override
- public String getName() {
- return "result";
- }
-
- @Override
- public int getType() {
- return LINE;
- }
-
- @Override
- public boolean render(InternalContextAdapter context, Writer writer, Node node)
- throws IOException, ResourceNotFoundException, ParseErrorException,
- MethodInvocationException {
-
- String column = getChildAsString(context, node, 0);
- if (column == null) {
- throw new ParseErrorException("Column name expected at line "
- + node.getLine()
- + ", column "
- + node.getColumn());
- }
-
- String alias = getChildAsString(context, node, 2);
- String dataRowKey = getChildAsString(context, node, 3);
-
- // determine what we want to name this column in a resulting DataRow...
- String label = (!Util.isEmptyString(dataRowKey)) ? dataRowKey : (!Util
- .isEmptyString(alias)) ? alias : null;
-
- ColumnDescriptor columnDescriptor = new ColumnDescriptor();
- columnDescriptor.setName(column);
- columnDescriptor.setDataRowKey(label);
-
- String type = getChildAsString(context, node, 1);
- if (type != null) {
- columnDescriptor.setJavaClass(guessType(type));
- }
-
- // TODO: andrus 6/27/2007 - this is an unofficial jdbcType parameter that is added
- // temporarily pending CAY-813 implementation for the sake of EJBQL query...
- Object jdbcType = getChild(context, node, 4);
- if (jdbcType instanceof Number) {
- columnDescriptor.setJdbcType(((Number) jdbcType).intValue());
- }
-
- writer.write(column);
-
- // append column alias if needed.
-
- // Note that if table aliases are used, this logic will result in SQL like
- // "t0.ARTIST_NAME AS ARTIST_NAME". Doing extra regex matching to handle this
- // won't probably buy us much.
- if (!Util.isEmptyString(alias) && !alias.equals(column)) {
- writer.write(" AS ");
- writer.write(alias);
- }
-
- bindResult(context, columnDescriptor);
- return true;
- }
-
- protected Object getChild(InternalContextAdapter context, Node node, int i)
- throws MethodInvocationException {
- return (i >= 0 && i < node.jjtGetNumChildren()) ? node.jjtGetChild(i).value(
- context) : null;
- }
-
- /**
- * Returns a directive argument at a given index converted to String.
- *
- * @since 1.2
- */
- protected String getChildAsString(InternalContextAdapter context, Node node, int i)
- throws MethodInvocationException {
- Object value = getChild(context, node, i);
- return (value != null) ? value.toString() : null;
- }
-
- /**
- * Converts "short" type notation to the fully qualified class name. Right now
- * supports all major standard SQL types, including primitives. All other types are
- * expected to be fully qualified, and are not converted.
- */
- protected String guessType(String type) {
- String guessed = typesGuess.get(type);
- return guessed != null ? guessed : type;
- }
-
- /**
- * Adds value to the list of result columns in the context.
- */
- protected void bindResult(
- InternalContextAdapter context,
- ColumnDescriptor columnDescriptor) {
-
- Collection<Object> resultColumns = (Collection<Object>) context
- .getInternalUserContext()
- .get(SQLTemplateProcessor.RESULT_COLUMNS_LIST_KEY);
-
- if (resultColumns != null) {
- resultColumns.add(columnDescriptor);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
index e86f04b..50e8691 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
@@ -49,6 +49,7 @@ import org.apache.cayenne.query.QueryMetadata;
import org.apache.cayenne.query.SQLAction;
import org.apache.cayenne.query.SQLTemplate;
import org.apache.cayenne.util.Util;
+import org.apache.cayenne.velocity.SQLTemplateProcessor;
import org.apache.commons.collections.IteratorUtils;
/**
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
deleted file mode 100644
index d5f487e..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.context.InternalContextAdapterImpl;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.runtime.RuntimeInstance;
-import org.apache.velocity.runtime.log.NullLogChute;
-import org.apache.velocity.runtime.parser.ParseException;
-import org.apache.velocity.runtime.parser.node.SimpleNode;
-
-/**
- * Processor for SQL velocity templates.
- *
- * @see org.apache.cayenne.query.SQLTemplate
- * @since 1.1
- */
-class SQLTemplateProcessor {
-
- private static RuntimeInstance sharedRuntime;
-
- static final String BINDINGS_LIST_KEY = "bindings";
- static final String RESULT_COLUMNS_LIST_KEY = "resultColumns";
- static final String HELPER_KEY = "helper";
-
- private static final SQLTemplateRenderingUtils sharedUtils = new SQLTemplateRenderingUtils();
-
- RuntimeInstance velocityRuntime;
- SQLTemplateRenderingUtils renderingUtils;
-
- static {
- initVelocityRuntime();
- }
-
- private static void initVelocityRuntime() {
- // init static velocity engine
- sharedRuntime = new RuntimeInstance();
-
- // set null logger
- sharedRuntime.addProperty(
- RuntimeConstants.RUNTIME_LOG_LOGSYSTEM,
- new NullLogChute());
-
- sharedRuntime.addProperty(
- RuntimeConstants.RESOURCE_MANAGER_CLASS,
- SQLTemplateResourceManager.class.getName());
- sharedRuntime.addProperty("userdirective", BindDirective.class.getName());
- sharedRuntime.addProperty("userdirective", BindEqualDirective.class.getName());
- sharedRuntime.addProperty("userdirective", BindNotEqualDirective.class.getName());
- sharedRuntime.addProperty("userdirective", BindObjectEqualDirective.class
- .getName());
- sharedRuntime.addProperty("userdirective", BindObjectNotEqualDirective.class
- .getName());
- sharedRuntime.addProperty("userdirective", ResultDirective.class.getName());
- sharedRuntime.addProperty("userdirective", ChainDirective.class.getName());
- sharedRuntime.addProperty("userdirective", ChunkDirective.class.getName());
- try {
- sharedRuntime.init();
- }
- catch (Exception ex) {
- throw new CayenneRuntimeException(
- "Error setting up Velocity RuntimeInstance.",
- ex);
- }
- }
-
- SQLTemplateProcessor() {
- this.velocityRuntime = sharedRuntime;
- this.renderingUtils = sharedUtils;
- }
-
- SQLTemplateProcessor(RuntimeInstance velocityRuntime,
- SQLTemplateRenderingUtils renderingUtils) {
- this.velocityRuntime = velocityRuntime;
- this.renderingUtils = renderingUtils;
- }
-
- /**
- * Builds and returns a SQLStatement based on SQL template and a set of parameters.
- * During rendering, VelocityContext exposes the following as variables: all
- * parameters in the map, {@link SQLTemplateRenderingUtils} as a "helper" variable and
- * SQLStatement object as "statement" variable.
- */
- SQLStatement processTemplate(String template, Map<String, ?> parameters) throws Exception {
- // have to make a copy of parameter map since we are gonna modify it..
- Map<String, Object> internalParameters = (parameters != null && !parameters.isEmpty()) ? new HashMap<String, Object>(
- parameters) : new HashMap<String, Object>(5);
-
- List<ParameterBinding> bindings = new ArrayList<ParameterBinding>();
- List<ColumnDescriptor> results = new ArrayList<ColumnDescriptor>();
- internalParameters.put(BINDINGS_LIST_KEY, bindings);
- internalParameters.put(RESULT_COLUMNS_LIST_KEY, results);
- internalParameters.put(HELPER_KEY, renderingUtils);
-
- String sql = buildStatement(new VelocityContext(internalParameters), template);
-
- ParameterBinding[] bindingsArray = new ParameterBinding[bindings.size()];
- bindings.toArray(bindingsArray);
-
- ColumnDescriptor[] resultsArray = new ColumnDescriptor[results.size()];
- results.toArray(resultsArray);
-
- return new SQLStatement(sql, resultsArray, bindingsArray);
- }
-
- String buildStatement(VelocityContext context, String template)
- throws Exception {
- // Note: this method is a reworked version of
- // org.apache.velocity.app.Velocity.evaluate(..)
- // cleaned up to avoid using any Velocity singletons
-
- StringWriter out = new StringWriter(template.length());
- SimpleNode nodeTree = null;
-
- try {
- nodeTree = velocityRuntime.parse(new StringReader(template), template);
- }
- catch (ParseException pex) {
- throw new CayenneRuntimeException("Error parsing template '"
- + template
- + "' : "
- + pex.getMessage());
- }
-
- if (nodeTree == null) {
- throw new CayenneRuntimeException("Error parsing template " + template);
- }
-
- // ... not sure what InternalContextAdapter is for...
- InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
- ica.pushCurrentTemplateName(template);
-
- try {
- nodeTree.init(ica, velocityRuntime);
- nodeTree.render(ica, out);
- return out.toString();
- }
- finally {
- ica.popCurrentTemplateName();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateRenderingUtils.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateRenderingUtils.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateRenderingUtils.java
deleted file mode 100644
index 6350f56..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateRenderingUtils.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import org.apache.cayenne.exp.Expression;
-
-/**
- * Implements utility methods used inside Velocity templates
- * when rendering SQLTemplates.
- *
- * @since 1.1
- */
-public class SQLTemplateRenderingUtils {
- /**
- * Returns the result of evaluation of expression with object.
- */
- public Object cayenneExp(Object object, String expression) {
- return Expression.fromString(expression).evaluate(object);
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateResourceManager.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateResourceManager.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateResourceManager.java
deleted file mode 100644
index d339d71..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateResourceManager.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.util.Map;
-
-import org.apache.commons.collections.ExtendedProperties;
-import org.apache.commons.collections.map.LRUMap;
-import org.apache.velocity.Template;
-import org.apache.velocity.exception.ParseErrorException;
-import org.apache.velocity.exception.ResourceNotFoundException;
-import org.apache.velocity.runtime.RuntimeServices;
-import org.apache.velocity.runtime.resource.Resource;
-import org.apache.velocity.runtime.resource.ResourceManager;
-import org.apache.velocity.runtime.resource.loader.ResourceLoader;
-
-/**
- * An implementation of the Velocity ResourceManager and ResourceLoader that
- * creates templates from in-memory Strings.
- *
- * @since 1.1
- */
-// class must be public since it is instantiated by Velocity via reflection.
-public class SQLTemplateResourceManager
- extends ResourceLoader
- implements ResourceManager {
-
- protected Map<String, Template> templateCache;
-
- public void initialize(RuntimeServices rs) throws Exception {
- super.rsvc = rs;
- this.templateCache = new LRUMap(100);
- }
-
- public void clearCache() {
- templateCache.clear();
- }
-
- /**
- * Returns a Velocity Resource which is a Template for the given SQL.
- */
- public Resource getResource(String resourceName, int resourceType, String encoding)
- throws ResourceNotFoundException, ParseErrorException, Exception {
-
- synchronized (templateCache) {
- Template resource = templateCache.get(resourceName);
-
- if (resource == null) {
- resource = new Template();
- resource.setRuntimeServices(rsvc);
- resource.setResourceLoader(this);
- resource.setName(resourceName);
- resource.setEncoding(encoding);
- resource.process();
-
- templateCache.put(resourceName, resource);
- }
-
- return resource;
- }
- }
-
- public String getLoaderNameForResource(String resourceName) {
- return getClass().getName();
- }
-
- @Override
- public long getLastModified(Resource resource) {
- return -1;
- }
-
- @Override
- public InputStream getResourceStream(String source)
- throws ResourceNotFoundException {
- return new ByteArrayInputStream(source.getBytes());
- }
-
- @Override
- public void init(ExtendedProperties configuration) {
-
- }
-
- @Override
- public boolean isSourceModified(Resource resource) {
- return false;
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java
new file mode 100644
index 0000000..3ff81b7
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java
@@ -0,0 +1,176 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.cayenne.util.ConversionUtil;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * A custom Velocity directive to create a PreparedStatement parameter text. There are the
+ * following possible invocation formats inside the template:
+ *
+ * <pre>
+ * #bind(value) - e.g. #bind($xyz)
+ * #bind(value jdbc_type_name) - e.g. #bind($xyz 'VARCHAR'). This is the most common and useful form.
+ * #bind(value jdbc_type_name, scale) - e.g. #bind($xyz 'VARCHAR' 2)
+ * </pre>
+ * <p>
+ * Other examples:
+ * </p>
+ * <p>
+ * <strong>Binding literal parameter value:</strong>
+ * </p>
+ * <p>
+ * <code>"WHERE SOME_COLUMN > #bind($xyz)"</code> produces
+ * <code>"WHERE SOME_COLUMN > ?"</code> and also places the value of the "xyz" parameter
+ * in the context "bindings" collection.
+ * </p>
+ * <p>
+ * <strong>Binding ID column of a DataObject value:</strong>
+ * </p>
+ * <p>
+ * <code>"WHERE ID_COL1 = #bind($helper.cayenneExp($xyz, 'db:ID_COL2'))
+ * AND ID_COL2 = #bind($helper.cayenneExp($xyz, 'db:ID_COL2'))"</code> produces <code>"WHERE ID_COL1 = ? AND ID_COL2 = ?"</code> and also places the
+ * values of id columns of the DataObject parameter "xyz" in the context "bindings"
+ * collection.
+ * </p>
+ *
+ * @since 1.1
+ */
+public class BindDirective extends Directive {
+
+ @Override
+ public String getName() {
+ return "bind";
+ }
+
+ @Override
+ public int getType() {
+ return LINE;
+ }
+
+ /**
+ * Extracts the value of the object property to render and passes control to
+ * {@link #render(InternalContextAdapter, Writer, ParameterBinding)} to do the actual
+ * rendering.
+ */
+ @Override
+ public boolean render(InternalContextAdapter context, Writer writer, Node node)
+ throws IOException, ResourceNotFoundException, ParseErrorException,
+ MethodInvocationException {
+
+ Object value = getChild(context, node, 0);
+ Object type = getChild(context, node, 1);
+ int scale = ConversionUtil.toInt(getChild(context, node, 2), -1);
+ String typeString = type != null ? type.toString() : null;
+
+ if (value instanceof Collection) {
+ Iterator<?> it = ((Collection) value).iterator();
+ while (it.hasNext()) {
+ render(context, writer, node, it.next(), typeString, scale);
+
+ if (it.hasNext()) {
+ writer.write(',');
+ }
+ }
+ }
+ else {
+ render(context, writer, node, value, typeString, scale);
+ }
+
+ return true;
+ }
+
+ /**
+ * @since 3.0
+ */
+ protected void render(
+ InternalContextAdapter context,
+ Writer writer,
+ Node node,
+ Object value,
+ String typeString,
+ int scale) throws IOException, ParseErrorException {
+
+ int jdbcType = TypesMapping.NOT_DEFINED;
+ if (typeString != null) {
+ jdbcType = TypesMapping.getSqlTypeByName(typeString);
+ }
+ else if (value != null) {
+ jdbcType = TypesMapping.getSqlTypeByJava(value.getClass());
+ } else {
+ // value is null, set JDBC type to NULL
+ jdbcType = TypesMapping.getSqlTypeByName(TypesMapping.SQL_NULL);
+ }
+
+ if (jdbcType == TypesMapping.NOT_DEFINED) {
+ throw new ParseErrorException("Can't determine JDBC type of binding ("
+ + value
+ + ", "
+ + typeString
+ + ") at line "
+ + node.getLine()
+ + ", column "
+ + node.getColumn());
+ }
+
+ render(context, writer, new ParameterBinding(value, jdbcType, scale));
+ }
+
+ protected void render(
+ InternalContextAdapter context,
+ Writer writer,
+ ParameterBinding binding) throws IOException {
+
+ bind(context, binding);
+ writer.write('?');
+ }
+
+ protected Object getChild(InternalContextAdapter context, Node node, int i)
+ throws MethodInvocationException {
+ return (i >= 0 && i < node.jjtGetNumChildren()) ? node.jjtGetChild(i).value(
+ context) : null;
+ }
+
+ /**
+ * Adds value to the list of bindings in the context.
+ */
+ protected void bind(InternalContextAdapter context, ParameterBinding binding) {
+
+ Collection bindings = (Collection) context.getInternalUserContext().get(
+ SQLTemplateProcessor.BINDINGS_LIST_KEY);
+
+ if (bindings != null) {
+ bindings.add(binding);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindEqualDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindEqualDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindEqualDirective.java
new file mode 100644
index 0000000..b773cf5
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindEqualDirective.java
@@ -0,0 +1,57 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.velocity.context.InternalContextAdapter;
+
+/**
+ * A custom Velocity directive to create a PreparedStatement parameter text
+ * for "= ?". If null value is encountered, generated text will look like "IS NULL".
+ * Usage in Velocity template is "WHERE SOME_COLUMN #bindEqual($xyz)".
+ *
+ * @since 1.1
+ */
+public class BindEqualDirective extends BindDirective {
+
+ @Override
+ public String getName() {
+ return "bindEqual";
+ }
+
+ @Override
+ protected void render(
+ InternalContextAdapter context,
+ Writer writer,
+ ParameterBinding binding)
+ throws IOException {
+
+ if (binding.getValue() != null) {
+ bind(context, binding);
+ writer.write("= ?");
+ }
+ else {
+ writer.write("IS NULL");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindNotEqualDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindNotEqualDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindNotEqualDirective.java
new file mode 100644
index 0000000..a49a8d6
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindNotEqualDirective.java
@@ -0,0 +1,56 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.velocity.context.InternalContextAdapter;
+
+/**
+ * A custom Velocity directive to create a PreparedStatement parameter text for "<>?".
+ * If null value is encountered, generated text will look like "IS NOT NULL". Usage in
+ * Velocity template is "WHERE SOME_COLUMN #bindNotEqual($xyz)".
+ *
+ * @since 1.1
+ */
+public class BindNotEqualDirective extends BindDirective {
+
+ @Override
+ public String getName() {
+ return "bindNotEqual";
+ }
+
+ @Override
+ protected void render(
+ InternalContextAdapter context,
+ Writer writer,
+ ParameterBinding binding) throws IOException {
+
+ if (binding.getValue() != null) {
+ bind(context, binding);
+ writer.write("<> ?");
+ }
+ else {
+ writer.write("IS NOT NULL");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindObjectEqualDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindObjectEqualDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindObjectEqualDirective.java
new file mode 100644
index 0000000..ed1f7d0
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindObjectEqualDirective.java
@@ -0,0 +1,164 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.velocity;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.sql.Types;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.Persistent;
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.cayenne.dba.TypesMapping;
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * A custom Velocity directive to create a set of SQL conditions to match an ObjectId of
+ * an object. Usage in Velocity template is "WHERE #bindObjectEqual($object)" or "WHERE
+ * #bindObjectEqual($object $columns $idValues)".
+ *
+ * @since 3.0
+ */
+public class BindObjectEqualDirective extends BindDirective {
+
+ @Override
+ public String getName() {
+ return "bindObjectEqual";
+ }
+
+ @Override
+ public boolean render(InternalContextAdapter context, Writer writer, Node node)
+ throws IOException, ResourceNotFoundException, ParseErrorException,
+ MethodInvocationException {
+
+ Object object = getChild(context, node, 0);
+ Map idMap = toIdMap(object);
+
+ Object sqlColumns = getChild(context, node, 1);
+ Object idColumns = getChild(context, node, 2);
+
+ if (idMap == null) {
+ // assume null object, and bind all null values
+
+ if (sqlColumns == null || idColumns == null) {
+ throw new ParseErrorException("Invalid parameters. "
+ + "Either object has to be set "
+ + "or sqlColumns and idColumns or both.");
+ }
+
+ idMap = Collections.EMPTY_MAP;
+ }
+ else if (sqlColumns == null || idColumns == null) {
+ // infer SQL columns from ID columns
+ sqlColumns = idMap.keySet().toArray();
+ idColumns = sqlColumns;
+ }
+
+ Object[] sqlColumnsArray = toArray(sqlColumns);
+ Object[] idColumnsArray = toArray(idColumns);
+
+ if (sqlColumnsArray.length != idColumnsArray.length) {
+ throw new ParseErrorException(
+ "SQL columns and ID columns arrays have different sizes.");
+ }
+
+ for (int i = 0; i < sqlColumnsArray.length; i++) {
+
+ Object value = idMap.get(idColumnsArray[i]);
+
+ int jdbcType = (value != null) ? TypesMapping.getSqlTypeByJava(value
+ .getClass()) : Types.INTEGER;
+
+ renderColumn(context, writer, sqlColumnsArray[i], i);
+ writer.write(' ');
+ render(context, writer, new ParameterBinding(value, jdbcType, -1));
+ }
+
+ return true;
+ }
+
+ protected Object[] toArray(Object columns) {
+ if (columns instanceof Collection) {
+ return ((Collection) columns).toArray();
+ }
+ else if (columns.getClass().isArray()) {
+ return (Object[]) columns;
+ }
+ else {
+ return new Object[] {
+ columns
+ };
+ }
+ }
+
+ protected Map toIdMap(Object object) throws ParseErrorException {
+ if (object instanceof Persistent) {
+ return ((Persistent) object).getObjectId().getIdSnapshot();
+ }
+ else if (object instanceof ObjectId) {
+ return ((ObjectId) object).getIdSnapshot();
+ }
+ else if(object instanceof Map) {
+ return (Map) object;
+ }
+ else if (object != null) {
+ throw new ParseErrorException(
+ "Invalid object parameter, expected Persistent or ObjectId or null: "
+ + object);
+ }
+ else {
+ return null;
+ }
+ }
+
+ protected void renderColumn(
+ InternalContextAdapter context,
+ Writer writer,
+ Object columnName,
+ int columnIndex) throws IOException {
+
+ if (columnIndex > 0) {
+ writer.write(" AND ");
+ }
+
+ writer.write(columnName.toString());
+ }
+
+ @Override
+ protected void render(
+ InternalContextAdapter context,
+ Writer writer,
+ ParameterBinding binding) throws IOException {
+
+ if (binding.getValue() != null) {
+ bind(context, binding);
+ writer.write("= ?");
+ }
+ else {
+ writer.write("IS NULL");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindObjectNotEqualDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindObjectNotEqualDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindObjectNotEqualDirective.java
new file mode 100644
index 0000000..0b610ab
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindObjectNotEqualDirective.java
@@ -0,0 +1,70 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.velocity;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.velocity.context.InternalContextAdapter;
+
+/**
+ * A custom Velocity directive to create a set of SQL conditions to check unequality of an
+ * ObjectId of an object. Usage in Velocity template is "WHERE
+ * #bindObjectNotEqual($object)" or "WHERE #bindObjectNotEqual($object $columns
+ * $idValues)".
+ *
+ * @since 3.0
+ */
+public class BindObjectNotEqualDirective extends BindObjectEqualDirective {
+
+ @Override
+ public String getName() {
+ return "bindObjectNotEqual";
+ }
+
+ @Override
+ protected void renderColumn(
+ InternalContextAdapter context,
+ Writer writer,
+ Object columnName,
+ int columnIndex) throws IOException {
+
+ if (columnIndex > 0) {
+ writer.write(" OR ");
+ }
+
+ writer.write(columnName.toString());
+ }
+
+ @Override
+ protected void render(
+ InternalContextAdapter context,
+ Writer writer,
+ ParameterBinding binding) throws IOException {
+
+ if (binding.getValue() != null) {
+ bind(context, binding);
+ writer.write("<> ?");
+ }
+ else {
+ writer.write("IS NOT NULL");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/ChainDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/ChainDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/ChainDirective.java
new file mode 100644
index 0000000..b0be445
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/ChainDirective.java
@@ -0,0 +1,112 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.ASTDirective;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * A custom Velocity directive to conditionally join a number of {@link ChunkDirective chunks}.
+ * Usage of chain is the following:
+ *
+ * <pre>
+ * #chain(operator) - e.g. #chain(' AND ')
+ * #chain(operator prefix) - e.g. #chain(' AND ' 'WHERE ')</pre>
+ *
+ * <p><code>operator</code> (e.g. AND, OR, etc.) is used to join chunks that are included
+ * in a chain. <code>prefix</code> is inserted if a chain contains at least one chunk.
+ * </p>
+ *
+ * @since 1.1
+ */
+public class ChainDirective extends Directive {
+
+ @Override
+ public String getName() {
+ return "chain";
+ }
+
+ @Override
+ public int getType() {
+ return BLOCK;
+ }
+
+ @Override
+ public boolean render(InternalContextAdapter context, Writer writer, Node node)
+ throws
+ IOException,
+ ResourceNotFoundException,
+ ParseErrorException,
+ MethodInvocationException {
+
+ int size = node.jjtGetNumChildren();
+ if (size == 0) {
+ return true;
+ }
+
+ // BLOCK is the last child
+ Node block = node.jjtGetChild(node.jjtGetNumChildren() - 1);
+ String join = (size > 1) ? (String) node.jjtGetChild(0).value(context) : "";
+ String prefix = (size > 2) ? (String) node.jjtGetChild(1).value(context) : "";
+
+ // if there is a conditional prefix, use a separate buffer ofr children
+ StringWriter childWriter = new StringWriter(30);
+
+ int len = block.jjtGetNumChildren();
+ int includedChunks = 0;
+ for (int i = 0; i < len; i++) {
+ Node child = block.jjtGetChild(i);
+
+ // if this is a "chunk", evaluate its expression and prepend join if included...
+ if (child instanceof ASTDirective
+ && "chunk".equals(((ASTDirective) child).getDirectiveName())) {
+
+ if (child.jjtGetNumChildren() < 2
+ || child.jjtGetChild(0).value(context) != null) {
+
+ if (includedChunks > 0) {
+ childWriter.write(join);
+ }
+
+ includedChunks++;
+ }
+ }
+
+ child.render(context, childWriter);
+ }
+
+ if (includedChunks > 0) {
+ childWriter.flush();
+ writer.write(prefix);
+ writer.write(childWriter.toString());
+ }
+
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/ChunkDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/ChunkDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/ChunkDirective.java
new file mode 100644
index 0000000..5ff0a5e
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/ChunkDirective.java
@@ -0,0 +1,75 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+
+/**
+ * A custom Velocity directive to describe a conditional chunk of a {@link ChainDirective chain}.
+ * Usage of chunk is the following:
+ *
+ * <pre>
+ * #chunk()...#end - e.g. #chunk()A = 5#end
+ * #chunk($paramKey)...#end - e.g. #chunk($a)A = $a#end
+ * </pre>
+ * <p>
+ * If context contains paramKey and it's value isn't null, chunk is included in the
+ * chain, and if it is not the first chunk, it is prefixed with chain join (OR/AND).
+ * If context doesn't contain paramKey or it's value is null, chunk is skipped.
+ * @since 1.1
+ */
+public class ChunkDirective extends Directive {
+
+ @Override
+ public String getName() {
+ return "chunk";
+ }
+
+ @Override
+ public int getType() {
+ return BLOCK;
+ }
+
+ @Override
+ public boolean render(InternalContextAdapter context, Writer writer, Node node)
+ throws IOException, ResourceNotFoundException, ParseErrorException,
+ MethodInvocationException {
+
+ // first child is an expression, second is BLOCK
+ if (node.jjtGetNumChildren() > 1 && node.jjtGetChild(0).value(context) == null) {
+ // skip this chunk
+ return false;
+ }
+
+ // BLOCK is the last child
+ Node block = node.jjtGetChild(node.jjtGetNumChildren() - 1);
+ block.render(context, writer);
+ return true;
+ }
+
+}
[6/6] git commit: CAY-1966 SQLTemplate/SQLSelect positional parameter
binding
Posted by aa...@apache.org.
CAY-1966 SQLTemplate/SQLSelect positional parameter binding
* utest cleanup
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/617628c7
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/617628c7
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/617628c7
Branch: refs/heads/master
Commit: 617628c7f50c544718f9b3d8e66cdd3ad408a38a
Parents: 5aedf54
Author: aadamchik <aa...@apache.org>
Authored: Sun Nov 2 15:49:38 2014 +0300
Committer: aadamchik <aa...@apache.org>
Committed: Sun Nov 2 18:33:45 2014 +0300
----------------------------------------------------------------------
.../access/dbsync/SchemaUpdateStrategyBase.java | 129 +++++++
.../access/dbsync/SchemaUpdateStrategyIT.java | 335 ++-----------------
...hrowOnPartialOrCreateSchemaStrategyTest.java | 78 +++++
.../ThrowOnPartialSchemaStrategyTest.java | 85 +++++
.../cayenne/unit/di/server/ServerCase.java | 51 +--
.../di/server/ServerCaseDataSourceFactory.java | 2 -
.../src/test/resources/cayenne-default.xml | 1 -
.../src/test/resources/cayenne-sus.xml | 4 +
8 files changed, 349 insertions(+), 336 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/617628c7/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyBase.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyBase.java b/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyBase.java
new file mode 100644
index 0000000..3022457
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyBase.java
@@ -0,0 +1,129 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.access.dbsync;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.unit.di.server.ServerCase;
+
+public class SchemaUpdateStrategyBase extends ServerCase {
+
+ @Inject
+ protected ObjectContext context;
+
+ @Inject
+ protected DataNode node;
+
+ @Inject
+ protected DbAdapter adapter;
+
+ @Override
+ protected void setUpAfterInjection() throws Exception {
+
+ DataMap map = node.getEntityResolver().getDataMap("sus-map");
+ for (String name : existingTables()) {
+
+ for (String drop : adapter.dropTableStatements(map.getDbEntity(name))) {
+ context.performGenericQuery(new SQLTemplate(Object.class, drop));
+ }
+ }
+ }
+
+ protected void setStrategy(Class<? extends SchemaUpdateStrategy> type) throws Exception {
+ node.setSchemaUpdateStrategyName(type.getName());
+ node.setSchemaUpdateStrategy(type.newInstance());
+ }
+
+ protected Collection<String> existingTables() {
+ Collection<String> present = new ArrayList<String>();
+ for (Entry<String, Boolean> e : tablesMap().entrySet()) {
+ if (e.getValue()) {
+ present.add(e.getKey());
+ }
+ }
+
+ return present;
+ }
+
+ protected void createOneTable(String entityName) {
+ DataMap map = node.getEntityResolver().getDataMap("sus-map");
+ String createTable = adapter.createTable(map.getDbEntity(entityName));
+ context.performGenericQuery(new SQLTemplate(Object.class, createTable));
+ }
+
+ protected Map<String, Boolean> tablesMap() {
+ DataMap map = node.getEntityResolver().getDataMap("sus-map");
+ Map<String, String> tables = new HashMap<String, String>();
+
+ // add upper/lower case permutations
+ for (String name : map.getDbEntityMap().keySet()) {
+ tables.put(name.toLowerCase(), name);
+ tables.put(name.toUpperCase(), name);
+ }
+
+ Map<String, Boolean> presentInDB = new HashMap<String, Boolean>();
+ for (String name : map.getDbEntityMap().keySet()) {
+ presentInDB.put(name, false);
+ }
+
+ String tableLabel = node.getAdapter().tableTypeForTable();
+ Connection con = null;
+ try {
+ con = node.getDataSource().getConnection();
+ ResultSet rs = con.getMetaData().getTables(null, null, "%", new String[] { tableLabel });
+ while (rs.next()) {
+ String dbName = rs.getString("TABLE_NAME");
+
+ String name = tables.get(dbName);
+
+ if (name != null) {
+ presentInDB.put(name, true);
+ }
+ }
+ rs.close();
+ } catch (SQLException e) {
+ throw new CayenneRuntimeException(e);
+ } finally {
+ try {
+ if (con != null) {
+ con.close();
+ }
+ } catch (SQLException e) {
+ throw new CayenneRuntimeException(e);
+ }
+ }
+
+ return presentInDB;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/617628c7/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyIT.java
index fd8b118..682d187 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/SchemaUpdateStrategyIT.java
@@ -18,329 +18,46 @@
****************************************************************/
package org.apache.cayenne.access.dbsync;
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.access.DataNode;
+import java.util.Collections;
+import java.util.Map;
+
import org.apache.cayenne.access.MockOperationObserver;
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.access.OperationObserver;
import org.apache.cayenne.query.Query;
import org.apache.cayenne.query.SQLTemplate;
import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-@UseServerRuntime(ServerCase.DEFAULT_PROJECT)
-public class SchemaUpdateStrategyIT extends ServerCase {
-
- @Inject
- private DataNode node;
-
- @Inject
- private DbAdapter adapter;
-
- @Inject
- private ServerCaseDataSourceFactory dataSourceFactory;
-
- @Inject
- private JdbcEventLogger jdbcEventLogger;
-
- public void testDBGeneratorStrategy() throws Exception {
-
- String template = "SELECT #result('id' 'int') FROM SUS1";
- SQLTemplate query = new SQLTemplate(Object.class, template);
-
- DataMap map = node.getEntityResolver().getDataMap("sus-map");
- DataNode dataNode = createDataNode(map);
- int sizeDB = getNameTablesInDB(dataNode).size();
- MockOperationObserver observer = new MockOperationObserver();
- try {
-
- generateDBWithDBGeneratorStrategy(dataNode, query, observer);
- int sizeDB2 = getNameTablesInDB(dataNode).size();
- assertEquals(2, sizeDB2 - sizeDB);
- dataNode.performQueries(Collections.singletonList((Query) query), observer);
- int sizeDB3 = getNameTablesInDB(dataNode).size();
- assertEquals(sizeDB2, sizeDB3);
- }
- finally {
- DataNode dataNode2 = createDataNode(map);
- dataNode2.setSchemaUpdateStrategy((SchemaUpdateStrategy) Class.forName(
- dataNode2.getSchemaUpdateStrategyName()).newInstance());
- dropTables(map, dataNode2, observer);
- }
- assertEquals(getNameTablesInDB(dataNode).size(), sizeDB);
- }
-
- public void testThrowOnPartialStrategyTableNoExist() throws Exception {
-
- String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
- SQLTemplate query = new SQLTemplate(Object.class, template);
- DataMap map = node.getEntityResolver().getDataMap("sus-map");
- MockOperationObserver observer = new MockOperationObserver();
- DataNode dataNode = createDataNode(map);
-
- setStrategy(ThrowOnPartialSchemaStrategy.class.getName(), dataNode);
-
- try {
- dataNode.performQueries(Collections.singletonList((Query) query), observer);
- }
- catch (CayenneRuntimeException e) {
- assertNotNull(e);
- }
-
- try {
- dataNode.performQueries(Collections.singletonList((Query) query), observer);
- }
- catch (CayenneRuntimeException e) {
- assertNotNull(e);
- }
- }
-
- public void testThrowOnPartialStrategyTableExist() throws Exception {
- tableExistfForThrowOnPartialAndMixStrategy(ThrowOnPartialSchemaStrategy.class
- .getName());
- }
-
- public void testThrowOnPartialStrategyWithOneTable() throws Exception {
- withOneTableForThrowOnPartialAndMixStrategy(ThrowOnPartialSchemaStrategy.class
- .getName());
- }
-
- public void testMixedStrategyTableNoExist() throws Exception {
-
- String template = "SELECT #result('id' 'int') FROM SUS1";
- SQLTemplate query = new SQLTemplate(Object.class, template);
- DataMap map = node.getEntityResolver().getDataMap("sus-map");
- DataNode dataNode = createDataNode(map);
- int sizeDB = getNameTablesInDB(dataNode).size();
- MockOperationObserver observer = new MockOperationObserver();
-
- setStrategy(ThrowOnPartialOrCreateSchemaStrategy.class.getName(), dataNode);
-
- try {
- dataNode.performQueries(Collections.singletonList((Query) query), observer);
- Map<String, Boolean> nameTables = getNameTablesInDB(dataNode);
- assertTrue(nameTables.get("sus1") != null || nameTables.get("SUS1") != null);
- int sizeDB2 = getNameTablesInDB(dataNode).size();
- assertEquals(2, sizeDB2 - sizeDB);
- dataNode.performQueries(Collections.singletonList((Query) query), observer);
- int sizeDB3 = getNameTablesInDB(dataNode).size();
- assertEquals(sizeDB2, sizeDB3);
- }
- finally {
- DataNode dataNode2 = createDataNode(map);
- dataNode2.setSchemaUpdateStrategy((SchemaUpdateStrategy) Class.forName(
- dataNode2.getSchemaUpdateStrategyName()).newInstance());
- dropTables(map, dataNode2, observer);
- }
- assertEquals(getNameTablesInDB(dataNode).size(), sizeDB);
-
- }
-
- public void testMixedStrategyTableExist() throws Exception {
- tableExistfForThrowOnPartialAndMixStrategy(ThrowOnPartialOrCreateSchemaStrategy.class
- .getName());
- }
-
- public void testMixedStrategyWithOneTable() throws Exception {
- withOneTableForThrowOnPartialAndMixStrategy(ThrowOnPartialOrCreateSchemaStrategy.class
- .getName());
- };
-
- public void testNoStandartSchema() {
- String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
- SQLTemplate query = new SQLTemplate(Object.class, template);
- MockOperationObserver observer = new MockOperationObserver();
- DataMap map = node.getEntityResolver().getDataMap("sus-map");
- DataNode dataNode = createDataNode(map);
-
- setStrategy(TstSchemaUpdateStrategy.class.getName(), dataNode);
-
- dataNode.performQueries(Collections.singletonList((Query) query), observer);
- assertTrue(dataNode.getSchemaUpdateStrategy() instanceof TstSchemaUpdateStrategy);
- }
-
- private void withOneTableForThrowOnPartialAndMixStrategy(String strategy) {
- DbEntity entity = null;
- String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
- SQLTemplate query = new SQLTemplate(Object.class, template);
- DataMap map = node.getEntityResolver().getDataMap("sus-map");
- MockOperationObserver observer = new MockOperationObserver();
- DataNode dataNode = createDataNode(map);
-
- DataNode dataNode2 = createDataNode(map);
-
- try {
-
- int sizeDB = getNameTablesInDB(dataNode).size();
- entity = createOneTable(dataNode);
- int sizeDB2 = getNameTablesInDB(dataNode).size();
- assertEquals(1, sizeDB2 - sizeDB);
- setStrategy(strategy, dataNode2);
- dataNode2.performQueries(Collections.singletonList((Query) query), observer);
-
- }
- catch (CayenneRuntimeException e) {
- assertNotNull(e);
- }
- try {
- dataNode2.performQueries(Collections.singletonList((Query) query), observer);
- }
- catch (CayenneRuntimeException e) {
- assertNotNull(e);
- }
- finally {
-
- if (entity != null) {
-
- Collection<String> template2 = dataNode.getAdapter().dropTableStatements(
- entity);
- Iterator<String> it = template2.iterator();
- List<Query> list = new ArrayList<Query>();
- while (it.hasNext()) {
- SQLTemplate q = new SQLTemplate(Object.class, it.next());
- list.add(q);
- }
- dataNode.performQueries(list, observer);
- }
- }
- }
-
- private void tableExistfForThrowOnPartialAndMixStrategy(String strategy)
- throws Exception {
-
- String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
- SQLTemplate query = new SQLTemplate(Object.class, template);
- DataMap map = node.getEntityResolver().getDataMap("sus-map");
- MockOperationObserver observer = new MockOperationObserver();
- DataNode dataNode = createDataNode(map);
- int sizeDB = getNameTablesInDB(dataNode).size();
- generateDBWithDBGeneratorStrategy(dataNode, query, observer);
- int sizeDB2 = getNameTablesInDB(dataNode).size();
- assertEquals(2, sizeDB2 - sizeDB);
- try {
- DataNode dataNode2 = createDataNode(map);
- setStrategy(strategy, dataNode2);
- dataNode2.performQueries(Collections.singletonList((Query) query), observer);
- }
- finally {
- dropTables(map, dataNode, observer);
- }
-
- }
-
- private DbEntity createOneTable(DataNode dataNode) {
- DataMap map = node.getEntityResolver().getDataMap("sus-map");
- Collection<DbEntity> ent = map.getDbEntities();
- DbEntity entity = ent.iterator().next();
- String template = dataNode.getAdapter().createTable(entity);
-
- SQLTemplate query = new SQLTemplate(Object.class, template);
- MockOperationObserver observer = new MockOperationObserver();
+@UseServerRuntime(ServerCase.SUS_PROJECT)
+public class SchemaUpdateStrategyIT extends SchemaUpdateStrategyBase {
- setStrategy(null, dataNode);
+ public void testCreateIfNoSchemaStrategy() throws Exception {
- dataNode.performQueries(Collections.singletonList((Query) query), observer);
- return entity;
- }
+ setStrategy(CreateIfNoSchemaStrategy.class);
- private DataNode createDataNode(DataMap map) {
- Collection<DataMap> colection = new ArrayList<DataMap>();
- colection.add(map);
- DataNode dataNode = new DataNode();
- dataNode.setJdbcEventLogger(jdbcEventLogger);
- dataNode.setDataMaps(colection);
- dataNode.setAdapter(adapter);
- dataNode.setDataSource(dataSourceFactory.getSharedDataSource());
- dataNode.setDataSourceFactory(node.getDataSourceFactory());
- dataNode.setSchemaUpdateStrategyName(node.getSchemaUpdateStrategyName());
- dataNode.setRowReaderFactory(node.getRowReaderFactory());
- dataNode.setBatchTranslatorFactory(node.getBatchTranslatorFactory());
- dataNode.setEntityResolver(new EntityResolver(colection));
- return dataNode;
- }
+ String template = "SELECT #result('id' 'int') FROM SUS1";
+ SQLTemplate query = new SQLTemplate(Object.class, template);
- private void generateDBWithDBGeneratorStrategy(
- DataNode dataNode,
- SQLTemplate query,
- MockOperationObserver observer) {
+ OperationObserver observer = new MockOperationObserver();
- setStrategy(CreateIfNoSchemaStrategy.class.getName(), dataNode);
+ node.performQueries(Collections.singletonList((Query) query), observer);
+ Map<String, Boolean> nameTables = tablesMap();
+ assertTrue(nameTables.get("SUS1"));
- dataNode.performQueries(Collections.singletonList((Query) query), observer);
- Map<String, Boolean> nameTables = getNameTablesInDB(dataNode);
- assertTrue(nameTables.get("sus1") != null || nameTables.get("SUS1") != null);
+ assertEquals(2, existingTables().size());
+ node.performQueries(Collections.singletonList(query), observer);
+ assertEquals(2, existingTables().size());
+ }
- }
+ public void testNoStandardSchema() throws Exception {
+ String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
+ SQLTemplate query = new SQLTemplate(Object.class, template);
+ MockOperationObserver observer = new MockOperationObserver();
- private void setStrategy(String name, DataNode dataNode) {
- dataNode.setSchemaUpdateStrategyName(name);
- try {
- dataNode.setSchemaUpdateStrategy((SchemaUpdateStrategy) Class.forName(
- dataNode.getSchemaUpdateStrategyName()).newInstance());
- }
- catch (Exception e) {
- throw new CayenneRuntimeException(e);
- }
- }
+ setStrategy(TstSchemaUpdateStrategy.class);
- private void dropTables(DataMap map, DataNode dataNode, MockOperationObserver observer) {
- Collection<DbEntity> ent = map.getDbEntities();
- Iterator<DbEntity> iterator = ent.iterator();
- while (iterator.hasNext()) {
- Collection<String> collectionDrop = dataNode
- .getAdapter()
- .dropTableStatements(iterator.next());
- for (String s : collectionDrop) {
- SQLTemplate queryDrop = new SQLTemplate(Object.class, s);
- dataNode.performQueries(
- Collections.singletonList((Query) queryDrop),
- observer);
- }
- }
- }
+ node.performQueries(Collections.singletonList((Query) query), observer);
+ assertTrue(node.getSchemaUpdateStrategy() instanceof TstSchemaUpdateStrategy);
+ }
- private Map<String, Boolean> getNameTablesInDB(DataNode dataNode) {
- String tableLabel = dataNode.getAdapter().tableTypeForTable();
- Connection con = null;
- Map<String, Boolean> nameTables = new HashMap<String, Boolean>();
- try {
- con = dataNode.getDataSource().getConnection();
- ResultSet rs = con.getMetaData().getTables(null, null, "%", new String[] {
- tableLabel
- });
- while (rs.next()) {
- String name = rs.getString("TABLE_NAME");
- nameTables.put(name, false);
- }
- rs.close();
- }
- catch (SQLException e) {
- throw new CayenneRuntimeException(e);
- }
- finally {
- try {
- con.close();
- }
- catch (SQLException e) {
- throw new CayenneRuntimeException(e);
- }
- }
- return nameTables;
- }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/617628c7/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/ThrowOnPartialOrCreateSchemaStrategyTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/ThrowOnPartialOrCreateSchemaStrategyTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/ThrowOnPartialOrCreateSchemaStrategyTest.java
new file mode 100644
index 0000000..138f131
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/ThrowOnPartialOrCreateSchemaStrategyTest.java
@@ -0,0 +1,78 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.access.dbsync;
+
+import static org.mockito.Mockito.mock;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.access.OperationObserver;
+import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+@UseServerRuntime(ServerCase.SUS_PROJECT)
+public class ThrowOnPartialOrCreateSchemaStrategyTest extends SchemaUpdateStrategyBase {
+
+ public void testMixedStrategyTableExist() throws Exception {
+
+ createOneTable("SUS1");
+ createOneTable("SUS2");
+
+ String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
+ SQLTemplate query = new SQLTemplate(Object.class, template);
+
+ setStrategy(ThrowOnPartialOrCreateSchemaStrategy.class);
+ node.performQueries(Collections.singletonList(query), mock(OperationObserver.class));
+ }
+
+ public void testMixedStrategyTableNoExist() throws Exception {
+
+ String template = "SELECT #result('id' 'int') FROM SUS1";
+ SQLTemplate query = new SQLTemplate(Object.class, template);
+
+ setStrategy(ThrowOnPartialOrCreateSchemaStrategy.class);
+
+ node.performQueries(Collections.singletonList(query), mock(OperationObserver.class));
+ Map<String, Boolean> nameTables = tablesMap();
+ assertTrue(nameTables.get("SUS1"));
+ assertEquals(2, existingTables().size());
+
+ node.performQueries(Collections.singletonList(query), mock(OperationObserver.class));
+ assertEquals(2, existingTables().size());
+ }
+
+ public void testMixedStrategyWithOneTable() throws Exception {
+ createOneTable("SUS1");
+ setStrategy(ThrowOnPartialOrCreateSchemaStrategy.class);
+
+ String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
+ SQLTemplate query = new SQLTemplate(Object.class, template);
+
+ try {
+ node.performQueries(Collections.singletonList(query), mock(OperationObserver.class));
+ assertEquals(1, existingTables().size());
+ fail("Must have thrown on partial schema");
+ } catch (CayenneRuntimeException e) {
+ // expected
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/617628c7/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/ThrowOnPartialSchemaStrategyTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/ThrowOnPartialSchemaStrategyTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/ThrowOnPartialSchemaStrategyTest.java
new file mode 100644
index 0000000..383996a
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/dbsync/ThrowOnPartialSchemaStrategyTest.java
@@ -0,0 +1,85 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.access.dbsync;
+
+import java.util.Collections;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.access.MockOperationObserver;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+@UseServerRuntime(ServerCase.SUS_PROJECT)
+public class ThrowOnPartialSchemaStrategyTest extends SchemaUpdateStrategyBase {
+
+ public void testThrowOnPartialStrategyTableNoExist() throws Exception {
+
+ String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
+ SQLTemplate query = new SQLTemplate(Object.class, template);
+ MockOperationObserver observer = new MockOperationObserver();
+
+ setStrategy(ThrowOnPartialSchemaStrategy.class);
+
+ try {
+ node.performQueries(Collections.singletonList((Query) query), observer);
+ } catch (CayenneRuntimeException e) {
+ assertNotNull(e);
+ }
+
+ try {
+ node.performQueries(Collections.singletonList((Query) query), observer);
+ } catch (CayenneRuntimeException e) {
+ assertNotNull(e);
+ }
+ }
+
+ public void testThrowOnPartialStrategyTableExist() throws Exception {
+
+ String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
+ SQLTemplate query = new SQLTemplate(Object.class, template);
+ MockOperationObserver observer = new MockOperationObserver();
+
+ createOneTable("SUS1");
+ createOneTable("SUS2");
+
+ setStrategy(ThrowOnPartialSchemaStrategy.class);
+ node.performQueries(Collections.singletonList(query), observer);
+ }
+
+ public void testThrowOnPartialStrategyWithOneTable() throws Exception {
+ createOneTable("SUS1");
+
+ setStrategy(ThrowOnPartialSchemaStrategy.class);
+
+ String template = "SELECT #result('ARTIST_ID' 'int') FROM ARTIST ORDER BY ARTIST_ID";
+ SQLTemplate query = new SQLTemplate(Object.class, template);
+ MockOperationObserver observer = new MockOperationObserver();
+
+ try {
+ node.performQueries(Collections.singletonList(query), observer);
+ assertEquals(1, existingTables().size());
+ fail("Must have thrown on partial schema");
+ } catch (CayenneRuntimeException e) {
+ // expected
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/617628c7/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java
index 0240cec..854f7cc 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCase.java
@@ -25,31 +25,34 @@ import org.apache.cayenne.unit.di.DICase;
public class ServerCase extends DICase {
- // known runtimes... unit tests may reuse these with @UseServerRuntime annotation or
- // can define their own on the fly (TODO: how would that work with the global schema
- // setup?)
- public static final String INHERTITANCE_SINGLE_TABLE1_PROJECT = "cayenne-inheritance-single-table1.xml";
- public static final String INHERTITANCE_VERTICAL_PROJECT = "cayenne-inheritance-vertical.xml";
- public static final String LOCKING_PROJECT = "cayenne-locking.xml";
- public static final String QUOTED_IDENTIFIERS_PROJECT = "cayenne-quoted-identifiers.xml";
- public static final String PEOPLE_PROJECT = "cayenne-people.xml";
- public static final String RELATIONSHIPS_PROJECT = "cayenne-relationships.xml";
- public static final String TESTMAP_PROJECT = "cayenne-testmap.xml";
- public static final String DEFAULT_PROJECT = "cayenne-default.xml";
- public static final String MULTINODE_PROJECT = "cayenne-multinode.xml";
- public static final String ONEWAY_PROJECT = "cayenne-oneway-rels.xml";
- public static final String MULTI_TIER_PROJECT = "cayenne-multi-tier.xml";
+ // known runtimes... unit tests may reuse these with @UseServerRuntime
+ // annotation or
+ // can define their own on the fly (TODO: how would that work with the
+ // global schema
+ // setup?)
+ public static final String INHERTITANCE_SINGLE_TABLE1_PROJECT = "cayenne-inheritance-single-table1.xml";
+ public static final String INHERTITANCE_VERTICAL_PROJECT = "cayenne-inheritance-vertical.xml";
+ public static final String LOCKING_PROJECT = "cayenne-locking.xml";
+ public static final String QUOTED_IDENTIFIERS_PROJECT = "cayenne-quoted-identifiers.xml";
+ public static final String PEOPLE_PROJECT = "cayenne-people.xml";
+ public static final String RELATIONSHIPS_PROJECT = "cayenne-relationships.xml";
+ public static final String TESTMAP_PROJECT = "cayenne-testmap.xml";
+ public static final String DEFAULT_PROJECT = "cayenne-default.xml";
+ public static final String MULTINODE_PROJECT = "cayenne-multinode.xml";
+ public static final String ONEWAY_PROJECT = "cayenne-oneway-rels.xml";
+ public static final String MULTI_TIER_PROJECT = "cayenne-multi-tier.xml";
+ public static final String SUS_PROJECT = "cayenne-sus.xml";
- private static final Injector injector;
+ private static final Injector injector;
- static {
- DefaultScope testScope = new DefaultScope();
- injector = DIBootstrap.createInjector(new ServerCaseModule(testScope));
- injector.getInstance(SchemaBuilder.class).rebuildSchema();
- }
+ static {
+ DefaultScope testScope = new DefaultScope();
+ injector = DIBootstrap.createInjector(new ServerCaseModule(testScope));
+ injector.getInstance(SchemaBuilder.class).rebuildSchema();
+ }
- @Override
- protected Injector getUnitTestInjector() {
- return injector;
- }
+ @Override
+ protected Injector getUnitTestInjector() {
+ return injector;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/617628c7/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java
index 203d06d..6859f2f 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java
@@ -27,8 +27,6 @@ import java.util.Set;
import javax.sql.DataSource;
-import org.apache.cayenne.configuration.DataNodeDescriptor;
-import org.apache.cayenne.configuration.server.DataSourceFactory;
import org.apache.cayenne.conn.DataSourceInfo;
import org.apache.cayenne.conn.PoolDataSource;
import org.apache.cayenne.conn.PoolManager;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/617628c7/cayenne-server/src/test/resources/cayenne-default.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/cayenne-default.xml b/cayenne-server/src/test/resources/cayenne-default.xml
index 8ef6d91..a248a10 100644
--- a/cayenne-server/src/test/resources/cayenne-default.xml
+++ b/cayenne-server/src/test/resources/cayenne-default.xml
@@ -3,5 +3,4 @@
<map name="embeddable"/>
<map name="generic"/>
<map name="qualified"/>
- <map name="sus-map"/>
</domain>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/617628c7/cayenne-server/src/test/resources/cayenne-sus.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/cayenne-sus.xml b/cayenne-server/src/test/resources/cayenne-sus.xml
new file mode 100644
index 0000000..ff93d6c
--- /dev/null
+++ b/cayenne-server/src/test/resources/cayenne-sus.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domain project-version="7">
+ <map name="sus-map"/>
+</domain>
[2/6] CAY-1966 SQLTemplate/SQLSelect positional parameter binding
Posted by aa...@apache.org.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java
new file mode 100644
index 0000000..8a3a5e4
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java
@@ -0,0 +1,206 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.velocity.context.InternalContextAdapter;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.directive.Directive;
+import org.apache.velocity.runtime.parser.node.Node;
+import org.apache.cayenne.access.jdbc.ColumnDescriptor;
+import org.apache.cayenne.util.Util;
+
+/**
+ * A custom Velocity directive to describe a ResultSet column. There are the following
+ * possible invocation formats inside the template:
+ *
+ * <pre>
+ * #result(column_name) - e.g. #result('ARTIST_ID')
+ * #result(column_name java_type) - e.g. #result('ARTIST_ID' 'String')
+ * #result(column_name java_type column_alias) - e.g. #result('ARTIST_ID' 'String' 'ID')
+ * #result(column_name java_type column_alias data_row_key) - e.g. #result('ARTIST_ID' 'String' 'ID' 'toArtist.ID')
+ * </pre>
+ *
+ * <p>
+ * 'data_row_key' is needed if SQL 'column_alias' is not appropriate as a DataRow key on
+ * the Cayenne side. One common case when this happens is when a DataRow retrieved from a
+ * query is mapped using joint prefetch keys. In this case DataRow must use DB_PATH
+ * expressions for joint column keys, and their format is incompatible with most databases
+ * alias format.
+ * </p>
+ * <p>
+ * Most common Java types used in JDBC can be specified without a package. This includes
+ * all numeric types, primitives, String, SQL dates, BigDecimal and BigInteger.
+ * </p>
+ *
+ * @since 1.1
+ */
+public class ResultDirective extends Directive {
+
+ private static final Map<String, String> typesGuess;
+
+ static {
+ // init default types
+ typesGuess = new HashMap<String, String>();
+
+ // primitives
+ typesGuess.put("long", Long.class.getName());
+ typesGuess.put("double", Double.class.getName());
+ typesGuess.put("byte", Byte.class.getName());
+ typesGuess.put("boolean", Boolean.class.getName());
+ typesGuess.put("float", Float.class.getName());
+ typesGuess.put("short", Short.class.getName());
+ typesGuess.put("int", Integer.class.getName());
+
+ // numeric
+ typesGuess.put("Long", Long.class.getName());
+ typesGuess.put("Double", Double.class.getName());
+ typesGuess.put("Byte", Byte.class.getName());
+ typesGuess.put("Boolean", Boolean.class.getName());
+ typesGuess.put("Float", Float.class.getName());
+ typesGuess.put("Short", Short.class.getName());
+ typesGuess.put("Integer", Integer.class.getName());
+
+ // other
+ typesGuess.put("String", String.class.getName());
+ typesGuess.put("Date", Date.class.getName());
+ typesGuess.put("Time", Time.class.getName());
+ typesGuess.put("Timestamp", Timestamp.class.getName());
+ typesGuess.put("BigDecimal", BigDecimal.class.getName());
+ typesGuess.put("BigInteger", BigInteger.class.getName());
+ }
+
+ @Override
+ public String getName() {
+ return "result";
+ }
+
+ @Override
+ public int getType() {
+ return LINE;
+ }
+
+ @Override
+ public boolean render(InternalContextAdapter context, Writer writer, Node node)
+ throws IOException, ResourceNotFoundException, ParseErrorException,
+ MethodInvocationException {
+
+ String column = getChildAsString(context, node, 0);
+ if (column == null) {
+ throw new ParseErrorException("Column name expected at line "
+ + node.getLine()
+ + ", column "
+ + node.getColumn());
+ }
+
+ String alias = getChildAsString(context, node, 2);
+ String dataRowKey = getChildAsString(context, node, 3);
+
+ // determine what we want to name this column in a resulting DataRow...
+ String label = (!Util.isEmptyString(dataRowKey)) ? dataRowKey : (!Util
+ .isEmptyString(alias)) ? alias : null;
+
+ ColumnDescriptor columnDescriptor = new ColumnDescriptor();
+ columnDescriptor.setName(column);
+ columnDescriptor.setDataRowKey(label);
+
+ String type = getChildAsString(context, node, 1);
+ if (type != null) {
+ columnDescriptor.setJavaClass(guessType(type));
+ }
+
+ // TODO: andrus 6/27/2007 - this is an unofficial jdbcType parameter that is added
+ // temporarily pending CAY-813 implementation for the sake of EJBQL query...
+ Object jdbcType = getChild(context, node, 4);
+ if (jdbcType instanceof Number) {
+ columnDescriptor.setJdbcType(((Number) jdbcType).intValue());
+ }
+
+ writer.write(column);
+
+ // append column alias if needed.
+
+ // Note that if table aliases are used, this logic will result in SQL like
+ // "t0.ARTIST_NAME AS ARTIST_NAME". Doing extra regex matching to handle this
+ // won't probably buy us much.
+ if (!Util.isEmptyString(alias) && !alias.equals(column)) {
+ writer.write(" AS ");
+ writer.write(alias);
+ }
+
+ bindResult(context, columnDescriptor);
+ return true;
+ }
+
+ protected Object getChild(InternalContextAdapter context, Node node, int i)
+ throws MethodInvocationException {
+ return (i >= 0 && i < node.jjtGetNumChildren()) ? node.jjtGetChild(i).value(
+ context) : null;
+ }
+
+ /**
+ * Returns a directive argument at a given index converted to String.
+ *
+ * @since 1.2
+ */
+ protected String getChildAsString(InternalContextAdapter context, Node node, int i)
+ throws MethodInvocationException {
+ Object value = getChild(context, node, i);
+ return (value != null) ? value.toString() : null;
+ }
+
+ /**
+ * Converts "short" type notation to the fully qualified class name. Right now
+ * supports all major standard SQL types, including primitives. All other types are
+ * expected to be fully qualified, and are not converted.
+ */
+ protected String guessType(String type) {
+ String guessed = typesGuess.get(type);
+ return guessed != null ? guessed : type;
+ }
+
+ /**
+ * Adds value to the list of result columns in the context.
+ */
+ protected void bindResult(
+ InternalContextAdapter context,
+ ColumnDescriptor columnDescriptor) {
+
+ Collection<Object> resultColumns = (Collection<Object>) context
+ .getInternalUserContext()
+ .get(SQLTemplateProcessor.RESULT_COLUMNS_LIST_KEY);
+
+ if (resultColumns != null) {
+ resultColumns.add(columnDescriptor);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateProcessor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateProcessor.java
new file mode 100644
index 0000000..71974d3
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateProcessor.java
@@ -0,0 +1,155 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.access.jdbc.ColumnDescriptor;
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.cayenne.access.jdbc.SQLStatement;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.context.InternalContextAdapterImpl;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeInstance;
+import org.apache.velocity.runtime.log.NullLogChute;
+import org.apache.velocity.runtime.parser.ParseException;
+import org.apache.velocity.runtime.parser.node.SimpleNode;
+
+/**
+ * Processor for SQL velocity templates.
+ *
+ * @see org.apache.cayenne.query.SQLTemplate
+ * @since 4.0
+ */
+public class SQLTemplateProcessor {
+
+ private static RuntimeInstance sharedRuntime;
+
+ static final String BINDINGS_LIST_KEY = "bindings";
+ static final String RESULT_COLUMNS_LIST_KEY = "resultColumns";
+ static final String HELPER_KEY = "helper";
+
+ private static final SQLTemplateRenderingUtils sharedUtils = new SQLTemplateRenderingUtils();
+
+ RuntimeInstance velocityRuntime;
+ SQLTemplateRenderingUtils renderingUtils;
+
+ static {
+ initVelocityRuntime();
+ }
+
+ private static void initVelocityRuntime() {
+ // init static velocity engine
+ sharedRuntime = new RuntimeInstance();
+
+ // set null logger
+ sharedRuntime.addProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new NullLogChute());
+
+ sharedRuntime.addProperty(RuntimeConstants.RESOURCE_MANAGER_CLASS, SQLTemplateResourceManager.class.getName());
+ sharedRuntime.addProperty("userdirective", BindDirective.class.getName());
+ sharedRuntime.addProperty("userdirective", BindEqualDirective.class.getName());
+ sharedRuntime.addProperty("userdirective", BindNotEqualDirective.class.getName());
+ sharedRuntime.addProperty("userdirective", BindObjectEqualDirective.class.getName());
+ sharedRuntime.addProperty("userdirective", BindObjectNotEqualDirective.class.getName());
+ sharedRuntime.addProperty("userdirective", ResultDirective.class.getName());
+ sharedRuntime.addProperty("userdirective", ChainDirective.class.getName());
+ sharedRuntime.addProperty("userdirective", ChunkDirective.class.getName());
+ try {
+ sharedRuntime.init();
+ } catch (Exception ex) {
+ throw new CayenneRuntimeException("Error setting up Velocity RuntimeInstance.", ex);
+ }
+ }
+
+ public SQLTemplateProcessor() {
+ this.velocityRuntime = sharedRuntime;
+ this.renderingUtils = sharedUtils;
+ }
+
+ public SQLTemplateProcessor(RuntimeInstance velocityRuntime, SQLTemplateRenderingUtils renderingUtils) {
+ this.velocityRuntime = velocityRuntime;
+ this.renderingUtils = renderingUtils;
+ }
+
+ /**
+ * Builds and returns a SQLStatement based on SQL template and a set of
+ * parameters. During rendering, VelocityContext exposes the following as
+ * variables: all parameters in the map, {@link SQLTemplateRenderingUtils}
+ * as a "helper" variable and SQLStatement object as "statement" variable.
+ */
+ public SQLStatement processTemplate(String template, Map<String, ?> parameters) throws Exception {
+ // have to make a copy of parameter map since we are gonna modify it..
+ Map<String, Object> internalParameters = (parameters != null && !parameters.isEmpty()) ? new HashMap<String, Object>(
+ parameters) : new HashMap<String, Object>(5);
+
+ List<ParameterBinding> bindings = new ArrayList<ParameterBinding>();
+ List<ColumnDescriptor> results = new ArrayList<ColumnDescriptor>();
+ internalParameters.put(BINDINGS_LIST_KEY, bindings);
+ internalParameters.put(RESULT_COLUMNS_LIST_KEY, results);
+ internalParameters.put(HELPER_KEY, renderingUtils);
+
+ String sql = buildStatement(new VelocityContext(internalParameters), template);
+
+ ParameterBinding[] bindingsArray = new ParameterBinding[bindings.size()];
+ bindings.toArray(bindingsArray);
+
+ ColumnDescriptor[] resultsArray = new ColumnDescriptor[results.size()];
+ results.toArray(resultsArray);
+
+ return new SQLStatement(sql, resultsArray, bindingsArray);
+ }
+
+ String buildStatement(VelocityContext context, String template) throws Exception {
+ // Note: this method is a reworked version of
+ // org.apache.velocity.app.Velocity.evaluate(..)
+ // cleaned up to avoid using any Velocity singletons
+
+ StringWriter out = new StringWriter(template.length());
+ SimpleNode nodeTree = null;
+
+ try {
+ nodeTree = velocityRuntime.parse(new StringReader(template), template);
+ } catch (ParseException pex) {
+ throw new CayenneRuntimeException("Error parsing template '" + template + "' : " + pex.getMessage());
+ }
+
+ if (nodeTree == null) {
+ throw new CayenneRuntimeException("Error parsing template " + template);
+ }
+
+ // ... not sure what InternalContextAdapter is for...
+ InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
+ ica.pushCurrentTemplateName(template);
+
+ try {
+ nodeTree.init(ica, velocityRuntime);
+ nodeTree.render(ica, out);
+ return out.toString();
+ } finally {
+ ica.popCurrentTemplateName();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateRenderingUtils.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateRenderingUtils.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateRenderingUtils.java
new file mode 100644
index 0000000..14b8646
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateRenderingUtils.java
@@ -0,0 +1,37 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import org.apache.cayenne.exp.ExpressionFactory;
+
+/**
+ * Implements utility methods used inside Velocity templates when rendering
+ * SQLTemplates.
+ *
+ * @since 1.1
+ */
+public class SQLTemplateRenderingUtils {
+ /**
+ * Returns the result of evaluation of expression with object.
+ */
+ public Object cayenneExp(Object object, String expression) {
+ return ExpressionFactory.exp(expression).evaluate(object);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateResourceManager.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateResourceManager.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateResourceManager.java
new file mode 100644
index 0000000..e80cd46
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateResourceManager.java
@@ -0,0 +1,106 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Map;
+
+import org.apache.commons.collections.ExtendedProperties;
+import org.apache.commons.collections.map.LRUMap;
+import org.apache.velocity.Template;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.resource.Resource;
+import org.apache.velocity.runtime.resource.ResourceManager;
+import org.apache.velocity.runtime.resource.loader.ResourceLoader;
+
+/**
+ * An implementation of the Velocity ResourceManager and ResourceLoader that
+ * creates templates from in-memory Strings.
+ *
+ * @since 1.1
+ */
+// class must be public since it is instantiated by Velocity via reflection.
+public class SQLTemplateResourceManager
+ extends ResourceLoader
+ implements ResourceManager {
+
+ protected Map<String, Template> templateCache;
+
+ public void initialize(RuntimeServices rs) throws Exception {
+ super.rsvc = rs;
+ this.templateCache = new LRUMap(100);
+ }
+
+ public void clearCache() {
+ templateCache.clear();
+ }
+
+ /**
+ * Returns a Velocity Resource which is a Template for the given SQL.
+ */
+ public Resource getResource(String resourceName, int resourceType, String encoding)
+ throws ResourceNotFoundException, ParseErrorException, Exception {
+
+ synchronized (templateCache) {
+ Template resource = templateCache.get(resourceName);
+
+ if (resource == null) {
+ resource = new Template();
+ resource.setRuntimeServices(rsvc);
+ resource.setResourceLoader(this);
+ resource.setName(resourceName);
+ resource.setEncoding(encoding);
+ resource.process();
+
+ templateCache.put(resourceName, resource);
+ }
+
+ return resource;
+ }
+ }
+
+ public String getLoaderNameForResource(String resourceName) {
+ return getClass().getName();
+ }
+
+ @Override
+ public long getLastModified(Resource resource) {
+ return -1;
+ }
+
+ @Override
+ public InputStream getResourceStream(String source)
+ throws ResourceNotFoundException {
+ return new ByteArrayInputStream(source.getBytes());
+ }
+
+ @Override
+ public void init(ExtendedProperties configuration) {
+
+ }
+
+ @Override
+ public boolean isSourceModified(Resource resource) {
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BindDirectiveIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BindDirectiveIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BindDirectiveIT.java
deleted file mode 100644
index e9beaa8..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/BindDirectiveIT.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-package org.apache.cayenne.access.jdbc;
-
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectContext;
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.access.MockOperationObserver;
-import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
-import org.apache.cayenne.dba.JdbcAdapter;
-import org.apache.cayenne.dba.oracle.OracleAdapter;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.query.CapsStrategy;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.testdo.testmap.Artist;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-import java.sql.Connection;
-import java.sql.Timestamp;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.mockito.Mockito.mock;
-
-/**
- * Tests BindDirective for passed null parameters and for not passed parameters
- */
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class BindDirectiveIT extends ServerCase {
-
- @Inject
- private ServerCaseDataSourceFactory dataSourceFactory;
-
- @Inject
- private JdbcAdapter adapter;
-
- @Inject
- private ObjectContext context;
-
- @Inject
- private DBHelper dbHelper;
-
- @Inject
- private JdbcEventLogger logger;
-
- @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 testBindTimestamp() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Integer(1));
- parameters.put("name", "ArtistWithDOB");
- Calendar cal = Calendar.getInstance();
- cal.clear();
- cal.set(2010, 2, 8);
- parameters.put("dob", new Timestamp(cal.getTime().getTime()));
-
- // without JDBC usage
- Map<String, ?> row = performInsertForParameters(parameters, false, 1);
- assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
- assertEquals(cal.getTime(), row.get("DATE_OF_BIRTH"));
- assertNotNull(row.get("DATE_OF_BIRTH"));
- assertEquals(Date.class, row.get("DATE_OF_BIRTH").getClass());
- }
-
- public void testBindSQLDate() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Integer(1));
- parameters.put("name", "ArtistWithDOB");
- Calendar cal = Calendar.getInstance();
- cal.clear();
- cal.set(2010, 2, 8);
- parameters.put("dob", new java.sql.Date(cal.getTime().getTime()));
-
- // without JDBC usage
- Map<String, ?> row = performInsertForParameters(parameters, false, 1);
- assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
- assertEquals(parameters.get("dob"), row.get("DATE_OF_BIRTH"));
- assertNotNull(row.get("DATE_OF_BIRTH"));
- assertEquals(Date.class, row.get("DATE_OF_BIRTH").getClass());
- }
-
- public void testBindUtilDate() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Integer(1));
- parameters.put("name", "ArtistWithDOB");
- Calendar cal = Calendar.getInstance();
- cal.clear();
- cal.set(2010, 2, 8);
- parameters.put("dob", cal.getTime());
-
- // without JDBC usage
- Map<String, ?> row = performInsertForParameters(parameters, false, 1);
- assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
- assertEquals(parameters.get("dob"), row.get("DATE_OF_BIRTH"));
- assertNotNull(row.get("DATE_OF_BIRTH"));
- assertEquals(Date.class, row.get("DATE_OF_BIRTH").getClass());
- }
-
- public void testBindingForCollection() throws Exception {
-
- // insert 3 artists
- for (int i = 1; i < 4; i++) {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Long(i));
- parameters.put("name", "Artist" + i);
- performInsertForParameters(parameters, true, i);
- }
-
- // now select only with names: Artist1 and Artist3
- Set<String> artistNames = new HashSet<String>();
- artistNames.add("Artist1");
- artistNames.add("Artist3");
- String sql = "SELECT * FROM ARTIST WHERE ARTIST_NAME in (#bind($ARTISTNAMES))";
- SQLTemplate query = new SQLTemplate(Artist.class, sql);
-
- // customize for DB's that require trimming CHAR spaces
- query.setTemplate(OracleAdapter.class.getName(), "SELECT * FROM ARTIST WHERE RTRIM(ARTIST_NAME) in (#bind($ARTISTNAMES))");
-
- query.setColumnNamesCapitalization(CapsStrategy.UPPER);
- query.setParameters(Collections.singletonMap("ARTISTNAMES", artistNames));
- List<DataRow> result = context.performQuery(query);
- assertEquals(2, result.size());
- }
-
- public void testBindForPassedNullParam() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Long(1));
- parameters.put("name", "ArtistWithoutDOB");
- // passing null in parameter
- parameters.put("dob", null);
-
- // without JDBC usage
- Map<String, ?> row = performInsertForParameters(parameters, false, 1);
- assertEquals(parameters.get("id"), row.get("ARTIST_ID"));
- assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
- assertEquals(parameters.get("dob"), row.get("DATE_OF_BIRTH"));
- assertNull(row.get("DATE_OF_BIRTH"));
- }
-
- public void testBindWithJDBCForPassedNullParam() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Long(1));
- parameters.put("name", "ArtistWithoutDOB");
- // passing null in parameter
- parameters.put("dob", null);
-
- // use JDBC
- Map<String, ?> row = performInsertForParameters(parameters, true, 1);
- assertEquals(parameters.get("id"), row.get("ARTIST_ID"));
- assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
- assertEquals(parameters.get("dob"), row.get("DATE_OF_BIRTH"));
- assertNull(row.get("DATE_OF_BIRTH"));
- }
-
- public void testBindForNotPassedParam() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Long(1));
- parameters.put("name", "ArtistWithoutDOB");
- // not passing parameter parameters.put("dob", not passed!);
-
- // without JDBC usage
- Map<String, ?> row = performInsertForParameters(parameters, false, 1);
- assertEquals(parameters.get("id"), row.get("ARTIST_ID"));
- assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
- // parameter should be passed as null
- assertNull(row.get("DATE_OF_BIRTH"));
- }
-
- public void testBindWithJDBCForNotPassedParam() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Long(1));
- parameters.put("name", "ArtistWithoutDOB");
- // not passing parameter parameters.put("dob", not passed!);
-
- // use JDBC
- Map<String, ?> row = performInsertForParameters(parameters, true, 1);
- assertEquals(parameters.get("id"), row.get("ARTIST_ID"));
- assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
- // parameter should be passed as null
- assertNull(row.get("DATE_OF_BIRTH"));
- }
-
- /**
- * Inserts row for given parameters
- *
- * @return inserted row
- */
- private Map<String, ?> performInsertForParameters(
- Map<String, Object> parameters,
- boolean useJDBCType,
- int expectedRowCount) throws Exception {
-
- String templateString;
- if (useJDBCType) {
- templateString = "INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME, DATE_OF_BIRTH) "
- + "VALUES (#bind($id), #bind($name), #bind($dob 'DATE'))";
- }
- else {
- templateString = "INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME, DATE_OF_BIRTH) "
- + "VALUES (#bind($id), #bind($name), #bind($dob))";
- }
- SQLTemplate template = new SQLTemplate(Object.class, templateString);
-
- template.setParameters(parameters);
-
- DataNode node = new DataNode();
- node.setEntityResolver(context.getEntityResolver());
- node.setRowReaderFactory(mock(RowReaderFactory.class));
- node.setAdapter(adapter);
- SQLTemplateAction action = new SQLTemplateAction(template, node);
-
- Connection c = dataSourceFactory.getSharedDataSource().getConnection();
- try {
- MockOperationObserver observer = new MockOperationObserver();
- action.performAction(c, observer);
-
- int[] batches = observer.countsForQuery(template);
- assertNotNull(batches);
- assertEquals(1, batches.length);
- assertEquals(1, batches[0]);
- }
- finally {
- c.close();
- }
-
- SelectQuery query = new SelectQuery(Artist.class);
- query.setFetchingDataRows(true);
-
- List<DataRow> data = context.performQuery(query);
- assertEquals(expectedRowCount, data.size());
- return data.get(0);
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/MockupRuntimeServices.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/MockupRuntimeServices.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/MockupRuntimeServices.java
deleted file mode 100644
index b272dfa..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/MockupRuntimeServices.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import java.io.Reader;
-
-import org.apache.velocity.runtime.RuntimeInstance;
-import org.apache.velocity.runtime.parser.ParseException;
-import org.apache.velocity.runtime.parser.node.SimpleNode;
-
-/**
- */
-class MockupRuntimeServices extends RuntimeInstance {
-
- @Override
- public SimpleNode parse(Reader reader, String templateName, boolean dumpNamespace)
- throws ParseException {
- return new SimpleNode(1);
- }
-
- @Override
- public SimpleNode parse(Reader reader, String templateName) throws ParseException {
- return new SimpleNode(1);
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/ResultDirectiveIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/ResultDirectiveIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/ResultDirectiveIT.java
deleted file mode 100644
index 7b9bce4..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/ResultDirectiveIT.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-package org.apache.cayenne.access.jdbc;
-
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.access.MockOperationObserver;
-import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
-import org.apache.cayenne.configuration.server.ServerRuntime;
-import org.apache.cayenne.dba.JdbcAdapter;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.query.CapsStrategy;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.test.jdbc.DBHelper;
-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.sql.Connection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.mockito.Mockito.mock;
-
-/**
- * Test for Result directive to check if we could use ResultDitrective optionally.
- */
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class ResultDirectiveIT extends ServerCase {
-
- @Inject
- private ServerRuntime runtime;
-
- @Inject
- private DBHelper dbHelper;
-
- @Inject
- private JdbcAdapter dbAdapter;
-
- @Override
- protected void setUpAfterInjection() throws Exception {
- dbHelper.deleteAll("PAINTING_INFO");
- dbHelper.deleteAll("PAINTING");
- dbHelper.deleteAll("PAINTING1");
- dbHelper.deleteAll("ARTIST_EXHIBIT");
- dbHelper.deleteAll("ARTIST_GROUP");
- dbHelper.deleteAll("ARTIST");
- dbHelper.deleteAll("EXHIBIT");
- dbHelper.deleteAll("GALLERY");
- }
-
- public void testWithoutResultDirective() throws Exception {
- String sql = "SELECT ARTIST_ID, ARTIST_NAME FROM ARTIST";
- Map<String, Object> artist = insertArtist();
- Map<String, Object> selectResult = selectForQuery(sql);
-
- assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
- assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME"));
- }
-
- public void testWithOnlyResultDirective() throws Exception {
- String sql = "SELECT #result('ARTIST_ID' 'java.lang.Integer'),"
- + " #result('ARTIST_NAME' 'java.lang.String')"
- + " FROM ARTIST";
- Map<String, Object> artist = insertArtist();
- Map<String, Object> selectResult = selectForQuery(sql);
-
- assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
- assertEquals(artist.get("ARTIST_NAME"), selectResult
- .get("ARTIST_NAME")
- .toString()
- .trim());
- }
-
- public void testWithMixedDirectiveUse1() throws Exception {
- String sql = "SELECT ARTIST_ID,"
- + " #result('ARTIST_NAME' 'java.lang.String')"
- + " FROM ARTIST";
- Map<String, Object> artist = insertArtist();
- Map<String, Object> selectResult = selectForQuery(sql);
-
- assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
- assertEquals(artist.get("ARTIST_NAME"), selectResult
- .get("ARTIST_NAME")
- .toString()
- .trim());
- }
-
- public void testWithMixedDirectiveUse2() throws Exception {
- String sql = "SELECT #result('ARTIST_ID' 'java.lang.Integer'),"
- + " ARTIST_NAME "
- + " FROM ARTIST";
- Map<String, Object> artist = insertArtist();
- Map<String, Object> selectResult = selectForQuery(sql);
-
- assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
- assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME"));
- }
-
- private Map<String, Object> selectForQuery(String sql) {
- SQLTemplate template = new SQLTemplate(Artist.class, sql);
- template.setColumnNamesCapitalization(CapsStrategy.UPPER);
- MockOperationObserver observer = new MockOperationObserver();
- runtime.getDataDomain().performQueries(
- Collections.singletonList(template),
- observer);
-
- List<Map<String, Object>> data = observer.rowsForQuery(template);
- assertEquals(1, data.size());
- Map<String, Object> row = data.get(0);
- return row;
- }
-
- /**
- * Inserts one Artist
- *
- * @return Inserted Artist as a DataRow
- */
- private Map<String, Object> insertArtist() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Integer(1));
- parameters.put("name", "ArtistToTestResult");
- String templateString = "INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME, DATE_OF_BIRTH) "
- + "VALUES (#bind($id), #bind($name), #bind($dob))";
-
- SQLTemplate template = new SQLTemplate(Object.class, templateString);
-
- template.setParameters(parameters);
-
- DataNode node = new DataNode();
- node.setEntityResolver(runtime.getDataDomain().getEntityResolver());
- node.setRowReaderFactory(mock(RowReaderFactory.class));
- node.setAdapter(dbAdapter);
-
- SQLTemplateAction action = new SQLTemplateAction(template, node);
-
- Connection c = runtime
- .getDataDomain()
- .getDataNodes()
- .iterator()
- .next()
- .getDataSource()
- .getConnection();
- try {
- MockOperationObserver observer = new MockOperationObserver();
- action.performAction(c, observer);
-
- int[] batches = observer.countsForQuery(template);
- assertNotNull(batches);
- assertEquals(1, batches.length);
- assertEquals(1, batches[0]);
- }
- finally {
- c.close();
- }
-
- MockOperationObserver observer = new MockOperationObserver();
- SelectQuery query = new SelectQuery(Artist.class);
- runtime
- .getDataDomain()
- .performQueries(Collections.singletonList(query), observer);
-
- List<?> data = observer.rowsForQuery(query);
- assertEquals(1, data.size());
- DataRow row = (DataRow) data.get(0);
- return row;
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorChainTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorChainTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorChainTest.java
deleted file mode 100644
index 69e5bf4..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorChainTest.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import org.junit.Test;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-public class SQLTemplateProcessorChainTest {
-
- @Test
- public void testProcessTemplateNoChunks() throws Exception {
- // whatever is inside the chain, it should render as empty if there
- // is no chunks...
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- "#chain(' AND ') #end",
- Collections.EMPTY_MAP);
-
- assertEquals("", compiled.getSql());
-
- compiled = new SQLTemplateProcessor().processTemplate(
- "#chain(' AND ') garbage #end",
- Collections.EMPTY_MAP);
-
- assertEquals("", compiled.getSql());
-
- compiled = new SQLTemplateProcessor().processTemplate(
- "#chain(' AND ' 'PREFIX') #end",
- Collections.EMPTY_MAP);
-
- assertEquals("", compiled.getSql());
- compiled = new SQLTemplateProcessor().processTemplate(
- "#chain(' AND ' 'PREFIX') garbage #end",
- Collections.EMPTY_MAP);
-
- assertEquals("", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateFullChain() throws Exception {
- String template = "#chain(' OR ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("b", "[B]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("[A] OR [B] OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateFullChainAndPrefix() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("b", "[B]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] OR [B] OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplatePartialChainMiddle() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplatePartialChainStart() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("b", "[B]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [B] OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplatePartialChainEnd() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("b", "[B]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] OR [B]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateChainWithGarbage() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + " some other stuff"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] some other stuff OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateChainUnconditionalChunks() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk()C1#end"
- + "#chunk()C2#end"
- + "#chunk()C3#end"
- + "#end";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- template,
- Collections.EMPTY_MAP);
- assertEquals("WHERE C1 OR C2 OR C3", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateEmptyChain() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- template,
- Collections.EMPTY_MAP);
- assertEquals("", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateWithFalseOrZero1() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)[A]#end"
- + "#chunk($b)[B]#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", false);
- map.put("b", 0);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] OR [B]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateWithFalseOrZero2() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", false);
- map.put("b", 0);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE false OR 0", compiled.getSql());
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorSelectTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorSelectTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorSelectTest.java
deleted file mode 100644
index bc498c8..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorSelectTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import org.junit.Test;
-
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-public class SQLTemplateProcessorSelectTest {
-
- @Test
- public void testProcessTemplateUnchanged() throws Exception {
- String sqlTemplate = "SELECT * FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals(sqlTemplate, compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- assertEquals(0, compiled.getResultColumns().length);
- }
-
- @Test
- public void testProcessSelectTemplate1() throws Exception {
- String sqlTemplate = "SELECT #result('A') FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT A FROM ME", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- assertEquals(1, compiled.getResultColumns().length);
- assertEquals("A", compiled.getResultColumns()[0].getName());
- assertNull(compiled.getResultColumns()[0].getJavaClass());
- }
-
- @Test
- public void testProcessSelectTemplate2() throws Exception {
- String sqlTemplate = "SELECT #result('A' 'String') FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT A FROM ME", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- assertEquals(1, compiled.getResultColumns().length);
- assertEquals("A", compiled.getResultColumns()[0].getName());
- assertEquals("java.lang.String", compiled.getResultColumns()[0].getJavaClass());
- }
-
- @Test
- public void testProcessSelectTemplate3() throws Exception {
- String sqlTemplate = "SELECT #result('A' 'String' 'B') FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT A AS B FROM ME", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- assertEquals(1, compiled.getResultColumns().length);
- ColumnDescriptor column = compiled.getResultColumns()[0];
- assertEquals("A", column.getName());
- assertEquals("B", column.getDataRowKey());
- assertEquals("java.lang.String", column.getJavaClass());
- }
-
- @Test
- public void testProcessSelectTemplate4() throws Exception {
- String sqlTemplate = "SELECT #result('A'), #result('B'), #result('C') FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT A, B, C FROM ME", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- assertEquals(3, compiled.getResultColumns().length);
- assertEquals("A", compiled.getResultColumns()[0].getName());
- assertEquals("B", compiled.getResultColumns()[1].getName());
- assertEquals("C", compiled.getResultColumns()[2].getName());
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorTest.java
deleted file mode 100644
index a45c068..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessorTest.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.DataObject;
-import org.apache.cayenne.ObjectId;
-import org.junit.Test;
-
-import java.sql.Types;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- */
-public class SQLTemplateProcessorTest {
-
- @Test
- public void testProcessTemplateUnchanged1() throws Exception {
- String sqlTemplate = "SELECT * FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals(sqlTemplate, compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- }
-
- @Test
- public void testProcessTemplateUnchanged2() throws Exception {
- String sqlTemplate = "SELECT a.b as XYZ FROM $SYSTEM_TABLE";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals(sqlTemplate, compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- }
-
- @Test
- public void testProcessTemplateSimpleDynamicContent() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE $a";
-
- Map map = Collections.singletonMap("a", "VALUE_OF_A");
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- map);
-
- assertEquals("SELECT * FROM ME WHERE VALUE_OF_A", compiled.getSql());
-
- // bindings are not populated, since no "bind" macro is used.
- assertEquals(0, compiled.getBindings().length);
- }
-
- @Test
- public void testProcessTemplateBind() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE "
- + "COLUMN1 = #bind($a 'VARCHAR') AND COLUMN2 = #bind($b 'INTEGER')";
- Map map = Collections.singletonMap("a", "VALUE_OF_A");
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN1 = ? AND COLUMN2 = ?", compiled
- .getSql());
- assertEquals(2, compiled.getBindings().length);
- assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
- assertBindingValue(null, compiled.getBindings()[1]);
- }
-
- @Test
- public void testProcessTemplateBindGuessVarchar() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($a)";
- Map map = Collections.singletonMap("a", "VALUE_OF_A");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- map);
-
- assertEquals(1, compiled.getBindings().length);
- assertBindingType(Types.VARCHAR, compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateBindGuessInteger() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($a)";
- Map map = Collections.singletonMap("a", new Integer(4));
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- map);
-
- assertEquals(1, compiled.getBindings().length);
- assertBindingType(Types.INTEGER, compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateBindEqual() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN #bindEqual($a 'VARCHAR')";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN IS NULL", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- Map map = Collections.singletonMap("a", "VALUE_OF_A");
-
- compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN = ?", compiled.getSql());
- assertEquals(1, compiled.getBindings().length);
- assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateBindNotEqual() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN #bindNotEqual($a 'VARCHAR')";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN IS NOT NULL", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- Map map = Collections.singletonMap("a", "VALUE_OF_A");
-
- compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN <> ?", compiled.getSql());
- assertEquals(1, compiled.getBindings().length);
- assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateID() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($helper.cayenneExp($a, 'db:ID_COLUMN'))";
-
- DataObject dataObject = new CayenneDataObject();
- dataObject.setObjectId(new ObjectId("T", "ID_COLUMN", 5));
-
- Map map = Collections.singletonMap("a", dataObject);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN1 = ?", compiled.getSql());
- assertEquals(1, compiled.getBindings().length);
- assertBindingValue(new Integer(5), compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateNotEqualID() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE "
- + "COLUMN1 #bindNotEqual($helper.cayenneExp($a, 'db:ID_COLUMN1')) "
- + "AND COLUMN2 #bindNotEqual($helper.cayenneExp($a, 'db:ID_COLUMN2'))";
-
- Map idMap = new HashMap();
- idMap.put("ID_COLUMN1", new Integer(3));
- idMap.put("ID_COLUMN2", "aaa");
- ObjectId id = new ObjectId("T", idMap);
- DataObject dataObject = new CayenneDataObject();
- dataObject.setObjectId(id);
-
- Map map = Collections.singletonMap("a", dataObject);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN1 <> ? AND COLUMN2 <> ?", compiled
- .getSql());
- assertEquals(2, compiled.getBindings().length);
- assertBindingValue(new Integer(3), compiled.getBindings()[0]);
- assertBindingValue("aaa", compiled.getBindings()[1]);
- }
-
- @Test
- public void testProcessTemplateConditions() throws Exception {
- String sqlTemplate = "SELECT * FROM ME #if($a) WHERE COLUMN1 > #bind($a)#end";
-
- Map map = Collections.singletonMap("a", "VALUE_OF_A");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN1 > ?", compiled.getSql());
- assertEquals(1, compiled.getBindings().length);
- assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
-
- compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT * FROM ME ", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- }
-
- @Test
- public void testProcessTemplateBindCollection() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN IN (#bind($list 'VARCHAR'))";
-
- Map map = new HashMap();
- map.put("list", Arrays.asList("a", "b", "c"));
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN IN (?,?,?)", compiled.getSql());
- assertEquals(3, compiled.getBindings().length);
-
- compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
- assertBindingValue("a", compiled.getBindings()[0]);
- assertBindingValue("b", compiled.getBindings()[1]);
- assertBindingValue("c", compiled.getBindings()[2]);
- }
-
- protected void assertBindingValue(Object expectedValue, Object binding) {
- assertTrue("Not a binding!", binding instanceof ParameterBinding);
- assertEquals(expectedValue, ((ParameterBinding) binding).getValue());
- }
-
- protected void assertBindingType(int expectedType, Object binding) {
- assertTrue("Not a binding!", binding instanceof ParameterBinding);
- assertEquals(expectedType, ((ParameterBinding) binding).getJdbcType());
- }
-
- protected void assertBindingPrecision(int expectedPrecision, Object binding) {
- assertTrue("Not a binding!", binding instanceof ParameterBinding);
- assertEquals(expectedPrecision, ((ParameterBinding) binding).getScale());
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateResourceManagerTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateResourceManagerTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateResourceManagerTest.java
deleted file mode 100644
index ad7bf61..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/jdbc/SQLTemplateResourceManagerTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.access.jdbc;
-
-import org.apache.velocity.Template;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.runtime.resource.Resource;
-import org.apache.velocity.runtime.resource.ResourceManager;
-import org.junit.Test;
-
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-public class SQLTemplateResourceManagerTest {
-
- @Test
- public void testFetResource() throws Exception {
- SQLTemplateResourceManager rm = new SQLTemplateResourceManager();
- rm.initialize(new MockupRuntimeServices());
-
- Resource resource = rm.getResource(
- "abc",
- ResourceManager.RESOURCE_TEMPLATE,
- RuntimeConstants.ENCODING_DEFAULT);
-
- assertTrue(resource instanceof Template);
-
- // must be cached...
- assertSame(resource, rm.getResource(
- "abc",
- ResourceManager.RESOURCE_TEMPLATE,
- RuntimeConstants.ENCODING_DEFAULT));
-
- // new resource must be different
- assertNotSame(resource, rm.getResource(
- "xyz",
- ResourceManager.RESOURCE_TEMPLATE,
- RuntimeConstants.ENCODING_DEFAULT));
-
- // after clearing cache, resource must be refreshed
- rm.clearCache();
- assertNotSame(resource, rm.getResource(
- "abc",
- ResourceManager.RESOURCE_TEMPLATE,
- RuntimeConstants.ENCODING_DEFAULT));
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/c8709542/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java
new file mode 100644
index 0000000..78e55e8
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java
@@ -0,0 +1,268 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.velocity;
+
+import org.apache.cayenne.DataRow;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.MockOperationObserver;
+import org.apache.cayenne.access.jdbc.SQLTemplateAction;
+import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
+import org.apache.cayenne.dba.JdbcAdapter;
+import org.apache.cayenne.dba.oracle.OracleAdapter;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.query.CapsStrategy;
+import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.sql.Connection;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests BindDirective for passed null parameters and for not passed parameters
+ */
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class BindDirectiveIT extends ServerCase {
+
+ @Inject
+ private ServerCaseDataSourceFactory dataSourceFactory;
+
+ @Inject
+ private JdbcAdapter adapter;
+
+ @Inject
+ private ObjectContext context;
+
+ @Inject
+ private DBHelper dbHelper;
+
+ @Inject
+ private JdbcEventLogger logger;
+
+ @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 testBindTimestamp() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Integer(1));
+ parameters.put("name", "ArtistWithDOB");
+ Calendar cal = Calendar.getInstance();
+ cal.clear();
+ cal.set(2010, 2, 8);
+ parameters.put("dob", new Timestamp(cal.getTime().getTime()));
+
+ // without JDBC usage
+ Map<String, ?> row = performInsertForParameters(parameters, false, 1);
+ assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
+ assertEquals(cal.getTime(), row.get("DATE_OF_BIRTH"));
+ assertNotNull(row.get("DATE_OF_BIRTH"));
+ assertEquals(Date.class, row.get("DATE_OF_BIRTH").getClass());
+ }
+
+ public void testBindSQLDate() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Integer(1));
+ parameters.put("name", "ArtistWithDOB");
+ Calendar cal = Calendar.getInstance();
+ cal.clear();
+ cal.set(2010, 2, 8);
+ parameters.put("dob", new java.sql.Date(cal.getTime().getTime()));
+
+ // without JDBC usage
+ Map<String, ?> row = performInsertForParameters(parameters, false, 1);
+ assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
+ assertEquals(parameters.get("dob"), row.get("DATE_OF_BIRTH"));
+ assertNotNull(row.get("DATE_OF_BIRTH"));
+ assertEquals(Date.class, row.get("DATE_OF_BIRTH").getClass());
+ }
+
+ public void testBindUtilDate() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Integer(1));
+ parameters.put("name", "ArtistWithDOB");
+ Calendar cal = Calendar.getInstance();
+ cal.clear();
+ cal.set(2010, 2, 8);
+ parameters.put("dob", cal.getTime());
+
+ // without JDBC usage
+ Map<String, ?> row = performInsertForParameters(parameters, false, 1);
+ assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
+ assertEquals(parameters.get("dob"), row.get("DATE_OF_BIRTH"));
+ assertNotNull(row.get("DATE_OF_BIRTH"));
+ assertEquals(Date.class, row.get("DATE_OF_BIRTH").getClass());
+ }
+
+ public void testBindingForCollection() throws Exception {
+
+ // insert 3 artists
+ for (int i = 1; i < 4; i++) {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Long(i));
+ parameters.put("name", "Artist" + i);
+ performInsertForParameters(parameters, true, i);
+ }
+
+ // now select only with names: Artist1 and Artist3
+ Set<String> artistNames = new HashSet<String>();
+ artistNames.add("Artist1");
+ artistNames.add("Artist3");
+ String sql = "SELECT * FROM ARTIST WHERE ARTIST_NAME in (#bind($ARTISTNAMES))";
+ SQLTemplate query = new SQLTemplate(Artist.class, sql);
+
+ // customize for DB's that require trimming CHAR spaces
+ query.setTemplate(OracleAdapter.class.getName(), "SELECT * FROM ARTIST WHERE RTRIM(ARTIST_NAME) in (#bind($ARTISTNAMES))");
+
+ query.setColumnNamesCapitalization(CapsStrategy.UPPER);
+ query.setParams(Collections.singletonMap("ARTISTNAMES", artistNames));
+ List<DataRow> result = context.performQuery(query);
+ assertEquals(2, result.size());
+ }
+
+ public void testBindForPassedNullParam() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Long(1));
+ parameters.put("name", "ArtistWithoutDOB");
+ // passing null in parameter
+ parameters.put("dob", null);
+
+ // without JDBC usage
+ Map<String, ?> row = performInsertForParameters(parameters, false, 1);
+ assertEquals(parameters.get("id"), row.get("ARTIST_ID"));
+ assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
+ assertEquals(parameters.get("dob"), row.get("DATE_OF_BIRTH"));
+ assertNull(row.get("DATE_OF_BIRTH"));
+ }
+
+ public void testBindWithJDBCForPassedNullParam() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Long(1));
+ parameters.put("name", "ArtistWithoutDOB");
+ // passing null in parameter
+ parameters.put("dob", null);
+
+ // use JDBC
+ Map<String, ?> row = performInsertForParameters(parameters, true, 1);
+ assertEquals(parameters.get("id"), row.get("ARTIST_ID"));
+ assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
+ assertEquals(parameters.get("dob"), row.get("DATE_OF_BIRTH"));
+ assertNull(row.get("DATE_OF_BIRTH"));
+ }
+
+ public void testBindForNotPassedParam() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Long(1));
+ parameters.put("name", "ArtistWithoutDOB");
+ // not passing parameter parameters.put("dob", not passed!);
+
+ // without JDBC usage
+ Map<String, ?> row = performInsertForParameters(parameters, false, 1);
+ assertEquals(parameters.get("id"), row.get("ARTIST_ID"));
+ assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
+ // parameter should be passed as null
+ assertNull(row.get("DATE_OF_BIRTH"));
+ }
+
+ public void testBindWithJDBCForNotPassedParam() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", new Long(1));
+ parameters.put("name", "ArtistWithoutDOB");
+ // not passing parameter parameters.put("dob", not passed!);
+
+ // use JDBC
+ Map<String, ?> row = performInsertForParameters(parameters, true, 1);
+ assertEquals(parameters.get("id"), row.get("ARTIST_ID"));
+ assertEquals(parameters.get("name"), row.get("ARTIST_NAME"));
+ // parameter should be passed as null
+ assertNull(row.get("DATE_OF_BIRTH"));
+ }
+
+ /**
+ * Inserts row for given parameters
+ *
+ * @return inserted row
+ */
+ private Map<String, ?> performInsertForParameters(
+ Map<String, Object> parameters,
+ boolean useJDBCType,
+ int expectedRowCount) throws Exception {
+
+ String templateString;
+ if (useJDBCType) {
+ templateString = "INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME, DATE_OF_BIRTH) "
+ + "VALUES (#bind($id), #bind($name), #bind($dob 'DATE'))";
+ }
+ else {
+ templateString = "INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME, DATE_OF_BIRTH) "
+ + "VALUES (#bind($id), #bind($name), #bind($dob))";
+ }
+ SQLTemplate template = new SQLTemplate(Object.class, templateString);
+
+ template.setParams(parameters);
+
+ DataNode node = new DataNode();
+ node.setEntityResolver(context.getEntityResolver());
+ node.setRowReaderFactory(mock(RowReaderFactory.class));
+ node.setAdapter(adapter);
+ SQLTemplateAction action = new SQLTemplateAction(template, node);
+
+ Connection c = dataSourceFactory.getSharedDataSource().getConnection();
+ try {
+ MockOperationObserver observer = new MockOperationObserver();
+ action.performAction(c, observer);
+
+ int[] batches = observer.countsForQuery(template);
+ assertNotNull(batches);
+ assertEquals(1, batches.length);
+ assertEquals(1, batches[0]);
+ }
+ finally {
+ c.close();
+ }
+
+ SelectQuery query = new SelectQuery(Artist.class);
+ query.setFetchingDataRows(true);
+
+ List<DataRow> data = context.performQuery(query);
+ assertEquals(expectedRowCount, data.size());
+ return data.get(0);
+ }
+}
[5/6] git commit: CAY-1966 SQLTemplate/SQLSelect positional parameter
binding
Posted by aa...@apache.org.
CAY-1966 SQLTemplate/SQLSelect positional parameter binding
* abstracting Velocity work in an injectable SQLTemplateProcessor service
* more utest cleanup
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/5aedf54e
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/5aedf54e
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/5aedf54e
Branch: refs/heads/master
Commit: 5aedf54ed7b420e3c92bb6add3fcb9619aecce5c
Parents: c870954
Author: aadamchik <aa...@apache.org>
Authored: Sun Nov 2 15:49:38 2014 +0300
Committer: aadamchik <aa...@apache.org>
Committed: Sun Nov 2 16:51:54 2014 +0300
----------------------------------------------------------------------
.../org/apache/cayenne/access/DataNode.java | 16 +
.../cayenne/access/jdbc/SQLTemplateAction.java | 5 +-
.../access/jdbc/SQLTemplateProcessor.java | 33 ++
.../server/DefaultDataNodeFactory.java | 5 +
.../configuration/server/ServerModule.java | 4 +
.../apache/cayenne/velocity/BindDirective.java | 2 +-
.../cayenne/velocity/ResultDirective.java | 2 +-
.../cayenne/velocity/SQLTemplateProcessor.java | 155 ---------
.../velocity/VelocitySQLTemplateProcessor.java | 146 ++++++++
.../server/DataDomainProviderTest.java | 346 ++++++++++---------
.../di/server/ServerCaseDataNodeFactory.java | 5 +
.../cayenne/velocity/BindDirectiveIT.java | 33 +-
.../cayenne/velocity/ResultDirectiveIT.java | 266 +++++++-------
.../velocity/SQLTemplateProcessorChainTest.java | 221 ------------
.../SQLTemplateProcessorSelectTest.java | 112 ------
.../velocity/SQLTemplateProcessorTest.java | 235 -------------
.../VelocitySQLTemplateProcessorTest.java | 234 +++++++++++++
.../VelocitySQLTemplateProcessor_ChainTest.java | 184 ++++++++++
...VelocitySQLTemplateProcessor_SelectTest.java | 109 ++++++
19 files changed, 1047 insertions(+), 1066 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java
index 907c81a..4d1b5f0 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DataNode.java
@@ -36,6 +36,7 @@ import org.apache.cayenne.access.dbsync.SchemaUpdateStrategy;
import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy;
import org.apache.cayenne.access.jdbc.ColumnDescriptor;
import org.apache.cayenne.access.jdbc.RowDescriptor;
+import org.apache.cayenne.access.jdbc.SQLTemplateProcessor;
import org.apache.cayenne.access.jdbc.reader.RowReader;
import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
import org.apache.cayenne.access.translator.batch.BatchTranslator;
@@ -74,6 +75,7 @@ public class DataNode implements QueryEngine {
private JdbcEventLogger jdbcEventLogger;
private RowReaderFactory rowReaderFactory;
private BatchTranslatorFactory batchTranslatorFactory;
+ private SQLTemplateProcessor sqlTemplateProcessor;
TransactionDataSource readThroughDataSource;
@@ -504,4 +506,18 @@ public class DataNode implements QueryEngine {
public void setBatchTranslatorFactory(BatchTranslatorFactory batchTranslatorFactory) {
this.batchTranslatorFactory = batchTranslatorFactory;
}
+
+ /**
+ * @since 4.0
+ */
+ public SQLTemplateProcessor getSqlTemplateProcessor() {
+ return sqlTemplateProcessor;
+ }
+
+ /**
+ * @since 4.0
+ */
+ public void setSqlTemplateProcessor(SQLTemplateProcessor sqlTemplateProcessor) {
+ this.sqlTemplateProcessor = sqlTemplateProcessor;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
index 50e8691..2e0d767 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateAction.java
@@ -49,7 +49,6 @@ import org.apache.cayenne.query.QueryMetadata;
import org.apache.cayenne.query.SQLAction;
import org.apache.cayenne.query.SQLTemplate;
import org.apache.cayenne.util.Util;
-import org.apache.cayenne.velocity.SQLTemplateProcessor;
import org.apache.commons.collections.IteratorUtils;
/**
@@ -104,8 +103,6 @@ public class SQLTemplateAction implements SQLAction {
boolean loggable = dataNode.getJdbcEventLogger().isLoggable();
int size = query.parametersSize();
- SQLTemplateProcessor templateProcessor = new SQLTemplateProcessor();
-
// zero size indicates a one-shot query with no parameters
// so fake a single entry batch...
int batchSize = (size > 0) ? size : 1;
@@ -119,7 +116,7 @@ public class SQLTemplateAction implements SQLAction {
for (int i = 0; i < batchSize; i++) {
Map<String, ?> nextParameters = it.next();
- SQLStatement compiled = templateProcessor.processTemplate(template, nextParameters);
+ SQLStatement compiled = dataNode.getSqlTemplateProcessor().processTemplate(template, nextParameters);
if (loggable) {
dataNode.getJdbcEventLogger().logQuery(compiled.getSql(), Arrays.asList(compiled.getBindings()));
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
new file mode 100644
index 0000000..3873494
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/jdbc/SQLTemplateProcessor.java
@@ -0,0 +1,33 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.access.jdbc;
+
+import java.util.Map;
+
+/**
+ * @since 4.0
+ */
+public interface SQLTemplateProcessor {
+
+ /**
+ * Builds and returns a SQLStatement based on SQL template String and a map
+ * of parameters.
+ */
+ SQLStatement processTemplate(String template, Map<String, ?> parameters);
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
index bd844d4..4acaa9e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DefaultDataNodeFactory.java
@@ -22,6 +22,7 @@ import javax.sql.DataSource;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.dbsync.SchemaUpdateStrategy;
+import org.apache.cayenne.access.jdbc.SQLTemplateProcessor;
import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
import org.apache.cayenne.configuration.DataNodeDescriptor;
@@ -54,6 +55,9 @@ public class DefaultDataNodeFactory implements DataNodeFactory {
@Inject
protected SchemaUpdateStrategy defaultSchemaUpdateStrategy;
+
+ @Inject
+ protected SQLTemplateProcessor sqlTemplateProcessor;
@Override
public DataNode createDataNode(DataNodeDescriptor nodeDescriptor) throws Exception {
@@ -63,6 +67,7 @@ public class DefaultDataNodeFactory implements DataNodeFactory {
dataNode.setJdbcEventLogger(jdbcEventLogger);
dataNode.setRowReaderFactory(rowReaderFactory);
dataNode.setBatchTranslatorFactory(batchTranslatorFactory);
+ dataNode.setSqlTemplateProcessor(sqlTemplateProcessor);
dataNode.setDataSourceLocation(nodeDescriptor.getParameters());
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
index 7e1cd74..8119982 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
@@ -27,6 +27,7 @@ import org.apache.cayenne.access.DefaultObjectMapRetainStrategy;
import org.apache.cayenne.access.ObjectMapRetainStrategy;
import org.apache.cayenne.access.dbsync.SchemaUpdateStrategy;
import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy;
+import org.apache.cayenne.access.jdbc.SQLTemplateProcessor;
import org.apache.cayenne.access.jdbc.reader.DefaultRowReaderFactory;
import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
@@ -98,6 +99,7 @@ import org.apache.cayenne.tx.DefaultTransactionFactory;
import org.apache.cayenne.tx.DefaultTransactionManager;
import org.apache.cayenne.tx.TransactionFactory;
import org.apache.cayenne.tx.TransactionManager;
+import org.apache.cayenne.velocity.VelocitySQLTemplateProcessor;
/**
* A DI module containing all Cayenne server runtime configuration.
@@ -265,5 +267,7 @@ public class ServerModule implements Module {
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
binder.bind(RowReaderFactory.class).to(DefaultRowReaderFactory.class);
+
+ binder.bind(SQLTemplateProcessor.class).to(VelocitySQLTemplateProcessor.class);
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java
index 3ff81b7..6e7e83e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/BindDirective.java
@@ -167,7 +167,7 @@ public class BindDirective extends Directive {
protected void bind(InternalContextAdapter context, ParameterBinding binding) {
Collection bindings = (Collection) context.getInternalUserContext().get(
- SQLTemplateProcessor.BINDINGS_LIST_KEY);
+ VelocitySQLTemplateProcessor.BINDINGS_LIST_KEY);
if (bindings != null) {
bindings.add(binding);
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java
index 8a3a5e4..315c56b 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/ResultDirective.java
@@ -197,7 +197,7 @@ public class ResultDirective extends Directive {
Collection<Object> resultColumns = (Collection<Object>) context
.getInternalUserContext()
- .get(SQLTemplateProcessor.RESULT_COLUMNS_LIST_KEY);
+ .get(VelocitySQLTemplateProcessor.RESULT_COLUMNS_LIST_KEY);
if (resultColumns != null) {
resultColumns.add(columnDescriptor);
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateProcessor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateProcessor.java
deleted file mode 100644
index 71974d3..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/velocity/SQLTemplateProcessor.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.velocity;
-
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.access.jdbc.ColumnDescriptor;
-import org.apache.cayenne.access.jdbc.ParameterBinding;
-import org.apache.cayenne.access.jdbc.SQLStatement;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.context.InternalContextAdapterImpl;
-import org.apache.velocity.runtime.RuntimeConstants;
-import org.apache.velocity.runtime.RuntimeInstance;
-import org.apache.velocity.runtime.log.NullLogChute;
-import org.apache.velocity.runtime.parser.ParseException;
-import org.apache.velocity.runtime.parser.node.SimpleNode;
-
-/**
- * Processor for SQL velocity templates.
- *
- * @see org.apache.cayenne.query.SQLTemplate
- * @since 4.0
- */
-public class SQLTemplateProcessor {
-
- private static RuntimeInstance sharedRuntime;
-
- static final String BINDINGS_LIST_KEY = "bindings";
- static final String RESULT_COLUMNS_LIST_KEY = "resultColumns";
- static final String HELPER_KEY = "helper";
-
- private static final SQLTemplateRenderingUtils sharedUtils = new SQLTemplateRenderingUtils();
-
- RuntimeInstance velocityRuntime;
- SQLTemplateRenderingUtils renderingUtils;
-
- static {
- initVelocityRuntime();
- }
-
- private static void initVelocityRuntime() {
- // init static velocity engine
- sharedRuntime = new RuntimeInstance();
-
- // set null logger
- sharedRuntime.addProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new NullLogChute());
-
- sharedRuntime.addProperty(RuntimeConstants.RESOURCE_MANAGER_CLASS, SQLTemplateResourceManager.class.getName());
- sharedRuntime.addProperty("userdirective", BindDirective.class.getName());
- sharedRuntime.addProperty("userdirective", BindEqualDirective.class.getName());
- sharedRuntime.addProperty("userdirective", BindNotEqualDirective.class.getName());
- sharedRuntime.addProperty("userdirective", BindObjectEqualDirective.class.getName());
- sharedRuntime.addProperty("userdirective", BindObjectNotEqualDirective.class.getName());
- sharedRuntime.addProperty("userdirective", ResultDirective.class.getName());
- sharedRuntime.addProperty("userdirective", ChainDirective.class.getName());
- sharedRuntime.addProperty("userdirective", ChunkDirective.class.getName());
- try {
- sharedRuntime.init();
- } catch (Exception ex) {
- throw new CayenneRuntimeException("Error setting up Velocity RuntimeInstance.", ex);
- }
- }
-
- public SQLTemplateProcessor() {
- this.velocityRuntime = sharedRuntime;
- this.renderingUtils = sharedUtils;
- }
-
- public SQLTemplateProcessor(RuntimeInstance velocityRuntime, SQLTemplateRenderingUtils renderingUtils) {
- this.velocityRuntime = velocityRuntime;
- this.renderingUtils = renderingUtils;
- }
-
- /**
- * Builds and returns a SQLStatement based on SQL template and a set of
- * parameters. During rendering, VelocityContext exposes the following as
- * variables: all parameters in the map, {@link SQLTemplateRenderingUtils}
- * as a "helper" variable and SQLStatement object as "statement" variable.
- */
- public SQLStatement processTemplate(String template, Map<String, ?> parameters) throws Exception {
- // have to make a copy of parameter map since we are gonna modify it..
- Map<String, Object> internalParameters = (parameters != null && !parameters.isEmpty()) ? new HashMap<String, Object>(
- parameters) : new HashMap<String, Object>(5);
-
- List<ParameterBinding> bindings = new ArrayList<ParameterBinding>();
- List<ColumnDescriptor> results = new ArrayList<ColumnDescriptor>();
- internalParameters.put(BINDINGS_LIST_KEY, bindings);
- internalParameters.put(RESULT_COLUMNS_LIST_KEY, results);
- internalParameters.put(HELPER_KEY, renderingUtils);
-
- String sql = buildStatement(new VelocityContext(internalParameters), template);
-
- ParameterBinding[] bindingsArray = new ParameterBinding[bindings.size()];
- bindings.toArray(bindingsArray);
-
- ColumnDescriptor[] resultsArray = new ColumnDescriptor[results.size()];
- results.toArray(resultsArray);
-
- return new SQLStatement(sql, resultsArray, bindingsArray);
- }
-
- String buildStatement(VelocityContext context, String template) throws Exception {
- // Note: this method is a reworked version of
- // org.apache.velocity.app.Velocity.evaluate(..)
- // cleaned up to avoid using any Velocity singletons
-
- StringWriter out = new StringWriter(template.length());
- SimpleNode nodeTree = null;
-
- try {
- nodeTree = velocityRuntime.parse(new StringReader(template), template);
- } catch (ParseException pex) {
- throw new CayenneRuntimeException("Error parsing template '" + template + "' : " + pex.getMessage());
- }
-
- if (nodeTree == null) {
- throw new CayenneRuntimeException("Error parsing template " + template);
- }
-
- // ... not sure what InternalContextAdapter is for...
- InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
- ica.pushCurrentTemplateName(template);
-
- try {
- nodeTree.init(ica, velocityRuntime);
- nodeTree.render(ica, out);
- return out.toString();
- } finally {
- ica.popCurrentTemplateName();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/main/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor.java b/cayenne-server/src/main/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor.java
new file mode 100644
index 0000000..89e7952
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor.java
@@ -0,0 +1,146 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.access.jdbc.ColumnDescriptor;
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.cayenne.access.jdbc.SQLStatement;
+import org.apache.cayenne.access.jdbc.SQLTemplateProcessor;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.context.InternalContextAdapterImpl;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeInstance;
+import org.apache.velocity.runtime.log.NullLogChute;
+import org.apache.velocity.runtime.parser.ParseException;
+import org.apache.velocity.runtime.parser.node.SimpleNode;
+
+/**
+ * Processor for SQL velocity templates.
+ *
+ * @see org.apache.cayenne.query.SQLTemplate
+ * @since 4.0
+ */
+public class VelocitySQLTemplateProcessor implements SQLTemplateProcessor {
+
+ static final String BINDINGS_LIST_KEY = "bindings";
+ static final String RESULT_COLUMNS_LIST_KEY = "resultColumns";
+ static final String HELPER_KEY = "helper";
+
+ protected RuntimeInstance velocityRuntime;
+ protected SQLTemplateRenderingUtils renderingUtils;
+
+ public VelocitySQLTemplateProcessor() {
+ this.renderingUtils = new SQLTemplateRenderingUtils();
+ this.velocityRuntime = new RuntimeInstance();
+
+ // set null logger
+ velocityRuntime.addProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new NullLogChute());
+
+ velocityRuntime
+ .addProperty(RuntimeConstants.RESOURCE_MANAGER_CLASS, SQLTemplateResourceManager.class.getName());
+ velocityRuntime.addProperty("userdirective", BindDirective.class.getName());
+ velocityRuntime.addProperty("userdirective", BindEqualDirective.class.getName());
+ velocityRuntime.addProperty("userdirective", BindNotEqualDirective.class.getName());
+ velocityRuntime.addProperty("userdirective", BindObjectEqualDirective.class.getName());
+ velocityRuntime.addProperty("userdirective", BindObjectNotEqualDirective.class.getName());
+ velocityRuntime.addProperty("userdirective", ResultDirective.class.getName());
+ velocityRuntime.addProperty("userdirective", ChainDirective.class.getName());
+ velocityRuntime.addProperty("userdirective", ChunkDirective.class.getName());
+ try {
+ velocityRuntime.init();
+ } catch (Exception ex) {
+ throw new CayenneRuntimeException("Error setting up Velocity RuntimeInstance.", ex);
+ }
+
+ }
+
+ /**
+ * Builds and returns a SQLStatement based on SQL template and a set of
+ * parameters. During rendering, VelocityContext exposes the following as
+ * variables: all parameters in the map, {@link SQLTemplateRenderingUtils}
+ * as a "helper" variable and SQLStatement object as "statement" variable.
+ */
+ @Override
+ public SQLStatement processTemplate(String template, Map<String, ?> parameters) {
+ // have to make a copy of parameter map since we are gonna modify it..
+ Map<String, Object> internalParameters = (parameters != null && !parameters.isEmpty()) ? new HashMap<String, Object>(
+ parameters) : new HashMap<String, Object>(5);
+
+ List<ParameterBinding> bindings = new ArrayList<ParameterBinding>();
+ List<ColumnDescriptor> results = new ArrayList<ColumnDescriptor>();
+ internalParameters.put(BINDINGS_LIST_KEY, bindings);
+ internalParameters.put(RESULT_COLUMNS_LIST_KEY, results);
+ internalParameters.put(HELPER_KEY, renderingUtils);
+
+ String sql;
+ try {
+ sql = buildStatement(new VelocityContext(internalParameters), template);
+ } catch (Exception e) {
+ throw new CayenneRuntimeException("Error processing Velocity template", e);
+ }
+
+ ParameterBinding[] bindingsArray = new ParameterBinding[bindings.size()];
+ bindings.toArray(bindingsArray);
+
+ ColumnDescriptor[] resultsArray = new ColumnDescriptor[results.size()];
+ results.toArray(resultsArray);
+
+ return new SQLStatement(sql, resultsArray, bindingsArray);
+ }
+
+ String buildStatement(VelocityContext context, String template) throws Exception {
+ // Note: this method is a reworked version of
+ // org.apache.velocity.app.Velocity.evaluate(..)
+ // cleaned up to avoid using any Velocity singletons
+
+ StringWriter out = new StringWriter(template.length());
+ SimpleNode nodeTree = null;
+
+ try {
+ nodeTree = velocityRuntime.parse(new StringReader(template), template);
+ } catch (ParseException pex) {
+ throw new CayenneRuntimeException("Error parsing template '" + template + "' : " + pex.getMessage());
+ }
+
+ if (nodeTree == null) {
+ throw new CayenneRuntimeException("Error parsing template " + template);
+ }
+
+ // ... not sure what InternalContextAdapter is for...
+ InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
+ ica.pushCurrentTemplateName(template);
+
+ try {
+ nodeTree.init(ica, velocityRuntime);
+ nodeTree.render(ica, out);
+ return out.toString();
+ } finally {
+ ica.popCurrentTemplateName();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
index fbbbce9..69b5164 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/DataDomainProviderTest.java
@@ -18,6 +18,16 @@
****************************************************************/
package org.apache.cayenne.configuration.server;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.util.Collection;
+import java.util.Collections;
+
import org.apache.cayenne.ConfigurationException;
import org.apache.cayenne.DataChannel;
import org.apache.cayenne.access.DataDomain;
@@ -25,6 +35,7 @@ import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.dbsync.SchemaUpdateStrategy;
import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy;
import org.apache.cayenne.access.dbsync.ThrowOnPartialOrCreateSchemaStrategy;
+import org.apache.cayenne.access.jdbc.SQLTemplateProcessor;
import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
import org.apache.cayenne.access.translator.batch.DefaultBatchTranslatorFactory;
@@ -77,178 +88,169 @@ import org.apache.cayenne.resource.ResourceLocator;
import org.apache.cayenne.resource.mock.MockResource;
import org.junit.Test;
-import java.util.Collection;
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
public class DataDomainProviderTest {
- @Test
- public void testGet() {
-
- // create dependencies
- final String testConfigName = "testConfig";
- final DataChannelDescriptor testDescriptor = new DataChannelDescriptor();
-
- DataMap map1 = new DataMap("map1");
- testDescriptor.getDataMaps().add(map1);
-
- DataMap map2 = new DataMap("map2");
- testDescriptor.getDataMaps().add(map2);
-
- DataNodeDescriptor nodeDescriptor1 = new DataNodeDescriptor();
- nodeDescriptor1.setName("node1");
- nodeDescriptor1.getDataMapNames().add("map1");
- nodeDescriptor1.setAdapterType(OracleAdapter.class.getName());
- nodeDescriptor1.setDataSourceFactoryType(MockDataSourceFactory.class.getName());
- nodeDescriptor1.setParameters("jdbc/testDataNode1");
- nodeDescriptor1.setSchemaUpdateStrategyType(ThrowOnPartialOrCreateSchemaStrategy.class.getName());
- testDescriptor.getNodeDescriptors().add(nodeDescriptor1);
-
- DataNodeDescriptor nodeDescriptor2 = new DataNodeDescriptor();
- nodeDescriptor2.setName("node2");
- nodeDescriptor2.getDataMapNames().add("map2");
- nodeDescriptor2.setParameters("testDataNode2.driver.xml");
- testDescriptor.getNodeDescriptors().add(nodeDescriptor2);
-
- final DataChannelDescriptorLoader testLoader = new DataChannelDescriptorLoader() {
-
- @Override
- public ConfigurationTree<DataChannelDescriptor> load(Resource configurationResource)
- throws ConfigurationException {
- return new ConfigurationTree<DataChannelDescriptor>(testDescriptor, null);
- }
- };
-
- final EventManager eventManager = new MockEventManager();
-
- Module testModule = new Module() {
-
- @Override
- public void configure(Binder binder) {
- final ClassLoaderManager classLoaderManager = new DefaultClassLoaderManager();
- binder.bind(ClassLoaderManager.class).toInstance(classLoaderManager);
- binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
-
- binder.bindMap(Constants.PROPERTIES_MAP);
-
- binder.bind(FirebirdSniffer.class).to(FirebirdSniffer.class);
- binder.bind(OpenBaseSniffer.class).to(OpenBaseSniffer.class);
- binder.bind(FrontBaseSniffer.class).to(FrontBaseSniffer.class);
- binder.bind(IngresSniffer.class).to(IngresSniffer.class);
- binder.bind(SQLiteSniffer.class).to(SQLiteSniffer.class);
- binder.bind(DB2Sniffer.class).to(DB2Sniffer.class);
- binder.bind(H2Sniffer.class).to(H2Sniffer.class);
- binder.bind(HSQLDBSniffer.class).to(HSQLDBSniffer.class);
- binder.bind(SybaseSniffer.class).to(SybaseSniffer.class);
- binder.bind(DerbySniffer.class).to(DerbySniffer.class);
- binder.bind(SQLServerSniffer.class).to(SQLServerSniffer.class);
- binder.bind(OracleSniffer.class).to(OracleSniffer.class);
- binder.bind(PostgresSniffer.class).to(PostgresSniffer.class);
- binder.bind(MySQLSniffer.class).to(MySQLSniffer.class);
-
- binder.bindList(Constants.SERVER_ADAPTER_DETECTORS_LIST).add(FirebirdSniffer.class)
- .add(OpenBaseSniffer.class).add(FrontBaseSniffer.class).add(IngresSniffer.class)
- .add(SQLiteSniffer.class).add(DB2Sniffer.class).add(H2Sniffer.class).add(HSQLDBSniffer.class)
- .add(SybaseSniffer.class).add(DerbySniffer.class).add(SQLServerSniffer.class)
- .add(OracleSniffer.class).add(PostgresSniffer.class).add(MySQLSniffer.class);
- binder.bindList(Constants.SERVER_DOMAIN_FILTERS_LIST);
- binder.bindList(Constants.SERVER_PROJECT_LOCATIONS_LIST).add(testConfigName);
-
- // configure extended types
- binder.bindList(Constants.SERVER_DEFAULT_TYPES_LIST);
- binder.bindList(Constants.SERVER_USER_TYPES_LIST);
- binder.bindList(Constants.SERVER_TYPE_FACTORIES_LIST);
-
- binder.bind(EventManager.class).toInstance(eventManager);
- binder.bind(EntitySorter.class).toInstance(new AshwoodEntitySorter());
-
- final ResourceLocator locator = new ClassLoaderResourceLocator(classLoaderManager) {
-
- public Collection<Resource> findResources(String name) {
- // ResourceLocator also used by JdbcAdapter to locate
- // types.xml... if this is the request we are getting,
- // just let
- // it go through..
- if (name.endsWith("types.xml")) {
- return super.findResources(name);
- }
-
- assertEquals(testConfigName, name);
- return Collections.<Resource> singleton(new MockResource());
- }
- };
-
- binder.bind(ResourceLocator.class).toInstance(locator);
- binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
- binder.bind(DataChannelDescriptorMerger.class).to(DefaultDataChannelDescriptorMerger.class);
- binder.bind(DataChannelDescriptorLoader.class).toInstance(testLoader);
- binder.bind(SchemaUpdateStrategy.class).toInstance(new SkipSchemaUpdateStrategy());
- binder.bind(DbAdapterFactory.class).to(DefaultDbAdapterFactory.class);
- binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
- binder.bind(BatchTranslatorFactory.class).to(DefaultBatchTranslatorFactory.class);
-
- binder.bind(DataSourceFactory.class).toInstance(new MockDataSourceFactory());
- binder.bind(JdbcEventLogger.class).to(CommonsJdbcEventLogger.class);
- binder.bind(QueryCache.class).toInstance(mock(QueryCache.class));
- binder.bind(RowReaderFactory.class).toInstance(mock(RowReaderFactory.class));
- binder.bind(DataNodeFactory.class).to(DefaultDataNodeFactory.class);
- }
- };
-
- Injector injector = DIBootstrap.createInjector(testModule);
-
- // create and initialize provide instance to test
- DataDomainProvider provider = new DataDomainProvider();
- injector.injectMembers(provider);
-
- DataChannel channel = provider.get();
- assertNotNull(channel);
-
- assertTrue(channel instanceof DataDomain);
-
- DataDomain domain = (DataDomain) channel;
- assertSame(eventManager, domain.getEventManager());
- assertEquals(2, domain.getDataMaps().size());
- assertTrue(domain.getDataMaps().contains(map1));
- assertTrue(domain.getDataMaps().contains(map2));
-
- assertEquals(2, domain.getDataNodes().size());
- DataNode node1 = domain.getDataNode("node1");
- assertNotNull(node1);
- assertEquals(1, node1.getDataMaps().size());
- assertSame(map1, node1.getDataMaps().iterator().next());
- assertSame(node1, domain.lookupDataNode(map1));
- assertEquals(nodeDescriptor1.getDataSourceFactoryType(), node1.getDataSourceFactory());
- assertNotNull(node1.getDataSource());
- assertEquals(nodeDescriptor1.getParameters(), node1.getDataSourceLocation());
-
- assertEquals(nodeDescriptor1.getSchemaUpdateStrategyType(), node1.getSchemaUpdateStrategyName());
- assertNotNull(node1.getSchemaUpdateStrategy());
- assertEquals(nodeDescriptor1.getSchemaUpdateStrategyType(), node1.getSchemaUpdateStrategy().getClass()
- .getName());
-
- assertNotNull(node1.getAdapter());
- assertEquals(OracleAdapter.class, node1.getAdapter().getClass());
-
- DataNode node2 = domain.getDataNode("node2");
- assertNotNull(node2);
- assertEquals(1, node2.getDataMaps().size());
- assertSame(map2, node2.getDataMaps().iterator().next());
- assertSame(node2, domain.lookupDataNode(map2));
- assertNull(node2.getDataSourceFactory());
- assertNotNull(node2.getDataSource());
- assertEquals(nodeDescriptor2.getParameters(), node2.getDataSourceLocation());
- assertEquals(SkipSchemaUpdateStrategy.class.getName(), node2.getSchemaUpdateStrategyName());
- assertNotNull(node2.getSchemaUpdateStrategy());
- assertEquals(SkipSchemaUpdateStrategy.class.getName(), node2.getSchemaUpdateStrategy().getClass().getName());
-
- assertNotNull(node2.getAdapter());
- }
+ @Test
+ public void testGet() {
+
+ // create dependencies
+ final String testConfigName = "testConfig";
+ final DataChannelDescriptor testDescriptor = new DataChannelDescriptor();
+
+ DataMap map1 = new DataMap("map1");
+ testDescriptor.getDataMaps().add(map1);
+
+ DataMap map2 = new DataMap("map2");
+ testDescriptor.getDataMaps().add(map2);
+
+ DataNodeDescriptor nodeDescriptor1 = new DataNodeDescriptor();
+ nodeDescriptor1.setName("node1");
+ nodeDescriptor1.getDataMapNames().add("map1");
+ nodeDescriptor1.setAdapterType(OracleAdapter.class.getName());
+ nodeDescriptor1.setDataSourceFactoryType(MockDataSourceFactory.class.getName());
+ nodeDescriptor1.setParameters("jdbc/testDataNode1");
+ nodeDescriptor1.setSchemaUpdateStrategyType(ThrowOnPartialOrCreateSchemaStrategy.class.getName());
+ testDescriptor.getNodeDescriptors().add(nodeDescriptor1);
+
+ DataNodeDescriptor nodeDescriptor2 = new DataNodeDescriptor();
+ nodeDescriptor2.setName("node2");
+ nodeDescriptor2.getDataMapNames().add("map2");
+ nodeDescriptor2.setParameters("testDataNode2.driver.xml");
+ testDescriptor.getNodeDescriptors().add(nodeDescriptor2);
+
+ final DataChannelDescriptorLoader testLoader = new DataChannelDescriptorLoader() {
+
+ @Override
+ public ConfigurationTree<DataChannelDescriptor> load(Resource configurationResource)
+ throws ConfigurationException {
+ return new ConfigurationTree<DataChannelDescriptor>(testDescriptor, null);
+ }
+ };
+
+ final EventManager eventManager = new MockEventManager();
+
+ Module testModule = new Module() {
+
+ @Override
+ public void configure(Binder binder) {
+ final ClassLoaderManager classLoaderManager = new DefaultClassLoaderManager();
+ binder.bind(ClassLoaderManager.class).toInstance(classLoaderManager);
+ binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
+
+ binder.bindMap(Constants.PROPERTIES_MAP);
+
+ binder.bind(FirebirdSniffer.class).to(FirebirdSniffer.class);
+ binder.bind(OpenBaseSniffer.class).to(OpenBaseSniffer.class);
+ binder.bind(FrontBaseSniffer.class).to(FrontBaseSniffer.class);
+ binder.bind(IngresSniffer.class).to(IngresSniffer.class);
+ binder.bind(SQLiteSniffer.class).to(SQLiteSniffer.class);
+ binder.bind(DB2Sniffer.class).to(DB2Sniffer.class);
+ binder.bind(H2Sniffer.class).to(H2Sniffer.class);
+ binder.bind(HSQLDBSniffer.class).to(HSQLDBSniffer.class);
+ binder.bind(SybaseSniffer.class).to(SybaseSniffer.class);
+ binder.bind(DerbySniffer.class).to(DerbySniffer.class);
+ binder.bind(SQLServerSniffer.class).to(SQLServerSniffer.class);
+ binder.bind(OracleSniffer.class).to(OracleSniffer.class);
+ binder.bind(PostgresSniffer.class).to(PostgresSniffer.class);
+ binder.bind(MySQLSniffer.class).to(MySQLSniffer.class);
+
+ binder.bindList(Constants.SERVER_ADAPTER_DETECTORS_LIST).add(FirebirdSniffer.class)
+ .add(OpenBaseSniffer.class).add(FrontBaseSniffer.class).add(IngresSniffer.class)
+ .add(SQLiteSniffer.class).add(DB2Sniffer.class).add(H2Sniffer.class).add(HSQLDBSniffer.class)
+ .add(SybaseSniffer.class).add(DerbySniffer.class).add(SQLServerSniffer.class)
+ .add(OracleSniffer.class).add(PostgresSniffer.class).add(MySQLSniffer.class);
+ binder.bindList(Constants.SERVER_DOMAIN_FILTERS_LIST);
+ binder.bindList(Constants.SERVER_PROJECT_LOCATIONS_LIST).add(testConfigName);
+
+ // configure extended types
+ binder.bindList(Constants.SERVER_DEFAULT_TYPES_LIST);
+ binder.bindList(Constants.SERVER_USER_TYPES_LIST);
+ binder.bindList(Constants.SERVER_TYPE_FACTORIES_LIST);
+
+ binder.bind(EventManager.class).toInstance(eventManager);
+ binder.bind(EntitySorter.class).toInstance(new AshwoodEntitySorter());
+
+ final ResourceLocator locator = new ClassLoaderResourceLocator(classLoaderManager) {
+
+ public Collection<Resource> findResources(String name) {
+ // ResourceLocator also used by JdbcAdapter to locate
+ // types.xml... if this is the request we are getting,
+ // just let
+ // it go through..
+ if (name.endsWith("types.xml")) {
+ return super.findResources(name);
+ }
+
+ assertEquals(testConfigName, name);
+ return Collections.<Resource> singleton(new MockResource());
+ }
+ };
+
+ binder.bind(ResourceLocator.class).toInstance(locator);
+ binder.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
+ binder.bind(DataChannelDescriptorMerger.class).to(DefaultDataChannelDescriptorMerger.class);
+ binder.bind(DataChannelDescriptorLoader.class).toInstance(testLoader);
+ binder.bind(SchemaUpdateStrategy.class).toInstance(new SkipSchemaUpdateStrategy());
+ binder.bind(DbAdapterFactory.class).to(DefaultDbAdapterFactory.class);
+ binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
+ binder.bind(BatchTranslatorFactory.class).to(DefaultBatchTranslatorFactory.class);
+
+ binder.bind(DataSourceFactory.class).toInstance(new MockDataSourceFactory());
+ binder.bind(JdbcEventLogger.class).to(CommonsJdbcEventLogger.class);
+ binder.bind(QueryCache.class).toInstance(mock(QueryCache.class));
+ binder.bind(RowReaderFactory.class).toInstance(mock(RowReaderFactory.class));
+ binder.bind(DataNodeFactory.class).to(DefaultDataNodeFactory.class);
+ binder.bind(SQLTemplateProcessor.class).toInstance(mock(SQLTemplateProcessor.class));
+ }
+ };
+
+ Injector injector = DIBootstrap.createInjector(testModule);
+
+ // create and initialize provide instance to test
+ DataDomainProvider provider = new DataDomainProvider();
+ injector.injectMembers(provider);
+
+ DataChannel channel = provider.get();
+ assertNotNull(channel);
+
+ assertTrue(channel instanceof DataDomain);
+
+ DataDomain domain = (DataDomain) channel;
+ assertSame(eventManager, domain.getEventManager());
+ assertEquals(2, domain.getDataMaps().size());
+ assertTrue(domain.getDataMaps().contains(map1));
+ assertTrue(domain.getDataMaps().contains(map2));
+
+ assertEquals(2, domain.getDataNodes().size());
+ DataNode node1 = domain.getDataNode("node1");
+ assertNotNull(node1);
+ assertEquals(1, node1.getDataMaps().size());
+ assertSame(map1, node1.getDataMaps().iterator().next());
+ assertSame(node1, domain.lookupDataNode(map1));
+ assertEquals(nodeDescriptor1.getDataSourceFactoryType(), node1.getDataSourceFactory());
+ assertNotNull(node1.getDataSource());
+ assertEquals(nodeDescriptor1.getParameters(), node1.getDataSourceLocation());
+
+ assertEquals(nodeDescriptor1.getSchemaUpdateStrategyType(), node1.getSchemaUpdateStrategyName());
+ assertNotNull(node1.getSchemaUpdateStrategy());
+ assertEquals(nodeDescriptor1.getSchemaUpdateStrategyType(), node1.getSchemaUpdateStrategy().getClass()
+ .getName());
+
+ assertNotNull(node1.getAdapter());
+ assertEquals(OracleAdapter.class, node1.getAdapter().getClass());
+
+ DataNode node2 = domain.getDataNode("node2");
+ assertNotNull(node2);
+ assertEquals(1, node2.getDataMaps().size());
+ assertSame(map2, node2.getDataMaps().iterator().next());
+ assertSame(node2, domain.lookupDataNode(map2));
+ assertNull(node2.getDataSourceFactory());
+ assertNotNull(node2.getDataSource());
+ assertEquals(nodeDescriptor2.getParameters(), node2.getDataSourceLocation());
+ assertEquals(SkipSchemaUpdateStrategy.class.getName(), node2.getSchemaUpdateStrategyName());
+ assertNotNull(node2.getSchemaUpdateStrategy());
+ assertEquals(SkipSchemaUpdateStrategy.class.getName(), node2.getSchemaUpdateStrategy().getClass().getName());
+
+ assertNotNull(node2.getAdapter());
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataNodeFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataNodeFactory.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataNodeFactory.java
index 7686eae..85ab18f 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataNodeFactory.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataNodeFactory.java
@@ -20,6 +20,7 @@ package org.apache.cayenne.unit.di.server;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy;
+import org.apache.cayenne.access.jdbc.SQLTemplateProcessor;
import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
import org.apache.cayenne.configuration.DataNodeDescriptor;
@@ -44,6 +45,9 @@ public class ServerCaseDataNodeFactory implements DataNodeFactory {
@Inject
private DbAdapter adapter;
+
+ @Inject
+ protected SQLTemplateProcessor sqlTemplateProcessor;
@Override
public DataNode createDataNode(DataNodeDescriptor nodeDescriptor) throws Exception {
@@ -57,6 +61,7 @@ public class ServerCaseDataNodeFactory implements DataNodeFactory {
dataNode.setDataSource(dataSourceFactory.getDataSource(nodeDescriptor.getName()));
dataNode.setAdapter(adapter);
dataNode.setSchemaUpdateStrategy(new SkipSchemaUpdateStrategy());
+ dataNode.setSqlTemplateProcessor(sqlTemplateProcessor);
return dataNode;
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java
index 78e55e8..60f23d6 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/BindDirectiveIT.java
@@ -18,12 +18,22 @@
****************************************************************/
package org.apache.cayenne.velocity;
+import java.sql.Connection;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
import org.apache.cayenne.DataRow;
import org.apache.cayenne.ObjectContext;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.MockOperationObserver;
import org.apache.cayenne.access.jdbc.SQLTemplateAction;
-import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
import org.apache.cayenne.dba.JdbcAdapter;
import org.apache.cayenne.dba.oracle.OracleAdapter;
import org.apache.cayenne.di.Inject;
@@ -37,19 +47,6 @@ import org.apache.cayenne.unit.di.server.ServerCase;
import org.apache.cayenne.unit.di.server.ServerCaseDataSourceFactory;
import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import java.sql.Connection;
-import java.sql.Timestamp;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.mockito.Mockito.mock;
-
/**
* Tests BindDirective for passed null parameters and for not passed parameters
*/
@@ -70,6 +67,9 @@ public class BindDirectiveIT extends ServerCase {
@Inject
private JdbcEventLogger logger;
+
+ @Inject
+ private DataNode node;
@Override
protected void setUpAfterInjection() throws Exception {
@@ -238,10 +238,7 @@ public class BindDirectiveIT extends ServerCase {
template.setParams(parameters);
- DataNode node = new DataNode();
- node.setEntityResolver(context.getEntityResolver());
- node.setRowReaderFactory(mock(RowReaderFactory.class));
- node.setAdapter(adapter);
+
SQLTemplateAction action = new SQLTemplateAction(template, node);
Connection c = dataSourceFactory.getSharedDataSource().getConnection();
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java
index 3c291b8..2e7049b 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/ResultDirectiveIT.java
@@ -18,11 +18,16 @@
****************************************************************/
package org.apache.cayenne.velocity;
+import java.sql.Connection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.apache.cayenne.DataRow;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.access.MockOperationObserver;
import org.apache.cayenne.access.jdbc.SQLTemplateAction;
-import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
import org.apache.cayenne.configuration.server.ServerRuntime;
import org.apache.cayenne.dba.JdbcAdapter;
import org.apache.cayenne.di.Inject;
@@ -34,155 +39,122 @@ 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.sql.Connection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.mockito.Mockito.mock;
-
/**
- * Test for Result directive to check if we could use ResultDitrective optionally.
+ * Test for Result directive to check if we could use ResultDitrective
+ * optionally.
*/
@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
public class ResultDirectiveIT extends ServerCase {
- @Inject
- private ServerRuntime runtime;
-
- @Inject
- private DBHelper dbHelper;
-
- @Inject
- private JdbcAdapter dbAdapter;
-
- @Override
- protected void setUpAfterInjection() throws Exception {
- dbHelper.deleteAll("PAINTING_INFO");
- dbHelper.deleteAll("PAINTING");
- dbHelper.deleteAll("PAINTING1");
- dbHelper.deleteAll("ARTIST_EXHIBIT");
- dbHelper.deleteAll("ARTIST_GROUP");
- dbHelper.deleteAll("ARTIST");
- dbHelper.deleteAll("EXHIBIT");
- dbHelper.deleteAll("GALLERY");
- }
-
- public void testWithoutResultDirective() throws Exception {
- String sql = "SELECT ARTIST_ID, ARTIST_NAME FROM ARTIST";
- Map<String, Object> artist = insertArtist();
- Map<String, Object> selectResult = selectForQuery(sql);
-
- assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
- assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME"));
- }
-
- public void testWithOnlyResultDirective() throws Exception {
- String sql = "SELECT #result('ARTIST_ID' 'java.lang.Integer'),"
- + " #result('ARTIST_NAME' 'java.lang.String')"
- + " FROM ARTIST";
- Map<String, Object> artist = insertArtist();
- Map<String, Object> selectResult = selectForQuery(sql);
-
- assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
- assertEquals(artist.get("ARTIST_NAME"), selectResult
- .get("ARTIST_NAME")
- .toString()
- .trim());
- }
-
- public void testWithMixedDirectiveUse1() throws Exception {
- String sql = "SELECT ARTIST_ID,"
- + " #result('ARTIST_NAME' 'java.lang.String')"
- + " FROM ARTIST";
- Map<String, Object> artist = insertArtist();
- Map<String, Object> selectResult = selectForQuery(sql);
-
- assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
- assertEquals(artist.get("ARTIST_NAME"), selectResult
- .get("ARTIST_NAME")
- .toString()
- .trim());
- }
-
- public void testWithMixedDirectiveUse2() throws Exception {
- String sql = "SELECT #result('ARTIST_ID' 'java.lang.Integer'),"
- + " ARTIST_NAME "
- + " FROM ARTIST";
- Map<String, Object> artist = insertArtist();
- Map<String, Object> selectResult = selectForQuery(sql);
-
- assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
- assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME"));
- }
-
- private Map<String, Object> selectForQuery(String sql) {
- SQLTemplate template = new SQLTemplate(Artist.class, sql);
- template.setColumnNamesCapitalization(CapsStrategy.UPPER);
- MockOperationObserver observer = new MockOperationObserver();
- runtime.getDataDomain().performQueries(
- Collections.singletonList(template),
- observer);
-
- List<Map<String, Object>> data = observer.rowsForQuery(template);
- assertEquals(1, data.size());
- Map<String, Object> row = data.get(0);
- return row;
- }
-
- /**
- * Inserts one Artist
- *
- * @return Inserted Artist as a DataRow
- */
- private Map<String, Object> insertArtist() throws Exception {
- Map<String, Object> parameters = new HashMap<String, Object>();
- parameters.put("id", new Integer(1));
- parameters.put("name", "ArtistToTestResult");
- String templateString = "INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME, DATE_OF_BIRTH) "
- + "VALUES (#bind($id), #bind($name), #bind($dob))";
-
- SQLTemplate template = new SQLTemplate(Object.class, templateString);
-
- template.setParameters(parameters);
-
- DataNode node = new DataNode();
- node.setEntityResolver(runtime.getDataDomain().getEntityResolver());
- node.setRowReaderFactory(mock(RowReaderFactory.class));
- node.setAdapter(dbAdapter);
-
- SQLTemplateAction action = new SQLTemplateAction(template, node);
-
- Connection c = runtime
- .getDataDomain()
- .getDataNodes()
- .iterator()
- .next()
- .getDataSource()
- .getConnection();
- try {
- MockOperationObserver observer = new MockOperationObserver();
- action.performAction(c, observer);
-
- int[] batches = observer.countsForQuery(template);
- assertNotNull(batches);
- assertEquals(1, batches.length);
- assertEquals(1, batches[0]);
- }
- finally {
- c.close();
- }
-
- MockOperationObserver observer = new MockOperationObserver();
- SelectQuery query = new SelectQuery(Artist.class);
- runtime
- .getDataDomain()
- .performQueries(Collections.singletonList(query), observer);
-
- List<?> data = observer.rowsForQuery(query);
- assertEquals(1, data.size());
- DataRow row = (DataRow) data.get(0);
- return row;
- }
+ @Inject
+ private ServerRuntime runtime;
+
+ @Inject
+ private DBHelper dbHelper;
+
+ @Inject
+ private JdbcAdapter dbAdapter;
+
+ @Inject
+ private DataNode node;
+
+ @Override
+ protected void setUpAfterInjection() throws Exception {
+ dbHelper.deleteAll("PAINTING_INFO");
+ dbHelper.deleteAll("PAINTING");
+ dbHelper.deleteAll("PAINTING1");
+ dbHelper.deleteAll("ARTIST_EXHIBIT");
+ dbHelper.deleteAll("ARTIST_GROUP");
+ dbHelper.deleteAll("ARTIST");
+ dbHelper.deleteAll("EXHIBIT");
+ dbHelper.deleteAll("GALLERY");
+ }
+
+ public void testWithoutResultDirective() throws Exception {
+ String sql = "SELECT ARTIST_ID, ARTIST_NAME FROM ARTIST";
+ Map<String, Object> artist = insertArtist();
+ Map<String, Object> selectResult = selectForQuery(sql);
+
+ assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
+ assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME"));
+ }
+
+ public void testWithOnlyResultDirective() throws Exception {
+ String sql = "SELECT #result('ARTIST_ID' 'java.lang.Integer')," + " #result('ARTIST_NAME' 'java.lang.String')"
+ + " FROM ARTIST";
+ Map<String, Object> artist = insertArtist();
+ Map<String, Object> selectResult = selectForQuery(sql);
+
+ assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
+ assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME").toString().trim());
+ }
+
+ public void testWithMixedDirectiveUse1() throws Exception {
+ String sql = "SELECT ARTIST_ID," + " #result('ARTIST_NAME' 'java.lang.String')" + " FROM ARTIST";
+ Map<String, Object> artist = insertArtist();
+ Map<String, Object> selectResult = selectForQuery(sql);
+
+ assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
+ assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME").toString().trim());
+ }
+
+ public void testWithMixedDirectiveUse2() throws Exception {
+ String sql = "SELECT #result('ARTIST_ID' 'java.lang.Integer')," + " ARTIST_NAME " + " FROM ARTIST";
+ Map<String, Object> artist = insertArtist();
+ Map<String, Object> selectResult = selectForQuery(sql);
+
+ assertEquals(artist.get("ARTIST_ID"), selectResult.get("ARTIST_ID"));
+ assertEquals(artist.get("ARTIST_NAME"), selectResult.get("ARTIST_NAME"));
+ }
+
+ private Map<String, Object> selectForQuery(String sql) {
+ SQLTemplate template = new SQLTemplate(Artist.class, sql);
+ template.setColumnNamesCapitalization(CapsStrategy.UPPER);
+ MockOperationObserver observer = new MockOperationObserver();
+ runtime.getDataDomain().performQueries(Collections.singletonList(template), observer);
+
+ List<Map<String, Object>> data = observer.rowsForQuery(template);
+ assertEquals(1, data.size());
+ Map<String, Object> row = data.get(0);
+ return row;
+ }
+
+ /**
+ * Inserts one Artist
+ */
+ private Map<String, Object> insertArtist() throws Exception {
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("id", 1);
+ parameters.put("name", "ArtistToTestResult");
+ String templateString = "INSERT INTO ARTIST (ARTIST_ID, ARTIST_NAME, DATE_OF_BIRTH) "
+ + "VALUES (#bind($id), #bind($name), #bind($dob))";
+
+ SQLTemplate template = new SQLTemplate(Object.class, templateString);
+
+ template.setParams(parameters);
+
+ SQLTemplateAction action = new SQLTemplateAction(template, node);
+
+ Connection c = runtime.getDataDomain().getDataNodes().iterator().next().getDataSource().getConnection();
+ try {
+ MockOperationObserver observer = new MockOperationObserver();
+ action.performAction(c, observer);
+
+ int[] batches = observer.countsForQuery(template);
+ assertNotNull(batches);
+ assertEquals(1, batches.length);
+ assertEquals(1, batches[0]);
+ } finally {
+ c.close();
+ }
+
+ MockOperationObserver observer = new MockOperationObserver();
+ SelectQuery query = new SelectQuery(Artist.class);
+ runtime.getDataDomain().performQueries(Collections.singletonList(query), observer);
+
+ List<?> data = observer.rowsForQuery(query);
+ assertEquals(1, data.size());
+ DataRow row = (DataRow) data.get(0);
+ return row;
+ }
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorChainTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorChainTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorChainTest.java
deleted file mode 100644
index d0e812a..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorChainTest.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.velocity;
-
-import org.apache.cayenne.access.jdbc.SQLStatement;
-import org.apache.cayenne.velocity.SQLTemplateProcessor;
-import org.junit.Test;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-public class SQLTemplateProcessorChainTest {
-
- @Test
- public void testProcessTemplateNoChunks() throws Exception {
- // whatever is inside the chain, it should render as empty if there
- // is no chunks...
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- "#chain(' AND ') #end",
- Collections.EMPTY_MAP);
-
- assertEquals("", compiled.getSql());
-
- compiled = new SQLTemplateProcessor().processTemplate(
- "#chain(' AND ') garbage #end",
- Collections.EMPTY_MAP);
-
- assertEquals("", compiled.getSql());
-
- compiled = new SQLTemplateProcessor().processTemplate(
- "#chain(' AND ' 'PREFIX') #end",
- Collections.EMPTY_MAP);
-
- assertEquals("", compiled.getSql());
- compiled = new SQLTemplateProcessor().processTemplate(
- "#chain(' AND ' 'PREFIX') garbage #end",
- Collections.EMPTY_MAP);
-
- assertEquals("", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateFullChain() throws Exception {
- String template = "#chain(' OR ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("b", "[B]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("[A] OR [B] OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateFullChainAndPrefix() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("b", "[B]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] OR [B] OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplatePartialChainMiddle() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplatePartialChainStart() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("b", "[B]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [B] OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplatePartialChainEnd() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("b", "[B]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] OR [B]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateChainWithGarbage() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + " some other stuff"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", "[A]");
- map.put("c", "[C]");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] some other stuff OR [C]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateChainUnconditionalChunks() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk()C1#end"
- + "#chunk()C2#end"
- + "#chunk()C3#end"
- + "#end";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- template,
- Collections.EMPTY_MAP);
- assertEquals("WHERE C1 OR C2 OR C3", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateEmptyChain() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- template,
- Collections.EMPTY_MAP);
- assertEquals("", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateWithFalseOrZero1() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)[A]#end"
- + "#chunk($b)[B]#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", false);
- map.put("b", 0);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE [A] OR [B]", compiled.getSql());
- }
-
- @Test
- public void testProcessTemplateWithFalseOrZero2() throws Exception {
- String template = "#chain(' OR ' 'WHERE ')"
- + "#chunk($a)$a#end"
- + "#chunk($b)$b#end"
- + "#chunk($c)$c#end"
- + "#end";
-
- Map map = new HashMap();
- map.put("a", false);
- map.put("b", 0);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(template, map);
- assertEquals("WHERE false OR 0", compiled.getSql());
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorSelectTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorSelectTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorSelectTest.java
deleted file mode 100644
index 3481982..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorSelectTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.velocity;
-
-import org.apache.cayenne.access.jdbc.ColumnDescriptor;
-import org.apache.cayenne.access.jdbc.SQLStatement;
-import org.apache.cayenne.velocity.SQLTemplateProcessor;
-import org.junit.Test;
-
-import java.util.Collections;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-public class SQLTemplateProcessorSelectTest {
-
- @Test
- public void testProcessTemplateUnchanged() throws Exception {
- String sqlTemplate = "SELECT * FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals(sqlTemplate, compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- assertEquals(0, compiled.getResultColumns().length);
- }
-
- @Test
- public void testProcessSelectTemplate1() throws Exception {
- String sqlTemplate = "SELECT #result('A') FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT A FROM ME", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- assertEquals(1, compiled.getResultColumns().length);
- assertEquals("A", compiled.getResultColumns()[0].getName());
- assertNull(compiled.getResultColumns()[0].getJavaClass());
- }
-
- @Test
- public void testProcessSelectTemplate2() throws Exception {
- String sqlTemplate = "SELECT #result('A' 'String') FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT A FROM ME", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- assertEquals(1, compiled.getResultColumns().length);
- assertEquals("A", compiled.getResultColumns()[0].getName());
- assertEquals("java.lang.String", compiled.getResultColumns()[0].getJavaClass());
- }
-
- @Test
- public void testProcessSelectTemplate3() throws Exception {
- String sqlTemplate = "SELECT #result('A' 'String' 'B') FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT A AS B FROM ME", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- assertEquals(1, compiled.getResultColumns().length);
- ColumnDescriptor column = compiled.getResultColumns()[0];
- assertEquals("A", column.getName());
- assertEquals("B", column.getDataRowKey());
- assertEquals("java.lang.String", column.getJavaClass());
- }
-
- @Test
- public void testProcessSelectTemplate4() throws Exception {
- String sqlTemplate = "SELECT #result('A'), #result('B'), #result('C') FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(
- sqlTemplate,
- Collections.EMPTY_MAP);
-
- assertEquals("SELECT A, B, C FROM ME", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- assertEquals(3, compiled.getResultColumns().length);
- assertEquals("A", compiled.getResultColumns()[0].getName());
- assertEquals("B", compiled.getResultColumns()[1].getName());
- assertEquals("C", compiled.getResultColumns()[2].getName());
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorTest.java
deleted file mode 100644
index 89f48dc..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/velocity/SQLTemplateProcessorTest.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ****************************************************************/
-
-package org.apache.cayenne.velocity;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.sql.Types;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.DataObject;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.access.jdbc.ParameterBinding;
-import org.apache.cayenne.access.jdbc.SQLStatement;
-import org.junit.Test;
-
-public class SQLTemplateProcessorTest {
-
- @Test
- public void testProcessTemplateUnchanged1() throws Exception {
- String sqlTemplate = "SELECT * FROM ME";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate,
- Collections.<String, Object> emptyMap());
-
- assertEquals(sqlTemplate, compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- }
-
- @Test
- public void testProcessTemplateUnchanged2() throws Exception {
- String sqlTemplate = "SELECT a.b as XYZ FROM $SYSTEM_TABLE";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate,
- Collections.<String, Object> emptyMap());
-
- assertEquals(sqlTemplate, compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- }
-
- @Test
- public void testProcessTemplateSimpleDynamicContent() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE $a";
-
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE VALUE_OF_A", compiled.getSql());
-
- // bindings are not populated, since no "bind" macro is used.
- assertEquals(0, compiled.getBindings().length);
- }
-
- @Test
- public void testProcessTemplateBind() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE "
- + "COLUMN1 = #bind($a 'VARCHAR') AND COLUMN2 = #bind($b 'INTEGER')";
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN1 = ? AND COLUMN2 = ?", compiled.getSql());
- assertEquals(2, compiled.getBindings().length);
- assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
- assertBindingValue(null, compiled.getBindings()[1]);
- }
-
- @Test
- public void testProcessTemplateBindGuessVarchar() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($a)";
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals(1, compiled.getBindings().length);
- assertBindingType(Types.VARCHAR, compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateBindGuessInteger() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($a)";
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", 4);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals(1, compiled.getBindings().length);
- assertBindingType(Types.INTEGER, compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateBindEqual() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN #bindEqual($a 'VARCHAR')";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate,
- Collections.<String, Object> emptyMap());
-
- assertEquals("SELECT * FROM ME WHERE COLUMN IS NULL", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
-
- compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN = ?", compiled.getSql());
- assertEquals(1, compiled.getBindings().length);
- assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateBindNotEqual() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN #bindNotEqual($a 'VARCHAR')";
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate,
- Collections.<String, Object> emptyMap());
-
- assertEquals("SELECT * FROM ME WHERE COLUMN IS NOT NULL", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
-
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
-
- compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN <> ?", compiled.getSql());
- assertEquals(1, compiled.getBindings().length);
- assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateID() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($helper.cayenneExp($a, 'db:ID_COLUMN'))";
-
- DataObject dataObject = new CayenneDataObject();
- dataObject.setObjectId(new ObjectId("T", "ID_COLUMN", 5));
-
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", dataObject);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN1 = ?", compiled.getSql());
- assertEquals(1, compiled.getBindings().length);
- assertBindingValue(new Integer(5), compiled.getBindings()[0]);
- }
-
- @Test
- public void testProcessTemplateNotEqualID() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE "
- + "COLUMN1 #bindNotEqual($helper.cayenneExp($a, 'db:ID_COLUMN1')) "
- + "AND COLUMN2 #bindNotEqual($helper.cayenneExp($a, 'db:ID_COLUMN2'))";
-
- Map<String, Object> idMap = new HashMap<String, Object>();
- idMap.put("ID_COLUMN1", new Integer(3));
- idMap.put("ID_COLUMN2", "aaa");
- ObjectId id = new ObjectId("T", idMap);
- DataObject dataObject = new CayenneDataObject();
- dataObject.setObjectId(id);
-
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", dataObject);
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN1 <> ? AND COLUMN2 <> ?", compiled.getSql());
- assertEquals(2, compiled.getBindings().length);
- assertBindingValue(new Integer(3), compiled.getBindings()[0]);
- assertBindingValue("aaa", compiled.getBindings()[1]);
- }
-
- @Test
- public void testProcessTemplateConditions() throws Exception {
- String sqlTemplate = "SELECT * FROM ME #if($a) WHERE COLUMN1 > #bind($a)#end";
-
- Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
-
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN1 > ?", compiled.getSql());
- assertEquals(1, compiled.getBindings().length);
- assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
-
- compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
-
- assertEquals("SELECT * FROM ME ", compiled.getSql());
- assertEquals(0, compiled.getBindings().length);
- }
-
- @Test
- public void testProcessTemplateBindCollection() throws Exception {
- String sqlTemplate = "SELECT * FROM ME WHERE COLUMN IN (#bind($list 'VARCHAR'))";
-
- Map<String, Object> map = Collections.<String, Object> singletonMap("list", Arrays.asList("a", "b", "c"));
- SQLStatement compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
-
- assertEquals("SELECT * FROM ME WHERE COLUMN IN (?,?,?)", compiled.getSql());
- assertEquals(3, compiled.getBindings().length);
-
- compiled = new SQLTemplateProcessor().processTemplate(sqlTemplate, map);
- assertBindingValue("a", compiled.getBindings()[0]);
- assertBindingValue("b", compiled.getBindings()[1]);
- assertBindingValue("c", compiled.getBindings()[2]);
- }
-
- protected void assertBindingValue(Object expectedValue, Object binding) {
- assertTrue("Not a binding!", binding instanceof ParameterBinding);
- assertEquals(expectedValue, ((ParameterBinding) binding).getValue());
- }
-
- protected void assertBindingType(int expectedType, Object binding) {
- assertTrue("Not a binding!", binding instanceof ParameterBinding);
- assertEquals(expectedType, ((ParameterBinding) binding).getJdbcType());
- }
-
- protected void assertBindingPrecision(int expectedPrecision, Object binding) {
- assertTrue("Not a binding!", binding instanceof ParameterBinding);
- assertEquals(expectedPrecision, ((ParameterBinding) binding).getScale());
- }
-}
[4/6] CAY-1966 SQLTemplate/SQLSelect positional parameter binding
Posted by aa...@apache.org.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessorTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessorTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessorTest.java
new file mode 100644
index 0000000..f21e0f3
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessorTest.java
@@ -0,0 +1,234 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Types;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cayenne.CayenneDataObject;
+import org.apache.cayenne.DataObject;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.access.jdbc.ParameterBinding;
+import org.apache.cayenne.access.jdbc.SQLStatement;
+import org.junit.Before;
+import org.junit.Test;
+
+public class VelocitySQLTemplateProcessorTest {
+
+ private VelocitySQLTemplateProcessor processor;
+
+ @Before
+ public void before() {
+ processor = new VelocitySQLTemplateProcessor();
+ }
+
+ @Test
+ public void testProcessTemplateUnchanged1() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals(sqlTemplate, compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ }
+
+ @Test
+ public void testProcessTemplateUnchanged2() throws Exception {
+ String sqlTemplate = "SELECT a.b as XYZ FROM $SYSTEM_TABLE";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals(sqlTemplate, compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ }
+
+ @Test
+ public void testProcessTemplateSimpleDynamicContent() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE $a";
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE VALUE_OF_A", compiled.getSql());
+
+ // bindings are not populated, since no "bind" macro is used.
+ assertEquals(0, compiled.getBindings().length);
+ }
+
+ @Test
+ public void testProcessTemplateBind() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE "
+ + "COLUMN1 = #bind($a 'VARCHAR') AND COLUMN2 = #bind($b 'INTEGER')";
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN1 = ? AND COLUMN2 = ?", compiled.getSql());
+ assertEquals(2, compiled.getBindings().length);
+ assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
+ assertBindingValue(null, compiled.getBindings()[1]);
+ }
+
+ @Test
+ public void testProcessTemplateBindGuessVarchar() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($a)";
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingType(Types.VARCHAR, compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateBindGuessInteger() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($a)";
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", 4);
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingType(Types.INTEGER, compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateBindEqual() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN #bindEqual($a 'VARCHAR')";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN IS NULL", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+
+ compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN = ?", compiled.getSql());
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateBindNotEqual() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN #bindNotEqual($a 'VARCHAR')";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN IS NOT NULL", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+
+ compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN <> ?", compiled.getSql());
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateID() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN1 = #bind($helper.cayenneExp($a, 'db:ID_COLUMN'))";
+
+ DataObject dataObject = new CayenneDataObject();
+ dataObject.setObjectId(new ObjectId("T", "ID_COLUMN", 5));
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", dataObject);
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN1 = ?", compiled.getSql());
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingValue(new Integer(5), compiled.getBindings()[0]);
+ }
+
+ @Test
+ public void testProcessTemplateNotEqualID() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE "
+ + "COLUMN1 #bindNotEqual($helper.cayenneExp($a, 'db:ID_COLUMN1')) "
+ + "AND COLUMN2 #bindNotEqual($helper.cayenneExp($a, 'db:ID_COLUMN2'))";
+
+ Map<String, Object> idMap = new HashMap<String, Object>();
+ idMap.put("ID_COLUMN1", new Integer(3));
+ idMap.put("ID_COLUMN2", "aaa");
+ ObjectId id = new ObjectId("T", idMap);
+ DataObject dataObject = new CayenneDataObject();
+ dataObject.setObjectId(id);
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", dataObject);
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN1 <> ? AND COLUMN2 <> ?", compiled.getSql());
+ assertEquals(2, compiled.getBindings().length);
+ assertBindingValue(new Integer(3), compiled.getBindings()[0]);
+ assertBindingValue("aaa", compiled.getBindings()[1]);
+ }
+
+ @Test
+ public void testProcessTemplateConditions() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME #if($a) WHERE COLUMN1 > #bind($a)#end";
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("a", "VALUE_OF_A");
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN1 > ?", compiled.getSql());
+ assertEquals(1, compiled.getBindings().length);
+ assertBindingValue("VALUE_OF_A", compiled.getBindings()[0]);
+
+ compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT * FROM ME ", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ }
+
+ @Test
+ public void testProcessTemplateBindCollection() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME WHERE COLUMN IN (#bind($list 'VARCHAR'))";
+
+ Map<String, Object> map = Collections.<String, Object> singletonMap("list", Arrays.asList("a", "b", "c"));
+ SQLStatement compiled = new VelocitySQLTemplateProcessor().processTemplate(sqlTemplate, map);
+
+ assertEquals("SELECT * FROM ME WHERE COLUMN IN (?,?,?)", compiled.getSql());
+ assertEquals(3, compiled.getBindings().length);
+
+ compiled = processor.processTemplate(sqlTemplate, map);
+ assertBindingValue("a", compiled.getBindings()[0]);
+ assertBindingValue("b", compiled.getBindings()[1]);
+ assertBindingValue("c", compiled.getBindings()[2]);
+ }
+
+ private void assertBindingValue(Object expectedValue, Object binding) {
+ assertTrue("Not a binding!", binding instanceof ParameterBinding);
+ assertEquals(expectedValue, ((ParameterBinding) binding).getValue());
+ }
+
+ private void assertBindingType(int expectedType, Object binding) {
+ assertTrue("Not a binding!", binding instanceof ParameterBinding);
+ assertEquals(expectedType, ((ParameterBinding) binding).getJdbcType());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor_ChainTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor_ChainTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor_ChainTest.java
new file mode 100644
index 0000000..6bbc271
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor_ChainTest.java
@@ -0,0 +1,184 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cayenne.access.jdbc.SQLStatement;
+import org.junit.Before;
+import org.junit.Test;
+
+public class VelocitySQLTemplateProcessor_ChainTest {
+
+ private VelocitySQLTemplateProcessor processor;
+
+ @Before
+ public void before() {
+ processor = new VelocitySQLTemplateProcessor();
+ }
+
+ @Test
+ public void testProcessTemplateNoChunks() throws Exception {
+ // whatever is inside the chain, it should render as empty if there
+ // is no chunks...
+
+ SQLStatement compiled = processor.processTemplate("#chain(' AND ') #end",
+ Collections.<String, Object> emptyMap());
+ assertEquals("", compiled.getSql());
+
+ compiled = processor.processTemplate("#chain(' AND ') garbage #end", Collections.<String, Object> emptyMap());
+ assertEquals("", compiled.getSql());
+
+ compiled = processor.processTemplate("#chain(' AND ' 'PREFIX') #end", Collections.<String, Object> emptyMap());
+
+ assertEquals("", compiled.getSql());
+ compiled = processor.processTemplate("#chain(' AND ' 'PREFIX') garbage #end",
+ Collections.<String, Object> emptyMap());
+
+ assertEquals("", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateFullChain() throws Exception {
+ String template = "#chain(' OR ')" + "#chunk($a)$a#end" + "#chunk($b)$b#end" + "#chunk($c)$c#end" + "#end";
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("a", "[A]");
+ map.put("b", "[B]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = processor.processTemplate(template, map);
+ assertEquals("[A] OR [B] OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateFullChainAndPrefix() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk($a)$a#end" + "#chunk($b)$b#end" + "#chunk($c)$c#end"
+ + "#end";
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("a", "[A]");
+ map.put("b", "[B]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = processor.processTemplate(template, map);
+ assertEquals("WHERE [A] OR [B] OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplatePartialChainMiddle() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk($a)$a#end" + "#chunk($b)$b#end" + "#chunk($c)$c#end"
+ + "#end";
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("a", "[A]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = processor.processTemplate(template, map);
+ assertEquals("WHERE [A] OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplatePartialChainStart() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk($a)$a#end" + "#chunk($b)$b#end" + "#chunk($c)$c#end"
+ + "#end";
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("b", "[B]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = processor.processTemplate(template, map);
+ assertEquals("WHERE [B] OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplatePartialChainEnd() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk($a)$a#end" + "#chunk($b)$b#end" + "#chunk($c)$c#end"
+ + "#end";
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("a", "[A]");
+ map.put("b", "[B]");
+
+ SQLStatement compiled = processor.processTemplate(template, map);
+ assertEquals("WHERE [A] OR [B]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateChainWithGarbage() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk($a)$a#end" + " some other stuff" + "#chunk($c)$c#end"
+ + "#end";
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("a", "[A]");
+ map.put("c", "[C]");
+
+ SQLStatement compiled = processor.processTemplate(template, map);
+ assertEquals("WHERE [A] some other stuff OR [C]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateChainUnconditionalChunks() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk()C1#end" + "#chunk()C2#end" + "#chunk()C3#end" + "#end";
+
+ SQLStatement compiled = processor.processTemplate(template, Collections.<String, Object> emptyMap());
+ assertEquals("WHERE C1 OR C2 OR C3", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateEmptyChain() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk($a)$a#end" + "#chunk($b)$b#end" + "#chunk($c)$c#end"
+ + "#end";
+
+ SQLStatement compiled = processor.processTemplate(template, Collections.<String, Object> emptyMap());
+ assertEquals("", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateWithFalseOrZero1() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk($a)[A]#end" + "#chunk($b)[B]#end" + "#chunk($c)$c#end"
+ + "#end";
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("a", false);
+ map.put("b", 0);
+
+ SQLStatement compiled = processor.processTemplate(template, map);
+ assertEquals("WHERE [A] OR [B]", compiled.getSql());
+ }
+
+ @Test
+ public void testProcessTemplateWithFalseOrZero2() throws Exception {
+ String template = "#chain(' OR ' 'WHERE ')" + "#chunk($a)$a#end" + "#chunk($b)$b#end" + "#chunk($c)$c#end"
+ + "#end";
+
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("a", false);
+ map.put("b", 0);
+
+ SQLStatement compiled = processor.processTemplate(template, map);
+ assertEquals("WHERE false OR 0", compiled.getSql());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/5aedf54e/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor_SelectTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor_SelectTest.java b/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor_SelectTest.java
new file mode 100644
index 0000000..74a4d22
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/velocity/VelocitySQLTemplateProcessor_SelectTest.java
@@ -0,0 +1,109 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.velocity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Collections;
+
+import org.apache.cayenne.access.jdbc.ColumnDescriptor;
+import org.apache.cayenne.access.jdbc.SQLStatement;
+import org.junit.Before;
+import org.junit.Test;
+
+public class VelocitySQLTemplateProcessor_SelectTest {
+
+ private VelocitySQLTemplateProcessor processor;
+
+ @Before
+ public void before() {
+ processor = new VelocitySQLTemplateProcessor();
+ }
+
+ @Test
+ public void testProcessTemplateUnchanged() throws Exception {
+ String sqlTemplate = "SELECT * FROM ME";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals(sqlTemplate, compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ assertEquals(0, compiled.getResultColumns().length);
+ }
+
+ @Test
+ public void testProcessSelectTemplate1() throws Exception {
+ String sqlTemplate = "SELECT #result('A') FROM ME";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT A FROM ME", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+ assertEquals(1, compiled.getResultColumns().length);
+ assertEquals("A", compiled.getResultColumns()[0].getName());
+ assertNull(compiled.getResultColumns()[0].getJavaClass());
+ }
+
+ @Test
+ public void testProcessSelectTemplate2() throws Exception {
+ String sqlTemplate = "SELECT #result('A' 'String') FROM ME";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT A FROM ME", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ assertEquals(1, compiled.getResultColumns().length);
+ assertEquals("A", compiled.getResultColumns()[0].getName());
+ assertEquals("java.lang.String", compiled.getResultColumns()[0].getJavaClass());
+ }
+
+ @Test
+ public void testProcessSelectTemplate3() throws Exception {
+ String sqlTemplate = "SELECT #result('A' 'String' 'B') FROM ME";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT A AS B FROM ME", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ assertEquals(1, compiled.getResultColumns().length);
+ ColumnDescriptor column = compiled.getResultColumns()[0];
+ assertEquals("A", column.getName());
+ assertEquals("B", column.getDataRowKey());
+ assertEquals("java.lang.String", column.getJavaClass());
+ }
+
+ @Test
+ public void testProcessSelectTemplate4() throws Exception {
+ String sqlTemplate = "SELECT #result('A'), #result('B'), #result('C') FROM ME";
+
+ SQLStatement compiled = processor.processTemplate(sqlTemplate, Collections.<String, Object> emptyMap());
+
+ assertEquals("SELECT A, B, C FROM ME", compiled.getSql());
+ assertEquals(0, compiled.getBindings().length);
+
+ assertEquals(3, compiled.getResultColumns().length);
+ assertEquals("A", compiled.getResultColumns()[0].getName());
+ assertEquals("B", compiled.getResultColumns()[1].getName());
+ assertEquals("C", compiled.getResultColumns()[2].getName());
+ }
+}