From b756b7d614af231d66e1a78b81c5c7b521b3b85a Mon Sep 17 00:00:00 2001 From: MK13 Date: Fri, 13 Nov 2020 22:25:36 +0100 Subject: [PATCH] FQL improvements --- .../src/main/antlr4/de/financer/fql/FQL.g4 | 9 ++++++-- .../java/de/financer/fql/FQLVisitorImpl.java | 10 +++++++++ .../java/de/financer/fql/FieldMapping.java | 5 ++++- .../fql/field_handler/LikeHandler.java | 21 +++++++++++++++++++ .../main/resources/i18n/message.properties | 2 ++ .../resources/i18n/message_de_DE.properties | 2 ++ .../src/main/resources/static/changelog.txt | 5 +++++ .../transaction/searchTransactions.html | 2 ++ 8 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 financer-server/src/main/java/de/financer/fql/field_handler/LikeHandler.java diff --git a/financer-server/src/main/antlr4/de/financer/fql/FQL.g4 b/financer-server/src/main/antlr4/de/financer/fql/FQL.g4 index 13088a0..9d92ea7 100644 --- a/financer-server/src/main/antlr4/de/financer/fql/FQL.g4 +++ b/financer-server/src/main/antlr4/de/financer/fql/FQL.g4 @@ -21,7 +21,7 @@ orderByExpression // regular expressions - NOT regex regularExpression - : (stringExpression | intExpression | booleanExpression | dateExpression) ; + : (stringExpression | intExpression | booleanExpression | dateExpression | likeExpression) ; stringExpression : field=IDENTIFIER operator=STRING_OPERATOR value=STRING_VALUE ; intExpression @@ -32,6 +32,8 @@ booleanExpression dateExpression : field=IDENTIFIER operator=STRING_OPERATOR value=DATE_VALUE ; +likeExpression : field=IDENTIFIER LIKE value=STRING_VALUE ; + // BETWEEN expressions betweenExpression : (betweenStringExpression | betweenIntExpression ) ; @@ -70,6 +72,8 @@ fragment Y : ('Y' | 'y') ; fragment G : ('G' | 'g') ; fragment O : ('O' | 'o') ; fragment F : ('F' | 'f') ; +fragment I : ('I' | 'i') ; +fragment K : ('K' | 'k') ; fragment SPACE : ' ' ; // Keywords @@ -81,6 +85,7 @@ DESC : D E S C ; ASC : A S C ; TRUE : T R U E ; FALSE : F A L S E ; +LIKE : L I K E ; // Constant values CURRENT : C U R R E N T ; @@ -96,7 +101,7 @@ L_PAREN : '(' ; R_PAREN : ')' ; IDENTIFIER : [a-zA-Z]+ ; INT_VALUE : [0-9]+ ; -STRING_VALUE : '\'' [a-zA-Z0-9\-/ ]+ '\'' ; +STRING_VALUE : '\'' [a-zA-Z0-9\-/.&%@$ ]+ '\'' ; DATE_VALUE : [0-9-]+ ; NEWLINE : ('\r'? '\n' | '\r')+ ; diff --git a/financer-server/src/main/java/de/financer/fql/FQLVisitorImpl.java b/financer-server/src/main/java/de/financer/fql/FQLVisitorImpl.java index b8129d2..d222036 100644 --- a/financer-server/src/main/java/de/financer/fql/FQLVisitorImpl.java +++ b/financer-server/src/main/java/de/financer/fql/FQLVisitorImpl.java @@ -140,6 +140,16 @@ public class FQLVisitorImpl extends FQLBaseVisitor { .apply(fieldMapping, this.froms, this.criteriaBuilder, ctx.value.getText()); } + @Override + public Predicate visitLikeExpression(FQLParser.LikeExpressionContext ctx) { + final FieldMapping fieldMapping = FieldMapping.findByFieldName(ctx.field.getText()); + + fieldMapping.getJoinHandler().apply(this.froms, fieldMapping); + + return fieldMapping.getFieldHandler() + .apply(fieldMapping, this.froms, this.criteriaBuilder, ctx.value.getText()); + } + @Override public Predicate visitIntExpression(FQLParser.IntExpressionContext ctx) { final FieldMapping fieldMapping = FieldMapping.findByFieldName(ctx.field.getText()); diff --git a/financer-server/src/main/java/de/financer/fql/FieldMapping.java b/financer-server/src/main/java/de/financer/fql/FieldMapping.java index c2dd772..0be2b1e 100644 --- a/financer-server/src/main/java/de/financer/fql/FieldMapping.java +++ b/financer-server/src/main/java/de/financer/fql/FieldMapping.java @@ -32,7 +32,10 @@ public enum FieldMapping { TAX_RELEVANT("taxRelevant", Transaction_.TAX_RELEVANT, Transaction.class, NoopJoinHandler.class, JoinKey.of(Transaction.class), null, BooleanHandler.class), - HAS_FILE("hasFile", File_.ID, File.class, FileJoinHandler.class, JoinKey.of(File.class), null, NotNullSyntheticHandler.class); + HAS_FILE("hasFile", File_.ID, File.class, FileJoinHandler.class, JoinKey.of(File.class), null, NotNullSyntheticHandler.class), + + DESCRIPTION("description", Transaction_.DESCRIPTION, Transaction.class, NoopJoinHandler.class, JoinKey.of(Transaction.class), + null, LikeHandler.class); /** * The name of the field as used in FQL diff --git a/financer-server/src/main/java/de/financer/fql/field_handler/LikeHandler.java b/financer-server/src/main/java/de/financer/fql/field_handler/LikeHandler.java new file mode 100644 index 0000000..e7c02ef --- /dev/null +++ b/financer-server/src/main/java/de/financer/fql/field_handler/LikeHandler.java @@ -0,0 +1,21 @@ +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.util.Map; + +public class LikeHandler implements FieldHandler { + @Override + public Predicate apply(FieldMapping fieldMapping, Map> froms, CriteriaBuilder criteriaBuilder, String value) { + return criteriaBuilder + .like(criteriaBuilder.lower(froms.get(fieldMapping.getJoinKey()).get(fieldMapping.getAttributeName())), removeQuotes(value).toLowerCase()); + } + + private String removeQuotes(String value) { + return value.replaceAll("'", ""); + } +} diff --git a/financer-web-client/src/main/resources/i18n/message.properties b/financer-web-client/src/main/resources/i18n/message.properties index 143c3bb..a0e75c1 100644 --- a/financer-web-client/src/main/resources/i18n/message.properties +++ b/financer-web-client/src/main/resources/i18n/message.properties @@ -140,6 +140,7 @@ financer.search-transactions.show-query-options.date=date\: the date of the tran financer.search-transactions.show-query-options.recurring=recurring\: whether the transaction has been created from a recurring transaction financer.search-transactions.show-query-options.taxRelevant=taxRelevant\: whether the transaction is relevant for tax declaration financer.search-transactions.show-query-options.hasFile=hasFile\: whether the transaction has a file linked +financer.search-transactions.show-query-options.description=description\: the description of the transaction financer.search-transactions.show-query-options.period=period\: the period the transaction is assigned to financer.search-transactions.show-query-options.period.CURRENT=CURRENT\: denotes the current expense period financer.search-transactions.show-query-options.period.LAST=LAST\: denotes the last expense period @@ -153,6 +154,7 @@ financer.search-transactions.show-query-options.strings=Strings enclosed in sing 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 (only applicable for field description) financer.chart-select.title=Select a chart to generate financer.chart-select.submit=Select diff --git a/financer-web-client/src/main/resources/i18n/message_de_DE.properties b/financer-web-client/src/main/resources/i18n/message_de_DE.properties index 7a41d71..ff4bd2d 100644 --- a/financer-web-client/src/main/resources/i18n/message_de_DE.properties +++ b/financer-web-client/src/main/resources/i18n/message_de_DE.properties @@ -140,6 +140,7 @@ financer.search-transactions.show-query-options.date=date\: das Datum der Buchun financer.search-transactions.show-query-options.recurring=recurring\: ob die Buchung durch eine wiederkehrende Buchung erzeugt wurde financer.search-transactions.show-query-options.taxRelevant=taxRelevant\: ob die Buchung als steuerrelevant markiert wurde financer.search-transactions.show-query-options.hasFile=hasFile\: ob eine Datei der Buchung zugeordnet ist +financer.search-transactions.show-query-options.description=description\: die Beschreibung der Buchung financer.search-transactions.show-query-options.period=period\: die Periode der Buchung financer.search-transactions.show-query-options.period.CURRENT=CURRENT\: bezeichnet die aktuelle Ausgabenperiode financer.search-transactions.show-query-options.period.LAST=LAST\: bezeichnet die letzte Ausgabenperiode @@ -153,6 +154,7 @@ financer.search-transactions.show-query-options.strings=Zeichenketten werden dur financer.search-transactions.show-query-options.case=Unterscheidung von Gro\u1E9E- und Kleinschreibung 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 (nur anwendbar bei Feld description) financer.chart-select.title=Ein Diagramm zum Erzeugen ausw\u00E4hlen financer.chart-select.submit=Ausw\u00E4hlen diff --git a/financer-web-client/src/main/resources/static/changelog.txt b/financer-web-client/src/main/resources/static/changelog.txt index 8c37afe..fc32f5a 100644 --- a/financer-web-client/src/main/resources/static/changelog.txt +++ b/financer-web-client/src/main/resources/static/changelog.txt @@ -1,3 +1,8 @@ +v33 -> v34: +- Fix a bug in the parsing of FQL +- Add the transaction description field to the FQL search +- Add LIKE support to the FQL search + v32 -> v33: - Introduce Holiday/Weekend Type SKIP to skip an occurrence of a recurring transaction once, if the due date is either a holiday or a weekend day diff --git a/financer-web-client/src/main/resources/templates/transaction/searchTransactions.html b/financer-web-client/src/main/resources/templates/transaction/searchTransactions.html index 2f03417..8448687 100644 --- a/financer-web-client/src/main/resources/templates/transaction/searchTransactions.html +++ b/financer-web-client/src/main/resources/templates/transaction/searchTransactions.html @@ -32,6 +32,7 @@
  • +
    • @@ -52,6 +53,7 @@
    • +