Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

References

CPS-1273

Query data node using cps-path

Comparative Operators Condition

In query of data node, when we can query using <,>,>=,<= comparative operators . Also we can combine  “AND/OR” conditions with comparative operators . Below are the some examples


#
cps-path

Output

1

Using "<" condition

cps-path : //books[@price<15]


Code Block
titleJson Response
collapsetrue
[
    {
        "book-store:books": {
            "lang": "English",
            "price": 10,
            "title": "Matilda",
            "authors": [
                "Roald Dahl"
            ],
            "editions": [
                1988,
                2000
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "English",
            "price": 14,
            "title": "The Light Fantastic",
            "authors": [
                "Terry Pratchett"
            ],
            "editions": [
                1986
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "English",
            "price": 12,
            "title": "The Colour of Magic",
            "authors": [
                "Terry Pratchett"
            ],
            "editions": [
                1983
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "English",
            "price": 13,
            "title": "Good Omens",
            "authors": [
                "Terry Pratchett",
                "Neil Gaiman"
            ],
            "editions": [
                2006
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "N/A",
            "price": 11,
            "title": "Logarithm tables",
            "authors": [
                "Joe Bloggs"
            ],
            "editions": [
                2009
            ]
        }
    }
]
            
2

Using "<" with OR condition

cps-path : //books[@price<10 or @lang="German"]


Code Block
titleJson Response
collapsetrue
[
    {
        "book-store:books": {
            "lang": "German",
            "price": 39,
            "title": "Debian GNU/Linux",
            "authors": [
                "Peter H. Ganten",
                "Wulf Alex"
            ],
            "editions": [
                2013,
                2021,
                2007
            ]
        }
    }
]
            
3

Using ">" with AND condition

cps-path : //books[@price>13 and @title="A Book with No Language"]


Code Block
titleJson Response
collapsetrue
 [
    {
        "book-store:books": {
            "lang": "",
            "price": 20,
            "title": "A Book with No Language",
            "authors": [
                "Joe Bloggs"
            ],
            "editions": [
                2023
            ]
        }
    }
]                                                                                                           


4

Using ">=" with combination of OR/AND condition

cps-path : //books[@price>=13 or @lang="Spanish" and @title="Good Omens"]


Code Block
titleJson Response
collapsetrue
[
    {
        "book-store:books": {
            "lang": "English",
            "price": 15,
            "title": "The Gruffalo",
            "authors": [
                "Julia Donaldson"
            ],
            "editions": [
                1999
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "English",
            "price": 15,
            "title": "Annihilation",
            "authors": [
                "Jeff VanderMeer"
            ],
            "editions": [
                2014
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "English",
            "price": 14,
            "title": "The Light Fantastic",
            "authors": [
                "Terry Pratchett"
            ],
            "editions": [
                1986
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "English",
            "price": 13,

Issues & Decisions

#

Changes made

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 

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("'");
    }
}
3Test 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
            "title": "Good Omens",
     
|
 
cpsPath
      "authors": [
                "Terry Pratchett",
                "Neil Gaiman"
         
||
 
expectedXPaths
  ],
  
'more
 
than
 
one
 
leaf'
       
| '//author[@FirstName="Joe" or @title="title"]'
"editions": [
                2006
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "",
            "price": 20,
            "title": "A Book with No Language",
            
|| ["/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

"authors": [
                "Joe Bloggs"
            ],
            "editions": [
                2023
            ]
        }
    },
    {
        "book-store:books": {
            "lang": "German",
            "price": 39,
            "title": "Debian GNU/Linux",
            "authors": [
                "Peter H. Ganten",
                "Wulf Alex"
            ],
            "editions": [
                2013,
                2021,
                2007
            ]
        }
    }
]    


5

Using "<="  with combination of AND/OR condition

cps-path : //books[@price<=15 and @title="Annihilation" or @lang="Spanish"]


Code Block
titleJson Response
collapsetrue
[
    {
        "book-store:books": {
            "lang": "English",
            "price": 15,
            "title": "Annihilation",
            "authors": [
                "Jeff VanderMeer"
            ],
            "editions": [
                2014
            ]
        }
    }
]          



Implementation of Comparative Operator

1.Update antlr parser to recognize <,>,<=,>=  in leaf-condition
2.Implement required (native) query
3.Add Integration tests for comparative operators
4.Update documentation
5.demo to team 

Query used  : SELECT * FROM fragment WHERE anchor_id = :anchorId AND xpath ~ :xpathRegex AND ((attributes ->> 'price')\:\:int > '13' and  attributes @> '{"title":"A Book with No Language"}')

Limitations

1.Using comparative operators with string values will lead to an error at runtime. This error can't be validated earlier as the datatype is unknown until the execution phaseWould like to get help with it.