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 <[email protected]> Authored: Sun Nov 2 15:49:38 2014 +0300 Committer: aadamchik <[email protected]> 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()); - } -}
