Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11f3b357e4 | ||
|
|
5f89334403 | ||
|
|
e612fa97ea | ||
|
|
da2ea39466 | ||
|
|
117000df71 | ||
|
|
f3ffb69d3a | ||
|
|
f908484973 | ||
|
|
c4529f3cd7 | ||
|
|
0220400484 | ||
|
|
c1911b6e96 | ||
|
|
19083d156e | ||
|
|
48d547e6cd | ||
|
|
bae491a832 | ||
|
|
ca41a2141c | ||
|
|
08f409af73 | ||
|
|
efa60550fb | ||
|
|
f599206bf4 | ||
|
|
2f5d159428 | ||
|
|
2be3d50389 | ||
|
|
46b58f1b5c | ||
|
|
e87527cbcd | ||
|
|
091844219b | ||
|
|
de796e5a89 | ||
|
|
f988088412 | ||
|
|
c4a51ab719 | ||
|
|
f58376607a | ||
|
|
839048d87c | ||
|
|
3b3463f889 | ||
|
|
d3396304ec | ||
|
|
ae09caf7ad | ||
|
|
e1052c209b | ||
|
|
cd3aad59e1 | ||
|
|
bcbf65f95e | ||
|
|
1189374860 | ||
|
|
9f2eb8fa83 | ||
|
|
7b18e15e5b | ||
|
|
00bfc1507e | ||
|
|
47a58e7393 | ||
|
|
c04b972d27 | ||
|
|
85b9b9d3a3 | ||
|
|
3655eef971 | ||
|
|
87dd356204 | ||
|
|
a89ec34f7c | ||
|
|
444dcacb14 | ||
|
|
2011a1ca7a | ||
|
|
7e0c36ede5 | ||
|
|
e8d08d039e | ||
|
|
5e3258913e | ||
|
|
44e14926e4 | ||
|
|
592e945c28 | ||
|
|
5d5c787365 | ||
|
|
bb79def1d9 | ||
|
|
bd4a38bf54 | ||
|
|
abf18d74db | ||
|
|
f144354229 | ||
|
|
97670bbc84 | ||
|
|
82d6f54337 | ||
|
|
a4baee6e3b | ||
|
|
95b01e7d7a | ||
|
|
c2437fc419 | ||
|
|
9381459458 | ||
|
|
28a7c16895 | ||
|
|
c1141e6c87 | ||
|
|
6e686c6c8b | ||
|
|
1ccddb2155 | ||
|
|
7c8e52d5e9 | ||
|
|
0dc1dc198d | ||
|
|
20bfb5c5f7 | ||
|
|
be87f5617a | ||
|
|
3117df1282 | ||
|
|
be685437aa | ||
|
|
ff3801be71 | ||
|
|
702c3245bd | ||
|
|
14002300c5 | ||
|
|
ad417ec061 | ||
|
|
a6ec296129 | ||
|
|
1b10bbbfe4 | ||
|
|
aaa1b2d6c7 | ||
|
|
1cb169e886 | ||
|
|
9b9bb4c114 | ||
|
|
2536f36596 | ||
|
|
5e829ae7bb | ||
|
|
d265a385f8 | ||
|
|
80f469b5b6 | ||
|
|
8e8ae949df | ||
|
|
3d24dc491d | ||
|
|
f593265687 | ||
|
|
6d488b042c | ||
|
|
d5ef630743 | ||
|
|
b47c9d75df |
6
.github/workflows/node.js.yml
vendored
6
.github/workflows/node.js.yml
vendored
@@ -5,9 +5,9 @@ name: CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ main ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ main ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -24,5 +24,5 @@ jobs:
|
|||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node-version }}
|
node-version: ${{ matrix.node-version }}
|
||||||
- run: npm install
|
- run: npm ci
|
||||||
- run: npm test
|
- run: npm test
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -15,3 +15,5 @@ default-env.json
|
|||||||
packages/messageBox
|
packages/messageBox
|
||||||
reviews/msg-box
|
reviews/msg-box
|
||||||
reviews/db/test.db
|
reviews/db/test.db
|
||||||
|
|
||||||
|
*.openapi3.json
|
||||||
|
|||||||
3
.npmrc
Normal file
3
.npmrc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Ensure we always use public packages, i.e. avoid using local registries from ~/.npmrc
|
||||||
|
@sap:registry=https://registry.npmjs.org/
|
||||||
|
registry=https://registry.npmjs.org/
|
||||||
@@ -5,7 +5,7 @@ const app = express()
|
|||||||
|
|
||||||
const { PORT=4444 } = process.env
|
const { PORT=4444 } = process.env
|
||||||
const [,,port=PORT] = process.argv
|
const [,,port=PORT] = process.argv
|
||||||
process.chdir(__dirname)
|
const cwd = __dirname
|
||||||
|
|
||||||
app.use('/-/:tarball', (req,res,next) => {
|
app.use('/-/:tarball', (req,res,next) => {
|
||||||
console.debug ('GET', req.params)
|
console.debug ('GET', req.params)
|
||||||
@@ -13,7 +13,7 @@ app.use('/-/:tarball', (req,res,next) => {
|
|||||||
const { tarball } = req.params
|
const { tarball } = req.params
|
||||||
const [, pkg ] = /^capire-(\w+)/.exec(tarball)
|
const [, pkg ] = /^capire-(\w+)/.exec(tarball)
|
||||||
fs.lstat(tarball,(err => {
|
fs.lstat(tarball,(err => {
|
||||||
if (err) exec(`npm pack ../${pkg}`,next)
|
if (err) exec(`npm pack ../${pkg}`,{cwd},next)
|
||||||
else next()
|
else next()
|
||||||
}))
|
}))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -105,5 +105,5 @@
|
|||||||
"description": "### Summary\n\nThat's it! You have seen: \n- How to integrate database-specific functions in a CDS model.\n- How to switch between the two implementations for SQLite and SAP HANA."
|
"description": "### Summary\n\nThat's it! You have seen: \n- How to integrate database-specific functions in a CDS model.\n- How to switch between the two implementations for SQLite and SAP HANA."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ref": "master"
|
"ref": "main"
|
||||||
}
|
}
|
||||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -13,5 +13,5 @@
|
|||||||
"**/cds/lib/req/cls.js",
|
"**/cds/lib/req/cls.js",
|
||||||
"**/odata-v4/okra/**"
|
"**/odata-v4/okra/**"
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Find here a collection of samples for the [SAP Cloud Application Programming Mod
|
|||||||
|
|
||||||
### Download
|
### Download
|
||||||
|
|
||||||
If you've [Git](https://git-scm.com/downloads) installed, clone this repo as shown below, otherwise [download as ZIP file](archive/master.zip).
|
If you've [Git](https://git-scm.com/downloads) installed, clone this repo as shown below, otherwise [download as ZIP file](archive/main.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
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const books = new Vue ({
|
|||||||
data: {
|
data: {
|
||||||
list: [],
|
list: [],
|
||||||
book: undefined,
|
book: undefined,
|
||||||
order: { amount:1, succeeded:'', failed:'' }
|
order: { quantity:1, succeeded:'', failed:'' }
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -26,18 +26,18 @@ const books = new Vue ({
|
|||||||
const book = books.book = books.list [eve.currentTarget.rowIndex-1]
|
const book = books.book = books.list [eve.currentTarget.rowIndex-1]
|
||||||
const res = await GET(`/Books/${book.ID}?$select=descr,stock,image`)
|
const res = await GET(`/Books/${book.ID}?$select=descr,stock,image`)
|
||||||
Object.assign (book, res.data)
|
Object.assign (book, res.data)
|
||||||
books.order = { amount:1 }
|
books.order = { quantity:1 }
|
||||||
setTimeout (()=> $('form > input').focus(), 111)
|
setTimeout (()=> $('form > input').focus(), 111)
|
||||||
},
|
},
|
||||||
|
|
||||||
async submitOrder () {
|
async submitOrder () {
|
||||||
const {book,order} = books, amount = parseInt (order.amount) || 1 // REVISIT: Okra should be less strict
|
const {book,order} = books, quantity = parseInt (order.quantity) || 1 // REVISIT: Okra should be less strict
|
||||||
try {
|
try {
|
||||||
const res = await POST(`/submitOrder`, { amount, book: book.ID })
|
const res = await POST(`/submitOrder`, { quantity, book: book.ID })
|
||||||
book.stock = res.data.stock
|
book.stock = res.data.stock
|
||||||
books.order = { amount, succeeded: `Successfully orderd ${amount} item(s).` }
|
books.order = { quantity, succeeded: `Successfully ordered ${quantity} item(s).` }
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
books.order = { amount, failed: e.response.data.error.message }
|
books.order = { quantity, failed: e.response.data.error.message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
{{ book.stock }} in stock
|
{{ book.stock }} in stock
|
||||||
</label>
|
</label>
|
||||||
<form @submit.prevent="submitOrder" style="float:right; display:flex; flex-direction:row-reverse">
|
<form @submit.prevent="submitOrder" style="float:right; display:flex; flex-direction:row-reverse">
|
||||||
<input type="number" v-model="order.amount" v-bind:class="{ failed: order.failed }" style="width:5em">
|
<input type="number" v-model="order.quantity" v-bind:class="{ failed: order.failed }" style="width:5em">
|
||||||
<input type="submit" value="Order:" class="muted-button">
|
<input type="submit" value="Order:" class="muted-button">
|
||||||
</form>
|
</form>
|
||||||
<h4> {{ book.title }} </h4>
|
<h4> {{ book.title }} </h4>
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ ID;title;descr;author_ID;stock;price;currency_code;genre_ID
|
|||||||
207;Jane Eyre;"Jane Eyre /ɛər/ (originally published as Jane Eyre: An Autobiography) is a novel by English writer Charlotte Brontë, published under the pen name ""Currer Bell"", on 16 October 1847, by Smith, Elder & Co. of London. The first American edition was published the following year by Harper & Brothers of New York. Primarily a bildungsroman, Jane Eyre follows the experiences of its eponymous heroine, including her growth to adulthood and her love for Mr. Rochester, the brooding master of Thornfield Hall. The novel revolutionised prose fiction in that the focus on Jane's moral and spiritual development is told through an intimate, first-person narrative, where actions and events are coloured by a psychological intensity. The book contains elements of social criticism, with a strong sense of Christian morality at its core and is considered by many to be ahead of its time because of Jane's individualistic character and how the novel approaches the topics of class, sexuality, religion and feminism.";107;11;12.34;GBP;11
|
207;Jane Eyre;"Jane Eyre /ɛər/ (originally published as Jane Eyre: An Autobiography) is a novel by English writer Charlotte Brontë, published under the pen name ""Currer Bell"", on 16 October 1847, by Smith, Elder & Co. of London. The first American edition was published the following year by Harper & Brothers of New York. Primarily a bildungsroman, Jane Eyre follows the experiences of its eponymous heroine, including her growth to adulthood and her love for Mr. Rochester, the brooding master of Thornfield Hall. The novel revolutionised prose fiction in that the focus on Jane's moral and spiritual development is told through an intimate, first-person narrative, where actions and events are coloured by a psychological intensity. The book contains elements of social criticism, with a strong sense of Christian morality at its core and is considered by many to be ahead of its time because of Jane's individualistic character and how the novel approaches the topics of class, sexuality, religion and feminism.";107;11;12.34;GBP;11
|
||||||
251;The Raven;"""The Raven"" is a narrative poem by American writer Edgar Allan Poe. First published in January 1845, the poem is often noted for its musicality, stylized language, and supernatural atmosphere. It tells of a talking raven's mysterious visit to a distraught lover, tracing the man's slow fall into madness. The lover, often identified as being a student, is lamenting the loss of his love, Lenore. Sitting on a bust of Pallas, the raven seems to further distress the protagonist with its constant repetition of the word ""Nevermore"". The poem makes use of folk, mythological, religious, and classical references.";150;333;13.13;USD;16
|
251;The Raven;"""The Raven"" is a narrative poem by American writer Edgar Allan Poe. First published in January 1845, the poem is often noted for its musicality, stylized language, and supernatural atmosphere. It tells of a talking raven's mysterious visit to a distraught lover, tracing the man's slow fall into madness. The lover, often identified as being a student, is lamenting the loss of his love, Lenore. Sitting on a bust of Pallas, the raven seems to further distress the protagonist with its constant repetition of the word ""Nevermore"". The poem makes use of folk, mythological, religious, and classical references.";150;333;13.13;USD;16
|
||||||
252;Eleonora;"""Eleonora"" is a short story by Edgar Allan Poe, first published in 1842 in Philadelphia in the literary annual The Gift. It is often regarded as somewhat autobiographical and has a relatively ""happy"" ending.";150;555;14;USD;16
|
252;Eleonora;"""Eleonora"" is a short story by Edgar Allan Poe, first published in 1842 in Philadelphia in the literary annual The Gift. It is often regarded as somewhat autobiographical and has a relatively ""happy"" ending.";150;555;14;USD;16
|
||||||
271;Catweazle;Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts.;170;22;15;EUR;13
|
271;Catweazle;Catweazle is a British fantasy television series, starring Geoffrey Bayldon in the title role, and created by Richard Carpenter for London Weekend Television. The first series, produced and directed by Quentin Lawrence, was screened in the UK on ITV in 1970. The second series, directed by David Reid and David Lane, was shown in 1971. Each series had thirteen episodes, most but not all written by Carpenter, who also published two books based on the scripts.;170;22;150;JPY;13
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using { Currency, managed, temporal, sap } from '@sap/cds/common';
|
using { Currency, managed, sap } from '@sap/cds/common';
|
||||||
namespace sap.capire.bookshop;
|
namespace sap.capire.bookshop;
|
||||||
|
|
||||||
entity Books : managed {
|
entity Books : managed {
|
||||||
|
|||||||
@@ -1,27 +1,5 @@
|
|||||||
using { sap.capire.bookshop as my } from '../db/schema';
|
using { sap.capire.bookshop as my } from '../db/schema';
|
||||||
service AdminService @(requires:'admin') {
|
service AdminService @(requires:'admin') {
|
||||||
|
entity Books as projection on my.Books;
|
||||||
entity Books as SELECT from my.Books { *,
|
|
||||||
// key ID, key validFrom
|
|
||||||
};
|
|
||||||
entity Authors as projection on my.Authors;
|
entity Authors as projection on my.Authors;
|
||||||
|
|
||||||
// @cds.redirection.target:false
|
|
||||||
// entity Books.history @(cds.temporal:false) as projection on Books {
|
|
||||||
// *,
|
|
||||||
// key ID,
|
|
||||||
// key validFrom @(cds.valid.from:false),
|
|
||||||
// validTo @(cds.valid.to:false),
|
|
||||||
// };
|
|
||||||
}
|
|
||||||
|
|
||||||
// entity NonTemporalBook as projection on my.Books {
|
|
||||||
// *,
|
|
||||||
// key ID,
|
|
||||||
// key validFrom @(cds.valid.from:false),
|
|
||||||
// validTo @(cds.valid.to:false),
|
|
||||||
// };
|
|
||||||
|
|
||||||
extend my.Books with {
|
|
||||||
history : Composition of many my.Books on history.ID = $self.ID;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
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 { *,
|
/** For displaying lists of Books */
|
||||||
|
@readonly entity ListOfBooks as projection on Books
|
||||||
|
excluding { descr };
|
||||||
|
|
||||||
|
/** For display in details pages */
|
||||||
|
@readonly entity Books as projection on my.Books { *,
|
||||||
author.name as author
|
author.name as author
|
||||||
} excluding { createdBy, modifiedBy };
|
} excluding { createdBy, modifiedBy };
|
||||||
|
|
||||||
@readonly entity ListOfBooks as SELECT from Books
|
|
||||||
excluding { descr };
|
|
||||||
|
|
||||||
@requires: 'authenticated-user'
|
@requires: 'authenticated-user'
|
||||||
action submitOrder ( book: Books:ID, amount: Integer ) returns { stock: Integer };
|
action submitOrder ( book: Books:ID, quantity: Integer ) returns { stock: Integer };
|
||||||
event OrderedBook : { book: Books:ID; amount: Integer; buyer: String };
|
event OrderedBook : { book: Books:ID; quantity: Integer; buyer: String };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ 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 => {
|
||||||
const {book,amount} = req.data
|
const {book,quantity} = req.data
|
||||||
let {stock} = await SELECT `stock` .from (Books,book)
|
let {stock} = await SELECT `stock` .from (Books,book)
|
||||||
if (stock >= amount) {
|
if (stock >= quantity) {
|
||||||
await UPDATE (Books,book) .with (`stock -=`, amount)
|
await UPDATE (Books,book) .with (`stock -=`, quantity)
|
||||||
await this.emit ('OrderedBook', { book, amount, buyer:req.user.id })
|
await this.emit ('OrderedBook', { book, quantity, buyer:req.user.id })
|
||||||
return { stock }
|
return { stock }
|
||||||
}
|
}
|
||||||
else return req.error (409,`${amount} exceeds stock for book #${book}`)
|
else return req.error (409,`${quantity} exceeds stock for book #${book}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Add some discount for overstocked books
|
// Add some discount for overstocked books
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ POST {{server}}/browse/submitOrder
|
|||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
{{me}}
|
{{me}}
|
||||||
|
|
||||||
{ "book":201, "amount":5 }
|
{ "book":201, "quantity":5 }
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
### ------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ CAD;de;Kanadischer Dollar;Kanadischer Dollar
|
|||||||
AUD;de;Australischer Dollar;Australischer Dollar
|
AUD;de;Australischer Dollar;Australischer Dollar
|
||||||
GBP;de;Pfund;Britische Pfund
|
GBP;de;Pfund;Britische Pfund
|
||||||
ILS;de;Schekel;Israelische Schekel
|
ILS;de;Schekel;Israelische Schekel
|
||||||
|
JPY;de;Yen;Japanische Yen
|
||||||
EUR;fr;euro;de la Zone euro
|
EUR;fr;euro;de la Zone euro
|
||||||
USD;fr;dollar;dollar des États-Unis
|
USD;fr;dollar;dollar des États-Unis
|
||||||
CAD;fr;dollar canadien;dollar canadien
|
CAD;fr;dollar canadien;dollar canadien
|
||||||
AUD;fr;dollar australien;dollar australien
|
AUD;fr;dollar australien;dollar australien
|
||||||
GBP;fr;livre sterling;pound sterling
|
GBP;fr;livre sterling;pound sterling
|
||||||
ILS;fr;Shekel;shekel israelien
|
ILS;fr;Shekel;shekel israelien
|
||||||
|
JPY;fr;Yen;Yen japonais
|
||||||
|
500 Internal Server Error
Gitea Version: 1.24.4 |