Skip to content

Commit be969cf

Browse files
authored
Add the doma-template module (#879)
* Add the doma-template module * Format * Format * Add error messages * Add documentation
1 parent 33a0682 commit be969cf

File tree

12 files changed

+363
-3
lines changed

12 files changed

+363
-3
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fun replaceVersionInArtifact(ver: String) {
4141
fun replaceVersionInDocs(ver: String) {
4242
ant.withGroovyBuilder {
4343
"replaceregexp"(
44-
"match" to """("org.seasar.doma:doma-(core|kotlin|processor|slf4j)?:)[^"]*(")""",
44+
"match" to """("org.seasar.doma:doma-(core|kotlin|processor|slf4j|template)?:)[^"]*(")""",
4545
"replace" to "\\1${ver}\\3",
4646
"encoding" to encoding,
4747
"flags" to "g"

docs/jpms-support.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ Doma provides the following modules:
2626
+----------------+------------------------------------+
2727
| doma-slf4j | org.seasar.doma.slf4j |
2828
+----------------+------------------------------------+
29+
| doma-template | org.seasar.doma.template |
30+
+----------------+------------------------------------+
2931

3032
Usage
3133
=====

docs/sql.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,36 @@ In other hand, the followings are the beginning of a directive:
796796
.. note::
797797

798798
We recommend you always use ``/**...*/`` to begin multi line comments because it is simple.
799+
800+
doma-template module
801+
====================
802+
803+
The doma-template module helps obtain prepared SQL statements from SQL templates.
804+
The module only contains the following classes:
805+
806+
* SqlArgument
807+
* SqlStatement
808+
* SqlTemplate
809+
810+
Gradle
811+
------
812+
813+
.. code-block:: xml
814+
815+
dependencies {
816+
implementation("org.seasar.doma:doma-template:2.52.0")
817+
}
818+
819+
Usage
820+
-----
821+
822+
.. code-block:: java
823+
824+
String sql = "select * from emp where name = /* name */'' and salary = /* salary */0";
825+
SqlStatement statement =
826+
new SqlTemplate(sql)
827+
.add("name", String.class, "abc")
828+
.add("salary", int.class, 1234)
829+
.execute();
830+
String rawSql = statement.getRawSql(); // select * from emp where name = ? and salary = ?
831+
List<SqlArgument> arguments = statement.getArguments();

doma-core/src/main/java/org/seasar/doma/internal/jdbc/sql/NodePreparedSqlBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public NodePreparedSqlBuilder(
117117
evaluator,
118118
sqlLogType,
119119
node -> {
120-
throw new UnsupportedOperationException();
120+
throw new UnsupportedOperationException("The '%expand' directive is not supported.");
121121
});
122122
}
123123

@@ -136,7 +136,7 @@ public NodePreparedSqlBuilder(
136136
sqlLogType,
137137
columnsExpander,
138138
(node, context) -> {
139-
throw new UnsupportedOperationException();
139+
throw new UnsupportedOperationException("The '%populate' directive is not supported.");
140140
});
141141
}
142142

doma-template/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/.classpath
2+
/.gradle/
3+
/.project
4+
/.settings/
5+
/bin/
6+
/build/
7+
/target/
8+
/.metadata
9+
.idea
10+
out
11+
.factorypath

doma-template/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
description = "doma-template"
2+
3+
dependencies {
4+
api(project(":doma-core"))
5+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.seasar.doma.template;
2+
3+
import java.util.Objects;
4+
5+
/** Represents a SQL argument. */
6+
public class SqlArgument {
7+
private final Class<?> type;
8+
private final Object value;
9+
10+
/**
11+
* @param type the variable type. Must not be null.
12+
* @param value the value. Can be null.
13+
*/
14+
public SqlArgument(Class<?> type, Object value) {
15+
this.type = Objects.requireNonNull(type);
16+
this.value = value;
17+
}
18+
19+
/**
20+
* Returns the value type.
21+
*
22+
* @return the value type. Must not be null.
23+
*/
24+
public Class<?> getType() {
25+
return type;
26+
}
27+
28+
/**
29+
* Returns the value.
30+
*
31+
* @return the value. Can be null.
32+
*/
33+
public Object getValue() {
34+
return value;
35+
}
36+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.seasar.doma.template;
2+
3+
import java.util.List;
4+
import java.util.Objects;
5+
6+
/** Represents a SQL statement. */
7+
public class SqlStatement {
8+
private final String rawSql;
9+
private final String formattedSql;
10+
private final List<SqlArgument> arguments;
11+
12+
/**
13+
* @param rawSql the raw SQL string. Must not be null.
14+
* @param formattedSql the formatted SQL string. Must not be null.
15+
* @param arguments the SQL arguments. Must not be null.
16+
*/
17+
public SqlStatement(String rawSql, String formattedSql, List<SqlArgument> arguments) {
18+
this.rawSql = Objects.requireNonNull(rawSql);
19+
this.formattedSql = Objects.requireNonNull(formattedSql);
20+
this.arguments = Objects.requireNonNull(arguments);
21+
}
22+
23+
/**
24+
* Returns the raw SQL string.
25+
*
26+
* <p>The bind variables are displayed as {@code ?}.
27+
*
28+
* @return the raw SQL string. Must not be null.
29+
*/
30+
public String getRawSql() {
31+
return rawSql;
32+
}
33+
34+
/**
35+
* Returns the formatted SQL string.
36+
*
37+
* <p>The bind variables are replaced with the string representations of the arguments.
38+
*
39+
* @return the formatted SQL string. Must not be null.
40+
*/
41+
public String getFormattedSql() {
42+
return formattedSql;
43+
}
44+
45+
/**
46+
* Returns the SQL arguments.
47+
*
48+
* @return the SQL arguments. Must not be null.
49+
*/
50+
public List<SqlArgument> getArguments() {
51+
return arguments;
52+
}
53+
54+
@Override
55+
public String toString() {
56+
return rawSql;
57+
}
58+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package org.seasar.doma.template;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.Objects;
7+
import java.util.function.Function;
8+
import java.util.stream.Collectors;
9+
import javax.sql.DataSource;
10+
import org.seasar.doma.internal.expr.ExpressionEvaluator;
11+
import org.seasar.doma.internal.expr.Value;
12+
import org.seasar.doma.internal.jdbc.sql.NodePreparedSqlBuilder;
13+
import org.seasar.doma.internal.jdbc.sql.SqlParser;
14+
import org.seasar.doma.jdbc.Config;
15+
import org.seasar.doma.jdbc.PreparedSql;
16+
import org.seasar.doma.jdbc.SqlKind;
17+
import org.seasar.doma.jdbc.SqlLogType;
18+
import org.seasar.doma.jdbc.SqlNode;
19+
import org.seasar.doma.jdbc.dialect.Dialect;
20+
import org.seasar.doma.jdbc.dialect.StandardDialect;
21+
import org.seasar.doma.wrapper.Wrapper;
22+
23+
/** Represents a SQL template. */
24+
public class SqlTemplate {
25+
private final String sql;
26+
private final Config config;
27+
private final Map<String, Value> values = new HashMap<>();
28+
29+
/** @param sql a template. Must not be null. */
30+
public SqlTemplate(String sql) {
31+
this(sql, new StandardDialect());
32+
}
33+
34+
/**
35+
* @param sql a template. Must not be null.
36+
* @param dialect a dialect. Must not be null.
37+
*/
38+
public SqlTemplate(String sql, Dialect dialect) {
39+
this(
40+
sql,
41+
new Config() {
42+
43+
@Override
44+
public DataSource getDataSource() {
45+
throw new UnsupportedOperationException();
46+
}
47+
48+
@Override
49+
public Dialect getDialect() {
50+
return dialect;
51+
}
52+
});
53+
Objects.requireNonNull(dialect);
54+
}
55+
56+
/**
57+
* @param sql a template. Must not be null.
58+
* @param config a configuration. Must not be null.
59+
*/
60+
public SqlTemplate(String sql, Config config) {
61+
this.sql = Objects.requireNonNull(sql);
62+
this.config = Objects.requireNonNull(config);
63+
}
64+
65+
/**
66+
* Adds a value.
67+
*
68+
* @param name the value name. Must not be null.
69+
* @param type the value type. Must not be null.
70+
* @param value the value. Can be null.
71+
* @return this instance. Must not be null.
72+
* @param <T> the value type
73+
*/
74+
public <T> SqlTemplate add(String name, Class<T> type, T value) {
75+
Objects.requireNonNull(name);
76+
Objects.requireNonNull(type);
77+
values.put(name, new Value(type, value));
78+
return this;
79+
}
80+
81+
/**
82+
* Creates a SQL statement from this template.
83+
*
84+
* @return a SQL statement. Must not be null.
85+
*/
86+
public SqlStatement execute() {
87+
SqlParser parser = new SqlParser(sql);
88+
SqlNode node = parser.parse();
89+
NodePreparedSqlBuilder builder = createNodePreparedSqlBuilder();
90+
PreparedSql preparedSql = builder.build(node, Function.identity());
91+
return toSqlStatement(preparedSql);
92+
}
93+
94+
private NodePreparedSqlBuilder createNodePreparedSqlBuilder() {
95+
ExpressionEvaluator evaluator =
96+
new ExpressionEvaluator(
97+
values, config.getDialect().getExpressionFunctions(), config.getClassHelper());
98+
return new NodePreparedSqlBuilder(
99+
config, SqlKind.SCRIPT, null, evaluator, SqlLogType.FORMATTED);
100+
}
101+
102+
private SqlStatement toSqlStatement(PreparedSql preparedSql) {
103+
List<SqlArgument> arguments =
104+
preparedSql.getParameters().stream()
105+
.map(
106+
it -> {
107+
Wrapper<?> w = it.getWrapper();
108+
return new SqlArgument(w.getBasicClass(), w.get());
109+
})
110+
.collect(Collectors.toList());
111+
return new SqlStatement(preparedSql.getRawSql(), preparedSql.getFormattedSql(), arguments);
112+
}
113+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module org.seasar.doma.template {
2+
exports org.seasar.doma.template;
3+
4+
requires org.seasar.doma.core;
5+
}

0 commit comments

Comments
 (0)