#12 FQL: Add BETWEEN for date

- Add BETWEEN for date
- Add support for other operators than = for date
- Document BETWEEN in the query options detail panel
This commit is contained in:
2021-03-04 01:04:07 +01:00
parent e4f21f25e8
commit 8dd3d9141c
8 changed files with 107 additions and 9 deletions

View File

@@ -30,7 +30,7 @@ intExpression
booleanExpression
: field=IDENTIFIER operator=STRING_OPERATOR value=(TRUE | FALSE) ;
dateExpression
: field=IDENTIFIER operator=STRING_OPERATOR value=DATE_VALUE ;
: field=IDENTIFIER operator=(INT_OPERATOR | STRING_OPERATOR) value=DATE_VALUE ;
// special expressions
specialExpression
@@ -47,11 +47,13 @@ inStringExpression
// BETWEEN expressions
betweenExpression
: (betweenStringExpression | betweenIntExpression ) ;
: (betweenStringExpression | betweenIntExpression | betweenDateExpression ) ;
betweenStringExpression
: field=IDENTIFIER BETWEEN left=STRING_VALUE AND right=STRING_VALUE ;
betweenIntExpression
: field=IDENTIFIER BETWEEN left=INT_VALUE AND right=INT_VALUE ;
betweenDateExpression
: field=IDENTIFIER BETWEEN left=DATE_VALUE AND right=DATE_VALUE ;
// period expressions
periodExpression
@@ -121,7 +123,7 @@ R_PAREN : ')' ;
IDENTIFIER : [a-zA-Z]+ ;
INT_VALUE : [0-9]+ ;
STRING_VALUE : '\'' [a-zA-Z0-9\-/.&%@$ ]+ '\'' ;
DATE_VALUE : [0-9-]+ ;
DATE_VALUE : [0-9][0-9][0-9][0-9][-][0-9][0-9][-][0-9][0-9] ; // ANTLR does not support regex quantifiers
NEWLINE : ('\r'? '\n' | '\r')+ ;
WHITESPACE : ' ' -> skip;

View File

@@ -188,11 +188,13 @@ public class FQLVisitorImpl extends FQLBaseVisitor<Predicate> {
@Override
public Predicate visitDateExpression(FQLParser.DateExpressionContext ctx) {
final FieldMapping fieldMapping = FieldMapping.findByFieldName(ctx.field.getText());
final DateHandler.DateHandlerParameterContainer con = DateHandler.DateHandlerParameterContainer
.of(ctx.operator.getText(), ctx.value.getText());
fieldMapping.getJoinHandler().apply(this.froms, fieldMapping);
return fieldMapping.getFieldHandler()
.apply(fieldMapping, this.froms, this.criteriaBuilder, ctx.value.getText());
.apply(fieldMapping, this.froms, this.criteriaBuilder, con);
}
@Override
@@ -213,6 +215,19 @@ public class FQLVisitorImpl extends FQLBaseVisitor<Predicate> {
return new BetweenStringHandler().apply(fieldMapping, this.froms, this.criteriaBuilder, con);
}
@Override
public Predicate visitBetweenDateExpression(FQLParser.BetweenDateExpressionContext ctx) {
final FieldMapping fieldMapping = FieldMapping.findByFieldName(ctx.field.getText());
final BetweenDateHandler.BetweenDateHandlerParameterContainer con = BetweenDateHandler.BetweenDateHandlerParameterContainer
.of(ctx.left.getText(), ctx.right.getText());
fieldMapping.getJoinHandler().apply(this.froms, fieldMapping);
// Overwrite the actual field handler of the field
return new BetweenDateHandler().apply(fieldMapping, this.froms, this.criteriaBuilder, con);
}
@Override
public Predicate visitBetweenIntExpression(FQLParser.BetweenIntExpressionContext ctx) {
final FieldMapping fieldMapping = FieldMapping.findByFieldName(ctx.field.getText());

View File

@@ -0,0 +1,38 @@
package de.financer.fql.field_handler;
import de.financer.fql.FieldMapping;
import de.financer.fql.join_handler.JoinKey;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Predicate;
import java.time.LocalDate;
import java.util.Map;
public class BetweenDateHandler implements FieldHandler<BetweenDateHandler.BetweenDateHandlerParameterContainer> {
public static class BetweenDateHandlerParameterContainer {
private String left;
private String right;
public static BetweenDateHandlerParameterContainer of(String left, String right) {
final BetweenDateHandlerParameterContainer con = new BetweenDateHandlerParameterContainer();
con.left = left;
con.right = right;
return con;
}
}
@Override
public Predicate apply(FieldMapping fieldMapping, Map<JoinKey, From<?, ?>> froms, CriteriaBuilder criteriaBuilder, BetweenDateHandlerParameterContainer con) {
return criteriaBuilder
.between(froms.get(fieldMapping.getJoinKey()).get(fieldMapping.getAttributeName()),
parseDate(con.left),
parseDate(con.right));
}
private LocalDate parseDate(String value) {
return LocalDate.parse(value);
}
}

View File

@@ -5,14 +5,53 @@ import de.financer.fql.join_handler.JoinKey;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.time.LocalDate;
import java.util.Map;
public class DateHandler implements FieldHandler<String> {
public class DateHandler implements FieldHandler<DateHandler.DateHandlerParameterContainer> {
public static class DateHandlerParameterContainer {
private String operator;
private String value;
public static DateHandler.DateHandlerParameterContainer of(String operator, String value) {
DateHandler.DateHandlerParameterContainer con = new DateHandler.DateHandlerParameterContainer();
con.operator = operator;
con.value = value;
return con;
}
}
@Override
public Predicate apply(FieldMapping fieldMapping, Map<JoinKey, From<?, ?>> froms, CriteriaBuilder criteriaBuilder, String value) {
return criteriaBuilder.equal(froms.get(fieldMapping.getJoinKey()).get(fieldMapping.getAttributeName()), parseDate(value));
public Predicate apply(FieldMapping fieldMapping, Map<JoinKey, From<?, ?>> froms, CriteriaBuilder criteriaBuilder, DateHandlerParameterContainer con) {
final Path<LocalDate> path = froms.get(fieldMapping.getJoinKey()).get(fieldMapping.getAttributeName());
Predicate retVal = null;
switch (con.operator) {
case "=":
retVal = criteriaBuilder.equal(path, parseDate(con.value));
break;
case ">":
retVal = criteriaBuilder.greaterThan(path, parseDate(con.value));
break;
case "<":
retVal = criteriaBuilder.lessThan(path, parseDate(con.value));
break;
case ">=":
retVal = criteriaBuilder.greaterThanOrEqualTo(path, parseDate(con.value));
break;
case "<=":
retVal = criteriaBuilder.lessThanOrEqualTo(path, parseDate(con.value));
break;
case "!=":
retVal = criteriaBuilder.notEqual(path, parseDate(con.value));
break;
}
return retVal;
}
private LocalDate parseDate(String value) {

View File

@@ -69,6 +69,7 @@ public class TransactionController {
// TODO
model.addAttribute("errorMessage", e.getResponseReason().name());
model.addAttribute("transactionCount", 0);
model.addAttribute("showSum", false);
}
model.addAttribute("form", form);

View File

@@ -156,7 +156,8 @@ financer.search-transactions.show-query-options.case=Case-insensitive
financer.search-transactions.show-query-options.operators=Possible operators =, >, >=, <, <=, !=
financer.search-transactions.show-query-options.ordering=Ordering for a single field ASC, DESC via ORDER BY
financer.search-transactions.show-query-options.like=Fuzzy search with LIKE, % as wildcard
financer.search-transactions.show-query-options.in=Multiple string or integer values via IN clause
financer.search-transactions.show-query-options.in=Multiple string or integer values via IN ('value1', 'value2', ...)
financer.search-transactions.show-query-options.between=Filtering of values (string, int, date) in a given range, start and end inclusive, via BETWEEN
financer.chart-select.title=Select a chart to generate
financer.chart-select.submit=Select

View File

@@ -156,7 +156,8 @@ financer.search-transactions.show-query-options.case=Unterscheidung von Gro\u1E9
financer.search-transactions.show-query-options.operators=Unterst\u00FCtzte Operatoren =, >, >=, <, <=, !=
financer.search-transactions.show-query-options.ordering=Sortierung \u00FCber ein einziges Feld mit ASC (aufsteigend), DESC (absteigend) via ORDER BY
financer.search-transactions.show-query-options.like=Platzhaltersuche mit LIKE, % als Platzhalter
financer.search-transactions.show-query-options.in=Mehrere Zeichenketten- oder Ganzzahlwerte mit IN Klausel
financer.search-transactions.show-query-options.in=Mehrere Zeichenketten- oder Ganzzahlwerte mit IN ('wert1', 'wert2', ...)
financer.search-transactions.show-query-options.between=Filtern von Werten (Zeichenketten, Ganzzahlen, Daten) in einem Bereich, Start und Ende jeweils inklusive, mit BETWEEN
financer.chart-select.title=Ein Diagramm zum Erzeugen ausw\u00E4hlen
financer.chart-select.submit=Ausw\u00E4hlen

View File

@@ -57,6 +57,7 @@
<li th:text="#{financer.search-transactions.show-query-options.ordering}" />
<li th:text="#{financer.search-transactions.show-query-options.like}" />
<li th:text="#{financer.search-transactions.show-query-options.in}" />
<li th:text="#{financer.search-transactions.show-query-options.between}" />
</ul>
</p>
</div>