Skip to content

Commit 0f9344e

Browse files
committed
Fixed higher level functions for Predicates
1 parent 7b6faa3 commit 0f9344e

File tree

6 files changed

+158
-23
lines changed

6 files changed

+158
-23
lines changed

README.MD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ You can include the Maven dependency:
5656
<dependency>
5757
<groupId>com.github.collinalpert</groupId>
5858
<artifactId>lambda2sql</artifactId>
59-
<version>1.8</version>
59+
<version>1.8.1</version>
6060
</dependency>
6161
```
6262

pom.xml

Lines changed: 9 additions & 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>1.8</version>
9+
<version>1.8.1</version>
1010
<packaging>jar</packaging>
1111

1212
<name>lambda2sql</name>
@@ -141,6 +141,14 @@
141141
</plugin>
142142
<plugin>
143143
<artifactId>maven-assembly-plugin</artifactId>
144+
<executions>
145+
<execution>
146+
<phase>package</phase>
147+
<goals>
148+
<goal>single</goal>
149+
</goals>
150+
</execution>
151+
</executions>
144152
<configuration>
145153
<descriptorRefs>
146154
<descriptorRef>jar-with-dependencies</descriptorRef>
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package com.github.collinalpert.lambda2sql;
2+
3+
import java.util.EmptyStackException;
4+
5+
/**
6+
* Custom implementation of a stack that uses a linked list functionality approach.
7+
*
8+
* @param <T> The type of the Stack.
9+
* @author Collin Alpert
10+
* @see Node
11+
*/
12+
public class LinkedListStack<T> {
13+
14+
/**
15+
* Element representing the head of the stack and the entry point for finding other elements.
16+
*/
17+
private Node head;
18+
private int elementCount;
19+
20+
/**
21+
* Constructor for creating an empty stack.
22+
*/
23+
public LinkedListStack() {
24+
elementCount = 0;
25+
}
26+
27+
/**
28+
* Pushes (adds) an element to the top of the stack.
29+
*
30+
* @param element The element to be added.
31+
*/
32+
public void push(T element) {
33+
head = new Node(head, element);
34+
elementCount++;
35+
}
36+
37+
/**
38+
* Pops (removes and returns) the top of the stack.
39+
*
40+
* @return The top element on the stack.
41+
*/
42+
public T pop() {
43+
if (isEmpty()) {
44+
throw new EmptyStackException();
45+
}
46+
Node firstElement = head;
47+
head = head.getNext();
48+
elementCount--;
49+
return firstElement.getValue();
50+
}
51+
52+
/**
53+
* Returns the top of the stack.
54+
*
55+
* @return The first element on the stack.
56+
*/
57+
public T top() {
58+
if (isEmpty()) {
59+
throw new EmptyStackException();
60+
}
61+
return head.getValue();
62+
}
63+
64+
/**
65+
* Checks if the stack is empty.
66+
*
67+
* @return <code>True</code> if there are elements in the stack, otherwise <code>false</code>.
68+
*/
69+
public boolean isEmpty() {
70+
return elementCount == 0;
71+
}
72+
73+
/**
74+
* @return the number of elements in this stack.
75+
*/
76+
public int size() {
77+
return elementCount;
78+
}
79+
80+
/**
81+
* A class which represents an element in a stack and includes a reference to the next element, as per linked list approach.
82+
*
83+
* @author Collin Alpert
84+
* @see LinkedListStack
85+
*/
86+
private class Node {
87+
88+
/**
89+
* Reference to the next element in the stack.
90+
*/
91+
private Node next;
92+
private T value;
93+
94+
/**
95+
* Constructor for creating an element with a value and a reference to the next element in the stack.
96+
*
97+
* @param next The next element in the stack.
98+
* @param value This element's value.
99+
*/
100+
Node(Node next, T value) {
101+
this.next = next;
102+
this.value = value;
103+
}
104+
105+
/**
106+
* @return the reference to the next element in the stack.
107+
*/
108+
Node getNext() {
109+
return next;
110+
}
111+
112+
/**
113+
* @return the value of this element.
114+
*/
115+
T getValue() {
116+
return value;
117+
}
118+
}
119+
}

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

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,23 @@
1111
import com.trigersoft.jaque.expression.ParameterExpression;
1212
import com.trigersoft.jaque.expression.UnaryExpression;
1313

14-
import java.util.LinkedList;
1514
import java.util.List;
15+
import java.util.stream.Collectors;
1616

1717
/**
1818
* Converts a lambda expression to an SQL where condition.
1919
*/
2020
public class ToSqlVisitor implements ExpressionVisitor<StringBuilder> {
2121

2222
private final String prefix;
23+
private LinkedListStack<List<ConstantExpression>> arguments;
2324
private StringBuilder sb;
24-
2525
private Expression body;
26-
private List<ConstantExpression> parameters;
2726

2827
ToSqlVisitor(String prefix) {
2928
this.prefix = prefix;
3029
this.sb = new StringBuilder();
31-
this.parameters = new LinkedList<>();
30+
arguments = new LinkedListStack<>();
3231
}
3332

3433
/**
@@ -62,7 +61,7 @@ private static String toSqlOp(int expressionType) {
6261
*/
6362
@Override
6463
public StringBuilder visit(BinaryExpression e) {
65-
boolean quote = e != body && e.getExpressionType() == ExpressionType.LogicalOr;
64+
boolean quote = e != this.body && e.getExpressionType() == ExpressionType.LogicalOr;
6665

6766
if (quote) sb.append('(');
6867

@@ -92,19 +91,21 @@ public StringBuilder visit(ConstantExpression e) {
9291

9392
/**
9493
* An expression which represents an invocation of a lambda expression.
95-
* It is the last {@link #visit} where the parameters of {@link ParameterExpression}s are available which is why
94+
* It is the last {@link #visit} where the arguments of {@link ParameterExpression}s are available which is why
9695
* they are temporarily saved in a list to be inserted into the SQL where condition later.
9796
*
9897
* @param e The {@link InvocationExpression} to convert.
9998
* @return A {@link StringBuilder} containing the body/target of the lambda expression.
10099
*/
101100
@Override
102101
public StringBuilder visit(InvocationExpression e) {
103-
e.getArguments()
102+
var list = e.getArguments()
104103
.stream()
105-
.filter(x -> x instanceof ConstantExpression && x.getResultType() != LambdaExpression.class)
106-
.map(ConstantExpression.class::cast)
107-
.forEach(parameters::add);
104+
.filter(x -> x instanceof ConstantExpression)
105+
.map(ConstantExpression.class::cast).collect(Collectors.toList());
106+
if (!list.isEmpty()) {
107+
arguments.push(list);
108+
}
108109
return e.getTarget().accept(this);
109110
}
110111

@@ -116,8 +117,10 @@ public StringBuilder visit(InvocationExpression e) {
116117
*/
117118
@Override
118119
public StringBuilder visit(LambdaExpression<?> e) {
119-
this.body = e.getBody();
120-
return body.accept(this);
120+
if (this.body == null && e.getBody() instanceof BinaryExpression) {
121+
this.body = e.getBody();
122+
}
123+
return e.getBody().accept(this);
121124
}
122125

123126
/**
@@ -148,7 +151,7 @@ public StringBuilder visit(MemberExpression e) {
148151
*/
149152
@Override
150153
public StringBuilder visit(ParameterExpression e) {
151-
parameters.get(e.getIndex()).accept(this);
154+
arguments.top().get(e.getIndex()).accept(this);
152155
return sb;
153156
}
154157

src/main/java/module-info.java

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/test/java/com/github/collinalpert/lambda2sql/test/Lambda2SqlTest.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void testMultipleLogicalOps() {
3535
void testWithVariables() {
3636
var name = "Donald";
3737
var age = 80;
38-
assertPredicateEqual("person.name = 'Donald' AND person.age > 80", person -> person.getName() == name && person.getAge() > age);
38+
assertPredicateEqual("person.name = 'Donald' OR person.age > 80", person -> person.getName() == name || person.getAge() > age);
3939
}
4040

4141
@Test
@@ -63,8 +63,18 @@ void testAndFunction() {
6363
void testOrFunction() {
6464
var id = 1;
6565
SqlPredicate<IPerson> personPredicate = person -> person.getId() == id;
66-
SqlPredicate<IPerson> personSqlPredicateAnd = personPredicate.or(x -> true);
67-
assertPredicateEqual("person.id = 1 OR true", personSqlPredicateAnd);
66+
SqlPredicate<IPerson> personSqlPredicateOr = personPredicate.or(x -> true);
67+
assertPredicateEqual("person.id = 1 OR true", personSqlPredicateOr);
68+
}
69+
70+
@Test
71+
void testHigherLevelWithParameters() {
72+
var name1 = "Donald";
73+
var age1 = 80;
74+
var name2 = "Steve";
75+
SqlPredicate<IPerson> personPredicate = p -> (p.getName() == name1 || p.getAge() == age1);
76+
personPredicate = personPredicate.and(p -> p.getName() == name2);
77+
assertPredicateEqual("(person.name = 'Donald' OR person.age = 80) AND person.name = 'Steve'", personPredicate);
6878
}
6979

7080
@Test

0 commit comments

Comments
 (0)