Skip to content

Commit e323004

Browse files
committed
Added escaping backticks when generating SQL.
1 parent 66b9654 commit e323004

File tree

5 files changed

+105
-90
lines changed

5 files changed

+105
-90
lines changed

README.MD

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ For example, the lambda expression\
5151
``person -> person.getAge() > 18 && person.getName().startsWith("Steve")``\
5252
would translate to:\
5353
``person.age > 18 AND person.name LIKE 'Steve%'``
54+
55+
Lambda2Sql also automatically escapes table names and columns with backticks (\`). If you do not wish this, you can specify it as an argument in the `Lambda2Sql.toSql()` method.
5456

5557
Feel free to open an issue with any requests you might have.
5658

@@ -62,7 +64,7 @@ You can include the Maven dependency:
6264
<dependency>
6365
<groupId>com.github.collinalpert</groupId>
6466
<artifactId>lambda2sql</artifactId>
65-
<version>2.1.1</version>
67+
<version>2.1.2</version>
6668
</dependency>
6769
```
6870

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.github.collinalpert</groupId>
88
<artifactId>lambda2sql</artifactId>
9-
<version>2.1.1</version>
9+
<version>2.1.2</version>
1010
<packaging>jar</packaging>
1111

1212
<name>lambda2sql</name>

src/main/java/com/github/collinalpert/lambda2sql/Lambda2Sql.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@ public class Lambda2Sql {
1616
* Supported operators: {@code >,>=,<,<=,=,!=,&&,||,!}
1717
*
1818
* @param functionalInterface A {@link FunctionalInterface} lambda to convert.
19-
* @param prefix An optional prefix to proceed the column name. Usually it is the table name.
19+
* @param tableName The table name which the column belongs to. This will explicitly reference the column.
20+
* It is optional to specify this.
21+
* @param withBackticks Specifies if the table and the column name should be escaped with backticks. The default behavior is {@code true}.
2022
* @return A {@link String} describing the SQL where condition.
2123
*/
22-
public static String toSql(SerializedFunctionalInterface functionalInterface, String prefix) {
24+
public static String toSql(SerializedFunctionalInterface functionalInterface, String tableName, boolean withBackticks) {
2325
var lambdaExpression = LambdaExpression.parse(functionalInterface);
24-
return lambdaExpression.accept(new SqlVisitor(prefix)).toString();
26+
return lambdaExpression.accept(new SqlVisitor(tableName, withBackticks)).toString();
27+
}
28+
29+
public static String toSql(SerializedFunctionalInterface functionalInterface, String tableName) {
30+
return toSql(functionalInterface, tableName, true);
2531
}
2632

2733
public static String toSql(SerializedFunctionalInterface functionalInterface) {
28-
return toSql(functionalInterface, null);
34+
return toSql(functionalInterface, null, false);
2935
}
3036
}

src/main/java/com/github/collinalpert/lambda2sql/SqlVisitor.java

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.List;
2727
import java.util.Map;
2828
import java.util.StringJoiner;
29+
import java.util.function.Consumer;
2930
import java.util.stream.Collectors;
3031

3132
/**
@@ -51,7 +52,8 @@ public class SqlVisitor implements ExpressionVisitor<StringBuilder> {
5152
}
5253
}};
5354

54-
private final String prefix;
55+
private final String tableName;
56+
private final boolean withBackticks;
5557
private final LinkedListStack<List<ConstantExpression>> arguments;
5658

5759
/**
@@ -69,16 +71,18 @@ public class SqlVisitor implements ExpressionVisitor<StringBuilder> {
6971
e.printStackTrace();
7072
}
7173
}};
74+
7275
private StringBuilder sb;
7376
private Expression body;
7477
private Expression javaMethodParameter;
7578

76-
SqlVisitor(String prefix) {
77-
this(prefix, new LinkedListStack<>());
79+
SqlVisitor(String tableName, boolean withBackTicks) {
80+
this(tableName, withBackTicks, new LinkedListStack<>());
7881
}
7982

80-
private SqlVisitor(String prefix, LinkedListStack<List<ConstantExpression>> arguments) {
81-
this.prefix = prefix;
83+
private SqlVisitor(String tableName, boolean withBackticks, LinkedListStack<List<ConstantExpression>> arguments) {
84+
this.tableName = tableName;
85+
this.withBackticks = withBackticks;
8286
this.arguments = arguments;
8387
this.sb = new StringBuilder();
8488
}
@@ -222,21 +226,22 @@ public StringBuilder visit(DelegateExpression e) {
222226
@Override
223227
public StringBuilder visit(MemberExpression e) {
224228
if (registeredMethods.containsKey(e.getMember())) {
225-
return Expression.binary(registeredMethods.get(e.getMember()), e.getInstance(), javaMethodParameter).accept(this);
229+
return Expression.binary(registeredMethods.get(e.getMember()), e.getInstance(), this.javaMethodParameter).accept(this);
226230
}
227231

228-
if (complexMethods.containsKey(e.getMember())) {
229-
return sb.append(complexMethods.get(e.getMember()).apply(e.getInstance(), javaMethodParameter, false));
232+
if (this.complexMethods.containsKey(e.getMember())) {
233+
return sb.append(this.complexMethods.get(e.getMember()).apply(e.getInstance(), this.javaMethodParameter, false));
230234
}
231235

232236
var nameArray = e.getMember().getName().replaceAll("^(get)", "").toCharArray();
233237
nameArray[0] = Character.toLowerCase(nameArray[0]);
234238
var name = new String(nameArray);
235-
if (prefix == null) {
239+
if (this.tableName == null) {
236240
return sb.append(name);
237241
}
238242

239-
return sb.append(prefix).append(".").append(name);
243+
String escape = this.withBackticks ? "`" : "";
244+
return sb.append(escape).append(this.tableName).append(escape).append(".").append(escape).append(name).append(escape);
240245
}
241246

242247
/**
@@ -287,28 +292,30 @@ public StringBuilder visit(UnaryExpression e) {
287292

288293
//region Complex Java methods
289294

290-
private StringBuilder stringStartsWith(Expression e, Expression e1, boolean negated) {
291-
var valueBuilder = e1.accept(new SqlVisitor(this.prefix, this.arguments));
292-
valueBuilder.insert(valueBuilder.length() - 1, '%');
293-
return e.accept(new SqlVisitor(this.prefix, this.arguments)).append(negated ? " NOT" : "").append(" LIKE ").append(valueBuilder);
295+
private StringBuilder stringStartsWith(Expression member, Expression argument, boolean negated) {
296+
return doStringOperation(member, argument, negated, valueBuilder -> valueBuilder.insert(valueBuilder.length() - 1, '%'));
294297
}
295298

296-
private StringBuilder stringEndsWith(Expression e, Expression e1, boolean negated) {
297-
return e.accept(new SqlVisitor(this.prefix, this.arguments)).append(negated ? " NOT" : "").append(" LIKE ").append(e1.accept(new SqlVisitor(this.prefix, this.arguments)).insert(1, '%'));
299+
private StringBuilder stringEndsWith(Expression member, Expression argument, boolean negated) {
300+
return doStringOperation(member, argument, negated, valueBuilder -> valueBuilder.insert(1, '%'));
298301
}
299302

300-
private StringBuilder stringContains(Expression e, Expression e1, boolean negated) {
301-
var valueBuilder = e1.accept(new SqlVisitor(this.prefix, this.arguments));
302-
valueBuilder.insert(1, '%').insert(valueBuilder.length() - 1, '%');
303-
return e.accept(new SqlVisitor(this.prefix, this.arguments)).append(negated ? " NOT" : "").append(" LIKE ").append(valueBuilder);
303+
private StringBuilder stringContains(Expression member, Expression argument, boolean negated) {
304+
return doStringOperation(member, argument, negated, valueBuilder -> valueBuilder.insert(1, '%').insert(valueBuilder.length() - 1, '%'));
304305
}
305306

306-
private StringBuilder listContains(Expression e, Expression e1, boolean negated) {
307-
List l = (List) arguments.pop().get(((ParameterExpression) e).getIndex()).getValue();
307+
private StringBuilder listContains(Expression listAsArgument, Expression argument, boolean negated) {
308+
List l = (List) arguments.pop().get(((ParameterExpression) listAsArgument).getIndex()).getValue();
308309
var joiner = new StringJoiner(", ", "(", ")");
309310
l.forEach(x -> joiner.add(x.toString()));
310-
return e1.accept(new SqlVisitor(this.prefix, this.arguments)).append(negated ? " NOT" : "").append(" IN ").append(joiner.toString());
311+
return argument.accept(new SqlVisitor(this.tableName, this.withBackticks, this.arguments)).append(negated ? " NOT" : "").append(" IN ").append(joiner.toString());
311312
}
312313

313314
//endregion
315+
316+
private StringBuilder doStringOperation(Expression member, Expression argument, boolean negated, Consumer<StringBuilder> modifier) {
317+
var valueBuilder = argument.accept(new SqlVisitor(this.tableName, this.withBackticks, this.arguments));
318+
modifier.accept(valueBuilder);
319+
return member.accept(new SqlVisitor(this.tableName, this.withBackticks, this.arguments)).append(negated ? " NOT" : "").append(" LIKE ").append(valueBuilder);
320+
}
314321
}

0 commit comments

Comments
 (0)