Skip to content

Commit

Permalink
Sync/cdr 423 enhance sdk parser (#376)
Browse files Browse the repository at this point in the history
* update aql grammar

see CDR-423

* add AqlExpressionTest

see CDR-423

* move all aql stuff to aql module

see CDR-411

* new predate handler for aql

see CDR-411

* fix formatting of predicate

see CDR-411

* aql parser: parse ehr/id

see CDR-411

* aql parser: parse predicate with other than equal

see CDR-411

* aql parser: parse functions

see CDR-411

* fix aql predicate value parsing

see CDR-411

* aql parsing allow reference by name

see CDR-411

* add aql path to dto modele

see CDR-411

* add test cases

see CDR-411

* aql parser: parse not and exist in where

see CDR-411

* aql parser: support more functions

see CDR-411

* aql parser: support distinct and correct limit

see CDR-411

* aql parser: add test cases

see CDR-411

* code cleanup

see CDR-411

* [skip ci] update changelog

see CDR-411

* fix review

see CDR-411
  • Loading branch information
stefanspiska authored Jul 26, 2022
1 parent e5a4376 commit dc89440
Show file tree
Hide file tree
Showing 119 changed files with 2,513 additions and 244 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ Note: version releases in the 0.x.y range may introduce breaking changes.
- Add spotless plugin, Add codestyle check to workflows ([#368](https://github.com/ehrbase/ehrbase/pull/368))
### Fixed
- Skip archetype slots not used by the template in example generator ([#369](https://github.com/ehrbase/openEHR_SDK/pull/369))
- enhance sdk aql parser to handle more cases ([#376](https://github.com/ehrbase/openEHR_SDK/pull/376))
- update update everit-json-schema to maven version ([#370](https://github.com/ehrbase/openEHR_SDK/pull/370))


## [1.19.0]

### Added
Expand Down
29 changes: 25 additions & 4 deletions aql/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,7 @@
</build>

<dependencies>
<dependency>
<groupId>org.ehrbase.openehr.sdk</groupId>
<artifactId>client</artifactId>
</dependency>

<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
Expand All @@ -79,5 +76,29 @@
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.ehrbase.openehr.sdk</groupId>
<artifactId>util</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.nedap.healthcare.archie</groupId>
<artifactId>openehr-rm</artifactId>
</dependency>
<dependency>
<groupId>com.nedap.healthcare.archie</groupId>
<artifactId>archie-utils</artifactId>
</dependency>
</dependencies>
</project>
46 changes: 37 additions & 9 deletions aql/src/main/antlr4/org/ehrbase/aql/parser/Aql.g4
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ grammar Aql;

query : queryExpr ;

queryExpr : select from (where)? (orderBy limitExpr? | limitExpr orderBy?)? EOF ;
queryExpr : select from (where)? (orderBy (limit offset?)? | (limit offset?) orderBy?)? EOF ;

select
: SELECT selectExpr
Expand All @@ -30,7 +30,10 @@ topExpr
// | TOP INTEGER FORWARD ;

function
: FUNCTION_IDENTIFIER OPEN_PAR (IDENTIFIER|identifiedPath|operand) (COMMA (IDENTIFIER|identifiedPath|operand))* CLOSE_PAR;
: FUNCTION_IDENTIFIER OPEN_PAR (IDENTIFIER|identifiedPath|operand|) (COMMA (IDENTIFIER|identifiedPath|operand))* CLOSE_PAR;

castFunction :
CAST_FUNCTION_IDENTIFIER OPEN_PAR (IDENTIFIER|identifiedPath|operand) AS STRING CLOSE_PAR;

extension
: EXTENSION_IDENTIFIER OPEN_PAR STRING COMMA STRING CLOSE_PAR;
Expand All @@ -41,8 +44,8 @@ where
orderBy
: ORDERBY orderBySeq ;

limitExpr
: LIMIT INTEGER (offset)?;
limit
: LIMIT INTEGER;

offset
: OFFSET INTEGER;
Expand All @@ -67,9 +70,19 @@ selectExpr

stdExpression
: function
| castFunction
| extension
| INTEGER
| STRING
| FLOAT
| REAL
| DATE
| PARAMETER
| BOOLEAN
| TRUE
| FALSE
| NULL
| UNKNOWN
;

//variableSeq_
Expand Down Expand Up @@ -176,6 +189,7 @@ nodePredicateRegEx

matchesOperand
: valueListItems
| identifiedPath
| URIVALUE ;

valueListItems
Expand Down Expand Up @@ -216,14 +230,18 @@ operand
: STRING
| INTEGER
| FLOAT
| REAL
| DATE
| PARAMETER
| BOOLEAN
| TRUE
| FALSE
| NULL
| UNKNOWN
| invokeOperand;
| invokeOperand
| function
| castFunction;


invokeOperand
: invokeExpr;
Expand Down Expand Up @@ -305,24 +323,28 @@ UNKNOWN: U N K N O W N;
TRUE: T R U E;
FALSE: F A L S E;


//demographic binding
PERSON: P E R S O N ;
AGENT: A G E N T ;
ORGANISATION: O R G A N I S A T I O N ;
GROUP: G R O U P ;

FUNCTION_IDENTIFIER : COUNT | AVG | BOOL_AND | BOOL_OR | EVERY | MAX | MIN | SUM |
//statistic
//statistics
CORR | COVAR_POP | COVAR_SAMP | REGR_AVGX | REGR_AVGY | REGR_COUNT | REGR_INTERCEPT | REGR_R2 | REGR_SLOPE | REGR_SXX |
REGR_SXY | REGR_SYY | STDDEV | STDDEV_POP | STDDEV_SAMP | VARIANCE | VAR_POP | VAR_SAMP |
//string function
//string functions
SUBSTR | STRPOS | SPLIT_PART | BTRIM | CONCAT | CONCAT_WS | DECODE | ENCODE | FORMAT | INITCAP | LEFT | LENGTH | LPAD | LTRIM |
REGEXP_MATCH | REGEXP_REPLACE | REGEXP_SPLIT_TO_ARRAY | REGEXP_SPLIT_TO_TABLE | REPEAT | REPLACE | REVERSE | RIGHT | RPAD |
RTRIM | TRANSLATE |
//encoding function
RAW_COMPOSITION_ENCODE
//encoding functions
RAW_COMPOSITION_ENCODE |
//basic date functions
NOW | AGE | CURRENT_TIME | CURRENT_DATE

;
CAST_FUNCTION_IDENTIFIER: C A S T;


EXTENSION_IDENTIFIER: '_' E X T;
Expand All @@ -342,6 +364,7 @@ DEMOGRAPHIC

INTEGER : '-'? DIGIT+;
FLOAT : '-'? DIGIT+ '.' DIGIT+;
REAL : '-'? DIGIT+ ('.' DIGIT+)? (E (|'+'|'-') DIGIT+)?;
DATE : '\'' DIGIT DIGIT DIGIT DIGIT DIGIT DIGIT DIGIT DIGIT 'T' DIGIT DIGIT DIGIT DIGIT DIGIT DIGIT '.' DIGIT DIGIT DIGIT '+' DIGIT DIGIT DIGIT DIGIT '\'';
PARAMETER : '$' LETTER IDCHAR*;

Expand Down Expand Up @@ -440,6 +463,11 @@ VARIANCE : V A R I A N C E;
VAR_POP : V A R '_' P O P;
VAR_SAMP : V A R '_' S A M P;
RAW_COMPOSITION_ENCODE : '_' '_' R A W '_' C O M P O S I T I O N '_' E N C O D E;
CAST : C A S T;
NOW : N O W;
AGE : A G E;
CURRENT_TIME : C U R R E N T '_' T I M E;
CURRENT_DATE : C U R R E N T '_' D A T E;

fragment
ESC_SEQ
Expand Down
5 changes: 5 additions & 0 deletions aql/src/main/java/org/ehrbase/aql/binder/AqlBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ public Pair<EntityQuery<Record>, List<ParameterValue>> bind(AqlDto aqlDto) {
query.top(TopExpresion.backward(aqlDto.getSelect().getTopCount()));
}

// build distinct
if (aqlDto.getSelect().isDistinct()) {
query.distinct(true);
}

// build order by
if (!CollectionUtils.isEmpty(aqlDto.getOrderBy())) {
query.orderBy(orderByBinder.bind(aqlDto.getOrderBy(), containmentMap));
Expand Down
22 changes: 22 additions & 0 deletions aql/src/main/java/org/ehrbase/aql/binder/SelectBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@

import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.ehrbase.aql.dto.select.FunctionDto;
import org.ehrbase.aql.dto.select.SelectFieldDto;
import org.ehrbase.aql.dto.select.SelectStatementDto;
import org.ehrbase.aql.parser.AqlParseException;
import org.ehrbase.client.aql.containment.Containment;
import org.ehrbase.client.aql.field.NativeSelectAqlField;
import org.ehrbase.client.aql.field.SelectAqlField;
import org.ehrbase.client.aql.funtion.Function;
import org.ehrbase.util.exception.SdkException;

public class SelectBinder {
Expand All @@ -32,13 +35,32 @@ public SelectAqlField<Object> bind(SelectStatementDto dto, Map<Integer, Containm
SelectAqlField<Object> selectAqlField;
if (dto instanceof SelectFieldDto) {
selectAqlField = handleSelectFieldDto((SelectFieldDto) dto, containmentMap);
} else if (dto instanceof FunctionDto) {
selectAqlField = handleFunctionDto((FunctionDto) dto, containmentMap);
} else {
throw new SdkException(
String.format("Unexpected class: %s", dto.getClass().getSimpleName()));
}
return selectAqlField;
}

private SelectAqlField<Object> handleFunctionDto(FunctionDto dto, Map<Integer, Containment> containmentMap) {

switch (dto.getAqlFunction()) {
case COUNT:
return (SelectAqlField) Function.count(bind(dto.getParameters().get(0), containmentMap), dto.getName());
case MAX:
return (SelectAqlField) Function.max(bind(dto.getParameters().get(0), containmentMap), dto.getName());
case MIN:
return (SelectAqlField) Function.min(bind(dto.getParameters().get(0), containmentMap), dto.getName());
case AVG:
return (SelectAqlField) Function.avg(bind(dto.getParameters().get(0), containmentMap), dto.getName());
default:
throw new AqlParseException(String.format(
"Unsupported Funktion %s", dto.getAqlFunction().name()));
}
}

public SelectAqlField<Object> handleSelectFieldDto(SelectFieldDto dto, Map<Integer, Containment> containmentMap) {
SelectAqlField<Object> selectAqlField;
selectAqlField = new NativeSelectAqlField<>(
Expand Down
8 changes: 8 additions & 0 deletions aql/src/main/java/org/ehrbase/aql/binder/WhereBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
import org.ehrbase.aql.dto.condition.ConditionDto;
import org.ehrbase.aql.dto.condition.ConditionLogicalOperatorDto;
import org.ehrbase.aql.dto.condition.ConditionLogicalOperatorSymbol;
import org.ehrbase.aql.dto.condition.ExistsConditionOperatorDto;
import org.ehrbase.aql.dto.condition.MatchesOperatorDto;
import org.ehrbase.aql.dto.condition.NotConditionOperatorDto;
import org.ehrbase.aql.dto.condition.ParameterValue;
import org.ehrbase.aql.dto.condition.SimpleValue;
import org.ehrbase.client.aql.condition.Condition;
Expand Down Expand Up @@ -68,6 +70,12 @@ public Pair<Condition, List<ParameterValue>> bind(ConditionDto dto, Map<Integer,
condition = Condition.matches(
selectBinder.bind(((MatchesOperatorDto) dto).getStatement(), containmentMap), value);

} else if (dto instanceof ExistsConditionOperatorDto) {
condition =
Condition.exists(selectBinder.bind(((ExistsConditionOperatorDto) dto).getValue(), containmentMap));
} else if (dto instanceof NotConditionOperatorDto) {
condition = Condition.not(bind(((NotConditionOperatorDto) dto).getConditionDto(), containmentMap)
.getLeft());
} else {
throw new SdkException(
String.format("Unexpected class: %s", dto.getClass().getSimpleName()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,36 @@
*/
package org.ehrbase.aql.dto.condition;

import java.util.Arrays;

public enum ConditionComparisonOperatorSymbol {
EQ("equal"),
NEQ("notEqual"),
GT_EQ("greaterOrEqual"),
GT("greaterThan"),
LT_EQ("lessOrEqual"),
LT("lessThan");
EQ("equal", "="),
NEQ("notEqual", "!="),
GT_EQ("greaterOrEqual", ">="),
GT("greaterThan", ">"),
LT_EQ("lessOrEqual", "<="),
LT("lessThan", "<");

private final String javaName;
private final String symbole;

ConditionComparisonOperatorSymbol(String javaName) {
ConditionComparisonOperatorSymbol(String javaName, String symbole) {
this.javaName = javaName;
this.symbole = symbole;
}

public String getJavaName() {
return javaName;
}

public String getSymbole() {
return symbole;
}

public static ConditionComparisonOperatorSymbol fromSymbol(String symbole) {
return Arrays.stream(values())
.filter(s -> s.getSymbole().equals(symbole))
.findAny()
.orElseThrow();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,28 @@

import java.util.List;

public class ConditionLogicalOperatorDto implements ConditionDto {
public class ConditionLogicalOperatorDto
implements ConditionDto, LogicalOperatorDto<ConditionLogicalOperatorSymbol, ConditionDto> {

private ConditionLogicalOperatorSymbol symbol;
private List<ConditionDto> values;

@Override
public ConditionLogicalOperatorSymbol getSymbol() {
return this.symbol;
}

@Override
public List<ConditionDto> getValues() {
return this.values;
}

@Override
public void setSymbol(ConditionLogicalOperatorSymbol symbol) {
this.symbol = symbol;
}

@Override
public void setValues(List<ConditionDto> values) {
this.values = values;
}
Expand Down
Loading

0 comments on commit dc89440

Please sign in to comment.