Skip to content

Commit 624047b

Browse files
committed
Switching to StringBuilder
1 parent efc388f commit 624047b

File tree

5 files changed

+78
-26
lines changed

5 files changed

+78
-26
lines changed

README.MD

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,53 @@ Lambda2sql
33

44
Convert Java 8 lambdas to SQL statements.
55

6+
For example, the following Predicate:
7+
```
8+
person -> person.getAge() < 100 && person.getHeight() > 200
9+
```
10+
11+
is converted to a string:
12+
13+
```
14+
age < 100 AND height > 200
15+
```
16+
allowing you to write readable queries in a type safe way.
617

18+
See Lambda2SqlTest for more examples.
19+
20+
Usage
21+
---------
22+
23+
```
24+
Lambda2Sql.init(); // initialize on program start
25+
26+
Predicate<Person> predicate = person -> person.getAge() < 100 && person.getHeight() > 200;
27+
28+
String sql = Lambda2Sql.toSql( predicate ); // age < 100 AND height > 200
29+
```
30+
31+
32+
How it works
33+
---------
34+
35+
It uses [JaQue](https://github.com/TrigerSoft/jaque) to build an expression tree for a lambda. The expression tree is then traversed and converted to a SQL statement.
36+
37+
Under the hood JaQue depends on the following system property:
38+
`jdk.internal.lambda.dumpProxyClasses`
39+
See [https://bugs.openjdk.java.net/browse/JDK-8023524](https://bugs.openjdk.java.net/browse/JDK-8023524).
40+
41+
When the property is enabled, JVM generated classes for lambdas are saved to disk. JaQue then uses [ASM](http://asm.ow2.org/) to read the .class files and creates expression trees.
42+
43+
44+
Limitations
45+
---------
46+
47+
Current version only works with predicates and supports the following operators: >, >=, <, <=, =, !=, &&, ||, !
48+
49+
Build
50+
---------
51+
52+
`gradle jar`
53+
54+
or you can just [download the jar](http://dl.bintray.com/ajermakovics/jar/lambda2sql-0.1.jar).
755

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ sourceCompatibility = 1.8
55
targetCompatibility = 1.8
66

77
version = '0.1'
8+
group = "lambda2sql"
9+
archivesBaseName = "lambda2sql"
10+
jar.baseName = archivesBaseName
11+
812
jar {
913
manifest {
1014
attributes 'Implementation-Title': 'Lambda2sql', 'Implementation-Version': version

src/main/java/lambda2sql/Lambda2Sql.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ public static void init() {
3737
*/
3838
public static <T> String toSql(Predicate<T> predicate) {
3939
LambdaExpression<Predicate<T>> lambdaExpression = LambdaExpression.parse(predicate);
40-
return lambdaExpression.accept(new ToSqlVisitor());
40+
return lambdaExpression.accept(new ToSqlVisitor()).toString();
4141
}
4242
}

src/main/java/lambda2sql/ToSqlVisitor.java

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,24 @@
66

77
import com.trigersoft.jaque.expression.*;
88

9-
public class ToSqlVisitor implements ExpressionVisitor<String> {
10-
11-
boolean top = true;
9+
public class ToSqlVisitor implements ExpressionVisitor<StringBuilder> {
1210

11+
private StringBuilder sb = new StringBuilder();
12+
private Expression body;
1313

1414
@Override
15-
public String visit(BinaryExpression e) {
16-
boolean quote = !top && e.getExpressionType() == LogicalOr;
17-
top = false;
15+
public StringBuilder visit(BinaryExpression e) {
16+
boolean quote = e != body && e.getExpressionType() == LogicalOr;
1817

19-
StringBuilder sb = new StringBuilder();
2018
if( quote ) sb.append('(');
2119

22-
String first = e.getFirst().accept(this);
23-
String second = e.getSecond().accept(this);
24-
25-
sb.append(first).append(' ').append(toSqlOp(e.getExpressionType())).append(' ').append(second);
20+
e.getFirst().accept(this);
21+
sb.append(' ').append(toSqlOp(e.getExpressionType())).append(' ');
22+
e.getSecond().accept(this);
2623

2724
if( quote ) sb.append(')');
2825

29-
return sb.toString();
26+
return sb;
3027
}
3128

3229
public static String toSqlOp(int expressionType) {
@@ -39,35 +36,37 @@ public static String toSqlOp(int expressionType) {
3936
}
4037

4138
@Override
42-
public String visit(ConstantExpression e) {
43-
return e.getValue().toString();
39+
public StringBuilder visit(ConstantExpression e) {
40+
return sb.append(e.getValue().toString());
4441
}
4542

4643
@Override
47-
public String visit(InvocationExpression e) {
44+
public StringBuilder visit(InvocationExpression e) {
4845
return e.getTarget().accept(this);
4946
}
5047

5148
@Override
52-
public String visit(LambdaExpression<?> e) {
53-
return e.getBody().accept(this);
49+
public StringBuilder visit(LambdaExpression<?> e) {
50+
this.body = e.getBody();
51+
return body.accept(this);
5452
}
5553

5654
@Override
57-
public String visit(MemberExpression e) {
55+
public StringBuilder visit(MemberExpression e) {
5856
String name = e.getMember().getName();
59-
return name.replaceAll("^(get|is)", "").toLowerCase();
57+
name = name.replaceAll("^(get|is)", "").toLowerCase();
58+
return sb.append(name);
6059
}
6160

6261
@Override
63-
public String visit(ParameterExpression e) {
64-
return "";
62+
public StringBuilder visit(ParameterExpression e) {
63+
return sb;
6564
}
6665

6766
@Override
68-
public String visit(UnaryExpression e) {
69-
String first = e.getFirst().accept(this);
70-
return ExpressionType.toString(e.getExpressionType()) + first;
67+
public StringBuilder visit(UnaryExpression e) {
68+
sb.append(ExpressionType.toString(e.getExpressionType()));
69+
return e.getFirst().accept(this);
7170
}
7271

7372
}

src/test/java/lambda2sql/Lambda2SqlTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ public void testLogicalOps() throws Exception {
3333
}
3434

3535
@Test
36-
public void testMultiLogicalOps() throws Exception {
36+
public void testMultipleLogicalOps() throws Exception {
3737
assertEqual("active AND (age < 100 OR height > 200)", e -> e.isActive() && (e.getAge() < 100 || e.getHeight() > 200) );
38+
assertEqual("(age < 100 OR height > 200) AND active", e -> (e.getAge() < 100 || e.getHeight() > 200) && e.isActive() );
3839
}
3940

4041
private void assertEqual(String expectedSql, Predicate<Person> p) {

0 commit comments

Comments
 (0)