From c6eb21ec5127db4e99da5489b4a2b1bbf494deb8 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 2 Mar 2020 08:29:49 +0100 Subject: [PATCH] cleaned up --- .eslintrc | 2 +- .vscode/tasks.json | 17 -------- README.md | 4 +- bookshop/db/schema.cds | 16 +------- bookshop/package.json | 13 ++---- bookshop/srv/admin-service.cds | 1 - bookshop/srv/cat-service.cds | 5 +-- bookshop/srv/cat-service.js | 41 +++++++++---------- bookshop/tests/genres.test.js | 6 +-- bookshop/tests/requests.http | 38 +++++++++++++---- events/package.json | 3 ++ fiori/app/fiori.html | 2 +- fiori/app/orders/fiori-service.cds | 14 ++++--- fiori/app/orders/webapp/manifest.json | 10 ++--- fiori/package.json | 10 +---- fiori/srv/admin-service.cds | 2 - .../data/sap.capire.bookshop-OrderItems.csv | 0 .../db/data/sap.capire.bookshop-Orders.csv | 0 orders/db/schema.cds | 17 ++++++++ orders/package.json | 5 +++ orders/srv/orders-service.cds | 5 +++ orders/srv/orders-service.js | 21 ++++++++++ package.json | 18 ++++---- reviews/.env | 1 - reviews/db/schema.cds | 2 +- reviews/package.json | 9 ++-- 26 files changed, 140 insertions(+), 122 deletions(-) delete mode 100644 .vscode/tasks.json rename {bookshop => orders}/db/data/sap.capire.bookshop-OrderItems.csv (100%) rename {bookshop => orders}/db/data/sap.capire.bookshop-Orders.csv (100%) create mode 100644 orders/db/schema.cds create mode 100644 orders/package.json create mode 100644 orders/srv/orders-service.cds create mode 100644 orders/srv/orders-service.js delete mode 100644 reviews/.env diff --git a/.eslintrc b/.eslintrc index 7e6f79e2..052d4616 100644 --- a/.eslintrc +++ b/.eslintrc @@ -21,4 +21,4 @@ "no-console": "off", "require-atomic-updates": "off" } -} \ No newline at end of file +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index c507ca84..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "type": "npm", "script": "watch", "path": "packages/bookshop/", - "options": { "env": { "PORT": "4004" }}, - "presentation": { "group": "A" } - }, - { - "type": "npm", "script": "watch", "path": "packages/reviews-service/", - "options": { "env": { "PORT": "5005" }}, - "presentation": { "group": "A" } - } - ] -} \ No newline at end of file diff --git a/README.md b/README.md index f72bd32f..e883a04d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Clone this repo as shown below, if you have [git](https://git-scm.com/downloads) otherwise [download as zip file](archive/master.zip). ```sh -git clone https://github.com/sap-samples/cap samples +git clone https://github.com/sap-samples/cloud-cap-samples samples cd samples ``` @@ -29,7 +29,7 @@ npm install With that you're ready to run the samples, for example: ```sh npm run bookshop # or... -npm run bookshop-fiori +cd bookshop; cds watch ``` After that open this link in your browser: diff --git a/bookshop/db/schema.cds b/bookshop/db/schema.cds index bb428f1d..23f00497 100644 --- a/bookshop/db/schema.cds +++ b/bookshop/db/schema.cds @@ -1,5 +1,6 @@ namespace sap.capire.bookshop; -using { Currency, managed, cuid, sap } from '@sap/cds/common'; +// using { Currency, managed, sap } from '@sap/cds/common'; +using { Currency, managed, sap } from '@capire/common'; entity Books : managed { key ID : Integer; @@ -27,16 +28,3 @@ entity Genres : sap.common.CodeList { parent : Association to Genres; children : Composition of many Genres on children.parent = $self; } - -entity Orders : cuid, managed { - OrderNo : String @title:'Order Number'; //> readable key - Items : Composition of many OrderItems on Items.parent = $self; - total : Decimal(9,2) @readonly; - currency : Currency; -} -entity OrderItems : cuid { - parent : Association to Orders; - book : Association to Books; - amount : Integer; - netAmount : Decimal(9,2); -} diff --git a/bookshop/package.json b/bookshop/package.json index 62543c2a..1e0a334d 100644 --- a/bookshop/package.json +++ b/bookshop/package.json @@ -2,20 +2,13 @@ "name": "@capire/bookshop", "version": "1.0.0", "description": "A simple bookshop application, build in a self-contained all-in-one fashion, i.e. w/o reusing other packages.", - "license": "SAP SAMPLE CODE LICENSE", "dependencies": { "@capire/common": "*" }, "scripts": { + "test:genres": "cds serve tests/genres.cds --in-memory", "start": "cds run --in-memory?", - "watch": "cds watch", - "test:genres": "cds serve tests/genres.cds --in-memory" + "watch": "cds watch" }, - "cds": { - "requires": { - "db": { - "kind": "sql" - } - } - } + "license": "SAP SAMPLE CODE LICENSE" } \ No newline at end of file diff --git a/bookshop/srv/admin-service.cds b/bookshop/srv/admin-service.cds index 10c0fef1..8bfc1371 100644 --- a/bookshop/srv/admin-service.cds +++ b/bookshop/srv/admin-service.cds @@ -3,5 +3,4 @@ using { sap.capire.bookshop as my } from '../db/schema'; service AdminService @(_requires:'authenticated-user') { entity Books as projection on my.Books; entity Authors as projection on my.Authors; - entity Orders as select from my.Orders; } diff --git a/bookshop/srv/cat-service.cds b/bookshop/srv/cat-service.cds index efe7b5d9..4654c158 100644 --- a/bookshop/srv/cat-service.cds +++ b/bookshop/srv/cat-service.cds @@ -1,13 +1,12 @@ using { sap.capire.bookshop as my } from '../db/schema'; -@path:'/browse' -service CatalogService { +service CatalogService @(path:'/browse') { @readonly entity Books as SELECT from my.Books {*, author.name as author } excluding { createdBy, modifiedBy }; @requires_: 'authenticated-user' - @insertonly entity Orders as projection on my.Orders; + action order (book : Books.ID, amount: Integer); } diff --git a/bookshop/srv/cat-service.js b/bookshop/srv/cat-service.js index 8ee056a7..25819333 100644 --- a/bookshop/srv/cat-service.js +++ b/bookshop/srv/cat-service.js @@ -1,26 +1,23 @@ const cds = require('@sap/cds') -const { Books } = cds.entities /** Service implementation for CatalogService */ -module.exports = cds.service.impl(function() { - this.after ('READ', 'Books', each => each.stock > 111 && _addDiscount2(each,11)) - this.before ('CREATE', 'Orders', _reduceStock) +module.exports = cds.service.impl (function() { + + // Get entity definitions from reflected model + const { Books } = cds.entities + + // Add some discount for overstocked books + this.after ('READ', 'Books', each => { + if (each.stock > 111) each.title += ` -- 11% discount!` + }) + + // Reduce stock of ordered books if available stock suffices + this.on ('order', async (req) => { + const {UPDATE} = cds.ql(req), {book,amount} = req.data + const n = await UPDATE (Books, book) + .where ('stock >=', amount) + .set ('stock -=', amount) + n > 0 || req.error (409,`${amount} exceeds stock for book #${book}`) + }) + }) - -/** Add some discount for overstocked books */ -function _addDiscount2 (each,discount) { - each.title += ` -- ${discount}% discount!` -} - -/** Reduce stock of ordered books if available stock suffices */ -async function _reduceStock (req) { - const { Items: OrderItems } = req.data - return cds.transaction(req) .run (()=> OrderItems.map (order => - UPDATE (Books) .set ('stock -=', order.amount) - .where ('ID =', order.book_ID) .and ('stock >=', order.amount) - )) .then (all => all.forEach ((affectedRows,i) => { - if (affectedRows === 0) req.error (409, - `${OrderItems[i].amount} exceeds stock for book #${OrderItems[i].book_ID}` - ) - })) -} \ No newline at end of file diff --git a/bookshop/tests/genres.test.js b/bookshop/tests/genres.test.js index c4d295f3..a3030f57 100644 --- a/bookshop/tests/genres.test.js +++ b/bookshop/tests/genres.test.js @@ -1,5 +1,5 @@ const cds = require ('@sap/cds') -const { expect } = require('chai').use (require('chai-deep-match')) +const { expect } = require('chai') .use (require('chai-subset')) describe('reading/writing hierarchies', ()=>{ @@ -35,7 +35,7 @@ describe('reading/writing hierarchies', ()=>{ }) }) .where ({name:'Cat'}) - ) .to.deep.match ( + ) .to.containSubset ( { ID:101, parent:'Cat', children:[ { child:'Kitty' }, @@ -53,7 +53,7 @@ describe('reading/writing hierarchies', ()=>{ c.ID, c.name, c.children (c=>{ c.name },{levels:3}) }) .where ({name:'Cat'}) - ) .to.deep.match ( + ) .to.containSubset ( { ID:101, name:'Cat', children:[ { name:'Kitty', children:[ diff --git a/bookshop/tests/requests.http b/bookshop/tests/requests.http index 0d50023e..14416fbd 100644 --- a/bookshop/tests/requests.http +++ b/bookshop/tests/requests.http @@ -1,18 +1,40 @@ -### Service Document GET http://localhost:4004/browse +### -### Service $metadata document GET http://localhost:4004/browse/$metadata +### + -### Browsing Books GET http://localhost:4004/browse/Books? -# &$select=title,author -# &$expand=currency +&$select=title,stock +&$expand=currency +#> add @capire/common to see data for currencies # &sap-language=de +### + -### Browsing Authors GET http://localhost:4004/admin/Authors? # &$select=name,dateOfBirth,placeOfBirth -# &$expand=books($select=title;$expand=currency) +&$expand=books($select=title;$expand=currency) +#> add @capire/common to see data for currencies # &$filter=ID eq 101 -# &sap-language=de +&sap-language=de +### + + +POST http://localhost:4004/browse/order +# Run that three times to get out-of-stock message +Content-Type: application/json + +{ "book":201, "amount":5 } +### + + + +GET http://localhost:4004/browse/Genres? +### + +GET http://localhost:4004/browse/Genres? +&$filter=parent_ID eq null&$select=name +&$expand=children($select=name) +### diff --git a/events/package.json b/events/package.json index 898be68e..55c4f202 100644 --- a/events/package.json +++ b/events/package.json @@ -5,6 +5,9 @@ "@capire/bookshop": "*", "@capire/reviews": "*" }, + "scripts": { + "watch": "cds watch" + }, "cds": { "requires": { "db": { diff --git a/fiori/app/fiori.html b/fiori/app/fiori.html index 2fc2a0d4..26182c12 100644 --- a/fiori/app/fiori.html +++ b/fiori/app/fiori.html @@ -28,7 +28,7 @@ navigationMode: "embedded" }, "manage-orders": { - title: "Manage Orders", + title: "Order Books", description: "... testing FE v42", additionalInformation: "SAPUI5.Component=orders", applicationType : "URL", diff --git a/fiori/app/orders/fiori-service.cds b/fiori/app/orders/fiori-service.cds index 44612ee5..cced0972 100644 --- a/fiori/app/orders/fiori-service.cds +++ b/fiori/app/orders/fiori-service.cds @@ -1,13 +1,15 @@ -using AdminService from '@capire/bookshop/srv/admin-service'; +using OrdersService from '@capire/orders/srv/orders-service'; -annotate AdminService.Books with { +annotate OrdersService.Books with { price @Common.FieldControl: #ReadOnly; } + + //////////////////////////////////////////////////////////////////////////// // // Common // -annotate AdminService.OrderItems with { +annotate OrdersService.OrderItems with { book @( Common: { Text: book.title, @@ -22,7 +24,7 @@ annotate AdminService.OrderItems with { @odata.draft.enabled -annotate AdminService.Orders with @( +annotate OrdersService.Orders with @( UI: { //////////////////////////////////////////////////////////////////////////// // @@ -83,9 +85,9 @@ annotate AdminService.Orders with @( -//The enity types name is AdminService.my_bookshop_OrderItems +//The enity types name is OrdersService.my_bookshop_OrderItems //The annotations below are not generated in edmx WHY? -annotate AdminService.OrderItems with @( +annotate OrdersService.OrderItems with @( UI: { HeaderInfo: { TypeName: 'Order Item', TypeNamePlural: ' ', diff --git a/fiori/app/orders/webapp/manifest.json b/fiori/app/orders/webapp/manifest.json index e33eb24b..ce659ec2 100644 --- a/fiori/app/orders/webapp/manifest.json +++ b/fiori/app/orders/webapp/manifest.json @@ -3,12 +3,12 @@ "sap.app": { "id": "orders", "type": "application", - "title": "Manage Orders", + "title": "Order Books", "description": "Sample Application", "i18n": "i18n/i18n.properties", "dataSources": { - "AdminService": { - "uri": "/admin/", + "OrdersService": { + "uri": "/orders/", "type": "OData", "settings": { "odataVersion": "4.0" @@ -33,7 +33,7 @@ "uri": "i18n/i18n.properties" }, "": { - "dataSource": "AdminService", + "dataSource": "OrdersService", "settings": { "synchronizationMode": "None", "operationMode": "Server", @@ -140,7 +140,7 @@ } } } - } + } }, "AuthorsDetails": { "type": "Component", diff --git a/fiori/package.json b/fiori/package.json index 5924c98d..84da4ecb 100644 --- a/fiori/package.json +++ b/fiori/package.json @@ -2,20 +2,14 @@ "name": "@capire/fiori", "version": "1.0.0", "description": "A simple bookshop application, build in a self-contained all-in-one fashion, i.e. w/o reusing other packages.", - "license": "SAP SAMPLE CODE LICENSE", "dependencies": { "@capire/bookshop": "*", + "@capire/orders": "*", "@capire/common": "*" }, "scripts": { "start": "cds run --in-memory?", "watch": "cds watch" }, - "cds": { - "requires": { - "db": { - "kind": "sql" - } - } - } + "license": "SAP SAMPLE CODE LICENSE" } \ No newline at end of file diff --git a/fiori/srv/admin-service.cds b/fiori/srv/admin-service.cds index fceb9936..83bc3a9c 100644 --- a/fiori/srv/admin-service.cds +++ b/fiori/srv/admin-service.cds @@ -1,5 +1,3 @@ // Proxy for importing services from bookshop sample using from '@capire/bookshop/srv/admin-service'; -using from '@capire/bookshop/srv/cat-service'; - annotate AdminService with @impl:'srv/admin-service.js'; diff --git a/bookshop/db/data/sap.capire.bookshop-OrderItems.csv b/orders/db/data/sap.capire.bookshop-OrderItems.csv similarity index 100% rename from bookshop/db/data/sap.capire.bookshop-OrderItems.csv rename to orders/db/data/sap.capire.bookshop-OrderItems.csv diff --git a/bookshop/db/data/sap.capire.bookshop-Orders.csv b/orders/db/data/sap.capire.bookshop-Orders.csv similarity index 100% rename from bookshop/db/data/sap.capire.bookshop-Orders.csv rename to orders/db/data/sap.capire.bookshop-Orders.csv diff --git a/orders/db/schema.cds b/orders/db/schema.cds new file mode 100644 index 00000000..f64b307a --- /dev/null +++ b/orders/db/schema.cds @@ -0,0 +1,17 @@ +using { sap.capire.bookshop.Books } from '@capire/bookshop/db/schema'; +using { Currency, managed, cuid } from '@sap/cds/common'; +namespace sap.capire.bookshop; + +entity Orders : cuid, managed { + OrderNo : String @title:'Order Number'; //> readable key + Items : Composition of many OrderItems on Items.parent = $self; + total : Decimal(9,2) @readonly; + currency : Currency; +} + +entity OrderItems : cuid { + parent : Association to Orders; + book : Association to Books; + amount : Integer; + netAmount : Decimal(9,2); +} diff --git a/orders/package.json b/orders/package.json new file mode 100644 index 00000000..f8d2c6c6 --- /dev/null +++ b/orders/package.json @@ -0,0 +1,5 @@ +{ + "name": "@capire/orders", + "version": "1.0.0", + "license": "SAP SAMPLE CODE LICENSE" +} \ No newline at end of file diff --git a/orders/srv/orders-service.cds b/orders/srv/orders-service.cds new file mode 100644 index 00000000..249bcca4 --- /dev/null +++ b/orders/srv/orders-service.cds @@ -0,0 +1,5 @@ +using { sap.capire.bookshop as my } from '../db/schema'; + +service OrdersService { + entity Orders as projection on my.Orders; +} diff --git a/orders/srv/orders-service.js b/orders/srv/orders-service.js new file mode 100644 index 00000000..55d0e1ba --- /dev/null +++ b/orders/srv/orders-service.js @@ -0,0 +1,21 @@ +const cds = require('@sap/cds') + +module.exports = cds.service.impl(function() { + + const { Books } = cds.entities + + // Reduce stock of ordered books if available stock suffices + this.before ('CREATE', 'Orders', (req) => { + const { Items: OrderItems } = req.data + return cds.transaction(req) .run (()=> OrderItems.map (order => + UPDATE (Books) .where ('ID =', order.book_ID) + .and ('stock >=', order.amount) + .set ('stock -=', order.amount) + )) .then (all => all.forEach ((affectedRows,i) => { + if (affectedRows === 0) req.error (409, + `${OrderItems[i].amount} exceeds stock for book #${OrderItems[i].book_ID}` + ) + })) + }) + +}) diff --git a/package.json b/package.json index bd5aeee5..76386cd0 100644 --- a/package.json +++ b/package.json @@ -1,26 +1,22 @@ { "name": "@capire/samples", "description": "The umbrella project for all samples to easily setup for local development and tests.", - "repository": "https://github.com/SAP-samples/cloud-cap-samples.git", + "repository": "https://github.com/sap-samples/cloud-cap-samples.git", "author": "daniel.hutzel@sap.com", - "private": true, "scripts": { - "bookshop-fiori": "cds watch fiori", - "bookshop": "cds watch bookshop" + "bookshop": "cds watch fiori" }, "dependencies": { "@capire/bookshop": "file:bookshop", "@capire/common": "file:common", "@capire/fiori": "file:fiori", + "@capire/orders": "file:orders", "@capire/reviews": "file:reviews" }, - "add-these-to-devDependencies-for-tests": { - "@types/jest": "*", - "jest": "*" - }, - "license": "SAP SAMPLE CODE LICENSE", "devDependencies": { "chai": "^4.2.0", - "chai-deep-match": "^1.2.1" - } + "chai-subset": "^1.6.0" + }, + "license": "SAP SAMPLE CODE LICENSE", + "private": true } diff --git a/reviews/.env b/reviews/.env deleted file mode 100644 index 378d6075..00000000 --- a/reviews/.env +++ /dev/null @@ -1 +0,0 @@ -PORT = 5005 \ No newline at end of file diff --git a/reviews/db/schema.cds b/reviews/db/schema.cds index 9b07b02b..0183a8fd 100644 --- a/reviews/db/schema.cds +++ b/reviews/db/schema.cds @@ -28,4 +28,4 @@ type Rating : Decimal(3,2) enum { entity Likes { key review : Association to Reviews; key user : User; -} \ No newline at end of file +} diff --git a/reviews/package.json b/reviews/package.json index 4c7e6062..bb996e51 100644 --- a/reviews/package.json +++ b/reviews/package.json @@ -4,17 +4,14 @@ "description": "A reuse service providing generic means to add reviews and ratings to target objects, e.g. products.", "repository": "https://github.com/SAP-samples/cloud-cap-samples.git", "license": "SAP SAMPLE CODE LICENSE", - "dependencies": { - }, - "scripts": { - "start": "cds run --in-memory?", - "watch": "cds watch" - }, "files": [ "db", "srv", "index.cds" ], + "scripts": { + "watch": "PORT=5005 cds watch" + }, "cds": { "requires": { "db": {