Skip to content

Commit e8faee8

Browse files
authored
replace SQL template placeholder $ with # instead - fixes #655 (#659)
* replace SQL template placeholder $ with # instead - fixes #655 Signed-off-by: Billy Yuan <billy112487983@gmail.com> * add CI for SQL Template Signed-off-by: Billy Yuan <billy112487983@gmail.com>
1 parent 0a24a15 commit e8faee8

File tree

9 files changed

+47
-43
lines changed

9 files changed

+47
-43
lines changed

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ jobs:
5151
name: "Postgres 10"
5252
jdk: openjdk8
5353
script: mvn -q clean verify -B -Dembedded.postgres.version=10.6 --projects vertx-sql-client,vertx-pg-client
54+
- stage: test
55+
name: "SQL Template"
56+
jdk: openjdk8
57+
script: mvn -q clean verify -B --projects vertx-sql-client,vertx-sql-client-templates
5458
- stage: deploy
5559
name: "Deploy to Sonatype's snapshots repository"
5660
if: type != pull_request AND env(SONATYPE_NEXUS_USERNAME) IS present

vertx-sql-client-templates/src/main/asciidoc/index.adoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ When you need to perform an insert or update operation and you do not care of th
4949

5050
== Template syntax
5151

52-
The template syntax uses `${XXX}` syntax where `XXX` is a valid https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.8[java identifier] string
52+
The template syntax uses `#{XXX}` syntax where `XXX` is a valid https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.8[java identifier] string
5353
(without the keyword restriction).
5454

55-
You can use the backslash char `\` to escape any `$` character, i.e `\${foo}` will be interpreted as `${foo}` string without a `foo` parameter.
55+
You can use the backslash char `\` to escape any `#` character, i.e `\#{foo}` will be interpreted as `#{foo}` string without a `foo` parameter.
5656

5757
== Row mapping
5858

vertx-sql-client-templates/src/main/java/examples/TemplateExamples.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public void queryExample(SqlClient client) {
3131
Map<String, Object> parameters = Collections.singletonMap("id", 1);
3232

3333
SqlTemplate
34-
.forQuery(client, "SELECT * FROM users WHERE id=${id}")
34+
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
3535
.execute(parameters)
3636
.onSuccess(users -> {
3737
users.forEach(row -> {
@@ -47,7 +47,7 @@ public void insertExample(SqlClient client) {
4747
parameters.put("lastName", "Cooper");
4848

4949
SqlTemplate
50-
.forUpdate(client, "INSERT INTO users VALUES (${id},${firstName},${lastName})")
50+
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
5151
.execute(parameters)
5252
.onSuccess(v -> {
5353
System.out.println("Successful update");
@@ -74,7 +74,7 @@ public void rowUserMapper() {
7474

7575
public void bindingRowWithCustomFunction(SqlClient client) {
7676
SqlTemplate
77-
.forQuery(client, "SELECT * FROM users WHERE id=${id}")
77+
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
7878
.mapTo(ROW_USER_MAPPER)
7979
.execute(Collections.singletonMap("id", 1))
8080
.onSuccess(users -> {
@@ -109,7 +109,7 @@ public void bindingParamsWithCustomFunction(SqlClient client) {
109109
user.firstName = "Cooper";
110110

111111
SqlTemplate
112-
.forUpdate(client, "INSERT INTO users VALUES (${id},${firstName},${lastName})")
112+
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
113113
.mapFrom(PARAMETERS_USER_MAPPER)
114114
.execute(user)
115115
.onSuccess(res -> {
@@ -119,7 +119,7 @@ public void bindingParamsWithCustomFunction(SqlClient client) {
119119

120120
public void batchBindingParamsWithCustomFunction(SqlClient client, List<User> users) {
121121
SqlTemplate
122-
.forUpdate(client, "INSERT INTO users VALUES (${id},${firstName},${lastName})")
122+
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
123123
.mapFrom(PARAMETERS_USER_MAPPER)
124124
.executeBatch(users)
125125
.onSuccess(res -> {
@@ -129,7 +129,7 @@ public void batchBindingParamsWithCustomFunction(SqlClient client, List<User> us
129129

130130
public void bindingRowWithJacksonDatabind(SqlClient client) {
131131
SqlTemplate
132-
.forQuery(client, "SELECT * FROM users WHERE id=${id}")
132+
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
133133
.mapTo(User.class)
134134
.execute(Collections.singletonMap("id", 1))
135135
.onSuccess(users -> {
@@ -144,7 +144,7 @@ public void bindingParamsWithJacksonDatabind(SqlClient client) {
144144
u.id = 1;
145145

146146
SqlTemplate
147-
.forUpdate(client, "INSERT INTO users VALUES (${id},${firstName},${lastName})")
147+
.forUpdate(client, "INSERT INTO users VALUES (#{id},#{firstName},#{lastName})")
148148
.mapFrom(User.class)
149149
.execute(u)
150150
.onSuccess(res -> {
@@ -260,7 +260,7 @@ public void setLastName(String lastName) {
260260

261261
public void bindingRowWithRowMapper(SqlClient client) {
262262
SqlTemplate
263-
.forQuery(client, "SELECT * FROM users WHERE id=${id}")
263+
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
264264
.mapTo(UserDataObjectRowMapper.INSTANCE)
265265
.execute(Collections.singletonMap("id", 1))
266266
.onSuccess(users -> {
@@ -346,7 +346,7 @@ public void bindingParamsWithParamsMapper(SqlClient client) {
346346
UserDataObject user = new UserDataObject().setId(1);
347347

348348
SqlTemplate
349-
.forQuery(client, "SELECT * FROM users WHERE id=${id}")
349+
.forQuery(client, "SELECT * FROM users WHERE id=#{id}")
350350
.mapFrom(UserDataObjectParamMapper.INSTANCE)
351351
.execute(user)
352352
.onSuccess(users -> {

vertx-sql-client-templates/src/main/java/io/vertx/sqlclient/templates/impl/SqlTemplate.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
public class SqlTemplate {
1414

15-
private static Pattern PARAM_PATTERN = Pattern.compile("(?<!\\\\)\\$\\{(\\p{javaUnicodeIdentifierStart}\\p{javaUnicodeIdentifierPart}*)}");
16-
private static Pattern BACKSLASH_DOLLAR_PATTERN = Pattern.compile("\\\\\\$");
15+
private static Pattern PARAM_PATTERN = Pattern.compile("(?<!\\\\)#\\{(\\p{javaUnicodeIdentifierStart}\\p{javaUnicodeIdentifierPart}*)}");
16+
private static Pattern BACKSLASH_DOLLAR_PATTERN = Pattern.compile("\\\\#");
1717

1818
private final String sql;
1919
private final String[] mapping;
@@ -40,7 +40,7 @@ public static SqlTemplate create(SqlClientInternal client, List<String> template
4040
}
4141

4242
/**
43-
* Sanitize a string escaped dollars, i.e {@code assertEquals(sanitize("\$"), "$")}
43+
* Sanitize a string escaped dollars, i.e {@code assertEquals(sanitize("\#"), "#")}
4444
*
4545
* @param s the string to sanitize
4646
* @return the sanitized string
@@ -52,7 +52,7 @@ private static String sanitize(String s) {
5252
while (m.find()) {
5353
int start = m.start();
5454
sb.append(s, prev, start);
55-
sb.append("$");
55+
sb.append("#");
5656
prev = m.end();
5757
}
5858
sb.append(s, prev, s.length());

vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/DataObjectTypesTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private void testNumberArray(TestContext ctx, String sqlType, Object value) {
138138
private <I, O> void testNumber(TestContext ctx, String sqlType, I value, O expected, String column, Function<TestDataObject, O> getter) {
139139
Async async = ctx.async();
140140
SqlTemplate<Map<String, Object>, RowSet<TestDataObject>> template = SqlTemplate
141-
.forQuery(connection, "SELECT ${value} :: " + sqlType + " \"" + column + "\"")
141+
.forQuery(connection, "SELECT #{value} :: " + sqlType + " \"" + column + "\"")
142142
.mapTo(TestDataObjectRowMapper.INSTANCE);
143143
template.execute(Collections.singletonMap("value", value), ctx.asyncAssertSuccess(result -> {
144144
ctx.assertEquals(1, result.size());

vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/MySQLTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void setup() throws Exception {
6565
public void testDurationMapping(TestContext ctx) {
6666
Duration duration = Duration.ofHours(11);
6767
SqlTemplate
68-
.forQuery(pool, "SELECT CAST(${duration} AS TIME) AS duration")
68+
.forQuery(pool, "SELECT CAST(#{duration} AS TIME) AS duration")
6969
.mapFrom(MySQLDataObjectParametersMapper.INSTANCE)
7070
.mapTo(MySQLDataObjectRowMapper.INSTANCE)
7171
.execute(new MySQLDataObject().setDuration(duration))

vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/PgClientTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class PgClientTest extends PgTemplateTestBase {
4343
@Test
4444
public void testQuery(TestContext ctx) {
4545
SqlTemplate<Map<String, Object>, RowSet<Row>> template = SqlTemplate
46-
.forQuery(connection, "SELECT ${id} :: INT4 \"id\", ${randomnumber} :: INT4 \"randomnumber\"");
46+
.forQuery(connection, "SELECT #{id} :: INT4 \"id\", #{randomnumber} :: INT4 \"randomnumber\"");
4747
Map<String, Object> params = new HashMap<>();
4848
params.put("id", 1);
4949
params.put("randomnumber", 10);
@@ -58,7 +58,7 @@ public void testQuery(TestContext ctx) {
5858
@Test
5959
public void testBatch(TestContext ctx) {
6060
SqlTemplate<Map<String, Object>, RowSet<Row>> template = SqlTemplate
61-
.forQuery(connection, "SELECT ${id} :: INT4 \"id\", ${randomnumber} :: INT4 \"randomnumber\"");
61+
.forQuery(connection, "SELECT #{id} :: INT4 \"id\", #{randomnumber} :: INT4 \"randomnumber\"");
6262
Map<String, Object> params1 = new HashMap<>();
6363
params1.put("id", 1);
6464
params1.put("randomnumber", 10);
@@ -85,7 +85,7 @@ public void testQueryMap(TestContext ctx) {
8585
w.id = 1;
8686
w.randomnumber = 10;
8787
SqlTemplate<World, RowSet<World>> template = SqlTemplate
88-
.<World>forQuery(connection, "SELECT ${id} :: INT4 \"id\", ${randomnumber} :: INT4 \"randomnumber\"")
88+
.<World>forQuery(connection, "SELECT #{id} :: INT4 \"id\", #{randomnumber} :: INT4 \"randomnumber\"")
8989
.mapFrom(World.class)
9090
.mapTo(World.class);
9191
template.execute(w, ctx.asyncAssertSuccess(res -> {
@@ -100,7 +100,7 @@ public void testQueryMap(TestContext ctx) {
100100
public void testLocalDateTimeWithJackson(TestContext ctx) {
101101
DatabindCodec.mapper().registerModule(new JavaTimeModule());
102102
SqlTemplate<Map<String, Object>, RowSet<LocalDateTimePojo>> template = SqlTemplate
103-
.forQuery(connection, "SELECT ${value} :: TIMESTAMP WITHOUT TIME ZONE \"localDateTime\"")
103+
.forQuery(connection, "SELECT #{value} :: TIMESTAMP WITHOUT TIME ZONE \"localDateTime\"")
104104
.mapTo(LocalDateTimePojo.class);
105105
LocalDateTime ldt = LocalDateTime.parse("2017-05-14T19:35:58.237666");
106106
template.execute(Collections.singletonMap("value", ldt), ctx.asyncAssertSuccess(result -> {
@@ -112,7 +112,7 @@ public void testLocalDateTimeWithJackson(TestContext ctx) {
112112
@Test
113113
public void testLocalDateTimeWithCodegen(TestContext ctx) {
114114
SqlTemplate<Map<String, Object>, RowSet<LocalDateTimeDataObject>> template = SqlTemplate
115-
.forQuery(connection, "SELECT ${value} :: TIMESTAMP WITHOUT TIME ZONE \"localDateTime\"")
115+
.forQuery(connection, "SELECT #{value} :: TIMESTAMP WITHOUT TIME ZONE \"localDateTime\"")
116116
.mapTo(LocalDateTimeDataObjectRowMapper.INSTANCE);
117117
LocalDateTime ldt = LocalDateTime.parse("2017-05-14T19:35:58.237666");
118118
template.execute(Collections.singletonMap("value", ldt), ctx.asyncAssertSuccess(result -> {
@@ -124,7 +124,7 @@ public void testLocalDateTimeWithCodegen(TestContext ctx) {
124124
@Test
125125
public void testLocalDateTimeWithCodegenCollector(TestContext ctx) {
126126
SqlTemplate<Map<String, Object>, SqlResult<List<LocalDateTimeDataObject>>> template = SqlTemplate
127-
.forQuery(connection, "SELECT ${value} :: TIMESTAMP WITHOUT TIME ZONE \"localDateTime\"")
127+
.forQuery(connection, "SELECT #{value} :: TIMESTAMP WITHOUT TIME ZONE \"localDateTime\"")
128128
.collecting(LocalDateTimeDataObjectRowMapper.COLLECTOR);
129129
LocalDateTime ldt = LocalDateTime.parse("2017-05-14T19:35:58.237666");
130130
template.execute(Collections.singletonMap("value", ldt), ctx.asyncAssertSuccess(result -> {

vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/PgTemplateTestBase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ protected <P, T, V> void testGet(TestContext ctx,
8585
String column) {
8686
Async async = ctx.async();
8787
SqlTemplate<P, RowSet<T>> template = SqlTemplate
88-
.forQuery(connection, "SELECT ${" + paramName + "} :: " + sqlType + " \"" + column + "\"")
88+
.forQuery(connection, "SELECT #{" + paramName + "} :: " + sqlType + " \"" + column + "\"")
8989
.mapFrom(paramsMapper)
9090
.mapTo(rowMapper);
9191
template.execute(params, ctx.asyncAssertSuccess(result -> {

vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/TemplateBuilderTest.java

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,47 +41,47 @@ public Future<Void> close() {
4141

4242
@Test
4343
public void testPostgresSql() {
44-
assertPgSql("${foo} ${bar}", "$1 $2");
45-
assertPgSql("${foo} ${foo}", "$1 $1");
46-
assertPgSql("${foo} ${bar} ${foo}", "$1 $2 $1");
47-
assertPgSql("${foo} ${bar} ${foo} ${bar}", "$1 $2 $1 $2");
44+
assertPgSql("#{foo} #{bar}", "$1 $2");
45+
assertPgSql("#{foo} #{foo}", "$1 $1");
46+
assertPgSql("#{foo} #{bar} #{foo}", "$1 $2 $1");
47+
assertPgSql("#{foo} #{bar} #{foo} #{bar}", "$1 $2 $1 $2");
4848
}
4949

5050
@Test
5151
public void testPostgresTuple() {
5252
Map<String, Object> params = new HashMap<>();
5353
params.put("foo", "foo_value");
5454
params.put("bar", "bar_value");
55-
assertPgTuple("${foo} ${bar}", params, Tuple.of("foo_value", "bar_value"));
56-
assertPgTuple("${foo} ${foo}", params, Tuple.of("foo_value"));
57-
assertPgTuple("${foo} ${bar} ${foo}", params, Tuple.of("foo_value", "bar_value"));
58-
assertPgTuple("${foo} ${bar} ${foo} ${bar}", params, Tuple.of("foo_value", "bar_value"));
55+
assertPgTuple("#{foo} #{bar}", params, Tuple.of("foo_value", "bar_value"));
56+
assertPgTuple("#{foo} #{foo}", params, Tuple.of("foo_value"));
57+
assertPgTuple("#{foo} #{bar} #{foo}", params, Tuple.of("foo_value", "bar_value"));
58+
assertPgTuple("#{foo} #{bar} #{foo} #{bar}", params, Tuple.of("foo_value", "bar_value"));
5959
}
6060

6161
@Test
6262
public void testOtherSql() {
63-
assertOtherSql("${foo} ${bar}", "? ?");
64-
assertOtherSql("${foo} ${foo}", "? ?");
65-
assertOtherSql("${foo} ${bar} ${foo}", "? ? ?");
66-
assertOtherSql("${foo} ${bar} ${foo} ${bar}", "? ? ? ?");
63+
assertOtherSql("#{foo} #{bar}", "? ?");
64+
assertOtherSql("#{foo} #{foo}", "? ?");
65+
assertOtherSql("#{foo} #{bar} #{foo}", "? ? ?");
66+
assertOtherSql("#{foo} #{bar} #{foo} #{bar}", "? ? ? ?");
6767
}
6868

6969
@Test
7070
public void testOtherTuple() {
7171
Map<String, Object> params = new HashMap<>();
7272
params.put("foo", "foo_value");
7373
params.put("bar", "bar_value");
74-
assertOtherTuple("${foo} ${bar}", params, Tuple.of("foo_value", "bar_value"));
75-
assertOtherTuple("${foo} ${foo}", params, Tuple.of("foo_value", "foo_value"));
76-
assertOtherTuple("${foo} ${bar} ${foo}", params, Tuple.of("foo_value", "bar_value", "foo_value"));
77-
assertOtherTuple("${foo} ${bar} ${foo} ${bar}", params, Tuple.of("foo_value", "bar_value", "foo_value", "bar_value"));
74+
assertOtherTuple("#{foo} #{bar}", params, Tuple.of("foo_value", "bar_value"));
75+
assertOtherTuple("#{foo} #{foo}", params, Tuple.of("foo_value", "foo_value"));
76+
assertOtherTuple("#{foo} #{bar} #{foo}", params, Tuple.of("foo_value", "bar_value", "foo_value"));
77+
assertOtherTuple("#{foo} #{bar} #{foo} #{bar}", params, Tuple.of("foo_value", "bar_value", "foo_value", "bar_value"));
7878
}
7979

8080
@Test
8181
public void testSpecialCases() {
82-
assertOtherSql("\\${foo}", "${foo}");
83-
assertOtherSql("before\\${foo}after", "before${foo}after");
84-
assertOtherSql("${begin", "${begin");
82+
assertOtherSql("\\#{foo}", "#{foo}");
83+
assertOtherSql("before\\#{foo}after", "before#{foo}after");
84+
assertOtherSql("#{begin", "#{begin");
8585
}
8686

8787
private void assertPgSql(String template, String expectedSql) {

0 commit comments

Comments
 (0)