1 /* 2 * Copyright 2016-2024 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package org.mybatis.dynamic.sql.render; 17 18 import java.util.concurrent.atomic.AtomicInteger; 19 20 import org.mybatis.dynamic.sql.BindableColumn; 21 22 /** 23 * A rendering strategy is used to generate a platform specific binding. 24 * 25 * <p>Rendering strategies are used during the rendering phase of statement generation. 26 * All generated SQL statements include the generated statement itself, and a map of parameters that 27 * should be bound to the statement at execution time. For example, a generated select statement may 28 * look like this when rendered for MyBatis: 29 * 30 * <p><code>select foo from bar where id = #{parameters.p1,jdbcType=INTEGER}</code> 31 * 32 * <p>In this case, the binding is <code>#{parameters.p1,jdbcType=INTEGER}</code>. MyBatis knows how to interpret this 33 * binding - it will look for a value in the <code>parameters.p1</code> property of the parameter object 34 * passed to the statement and bind it as a prepared statement parameter when executing the statement. 35 */ 36 public abstract class RenderingStrategy { 37 public static final String DEFAULT_PARAMETER_PREFIX = "parameters"; //$NON-NLS-1$ 38 39 public String formatParameterMapKey(AtomicInteger sequence) { 40 return "p" + sequence.getAndIncrement(); //$NON-NLS-1$ 41 } 42 43 /** 44 * This method generates a binding for a parameter to a placeholder in a generated SQL statement. 45 * 46 * <p>This binding is appropriate when there can be a mapping between a parameter and a known target column, 47 * In MyBatis, the binding can specify type information based on the column. The bindings are specific 48 * to the target framework. 49 * 50 * <p>For MyBatis, a binding looks like this: "#{prefix.parameterName,jdbcType=xxx,typeHandler=xxx,javaType=xxx}" 51 * 52 * <p>For Spring, a binding looks like this: ":parameterName" 53 * 54 * @param column column definition used for generating type details in a MyBatis binding. Ignored for Spring. 55 * @param prefix parameter prefix used for locating the parameters in a SQL provider object. Typically, will be 56 * {@link RenderingStrategy#DEFAULT_PARAMETER_PREFIX}. This is ignored for Spring. 57 * @param parameterName name of the parameter. Typically generated by calling 58 * {@link RenderingStrategy#formatParameterMapKey(AtomicInteger)} 59 * @return the generated binding 60 */ 61 public abstract String getFormattedJdbcPlaceholder(BindableColumn<?> column, String prefix, String parameterName); 62 63 /** 64 * This method generates a binding for a parameter to a placeholder in a generated SQL statement. 65 * 66 * <p>This binding is appropriate when the parameter is bound to placeholder that is not a known column (such as 67 * a limit or offset parameter). The bindings are specific to the target framework. 68 * 69 * <p>For MyBatis, a binding looks like this: "#{prefix.parameterName}" 70 * 71 * <p>For Spring, a binding looks like this: ":parameterName" 72 * 73 * @param prefix parameter prefix used for locating the parameters in a SQL provider object. Typically, will be 74 * {@link RenderingStrategy#DEFAULT_PARAMETER_PREFIX}. This is ignored for Spring. 75 * @param parameterName name of the parameter. Typically generated by calling 76 * {@link RenderingStrategy#formatParameterMapKey(AtomicInteger)} 77 * @return the generated binding 78 */ 79 public abstract String getFormattedJdbcPlaceholder(String prefix, String parameterName); 80 81 /** 82 * This method generates a binding for a parameter to a placeholder in a row based insert statement. 83 * 84 * <p>This binding is specifically for use with insert, batch insert, and multirow insert statements. 85 * These statements bind parameters to properties of a row class. The Spring implementation changes the binding 86 * to match values expected for a these insert statements. For MyBatis, the binding is the same 87 * as {@link RenderingStrategy#getFormattedJdbcPlaceholder(BindableColumn, String, String)}. 88 * 89 * <p>For MyBatis, a binding looks like this: "#{prefix.parameterName,jdbcType=xxx,typeHandler=xxx,javaType=xxx}" 90 * 91 * <p>For Spring, a binding looks like this: ":prefix.parameterName" 92 * 93 * @param column column definition used for generating type details in a MyBatis binding. Ignored for Spring. 94 * @param prefix parameter prefix used for locating the parameters in a SQL provider object. Typically, will be 95 * either "row" or "records[x]" to match the properties of the generated statement object class. 96 * @param parameterName name of the parameter. Typically, this is a property in the row class associated with the 97 * insert statement. 98 * @return the generated binding 99 */ 100 public String getRecordBasedInsertBinding(BindableColumn<?> column, String prefix, String parameterName) { 101 return getFormattedJdbcPlaceholder(column, prefix, parameterName); 102 } 103 104 /** 105 * This method generates a binding for a parameter to a placeholder in a row based insert statement. 106 * 107 * <p>This binding is specifically for use with insert, batch insert, and multirow insert statements and the 108 * MapToRow mapping. These statements bind parameters to the row class directly. 109 * 110 * <p>For MyBatis, a binding looks like this: "#{parameterName,jdbcType=xxx,typeHandler=xxx,javaType=xxx}" 111 * 112 * <p>For Spring, a binding looks like this: ":parameterName" 113 * 114 * @param column column definition used for generating type details in a MyBatis binding. Ignored for Spring. 115 * @param parameterName name of the parameter. Typically, will be 116 * either "row" or "records[x]" to match the properties of the generated statement object class. 117 * @return the generated binding 118 */ 119 public abstract String getRecordBasedInsertBinding(BindableColumn<?> column, String parameterName); 120 }