Compare commits

..

24 Commits

Author SHA1 Message Date
Daniel
ddb962dcc3 Added more comments 2021-02-01 11:01:23 +01:00
Daniel
5e52d4633a Added a comment re generic peg.js grammar 2021-02-01 10:59:17 +01:00
Daniel
24dd1164cc Adjusted number literals to compiler v2 2021-02-01 10:30:40 +01:00
Daniel
f3f554396c Using forward-declared target API of cds.odata 2021-02-01 10:04:15 +01:00
Daniel
a11aadc8f0 Reverting last commit 2021-02-01 09:43:44 +01:00
Daniel
cfc5a56d5a Adding peg.js 2021-02-01 09:43:30 +01:00
Daniel
098b27330a New home of odata2cqn 2021-02-01 09:37:06 +01:00
Daniel
683b785ac5 Simplified filter construction 2021-01-29 19:22:11 +01:00
Daniel
2782cf0d6d fixed tests 2021-01-29 19:21:41 +01:00
Daniel
fd97e3bda9 Moved to main repo 2021-01-29 18:37:13 +01:00
Iwona Hahn
6a4af929f1 minor updates 2021-01-27 08:49:33 +01:00
Christian Georgi
5b966c503c Add hint for authentication
So that fewer users stumble over the basic authentication popup.
2021-01-18 14:40:24 +01:00
Christian Georgi
75628b6096 Use latest UI5 again 2021-01-18 14:31:57 +01:00
Daniel
c12e516f5d Prep for upcomming releases 2021-01-13 16:30:40 +01:00
Marius Obert
01073fd6a5 Restructure sentence 2021-01-11 10:54:59 +01:00
Christian Georgi
dc72442764 Better brand name 2020-12-18 15:09:38 +01:00
Manuel Blechschmidt
7e04f50852 Added installation for cds (#177)
When running these samples for the first time,
it is necessary to install the cds binaries globally.

Co-authored-by: Christian Georgi <chgeo@users.noreply.github.com>
Co-authored-by: Daniel Hutzel <daniel.hutzel@sap.com>
2020-12-18 09:25:11 +01:00
Daniel
ea6e274810 Fixed: missing await srv.emit 2020-12-17 16:39:06 +01:00
Christian Georgi
86e5c429bd Example for draft choreography 2020-12-16 17:58:03 +01:00
Daniel
f32398ba8d Using cds.User.default in 4.4.4 2020-12-07 12:41:22 +01:00
Daniel
684c2d53f1 Preparing test for upcomming release 4.4.4 2020-12-03 14:02:15 +01:00
Daniel
b4594e23c5 remove .db file 2020-11-23 14:23:36 +01:00
Daniel
b6028721af make tests more robust 2020-11-22 10:57:13 +01:00
Daniel
e15a6192b6 Aligned orders w/ managed compositions 2020-11-21 01:32:39 +01:00
46 changed files with 2869 additions and 1629 deletions

View File

@@ -21,6 +21,7 @@
}, },
"rules": { "rules": {
"no-console": "off", "no-console": "off",
"require-atomic-updates": "off" "require-atomic-updates": "off",
"require-await":"warn"
} }
} }

View File

@@ -5,16 +5,20 @@ Find here a collection of samples for the [SAP Cloud Application Programming Mod
![](https://github.com/SAP-samples/cloud-cap-samples/workflows/CI/badge.svg) ![](https://github.com/SAP-samples/cloud-cap-samples/workflows/CI/badge.svg)
[![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/cloud-cap-samples)](https://api.reuse.software/info/github.com/SAP-samples/cloud-cap-samples) [![REUSE status](https://api.reuse.software/badge/github.com/SAP-samples/cloud-cap-samples)](https://api.reuse.software/info/github.com/SAP-samples/cloud-cap-samples)
### Preliminaries ### Preliminaries
1. [Install @sap/cds-dk](https://cap.cloud.sap/docs/get-started/) as documented in [capire](https://cap.cloud.sap) 1. Install [**@sap/cds-dk**](https://cap.cloud.sap/docs/get-started/) globally:
2. _Optional:_ [Use Visual Studio Code](https://cap.cloud.sap/docs/get-started/in-vscode)
```sh
npm i -g @sap/cds-dk
```
2. _Optional:_ [Use Visual Studio Code](https://cap.cloud.sap/docs/get-started/tools#vscode)
### Download ### Download
Clone this repo as shown below, if you have [git](https://git-scm.com/downloads) installed, If you have [Git](https://git-scm.com/downloads) installed, clone this repo as shown below, otherwise [download as ZIP file](archive/master.zip).
otherwise [download as zip file](archive/master.zip).
```sh ```sh
git clone https://github.com/sap-samples/cloud-cap-samples samples git clone https://github.com/sap-samples/cloud-cap-samples samples
@@ -39,9 +43,12 @@ cds watch bookshop
After that open this link in your browser: [http://localhost:4004](http://localhost:4004) After that open this link in your browser: [http://localhost:4004](http://localhost:4004)
When asked to log in, type `alice` as user and leave the password field blank, which is the [default user](https://cap.cloud.sap/docs/node.js/authentication#mocked).
### Testing ### Testing
Run the provided tests with [_jest_](http://jestjs.io) or [_mocha_](http://mochajs.org), for example: Run the provided tests with [_jest_](http://jestjs.io) or [_mocha_](http://mochajs.org), for example:
```sh ```sh
npx jest npx jest
``` ```
@@ -50,7 +57,7 @@ npx jest
### Serve `npm` ### Serve `npm`
We've simple npm registry mock included which allows you to do an `npm install @capire/<package>` anywhere locally. Use it as follows: We've included a simple npm registry mock, which allows you to do an `npm install @capire/<package>` locally. Use it as follows:
1. Start the @capire registry: 1. Start the @capire registry:
```sh ```sh
@@ -58,7 +65,8 @@ npm run registry
``` ```
> While running this will have `@capire:registry=http://localhost:4444` set with npmrc. > While running this will have `@capire:registry=http://localhost:4444` set with npmrc.
2. Install one of the @capire packages wherever you like, e.g.: 2. Install one of the @capire packages wherever you like, for example:
```sh ```sh
npm add @capire/common @capire/bookshop npm add @capire/common @capire/bookshop
``` ```
@@ -72,4 +80,4 @@ In case you have a question, find a bug, or otherwise need support, please use o
## License ## License
Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSES/Apache-2.0.txt) file. Copyright (c) 2021 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, version 2.0 except as noted otherwise in the [LICENSE](LICENSES/Apache-2.0.txt) file.

View File

@@ -5,10 +5,10 @@ This stand-alone sample introduces the essential tasks in the development of CAP
## Hypothetical Use Cases ## Hypothetical Use Cases
1. Build a service that allows to browse _Books_ and _Authors_. 1. Build a service that allows to browse _Books_ and _Authors_.
2. Books have assigned _Genres_ which are organized hierarchically. 2. Books have assigned _Genres_, which are organized hierarchically.
3. All users may browse books without login. 3. All users may browse books without login.
4. All entries are maintained by Administrators. 4. All entries are maintained by Administrators.
5. End users may order books (the actual order mgmt being out of scope) 5. End users may order books (the actual order mgmt being out of scope).
## Running the Sample ## Running the Sample
@@ -20,12 +20,12 @@ npm run watch
| Links to capire | Sample files / folders | | Links to capire | Sample files / folders |
| --------------------------------------------------------------------------------------------------------- | ------------------------------------ | | --------------------------------------------------------------------------------------------------------- | ------------------------------------ |
| [Project Setup and Layouts](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content) | [`./`](./) | | [Project Setup & Layouts](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content) | [`./`](./) |
| [Defining Domain Models](https://cap.cloud.sap/docs/guides/domain-models) | [`./db/schema.cds`](./db/schema.cds) | | [Domain Modeling with CDS](https://cap.cloud.sap/docs/guides/domain-models) | [`./db/schema.cds`](./db/schema.cds) |
| [Defining Services](https://cap.cloud.sap/docs/guides/providing-services) | [`./srv/*.cds`](./srv) | | [Defining Services](https://cap.cloud.sap/docs/guides/services#defining-services) | [`./srv/*.cds`](./srv) |
| [Single-purposed Services](https://cap.cloud.sap/docs/guides/providing-services#single-purposed-services) | [`./srv/*.cds`](./srv) | | [Single-purposed Services](https://cap.cloud.sap/docs/guides/services#single-purposed-services) | [`./srv/*.cds`](./srv) |
| [Generic Providers](https://cap.cloud.sap/docs/guides/providing-services) | http://localhost:4004 | | [Providing & Consuming Providers](https://cap.cloud.sap/docs/guides/providing-services) | http://localhost:4004 |
| Using Databases | [`./db/data/*.csv`](./db/data) | | [Using Databases](https://cap.cloud.sap/docs/guides/databases) | [`./db/data/*.csv`](./db/data) |
| [Adding Custom Logic](https://cap.cloud.sap/docs/guides/service-impl) | [`./srv/*.js`](./srv) | | [Adding Custom Logic](https://cap.cloud.sap/docs/guides/service-impl) | [`./srv/*.js`](./srv) |
| Adding Tests | [`./test`](./test) | | Adding Tests | [`./test`](./test) |
| [Sharing for Reuse](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content) | [`./index.cds`](./index.cds) | | [Sharing for Reuse](https://cap.cloud.sap/docs/guides/reuse-and-compose) | [`./index.cds`](./index.cds) |

View File

@@ -1,12 +1,12 @@
using { sap.capire.bookshop as my } from '../db/schema'; using { sap.capire.bookshop as my } from '../db/schema';
service CatalogService @(path:'/browse') { service CatalogService @(path:'/browse') {
@readonly entity Books as SELECT from my.Books {*, @readonly entity Books as SELECT from my.Books { *,
author.name as author author.name as author
} excluding { createdBy, modifiedBy }; } excluding { createdBy, modifiedBy };
@readonly entity ListOfBooks as SELECT from Books @readonly entity ListOfBooks as SELECT from Books
excluding { descr, stock }; excluding { descr };
@requires: 'authenticated-user' @requires: 'authenticated-user'
action submitOrder ( book: Books:ID, amount: Integer ) returns { stock: Integer }; action submitOrder ( book: Books:ID, amount: Integer ) returns { stock: Integer };

View File

@@ -1,7 +1,7 @@
const cds = require('@sap/cds') const cds = require('@sap/cds')
const { Books } = cds.entities ('sap.capire.bookshop') const { Books } = cds.entities ('sap.capire.bookshop')
class CatalogService extends cds.ApplicationService { async init(){ class CatalogService extends cds.ApplicationService { init(){
// Reduce stock of ordered books if available stock suffices // Reduce stock of ordered books if available stock suffices
this.on ('submitOrder', async req => { this.on ('submitOrder', async req => {
@@ -9,7 +9,7 @@ class CatalogService extends cds.ApplicationService { async init(){
let {stock} = await tx.read('stock').from(Books,book) let {stock} = await tx.read('stock').from(Books,book)
if (stock >= amount) { if (stock >= amount) {
await tx.update (Books,book).with ({ stock: stock -= amount }) await tx.update (Books,book).with ({ stock: stock -= amount })
this.emit ('OrderedBook', { book, amount, buyer:req.user.id }) await this.emit ('OrderedBook', { book, amount, buyer:req.user.id })
return { stock } return { stock }
} }
else return req.error (409,`${amount} exceeds stock for book #${book}`) else return req.error (409,`${amount} exceeds stock for book #${book}`)

View File

@@ -1,4 +1,8 @@
{ {
"name": "@capire/common", "name": "@capire/common",
"version": "1.0.0" "description": "Provides a pre-built extension package for std @sap/cds/common",
"version": "1.0.0",
"dependencies": {
"@sap/cds": "latest"
}
} }

View File

@@ -1,3 +1,2 @@
# cds.requires.messaging.kind = file-based-messaging # cds.requires.messaging.kind = file-based-messaging
cds.cdsc.severities.extend-for-generated = info
PORT = 4004 PORT = 4004

View File

@@ -13,7 +13,7 @@
applications: { applications: {
"browse-books": { "browse-books": {
title: "Browse Books", title: "Browse Books",
description: "... testing FE v42", description: "w/ SAP Fiori Elements",
additionalInformation: "SAPUI5.Component=bookshop", additionalInformation: "SAPUI5.Component=bookshop",
applicationType : "URL", applicationType : "URL",
url: "/browse/webapp", url: "/browse/webapp",
@@ -21,7 +21,7 @@
}, },
"manage-books": { "manage-books": {
title: "Manage Books", title: "Manage Books",
description: "... testing FE v42", description: "w/ SAP Fiori Elements",
additionalInformation: "SAPUI5.Component=admin", additionalInformation: "SAPUI5.Component=admin",
applicationType : "URL", applicationType : "URL",
url: "/admin/webapp", url: "/admin/webapp",
@@ -29,7 +29,7 @@
}, },
"manage-orders": { "manage-orders": {
title: "Manage Orders", title: "Manage Orders",
description: "... testing FE v42", description: "w/ SAP Fiori Elements",
additionalInformation: "SAPUI5.Component=orders", additionalInformation: "SAPUI5.Component=orders",
applicationType : "URL", applicationType : "URL",
url: "/orders/webapp", url: "/orders/webapp",
@@ -40,8 +40,7 @@
</script> </script>
<script id="sap-ushell-bootstrap" src="https://sapui5.hana.ondemand.com/test-resources/sap/ushell/bootstrap/sandbox.js"></script> <script id="sap-ushell-bootstrap" src="https://sapui5.hana.ondemand.com/test-resources/sap/ushell/bootstrap/sandbox.js"></script>
<!-- <script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js" --> <script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
<script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/1.78.6/resources/sap-ui-core.js"
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout" data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
data-sap-ui-compatVersion="edge" data-sap-ui-compatVersion="edge"
data-sap-ui-theme="sap_fiori_3" data-sap-ui-theme="sap_fiori_3"

View File

@@ -49,7 +49,7 @@ module.exports = async()=>{ // called by server.js
// //
// Reduce stock of ordered books for orders are created from Orders admin UI // Reduce stock of ordered books for orders are created from Orders admin UI
// //
OrdersService.on ('OrderChanged', async (msg) => { OrdersService.on ('OrderChanged', (msg) => {
console.debug ('> received:', msg.event, msg.data) console.debug ('> received:', msg.event, msg.data)
const { product, deltaAmount } = msg.data const { product, deltaAmount } = msg.data
return UPDATE (Books) .where ('ID =', product) return UPDATE (Books) .where ('ID =', product)

View File

@@ -42,7 +42,24 @@ GET {{bookshop}}/browse/Books(201)?
################################################# #################################################
# #
# Orders Service # Orders Service, incl. draft choreography
# #
@newOrderID = e939604c-ab83-4d4f-bdb6-95fe30b3773e
GET {{bookshop}}/orders/Orders GET {{bookshop}}/orders/Orders
### Create order, still inactive
POST {{bookshop}}/orders/Orders
Content-Type: application/json
{"ID": "{{newOrderID}}"}
### Get inactive order. We have to specify `IsActiveEntity`.
GET {{bookshop}}/orders/Orders(ID={{newOrderID}},IsActiveEntity=false)
### Activate order using `.../<servicename>.draftActivate`
POST {{bookshop}}/orders/Orders(ID={{newOrderID}},IsActiveEntity=false)/OrdersService.draftActivate
Content-Type: application/json
### Get active order
GET {{bookshop}}/orders/Orders(ID={{newOrderID}},IsActiveEntity=true)

1
odata/.npmrc Normal file
View File

@@ -0,0 +1 @@
@sap:registry=http://nexus.wdf.sap.corp:8081/nexus/repository/build.milestones.npm/

15
odata/.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"SirTobi.pegjs-language",
"tamuratak.vscode-pegjs",
"joeandaverde.vscode-pegjs-live"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
]
}

1189
odata/etc/odata-url.abnf Normal file

File diff suppressed because it is too large Load Diff

1162
odata/etc/odata-url.pegjs Normal file

File diff suppressed because it is too large Load Diff

26
odata/lib/index.js Normal file
View File

@@ -0,0 +1,26 @@
const fs = require("fs");
const path = require("path");
const peg = require("pegjs");
const pegGrammarPath = path.join(__dirname, "/odata2cqn.pegjs");
const odataPegGrammar = fs.readFileSync(pegGrammarPath, {
encoding: "utf8",
flag: "r",
});
const parser = peg.generate(odataPegGrammar);
module.exports = {
parse: {
url: parser.parse,
},
to: {
cqn: parser.parse,
url: (cqn) => pending(cqn)
},
serialize: (data) => pending(data),
deserialize: (body) => pending(body),
}
const pending = ()=>{
throw new Error ('Not yet implemented')
}

200
odata/lib/odata2cqn.pegjs Normal file
View File

@@ -0,0 +1,200 @@
/** ------------------------------------------
* This is a peg.js adaptation of the https://github.com/oasis-tcs/odata-abnf/blob/master/abnf/odata-abnf-construction-rules.txt
* which directly constructs CQN out of parsed sources.
*
* NOTE:
* In contrast to the OData ABNF source, which uses very detailedsemantic rules,
* this adaptation uses rather generic syntactic rules only, e.g. not distinguishing
* betwenn Collection Navigation or not knowing individual function names.
* This is to be open to future enhancements of the OData standard, as well as
* to improve error messages. For example a typo in a function name could be
* reported specifically instead of throwing a generic parser error.
*
* See also: https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview
* Future test cases http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/abnf/odata-abnf-testcases.xml
*
* Limitations: Type, Geo functions are not supported,
* maxdatetime, mindatetime, fractionalseconds,
* totaloffsetminutes, date, totalseconds,
* floor, ceiling also are not supported by CAP
*
* Examples:
* Books
* Books/201
* Books?$select=ID,title&$expand=author($select=name)&$filter=stock gt 1&$orderby=title
*/
// ---------- JavaScript Helpers -------------
{
const stack=[]
let SELECT
}
// ---------- Entity Paths ---------------
ODataRelativeURI // Note: case-sensitive!
= (p:path { SELECT = { from:p } })
( o"?"o QueryOption ( o'&'o QueryOption )* )? {
if (SELECT.expand) {
SELECT.columns = SELECT.expand
delete SELECT.expand
}
return { SELECT }
}
path
= crv:$("$count"/"$ref"/"$value") {return {ref:[crv]}}
/ head:identifier filter:(OPEN args CLOSE)? tail:( '/' p:path {return p} )? {
const ref = [ filter ? { id:head, where:filter[1] } : head ]
if (tail) ref.push (...tail.ref)
return {ref}
}
args
= val:( number / integer / string ) {return [{val}]}
/ ref:identifier o"="o val:( number / integer / string ) more:( COMMA args )? {
const args = [ {ref}, '=', {val} ]
if (more) args.push ('and', ...more[1])
return args
}
ref "a reference"
= head:identifier tail:( '/' identifier )* {
return { ref:[ head, ...tail ] }
}
//
// ---------- Query Options ------------
QueryOption = ExpandOption
ExpandOption =
"$select=" o select ( COMMA select )* /
"$expand=" o expand ( COMMA expand )* /
"$filter=" o filter /
"$orderby=" o orderby /
"$top=" o top /
"$skip=" o skip /
"$search=" o search /
"$count=" o count
select
= col:ref {
(SELECT.expand || (SELECT.expand = [])).push(col)
return col
}
expand =
( c:select {c.expand='*'} )
( // --- nested query options, if any
(OPEN {
stack.push (SELECT)
SELECT = SELECT.expand[SELECT.expand.length-1]
SELECT.expand = []
})
ExpandOption ( o";"o ExpandOption )*
(CLOSE {
SELECT = stack.pop()
})
)? // --- end of nested query options
( COMMA expand )?
top
= val:integer {
(SELECT.limit || (SELECT.limit={})).rows = {val}
}
skip
= val:integer {
(SELECT.limit || (SELECT.limit={})).offset = {val}
}
search
= p:search_clause {SELECT.search = p}
search_clause = p:( n:NOT? {return n?[n]:[]} )(
OPEN xpr:search_clause CLOSE {p.push({xpr})}
/ val:(identifier/string) {p.push({val})}
)( ao:(AND/OR) more:search_clause {p.push(ao,...more)} )*
{return p}
filter
= p:where_clause {SELECT.where = p}
where_clause = p:( n:NOT? {return n?[n]:[]} )(
OPEN xpr:where_clause CLOSE {p.push({xpr})}
/ comp:comparison {p.push(...comp)}
/ func:boolish {p.push(func)}
)( ao:(AND/OR) more:where_clause {p.push(ao,...more)} )*
{return p}
orderby
= ref:ref sort:( _ s:$("asc"/"desc") {return s})? {
SELECT.orderby = $(ref, sort && {sort})
}
count
= c:$[^,?&()]+ { SELECT.count = true }
//
// ---------- Expressions ------------
comparison "a comparison"
= a:operand _ o:$("eq"/"ne"/"lt"/"gt"/"le"/"ge") _ b:operand {
const op = { eq:'=', ne:'!=', lt:'<', gt:'>', le:'<=', ge:'>=' }[o]||o
return [ a, op, b ]
}
operand "an operand"
= val:number {return Number.isSafeInteger(val) ? {val} : { val:String(val), literal:'number' }}
/ val:string {return {val}}
/ function
/ ref
function "a function call"
= func:$[a-z]+ OPEN a:operand more:( COMMA o:operand {return o} )* CLOSE
{ return { func, args:[a,...more] }}
boolish "a boolean function"
= func:("contains"/"endswith"/"startswith") OPEN a:operand COMMA b:operand CLOSE
{ return { func, args:[a,b] }}
NOT = o "not"i _ {return 'not'}
AND = _ "and"i _ {return 'and'}
OR = _ "or"i _ {return 'or'}
//
// ---------- Literals -----------
string "Edm.String"
= "'" s:$("''"/[^'])* "'"
{return s.replace(/''/g,"'")}
number
= x:$( [+-]? [0-9]+ ("."[0-9]+)? ("e"[0-9]+)? )
{return Number(x)}
integer
= x:$( [+-]? [0-9]+ )
{return parseInt(x)}
identifier
= $([a-zA-Z][_a-zA-Z0-9]*)
//
// ---------- Punctuation ----------
COLON = o":"o
COMMA = o","o
SEMI = o";"o
OPEN = o"("o
CLOSE = o")"
//
// ---------- Whitespaces -----------
o "optional whitespaces" = $[ \t\n]*
_ "mandatory whitespaces" = $[ \t\n]+
//
// ------------------------------------

15
odata/package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "@sap/cds-odata",
"version": "1.0.0",
"dependencies": {
"@sap/cds-compiler": "latest",
"@sap/cds": "^4.4.10"
},
"scripts": {
"postinstall": "rm -fr node_modules/@sap/cds/node_modules"
},
"devDependencies": {
"pegjs": "^0.10.0"
},
"private": true
}

View File

@@ -0,0 +1,105 @@
const cds = require("@sap/cds/lib"), {expect} = cds.test
cds.odata = require("../lib")
describe("$filter", () => {
describe("comparing expressions", () => {
const types = {
strings: "'some string'",
integers: 11,
decimals: 0.99,
// ...
}
it.each(Object.keys(types))("should support expressions with %s", (t) => {
expect (cds.odata.parse.url(`Foo?$filter=bar eq ${types[t]}`))
.to.eql (cds.parse.cql(`SELECT from Foo where bar = ${types[t]}`))
})
const operators = {
eq: '=',
lt: '<',
le: '<=',
gt: '>',
ge: '>=',
ne: '!=',
// ...
}
it.each(Object.keys(operators))("should support comparison operator '%s'", (op) => {
expect (cds.odata.parse.url(`Foo?$filter=bar ${op} 11`))
.to.eql (cds.parse.cql(`SELECT from Foo where bar ${operators[op]} 11`))
})
});
describe("logical expressions", () => {
it.each(['and','or'])("should support '%s'", (t) => {
expect (cds.odata.parse.url(`Foo?$filter=bar lt 11 ${t} name eq 'some name'`))
.to.eql (cds.parse.cql(`SELECT from Foo where bar < 11 ${t} name = 'some name'`))
})
it("should support 'not'", () => {
// REVISIT: We need to check with the Node.js team why they translated that to the equivalent of:
// not name like concat('%','sunny','%') escape '^'
expect (cds.odata.parse.url(`Foo?$filter= not contains(name,'sunny')`))
.to.eql (cds.parse.cql(`SELECT from Foo where not contains(name,'sunny')`))
});
// REVISIT: wait for compiler v2
it("should support group expr", () => {
expect (cds.odata.parse.url(`Foo?$filter= (unitPrice gt 11 and length(name) eq 12) or name eq 'Restless and Wild'`))
.to.eql (cds.parse.cql(`SELECT from Foo where (unitPrice > 11 and length(name) = 12) or name = 'Restless and Wild'`))
});
});
describe("function expressions", () => {
it("should support contains", () => {
expect (cds.odata.parse.url(`Foo?$filter= contains(name,'sunny')`))
.to.eql (cds.parse.cql(`SELECT from Foo where contains(name,'sunny')`))
});
it("should support startswith", () => {
expect (cds.odata.parse.url(`Foo?$filter= startswith(name,'sunny')`))
.to.eql (cds.parse.cql(`SELECT from Foo where startswith(name,'sunny')`))
});
it("should support endswith", () => {
expect (cds.odata.parse.url(`Foo?$filter= endswith(name,'sunny')`))
.to.eql (cds.parse.cql(`SELECT from Foo where endswith(name,'sunny')`))
});
it("should support length", () => {
expect (cds.odata.parse.url(`Foo?$filter= length(name) lt 11`))
.to.eql (cds.parse.cql(`SELECT from Foo where length(name) < 11`))
});
it("should support indexof", () => {
expect (cds.odata.parse.url(`Foo?$filter= indexof(name,'x') eq 11`))
.to.eql (cds.parse.cql(`SELECT from Foo where indexof(name,'x') = 11`))
});
it("should support substring", () => {
expect (cds.odata.parse.url(`Foo?$filter= substring(name,1) eq 'foo'`))
.to.eql (cds.parse.cql(`SELECT from Foo where substring(name,1) = 'foo'`))
});
it.each(['tolower','toupper','trim'])("should support '%s'", (fn) => {
expect (cds.odata.parse.url(`Foo?$filter= ${fn}(name) eq 'foo'`))
.to.eql (cds.parse.cql(`SELECT from Foo where ${fn}(name) = 'foo'`))
});
it("should support 'day'", () => {
expect (cds.odata.parse.url(`Foo?$filter= day(name) eq 11`))
.to.eql (cds.parse.cql(`SELECT from Foo where day(name) = 11`))
});
it("should support concat", () => {
expect (cds.odata.parse.url(`Foo?$filter= concat(name,'o') eq 'foo'`))
.to.eql (cds.parse.cql(`SELECT from Foo where concat(name,'o') = 'foo'`))
});
});
});

View File

@@ -121,7 +121,7 @@
"name": "sap.fe.templates.ObjectPage", "name": "sap.fe.templates.ObjectPage",
"options": { "options": {
"settings" : { "settings" : {
"entitySet": "OrderItems" "entitySet": "Orders_Items"
} }
} }
}, },

View File

@@ -1,2 +1,26 @@
// using from './without-managed-composition/schema'; using { Currency, User, managed, cuid } from '@sap/cds/common';
using from './with-managed-composition/schema'; namespace sap.capire.orders;
entity Orders : cuid, managed {
OrderNo : String @title:'Order Number'; //> readable key
Items : Composition of many Orders_Items on Items.up_ = $self;
buyer : User;
currency : Currency;
}
entity Orders_Items {
key ID : UUID;
up_ : Association to Orders;
product : Association to Products @assert.integrity:false; // REVISIT: this is a temporary workaround for a glitch in cds-runtime
amount : Integer;
title : String;
price : Double;
}
/** This is a stand-in for arbitrary ordered Products */
entity Products @(cds.persistence.skip:'always') {
key ID : String;
}
// Activate extension package
using from '@capire/common';

View File

@@ -1,23 +0,0 @@
using { Currency, User, managed, cuid } from '@sap/cds/common';
using from '@capire/common';
namespace sap.capire.orders;
entity Orders : cuid, managed {
OrderNo : String @title:'Order Number'; //> readable key
Items : Composition of many {
key ID : UUID;
@assert.integrity:false // REVISIT: this is a temporary workaround for a glitch in cds-runtime
product : Association to Products;
amount : Integer;
title : String;
price : Double;
};
buyer : User;
currency : Currency;
}
/** This is a stand-in for arbitrary ordered Products */
@cds.persistence.skip:'always'
entity Products {
key ID : String;
}

View File

@@ -1,26 +0,0 @@
using { Currency, User, managed, cuid } from '@sap/cds/common';
using from '@capire/common';
namespace sap.capire.orders;
entity Orders : cuid, managed {
OrderNo : String @title:'Order Number'; //> readable key
Items : Composition of many Orders_Items on Items.up_ = $self;
buyer : User;
currency : Currency;
}
entity Orders_Items {
up_ : Association to Orders not null; //> IMPORTANT for Draft: not key(!)
key ID : UUID;
@assert.integrity:false // REVISIT: this is a temporary workaround for a glitch in cds-runtime
product : Association to Products;
amount : Integer;
title : String;
price : Double;
}
/** This is a stand-in for arbitrary ordered Products */
@cds.persistence.skip:'always'
entity Products {
key ID : String;
}

View File

@@ -1,465 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/Common.xml">
<edmx:Include Alias="Common" Namespace="com.sap.vocabularies.Common.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/UI.xml">
<edmx:Include Alias="UI" Namespace="com.sap.vocabularies.UI.v1"/>
</edmx:Reference>
<edmx:DataServices>
<Schema Namespace="OrdersService" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="EntityContainer">
<EntitySet Name="Currencies" EntityType="OrdersService.Currencies">
<NavigationPropertyBinding Path="texts" Target="Currencies_texts"/>
<NavigationPropertyBinding Path="localized" Target="Currencies_texts"/>
</EntitySet>
<EntitySet Name="Currencies_texts" EntityType="OrdersService.Currencies_texts"/>
<EntitySet Name="Orders" EntityType="OrdersService.Orders">
<NavigationPropertyBinding Path="Items" Target="Orders_Items"/>
<NavigationPropertyBinding Path="currency" Target="Currencies"/>
<NavigationPropertyBinding Path="SiblingEntity" Target="Orders"/>
</EntitySet>
<EntitySet Name="Orders_Items" EntityType="OrdersService.Orders_Items">
<NavigationPropertyBinding Path="up_" Target="Orders"/>
<NavigationPropertyBinding Path="SiblingEntity" Target="Orders_Items"/>
</EntitySet>
</EntityContainer>
<EntityType Name="Currencies">
<Key>
<PropertyRef Name="code"/>
</Key>
<Property Name="name" Type="Edm.String" MaxLength="255"/>
<Property Name="descr" Type="Edm.String" MaxLength="1000"/>
<Property Name="code" Type="Edm.String" MaxLength="3" Nullable="false"/>
<Property Name="symbol" Type="Edm.String" MaxLength="5"/>
<Property Name="numcode" Type="Edm.Int32"/>
<Property Name="exponent" Type="Edm.Int32"/>
<Property Name="minor" Type="Edm.String"/>
<NavigationProperty Name="texts" Type="Collection(OrdersService.Currencies_texts)">
<OnDelete Action="Cascade"/>
</NavigationProperty>
<NavigationProperty Name="localized" Type="OrdersService.Currencies_texts">
<ReferentialConstraint Property="code" ReferencedProperty="code"/>
</NavigationProperty>
</EntityType>
<EntityType Name="Currencies_texts">
<Key>
<PropertyRef Name="locale"/>
<PropertyRef Name="code"/>
</Key>
<Property Name="locale" Type="Edm.String" MaxLength="14" Nullable="false"/>
<Property Name="name" Type="Edm.String" MaxLength="255"/>
<Property Name="descr" Type="Edm.String" MaxLength="1000"/>
<Property Name="code" Type="Edm.String" MaxLength="3" Nullable="false"/>
</EntityType>
<EntityType Name="DraftAdministrativeData">
<Key>
<PropertyRef Name="DraftUUID"/>
</Key>
<Property Name="DraftUUID" Type="Edm.Guid" Nullable="false"/>
<Property Name="CreationDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="CreatedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsCreatedByMe" Type="Edm.Boolean"/>
<Property Name="LastChangeDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="LastChangedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="InProcessByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsProcessedByMe" Type="Edm.Boolean"/>
</EntityType>
<EntityType Name="Orders">
<Key>
<PropertyRef Name="ID"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<Property Name="createdAt" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="createdBy" Type="Edm.String" MaxLength="255"/>
<Property Name="modifiedAt" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="modifiedBy" Type="Edm.String" MaxLength="255"/>
<Property Name="OrderNo" Type="Edm.String"/>
<NavigationProperty Name="Items" Type="Collection(OrdersService.Orders_Items)" Partner="up_">
<OnDelete Action="Cascade"/>
</NavigationProperty>
<Property Name="buyer" Type="Edm.String" MaxLength="255"/>
<NavigationProperty Name="currency" Type="OrdersService.Currencies">
<ReferentialConstraint Property="currency_code" ReferencedProperty="code"/>
</NavigationProperty>
<Property Name="currency_code" Type="Edm.String" MaxLength="3"/>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="OrdersService.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="OrdersService.Orders"/>
</EntityType>
<EntityType Name="Orders_Items">
<Key>
<PropertyRef Name="up__ID"/>
<PropertyRef Name="ID"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="up__ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="up_" Type="OrdersService.Orders" Nullable="false" Partner="Items">
<ReferentialConstraint Property="up__ID" ReferencedProperty="ID"/>
</NavigationProperty>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<Property Name="amount" Type="Edm.Int32"/>
<Property Name="title" Type="Edm.String"/>
<Property Name="price" Type="Edm.Double"/>
<Property Name="product_ID" Type="Edm.String"/>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="OrdersService.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="OrdersService.Orders_Items"/>
</EntityType>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="OrdersService.Orders"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="OrdersService.Orders"/>
</Action>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="OrdersService.Orders_Items"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="OrdersService.Orders_Items"/>
</Action>
<Action Name="draftActivate" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="OrdersService.Orders"/>
<ReturnType Type="OrdersService.Orders"/>
</Action>
<Action Name="draftEdit" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="OrdersService.Orders"/>
<Parameter Name="PreserveChanges" Type="Edm.Boolean"/>
<ReturnType Type="OrdersService.Orders"/>
</Action>
<Annotations Target="OrdersService.Currencies">
<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="name"/>
</Record>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.Currencies/name">
<Annotation Term="Common.Label" String="{i18n>Name}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies/descr">
<Annotation Term="Common.Label" String="{i18n>Description}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies/code">
<Annotation Term="Common.Label" String="{i18n>CurrencyCode}"/>
<Annotation Term="Common.Text" Path="name"/>
</Annotations>
<Annotations Target="OrdersService.Currencies/symbol">
<Annotation Term="Common.Label" String="{i18n>CurrencySymbol}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies_texts/name">
<Annotation Term="Common.Label" String="{i18n>Name}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies_texts/descr">
<Annotation Term="Common.Label" String="{i18n>Description}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies_texts/code">
<Annotation Term="Common.Label" String="{i18n>CurrencyCode}"/>
<Annotation Term="Common.Text" Path="name"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftAdministrativeData}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/DraftUUID">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftUUID}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/CreationDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_CreationDateTime}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/CreatedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_CreatedByUser}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/DraftIsCreatedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsCreatedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/LastChangeDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangeDateTime}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/LastChangedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangedByUser}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/InProcessByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_InProcessByUser}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/DraftIsProcessedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsProcessedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders">
<Annotation Term="UI.Facets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>Details}"/>
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Details"/>
</Record>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>OrderItems}"/>
<PropertyValue Property="Target" AnnotationPath="Items/@UI.LineItem"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.FieldGroup" Qualifier="Created">
<Record Type="UI.FieldGroupType">
<PropertyValue Property="Data">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdBy"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdAt"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="UI.FieldGroup" Qualifier="Details">
<Record Type="UI.FieldGroupType">
<PropertyValue Property="Data">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="currency/code"/>
<PropertyValue Property="Label" String="Currency"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="UI.FieldGroup" Qualifier="Modified">
<Record Type="UI.FieldGroupType">
<PropertyValue Property="Data">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="modifiedBy"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="modifiedAt"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="UI.HeaderFacets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>Created}"/>
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Created"/>
</Record>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>Modified}"/>
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Modified"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.HeaderInfo">
<Record Type="UI.HeaderInfoType">
<PropertyValue Property="Description">
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdBy"/>
</Record>
</PropertyValue>
<PropertyValue Property="Title">
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Order number "/>
<PropertyValue Property="Value" Path="OrderNo"/>
</Record>
</PropertyValue>
<PropertyValue Property="TypeName" String="Order"/>
<PropertyValue Property="TypeNamePlural" String="Orders"/>
</Record>
</Annotation>
<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdBy"/>
<PropertyValue Property="Label" String="Customer"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdAt"/>
<PropertyValue Property="Label" String="Date"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="OrderNo"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="OrderNo"/>
<PropertyValue Property="Label" String="OrderNo"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="buyer"/>
<PropertyValue Property="Label" String="Customer"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdAt"/>
<PropertyValue Property="Label" String="Date"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.SelectionFields">
<Collection>
<PropertyPath>createdAt</PropertyPath>
<PropertyPath>createdBy</PropertyPath>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.EntityContainer/Orders">
<Annotation Term="Common.DraftRoot">
<Record Type="Common.DraftRootType">
<PropertyValue Property="ActivationAction" String="OrdersService.draftActivate"/>
<PropertyValue Property="EditAction" String="OrdersService.draftEdit"/>
<PropertyValue Property="PreparationAction" String="OrdersService.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.Orders/createdAt">
<Annotation Term="Common.Label" String="{i18n>CreatedAt}"/>
<Annotation Term="Core.Computed" Bool="true"/>
<Annotation Term="Core.Immutable" Bool="true"/>
<Annotation Term="UI.HiddenFilter" Bool="false"/>
</Annotations>
<Annotations Target="OrdersService.Orders/createdBy">
<Annotation Term="Common.Label" String="{i18n>CreatedBy}"/>
<Annotation Term="Core.Computed" Bool="true"/>
<Annotation Term="Core.Description" String="{i18n>UserID.Description}"/>
<Annotation Term="Core.Immutable" Bool="true"/>
<Annotation Term="UI.HiddenFilter" Bool="false"/>
</Annotations>
<Annotations Target="OrdersService.Orders/modifiedAt">
<Annotation Term="Common.Label" String="{i18n>ChangedAt}"/>
<Annotation Term="Core.Computed" Bool="true"/>
<Annotation Term="UI.HiddenFilter" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/modifiedBy">
<Annotation Term="Common.Label" String="{i18n>ChangedBy}"/>
<Annotation Term="Core.Computed" Bool="true"/>
<Annotation Term="Core.Description" String="{i18n>UserID.Description}"/>
<Annotation Term="UI.HiddenFilter" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/OrderNo">
<Annotation Term="Common.Label" String="Order Number"/>
</Annotations>
<Annotations Target="OrdersService.Orders/buyer">
<Annotation Term="Common.Label" String="{i18n>UserID}"/>
<Annotation Term="Core.Description" String="{i18n>UserID.Description}"/>
</Annotations>
<Annotations Target="OrdersService.Orders/currency">
<Annotation Term="Common.Label" String="{i18n>Currency}"/>
<Annotation Term="Core.Description" String="{i18n>CurrencyCode.Description}"/>
</Annotations>
<Annotations Target="OrdersService.Orders/currency_code">
<Annotation Term="Common.Label" String="{i18n>Currency}"/>
<Annotation Term="Common.ValueList">
<Record Type="Common.ValueListType">
<PropertyValue Property="Label" String="{i18n>Currency}"/>
<PropertyValue Property="CollectionPath" String="Currencies"/>
<PropertyValue Property="Parameters">
<Collection>
<Record Type="Common.ValueListParameterInOut">
<PropertyValue Property="LocalDataProperty" PropertyPath="currency_code"/>
<PropertyValue Property="ValueListProperty" String="code"/>
</Record>
<Record Type="Common.ValueListParameterDisplayOnly">
<PropertyValue Property="ValueListProperty" String="name"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="Core.Description" String="{i18n>CurrencyCode.Description}"/>
</Annotations>
<Annotations Target="OrdersService.Orders/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items">
<Annotation Term="UI.Facets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>OrderItems}"/>
<PropertyValue Property="Target" AnnotationPath="@UI.Identification"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="amount"/>
<PropertyValue Property="Label" String="Amount"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="title"/>
<PropertyValue Property="Label" String="Product"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="price"/>
<PropertyValue Property="Label" String="Unit Price"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="product_ID"/>
<PropertyValue Property="Label" String="Product ID"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="title"/>
<PropertyValue Property="Label" String="Product Title"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="price"/>
<PropertyValue Property="Label" String="Unit Price"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="amount"/>
<PropertyValue Property="Label" String="Quantity"/>
</Record>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.EntityContainer/Orders_Items">
<Annotation Term="Common.DraftNode">
<Record Type="Common.DraftNodeType">
<PropertyValue Property="PreparationAction" String="OrdersService.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/amount">
<Annotation Term="Common.FieldControl" EnumMember="Common.FieldControlType/Mandatory"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@@ -1,464 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/Common.xml">
<edmx:Include Alias="Common" Namespace="com.sap.vocabularies.Common.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/UI.xml">
<edmx:Include Alias="UI" Namespace="com.sap.vocabularies.UI.v1"/>
</edmx:Reference>
<edmx:DataServices>
<Schema Namespace="OrdersService" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="EntityContainer">
<EntitySet Name="Currencies" EntityType="OrdersService.Currencies">
<NavigationPropertyBinding Path="texts" Target="Currencies_texts"/>
<NavigationPropertyBinding Path="localized" Target="Currencies_texts"/>
</EntitySet>
<EntitySet Name="Currencies_texts" EntityType="OrdersService.Currencies_texts"/>
<EntitySet Name="Orders" EntityType="OrdersService.Orders">
<NavigationPropertyBinding Path="Items" Target="Orders_Items"/>
<NavigationPropertyBinding Path="currency" Target="Currencies"/>
<NavigationPropertyBinding Path="SiblingEntity" Target="Orders"/>
</EntitySet>
<EntitySet Name="Orders_Items" EntityType="OrdersService.Orders_Items">
<NavigationPropertyBinding Path="up_" Target="Orders"/>
<NavigationPropertyBinding Path="SiblingEntity" Target="Orders_Items"/>
</EntitySet>
</EntityContainer>
<EntityType Name="Currencies">
<Key>
<PropertyRef Name="code"/>
</Key>
<Property Name="name" Type="Edm.String" MaxLength="255"/>
<Property Name="descr" Type="Edm.String" MaxLength="1000"/>
<Property Name="code" Type="Edm.String" MaxLength="3" Nullable="false"/>
<Property Name="symbol" Type="Edm.String" MaxLength="5"/>
<Property Name="numcode" Type="Edm.Int32"/>
<Property Name="exponent" Type="Edm.Int32"/>
<Property Name="minor" Type="Edm.String"/>
<NavigationProperty Name="texts" Type="Collection(OrdersService.Currencies_texts)">
<OnDelete Action="Cascade"/>
</NavigationProperty>
<NavigationProperty Name="localized" Type="OrdersService.Currencies_texts">
<ReferentialConstraint Property="code" ReferencedProperty="code"/>
</NavigationProperty>
</EntityType>
<EntityType Name="Currencies_texts">
<Key>
<PropertyRef Name="locale"/>
<PropertyRef Name="code"/>
</Key>
<Property Name="locale" Type="Edm.String" MaxLength="14" Nullable="false"/>
<Property Name="name" Type="Edm.String" MaxLength="255"/>
<Property Name="descr" Type="Edm.String" MaxLength="1000"/>
<Property Name="code" Type="Edm.String" MaxLength="3" Nullable="false"/>
</EntityType>
<EntityType Name="DraftAdministrativeData">
<Key>
<PropertyRef Name="DraftUUID"/>
</Key>
<Property Name="DraftUUID" Type="Edm.Guid" Nullable="false"/>
<Property Name="CreationDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="CreatedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsCreatedByMe" Type="Edm.Boolean"/>
<Property Name="LastChangeDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="LastChangedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="InProcessByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsProcessedByMe" Type="Edm.Boolean"/>
</EntityType>
<EntityType Name="Orders">
<Key>
<PropertyRef Name="ID"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<Property Name="createdAt" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="createdBy" Type="Edm.String" MaxLength="255"/>
<Property Name="modifiedAt" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="modifiedBy" Type="Edm.String" MaxLength="255"/>
<Property Name="OrderNo" Type="Edm.String"/>
<NavigationProperty Name="Items" Type="Collection(OrdersService.Orders_Items)" Partner="up_">
<OnDelete Action="Cascade"/>
</NavigationProperty>
<Property Name="buyer" Type="Edm.String" MaxLength="255"/>
<NavigationProperty Name="currency" Type="OrdersService.Currencies">
<ReferentialConstraint Property="currency_code" ReferencedProperty="code"/>
</NavigationProperty>
<Property Name="currency_code" Type="Edm.String" MaxLength="3"/>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="OrdersService.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="OrdersService.Orders"/>
</EntityType>
<EntityType Name="Orders_Items">
<Key>
<PropertyRef Name="ID"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="up__ID" Type="Edm.Guid"/>
<NavigationProperty Name="up_" Type="OrdersService.Orders" Partner="Items">
<ReferentialConstraint Property="up__ID" ReferencedProperty="ID"/>
</NavigationProperty>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<Property Name="amount" Type="Edm.Int32"/>
<Property Name="title" Type="Edm.String"/>
<Property Name="price" Type="Edm.Double"/>
<Property Name="product_ID" Type="Edm.String"/>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="OrdersService.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="OrdersService.Orders_Items"/>
</EntityType>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="OrdersService.Orders"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="OrdersService.Orders"/>
</Action>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="OrdersService.Orders_Items"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="OrdersService.Orders_Items"/>
</Action>
<Action Name="draftActivate" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="OrdersService.Orders"/>
<ReturnType Type="OrdersService.Orders"/>
</Action>
<Action Name="draftEdit" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="OrdersService.Orders"/>
<Parameter Name="PreserveChanges" Type="Edm.Boolean"/>
<ReturnType Type="OrdersService.Orders"/>
</Action>
<Annotations Target="OrdersService.Currencies">
<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="name"/>
</Record>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.Currencies/name">
<Annotation Term="Common.Label" String="{i18n>Name}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies/descr">
<Annotation Term="Common.Label" String="{i18n>Description}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies/code">
<Annotation Term="Common.Label" String="{i18n>CurrencyCode}"/>
<Annotation Term="Common.Text" Path="name"/>
</Annotations>
<Annotations Target="OrdersService.Currencies/symbol">
<Annotation Term="Common.Label" String="{i18n>CurrencySymbol}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies_texts/name">
<Annotation Term="Common.Label" String="{i18n>Name}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies_texts/descr">
<Annotation Term="Common.Label" String="{i18n>Description}"/>
</Annotations>
<Annotations Target="OrdersService.Currencies_texts/code">
<Annotation Term="Common.Label" String="{i18n>CurrencyCode}"/>
<Annotation Term="Common.Text" Path="name"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftAdministrativeData}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/DraftUUID">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftUUID}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/CreationDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_CreationDateTime}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/CreatedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_CreatedByUser}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/DraftIsCreatedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsCreatedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/LastChangeDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangeDateTime}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/LastChangedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangedByUser}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/InProcessByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_InProcessByUser}"/>
</Annotations>
<Annotations Target="OrdersService.DraftAdministrativeData/DraftIsProcessedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsProcessedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders">
<Annotation Term="UI.Facets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>Details}"/>
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Details"/>
</Record>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>OrderItems}"/>
<PropertyValue Property="Target" AnnotationPath="Items/@UI.LineItem"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.FieldGroup" Qualifier="Created">
<Record Type="UI.FieldGroupType">
<PropertyValue Property="Data">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdBy"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdAt"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="UI.FieldGroup" Qualifier="Details">
<Record Type="UI.FieldGroupType">
<PropertyValue Property="Data">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="currency/code"/>
<PropertyValue Property="Label" String="Currency"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="UI.FieldGroup" Qualifier="Modified">
<Record Type="UI.FieldGroupType">
<PropertyValue Property="Data">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="modifiedBy"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="modifiedAt"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="UI.HeaderFacets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>Created}"/>
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Created"/>
</Record>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>Modified}"/>
<PropertyValue Property="Target" AnnotationPath="@UI.FieldGroup#Modified"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.HeaderInfo">
<Record Type="UI.HeaderInfoType">
<PropertyValue Property="Description">
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdBy"/>
</Record>
</PropertyValue>
<PropertyValue Property="Title">
<Record Type="UI.DataField">
<PropertyValue Property="Label" String="Order number "/>
<PropertyValue Property="Value" Path="OrderNo"/>
</Record>
</PropertyValue>
<PropertyValue Property="TypeName" String="Order"/>
<PropertyValue Property="TypeNamePlural" String="Orders"/>
</Record>
</Annotation>
<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdBy"/>
<PropertyValue Property="Label" String="Customer"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdAt"/>
<PropertyValue Property="Label" String="Date"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="OrderNo"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="OrderNo"/>
<PropertyValue Property="Label" String="OrderNo"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="buyer"/>
<PropertyValue Property="Label" String="Customer"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="createdAt"/>
<PropertyValue Property="Label" String="Date"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.SelectionFields">
<Collection>
<PropertyPath>createdAt</PropertyPath>
<PropertyPath>createdBy</PropertyPath>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.EntityContainer/Orders">
<Annotation Term="Common.DraftRoot">
<Record Type="Common.DraftRootType">
<PropertyValue Property="ActivationAction" String="OrdersService.draftActivate"/>
<PropertyValue Property="EditAction" String="OrdersService.draftEdit"/>
<PropertyValue Property="PreparationAction" String="OrdersService.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.Orders/createdAt">
<Annotation Term="Common.Label" String="{i18n>CreatedAt}"/>
<Annotation Term="Core.Computed" Bool="true"/>
<Annotation Term="Core.Immutable" Bool="true"/>
<Annotation Term="UI.HiddenFilter" Bool="false"/>
</Annotations>
<Annotations Target="OrdersService.Orders/createdBy">
<Annotation Term="Common.Label" String="{i18n>CreatedBy}"/>
<Annotation Term="Core.Computed" Bool="true"/>
<Annotation Term="Core.Description" String="{i18n>UserID.Description}"/>
<Annotation Term="Core.Immutable" Bool="true"/>
<Annotation Term="UI.HiddenFilter" Bool="false"/>
</Annotations>
<Annotations Target="OrdersService.Orders/modifiedAt">
<Annotation Term="Common.Label" String="{i18n>ChangedAt}"/>
<Annotation Term="Core.Computed" Bool="true"/>
<Annotation Term="UI.HiddenFilter" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/modifiedBy">
<Annotation Term="Common.Label" String="{i18n>ChangedBy}"/>
<Annotation Term="Core.Computed" Bool="true"/>
<Annotation Term="Core.Description" String="{i18n>UserID.Description}"/>
<Annotation Term="UI.HiddenFilter" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/OrderNo">
<Annotation Term="Common.Label" String="Order Number"/>
</Annotations>
<Annotations Target="OrdersService.Orders/buyer">
<Annotation Term="Common.Label" String="{i18n>UserID}"/>
<Annotation Term="Core.Description" String="{i18n>UserID.Description}"/>
</Annotations>
<Annotations Target="OrdersService.Orders/currency">
<Annotation Term="Common.Label" String="{i18n>Currency}"/>
<Annotation Term="Core.Description" String="{i18n>CurrencyCode.Description}"/>
</Annotations>
<Annotations Target="OrdersService.Orders/currency_code">
<Annotation Term="Common.Label" String="{i18n>Currency}"/>
<Annotation Term="Common.ValueList">
<Record Type="Common.ValueListType">
<PropertyValue Property="Label" String="{i18n>Currency}"/>
<PropertyValue Property="CollectionPath" String="Currencies"/>
<PropertyValue Property="Parameters">
<Collection>
<Record Type="Common.ValueListParameterInOut">
<PropertyValue Property="LocalDataProperty" PropertyPath="currency_code"/>
<PropertyValue Property="ValueListProperty" String="code"/>
</Record>
<Record Type="Common.ValueListParameterDisplayOnly">
<PropertyValue Property="ValueListProperty" String="name"/>
</Record>
</Collection>
</PropertyValue>
</Record>
</Annotation>
<Annotation Term="Core.Description" String="{i18n>CurrencyCode.Description}"/>
</Annotations>
<Annotations Target="OrdersService.Orders/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items">
<Annotation Term="UI.Facets">
<Collection>
<Record Type="UI.ReferenceFacet">
<PropertyValue Property="Label" String="{i18n>OrderItems}"/>
<PropertyValue Property="Target" AnnotationPath="@UI.Identification"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="amount"/>
<PropertyValue Property="Label" String="Amount"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="title"/>
<PropertyValue Property="Label" String="Product"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="price"/>
<PropertyValue Property="Label" String="Unit Price"/>
</Record>
</Collection>
</Annotation>
<Annotation Term="UI.LineItem">
<Collection>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="product_ID"/>
<PropertyValue Property="Label" String="Product ID"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="title"/>
<PropertyValue Property="Label" String="Product Title"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="price"/>
<PropertyValue Property="Label" String="Unit Price"/>
</Record>
<Record Type="UI.DataField">
<PropertyValue Property="Value" Path="amount"/>
<PropertyValue Property="Label" String="Quantity"/>
</Record>
</Collection>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.EntityContainer/Orders_Items">
<Annotation Term="Common.DraftNode">
<Record Type="Common.DraftNodeType">
<PropertyValue Property="PreparationAction" String="OrdersService.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/amount">
<Annotation Term="Common.FieldControl" EnumMember="Common.FieldControlType/Mandatory"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="OrdersService.Orders_Items/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@@ -4,10 +4,5 @@
"dependencies": { "dependencies": {
"@capire/common": "*", "@capire/common": "*",
"@sap/cds": "^4.3.0" "@sap/cds": "^4.3.0"
},
"cds": {
"odata": {
"--containment": true
}
} }
} }

View File

@@ -11,7 +11,7 @@ class OrdersService extends cds.ApplicationService {
const { amount:before } = await cds.tx(req).run ( const { amount:before } = await cds.tx(req).run (
SELECT.one.from (OrderItems, oi => oi.amount) .where ({up__ID:ID, product_ID}) SELECT.one.from (OrderItems, oi => oi.amount) .where ({up__ID:ID, product_ID})
) )
if (amount != before) this.orderChanged (product_ID, amount-before) if (amount != before) await this.orderChanged (product_ID, amount-before)
} }
}) })
@@ -20,7 +20,7 @@ class OrdersService extends cds.ApplicationService {
const Items = await cds.tx(req).run ( const Items = await cds.tx(req).run (
SELECT.from (OrderItems, oi => { oi.product_ID, oi.amount }) .where ({up__ID:ID}) SELECT.from (OrderItems, oi => { oi.product_ID, oi.amount }) .where ({up__ID:ID})
) )
if (Items) for (let it of Items) this.orderChanged (it.product_ID, -it.amount) if (Items) await Promise.all (Items.map(it => this.orderChanged (it.product_ID, -it.amount)))
}) })
return super.init() return super.init()

View File

@@ -1,14 +0,0 @@
service WithDraft {
@odata.draft.enabled
entity Boo as projection on Foo;
}
service WithoutDraft {
entity Boo as projection on Foo;
}
entity Foo {
key ID : UUID;
bar : Composition of many {
key pos : Integer; //> meant to be a local key only
}
}

View File

@@ -1,142 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/Common.xml">
<edmx:Include Alias="Common" Namespace="com.sap.vocabularies.Common.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/UI.xml">
<edmx:Include Alias="UI" Namespace="com.sap.vocabularies.UI.v1"/>
</edmx:Reference>
<edmx:DataServices>
<Schema Namespace="WithDraft" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="EntityContainer">
<EntitySet Name="Boo" EntityType="WithDraft.Boo">
<NavigationPropertyBinding Path="SiblingEntity" Target="Boo"/>
</EntitySet>
</EntityContainer>
<EntityType Name="Boo">
<Key>
<PropertyRef Name="ID"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="bar" Type="Collection(WithDraft.Foo_bar)" Partner="up_" ContainsTarget="true"/>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="WithDraft.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="WithDraft.Boo"/>
</EntityType>
<EntityType Name="DraftAdministrativeData">
<Key>
<PropertyRef Name="DraftUUID"/>
</Key>
<Property Name="DraftUUID" Type="Edm.Guid" Nullable="false"/>
<Property Name="CreationDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="CreatedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsCreatedByMe" Type="Edm.Boolean"/>
<Property Name="LastChangeDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="LastChangedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="InProcessByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsProcessedByMe" Type="Edm.Boolean"/>
</EntityType>
<EntityType Name="Foo_bar">
<Key>
<PropertyRef Name="pos"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<NavigationProperty Name="up_" Type="WithDraft.Boo" Nullable="false" Partner="bar"/>
<Property Name="pos" Type="Edm.Int32" Nullable="false"/>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="WithDraft.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="WithDraft.Foo_bar"/>
</EntityType>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Foo_bar"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="WithDraft.Foo_bar"/>
</Action>
<Action Name="draftActivate" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Action Name="draftEdit" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<Parameter Name="PreserveChanges" Type="Edm.Boolean"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Annotations Target="WithDraft.EntityContainer/Boo">
<Annotation Term="Common.DraftRoot">
<Record Type="Common.DraftRootType">
<PropertyValue Property="ActivationAction" String="WithDraft.draftActivate"/>
<PropertyValue Property="EditAction" String="WithDraft.draftEdit"/>
<PropertyValue Property="PreparationAction" String="WithDraft.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="WithDraft.Boo/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftAdministrativeData}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftUUID">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftUUID}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/CreationDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_CreationDateTime}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/CreatedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_CreatedByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftIsCreatedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsCreatedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/LastChangeDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangeDateTime}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/LastChangedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangedByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/InProcessByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_InProcessByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftIsProcessedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsProcessedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="WithoutDraft" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="EntityContainer">
<EntitySet Name="Boo" EntityType="WithoutDraft.Boo"/>
</EntityContainer>
<EntityType Name="Boo">
<Key>
<PropertyRef Name="ID"/>
</Key>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="bar" Type="Collection(WithoutDraft.Foo_bar)" Partner="up_" ContainsTarget="true"/>
</EntityType>
<EntityType Name="Foo_bar">
<Key>
<PropertyRef Name="pos"/>
</Key>
<NavigationProperty Name="up_" Type="WithoutDraft.Boo" Nullable="false" Partner="bar"/>
<Property Name="pos" Type="Edm.Int32" Nullable="false"/>
</EntityType>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@@ -1,159 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/Common.xml">
<edmx:Include Alias="Common" Namespace="com.sap.vocabularies.Common.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/UI.xml">
<edmx:Include Alias="UI" Namespace="com.sap.vocabularies.UI.v1"/>
</edmx:Reference>
<edmx:DataServices>
<Schema Namespace="WithDraft" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="EntityContainer">
<EntitySet Name="Boo" EntityType="WithDraft.Boo">
<NavigationPropertyBinding Path="bar" Target="Foo_bar"/>
<NavigationPropertyBinding Path="SiblingEntity" Target="Boo"/>
</EntitySet>
<EntitySet Name="Foo_bar" EntityType="WithDraft.Foo_bar">
<NavigationPropertyBinding Path="up_" Target="Boo"/>
<NavigationPropertyBinding Path="SiblingEntity" Target="Foo_bar"/>
</EntitySet>
</EntityContainer>
<EntityType Name="Boo">
<Key>
<PropertyRef Name="ID"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="bar" Type="Collection(WithDraft.Foo_bar)" Partner="up_">
<OnDelete Action="Cascade"/>
</NavigationProperty>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="WithDraft.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="WithDraft.Boo"/>
</EntityType>
<EntityType Name="DraftAdministrativeData">
<Key>
<PropertyRef Name="DraftUUID"/>
</Key>
<Property Name="DraftUUID" Type="Edm.Guid" Nullable="false"/>
<Property Name="CreationDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="CreatedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsCreatedByMe" Type="Edm.Boolean"/>
<Property Name="LastChangeDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="LastChangedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="InProcessByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsProcessedByMe" Type="Edm.Boolean"/>
</EntityType>
<EntityType Name="Foo_bar">
<Key>
<PropertyRef Name="pos"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="up__ID" Type="Edm.Guid"/>
<NavigationProperty Name="up_" Type="WithDraft.Boo" Nullable="false" Partner="bar">
<ReferentialConstraint Property="up__ID" ReferencedProperty="ID"/>
</NavigationProperty>
<Property Name="pos" Type="Edm.Int32" Nullable="false"/>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="WithDraft.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="WithDraft.Foo_bar"/>
</EntityType>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Foo_bar"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="WithDraft.Foo_bar"/>
</Action>
<Action Name="draftActivate" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Action Name="draftEdit" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<Parameter Name="PreserveChanges" Type="Edm.Boolean"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Annotations Target="WithDraft.EntityContainer/Boo">
<Annotation Term="Common.DraftRoot">
<Record Type="Common.DraftRootType">
<PropertyValue Property="ActivationAction" String="WithDraft.draftActivate"/>
<PropertyValue Property="EditAction" String="WithDraft.draftEdit"/>
<PropertyValue Property="PreparationAction" String="WithDraft.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="WithDraft.Boo/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftAdministrativeData}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftUUID">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftUUID}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/CreationDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_CreationDateTime}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/CreatedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_CreatedByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftIsCreatedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsCreatedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/LastChangeDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangeDateTime}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/LastChangedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangedByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/InProcessByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_InProcessByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftIsProcessedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsProcessedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.EntityContainer/Foo_bar">
<Annotation Term="Common.DraftNode">
<Record Type="Common.DraftNodeType">
<PropertyValue Property="PreparationAction" String="WithDraft.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="WithoutDraft" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="EntityContainer">
<EntitySet Name="Boo" EntityType="WithoutDraft.Boo">
<NavigationPropertyBinding Path="bar" Target="Foo_bar"/>
</EntitySet>
<EntitySet Name="Foo_bar" EntityType="WithoutDraft.Foo_bar">
<NavigationPropertyBinding Path="up_" Target="Boo"/>
</EntitySet>
</EntityContainer>
<EntityType Name="Boo">
<Key>
<PropertyRef Name="ID"/>
</Key>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="bar" Type="Collection(WithoutDraft.Foo_bar)" Partner="up_">
<OnDelete Action="Cascade"/>
</NavigationProperty>
</EntityType>
<EntityType Name="Foo_bar">
<Key>
<PropertyRef Name="up__ID"/>
<PropertyRef Name="pos"/>
</Key>
<Property Name="up__ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="up_" Type="WithoutDraft.Boo" Nullable="false" Partner="bar">
<ReferentialConstraint Property="up__ID" ReferencedProperty="ID"/>
</NavigationProperty>
<Property Name="pos" Type="Edm.Int32" Nullable="false"/>
</EntityType>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@@ -1,160 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/Common.xml">
<edmx:Include Alias="Common" Namespace="com.sap.vocabularies.Common.v1"/>
</edmx:Reference>
<edmx:Reference Uri="https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Core.V1.xml">
<edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
</edmx:Reference>
<edmx:Reference Uri="https://sap.github.io/odata-vocabularies/vocabularies/UI.xml">
<edmx:Include Alias="UI" Namespace="com.sap.vocabularies.UI.v1"/>
</edmx:Reference>
<edmx:DataServices>
<Schema Namespace="WithDraft" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="EntityContainer">
<EntitySet Name="Boo" EntityType="WithDraft.Boo">
<NavigationPropertyBinding Path="bar" Target="Foo_bar"/>
<NavigationPropertyBinding Path="SiblingEntity" Target="Boo"/>
</EntitySet>
<EntitySet Name="Foo_bar" EntityType="WithDraft.Foo_bar">
<NavigationPropertyBinding Path="up_" Target="Boo"/>
<NavigationPropertyBinding Path="SiblingEntity" Target="Foo_bar"/>
</EntitySet>
</EntityContainer>
<EntityType Name="Boo">
<Key>
<PropertyRef Name="ID"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="bar" Type="Collection(WithDraft.Foo_bar)" Partner="up_">
<OnDelete Action="Cascade"/>
</NavigationProperty>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="WithDraft.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="WithDraft.Boo"/>
</EntityType>
<EntityType Name="DraftAdministrativeData">
<Key>
<PropertyRef Name="DraftUUID"/>
</Key>
<Property Name="DraftUUID" Type="Edm.Guid" Nullable="false"/>
<Property Name="CreationDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="CreatedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsCreatedByMe" Type="Edm.Boolean"/>
<Property Name="LastChangeDateTime" Type="Edm.DateTimeOffset" Precision="7"/>
<Property Name="LastChangedByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="InProcessByUser" Type="Edm.String" MaxLength="256"/>
<Property Name="DraftIsProcessedByMe" Type="Edm.Boolean"/>
</EntityType>
<EntityType Name="Foo_bar">
<Key>
<PropertyRef Name="up__ID"/>
<PropertyRef Name="pos"/>
<PropertyRef Name="IsActiveEntity"/>
</Key>
<Property Name="up__ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="up_" Type="WithDraft.Boo" Nullable="false" Partner="bar">
<ReferentialConstraint Property="up__ID" ReferencedProperty="ID"/>
</NavigationProperty>
<Property Name="pos" Type="Edm.Int32" Nullable="false"/>
<Property Name="IsActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasActiveEntity" Type="Edm.Boolean" Nullable="false"/>
<Property Name="HasDraftEntity" Type="Edm.Boolean" Nullable="false"/>
<NavigationProperty Name="DraftAdministrativeData" Type="WithDraft.DraftAdministrativeData" ContainsTarget="true"/>
<NavigationProperty Name="SiblingEntity" Type="WithDraft.Foo_bar"/>
</EntityType>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Action Name="draftPrepare" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Foo_bar"/>
<Parameter Name="SideEffectsQualifier" Type="Edm.String"/>
<ReturnType Type="WithDraft.Foo_bar"/>
</Action>
<Action Name="draftActivate" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Action Name="draftEdit" IsBound="true" EntitySetPath="in">
<Parameter Name="in" Type="WithDraft.Boo"/>
<Parameter Name="PreserveChanges" Type="Edm.Boolean"/>
<ReturnType Type="WithDraft.Boo"/>
</Action>
<Annotations Target="WithDraft.EntityContainer/Boo">
<Annotation Term="Common.DraftRoot">
<Record Type="Common.DraftRootType">
<PropertyValue Property="ActivationAction" String="WithDraft.draftActivate"/>
<PropertyValue Property="EditAction" String="WithDraft.draftEdit"/>
<PropertyValue Property="PreparationAction" String="WithDraft.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="WithDraft.Boo/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Boo/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftAdministrativeData}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftUUID">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftUUID}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/CreationDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_CreationDateTime}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/CreatedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_CreatedByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftIsCreatedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsCreatedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/LastChangeDateTime">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangeDateTime}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/LastChangedByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_LastChangedByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/InProcessByUser">
<Annotation Term="Common.Label" String="{i18n>Draft_InProcessByUser}"/>
</Annotations>
<Annotations Target="WithDraft.DraftAdministrativeData/DraftIsProcessedByMe">
<Annotation Term="Common.Label" String="{i18n>Draft_DraftIsProcessedByMe}"/>
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.EntityContainer/Foo_bar">
<Annotation Term="Common.DraftNode">
<Record Type="Common.DraftNodeType">
<PropertyValue Property="PreparationAction" String="WithDraft.draftPrepare"/>
</Record>
</Annotation>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/IsActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/HasActiveEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/HasDraftEntity">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
<Annotations Target="WithDraft.Foo_bar/DraftAdministrativeData">
<Annotation Term="UI.Hidden" Bool="true"/>
</Annotations>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="WithoutDraft" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="EntityContainer">
<EntitySet Name="Boo" EntityType="WithoutDraft.Boo">
<NavigationPropertyBinding Path="bar" Target="Foo_bar"/>
</EntitySet>
<EntitySet Name="Foo_bar" EntityType="WithoutDraft.Foo_bar">
<NavigationPropertyBinding Path="up_" Target="Boo"/>
</EntitySet>
</EntityContainer>
<EntityType Name="Boo">
<Key>
<PropertyRef Name="ID"/>
</Key>
<Property Name="ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="bar" Type="Collection(WithoutDraft.Foo_bar)" Partner="up_">
<OnDelete Action="Cascade"/>
</NavigationProperty>
</EntityType>
<EntityType Name="Foo_bar">
<Key>
<PropertyRef Name="up__ID"/>
<PropertyRef Name="pos"/>
</Key>
<Property Name="up__ID" Type="Edm.Guid" Nullable="false"/>
<NavigationProperty Name="up_" Type="WithoutDraft.Boo" Nullable="false" Partner="bar">
<ReferentialConstraint Property="up__ID" ReferencedProperty="ID"/>
</NavigationProperty>
<Property Name="pos" Type="Edm.Int32" Nullable="false"/>
</EntityType>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@@ -14,6 +14,7 @@
"@capire/reviews": "./reviews" "@capire/reviews": "./reviews"
}, },
"devDependencies": { "devDependencies": {
"pegjs": "^0.10.0",
"chai": "^4.2.0", "chai": "^4.2.0",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"chai-subset": "^1.6.0", "chai-subset": "^1.6.0",

View File

@@ -37,7 +37,7 @@ const reviews = new Vue ({
reviews.message = {} reviews.message = {}
}, },
async newReview () { newReview () {
reviews.review = {} reviews.review = {}
reviews.message = {} reviews.message = {}
setTimeout (()=> $('form > input').focus(), 111) setTimeout (()=> $('form > input').focus(), 111)

View File

@@ -1,5 +1,5 @@
const cds = require ('@sap/cds') const cds = require ('@sap/cds')
module.exports = cds.service.impl (async function(){ module.exports = cds.service.impl (function(){
// Get the CSN definition for Reviews from the db schema for sub-sequent queries // Get the CSN definition for Reviews from the db schema for sub-sequent queries
// ( Note: we explicitly specify the namespace to support embedded reuse ) // ( Note: we explicitly specify the namespace to support embedded reuse )
@@ -16,7 +16,7 @@ module.exports = cds.service.impl (async function(){
SELECT.one (['round(avg(rating),2) as rating']) .from (Reviews) .where ({subject}) SELECT.one (['round(avg(rating),2) as rating']) .from (Reviews) .where ({subject})
) )
global.it || console.log ('< emitting:', 'reviewed', { subject, rating }) global.it || console.log ('< emitting:', 'reviewed', { subject, rating })
this.emit ('reviewed', { subject, rating }) await this.emit ('reviewed', { subject, rating })
}) })
// Increment counter for reviews considered helpful // Increment counter for reviews considered helpful

View File

@@ -1,7 +1,7 @@
# Overview of Samples # Overview of Samples
The list below gives an overview of the samples provided in subdirectories. The following list gives an overview of the samples provided in subdirectories.
Each sub directory essentially is a individual npm package arranged in an [all-in-one monorepo](all-in-one-monorepo) umbrella setup. Each sub directory essentially is an individual npm package arranged in an [all-in-one monorepo](all-in-one-monorepo) umbrella setup.
## [@capire/hello-world](hello) ## [@capire/hello-world](hello)
@@ -13,7 +13,7 @@ Each sub directory essentially is a individual npm package arranged in an [all-i
- [Getting Started](https://cap.cloud.sap/docs/get-started/in-a-nutshell) with CAP, briefly introducing: - [Getting Started](https://cap.cloud.sap/docs/get-started/in-a-nutshell) with CAP, briefly introducing:
- [Project Setup](https://cap.cloud.sap/docs/get-started/) and [Layouts](https://cap.cloud.sap/docs/get-started/projects) - [Project Setup](https://cap.cloud.sap/docs/get-started/) and [Layouts](https://cap.cloud.sap/docs/get-started/projects)
- [Domain Modelling](https://cap.cloud.sap/docs/guides/domain-models) - [Domain Modeling](https://cap.cloud.sap/docs/guides/domain-models)
- [Defining Services](https://cap.cloud.sap/docs/guides/providing-services) - [Defining Services](https://cap.cloud.sap/docs/guides/providing-services)
- [Generic Providers](https://cap.cloud.sap/docs/guides/generic-providers) - [Generic Providers](https://cap.cloud.sap/docs/guides/generic-providers)
- [Adding Custom Logic](https://cap.cloud.sap/docs/guides/service-impl) - [Adding Custom Logic](https://cap.cloud.sap/docs/guides/service-impl)
@@ -22,7 +22,7 @@ Each sub directory essentially is a individual npm package arranged in an [all-i
## [@capire/common](common) ## [@capire/common](common)
- Showcases how to extend [@sap/cds/common](https://cap.cloud.sap/docs/cds/common) thereby covering... - Showcases how to extend [@sap/cds/common](https://cap.cloud.sap/docs/cds/common) thereby covering:
- Building [extension packages](https://cap.cloud.sap/docs/guides/domain-models#aspects-extensibility) - Building [extension packages](https://cap.cloud.sap/docs/guides/domain-models#aspects-extensibility)
- Providing [reuse packages](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content) - Providing [reuse packages](https://cap.cloud.sap/docs/get-started/projects#sharing-and-reusing-content)
- [Verticalization](https://cap.cloud.sap/docs/cds/common#adapting-to-your-needs) - [Verticalization](https://cap.cloud.sap/docs/cds/common#adapting-to-your-needs)
@@ -32,22 +32,22 @@ Each sub directory essentially is a individual npm package arranged in an [all-i
## [@capire/orders](orders) ## [@capire/orders](orders)
- A standalone orders mgmt service, demonstrating... - A standalone orders management service, demonstrating:
- Using [Compositions](https://cap.cloud.sap/docs/cds/cdl#compositions) in [Domain Models](https://cap.cloud.sap/docs/guides/domain-models), along with - Using [Compositions](https://cap.cloud.sap/docs/cds/cdl#compositions) in [Domain Models](https://cap.cloud.sap/docs/guides/domain-models), along with
- [Serving deeply nested documents](https://cap.cloud.sap/docs/guides/generic-providers#serving-structured-data) - [Serving deeply nested documents](https://cap.cloud.sap/docs/guides/generic-providers#serving-structured-data)
## [@capire/reviews](reviews) ## [@capire/reviews](reviews)
- Shows how to implement a modular service to manage product reviews, including... - Shows how to implement a modular service to manage product reviews, including:
- Consuming other services synchronously and asynchronously - Consuming other services synchronously and asynchronously
- Serving requests synchronously - Serving requests synchronously
- Emitting events asynchronously - Emitting events asynchronously
- Grow as you go, with... - Grow as you go, with:
- Mocking app services - Mocking app services
- Running service meshes - Running service meshes
- Late-cut Micro Services - Late-cut Micro Services
- As well as managed data, input validations and authorization - As well as managed data, input validations, and authorization
## [@capire/fiori](fiori) ## [@capire/fiori](fiori)
@@ -57,11 +57,11 @@ Each sub directory essentially is a individual npm package arranged in an [all-i
- [@capire/reviews](reviews) - [@capire/reviews](reviews)
- [@capire/orders](orders) - [@capire/orders](orders)
- [@capire/common](common) - [@capire/common](common)
- [Adds a Fiori elements application](https://cap.cloud.sap/docs/guides/fiori/) to bookshop, thereby introducing to... - [Adds a SAP Fiori elements application](https://cap.cloud.sap/docs/guides/fiori/) to bookshop, thereby introducing to:
- [OData Annotations](https://cap.cloud.sap/docs/guides/fiori#adding-odata-annotations) in `.cds` files - [OData Annotations](https://cap.cloud.sap/docs/guides/fiori#adding-odata-annotations) in `.cds` files
- Support for [Fiori Draft](https://cap.cloud.sap/docs/guides/fiori#draft) - Support for [Fiori Draft](https://cap.cloud.sap/docs/guides/fiori#draft)
- Support for [Value Helps](https://cap.cloud.sap/docs/guides/fiori#value-help) - Support for [Value Helps](https://cap.cloud.sap/docs/guides/fiori#value-help)
- Serving Fiori apps locally - Serving SAP Fiori apps locally
- [The Vue.js app](bookshop/app/vue) imported from bookshop is served as well - [The Vue.js app](bookshop/app/vue) imported from bookshop is served as well

View File

@@ -1,5 +1,5 @@
const { expect } = require('../test')
const cds = require('@sap/cds/lib') const cds = require('@sap/cds/lib')
const { expect } = cds.test
const CQL = ([cql]) => cds.parse.cql(cql) const CQL = ([cql]) => cds.parse.cql(cql)
const Foo = { name: 'Foo' } const Foo = { name: 'Foo' }
const Books = { name: 'capire.bookshop.Books' } const Books = { name: 'capire.bookshop.Books' }
@@ -325,7 +325,26 @@ describe('cds.ql → cqn', () => {
}) })
// using CQL fragments -> uses cds.parse.expr // using CQL fragments -> uses cds.parse.expr
expect((cqn = CQL`SELECT from Foo where ID=11 and x in ( foo, 'bar', 3)`)).to.eql({ const is_v2 = !!cds.parse.expr('(1,2)').list
if (is_v2) expect((cqn = CQL`SELECT from Foo where ID=11 and x in ( foo, 'bar', 3)`)).to.eql({
SELECT: {
from: { ref: ['Foo'] },
where: [
{ ref: ['ID'] },
'=',
{ val: ID },
'and',
{ ref: ['x'] },
'in',
{list:[
{ ref: ['foo'] },
{ val: 'bar' },
{ val: 3 },
]}
],
},
})
else expect((cqn = CQL`SELECT from Foo where ID=11 and x in ( foo, 'bar', 3)`)).to.eql({
SELECT: { SELECT: {
from: { ref: ['Foo'] }, from: { ref: ['Foo'] },
where: [ where: [

View File

@@ -1,7 +1,7 @@
const cds = require('@sap/cds/lib') const { expect } = require('../test') .run (
const { expect } = cds.test (
'serve', 'AdminService', '--from', '@capire/bookshop,@capire/common', '--in-memory' 'serve', 'AdminService', '--from', '@capire/bookshop,@capire/common', '--in-memory'
).in(__dirname) )
const cds = require('@sap/cds/lib')
describe('Consuming Services locally', () => { describe('Consuming Services locally', () => {
// //

View File

@@ -1,5 +1,7 @@
const cds = require('@sap/cds/lib'); cds.User = cds.User.Privileged // skip auth const { GET, POST, expect } = require('../test') .run ('bookshop')
const { GET, POST, expect } = cds.test('bookshop').in(__dirname,'..') const cds = require('@sap/cds/lib')
if (cds.User.default) cds.User.default = cds.User.Privileged // hard core monkey patch
else cds.User = cds.User.Privileged // hard core monkey patch for older cds releases
describe('Custom Handlers', () => { describe('Custom Handlers', () => {

View File

@@ -1,5 +1,4 @@
const cds = require('@sap/cds/lib') const { GET, expect } = require('../test') .run ('serve','hello/world.cds')
const { GET, expect } = cds.test('serve','hello/world.cds').in(__dirname,'..')
describe('Hello world!', () => { describe('Hello world!', () => {

View File

@@ -1,6 +1,5 @@
const cwd = process.cwd(); process.chdir (__dirname) //> only for internal CI/CD@SAP const {expect} = require('../test')
const cds = require('@sap/cds/lib') const cds = require('@sap/cds/lib')
const {expect} = cds.test
// monkey patching older releases: // monkey patching older releases:
if (!cds.compile.cdl) cds.compile.cdl = cds.parse if (!cds.compile.cdl) cds.compile.cdl = cds.parse
@@ -25,8 +24,6 @@ describe('Hierarchical Data', ()=>{
expect (cds.db.model) .to.exist expect (cds.db.model) .to.exist
}) })
after(()=> process.chdir(cwd))
it ('supports deeply nested inserts', ()=> INSERT.into (Cats, it ('supports deeply nested inserts', ()=> INSERT.into (Cats,
{ ID:100, name:'Some Cats...', children:[ { ID:100, name:'Some Cats...', children:[
{ ID:101, name:'Cat', children:[ { ID:101, name:'Cat', children:[

6
test/index.js Normal file
View File

@@ -0,0 +1,6 @@
const test = require('@sap/cds/lib/utils/tests').in(__dirname,'..')
module.exports = Object.assign(test,{run:test})
// REVISIT: With upcoming release of @sap/cds this should become:
// module.exports = require('@sap/cds/tests').in(__dirname,'..')

View File

@@ -1,5 +1,7 @@
const cds = require('@sap/cds/lib'); cds.User = cds.User.Privileged // skip auth const { GET, expect } = require('../test') .run ('serve', 'test/localized-data.cds', '--in-memory')
const { GET, expect } = cds.test ('serve', __dirname+'/localized-data.cds', '--in-memory') const cds = require('@sap/cds/lib')
if (cds.User.default) cds.User.default = cds.User.Privileged // hard core monkey patch
else cds.User = cds.User.Privileged // hard core monkey patch for older cds releases
describe('Localized Data', () => { describe('Localized Data', () => {

View File

@@ -1,13 +1,11 @@
const { expect } = require('../test')
const cds = require('@sap/cds/lib') const cds = require('@sap/cds/lib')
const cwd = process.cwd(); process.chdir (__dirname) //> only for internal CI/CD@SAP
const {expect} = cds.test
const _model = '@capire/reviews' const _model = '@capire/reviews'
cds.User = cds.User.Privileged // hard core monkey patch if (cds.User.default) cds.User.default = cds.User.Privileged // hard core monkey patch
else cds.User = cds.User.Privileged // hard core monkey patch for older cds releases
describe('Messaging', ()=>{ describe('Messaging', ()=>{
after(()=> process.chdir(cwd))
it ('should bootstrap sqlite in-memory db', async()=>{ it ('should bootstrap sqlite in-memory db', async()=>{
const db = await cds.deploy (_model) .to ('sqlite::memory:') const db = await cds.deploy (_model) .to ('sqlite::memory:')
await db.delete('Reviews') await db.delete('Reviews')
@@ -44,16 +42,16 @@ describe('Messaging', ()=>{
// { ID: 111 + (++N), subject: "201", title: "Captivating", rating: N }, // { ID: 111 + (++N), subject: "201", title: "Captivating", rating: N },
// ), // ),
srv.create ('Reviews') .entries ( srv.create ('Reviews') .entries (
{ ID: 111 + (++N), subject: "201", title: "Captivating", rating: N } { ID: String(111 + (++N)), subject: "201", title: "Captivating", rating: N }
), ),
srv.create ('Reviews') .entries ( srv.create ('Reviews') .entries (
{ ID: 111 + (++N), subject: "201", title: "Captivating", rating: N } { ID: String(111 + (++N)), subject: "201", title: "Captivating", rating: N }
), ),
srv.create ('Reviews') .entries ( srv.create ('Reviews') .entries (
{ ID: 111 + (++N), subject: "201", title: "Captivating", rating: N } { ID: String(111 + (++N)), subject: "201", title: "Captivating", rating: N }
), ),
srv.create ('Reviews') .entries ( srv.create ('Reviews') .entries (
{ ID: 111 + (++N), subject: "201", title: "Captivating", rating: N } { ID: String(111 + (++N)), subject: "201", title: "Captivating", rating: N }
), ),
])) ]))

View File

@@ -1,8 +1,11 @@
const cds = require('@sap/cds/lib'); cds.User = cds.User.Privileged // skip auth const { GET, expect } = require('../test') .run ('bookshop')
const { GET, expect } = cds.test('bookshop').in(__dirname,'..') const cds = require('@sap/cds/lib')
if (cds.User.default) cds.User.default = cds.User.Privileged // hard core monkey patch
else cds.User = cds.User.Privileged // hard core monkey patch for older cds releases
describe('OData Protocol', () => { describe('OData Protocol', () => {
it('serves $metadata documents in v4', async () => { it('serves $metadata documents in v4', async () => {
const { headers, status, data } = await GET `/browse/$metadata` const { headers, status, data } = await GET `/browse/$metadata`
expect(status).to.equal(200) expect(status).to.equal(200)