@@ -101,7 +101,7 @@ for integrating with template engine provide by Thymeleaf.
101
101
* Can read an SQL template from a Thymeleaf template file on classpath
102
102
* Can use a custom dialect(attribute tag and expression utility method) on your SQL template
103
103
* Can fully customize a template engine configuration
104
-
104
+ * Can generate the SQL from SQL template without the MyBatis core module (since 1.0.2)
105
105
106
106
== Requirements
107
107
@@ -743,7 +743,7 @@ configuration.setVariables(variables);
743
743
[source,sql]
744
744
.SQL template
745
745
----
746
- SELECT * FROM /*[( ${tableNameOfUser} ?: 'users') ]*/ users -- <2>
746
+ SELECT * FROM /*[# th:utext=" ${tableNameOfUser} ?: 'users'" ]*/ users /*[/]*/ -- <2>
747
747
----
748
748
749
749
<1> Define an any property as MyBatis's configuration properties
@@ -783,17 +783,16 @@ This configuration is optional. The non 2-way SQL can be use on the 2-way SQL mo
783
783
use2way = false # <1>
784
784
----
785
785
786
- or
786
+ <1> Set the `use2way` to `false`
787
787
788
788
[source,java]
789
789
.How to configure using config class
790
790
----
791
791
configuration.getLanguageRegistry().register(new ThymeleafLanguageDriver(
792
- ThymeleafLanguageDriverConfig.newInstance(c -> c.setUse2Way(false)))); // <2 >
792
+ ThymeleafLanguageDriverConfig.newInstance(c -> c.setUse2Way(false)))); // <1 >
793
793
----
794
794
795
- <1> Set the `use2way` to `false`
796
- <2> Set the `use2way` property to `false`
795
+ <1> Set the `use2way` property of `ThymeleafLanguageDriverConfig` to `false`
797
796
798
797
799
798
=== Basic usage
@@ -990,6 +989,174 @@ using <<Configuration properties, Configuration properties>>.
990
989
AND firstName LIKE #{patternFirstName} ESCAPE '\'
991
990
----
992
991
992
+ == Using SQL Generator
993
+
994
+ Since 1.0.2, we separate the SQL generating feature from the `ThymeleafLanguageDriver` and `ThymeleafSqlSource` class,
995
+ we added the `SqlGenerator` and `SqlGeneratorConfig` for generating SQL from SQL template.
996
+ These classes **does not depends on the MyBatis core module**(`mybatis-3.x.x.jar`).
997
+ So that, it also can be used in combination with any data access libraries(e.g. Spring JDBC, JPA, R2DBC, etc...) that provide with named parameter.
998
+
999
+ === Configuration
1000
+
1001
+ By default, the `SqlGenerator` applies settings for using together with the MyBatis core module(apply to `#{...}` as the bind variable format),
1002
+ but you can customize a default settings using configuration properties file or the `SqlGeneratorConfig`.
1003
+ The `SqlGeneratorConfig` allows the same configurations as the `ThymeleafLanguageDriverConfig` except the `TemplateFilePathProvider`(`template-file.path-provider.*`).
1004
+
1005
+ ==== Customize the bind variable format
1006
+
1007
+ You can customize the bind variable format using configuration properties file or configuration class.
1008
+ In the following example, it changes the bind variable format to the Spring JDBC format(e.g. `:id`) from MyBatis core format(e.g. `#{id}`).
1009
+
1010
+ [source,properties]
1011
+ .How to customize using configuration properties file
1012
+ ----
1013
+ dialect.bind-variable-render = org.mybatis.scripting.thymeleaf.processor.SpringJdbcBindVariableRender # <1>
1014
+ ----
1015
+
1016
+ <1> Specify the `BindVariableRender` implementation class(built-in class) that render Spring JDBC bind variable format
1017
+
1018
+
1019
+ [source,java]
1020
+ .How to customize using config class
1021
+ ----
1022
+ SqlGeneratorConfig config = SqlGeneratorConfig.newInstanceWithCustomizer(c ->
1023
+ c.getDialect().setBindVariableRender(BindVariableRender.BuiltIn.SPRING_JDBC.getType())); // <1>
1024
+ SqlGenerator sqlGenerator = new SqlGenerator(config); // <2>
1025
+ ----
1026
+
1027
+ <1> Specify the `BindVariableRender` implementation class(built-in class) that render Spring JDBC bind variable format via `BuiltIn` enum
1028
+ <2> Create a `SqlGenerator` instance with user defined configuration
1029
+
1030
+ If you use the custom bind variable format other than built-in format,
1031
+ please create a implementation class of `BindVariableRender` and apply it to the configuration.
1032
+
1033
+ [source,java]
1034
+ .How to create the BindVariableRender implementation class
1035
+ ----
1036
+ public class R2dbcMySQLBindVariableRender extends EnclosingBasedBindVariableRender { // <1>
1037
+ public R2dbcMySQLBindVariableRender() {
1038
+ super("?", ""); // Render '?...' (e.g. ?id)
1039
+ }
1040
+ }
1041
+ ----
1042
+
1043
+ <1> Create a `BindVariableRender` implementation class(The `EnclosingBasedBindVariableRender` supports to create an implementation class)
1044
+
1045
+
1046
+ ==== Customize other configurations
1047
+
1048
+ Please see also the following sections.
1049
+
1050
+ * <<_customizing_configuration>>
1051
+
1052
+
1053
+ === Basic Usage
1054
+
1055
+ The `SqlGenerator` provide feature for generating a SQL from SQL template using the Thymeleaf as follow:
1056
+
1057
+ [source,java]
1058
+ .Basic Usage:
1059
+ ----
1060
+ SqlGenerator sqlGenerator = new SqlGenerator(); // <1>
1061
+
1062
+ Conditions conditions = new Conditions();
1063
+ conditions.setId(10);
1064
+
1065
+ // sql = "SELECT * FROM accounts WHERE id = #{id}"
1066
+ String sql = sqlGenerator.generate(
1067
+ "SELECT * FROM accounts WHERE id = /*[# mb:p='id']*/ 1 /*[/]*/", conditions); // <2>
1068
+ ----
1069
+
1070
+ <1> Create a default instance of `SqlGenerator`
1071
+ <2> Generate an SQL from SQL template
1072
+
1073
+ [NOTE]
1074
+ ====
1075
+ The `SqlGenerator#generate` method is **thread-safe**. In other words, you can share an `SqlGenerator` instance at any components.
1076
+ ====
1077
+
1078
+ ==== Specifying custom variables
1079
+
1080
+ You can specify any custom variables separately from the parameter object as follow:
1081
+
1082
+ [source,java]
1083
+ .How to use custom variables:
1084
+ ----
1085
+ SqlGenerator sqlGenerator = new SqlGenerator();
1086
+ sqlGenerator.setDefaultCustomVariables(
1087
+ Collections.singletonMap("accountsTableName", "users")); // <1>
1088
+
1089
+ Account account = new Account();
1090
+ account.setName("Taro Yamada");
1091
+
1092
+ Map<String, Object> customVariables = new HashMap<>(); // <2>
1093
+ customVariables.put("now", LocalDateTime.now());
1094
+ customVariables.put("loginId", loginId);
1095
+
1096
+ // sql = "INSERT INTO users (name, created_at, created_by) VALUES(#{name}, #{now}, #{loginId})"
1097
+ String sql = sqlGenerator.generate(
1098
+ "INSERT INTO /*[# th:utext=\"${accountsTableName} ?: 'accounts'\"]*/ accounts /*[/]*/ " + // <3>
1099
+ "(name, created_at, created_by) VALUES(" +
1100
+ "/*[# mb:p='name']*/ 'Hanako Yamada' /*[/]*/, " +
1101
+ "/*[# mb:p='now']*/ current_timestamp() /*[/]*/, " + // <4>
1102
+ "/*[# mb:p='loginId']*/ 'A00000001' /*[/]*/" + // <4>
1103
+ ")", account, customVariables); // <5>
1104
+ ----
1105
+
1106
+ <1> Specify the default custom variable for sharing by every statements
1107
+ <2> Create custom variables per statement or transaction
1108
+ <3> Can be access to a custom variable at template processing time
1109
+ <4> Can be bind a custom variable
1110
+ <5> Specify(Pass) custom variables to sql generator at 3rd argument of `generate` method
1111
+
1112
+
1113
+ ==== Receiving custom bind variables
1114
+
1115
+ You can receiving custom bind variables that created during template processing via user define `Map` reference as follow:
1116
+
1117
+ [NOTE]
1118
+ ====
1119
+ The custom bind variables may create when use `mb:bind` or `mb:p` tag.
1120
+ ====
1121
+
1122
+ [source,java]
1123
+ .How to use custom bind variables store:
1124
+ ----
1125
+ SqlGenerator sqlGenerator = new SqlGenerator();
1126
+
1127
+ Map<String, Object> conditionsMap = new HashMap<>();
1128
+ conditionsMap.put("name", "Yamada");
1129
+
1130
+ // sql = "SELECT * FROM accounts WHERE name = #{patternName}"
1131
+ // customBindVariablesStore = {"patternName":"Yamada%"}
1132
+ Map<String, Object> customBindVariablesStore = new HashMap<>(); // <1>
1133
+ String sql = sqlGenerator.generate(
1134
+ "/*[# mb:bind='patternName=|${#likes.escapeWildcard(name)}%|' /]*/" +
1135
+ "SELECT * FROM accounts WHERE name = /*[# mb:p='patternName']*/ 'Sato' /*[/]*/",
1136
+ conditionsMap, null, customBindVariablesStore); // <2>
1137
+ ----
1138
+
1139
+ <1> Define a `Map` reference for receiving custom bind variables
1140
+ <2> Specify(Pass) a `Map` reference for receiving custom bind variables at 4th argument of `generate` method
1141
+
1142
+ === Advanced Usage
1143
+
1144
+ ==== Access JavaBeans property
1145
+
1146
+ By default, the `SqlGenerator` use the JDK standard APIs(JavaBeans and Reflection API) for accessing a property of user defined Java object.
1147
+ If there is a conflict with property accessing in the data access library,
1148
+ you can change a default behavior by applying a custom `org.mybatis.scripting.thymeleaf.PropertyAccessor` implementation class.
1149
+
1150
+ [source,java]
1151
+ .How to apply a custom PropertyAccessor
1152
+ ----
1153
+ SqlGenerator sqlGenerator = new SqlGenerator();
1154
+ sqlGenerator.setPropertyAccessor(new MyPropertyAccessor()); // <1>
1155
+ ----
1156
+
1157
+ <1> Set a custom `PropertyAccessor` implementation class to the `SqlGenerator`
1158
+
1159
+
993
1160
== Support classes
994
1161
995
1162
We provides useful classes for supporting development.
@@ -1076,7 +1243,7 @@ If you specify the `ESCAPE '\'` directly as static template parts, the Thymeleaf
1076
1243
.Invalid usage
1077
1244
----
1078
1245
/*[# mb:bind="patternFirstName=|${#likes.escapeWildcard(firstName)}%|" /]*/
1079
- AND firstName LIKE /*[('#{patternFirstName}')]*/ 'Taro%' /**/ ESCAPE '\'
1246
+ AND firstName LIKE /*[('#{patternFirstName}')]*/ 'Taro%' /**/ ESCAPE '\' --<1>
1080
1247
----
1081
1248
1082
1249
<1> Specify the `ESCAPE '\'` directly as static template parts
@@ -1145,7 +1312,8 @@ The mybatis-thymeleaf provides following properties for customizing configuratio
1145
1312
|`String[]`
1146
1313
|`"*.sql"`
1147
1314
1148
- 4+|*Template file path provider configuration(for TemplateFilePathProvider)*
1315
+ 4+|*Template file path provider configuration for TemplateFilePathProvider* +
1316
+ (Available only at `ThymeleafLanguageDriverConfig`)
1149
1317
1150
1318
|`template-file.path-provider.prefix`
1151
1319
|The prefix for adding to template file path
@@ -1195,6 +1363,12 @@ The mybatis-thymeleaf provides following properties for customizing configuratio
1195
1363
(Can specify multiple characters using comma(`","`) as separator character)
1196
1364
|`Character[]`
1197
1365
|`""` (no specify)
1366
+
1367
+ |`dialect.bind-variable-render`
1368
+ |The FQCN of class that implements the `BindVariableRender`
1369
+ (interface for rendering a bind variable such as `#{id}`, `:id`, etc...)
1370
+ |`Class`
1371
+ |FQCN of `MyBatisBindVariableRender.class`
1198
1372
|===
1199
1373
1200
1374
[source,properties]
@@ -1215,6 +1389,7 @@ dialect.prefix = mybatis
1215
1389
dialect.like-escape-char = ~
1216
1390
dialect.like-escape-clause-format = escape '%s'
1217
1391
dialect.like-additional-escape-target-chars = %, _
1392
+ dialect.bind-variable-render = org.mybatis.scripting.thymeleaf.processor.SpringJdbcBindVariableRender
1218
1393
----
1219
1394
1220
1395
[TIP]
@@ -1235,11 +1410,14 @@ configuration.getLanguageRegistry().register(
1235
1410
c.getTemplateFile().getPathProvider().setPrefix("sqls/");
1236
1411
c.getTemplateFile().getPathProvider().setIncludesPackagePath(false);
1237
1412
c.getTemplateFile().getPathProvider().setSeparateDirectoryPerMapper(false);
1238
- c.getTemplateFile().getPathProvider().setIncludesMapperNameWhenSeparateDirectory(false);
1413
+ c.getTemplateFile().getPathProvider()
1414
+ .setIncludesMapperNameWhenSeparateDirectory(false);
1239
1415
c.getDialect().setPrefix("mybatis");
1240
1416
c.getDialect().setLikeEscapeChar('~');
1241
1417
c.getDialect().setLikeEscapeClauseFormat("escape '%s'");
1242
1418
c.getDialect().setLikeAdditionalEscapeTargetChars('%', '_');
1419
+ c.getDialect().setBindVariableRender(
1420
+ BindVariableRender.BuiltIn.SPRING_JDBC.getType());
1243
1421
})));
1244
1422
----
1245
1423
@@ -1251,6 +1429,36 @@ We provide following factory methods for creating a `ThymeleafLanguageDriver` in
1251
1429
* `newInstance(Properties customProperties)`
1252
1430
* `newInstance(Consumer<ThymeleafLanguageDriverConfig> customizer)`
1253
1431
1432
+ These properties can be specified via factory method of `SqlGeneratorConfig` as follow:
1433
+
1434
+ [source,java]
1435
+ ----
1436
+ SqlGeneratorConfig config =
1437
+ SqlGeneratorConfig.newInstanceWithCustomizer(c -> {
1438
+ c.setUse2way(false);
1439
+ c.setCustomizer(CustomTemplateEngineCustomizer.class);
1440
+ c.getTemplateFile().setCacheEnabled(false);
1441
+ c.getTemplateFile().setCacheTtl(3600000L);
1442
+ c.getTemplateFile().setEncoding(StandardCharsets.UTF_8);
1443
+ c.getTemplateFile().setBaseDir("templates/");
1444
+ c.getTemplateFile().setPatterns("*.sql", "*.sql.template");
1445
+ c.getDialect().setPrefix("mybatis");
1446
+ c.getDialect().setLikeEscapeChar('~');
1447
+ c.getDialect().setLikeEscapeClauseFormat("escape '%s'");
1448
+ c.getDialect().setLikeAdditionalEscapeTargetChars('%', '_');
1449
+ c.getDialect().setBindVariableRender(
1450
+ BindVariableRender.BuiltIn.SPRING_JDBC.getType());
1451
+ });
1452
+ // ...
1453
+ ----
1454
+
1455
+ We provide following factory methods for creating a `SqlGeneratorConfig` instance.
1456
+
1457
+ * `newInstance()`
1458
+ * `newInstanceWithResourcePath(String resourcePath)`
1459
+ * `newInstanceWithProperties(Properties customProperties)`
1460
+ * `newInstanceWithCustomizer(Consumer<SqlGeneratorConfig> customizer)`
1461
+
1254
1462
====
1255
1463
1256
1464
0 commit comments