Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
835f450686 | ||
|
|
0a552b4346 | ||
|
|
6367081e9d | ||
|
|
3e73683d99 | ||
|
|
2b345ca447 | ||
|
|
20593f2fa2 | ||
|
|
ca45aa1cf7 | ||
|
|
e408836c2a | ||
|
|
3000a9e2df | ||
|
|
b83236de2a | ||
|
|
46b3b8aaec | ||
|
|
59f5c82684 |
3
.env
3
.env
@@ -1,2 +1 @@
|
|||||||
cds.features.snapi = y
|
cds.features.snapi = y
|
||||||
cds.cdsc.beta.aspectCompositions = true
|
|
||||||
28
.github/workflows/node.js.yml
vendored
Normal file
28
.github/workflows/node.js.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
|
||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||||
|
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [10.x, 12.16.2]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
- run: npm install
|
||||||
|
- run: npm test
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Find here a collection of samples for the [SAP Cloud Application Programming Model](https://cap.cloud.sap) organized in a simplistic [monorepo setup](samples.md#all-in-one-monorepo). → See [**Overview** of contained samples](samples.md)
|
Find here a collection of samples for the [SAP Cloud Application Programming Model](https://cap.cloud.sap) organized in a simplistic [monorepo setup](samples.md#all-in-one-monorepo). → See [**Overview** of contained samples](samples.md)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### Preliminaries
|
### Preliminaries
|
||||||
|
|
||||||
@@ -39,19 +40,19 @@ After that open this link in your browser: [http://localhost:4004](http://localh
|
|||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
Run the provided tests with [_jest_](http://jestjs.io) or [_mocha_](http://mochajs.org), e.g.:
|
Run the provided tests with [_jest_](http://jestjs.io) or [_mocha_](http://mochajs.org), for example:
|
||||||
```sh
|
```sh
|
||||||
npx jest
|
npx jest
|
||||||
```
|
```
|
||||||
> While mocha is a bit smaller and faster, jest runs tests in parallel and isolation which allows to run all tests.
|
> While mocha is a bit smaller and faster, jest runs tests in parallel and isolation, which allows to run all tests.
|
||||||
|
|
||||||
|
|
||||||
## Get Support
|
## Get Support
|
||||||
|
|
||||||
Check out the cap docs at [https://cap.cloud.sap](https://cap.cloud.sap). <br>
|
Check out the documentation at [https://cap.cloud.sap](https://cap.cloud.sap). <br>
|
||||||
In case you find a bug or need support, please [open an issue in here](https://github.com/SAP-samples/cloud-cap-samples/issues/new).
|
In case you find a bug or need support, please [open an issue in here](https://github.com/SAP-samples/cloud-cap-samples/issues/new).
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (c) 2019 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](/LICENSE) file.
|
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](/LICENSE) file.
|
||||||
|
|||||||
24
ext/.eslintrc
Normal file
24
ext/.eslintrc
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"es6": true,
|
||||||
|
"jest": true
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2017
|
||||||
|
},
|
||||||
|
"globals": {
|
||||||
|
"SELECT": true,
|
||||||
|
"INSERT": true,
|
||||||
|
"UPDATE": true,
|
||||||
|
"DELETE": true,
|
||||||
|
"CREATE": true,
|
||||||
|
"DROP": true,
|
||||||
|
"cds": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"no-console": "off",
|
||||||
|
"require-atomic-updates": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
30
ext/.gitignore
vendored
Normal file
30
ext/.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# CAP ext
|
||||||
|
_out
|
||||||
|
*.db
|
||||||
|
connection.properties
|
||||||
|
default-*.json
|
||||||
|
gen/
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Web IDE, App Studio
|
||||||
|
.che/
|
||||||
|
.gen/
|
||||||
|
|
||||||
|
# MTA
|
||||||
|
*_mta_build_tmp
|
||||||
|
*.mtar
|
||||||
|
mta_archives/
|
||||||
|
|
||||||
|
# Other
|
||||||
|
.DS_Store
|
||||||
|
*.orig
|
||||||
|
*.log
|
||||||
|
|
||||||
|
*.iml
|
||||||
|
*.flattened-pom.xml
|
||||||
|
|
||||||
|
# IDEs
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
6
ext/db/schema.cds
Normal file
6
ext/db/schema.cds
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
using { sap.capire.bookshop.Books } from '@capire/bookshop';
|
||||||
|
|
||||||
|
extend Books with {
|
||||||
|
ISBN : String;
|
||||||
|
discount : Decimal @assert.range:[0,1];
|
||||||
|
}
|
||||||
19
ext/package.json
Normal file
19
ext/package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "ext",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "A simple CAP project.",
|
||||||
|
"repository": "<Add your repository here>",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@capire/bookshop": "../bookshop",
|
||||||
|
"@sap/cds": "^4",
|
||||||
|
"express": "^4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"sqlite3": "^4"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "npx cds run"
|
||||||
|
}
|
||||||
|
}
|
||||||
40
ext/server.js
Normal file
40
ext/server.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
const cds = require ('@sap/cds')
|
||||||
|
const path = require ('path')
|
||||||
|
const fs = require ('fs')
|
||||||
|
const protected = {db:1,messaging:1,auth:1}
|
||||||
|
const { isfile } = cds.utils
|
||||||
|
|
||||||
|
cds.on('served', ()=>{
|
||||||
|
for (let each of cds.services) {
|
||||||
|
if (each.name in protected) continue
|
||||||
|
// search for local srv/<each>.js files and if exist
|
||||||
|
// activate them in a service extension sandbox
|
||||||
|
const impl = isfile (path.resolve('srv/'+each.name+'.js'))
|
||||||
|
if (impl) activate_sandboxed (each,impl)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function activate_sandboxed (srv,impl) {
|
||||||
|
console.log (`[cds] - extending ${srv.name} with sandboxed:`, {impl:path.relative(process.cwd(),impl)})
|
||||||
|
const src = fs.readFileSync (impl)
|
||||||
|
const sandbox = Object.keys(global).filter(name => name !== 'cds')
|
||||||
|
const fn = new Function (
|
||||||
|
'module','cds','global','process', ...sandbox,
|
||||||
|
src
|
||||||
|
)
|
||||||
|
// restricted sandboxed variant of 'module' and 'cds'
|
||||||
|
const module = {}
|
||||||
|
const cds = {
|
||||||
|
service: {
|
||||||
|
impl: fn=>fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn (module,cds,undefined,undefined, ...sandbox.map((()=>(undefined))))
|
||||||
|
if (typeof module.exports === 'function') try {
|
||||||
|
module.exports.call (srv,srv)
|
||||||
|
} catch (e) {
|
||||||
|
console.log (e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = cds.server
|
||||||
10
ext/srv/AdminService.js
Normal file
10
ext/srv/AdminService.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
module.exports = cds.service.impl(function(){
|
||||||
|
|
||||||
|
this.before(['CREATE','UPDATE'],'Books', req => { //> ....
|
||||||
|
const book = req.data
|
||||||
|
if (book.stock < 10 && book.discount > 0.5) {
|
||||||
|
req.error('Hey, da sind so wenig übrig, die wollen wir nicht zu billig verticken')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
9
ext/srv/CatalogService.js
Normal file
9
ext/srv/CatalogService.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
console.log ('Böses Zeug', global, process, cds)
|
||||||
|
// process.exit()
|
||||||
|
// const fs = require('fs')
|
||||||
|
// cds.run('Böses Zeugs')
|
||||||
|
// SELECT.from ('Foo')
|
||||||
|
|
||||||
|
module.exports = cds.service.impl(function(){
|
||||||
|
this.after('READ','Books', each => each.title += ' (served through sandbox)')
|
||||||
|
})
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
ID;amount;parent_ID;book_ID
|
ID;amount;parent_ID;book_ID;netAmount
|
||||||
58040e66-1dcd-4ffb-ab10-fdce32028b79;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;201
|
58040e66-1dcd-4ffb-ab10-fdce32028b79;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;201;11.11
|
||||||
64e718c9-ff99-47f1-8ca3-950c850777d4;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;271
|
64e718c9-ff99-47f1-8ca3-950c850777d4;1;7e2f2640-6866-4dcf-8f4d-3027aa831cad;271;15
|
||||||
e9641166-e050-4261-bfee-d1e797e6cb7f;2;64e718c9-ff99-47f1-8ca3-950c850777d4;252
|
e9641166-e050-4261-bfee-d1e797e6cb7f;2;64e718c9-ff99-47f1-8ca3-950c850777d4;252;28
|
||||||
|
@@ -4,10 +4,13 @@ namespace sap.capire.bookshop;
|
|||||||
|
|
||||||
entity Orders : cuid, managed {
|
entity Orders : cuid, managed {
|
||||||
OrderNo : String @title:'Order Number'; //> readable key
|
OrderNo : String @title:'Order Number'; //> readable key
|
||||||
Items : Composition of many {
|
Items : Composition of many OrderItems on Items.parent = $self;
|
||||||
key pos : Integer;
|
|
||||||
book : Association to Books;
|
|
||||||
amount : Integer;
|
|
||||||
};
|
|
||||||
currency : Currency;
|
currency : Currency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entity OrderItems : cuid {
|
||||||
|
parent : Association to Orders;
|
||||||
|
book : Association to Books;
|
||||||
|
amount : Integer;
|
||||||
|
netAmount : Decimal(9,2);
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ cds.once('served', async()=>{
|
|||||||
|
|
||||||
// Other bootstrapping events you could hook in to...
|
// Other bootstrapping events you could hook in to...
|
||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
||||||
cds.on('boostrap',(app) => {/* ... */})
|
cds.on('bootstrap',(app) => {/* ... */})
|
||||||
cds.on('loaded', (model) => {/* ... */})
|
cds.on('loaded', (model) => {/* ... */})
|
||||||
cds.on('connect', (srv) => {/* ... */})
|
cds.on('connect', (srv) => {/* ... */})
|
||||||
cds.on('serving', (srv) => {/* ... */})
|
cds.on('serving', (srv) => {/* ... */})
|
||||||
|
|||||||
@@ -359,6 +359,11 @@ describe('cds.ql → cqn', () => {
|
|||||||
CQL`SELECT from Foo where x in (SELECT y from Bar)`
|
CQL`SELECT from Foo where x in (SELECT y from Bar)`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// using query api
|
||||||
|
expect(SELECT.from('Books').where(
|
||||||
|
`author.name in`, SELECT('name').from('Authors'))).to.eql(CQL`SELECT from Books where author.name in (SELECT name from Authors)`
|
||||||
|
)
|
||||||
|
|
||||||
// in classical semi joins
|
// in classical semi joins
|
||||||
expect(
|
expect(
|
||||||
SELECT('x').from(Foo) .where ( `exists`,
|
SELECT('x').from(Foo) .where ( `exists`,
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ describe('Localized Data', () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('supports @cds.localized:false', async ()=>{
|
xit('supports @cds.localized:false', async ()=>{
|
||||||
const { data } = await GET(`/browse/BooksSans?&$select=title,localized_title&$expand=currency&$filter=locale eq 'de' or locale eq null`, {
|
const { data } = await GET(`/browse/BooksSans?&$select=title,localized_title&$expand=currency&$filter=locale eq 'de' or locale eq null`, {
|
||||||
headers: { 'Accept-Language': 'de' },
|
headers: { 'Accept-Language': 'de' },
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user