Introspecting CQN Queries

    API to introspect CDS QL statements in Java



    The CDS Query Introspection API allows to analyze CQN statements and extract values and information on the CDS entities in references.

    The CqnAnalyzer can be constructed from a CDS model:

    CdsModel cdsModel = context.getModel();
    CqnAnalyzer cqnAnalyzer = CqnAnalyzer.create(cdsModel);

    Furthermore the static isCountQuery(cqn) method can be used to check if a CQN statement only returns a single count:

    // cqn: Select.from("Books").columns(CQL.count().as("bookCount"));
    boolean isCount = CqnAnalyzer.isCountQuery(cqn);  // true


    Given the following CDS model and CQL query:

    entity Orders {
      key OrderNo : String;
      Items       : Composition of many OrderItems on Items.parent = $self;
    entity OrderItems {
      key ID : Integer;
      book   : Association to Books;

    Find this source also in cap/samples.

    --CQL query
    SELECT from Orders[OrderNo = '42'].items[ID = 1]

    the corresponding CQN statement can be analyzed using the analyze method of the CqnAnalyzer:

    CqnStatement cqn = context.getCqn();
    AnalysisResult result = cqnAnalyzer.analyze(cqn.ref());

    Resolving CDS Entities

    Based on the AnalysisResult, information on the CDS entities can be accessed through the Reflection API:

    CdsEntity order = result.rootEntity();   // Orders
    CdsEntity item  = result.targetEntity(); // OrderItems

    Extracting Filter Values

    Extracting filter values from CQN statements is supported for noncomplex predicates where the values can be unambiguously determined.

    The key values of the entities can be extracted as a map using the rootKeys and targetKeys method of the AnalysisResult object:

    Map<String, Object> rootKeys = result.rootKeys();
    String orderNo = (String) rootKeys.get("OrderNo"); // 42
    Map<String, Object> targetKeys  = result.targetKeys();
    Integer itemId = (Integer) targetKeys.get("ID");   // 1

    To extract all filter values of the target entity including nonkey values, the targetValues method can be used:

    Map<String, Object> filterValues = result.targetValues();

    For CqnSelect, CqnUpdate, and CqnDelete, values can also be extracted from the statement’s where condition:

    --CQL query
    SELECT from Orders[OrderNo = '42'].items where ID = 3 and status = 'open'
    CqnSelect select = context.getCqn();
    AnalysisResult result = cqnAnalyzer.analyze(select);
    Map<String, Object> targetKeys = result.targetKeys();
    Integer itemId = (Integer) targetKeys.get("ID");   // 3
    Map<String, Object> filterValues = result.targetValues();
    String status = (String) filterValues.get("status");   // 'open'

    Using the Iterator

    The methods prefixed with root and target access the first resp. last segment of the CQN statement’s ref. If the ref has more than two segments, such as:

    --CQL query
    SELECT from Orders[OrderNo = '42'].items[ID = 1].book

    the segment items can be analyzed using an iterator:

    Iterator<ResolvedSegment> iterator = result.iterator();
    CdsEntity order =;
    CdsEntity item  =;
    CdsEntity book  =;

    or a reverse iterator starting from the last segment:

    Iterator<ResolvedSegment> iterator = result.reverse();
    CdsEntity book  =;
    CdsEntity item  =;
    CdsEntity order =;

    In the same way, also the filter values for each segment can be extracted using the values and keys method instead of the entity method.

    Show/Hide Beta Features