Skip to content

Commit 3cfdad1

Browse files
committed
Different structure
1 parent e0c19c6 commit 3cfdad1

File tree

1 file changed

+92
-40
lines changed

1 file changed

+92
-40
lines changed

java/working-with-cql/query-api.md

Lines changed: 92 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,30 +1308,73 @@ The Query Builder API supports using expressions in many places. Expressions con
13081308

13091309
### Entity References {#entity-refs}
13101310

1311-
Entity references specify entity sets. They can be used to define the target entity set of a [CQL](../../cds/cql) statement or be an argument of event handler.
1311+
Entity references specify entity sets and define the target entity set of a [CQL](../../cds/cql) statement or be an argument of event handler.
13121312

1313-
You can also get [entity references](query-execution#entity-refs) from the result of a CDS QL statement to address an entity via its key values in other statements.
1313+
Reference consists of _segments_ that define the path from the entity's root to the certain part of it. Each segment has the _identifier_ with the name of the entity or an element and an optional filter _predicate_. These predicates might include other references.
13141314

1315-
Each reference has ordered sequence of _segments_ that define the path from the entity's root to the certain part of it. Segment has the _identifier_ with the name of the entity or an element and optional filter _predicate_.
1315+
References can be represented in the JSON following an [Expression](../../cds/cxn) notation.
13161316

1317-
Existing reference can be reused as an object or a variable, or a new reference can be built on top of it. References are not bound to the particular model and are not checked against it while they are being built.
1317+
References are either _absolute_ or _relative_. Absolute refs always have fully qualified name of the type in their first segment. Relative references need other absolute reference to which they relate.
13181318

1319-
References can be _absolute_ or _relative_. Absolute reference has fully qualified entity name as the identifier in the first segment. They usually have associations as their segments.
1320-
1321-
You start with the reference pointing to a book with certain key. You build it using corresponding [model interfaces](../cqn-services/persistence-services#model-interfaces) providing you the methods that corresponds to the elements of the book.
1319+
Simplest kind of absolute reference is the reference to the entity set, for example, to all books.
13221320

13231321
```java
1324-
StructuredType<?> bookWithId = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")); // Books(ID=...)
1322+
Books_ books = CQL.entity(Books_.class); // {"ref":["sap.capire.bookshop.Books"]}
13251323

1326-
// ref is complete and cannot be extended anymore
13271324
StructuredTypeRef ref = bookWithId.asRef(); // or CqnStructuredTypeRef which is cleaner equivalent type
13281325
```
13291326

1330-
This reference is absolute and can be used as the source of the statement or several statements.
1327+
Method `asRef()` seals the reference and makes it immutable.
1328+
1329+
Relative references typically reference elements of the entity, for example, title of the book. They are members of select list of the CQL statement and are relative to its source.
13311330

13321331
```java
1333-
import com.sap.cds.ql.CQL;
1332+
CqnElementRef title = CQL.entity(Books_.class).title(); // {"ref":["title"]}
1333+
CqnElementRef dynamicTitle = CQL.get(Books.TITLE); // {"ref":["title"]}
1334+
```
1335+
1336+
New references are constructed with [model interfaces](../cqn-services/persistence-services#model-interfaces) or via API that is also used to build [CQL statements](/java/working-with-cql/query-api#concepts). For most of the application code, the model interfaces are the recommended way to do this.
1337+
1338+
References might also represent navigation within the structured entity or between different entities via its associations. For example, below is the reference that represents the path from the book to its chapters.
1339+
1340+
```java
1341+
CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef();
1342+
```
1343+
1344+
Each segment of this reference has an identifier (typically an association or composition) and the filter.
1345+
1346+
```json
1347+
{
1348+
"ref": [
1349+
{
1350+
"id": "sap.capire.bookshop.Books",
1351+
"where": [
1352+
{ "ref": ["ID"]}, "=", {"val": "..."}
1353+
]
1354+
},
1355+
{
1356+
"id": "chapters",
1357+
"where": [
1358+
{ "ref": ["ID"]}, "=", {"val": "..."}
1359+
]
1360+
},
1361+
{
1362+
"id": "pages",
1363+
"where": [
1364+
{ "ref": ["ID"]}, "=", {"val": "..."}
1365+
]
1366+
}
1367+
]
1368+
}
1369+
```
1370+
1371+
Existing reference can be reused as an object or a variable, or a new reference can be built on top of it. They can be introspected with [`CqnVisitor`](/java/working-with-cql/query-introspection#cqnvisitor). They are not bound to the particular model and are not checked against it while they are being built.
1372+
1373+
Each reference can be serialized as JSON and also renders JSON as its `toString()` implementation. Do not use this JSON to process the references, for example, to extract values from them or to compare references between each other.
1374+
1375+
Absolute references can be used as sources of the CQL statements and statements generated by CAP typically have them as their [sources](/java/working-with-cql/query-api#from-reference).
13341376

1377+
```java
13351378
// bookshop.Books[year = 2020].author // [!code focus]
13361379
Authors_ authors = CQL.entity(Books_.class).filter(b -> b.year().eq(2020)).author(); // [!code focus]
13371380

@@ -1343,67 +1386,76 @@ StructuredType<?> authors =
13431386
Select.from(authors).columns("name"); // [!code focus]
13441387
```
13451388

1346-
If you want to use this ref to fetch the author of this book, you use `CQL.entity(...)` to make it typed again and add one more segment to it. Note, that this does not check that original ref is indeed the ref to the book, this only lets you use the required model interface.
1389+
The resulting statement has two references: one absolute describing the author and the one relative, describing the name of the author.
1390+
1391+
References can be analyzed with the [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer) to bind it back to the model, for example, to find annotations or extract filter values.
1392+
1393+
The existing references obtained from the statements or [injected in custom handlers](/java/event-handlers/#entity-reference-arguments) can be used to produce new references.
1394+
1395+
Given that there is simple reference pointing to the book created as follows.
13471396

13481397
```java
1349-
CqnStructuredTypeRef refToAuthor = CQL.entity(Books_.class, ref).author().asRef(); // Books(ID=...)/author
1398+
// {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]}
1399+
CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).asRef(); [!code focus]
13501400
```
13511401

1352-
`CQL.to(...)` lets you use dynamic syntax to express the same.
1402+
To navigate to author of the book, use `CQL.entity(...)` to make it typed again and add one more segment to it. Note, that this does not check that original reference is indeed the reference to the book, this only lets you use required model interface.
13531403

13541404
```java
1355-
CqnStructuredTypeRef toAuthor = CQL.to(ref.segments()).to("author").asRef(); // Books(ID=...)/author
1405+
// {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]},"author"]}
1406+
CqnStructuredTypeRef refToAuthor = CQL.entity(Books_.class, ref).author().asRef(); // [!code focus]
13561407
```
13571408

1358-
The result of both is the same reference. Model interfaces are strongly recommended for custom handlers as they are easier to use.
1409+
With `CQL.to(...)` the same is produced dynamically.
13591410

1360-
If you need to navigate to the parent, you can do it using the dynamic syntax to strip the last segment of it. This also accounts for the case when the reference contains longer path.
1411+
```java
1412+
// {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]},"author"]}
1413+
CqnStructuredTypeRef toAuthor = CQL.to(ref.segments()).to("author").asRef(); // [!code focus]
1414+
```
1415+
1416+
This new reference might be used as the root of its own statement to read or change the author.
1417+
1418+
With this one, one might need to navigate to the parent again. This is done by stripping the segments from the back of the reference.
13611419

13621420
```java
1421+
// {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]}
13631422
CqnStructuredTypeRef toParent = CQL.to(
1364-
refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // Books(ID=...)
1423+
refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // [!code focus]
13651424
```
13661425

1367-
You can also construct ref that starts from the first segment to navigate to different path of the same root.
1426+
There is the method `rootSegment()` that can be used to construct the reference starting with the same root as the existing reference. This is useful when you require navigation to different part of the same structured type, e.g. for example from the book's author to the pages of it.
13681427

13691428
```java
13701429
CqnStructuredTypeRef toPagesOfTheBook = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").to("pages").asRef();
13711430
```
13721431

1373-
You can use the `CQL.entity(...)` to use convenience of model interfaces by casing it.
1432+
You can use the `CQL.entity(...)` to use convenience of model interfaces for this with additional cast.
13741433

13751434
```java
13761435
CqnStructuredTypeRef toPagesOfTheBook = CQL.entity(Books_.class,
13771436
CQL.to(List.of(refToAuthor.rootSegment())).asRef()).chapters().pages().asRef();
13781437
```
13791438

1380-
Result of both statements above is the same reference and the values resulting from these are equivalent.
1439+
Same references is produced as the result of last two statements. You, of course, have to provide the filters, if to-many associations used in them.
13811440

1382-
To-many compositions usually require filters to be complete and you can use both static and dynamic API to include them as follows:
1441+
References can be copied to produce other refs with in-place modification available for its segments as follows.
13831442

13841443
```java
1385-
// yields Books(ID=...)/chapters(ID=...)/pages(ID=...)
1386-
1387-
CqnStructuredTypeRef dynamicRef = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").filter(CQL.get("ID").eq("...")).asRef();
1444+
StructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef();
1445+
RefBuilder<StructuredTypeRef> builder = CQL.copy(ref);
1446+
builder.segments().forEach(s -> {
1447+
// add new predicate to each segment
1448+
s.filter(CQL.and(CQL.get(Books.GENRE).eq("Fiction"), s.filter().orElse(null)));
1449+
});
13881450

1389-
CqnStructuredTypeRef staticRef = CQL.entity(Books_.class,
1390-
CQL.to(List.of(refToAuthor.rootSegment())).asRef()).chapters(c -> c.ID().eq("...")).asRef();
1451+
StructuredTypeRef copy = builder.build(); // new reference is ready
13911452
```
13921453

1393-
Filters that you define for references can contain complex predicates referring to other elements, for example, to express complex conditions and path expressions.
1394-
1395-
Segments of the references also usable as the variables and you can inspect them.
1396-
1397-
```java
1398-
r.rootSegment().id(); // yields Books
1399-
r.rootSegment().filter(); // filter an Optional with the predicate
1400-
```
1454+
The code that manipulates the references must be tested thoroughly and you always need to ensure that you do not loose the filters or change the reference so that it becomes inconsistent.
14011455

1402-
If you want to reflect the types behind the ref, you need to use [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer) that parses it and binds it back to the model. Use it, for example, to find annotations or extract key values.
1403-
1404-
References are not comparable so they cannot be used as a keys in maps and values in the sets. You should not compare references between each other.
1405-
1406-
Each reference can be serialized as JSON and also renders JSON as its `toString()` implementation. Do not use this JSON to process the references, for example, to extract values from them or to compare references between each other.
1456+
:::warning Limitation
1457+
The references are not comparable between each other. They cannot be used as keys of maps or values in a set.
1458+
:::
14071459

14081460
### Elements References {#element-refs}
14091461

0 commit comments

Comments
 (0)