Add OR operator to cps-path
steps to be followed :
- Antlr grammer file changes should be made to recognise OR
- Implement the code logic in order to add OR functionality
- Add test cases
- Update documentation
- Demo to team
Here following are the antlr changes which made to recognise the OR
So, Cps has and condition which is applied with leaf condition ,similarly we have added or to the antlr
path
Issues & Decisions
# | Issue | Notes | Decision |
---|
1 | Antlr changes to be made to recognize OR as input in cps-path | Adding OR operator to the antlr grammer file PATH : cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4 Solution : listElementRef : OB leafCondition ( ( KW_AND | KW_OR) leafCondition)* CB multipleLeafConditions : OB leafCondition ( ( KW_AND | KW_OR) leafCondition)* CB |
---|
The problem is we are unable to find the logic how and condition has been implemented , like is there any query written for it.
...
It is tested by antlr test | |
2 | Code changes made to recognise the operatoe i.e., and ,or | PATH:cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java |
---|
...
Solution: String parent = ctx.getParent().getText(); String payload = ctx.getPayload().getText(); payloads.add(payload); String operator = findOperator(parent, payloads); appendCondition(normalizedXpathBuilder, ctx.leafName().getText(), comparisonValue, operator); if (processingAncestorAxis) { appendCondition(normalizedAncestorPathBuilder, ctx.leafName().getText(), comparisonValue, operator); } } private String findOperator(String parent, List<String> payloads) { StringBuilder parentStringBuilder = new StringBuilder(parent); try { payloads.forEach(payload -> parentStringBuilder.delete(parentStringBuilder.indexOf(payload), parentStringBuilder.indexOf(payload) + payload.length())); parentStringBuilder.delete(0, parentStringBuilder.indexOf("[") + 1); return parentStringBuilder.toString().trim(); } catch (RuntimeException e) { return null; } } private void appendCondition(final StringBuilder currentNormalizedPathBuilder, final String name, final Object value, String operator) { final char lastCharacter = currentNormalizedPathBuilder.charAt(currentNormalizedPathBuilder.length() - 1); currentNormalizedPathBuilder.append(lastCharacter == '[' ? "" : " " + operator + " "); currentNormalizedPathBuilder.append("@"); currentNormalizedPathBuilder.append(name); currentNormalizedPathBuilder.append("='"); currentNormalizedPathBuilder.append(value); currentNormalizedPathBuilder.append("'"); } }
|
|
3 | Test Case written to test code changes | PATH:cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy 1. def 'Parse cps path having OR operator containing #scenario.'() { when: 'the given cps path is parsed' def result = CpsPathUtil.getCpsPathQuery(cpsPath) then: 'the query has the right normalized xpath type' assert result.normalizedXpath == expectedNormalizedXPath where: 'the following data is used' scenario | cpsPath || expectedNormalizedXPath 'parent & child with more than one attribute' | '/parent/child[@key1=1 or @key2="abc"]/child2' || "/parent/child[@key1='1' or @key2='abc']/child2" } 2. def 'Parse cps path that ends with a yang list containing #scenario and having or operator '() { when: 'the given cps path is parsed' def result = CpsPathQuery.createFrom(cpsPath) then: 'the query has the right xpath type' result.cpsPathPrefixType == DESCENDANT and: 'the right parameters are set' result.descendantName == "child" result.leavesData.size() == expectedNumberOfLeaves where: 'the following data is used' scenario | cpsPath || expectedNumberOfLeaves 'more than one attribute' | '//child[@int-leaf=5 or @leaf-name="leaf value"]' || 2 }
|
---|
4 | Testcases in CpsDataPersistenceQueryDataNodeSpec.groovy | @Sql([CLEAR_DATA, SET_DATA]) def 'Cps Path query using descendant anywhere with #scenario OR condition(s) for a container element.'() { when: 'a query is executed to get a data node by the given cps path' def result = objectUnderTest.queryDataNodes(DATASPACE_NAME, ANCHOR_FOR_SHOP_EXAMPLE, cpsPath, OMIT_DESCENDANTS) then: 'the correct number of data nodes are retrieved' result.size() == expectedXPaths.size() and: 'xpaths of the retrieved data nodes are as expected' for (int i = 0; i < result.size(); i++) { assert result[i].getXpath() == expectedXPaths[i] } where: 'the following data is used' scenario | cpsPath || expectedXPaths 'more than one leaf' | '//author[@FirstName="Joe" or @title="title"]' || ["/shops/shop[@id='1']/categories[@code='1']/book/author[@FirstName='Joe' or @Surname='Bloggs']"] 'leaves has OR condition' | '//author[@FirstName="Joe" or @Firstname="Jane"]' || ["/shops/shop[@id=''1'']/categories[@code=''1'']/book/author[@FirstName='Joe']", "/shops/shop[@id=''1'']/categories[@code=''2'']/book/author[@FirstName=''Jane'']"] } |
---|
So, this groovy testcase is based on the Query where it as
"SELECT * FROM FRAGMENT WHERE anchor_id = :anchorId AND xpath ~ :xpathRegex AND attributes @> :leafDataAsJson\\:\\:jsonb
The problem is we are unable to find the logic how AND condition has been implemented , Also OR works as AND
In this query they are passing anchor id,xpatRegex,Attributes but no where we see either of two operators(i.e, and/or).
Here we had analysis that whatever the attributes having jsondata is taking as graphdatabase that inbuilt functions as AND
So, would like to get help with it.
to-do:
Need to implement the logic for OR Operation
But there are few doubts regarding this to be discussed