Search

Introspecting CQN Queries

API to introspect CDS QL statements in Java

Content

Introduction

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

The CqnAnalyzer can be constructed from a CDS model:

import com.sap.cds.ql.cqn.CqnAnalyzer;

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

Usage

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 = iterator.next().entity();
CdsEntity item  = iterator.next().entity();
CdsEntity book  = iterator.next().entity();

or a reverse iterator starting from the last segment:

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

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