From 33380c07920a82bf8f377c5f81b8e0ee736c62f0 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Nov 2021 19:29:27 +0100 Subject: [PATCH 1/9] Restore simple bookshop - no workarounds Signed-off-by: Daniel --- bookshop/srv/admin-service.cds | 4 --- bookshop/srv/cat-service.cds | 50 ++++++++-------------------------- 2 files changed, 12 insertions(+), 42 deletions(-) diff --git a/bookshop/srv/admin-service.cds b/bookshop/srv/admin-service.cds index abbdeaf5..ea9b0731 100644 --- a/bookshop/srv/admin-service.cds +++ b/bookshop/srv/admin-service.cds @@ -3,7 +3,3 @@ service AdminService @(requires:'admin') { entity Books as projection on my.Books; entity Authors as projection on my.Authors; } - -//Since ID is computed, we can hide the popup for ID on Create -annotate AdminService.Books with { ID @Core.Computed; } -annotate AdminService.Authors with { ID @Core.Computed; } \ No newline at end of file diff --git a/bookshop/srv/cat-service.cds b/bookshop/srv/cat-service.cds index 223b045a..4cc44dff 100644 --- a/bookshop/srv/cat-service.cds +++ b/bookshop/srv/cat-service.cds @@ -1,42 +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') { + /** For displaying lists of Books */ + @readonly entity ListOfBooks as projection on Books + excluding { descr }; - /** - * 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 + } excluding { createdBy, modifiedBy }; - /** - * For display in details pages - */ - @readonly - entity Books as projection on my.Books { - * , author.name as authorName - } excluding { - createdBy, - modifiedBy - }; - - @readonly - entity Authors as projection on my.Authors { - * , books : redirected to Books - } excluding { - createdBy, - modifiedBy - }; - - @requires : 'authenticated-user' - action submitOrder(book : Books:ID, quantity : Integer) returns { - stock : Integer - }; - - event OrderedBook : { - book : Books:ID; - quantity : Integer; - buyer : String - }; + @requires: 'authenticated-user' + action submitOrder ( book: Books:ID, amount: Integer ) returns { stock: Integer }; + event OrderedBook : { book: Books:ID; amount: Integer; buyer: String }; } From 19b680ab3d4f457d7a624ba1563a50a5c783a486 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Nov 2021 19:30:47 +0100 Subject: [PATCH 2/9] Moving lifetime + age to where it is used Signed-off-by: Daniel --- bookstore/db/schema.cds | 8 -------- bookstore/index.cds | 4 +--- bookstore/package.json | 8 +------- {bookstore => fiori}/db/hana/index.cds | 2 +- {bookstore => fiori}/db/sqlite/index.cds | 2 +- fiori/package.json | 9 +++++++++ 6 files changed, 13 insertions(+), 20 deletions(-) delete mode 100644 bookstore/db/schema.cds rename {bookstore => fiori}/db/hana/index.cds (84%) rename {bookstore => fiori}/db/sqlite/index.cds (86%) diff --git a/bookstore/db/schema.cds b/bookstore/db/schema.cds deleted file mode 100644 index 479fdbfb..00000000 --- a/bookstore/db/schema.cds +++ /dev/null @@ -1,8 +0,0 @@ -using { sap.capire.bookshop } from '@capire/bookshop'; - -// Forward-declare calculated fields to be filled in database-specific ways -// TODO find a better way to have 'default' fields that still can be overwritten. -extend bookshop.Authors with { - virtual age: Integer; - virtual lifetime: String; -} diff --git a/bookstore/index.cds b/bookstore/index.cds index 4b86c023..ac2accff 100644 --- a/bookstore/index.cds +++ b/bookstore/index.cds @@ -1,4 +1,2 @@ namespace sap.capire.bookshop; //> important for reflection - -using from '@capire/bookshop'; -using from './db/schema'; +using from './srv/mashup'; diff --git a/bookstore/package.json b/bookstore/package.json index 216156e6..f69dae7a 100644 --- a/bookstore/package.json +++ b/bookstore/package.json @@ -25,13 +25,7 @@ "[production]": { "kind": "enterprise-messaging" } }, "db": { - "kind": "sql", - "[development]": { - "model": "db/sqlite" - }, - "[production]": { - "model": "db/hana" - } + "kind": "sql" } }, "log": { "service": true } diff --git a/bookstore/db/hana/index.cds b/fiori/db/hana/index.cds similarity index 84% rename from bookstore/db/hana/index.cds rename to fiori/db/hana/index.cds index 04822ad0..866e8741 100644 --- a/bookstore/db/hana/index.cds +++ b/fiori/db/hana/index.cds @@ -2,7 +2,7 @@ // Add Author.age and .lifetime with a DB-specific function // -using { AdminService } from '../schema'; +using { AdminService } from '@capire/bookshop'; extend projection AdminService.Authors with { YEARS_BETWEEN(dateOfBirth, dateOfDeath) as age: Integer, diff --git a/bookstore/db/sqlite/index.cds b/fiori/db/sqlite/index.cds similarity index 86% rename from bookstore/db/sqlite/index.cds rename to fiori/db/sqlite/index.cds index 019335ef..7bdfc6bb 100644 --- a/bookstore/db/sqlite/index.cds +++ b/fiori/db/sqlite/index.cds @@ -2,7 +2,7 @@ // Add Author.age and .lifetime with a DB-specific function // -using { AdminService } from '../schema'; +using { AdminService } from '@capire/bookshop'; extend projection AdminService.Authors with { strftime('%Y',dateOfDeath)-strftime('%Y',dateOfBirth) as age: Integer, diff --git a/fiori/package.json b/fiori/package.json index cf2f5ce1..64528079 100644 --- a/fiori/package.json +++ b/fiori/package.json @@ -29,6 +29,15 @@ "[development]": { "kind": "file-based-messaging" }, "[hybrid!]": { "kind": "enterprise-messaging-shared" } }, + "db": { + "kind": "sql", + "[development]": { + "model": "db/sqlite" + }, + "[production]": { + "model": "db/hana" + } + }, "hana": { "deploy-format": "hdbtable" } From 756ed48ce3299aa50b6075550db9e74b4aa802e1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Nov 2021 19:33:13 +0100 Subject: [PATCH 3/9] Fiori apps with manage authors Signed-off-by: Daniel --- fiori/app/admin-authors/fiori-service.cds | 47 +++++++++++++++++++ .../webapp/Component.js | 0 .../webapp/i18n/i18n.properties | 0 .../webapp/manifest.json | 10 ++-- .../{admin => admin-books}/fiori-service.cds | 24 ++-------- .../webapp/Component.js | 2 +- .../webapp/i18n/i18n.properties | 0 .../webapp/manifest.json | 2 +- fiori/app/appconfig/fioriSandboxConfig.json | 26 +++++----- fiori/app/authors/fiori-service.cds | 30 ------------ fiori/app/browse/fiori-service.cds | 4 +- fiori/app/services.cds | 4 +- 12 files changed, 74 insertions(+), 75 deletions(-) create mode 100644 fiori/app/admin-authors/fiori-service.cds rename fiori/app/{authors => admin-authors}/webapp/Component.js (100%) rename fiori/app/{authors => admin-authors}/webapp/i18n/i18n.properties (100%) rename fiori/app/{authors => admin-authors}/webapp/manifest.json (94%) rename fiori/app/{admin => admin-books}/fiori-service.cds (80%) rename fiori/app/{admin => admin-books}/webapp/Component.js (63%) rename fiori/app/{admin => admin-books}/webapp/i18n/i18n.properties (100%) rename fiori/app/{admin => admin-books}/webapp/manifest.json (99%) delete mode 100644 fiori/app/authors/fiori-service.cds diff --git a/fiori/app/admin-authors/fiori-service.cds b/fiori/app/admin-authors/fiori-service.cds new file mode 100644 index 00000000..2309eae6 --- /dev/null +++ b/fiori/app/admin-authors/fiori-service.cds @@ -0,0 +1,47 @@ +using {AdminService} from '@capire/bookshop'; + +annotate AdminService.Authors with @odata.draft.enabled; + +//////////////////////////////////////////////////////////////////////////// +// +// Authors Object Page +// +annotate AdminService.Authors with @(UI : { + HeaderInfo : { + TypeName : 'Author', + TypeNamePlural : 'Authors', + Description : {Value : lifetime} + }, + Facets : [ + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Details}', + Target : '@UI.FieldGroup#Details' + }, + { + $Type : 'UI.ReferenceFacet', + Label : '{i18n>Books}', + Target : 'books/@UI.LineItem' + }, + ], + FieldGroup #Details : {Data : [ + {Value : placeOfBirth}, + {Value : placeOfDeath}, + {Value : dateOfBirth}, + {Value : dateOfDeath}, + { + Value : age, + Label : '{i18n>Age}' + }, + ]}, +}); + + +// Workaround to avoid errors for unknown db-specific calculated fields above +extend sap.capire.bookshop.Authors with { + virtual age : Integer; + virtual lifetime : String; +} + +// Workaround for Fiori popup for asking user to enter a new UUID on Create +annotate AdminService.Authors with { ID @Core.Computed; } diff --git a/fiori/app/authors/webapp/Component.js b/fiori/app/admin-authors/webapp/Component.js similarity index 100% rename from fiori/app/authors/webapp/Component.js rename to fiori/app/admin-authors/webapp/Component.js diff --git a/fiori/app/authors/webapp/i18n/i18n.properties b/fiori/app/admin-authors/webapp/i18n/i18n.properties similarity index 100% rename from fiori/app/authors/webapp/i18n/i18n.properties rename to fiori/app/admin-authors/webapp/i18n/i18n.properties diff --git a/fiori/app/authors/webapp/manifest.json b/fiori/app/admin-authors/webapp/manifest.json similarity index 94% rename from fiori/app/authors/webapp/manifest.json rename to fiori/app/admin-authors/webapp/manifest.json index 7efe933c..f721b11d 100644 --- a/fiori/app/authors/webapp/manifest.json +++ b/fiori/app/admin-authors/webapp/manifest.json @@ -3,15 +3,15 @@ "sap.app": { "id": "authors", "type": "application", - "title": "Browse Authors", + "title": "Manage Authors", "description": "Sample Application", "i18n": "i18n/i18n.properties", "applicationVersion": { "version": "1.0.0" }, "dataSources": { - "CatalogService": { - "uri": "/browse/", + "AdminService": { + "uri": "/admin/", "type": "OData", "settings": { "odataVersion": "4.0" @@ -41,7 +41,7 @@ "subTitle": "{{appSubTitle}}", "icon": "sap-icon://SAP-icons-TNT/user", "indicatorDataSource": { - "dataSource": "CatalogService", + "dataSource": "AdminService", "path": "Authors/$count", "refresh": 1800 } @@ -62,7 +62,7 @@ "uri": "i18n/i18n.properties" }, "": { - "dataSource": "CatalogService", + "dataSource": "AdminService", "settings": { "synchronizationMode": "None", "operationMode": "Server", diff --git a/fiori/app/admin/fiori-service.cds b/fiori/app/admin-books/fiori-service.cds similarity index 80% rename from fiori/app/admin/fiori-service.cds rename to fiori/app/admin-books/fiori-service.cds index 14d00a55..58b4cc1c 100644 --- a/fiori/app/admin/fiori-service.cds +++ b/fiori/app/admin-books/fiori-service.cds @@ -40,27 +40,6 @@ annotate AdminService.Books with @( } ); -annotate AdminService.Authors with @( - UI: { - HeaderInfo: { - Description: {Value: lifetime} - }, - Facets: [ - {$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'}, - {$Type: 'UI.ReferenceFacet', Label: '{i18n>Books}', Target: 'books/@UI.LineItem'}, - ], - FieldGroup#Details: { - Data: [ - {Value: placeOfBirth}, - {Value: placeOfDeath}, - {Value: dateOfBirth}, - {Value: dateOfDeath}, - {Value: age, Label: '{i18n>Age}'}, - ] - }, - } -); - //////////////////////////////////////////////////////////// @@ -93,3 +72,6 @@ using { sap } from '@sap/cds/common'; extend service AdminService { @readonly entity Languages as projection on sap.common.Languages; } + +// Workaround for Fiori popup for asking user to enter a new UUID on Create +annotate AdminService.Books with { ID @Core.Computed; } diff --git a/fiori/app/admin/webapp/Component.js b/fiori/app/admin-books/webapp/Component.js similarity index 63% rename from fiori/app/admin/webapp/Component.js rename to fiori/app/admin-books/webapp/Component.js index c3137017..d4bc7328 100644 --- a/fiori/app/admin/webapp/Component.js +++ b/fiori/app/admin-books/webapp/Component.js @@ -1,6 +1,6 @@ sap.ui.define(["sap/fe/core/AppComponent"], function(AppComponent) { "use strict"; - return AppComponent.extend("admin.Component", { + return AppComponent.extend("books.Component", { metadata: { manifest: "json" } }); }); diff --git a/fiori/app/admin/webapp/i18n/i18n.properties b/fiori/app/admin-books/webapp/i18n/i18n.properties similarity index 100% rename from fiori/app/admin/webapp/i18n/i18n.properties rename to fiori/app/admin-books/webapp/i18n/i18n.properties diff --git a/fiori/app/admin/webapp/manifest.json b/fiori/app/admin-books/webapp/manifest.json similarity index 99% rename from fiori/app/admin/webapp/manifest.json rename to fiori/app/admin-books/webapp/manifest.json index bdedd060..1cac7ab1 100644 --- a/fiori/app/admin/webapp/manifest.json +++ b/fiori/app/admin-books/webapp/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.8.0", "sap.app": { - "id": "admin", + "id": "books", "type": "application", "title": "Manage Books", "description": "Sample Application", diff --git a/fiori/app/appconfig/fioriSandboxConfig.json b/fiori/app/appconfig/fioriSandboxConfig.json index b223b498..a95f01f5 100644 --- a/fiori/app/appconfig/fioriSandboxConfig.json +++ b/fiori/app/appconfig/fioriSandboxConfig.json @@ -19,14 +19,6 @@ "title": "Browse Books", "targetURL": "#Books-display" } - }, - { - "id": "BrowseAuthors", - "tileType": "sap.ushell.ui.tile.StaticTile", - "properties": { - "title": "Browse Authors", - "targetURL": "#Authors-display" - } } ] }, @@ -45,6 +37,14 @@ "targetURL": "#Books-manage" } }, + { + "id": "ManageAuthors", + "tileType": "sap.ushell.ui.tile.StaticTile", + "properties": { + "title": "Manage Authors", + "targetURL": "#Authors-display" + } + }, { "id": "ManageOrders", "tileType": "sap.ushell.ui.tile.StaticTile", @@ -75,10 +75,10 @@ "signature": { "parameters": { "Books.ID": { - "renameTo": "ID" + "renameTo": "ID" }, "Authors.books.ID": { - "renameTo": "ID" + "renameTo": "ID" } }, "additionalParameters": "ignored" @@ -104,7 +104,7 @@ "resolutionResult": { "applicationType": "SAPUI5", "additionalInformation": "SAPUI5.Component=authors", - "url": "/authors/webapp" + "url": "/admin-authors/webapp" } }, "ManageBooks": { @@ -117,8 +117,8 @@ }, "resolutionResult": { "applicationType": "SAPUI5", - "additionalInformation": "SAPUI5.Component=admin", - "url": "/admin/webapp" + "additionalInformation": "SAPUI5.Component=books", + "url": "/admin-books/webapp" } }, "ManageOrders": { diff --git a/fiori/app/authors/fiori-service.cds b/fiori/app/authors/fiori-service.cds deleted file mode 100644 index 4a16c735..00000000 --- a/fiori/app/authors/fiori-service.cds +++ /dev/null @@ -1,30 +0,0 @@ -using CatalogService from '@capire/bookshop'; - -//////////////////////////////////////////////////////////////////////////// -// -// Authors Object Page -// -annotate CatalogService.Authors with @(UI : { - HeaderInfo : { - TypeName : 'Author', - TypeNamePlural : 'Authors', - Description : {Value : name} - }, - HeaderFacets : [{ - $Type : 'UI.ReferenceFacet', - Label : '{i18n>Description}', - Target : '@UI.FieldGroup#Descr' - }, ], - Facets : [{ - $Type : 'UI.ReferenceFacet', - Label : '{i18n>Details}', - Target : 'books/@UI.LineItem' - }, ], - FieldGroup #Descr : {Data : [ - {Value : name}, - {Value : dateOfBirth}, - {Value : dateOfDeath}, - {Value : placeOfBirth}, - {Value : placeOfDeath}, - ]}, -}); \ No newline at end of file diff --git a/fiori/app/browse/fiori-service.cds b/fiori/app/browse/fiori-service.cds index 15895c97..ef960b29 100644 --- a/fiori/app/browse/fiori-service.cds +++ b/fiori/app/browse/fiori-service.cds @@ -8,7 +8,7 @@ annotate CatalogService.Books with @(UI : { HeaderInfo : { TypeName : 'Book', TypeNamePlural : 'Books', - Description : {Value : authorName} + Description : {Value : author} }, HeaderFacets : [{ $Type : 'UI.ReferenceFacet', @@ -47,7 +47,7 @@ annotate CatalogService.Books with @(UI : { Label : '{i18n>Title}' }, { - Value : author.ID, + Value : author, Label : '{i18n>Author}' }, {Value : genre.name}, diff --git a/fiori/app/services.cds b/fiori/app/services.cds index 6f96e3b9..3ab3f083 100644 --- a/fiori/app/services.cds +++ b/fiori/app/services.cds @@ -2,8 +2,8 @@ This model controls what gets served to Fiori frontends... */ -using from './admin/fiori-service'; +using from './admin-authors/fiori-service'; +using from './admin-books/fiori-service'; using from './browse/fiori-service'; -using from './authors/fiori-service'; using from './common'; using from '@capire/bookstore/srv/mashup'; From 8d8aa6c2c9b903d04685ac057a3bcb0461232677 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 24 Nov 2021 19:48:28 +0100 Subject: [PATCH 4/9] Fixing copy errors Signed-off-by: Daniel --- bookshop/srv/cat-service.cds | 4 ++-- bookshop/test/requests.http | 13 +++++++++++++ test/localized-data.test.js | 36 ++++++++++++++++++------------------ test/odata.test.js | 10 +++++----- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/bookshop/srv/cat-service.cds b/bookshop/srv/cat-service.cds index 4cc44dff..2441db25 100644 --- a/bookshop/srv/cat-service.cds +++ b/bookshop/srv/cat-service.cds @@ -11,6 +11,6 @@ service CatalogService @(path:'/browse') { } excluding { createdBy, modifiedBy }; @requires: 'authenticated-user' - action submitOrder ( book: Books:ID, amount: Integer ) returns { stock: Integer }; - event OrderedBook : { book: Books:ID; amount: Integer; buyer: String }; + action submitOrder ( book: Books:ID, quantity: Integer ) returns { stock: Integer }; + event OrderedBook : { book: Books:ID; quantity: Integer; buyer: String }; } diff --git a/bookshop/test/requests.http b/bookshop/test/requests.http index 890e621e..a4af87d6 100644 --- a/bookshop/test/requests.http +++ b/bookshop/test/requests.http @@ -32,6 +32,19 @@ GET {{server}}/admin/Authors? # &sap-language=de Authorization: Basic alice: +### ------------------------------------------------------------------------ +# Create Author +POST {{server}}/admin/Authors +Content-Type: application/json;IEEE754Compatible=true +Authorization: Basic alice: + +{ + "ID": 112, + "name": "Shakespeeeeere", + "age": 22 +} + + ### ------------------------------------------------------------------------ # Create book POST {{server}}/admin/Books diff --git a/test/localized-data.test.js b/test/localized-data.test.js index 316ae9e4..4d399786 100644 --- a/test/localized-data.test.js +++ b/test/localized-data.test.js @@ -11,39 +11,39 @@ describe('Localized Data', () => { }) it('supports sap-language param', async () => { - const { data } = await GET(`/browse/Books?$select=title,authorName` + '&sap-language=de') + const { data } = await GET(`/browse/Books?$select=title,author` + '&sap-language=de') expect(data.value).to.containSubset([ - { title: 'Sturmhöhe', authorName: 'Emily Brontë' }, - { title: 'Jane Eyre', authorName: 'Charlotte Brontë' }, - { title: 'The Raven', authorName: 'Edgar Allen Poe' }, - { title: 'Eleonora', authorName: 'Edgar Allen Poe' }, - { title: 'Catweazle', authorName: 'Richard Carpenter' }, + { title: 'Sturmhöhe', author: 'Emily Brontë' }, + { title: 'Jane Eyre', author: 'Charlotte Brontë' }, + { title: 'The Raven', author: 'Edgar Allen Poe' }, + { title: 'Eleonora', author: 'Edgar Allen Poe' }, + { title: 'Catweazle', author: 'Richard Carpenter' }, ]) }) it('supports accept-language header', async () => { - const { data } = await GET(`/browse/Books?$select=title,authorName`, { + const { data } = await GET(`/browse/Books?$select=title,author`, { headers: { 'Accept-Language': 'de' }, }) expect(data.value).to.containSubset([ - { title: 'Sturmhöhe', authorName: 'Emily Brontë' }, - { title: 'Jane Eyre', authorName: 'Charlotte Brontë' }, - { title: 'The Raven', authorName: 'Edgar Allen Poe' }, - { title: 'Eleonora', authorName: 'Edgar Allen Poe' }, - { title: 'Catweazle', authorName: 'Richard Carpenter' }, + { title: 'Sturmhöhe', author: 'Emily Brontë' }, + { title: 'Jane Eyre', author: 'Charlotte Brontë' }, + { title: 'The Raven', author: 'Edgar Allen Poe' }, + { title: 'Eleonora', author: 'Edgar Allen Poe' }, + { title: 'Catweazle', author: 'Richard Carpenter' }, ]) }) it('supports queries with $expand', async () => { - const { data } = await GET(`/browse/Books?&$select=title,authorName&$expand=currency`, { + const { data } = await GET(`/browse/Books?&$select=title,author&$expand=currency`, { headers: { 'Accept-Language': 'de' }, }) expect(data.value).to.containSubset([ - { title: 'Sturmhöhe', authorName: 'Emily Brontë', currency: { name: 'Pfund' } }, - { title: 'Jane Eyre', authorName: 'Charlotte Brontë', currency: { name: 'Pfund' } }, - { title: 'The Raven', authorName: 'Edgar Allen Poe', currency: { name: 'US-Dollar' } }, - { title: 'Eleonora', authorName: 'Edgar Allen Poe', currency: { name: 'US-Dollar' } }, - { title: 'Catweazle', authorName: 'Richard Carpenter', currency: { name: 'Yen' } }, + { title: 'Sturmhöhe', author: 'Emily Brontë', currency: { name: 'Pfund' } }, + { title: 'Jane Eyre', author: 'Charlotte Brontë', currency: { name: 'Pfund' } }, + { title: 'The Raven', author: 'Edgar Allen Poe', currency: { name: 'US-Dollar' } }, + { title: 'Eleonora', author: 'Edgar Allen Poe', currency: { name: 'US-Dollar' } }, + { title: 'Catweazle', author: 'Richard Carpenter', currency: { name: 'Yen' } }, ]) }) diff --git a/test/odata.test.js b/test/odata.test.js index ff1945f2..43b90791 100644 --- a/test/odata.test.js +++ b/test/odata.test.js @@ -19,13 +19,13 @@ describe('OData Protocol', () => { it('supports $search in multiple fields', async () => { const { data } = await GET `/browse/Books ${{ - params: { $search: 'Po', $select: `title,authorName` }, + params: { $search: 'Po', $select: `title,author` }, }}` expect(data.value).to.eql([ - { ID: 201, title: 'Wuthering Heights', authorName: 'Emily Brontë' }, - { ID: 207, title: 'Jane Eyre', authorName: 'Charlotte Brontë' }, - { ID: 251, title: 'The Raven', authorName: 'Edgar Allen Poe' }, - { ID: 252, title: 'Eleonora', authorName: 'Edgar Allen Poe' }, + { ID: 201, title: 'Wuthering Heights', author: 'Emily Brontë' }, + { ID: 207, title: 'Jane Eyre', author: 'Charlotte Brontë' }, + { ID: 251, title: 'The Raven', author: 'Edgar Allen Poe' }, + { ID: 252, title: 'Eleonora', author: 'Edgar Allen Poe' }, ]) }) From 042ddec41c1387cf06ad7b09dc6a2c891336a9f2 Mon Sep 17 00:00:00 2001 From: Christian Georgi Date: Thu, 25 Nov 2021 15:20:25 +0100 Subject: [PATCH 5/9] Adjust code tour --- .tours/db-native.tour | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/.tours/db-native.tour b/.tours/db-native.tour index d4d29e21..b47b6a0d 100644 --- a/.tours/db-native.tour +++ b/.tours/db-native.tour @@ -37,7 +37,7 @@ "title": "Authors service" }, { - "file": "bookstore/db/sqlite/index.cds", + "file": "fiori/db/sqlite/index.cds", "description": "#### SQLite Implementation\n\nHere's the first implementation for SQLite. It computes the two fields `age` and `lifetime` through SQLite's [strftime](https://sqlite.org/lang_datefunc.html) function.\n\nThrough the [`extend projection`](https://cap.cloud.sap/docs/cds/cdl#extend-view) clause you can add additional fields to projection entities. These are deployed as database views, which is why we can integrate the database functions in the first place.\n", "selection": { "start": { @@ -52,8 +52,8 @@ "title": "SQLite implementation" }, { - "file": "bookstore/db/hana/index.cds", - "description": "#### SAP HANA Implementation\n\nThis is the second implementation for SAP HANA. It computes the same two fields `age` and `lifetime` through the [YEARS_BETWEEN](https://help.sap.com/viewer/7c78579ce9b14a669c1f3295b0d8ca16/Cloud/en-US/7c0d2c161ea34def86de3f5eadd6a0af.html) and [YEAR](https://help.sap.com/viewer/7c78579ce9b14a669c1f3295b0d8ca16/Cloud/en-US/20f5fac6751910148dabd3c6821f907d.html) functions of SAP HANA.\n\n#### File Layout and Code Structure\n\nNote the path of the `.cds` file we are in: it's in a subfolder of `db`, so that it's _not_ automatically picked up when we start the application. The same is true for the SQLite implementation: it's in a separate `db/sqlite/` folder as well. In the next step, you'll see how these files are loaded.\n\nAlso, we choose to implement all of that as an extension of the original bookshop here in the _bookstore_ package. See the first [CAP Samples] code tour for more details on the different packages of this repository.", + "file": "fiori/db/hana/index.cds", + "description": "#### SAP HANA Implementation\n\nThis is the second implementation for SAP HANA. It computes the same two fields `age` and `lifetime` through the [YEARS_BETWEEN](https://help.sap.com/viewer/7c78579ce9b14a669c1f3295b0d8ca16/Cloud/en-US/7c0d2c161ea34def86de3f5eadd6a0af.html) and [YEAR](https://help.sap.com/viewer/7c78579ce9b14a669c1f3295b0d8ca16/Cloud/en-US/20f5fac6751910148dabd3c6821f907d.html) functions of SAP HANA.\n\n#### File Layout and Code Structure\n\nNote the path of the `.cds` file we are in: it's in a subfolder of `db`, so that it's _not_ automatically picked up when we start the application. The same is true for the SQLite implementation: it's in a separate `db/sqlite/` folder as well. In the next step, you'll see how these files are loaded.\n\nAlso, we choose to implement all of that as an extension of the original bookshop here in the _fiori_ package. See the first [CAP Samples] code tour for more details on the different packages of this repository.", "selection": { "start": { "line": 7, @@ -67,25 +67,25 @@ "title": "SAP HANA implementation" }, { - "file": "bookstore/package.json", + "file": "fiori/package.json", "description": "#### Configuration\n\nThe `cds` section in `package.json` is a place to configure which of the `db/sqlite` and `db/hana` folders are used for which database.\nWe use [Node.js profiles](https://cap.cloud.sap/docs/node.js/cds-env#profiles) to separate the configuration.\nIn the `development` profile, you can see that `db/sqlite` is set as the model, while the `db/hana` folder is configured in the `production` profile.", "line": 12, "title": "Configuration" }, { - "file": "bookstore/package.json", - "description": "#### Run with SQLite\n\nTo run with `development` and an in-memory SQLite database, you don't need to do anything special, because it's activated by default. Just run:\n\n>> cds watch bookstore\n\nThen open [http://localhost:4004/admin/Authors](http://localhost:4004/admin/Authors) to see the two new fields.\n", - "line": 30, + "file": "fiori/package.json", + "description": "#### Run with SQLite\n\nTo run with `development` and an in-memory SQLite database, you don't need to do anything special, because it's activated by default. Just run:\n\n>> cds watch fiori\n\nThen open [http://localhost:4004/admin/Authors](http://localhost:4004/admin/Authors) to see the two new fields.\n", + "line": 35, "title": "Run with SQLite" }, { - "file": "bookstore/package.json", - "description": "#### Deploy the CDS Model to SAP HANA\n\nTo 'activate' SAP HANA through the `production` profile, you can use the global `--production` flag:\n\n>> cd bookstore; cds deploy --to hana --production\n\n[Learn more about SAP HANA deployment](https://cap.cloud.sap/docs/guides/databases#get-hana)\n\n#### Run the Application\n\n>> cd bookstore; cds watch --production\n\nThe service on [http://localhost:4004/admin/Authors](http://localhost:4004/admin/Authors) is the same as before, but this time the `Authors` entity is backed by a database view with an SAP HANA function.\n\n#### More\n\nIf you don't see data, you can add some in the next step.", - "line": 33, + "file": "fiori/package.json", + "description": "#### Deploy the CDS Model to SAP HANA\n\nTo 'activate' SAP HANA through the `production` profile, you can use the global `--production` flag:\n\n>> cd fiori; cds deploy --to hana --production\n\n[Learn more about SAP HANA deployment](https://cap.cloud.sap/docs/guides/databases#get-hana)\n\n#### Run the Application\n\n>> cd fiori; cds watch --production\n\nThe service on [http://localhost:4004/admin/Authors](http://localhost:4004/admin/Authors) is the same as before, but this time the `Authors` entity is backed by a database view with an SAP HANA function.\n\n#### More\n\nIf you don't see data, you can add some in the next step.", + "line": 38, "title": "Run with SAP HANA" }, { - "file": "bookstore/test/requests.http", + "file": "fiori/test/requests.http", "description": "### Add More Data\n\nOptionally you can add some `Authors` data by clicking on the _Send Request_ link (provided by the [REST client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension).", "line": 72, "selection": { @@ -104,6 +104,5 @@ "title": "Wrap-up", "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": "main" + ] } \ No newline at end of file From a37f1b8e0c519edca1b951a7ef417dbad7aba255 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 25 Nov 2021 17:50:27 +0100 Subject: [PATCH 6/9] Reformatted package.json --- fiori/package.json | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fiori/package.json b/fiori/package.json index 64528079..9f397564 100644 --- a/fiori/package.json +++ b/fiori/package.json @@ -25,9 +25,15 @@ "model": "@capire/orders" }, "messaging": { - "[production]": { "kind": "enterprise-messaging" }, - "[development]": { "kind": "file-based-messaging" }, - "[hybrid!]": { "kind": "enterprise-messaging-shared" } + "[production]": { + "kind": "enterprise-messaging" + }, + "[development]": { + "kind": "file-based-messaging" + }, + "[hybrid!]": { + "kind": "enterprise-messaging-shared" + } }, "db": { "kind": "sql", From 40b6acee6a381531c12b888f32418ff2f5896dd4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 25 Nov 2021 18:35:41 +0100 Subject: [PATCH 7/9] Fixing erroneous db.model config --- fiori/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fiori/package.json b/fiori/package.json index 9f397564..a01cff46 100644 --- a/fiori/package.json +++ b/fiori/package.json @@ -36,7 +36,9 @@ } }, "db": { - "kind": "sql", + "kind": "sql" + }, + "db-ext": { "[development]": { "model": "db/sqlite" }, From fa854a241115e19008df23648cb0ac1f811b7b97 Mon Sep 17 00:00:00 2001 From: Christian Georgi Date: Fri, 26 Nov 2021 10:57:22 +0100 Subject: [PATCH 8/9] Add hint on `db-ext` datasource to code tour Signed-off-by: Christian Georgi --- .tours/db-native.tour | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.tours/db-native.tour b/.tours/db-native.tour index b47b6a0d..97b615e0 100644 --- a/.tours/db-native.tour +++ b/.tours/db-native.tour @@ -68,20 +68,29 @@ }, { "file": "fiori/package.json", - "description": "#### Configuration\n\nThe `cds` section in `package.json` is a place to configure which of the `db/sqlite` and `db/hana` folders are used for which database.\nWe use [Node.js profiles](https://cap.cloud.sap/docs/node.js/cds-env#profiles) to separate the configuration.\nIn the `development` profile, you can see that `db/sqlite` is set as the model, while the `db/hana` folder is configured in the `production` profile.", - "line": 12, + "description": "#### Configuration\n\nThe `cds.requires` section in `package.json` is a place to configure which of the `db/sqlite` and `db/hana` folders are used for which database.\n\nWe use [Node.js profiles](https://cap.cloud.sap/docs/node.js/cds-env#profiles) to separate the configuration.\nIn the `development` profile, you can see that `db/sqlite` is set as the model, while the `db/hana` folder is configured in the `production` profile. `db-ext` is a pseudo datasource, its name doesn't matter.\n\nSee [`cds.resolve`](https://cap.cloud.sap/docs/node.js/cds-compile#cds-resolve) to learn more about how models are found.", + "selection": { + "start": { + "line": 41, + "character": 1 + }, + "end": { + "line": 48, + "character": 1 + } + }, "title": "Configuration" }, { "file": "fiori/package.json", "description": "#### Run with SQLite\n\nTo run with `development` and an in-memory SQLite database, you don't need to do anything special, because it's activated by default. Just run:\n\n>> cds watch fiori\n\nThen open [http://localhost:4004/admin/Authors](http://localhost:4004/admin/Authors) to see the two new fields.\n", - "line": 35, + "line": 43, "title": "Run with SQLite" }, { "file": "fiori/package.json", "description": "#### Deploy the CDS Model to SAP HANA\n\nTo 'activate' SAP HANA through the `production` profile, you can use the global `--production` flag:\n\n>> cd fiori; cds deploy --to hana --production\n\n[Learn more about SAP HANA deployment](https://cap.cloud.sap/docs/guides/databases#get-hana)\n\n#### Run the Application\n\n>> cd fiori; cds watch --production\n\nThe service on [http://localhost:4004/admin/Authors](http://localhost:4004/admin/Authors) is the same as before, but this time the `Authors` entity is backed by a database view with an SAP HANA function.\n\n#### More\n\nIf you don't see data, you can add some in the next step.", - "line": 38, + "line": 46, "title": "Run with SAP HANA" }, { From 1fde0c928be8804ef678bedde9320859f4c915f8 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 29 Nov 2021 15:34:52 +0100 Subject: [PATCH 9/9] Fixed submit order -> returned stock was wrong --- bookshop/srv/cat-service.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bookshop/srv/cat-service.js b/bookshop/srv/cat-service.js index a9abc2e4..a9c629c0 100644 --- a/bookshop/srv/cat-service.js +++ b/bookshop/srv/cat-service.js @@ -7,13 +7,12 @@ class CatalogService extends cds.ApplicationService { init(){ // Reduce stock of ordered books if available stock suffices this.on ('submitOrder', async req => { const {book,quantity} = req.data + if (quantity < 1) return req.reject (400,`quantity has to be 1 or more`) let {stock} = await SELECT `stock` .from (Books,book) - if (stock >= quantity) { - await UPDATE (Books,book) .with (`stock -=`, quantity) - await this.emit ('OrderedBook', { book, quantity, buyer:req.user.id }) - return { stock } - } - else return req.error (409,`${quantity} exceeds stock for book #${book}`) + if (quantity > stock) return req.reject (409,`${quantity} exceeds stock for book #${book}`) + await UPDATE (Books,book) .with ({ stock: stock -= quantity }) + await this.emit ('OrderedBook', { book, quantity, buyer:req.user.id }) + return { stock } }) // Add some discount for overstocked books