@@ -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,169 @@ 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
+ ==== Specifying custom variables
1074
+
1075
+ You can specify any custom variables separately from the parameter object as follow:
1076
+
1077
+ [source,java]
1078
+ .How to use custom variables:
1079
+ ----
1080
+ SqlGenerator sqlGenerator = new SqlGenerator();
1081
+ sqlGenerator.setDefaultCustomVariables(
1082
+ Collections.singletonMap("accountsTableName", "users")); // <1>
1083
+
1084
+ Map<String, Object> accountMap = new HashMap<>();
1085
+ accountMap.put("name", "Taro Yamada");
1086
+
1087
+ Map<String, Object> customVariables = new HashMap<>(); // <2>
1088
+ customVariables.put("now", LocalDateTime.now());
1089
+ customVariables.put("loginId", loginId);
1090
+
1091
+ // sql = "INSERT INTO users (name, created_at, created_by) VALUES(#{name}, #{now}, #{loginId})"
1092
+ String sql = sqlGenerator.generate(
1093
+ "INSERT INTO /*[# th:utext=\"${accountsTableName} ?: 'accounts'\"]*/ accounts /*[/]*/ " + // <3>
1094
+ "(name, created_at, created_by) VALUES(" +
1095
+ "/*[# mb:p='name']*/ 'Hanako Yamada' /*[/]*/, " +
1096
+ "/*[# mb:p='now']*/ current_timestamp() /*[/]*/, " + // <4>
1097
+ "/*[# mb:p='loginId']*/ 'A00000001' /*[/]*/" + // <4>
1098
+ ")", accountMap, customVariables); // <5>
1099
+ ----
1100
+
1101
+ <1> Specify the default custom variable for sharing by every statement
1102
+ <2> Create custom variable per statement or transaction
1103
+ <3> Can be replace to custom variable value at template processing time
1104
+ <4> Can be bind a custom variable
1105
+ <5> Specify(Pass) custom variables to sql generator at 3rd argument of `generate` method
1106
+
1107
+
1108
+ ==== Receiving custom bind variables
1109
+
1110
+ You can receiving custom bind variables that created during template processing via user define `Map` reference as follow:
1111
+
1112
+ [NOTE]
1113
+ ====
1114
+ The custom bind variables may create when use `mb:bind` or `mb:p` tag.
1115
+ ====
1116
+
1117
+ [source,java]
1118
+ .How to use custom bind variables store:
1119
+ ----
1120
+ SqlGenerator sqlGenerator = new SqlGenerator();
1121
+
1122
+ Map<String, Object> conditionsMap = new HashMap<>();
1123
+ conditionsMap.put("name", "Yamada");
1124
+
1125
+ // sql = "SELECT * FROM accounts WHERE name = #{patternName}"
1126
+ // customBindVariablesStore = {"patternName":"Yamada%"}
1127
+ Map<String, Object> customBindVariablesStore = new HashMap<>(); // <1>
1128
+ String sql = sqlGenerator.generate(
1129
+ "/*[# mb:bind='patternName=|${#likes.escapeWildcard(name)}%|' /]*/" +
1130
+ "SELECT * FROM accounts WHERE name = /*[# mb:p='patternName']*/ 'Sato' /*[/]*/",
1131
+ conditionsMap, null, customBindVariablesStore); // <2>
1132
+ ----
1133
+
1134
+ <1> Define a `Map` reference for receiving custom bind variables
1135
+ <2> Specify(Pass) a `Map` reference for receiving custom bind variables at 4th argument of `generate` method
1136
+
1137
+ === Advanced Usage
1138
+
1139
+ ==== Access JavaBeans property
1140
+
1141
+ By default, the `SqlGenerator` use the JDK standard APIs(JavaBeans and Reflection API) for accessing a property of user defined Java object.
1142
+ If there is a conflict with property accessing in the data access library,
1143
+ you can change a default behavior by applying a custom `org.mybatis.scripting.thymeleaf.PropertyAccessor` implementation class.
1144
+
1145
+ [source,java]
1146
+ .How to apply a custom PropertyAccessor
1147
+ ----
1148
+ SqlGenerator sqlGenerator = new SqlGenerator();
1149
+ sqlGenerator.setPropertyAccessor(new MyPropertyAccessor()); // <1>
1150
+ ----
1151
+
1152
+ <1> Set a custom `PropertyAccessor` implementation class to the `SqlGenerator`
1153
+
1154
+
993
1155
== Support classes
994
1156
995
1157
We provides useful classes for supporting development.
@@ -1076,7 +1238,7 @@ If you specify the `ESCAPE '\'` directly as static template parts, the Thymeleaf
1076
1238
.Invalid usage
1077
1239
----
1078
1240
/*[# mb:bind="patternFirstName=|${#likes.escapeWildcard(firstName)}%|" /]*/
1079
- AND firstName LIKE /*[('#{patternFirstName}')]*/ 'Taro%' /**/ ESCAPE '\'
1241
+ AND firstName LIKE /*[('#{patternFirstName}')]*/ 'Taro%' /**/ ESCAPE '\' --<1>
1080
1242
----
1081
1243
1082
1244
<1> Specify the `ESCAPE '\'` directly as static template parts
@@ -1145,7 +1307,8 @@ The mybatis-thymeleaf provides following properties for customizing configuratio
1145
1307
|`String[]`
1146
1308
|`"*.sql"`
1147
1309
1148
- 4+|*Template file path provider configuration(for TemplateFilePathProvider)*
1310
+ 4+|*Template file path provider configuration for TemplateFilePathProvider* +
1311
+ (Available only at `ThymeleafLanguageDriverConfig`)
1149
1312
1150
1313
|`template-file.path-provider.prefix`
1151
1314
|The prefix for adding to template file path
@@ -1195,6 +1358,13 @@ The mybatis-thymeleaf provides following properties for customizing configuratio
1195
1358
(Can specify multiple characters using comma(`","`) as separator character)
1196
1359
|`Character[]`
1197
1360
|`""` (no specify)
1361
+
1362
+ |`dialect.bind-variable-render`
1363
+ |The FQCN of class that implements the `BindVariableRender`
1364
+ (interface for rendering a bind variable ( such as `#{id}`, `:id`, etc...)
1365
+ |The `BindVariableRender` implementation class for rendering bind variable
1366
+ |`Class`
1367
+ |`org.mybatis.scripting.thymeleaf.processor.MyBatisBindVariableRender` (no specify)
1198
1368
|===
1199
1369
1200
1370
[source,properties]
@@ -1215,6 +1385,7 @@ dialect.prefix = mybatis
1215
1385
dialect.like-escape-char = ~
1216
1386
dialect.like-escape-clause-format = escape '%s'
1217
1387
dialect.like-additional-escape-target-chars = %, _
1388
+ dialect.bind-variable-render = org.mybatis.scripting.thymeleaf.processor.SpringJdbcBindVariableRender
1218
1389
----
1219
1390
1220
1391
[TIP]
@@ -1235,11 +1406,14 @@ configuration.getLanguageRegistry().register(
1235
1406
c.getTemplateFile().getPathProvider().setPrefix("sqls/");
1236
1407
c.getTemplateFile().getPathProvider().setIncludesPackagePath(false);
1237
1408
c.getTemplateFile().getPathProvider().setSeparateDirectoryPerMapper(false);
1238
- c.getTemplateFile().getPathProvider().setIncludesMapperNameWhenSeparateDirectory(false);
1409
+ c.getTemplateFile().getPathProvider()
1410
+ .setIncludesMapperNameWhenSeparateDirectory(false);
1239
1411
c.getDialect().setPrefix("mybatis");
1240
1412
c.getDialect().setLikeEscapeChar('~');
1241
1413
c.getDialect().setLikeEscapeClauseFormat("escape '%s'");
1242
1414
c.getDialect().setLikeAdditionalEscapeTargetChars('%', '_');
1415
+ c.getDialect().setBindVariableRender(
1416
+ BindVariableRender.BuiltIn.SPRING_JDBC.getType());
1243
1417
})));
1244
1418
----
1245
1419
@@ -1251,6 +1425,36 @@ We provide following factory methods for creating a `ThymeleafLanguageDriver` in
1251
1425
* `newInstance(Properties customProperties)`
1252
1426
* `newInstance(Consumer<ThymeleafLanguageDriverConfig> customizer)`
1253
1427
1428
+ These properties can be specified via factory method of `SqlGeneratorConfig` as follow:
1429
+
1430
+ [source,java]
1431
+ ----
1432
+ SqlGeneratorConfig config =
1433
+ SqlGeneratorConfig.newInstanceWithCustomizer(c -> {
1434
+ c.setUse2way(false);
1435
+ c.setCustomizer(CustomTemplateEngineCustomizer.class);
1436
+ c.getTemplateFile().setCacheEnabled(false);
1437
+ c.getTemplateFile().setCacheTtl(3600000L);
1438
+ c.getTemplateFile().setEncoding(StandardCharsets.UTF_8);
1439
+ c.getTemplateFile().setBaseDir("templates/");
1440
+ c.getTemplateFile().setPatterns("*.sql", "*.sql.template");
1441
+ c.getDialect().setPrefix("mybatis");
1442
+ c.getDialect().setLikeEscapeChar('~');
1443
+ c.getDialect().setLikeEscapeClauseFormat("escape '%s'");
1444
+ c.getDialect().setLikeAdditionalEscapeTargetChars('%', '_');
1445
+ c.getDialect().setBindVariableRender(
1446
+ BindVariableRender.BuiltIn.SPRING_JDBC.getType());
1447
+ });
1448
+ // ...
1449
+ ----
1450
+
1451
+ We provide following factory methods for creating a `SqlGeneratorConfig` instance.
1452
+
1453
+ * `newInstance()`
1454
+ * `newInstanceWithResourcePath(String resourcePath)`
1455
+ * `newInstanceWithProperties(Properties customProperties)`
1456
+ * `newInstanceWithCustomizer(Consumer<SqlGeneratorConfig> customizer)`
1457
+
1254
1458
====
1255
1459
1256
1460
0 commit comments