From e0c19c6695b71cdcc403c4d6603d81ca0981a243 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Wed, 15 Oct 2025 16:55:54 +0200 Subject: [PATCH 01/16] Draft --- java/working-with-cql/query-api.md | 113 ++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 3 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index b78376698..490ebbc0e 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -131,7 +131,6 @@ In the [CDS Query Language (CQL)](/cds/cql) builder, the lambda expression `o -> To target components of a structured document, we recommend using path expressions with infix filters. ::: - ### Filters {#target-entity-filters} Besides using infix filters in path expressions, the `Select`, `Update`, and `Delete` builders support filtering the [target entity set](#target-entity-sets) via the `where` method. Using `where` is equivalent to defining an infix filter on the last segment of a path expression in the statement's `from` / `entity` clause. For statements that have both, an infix filter on the last path segment and a `where` filter, the resulting target filter is the conjunction (`and`) of the infix filter and the `where` filter. @@ -1309,7 +1308,26 @@ The Query Builder API supports using expressions in many places. Expressions con ### Entity References {#entity-refs} -Entity references specify entity sets. They can be used to define the target entity set of a [CQL](../../cds/cql) statement. They can either be defined inline using lambda expressions in the Query Builder (see [Target Entity Sets](#target-entity-sets)) or via the `CQL.entity` method, which is available in an _untyped_ version as well as in a _typed_ version that uses the generated [model interfaces](../cqn-services/persistence-services#model-interfaces). The following example shows an entity reference describing the set of *authors* that have published books in the year 2020: +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. + +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. + +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_. + +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. + +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. + +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. + +```java +StructuredType bookWithId = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")); // Books(ID=...) + +// ref is complete and cannot be extended anymore +StructuredTypeRef ref = bookWithId.asRef(); // or CqnStructuredTypeRef which is cleaner equivalent type +``` + +This reference is absolute and can be used as the source of the statement or several statements. ```java import com.sap.cds.ql.CQL; @@ -1325,8 +1343,97 @@ StructuredType authors = Select.from(authors).columns("name"); // [!code focus] ``` -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. +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. + +```java +CqnStructuredTypeRef refToAuthor = CQL.entity(Books_.class, ref).author().asRef(); // Books(ID=...)/author +``` + +`CQL.to(...)` lets you use dynamic syntax to express the same. + +```java +CqnStructuredTypeRef toAuthor = CQL.to(ref.segments()).to("author").asRef(); // Books(ID=...)/author +``` + +The result of both is the same reference. Model interfaces are strongly recommended for custom handlers as they are easier to use. + +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. + +```java +CqnStructuredTypeRef toParent = CQL.to( + refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // Books(ID=...) +``` + +You can also construct ref that starts from the first segment to navigate to different path of the same root. + +```java +CqnStructuredTypeRef toPagesOfTheBook = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").to("pages").asRef(); +``` + +You can use the `CQL.entity(...)` to use convenience of model interfaces by casing it. + +```java +CqnStructuredTypeRef toPagesOfTheBook = CQL.entity(Books_.class, + CQL.to(List.of(refToAuthor.rootSegment())).asRef()).chapters().pages().asRef(); +``` + +Result of both statements above is the same reference and the values resulting from these are equivalent. + +To-many compositions usually require filters to be complete and you can use both static and dynamic API to include them as follows: + +```java +// yields Books(ID=...)/chapters(ID=...)/pages(ID=...) + +CqnStructuredTypeRef dynamicRef = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").filter(CQL.get("ID").eq("...")).asRef(); + +CqnStructuredTypeRef staticRef = CQL.entity(Books_.class, + CQL.to(List.of(refToAuthor.rootSegment())).asRef()).chapters(c -> c.ID().eq("...")).asRef(); +``` + +Filters that you define for references can contain complex predicates referring to other elements, for example, to express complex conditions and path expressions. + +Segments of the references also usable as the variables and you can inspect them. + +```java +r.rootSegment().id(); // yields Books +r.rootSegment().filter(); // filter an Optional with the predicate +``` + +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. + +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. + +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. + +### Elements References {#element-refs} + +Element reference points to an element of the entity. Such references are usually _relative_, they do not have the name of the entity in their root. They also can include filters in their segments except _the last one_. +Most of the time, they exist as members of the [select list](#projections) of a statement or part of the statement, for example, of an expand predicate. + +The following example illustrates the difference: + +```java +CqnSelect statement = Select.from(Books_.class, b -> b.filter(f -> f.ID().eq("..."))) + .columns(b -> b.author().placeOfBirth()); + +CqnStructuredTypeRef absoluteRef = statement.ref(); // Books(ID=...) + +CqnElementRef relativeRef = statement.items().getFirst().asRef(); // author/placeOfBirth +``` + +Element references can be extended with the same APIs as the entity references. + +```java +CqnElementRef extendedRef = CQL.to(relativeRef.segments()).get("name"); // author/placeOfBirth/name +``` + +You can create _absolute_ element reference, but they are rarely used in practice. + +```java +CqnElementRef nameOfAuthor = CQL.entity(Books_.class).filter(f -> f.ID().eq("...")).author().name(); +``` +They also share the same features and limitations as the entity references and they cannot be used with [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer). ### Values From 3cfdad10503c8d83a529a2a83d88ffc0871498cb Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 16 Oct 2025 13:01:54 +0200 Subject: [PATCH 02/16] Different structure --- java/working-with-cql/query-api.md | 132 ++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 40 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 490ebbc0e..66e79150f 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1308,30 +1308,73 @@ The Query Builder API supports using expressions in many places. Expressions con ### Entity References {#entity-refs} -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. +Entity references specify entity sets and define the target entity set of a [CQL](../../cds/cql) statement or be an argument of event handler. -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. +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. -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_. +References can be represented in the JSON following an [Expression](../../cds/cxn) notation. -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. +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. -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. - -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. +Simplest kind of absolute reference is the reference to the entity set, for example, to all books. ```java -StructuredType bookWithId = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")); // Books(ID=...) +Books_ books = CQL.entity(Books_.class); // {"ref":["sap.capire.bookshop.Books"]} -// ref is complete and cannot be extended anymore StructuredTypeRef ref = bookWithId.asRef(); // or CqnStructuredTypeRef which is cleaner equivalent type ``` -This reference is absolute and can be used as the source of the statement or several statements. +Method `asRef()` seals the reference and makes it immutable. + +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. ```java -import com.sap.cds.ql.CQL; +CqnElementRef title = CQL.entity(Books_.class).title(); // {"ref":["title"]} +CqnElementRef dynamicTitle = CQL.get(Books.TITLE); // {"ref":["title"]} +``` + +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. + +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. + +```java +CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef(); +``` + +Each segment of this reference has an identifier (typically an association or composition) and the filter. + +```json +{ + "ref": [ + { + "id": "sap.capire.bookshop.Books", + "where": [ + { "ref": ["ID"]}, "=", {"val": "..."} + ] + }, + { + "id": "chapters", + "where": [ + { "ref": ["ID"]}, "=", {"val": "..."} + ] + }, + { + "id": "pages", + "where": [ + { "ref": ["ID"]}, "=", {"val": "..."} + ] + } + ] +} +``` + +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. + +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. + +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). +```java // bookshop.Books[year = 2020].author // [!code focus] Authors_ authors = CQL.entity(Books_.class).filter(b -> b.year().eq(2020)).author(); // [!code focus] @@ -1343,67 +1386,76 @@ StructuredType authors = Select.from(authors).columns("name"); // [!code focus] ``` -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. +The resulting statement has two references: one absolute describing the author and the one relative, describing the name of the author. + +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. + +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. + +Given that there is simple reference pointing to the book created as follows. ```java -CqnStructuredTypeRef refToAuthor = CQL.entity(Books_.class, ref).author().asRef(); // Books(ID=...)/author +// {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]} +CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).asRef(); [!code focus] ``` -`CQL.to(...)` lets you use dynamic syntax to express the same. +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. ```java -CqnStructuredTypeRef toAuthor = CQL.to(ref.segments()).to("author").asRef(); // Books(ID=...)/author +// {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]},"author"]} +CqnStructuredTypeRef refToAuthor = CQL.entity(Books_.class, ref).author().asRef(); // [!code focus] ``` -The result of both is the same reference. Model interfaces are strongly recommended for custom handlers as they are easier to use. +With `CQL.to(...)` the same is produced dynamically. -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. +```java +// {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]},"author"]} +CqnStructuredTypeRef toAuthor = CQL.to(ref.segments()).to("author").asRef(); // [!code focus] +``` + +This new reference might be used as the root of its own statement to read or change the author. + +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. ```java +// {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]} CqnStructuredTypeRef toParent = CQL.to( - refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // Books(ID=...) + refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // [!code focus] ``` -You can also construct ref that starts from the first segment to navigate to different path of the same root. +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. ```java CqnStructuredTypeRef toPagesOfTheBook = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").to("pages").asRef(); ``` -You can use the `CQL.entity(...)` to use convenience of model interfaces by casing it. +You can use the `CQL.entity(...)` to use convenience of model interfaces for this with additional cast. ```java CqnStructuredTypeRef toPagesOfTheBook = CQL.entity(Books_.class, CQL.to(List.of(refToAuthor.rootSegment())).asRef()).chapters().pages().asRef(); ``` -Result of both statements above is the same reference and the values resulting from these are equivalent. +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. -To-many compositions usually require filters to be complete and you can use both static and dynamic API to include them as follows: +References can be copied to produce other refs with in-place modification available for its segments as follows. ```java -// yields Books(ID=...)/chapters(ID=...)/pages(ID=...) - -CqnStructuredTypeRef dynamicRef = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").filter(CQL.get("ID").eq("...")).asRef(); +StructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef(); +RefBuilder builder = CQL.copy(ref); +builder.segments().forEach(s -> { + // add new predicate to each segment + s.filter(CQL.and(CQL.get(Books.GENRE).eq("Fiction"), s.filter().orElse(null))); +}); -CqnStructuredTypeRef staticRef = CQL.entity(Books_.class, - CQL.to(List.of(refToAuthor.rootSegment())).asRef()).chapters(c -> c.ID().eq("...")).asRef(); +StructuredTypeRef copy = builder.build(); // new reference is ready ``` -Filters that you define for references can contain complex predicates referring to other elements, for example, to express complex conditions and path expressions. - -Segments of the references also usable as the variables and you can inspect them. - -```java -r.rootSegment().id(); // yields Books -r.rootSegment().filter(); // filter an Optional with the predicate -``` +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. -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. - -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. - -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. +:::warning Limitation +The references are not comparable between each other. They cannot be used as keys of maps or values in a set. +::: ### Elements References {#element-refs} From 36fbf319bae994a8fa7f80604b1c9dff4858ae52 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 16 Oct 2025 18:37:31 +0200 Subject: [PATCH 03/16] Update java/working-with-cql/query-api.md --- java/working-with-cql/query-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 66e79150f..968c5c4ce 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1396,7 +1396,7 @@ Given that there is simple reference pointing to the book created as follows. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]} -CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).asRef(); [!code focus] +CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).asRef(); // [!code focus] ``` 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. From caa3892dd5b220224d8cc4cbc05b5763c315bd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Jeglinsky?= Date: Wed, 5 Nov 2025 10:41:32 +0100 Subject: [PATCH 04/16] Apply suggestions from code review --- java/working-with-cql/query-api.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 968c5c4ce..772c1b1a6 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1310,13 +1310,13 @@ The Query Builder API supports using expressions in many places. Expressions con Entity references specify entity sets and define the target entity set of a [CQL](../../cds/cql) statement or be an argument of event handler. -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. +A 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. -References can be represented in the JSON following an [Expression](../../cds/cxn) notation. +References can be represented in JSON following an [Expression](../../cds/cxn) notation. 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. -Simplest kind of absolute reference is the reference to the entity set, for example, to all books. +The simplest kind of absolute reference is the reference to the entity set, for example, to all books. ```java Books_ books = CQL.entity(Books_.class); // {"ref":["sap.capire.bookshop.Books"]} @@ -1324,7 +1324,7 @@ Books_ books = CQL.entity(Books_.class); // {"ref":["sap.capire.bookshop.Books"] StructuredTypeRef ref = bookWithId.asRef(); // or CqnStructuredTypeRef which is cleaner equivalent type ``` -Method `asRef()` seals the reference and makes it immutable. +The method `asRef()` seals the reference and makes it immutable. 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. @@ -1335,13 +1335,13 @@ CqnElementRef dynamicTitle = CQL.get(Books.TITLE); // {"ref":["title"]} 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. -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. +References might also represent navigation within a structured entity or between different entities using its associations. For example, in the following is the reference that represents the path from the book to its chapters. ```java CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef(); ``` -Each segment of this reference has an identifier (typically an association or composition) and the filter. +Each segment of this reference has an identifier (typically an association or composition) and a filter. ```json { @@ -1368,9 +1368,9 @@ Each segment of this reference has an identifier (typically an association or co } ``` -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. +An 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). The references are not bound to the particular model and are not checked against it while they are being built. -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. +Each reference can be serialized as JSON and also renders JSON in its `toString()` implementation. Do not use this JSON to process the references, for example, to extract values from them or to compare references with each other. 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). @@ -1386,13 +1386,13 @@ StructuredType authors = Select.from(authors).columns("name"); // [!code focus] ``` -The resulting statement has two references: one absolute describing the author and the one relative, describing the name of the author. +The resulting statement has two references: one absolute describing the author and one relative, describing the name of the author. 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. 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. -Given that there is simple reference pointing to the book created as follows. +Given that there is a simple reference pointing to the book created as follows. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]} @@ -1423,7 +1423,7 @@ CqnStructuredTypeRef toParent = CQL.to( refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // [!code focus] ``` -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. +There is a 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 parts of the same structured type, for example, from the book's author to the pages of it. ```java CqnStructuredTypeRef toPagesOfTheBook = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").to("pages").asRef(); @@ -1436,7 +1436,7 @@ CqnStructuredTypeRef toPagesOfTheBook = CQL.entity(Books_.class, CQL.to(List.of(refToAuthor.rootSegment())).asRef()).chapters().pages().asRef(); ``` -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. +The same reference is produced as the result of last two statements. You, of course, have to provide the filters, if to-many associations are used in them. References can be copied to produce other refs with in-place modification available for its segments as follows. @@ -1451,7 +1451,7 @@ builder.segments().forEach(s -> { StructuredTypeRef copy = builder.build(); // new reference is ready ``` -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. +The code that manipulates the references must be tested thoroughly and you always need to ensure that you do not lose the filters or change the reference so that it becomes inconsistent. :::warning Limitation The references are not comparable between each other. They cannot be used as keys of maps or values in a set. @@ -1459,7 +1459,7 @@ The references are not comparable between each other. They cannot be used as key ### Elements References {#element-refs} -Element reference points to an element of the entity. Such references are usually _relative_, they do not have the name of the entity in their root. They also can include filters in their segments except _the last one_. +An element reference points to an element of the entity. Such references are usually _relative_, they do not have the name of the entity in their root. They also can include filters in their segments except _the last one_. Most of the time, they exist as members of the [select list](#projections) of a statement or part of the statement, for example, of an expand predicate. The following example illustrates the difference: @@ -1479,7 +1479,7 @@ Element references can be extended with the same APIs as the entity references. CqnElementRef extendedRef = CQL.to(relativeRef.segments()).get("name"); // author/placeOfBirth/name ``` -You can create _absolute_ element reference, but they are rarely used in practice. +You can create an _absolute_ element reference, but they are rarely used in practice. ```java CqnElementRef nameOfAuthor = CQL.entity(Books_.class).filter(f -> f.ID().eq("...")).author().name(); From f2951892332024459a96406c50c1513bd26ec967 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 6 Nov 2025 10:58:23 +0100 Subject: [PATCH 05/16] rewrite --- java/working-with-cql/query-api.md | 58 +++++++++++++----------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 772c1b1a6..27a37cb6e 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1308,40 +1308,38 @@ The Query Builder API supports using expressions in many places. Expressions con ### Entity References {#entity-refs} -Entity references specify entity sets and define the target entity set of a [CQL](../../cds/cql) statement or be an argument of event handler. +Entity references specify entity sets and can define the target entity set of a [CQL](../../cds/cql) statement or serve as an argument for event handlers. -A 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. +A reference consists of _segments_ that define the path from the entity's root to a 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. The references are not bound to the particular model and are not checked against it while they are being built. -References can be represented in JSON following an [Expression](../../cds/cxn) notation. +References are either _absolute_ or _relative_. Absolute references always have the fully qualified name of the type in their first segment. -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. - -The simplest kind of absolute reference is the reference to the entity set, for example, to all books. +The simplest kind of absolute reference is a reference to the entity set, for example, to all books. ```java Books_ books = CQL.entity(Books_.class); // {"ref":["sap.capire.bookshop.Books"]} -StructuredTypeRef ref = bookWithId.asRef(); // or CqnStructuredTypeRef which is cleaner equivalent type +StructuredTypeRef ref = bookWithId.asRef(); // or CqnStructuredTypeRef which is a cleaner equivalent type ``` The method `asRef()` seals the reference and makes it immutable. -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. +Relative references point to the elements of the entity, for example, the title of a book, where the type is known in advance or specified elsewhere. In CQL statements, relative references are members of its select list and relate to the statement source that is an absolute reference. ```java CqnElementRef title = CQL.entity(Books_.class).title(); // {"ref":["title"]} CqnElementRef dynamicTitle = CQL.get(Books.TITLE); // {"ref":["title"]} ``` -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. +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 application code, the model interfaces are the recommended way to do this. -References might also represent navigation within a structured entity or between different entities using its associations. For example, in the following is the reference that represents the path from the book to its chapters. +References with multiple segments represent navigation within a structured entity or between different entities via its associations. For example, the following is a reference that represents the path from the book to its chapters. ```java CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef(); ``` -Each segment of this reference has an identifier (typically an association or composition) and a filter. +References can be represented as JSON following an [Expression](../../cds/cxn) notation. The following is the JSON representation of the reference above: ```json { @@ -1368,11 +1366,7 @@ Each segment of this reference has an identifier (typically an association or co } ``` -An 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). The references are not bound to the particular model and are not checked against it while they are being built. - -Each reference can be serialized as JSON and also renders JSON in its `toString()` implementation. Do not use this JSON to process the references, for example, to extract values from them or to compare references with each other. - -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). +Below is an example how this can be used together to build an CQL statement: ```java // bookshop.Books[year = 2020].author // [!code focus] @@ -1386,20 +1380,16 @@ StructuredType authors = Select.from(authors).columns("name"); // [!code focus] ``` -The resulting statement has two references: one absolute describing the author and one relative, describing the name of the author. - -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. +An existing reference can be reused as an object or a variable, or a new reference can be built on top of it. -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. - -Given that there is a simple reference pointing to the book created as follows. +Given a simple reference pointing to the book created as follows. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]} CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).asRef(); // [!code focus] ``` -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. +To navigate to the 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 the original reference is indeed the reference to the book. This only lets you use required model interface. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]},"author"]} @@ -1415,7 +1405,7 @@ CqnStructuredTypeRef toAuthor = CQL.to(ref.segments()).to("author").asRef(); // This new reference might be used as the root of its own statement to read or change the author. -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. +To navigate to the parent, you can strip segment from the end of the ref. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]} @@ -1423,22 +1413,20 @@ CqnStructuredTypeRef toParent = CQL.to( refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // [!code focus] ``` -There is a 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 parts of the same structured type, for example, from the book's author to the pages of it. +Method `rootSegment()` that can be used to construct the reference starting with the root of the existing reference. For example, when you need to navigate to different parts of the same structured type, for example, from the author of the book to its pages. ```java CqnStructuredTypeRef toPagesOfTheBook = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").to("pages").asRef(); ``` -You can use the `CQL.entity(...)` to use convenience of model interfaces for this with additional cast. +You can use the `CQL.entity(...)` to use the convenience of model interfaces for this with additional casts. ```java CqnStructuredTypeRef toPagesOfTheBook = CQL.entity(Books_.class, CQL.to(List.of(refToAuthor.rootSegment())).asRef()).chapters().pages().asRef(); ``` -The same reference is produced as the result of last two statements. You, of course, have to provide the filters, if to-many associations are used in them. - -References can be copied to produce other refs with in-place modification available for its segments as follows. +References can be copied to produce new references with in-place modification of its segments as follows. ```java StructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef(); @@ -1451,16 +1439,18 @@ builder.segments().forEach(s -> { StructuredTypeRef copy = builder.build(); // new reference is ready ``` -The code that manipulates the references must be tested thoroughly and you always need to ensure that you do not lose the filters or change the reference so that it becomes inconsistent. +Test this code thoroughly and ensure that you do not omit the filters or change the reference so that it becomes inconsistent. + +References can be analyzed using 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. References an be introspected with [`CqnVisitor`](/java/working-with-cql/query-introspection#cqnvisitor). :::warning Limitation -The references are not comparable between each other. They cannot be used as keys of maps or values in a set. +The references are not comparable between each other. They cannot be used as map keys or set values. ::: ### Elements References {#element-refs} -An element reference points to an element of the entity. Such references are usually _relative_, they do not have the name of the entity in their root. They also can include filters in their segments except _the last one_. -Most of the time, they exist as members of the [select list](#projections) of a statement or part of the statement, for example, of an expand predicate. +An element reference points to an element of the entity. Such references are usually _relative_, they do not have the name of the entity in their root. They can include filters in their segments except _in the last one_. +Most of the time, they exist as members of the [select list](#projections) of a statement or part of the statement, for example, of an expand predicate. The following example illustrates the difference: @@ -1479,7 +1469,7 @@ Element references can be extended with the same APIs as the entity references. CqnElementRef extendedRef = CQL.to(relativeRef.segments()).get("name"); // author/placeOfBirth/name ``` -You can create an _absolute_ element reference, but they are rarely used in practice. +You can create _absolute_ element references, but they are rarely used. ```java CqnElementRef nameOfAuthor = CQL.entity(Books_.class).filter(f -> f.ID().eq("...")).author().name(); From 0f14609051a6c6dad11805bf85351b44670e6bd2 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 6 Nov 2025 12:30:42 +0100 Subject: [PATCH 06/16] Update java/working-with-cql/query-api.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: René Jeglinsky --- java/working-with-cql/query-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 27a37cb6e..f23d0fb30 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1413,7 +1413,7 @@ CqnStructuredTypeRef toParent = CQL.to( refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // [!code focus] ``` -Method `rootSegment()` that can be used to construct the reference starting with the root of the existing reference. For example, when you need to navigate to different parts of the same structured type, for example, from the author of the book to its pages. +The `rootSegment()` method can be used to construct the reference starting with the root of the existing reference. For example, when you need to navigate to different parts of the same structured type, for example, from the author of the book to its pages. ```java CqnStructuredTypeRef toPagesOfTheBook = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").to("pages").asRef(); From fb7591f63e17158b2c82fd15b8476b12bc1d1aa6 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 6 Nov 2025 12:34:50 +0100 Subject: [PATCH 07/16] Update java/working-with-cql/query-api.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: René Jeglinsky --- java/working-with-cql/query-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index f23d0fb30..9bdbb257e 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1441,7 +1441,7 @@ StructuredTypeRef copy = builder.build(); // new reference is ready Test this code thoroughly and ensure that you do not omit the filters or change the reference so that it becomes inconsistent. -References can be analyzed using 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. References an be introspected with [`CqnVisitor`](/java/working-with-cql/query-introspection#cqnvisitor). +References can be analyzed using 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. References can be introspected with [`CqnVisitor`](/java/working-with-cql/query-introspection#cqnvisitor). :::warning Limitation The references are not comparable between each other. They cannot be used as map keys or set values. From 7a5c3c380b35ec00074740b2a004d313d097963e Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 6 Nov 2025 12:36:25 +0100 Subject: [PATCH 08/16] Apply suggestions --- java/working-with-cql/query-api.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index f23d0fb30..24c87dbff 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1310,7 +1310,7 @@ The Query Builder API supports using expressions in many places. Expressions con Entity references specify entity sets and can define the target entity set of a [CQL](../../cds/cql) statement or serve as an argument for event handlers. -A reference consists of _segments_ that define the path from the entity's root to a 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. The references are not bound to the particular model and are not checked against it while they are being built. +A reference consists of _segments_ that define the path from the entity's root to a 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. The references are not bound to the particular model and are not checked against it while they are being built. References are either _absolute_ or _relative_. Absolute references always have the fully qualified name of the type in their first segment. @@ -1366,7 +1366,7 @@ References can be represented as JSON following an [Expression](../../cds/cxn) n } ``` -Below is an example how this can be used together to build an CQL statement: +Below is an example how this can be used together to build a CQL statement: ```java // bookshop.Books[year = 2020].author // [!code focus] @@ -1380,7 +1380,7 @@ StructuredType authors = Select.from(authors).columns("name"); // [!code focus] ``` -An existing reference can be reused as an object or a variable, or a new reference can be built on top of it. +An existing reference can be reused as an object or a variable, or a new reference can be built on top of it. Given a simple reference pointing to the book created as follows. @@ -1413,7 +1413,7 @@ CqnStructuredTypeRef toParent = CQL.to( refToAuthor.segments().subList(0, refToAuthor.segments().size() - 1)).asRef(); // [!code focus] ``` -The `rootSegment()` method can be used to construct the reference starting with the root of the existing reference. For example, when you need to navigate to different parts of the same structured type, for example, from the author of the book to its pages. +The `rootSegment()` method can be used to construct the reference starting with the root of the existing reference when you need to navigate to different parts of the same structured type, for example, from the author of the book to its pages. ```java CqnStructuredTypeRef toPagesOfTheBook = CQL.to(List.of(refToAuthor.rootSegment())).to("chapters").to("pages").asRef(); @@ -1447,7 +1447,7 @@ References can be analyzed using the [`CqnAnalyzer`](/java/working-with-cql/quer The references are not comparable between each other. They cannot be used as map keys or set values. ::: -### Elements References {#element-refs} +### Element References {#element-refs} An element reference points to an element of the entity. Such references are usually _relative_, they do not have the name of the entity in their root. They can include filters in their segments except _in the last one_. Most of the time, they exist as members of the [select list](#projections) of a statement or part of the statement, for example, of an expand predicate. From 4a67d724e7de9a4643bb18064740ff63cfe15c88 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 6 Nov 2025 12:48:19 +0100 Subject: [PATCH 09/16] feedback --- java/working-with-cql/query-api.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 2cf03fdbf..09f449793 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1366,7 +1366,7 @@ References can be represented as JSON following an [Expression](../../cds/cxn) n } ``` -Below is an example how this can be used together to build a CQL statement: +Below is an example of how this can be used together to build a CQL statement: ```java // bookshop.Books[year = 2020].author // [!code focus] @@ -1389,7 +1389,7 @@ Given a simple reference pointing to the book created as follows. CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).asRef(); // [!code focus] ``` -To navigate to the 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 the original reference is indeed the reference to the book. This only lets you use required model interface. +You can use `CQL.entity(...)` method to cast the reference to required type and use its methods to extend it further. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]},"author"]} @@ -1475,7 +1475,7 @@ You can create _absolute_ element references, but they are rarely used. CqnElementRef nameOfAuthor = CQL.entity(Books_.class).filter(f -> f.ID().eq("...")).author().name(); ``` -They also share the same features and limitations as the entity references and they cannot be used with [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer). +Element references share the same features and limitations as entity references and cannot be used with [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer). ### Values From 2e7d15503898c9a5b4d60d285e5f83b5d74f83b7 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 6 Nov 2025 12:48:42 +0100 Subject: [PATCH 10/16] feedback --- java/working-with-cql/query-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 09f449793..c9b3e8b84 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1389,7 +1389,7 @@ Given a simple reference pointing to the book created as follows. CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).asRef(); // [!code focus] ``` -You can use `CQL.entity(...)` method to cast the reference to required type and use its methods to extend it further. +You can use `CQL.entity(...)` to cast the reference to the required type and use its methods to extend it further. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]},"author"]} From 51b74cd3fc3a4d7eeedea080ae2658cca9b64717 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 6 Nov 2025 12:54:29 +0100 Subject: [PATCH 11/16] Feedback --- java/working-with-cql/query-api.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index c9b3e8b84..0f6c58c0b 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1403,9 +1403,9 @@ With `CQL.to(...)` the same is produced dynamically. CqnStructuredTypeRef toAuthor = CQL.to(ref.segments()).to("author").asRef(); // [!code focus] ``` -This new reference might be used as the root of its own statement to read or change the author. +You can use this reference as the root for a new statement that targets the author. -To navigate to the parent, you can strip segment from the end of the ref. +To navigate to the parent, you can strip a segment from the end of the reference. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]} @@ -1439,7 +1439,7 @@ builder.segments().forEach(s -> { StructuredTypeRef copy = builder.build(); // new reference is ready ``` -Test this code thoroughly and ensure that you do not omit the filters or change the reference so that it becomes inconsistent. +Test this code thoroughly and ensure that you do not omit filters or make the reference inconsistent. References can be analyzed using 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. References can be introspected with [`CqnVisitor`](/java/working-with-cql/query-introspection#cqnvisitor). From 91b2f00306b3dcd42cba30c13d9300d860b130bf Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 6 Nov 2025 13:02:55 +0100 Subject: [PATCH 12/16] feedback --- java/working-with-cql/query-api.md | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 0f6c58c0b..4a6ca6af4 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1312,7 +1312,7 @@ Entity references specify entity sets and can define the target entity set of a A reference consists of _segments_ that define the path from the entity's root to a 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. The references are not bound to the particular model and are not checked against it while they are being built. -References are either _absolute_ or _relative_. Absolute references always have the fully qualified name of the type in their first segment. +References can be either _absolute_ or _relative_. Absolute references always have the fully qualified name of the type in their first segment. The simplest kind of absolute reference is a reference to the entity set, for example, to all books. @@ -1331,7 +1331,7 @@ CqnElementRef title = CQL.entity(Books_.class).title(); // {"ref":["title"]} CqnElementRef dynamicTitle = CQL.get(Books.TITLE); // {"ref":["title"]} ``` -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 application code, the model interfaces are the recommended way to do this. +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). Prefer model interfaces in the application code. References with multiple segments represent navigation within a structured entity or between different entities via its associations. For example, the following is a reference that represents the path from the book to its chapters. @@ -1339,7 +1339,7 @@ References with multiple segments represent navigation within a structured entit CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef(); ``` -References can be represented as JSON following an [Expression](../../cds/cxn) notation. The following is the JSON representation of the reference above: +References have JSON representation that follows an [Expression](../../cds/cxn) notation. Below is the example if it: ```json { @@ -1366,20 +1366,6 @@ References can be represented as JSON following an [Expression](../../cds/cxn) n } ``` -Below is an example of how this can be used together to build a CQL statement: - -```java -// bookshop.Books[year = 2020].author // [!code focus] -Authors_ authors = CQL.entity(Books_.class).filter(b -> b.year().eq(2020)).author(); // [!code focus] - -// or as untyped entity ref -StructuredType authors = - CQL.entity("bookshop.Books").filter(b -> b.get("year").eq(2020)).to("author"); - -// SELECT from bookshop.Books[year = 2020]:author { name } // [!code focus] -Select.from(authors).columns("name"); // [!code focus] -``` - An existing reference can be reused as an object or a variable, or a new reference can be built on top of it. Given a simple reference pointing to the book created as follows. @@ -1439,9 +1425,9 @@ builder.segments().forEach(s -> { StructuredTypeRef copy = builder.build(); // new reference is ready ``` -Test this code thoroughly and ensure that you do not omit filters or make the reference inconsistent. +Use the [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer) to bind the reference back to the CDS model and inspect annotations or filter values. -References can be analyzed using 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. References can be introspected with [`CqnVisitor`](/java/working-with-cql/query-introspection#cqnvisitor). +Use [`CqnVisitor`](/java/working-with-cql/query-introspection#cqnvisitor) to introspect references. :::warning Limitation The references are not comparable between each other. They cannot be used as map keys or set values. From 50022373e3a0cc7221dd225b492f0f0566e1433d Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 6 Nov 2025 13:26:15 +0100 Subject: [PATCH 13/16] Less text --- java/working-with-cql/query-api.md | 43 +++--------------------------- 1 file changed, 3 insertions(+), 40 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 4a6ca6af4..79793560c 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1324,12 +1324,7 @@ StructuredTypeRef ref = bookWithId.asRef(); // or CqnStructuredTypeRef which is The method `asRef()` seals the reference and makes it immutable. -Relative references point to the elements of the entity, for example, the title of a book, where the type is known in advance or specified elsewhere. In CQL statements, relative references are members of its select list and relate to the statement source that is an absolute reference. - -```java -CqnElementRef title = CQL.entity(Books_.class).title(); // {"ref":["title"]} -CqnElementRef dynamicTitle = CQL.get(Books.TITLE); // {"ref":["title"]} -``` +Relative references do not specify the type in the first segment and are [element references](/java/working-with-cql/query-api#element-refs) most of the time. 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). Prefer model interfaces in the application code. @@ -1339,33 +1334,6 @@ References with multiple segments represent navigation within a structured entit CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...")).chapters(c -> c.ID().eq("...")).pages(p -> p.ID().eq("...")).asRef(); ``` -References have JSON representation that follows an [Expression](../../cds/cxn) notation. Below is the example if it: - -```json -{ - "ref": [ - { - "id": "sap.capire.bookshop.Books", - "where": [ - { "ref": ["ID"]}, "=", {"val": "..."} - ] - }, - { - "id": "chapters", - "where": [ - { "ref": ["ID"]}, "=", {"val": "..."} - ] - }, - { - "id": "pages", - "where": [ - { "ref": ["ID"]}, "=", {"val": "..."} - ] - } - ] -} -``` - An existing reference can be reused as an object or a variable, or a new reference can be built on top of it. Given a simple reference pointing to the book created as follows. @@ -1382,7 +1350,7 @@ You can use `CQL.entity(...)` to cast the reference to the required type and use CqnStructuredTypeRef refToAuthor = CQL.entity(Books_.class, ref).author().asRef(); // [!code focus] ``` -With `CQL.to(...)` the same is produced dynamically. +Use `CQL.to(...)` to produce the same dynamically. ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]},"author"]} @@ -1435,17 +1403,12 @@ The references are not comparable between each other. They cannot be used as map ### Element References {#element-refs} -An element reference points to an element of the entity. Such references are usually _relative_, they do not have the name of the entity in their root. They can include filters in their segments except _in the last one_. -Most of the time, they exist as members of the [select list](#projections) of a statement or part of the statement, for example, of an expand predicate. - -The following example illustrates the difference: +An element reference points to regular element of the entity. Such references are usually _relative_ and form select list for a CQL statement or an expand. ```java CqnSelect statement = Select.from(Books_.class, b -> b.filter(f -> f.ID().eq("..."))) .columns(b -> b.author().placeOfBirth()); -CqnStructuredTypeRef absoluteRef = statement.ref(); // Books(ID=...) - CqnElementRef relativeRef = statement.items().getFirst().asRef(); // author/placeOfBirth ``` From 1b1f731d814c8419684372c6bc0dd11e3be72936 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Thu, 6 Nov 2025 13:28:54 +0100 Subject: [PATCH 14/16] feedback --- java/working-with-cql/query-api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index 79793560c..aeca38262 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1403,7 +1403,7 @@ The references are not comparable between each other. They cannot be used as map ### Element References {#element-refs} -An element reference points to regular element of the entity. Such references are usually _relative_ and form select list for a CQL statement or an expand. +An element reference points to a regular element of the entity. Such references are usually _relative_ and form select list for a CQL statement or an expand. ```java CqnSelect statement = Select.from(Books_.class, b -> b.filter(f -> f.ID().eq("..."))) @@ -1424,7 +1424,7 @@ You can create _absolute_ element references, but they are rarely used. CqnElementRef nameOfAuthor = CQL.entity(Books_.class).filter(f -> f.ID().eq("...")).author().name(); ``` -Element references share the same features and limitations as entity references and cannot be used with [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer). +Element references share the same features and limitations as entity references. However, you cannot use them with [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer). ### Values From 761a620f9922853f4245a032bc9ae9a7ee017d38 Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Wed, 12 Nov 2025 16:33:14 +0100 Subject: [PATCH 15/16] Feedback --- java/working-with-cql/query-api.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index aeca38262..d0820a4c6 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1324,9 +1324,9 @@ StructuredTypeRef ref = bookWithId.asRef(); // or CqnStructuredTypeRef which is The method `asRef()` seals the reference and makes it immutable. -Relative references do not specify the type in the first segment and are [element references](/java/working-with-cql/query-api#element-refs) most of the time. +Relative references do not specify the type in the first segment and are [element references](#element-refs) most of the time. -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). Prefer model interfaces in the application code. +New references are constructed with [model interfaces](../cqn-services/persistence-services#model-interfaces) or via API that is also used to build [CQL statements](#concepts). Prefer model interfaces in the application code. References with multiple segments represent navigation within a structured entity or between different entities via its associations. For example, the following is a reference that represents the path from the book to its chapters. @@ -1336,7 +1336,7 @@ CqnStructuredTypeRef ref = CQL.entity(Books_.class).filter(b -> b.ID().eq("...") An existing reference can be reused as an object or a variable, or a new reference can be built on top of it. -Given a simple reference pointing to the book created as follows. +For the upcoming examples, let's assume a simple reference pointing to the book created as follows: ```java // {"ref":[{"id":"sap.capire.bookshop.Books","where":[{"ref":["ID"]},"=",{"val":"..."}]}]} @@ -1412,18 +1412,12 @@ CqnSelect statement = Select.from(Books_.class, b -> b.filter(f -> f.ID().eq(".. CqnElementRef relativeRef = statement.items().getFirst().asRef(); // author/placeOfBirth ``` -Element references can be extended with the same APIs as the entity references. +Element references can be extended with the same APIs as the [entity references](#entity-refs). ```java CqnElementRef extendedRef = CQL.to(relativeRef.segments()).get("name"); // author/placeOfBirth/name ``` -You can create _absolute_ element references, but they are rarely used. - -```java -CqnElementRef nameOfAuthor = CQL.entity(Books_.class).filter(f -> f.ID().eq("...")).author().name(); -``` - Element references share the same features and limitations as entity references. However, you cannot use them with [`CqnAnalyzer`](/java/working-with-cql/query-introspection#cqnanalyzer). ### Values From 483e0a969cd7a3f9166b520f8a19de8b30f187fa Mon Sep 17 00:00:00 2001 From: Vladimir Mikhaylenko Date: Wed, 12 Nov 2025 16:37:29 +0100 Subject: [PATCH 16/16] Small corrections --- java/working-with-cql/query-api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/working-with-cql/query-api.md b/java/working-with-cql/query-api.md index d0820a4c6..31501b6bc 100644 --- a/java/working-with-cql/query-api.md +++ b/java/working-with-cql/query-api.md @@ -1308,7 +1308,7 @@ The Query Builder API supports using expressions in many places. Expressions con ### Entity References {#entity-refs} -Entity references specify entity sets and can define the target entity set of a [CQL](../../cds/cql) statement or serve as an argument for event handlers. +Entity references specify entity sets. You can use them to define the target entity set of a [CQL](../../cds/cql) statement or serve as an argument for event handlers. A reference consists of _segments_ that define the path from the entity's root to a 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. The references are not bound to the particular model and are not checked against it while they are being built. @@ -1326,7 +1326,7 @@ The method `asRef()` seals the reference and makes it immutable. Relative references do not specify the type in the first segment and are [element references](#element-refs) most of the time. -New references are constructed with [model interfaces](../cqn-services/persistence-services#model-interfaces) or via API that is also used to build [CQL statements](#concepts). Prefer model interfaces in the application code. +Construct new references with [model interfaces](../cqn-services/persistence-services#model-interfaces) or via the API to build [CQL statements](#concepts). Use model interfaces in the application code. References with multiple segments represent navigation within a structured entity or between different entities via its associations. For example, the following is a reference that represents the path from the book to its chapters.