Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync/cdr 423 enhance sdk parser #376

Merged
merged 20 commits into from
Jul 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am aware it is from the other grammar, but this would also parse e.g. CONCAT( , "x").
How about 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()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo "Unsupported Function"

}
}

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