From cae6a21b89aace71ec369f88e3b3af2517dc70cb Mon Sep 17 00:00:00 2001 From: Koch Date: Wed, 19 Oct 2022 15:38:28 +0200 Subject: [PATCH] case --- orders/.env | 2 - orders/app/fiori.cds | 92 ---------- orders/app/orders/index.html | 39 ---- orders/app/orders/webapp/Component.js | 8 - orders/app/orders/webapp/i18n/i18n.properties | 11 -- orders/app/orders/webapp/manifest.json | 170 ------------------ orders/db/_schema._cds | 24 --- .../data/sap.capire.orders-OrdersHeaders.csv | 3 - .../db/data/sap.capire.orders-OrdersItems.csv | 4 - orders/db/schema.cds | 32 ---- orders/index.cds | 6 - orders/package.json | 8 - .../_performance_example_orders-service._cds | 5 - orders/srv/orders-service.cds | 87 --------- orders/srv/orders-service.js | 37 ---- performance/srv/performance-service.cds | 16 +- performance/srv/performance-service.js | 8 + 17 files changed, 20 insertions(+), 532 deletions(-) delete mode 100644 orders/.env delete mode 100644 orders/app/fiori.cds delete mode 100644 orders/app/orders/index.html delete mode 100644 orders/app/orders/webapp/Component.js delete mode 100644 orders/app/orders/webapp/i18n/i18n.properties delete mode 100644 orders/app/orders/webapp/manifest.json delete mode 100644 orders/db/_schema._cds delete mode 100644 orders/db/data/sap.capire.orders-OrdersHeaders.csv delete mode 100644 orders/db/data/sap.capire.orders-OrdersItems.csv delete mode 100644 orders/db/schema.cds delete mode 100644 orders/index.cds delete mode 100644 orders/package.json delete mode 100644 orders/srv/_performance_example_orders-service._cds delete mode 100644 orders/srv/orders-service.cds delete mode 100644 orders/srv/orders-service.js diff --git a/orders/.env b/orders/.env deleted file mode 100644 index 616dd8d0..00000000 --- a/orders/.env +++ /dev/null @@ -1,2 +0,0 @@ -cds.requires.messaging.kind = file-based-messaging -PORT = 4006 \ No newline at end of file diff --git a/orders/app/fiori.cds b/orders/app/fiori.cds deleted file mode 100644 index e3644ede..00000000 --- a/orders/app/fiori.cds +++ /dev/null @@ -1,92 +0,0 @@ - - -//////////////////////////////////////////////////////////////////////////// -// -// Note: this is designed for the OrdersService being co-located with -// bookshop. It does not work if OrdersService is run as a separate -// process, and is not intended to do so. -// -//////////////////////////////////////////////////////////////////////////// - - - -using { OrdersService } from '../srv/orders-service'; - - -@odata.draft.enabled -annotate OrdersService.Orders with @( - UI: { - SelectionFields: [ createdAt, createdBy ], - LineItem: [ - {Value: OrderNo, Label:'OrderNo'}, - {Value: buyer, Label:'Customer'}, - {Value: createdAt, Label:'Date'} - ], - HeaderInfo: { - TypeName: 'Order', TypeNamePlural: 'Orders', - Title: { - Label: 'Order number ', //A label is possible but it is not considered on the ObjectPage yet - Value: OrderNo - }, - Description: {Value: createdBy} - }, - Identification: [ //Is the main field group - {Value: createdBy, Label:'Customer'}, - {Value: createdAt, Label:'Date'}, - {Value: OrderNo }, - ], - HeaderFacets: [ - {$Type: 'UI.ReferenceFacet', Label: '{i18n>Created}', Target: '@UI.FieldGroup#Created'}, - {$Type: 'UI.ReferenceFacet', Label: '{i18n>Modified}', Target: '@UI.FieldGroup#Modified'}, - ], - Facets: [ - {$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'}, - {$Type: 'UI.ReferenceFacet', Label: '{i18n>OrderItems}', Target: 'Items/@UI.LineItem'}, - ], - FieldGroup#Details: { - Data: [ - {Value: currency.code, Label:'Currency'} - ] - }, - FieldGroup#Created: { - Data: [ - {Value: createdBy}, - {Value: createdAt}, - ] - }, - FieldGroup#Modified: { - Data: [ - {Value: modifiedBy}, - {Value: modifiedAt}, - ] - }, - }, -) { - createdAt @UI.HiddenFilter:false; - createdBy @UI.HiddenFilter:false; -}; - - - -annotate OrdersService.Orders.Items with @( - UI: { - LineItem: [ - {Value: product_ID, Label:'Product ID'}, - {Value: title, Label:'Product Title'}, - {Value: price, Label:'Unit Price'}, - {Value: quantity, Label:'Quantity'}, - ], - Identification: [ //Is the main field group - {Value: quantity, Label:'Quantity'}, - {Value: title, Label:'Product'}, - {Value: price, Label:'Unit Price'}, - ], - Facets: [ - {$Type: 'UI.ReferenceFacet', Label: '{i18n>OrderItems}', Target: '@UI.Identification'}, - ], - }, -) { - quantity @( - Common.FieldControl: #Mandatory - ); -}; diff --git a/orders/app/orders/index.html b/orders/app/orders/index.html deleted file mode 100644 index 6324cec3..00000000 --- a/orders/app/orders/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - Bookshop - - - - - - - - - - \ No newline at end of file diff --git a/orders/app/orders/webapp/Component.js b/orders/app/orders/webapp/Component.js deleted file mode 100644 index dff3acbc..00000000 --- a/orders/app/orders/webapp/Component.js +++ /dev/null @@ -1,8 +0,0 @@ -sap.ui.define(["sap/fe/core/AppComponent"], function(AppComponent) { - "use strict"; - return AppComponent.extend("orders.Component", { - metadata: { manifest: "json" } - }); -}); - -/* eslint no-undef:0 */ \ No newline at end of file diff --git a/orders/app/orders/webapp/i18n/i18n.properties b/orders/app/orders/webapp/i18n/i18n.properties deleted file mode 100644 index 28b03dff..00000000 --- a/orders/app/orders/webapp/i18n/i18n.properties +++ /dev/null @@ -1,11 +0,0 @@ -# This is the resource bundle of itelo -# __ldi.translation.uuid=c3431418-9caf-11e8-98d0-529269fb1459 - -# JCI app descriptor contains lower case TITLE -appTitle=Bookshop Sample - -# JCI app descriptor contains lower case DESCRIPTION -appSubTitle=CAP Sample Application - -# JCI app descriptor contains lower case DESCRIPTION -appDescription=CDS Sample Service diff --git a/orders/app/orders/webapp/manifest.json b/orders/app/orders/webapp/manifest.json deleted file mode 100644 index 045fa70a..00000000 --- a/orders/app/orders/webapp/manifest.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "_version": "1.8.0", - "sap.app": { - "id": "orders", - "type": "application", - "title": "Order Books", - "description": "Sample Application", - "i18n": "i18n/i18n.properties", - "dataSources": { - "OrdersService": { - "uri": "/orders/", - "type": "OData", - "settings": { - "odataVersion": "4.0" - } - } - }, - "-sourceTemplate": { - "id": "ui5template.basicSAPUI5ApplicationProject", - "-id": "ui5template.smartTemplate", - "-version": "1.40.12" - } - }, - "sap.ui5": { - "dependencies": { - "libs": { - "sap.fe.templates": {} - } - }, - "models": { - "i18n": { - "type": "sap.ui.model.resource.ResourceModel", - "uri": "i18n/i18n.properties" - }, - "": { - "dataSource": "OrdersService", - "settings": { - "synchronizationMode": "None", - "operationMode": "Server", - "autoExpandSelect" : true, - "earlyRequests": true, - "groupProperties": { - "default": { - "submit": "Auto" - } - } - } - } - }, - "routing": { - "routes": [ - { - "pattern": ":?query:", - "name": "OrdersList", - "target": "OrdersList" - }, - { - "pattern": "Orders({key}):?query:", - "name": "OrdersDetails", - "target": "OrdersDetails" - }, - { - "pattern": "Orders({boo})/Items({boo2}):?query:", - "name": "OrderItemsDetails", - "target": "OrderItemsDetails" - }, - { - "pattern": "Books({key}):?query:", - "name": "BooksDetails", - "target": "BooksDetails" - } - ], - "targets": { - "OrdersList": { - "type": "Component", - "id": "OrdersList", - "name": "sap.fe.templates.ListReport", - "options": { - "settings" : { - "entitySet" : "Orders", - "navigation" : { - "Orders" : { - "detail" : { - "route" : "OrdersDetails" - } - } - } - } - } - }, - "OrdersDetails": { - "type": "Component", - "id": "OrdersDetails", - "name": "sap.fe.templates.ObjectPage", - "options": { - "settings" : { - "entitySet": "Orders", - "navigation" : { - "Items": { - "detail": { - "route": "OrderItemsDetails" - } - }, - "book": { - "detail": { - "route": "BooksDetails" - } - }, - "dummy": { - "detail": { - "route": "BooksDetails" - } - } - } - } - } - }, - "OrderItemsDetails": { - "type": "Component", - "id": "OrderItemsDetails", - "name": "sap.fe.templates.ObjectPage", - "options": { - "settings" : { - "entitySet": "Orders_Items" - } - } - }, - "BooksDetails": { - "type": "Component", - "id": "BooksDetails", - "name": "sap.fe.templates.ObjectPage", - "options": { - "settings" : { - "entitySet": "Books", - "navigation": { - "author": { - "detail": { - "route": "AuthorsDetails" - } - } - } - } - } - }, - "AuthorsDetails": { - "type": "Component", - "id": "AuthorsDetails", - "name": "sap.fe.templates.ObjectPage", - "options": { - "settings" : { - "entitySet": "Authors" - } - } - } - } - }, - "contentDensities": { - "compact": true, - "cozy": true - } - }, - "sap.ui": { - "technology": "UI5", - "fullWidth": false - }, - "sap.fiori": { - "registrationIds": [], - "archeType": "transactional" - } -} \ No newline at end of file diff --git a/orders/db/_schema._cds b/orders/db/_schema._cds deleted file mode 100644 index 85effeaf..00000000 --- a/orders/db/_schema._cds +++ /dev/null @@ -1,24 +0,0 @@ -using { Currency, User, managed, cuid } from '@sap/cds/common'; -namespace sap.capire.orders; - -entity Orders : cuid, managed { - OrderNo : String @title:'Order Number'; //> readable key - Items : Composition of many { - key ID : UUID; - product : Association to Products; - quantity : Integer; - title : String; //> intentionally replicated as snapshot from product.title - price : Double; //> materialized calculated field - }; - buyer : User; - currency : Currency; -} - -/** This is a stand-in for arbitrary ordered Products */ -entity Products @(cds.persistence.skip:'always') { - key ID : String; -} - - -// this is to ensure we have filled-in currencies -using from '@capire/common'; diff --git a/orders/db/data/sap.capire.orders-OrdersHeaders.csv b/orders/db/data/sap.capire.orders-OrdersHeaders.csv deleted file mode 100644 index 6ad3d700..00000000 --- a/orders/db/data/sap.capire.orders-OrdersHeaders.csv +++ /dev/null @@ -1,3 +0,0 @@ -ID;createdAt;createdBy;buyer;OrderNo;currency_code -7e2f2640-6866-4dcf-8f4d-3027aa831cad;2019-01-31;john.doe@test.com;john.doe@test.com;1;EUR -64e718c9-ff99-47f1-8ca3-950c850777d4;2019-01-30;jane.doe@test.com;jane.doe@test.com;2;EUR \ No newline at end of file diff --git a/orders/db/data/sap.capire.orders-OrdersItems.csv b/orders/db/data/sap.capire.orders-OrdersItems.csv deleted file mode 100644 index ba7a87ef..00000000 --- a/orders/db/data/sap.capire.orders-OrdersItems.csv +++ /dev/null @@ -1,4 +0,0 @@ -ID;Header_ID;quantity;product_ID;title;price -58040e66-1dcd-4ffb-ab10-fdce32028b79;7e2f2640-6866-4dcf-8f4d-3027aa831cad;10;201;Wuthering Heights;11.11 -64e718c9-ff99-47f1-8ca3-950c850777d4;7e2f2640-6866-4dcf-8f4d-3027aa831cad;501;271;Catweazle;15 -e9641166-e050-4261-bfee-d1e797e6cb7f;64e718c9-ff99-47f1-8ca3-950c850777d4;499;252;Eleonora;28 \ No newline at end of file diff --git a/orders/db/schema.cds b/orders/db/schema.cds deleted file mode 100644 index 38b5fbed..00000000 --- a/orders/db/schema.cds +++ /dev/null @@ -1,32 +0,0 @@ -using { Currency, User, managed, cuid } from '@sap/cds/common'; -// using {Orders, OrderItems} from './schema'; - -namespace sap.capire.orders; - -entity Products { - key ID : String; -} - -entity OrdersHeaders : managed { - key ID : UUID; - OrderNo : String @title:'Order Number'; //> readable key - buyer : User; - currency : Currency; - Items : Composition of many OrdersItems on Items.Header = $self; -} - -entity OrdersItems { - key ID : UUID; - product : Association to Products; - quantity : Integer; - title : String; //> intentionally replicated as snapshot from product.title - price : Double; //> materialized calculated field - Header : Association to OrdersHeaders; -}; - - - - - - - diff --git a/orders/index.cds b/orders/index.cds deleted file mode 100644 index a79e9f65..00000000 --- a/orders/index.cds +++ /dev/null @@ -1,6 +0,0 @@ -/* - This model controls what gets exposed -*/ -namespace sap.capire.orders; -using from './srv/orders-service'; -using from './db/schema'; diff --git a/orders/package.json b/orders/package.json deleted file mode 100644 index 2685aa44..00000000 --- a/orders/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "@capire/orders", - "version": "1.0.0", - "dependencies": { - "@capire/common": "*", - "@sap/cds": ">=5" - } -} \ No newline at end of file diff --git a/orders/srv/_performance_example_orders-service._cds b/orders/srv/_performance_example_orders-service._cds deleted file mode 100644 index 119373db..00000000 --- a/orders/srv/_performance_example_orders-service._cds +++ /dev/null @@ -1,5 +0,0 @@ -using { sap.capire.orders as my } from '../db/schema'; - -service OrdersService { - entity Orders as projection on my.Orders; -} diff --git a/orders/srv/orders-service.cds b/orders/srv/orders-service.cds deleted file mode 100644 index c466e3e2..00000000 --- a/orders/srv/orders-service.cds +++ /dev/null @@ -1,87 +0,0 @@ -using { sap.capire.orders as my } from '../db/schema'; - -service OrdersService { - entity OrdersHeaders as projection on my.OrdersHeaders; - entity OrdersItems as projection on my.OrdersItems; - entity Products as projection on my.Products; - - -// static -view OrdersItemsViewJoin as select - - OrdersHeaders.ID as Header_ID, - OrdersHeaders.OrderNo as OrderNo, - OrdersHeaders.buyer as buyer, - OrdersHeaders.currency as currency, - key OrdersItems.ID as Item_ID, - OrdersItems.product as product, - OrdersItems.quantity as quantity, - OrdersItems.title as title, - OrdersItems.price as price - - from OrdersHeaders JOIN OrdersItems on OrdersHeaders.ID = OrdersItems.Header.ID; - -// dynamic entity -entity OrderItemsViewAssoc as projection on OrdersHeaders; - -// sort on right table -view SortedOrdersJoin as select - OrdersHeaders.ID as Header_ID, - OrdersHeaders.OrderNo as OrderNo, - OrdersHeaders.buyer as buyer, - OrdersHeaders.currency as currency, - key OrdersItems.ID as Item_ID, - OrdersItems.product as product, - OrdersItems.quantity as quantity, - OrdersItems.title as title, - OrdersItems.price as price -from OrdersHeaders JOIN OrdersItems on OrdersHeaders.ID = OrdersItems.Header.ID -order by title; - -// sort on items and join back to header via assoc - -view SortedOrdersAssoc as select -from OrdersItems {*, Header.OrderNo, Header.buyer, Header.currency } -order by OrdersItems.title; - -// filter on right table - -view FilteredOrdersJoin as select - OrdersHeaders.ID as Header_ID, - OrdersHeaders.OrderNo as OrderNo, - OrdersHeaders.buyer as buyer, - OrdersHeaders.currency as currency, - key OrdersItems.ID as Item_ID, - OrdersItems.product as product, - OrdersItems.quantity as quantity, - OrdersItems.title as title, - OrdersItems.price as price -from OrdersHeaders JOIN OrdersItems on OrdersHeaders.ID = OrdersItems.Header.ID -where price > 100; - -// filter on items and join back to header via assoc - -view FilteredOrdersAssoc as select -from OrdersItems {*, Header.OrderNo, Header.buyer, Header.currency } -where OrdersItems.price > 100; - - -// TODO avoid CASE and/or JOIN: Denormalization of expensive complex structures, -// calculate on write instead of read - -// CASE -> try to remodel to avoid CASE, if re-modelling is not possible, -// fill redundant fields at write - -entity OrdersItemsCaseView as projection on OrdersItems { - *, - case - when quantity > 500 then 'Large' - when quantity > 100 then 'Medium' - else 'Small' - end as category : String -}; - - - -} - diff --git a/orders/srv/orders-service.js b/orders/srv/orders-service.js deleted file mode 100644 index f395c077..00000000 --- a/orders/srv/orders-service.js +++ /dev/null @@ -1,37 +0,0 @@ -const cds = require ('@sap/cds') -class OrdersService extends cds.ApplicationService { - - /** register custom handlers */ - init(){ - const { 'Orders.Items':OrderItems } = this.entities - - this.before ('UPDATE', 'Orders', async function(req) { - const { ID, Items } = req.data - if (Items) for (let { product_ID, quantity } of Items) { - const { quantity:before } = await cds.tx(req).run ( - SELECT.one.from (OrderItems, oi => oi.quantity) .where ({up__ID:ID, product_ID}) - ) - if (quantity != before) await this.orderChanged (product_ID, quantity-before) - } - }) - - this.before ('DELETE', 'Orders', async function(req) { - const { ID } = req.data - const Items = await cds.tx(req).run ( - SELECT.from (OrderItems, oi => { oi.product_ID, oi.quantity }) .where ({up__ID:ID}) - ) - if (Items) await Promise.all (Items.map(it => this.orderChanged (it.product_ID, -it.quantity))) - }) - - return super.init() - } - - /** order changed -> broadcast event */ - orderChanged (product, deltaQuantity) { - // Emit events to inform subscribers about changes in orders - console.log ('> emitting:', 'OrderChanged', { product, deltaQuantity }) - return this.emit ('OrderChanged', { product, deltaQuantity }) - } - -} -module.exports = OrdersService diff --git a/performance/srv/performance-service.cds b/performance/srv/performance-service.cds index da745c25..a1e9e8e7 100644 --- a/performance/srv/performance-service.cds +++ b/performance/srv/performance-service.cds @@ -3,8 +3,8 @@ using { sap.capire.performance as my } from '../db/schema'; service PerformanceService { entity OrdersHeaders as projection on my.OrdersHeaders; entity OrdersItems as projection on my.OrdersItems; - entity Books as projection on my.Books; - entity Authors as projection on my.Authors; + entity Books as projection on my.Books; + entity Authors as projection on my.Authors; // static view OrdersItemsViewJoin as select @@ -66,7 +66,7 @@ from OrdersItems {*, Header.OrderNo, Header.buyer, Header.currency } where OrdersItems.price > 100; -// TODO avoid CASE and/or JOIN: Denormalization of expensive complex structures, +// TODO avoid CASE -- Denormalization of expensive complex structures, // calculate on write instead of read // CASE -> try to remodel to avoid CASE, if re-modelling is not possible, @@ -82,6 +82,14 @@ entity OrdersItemsCaseView as projection on OrdersItems { }; - +extend my.OrdersItems with { + itemCategory: String enum{ Small; Medium; Large;}; + // fill itemCategory at runtime in performance-service.js +} + +entity OrdersItemsNoCaseView as projection on OrdersItems { + *, + itemCategory as category +}; } diff --git a/performance/srv/performance-service.js b/performance/srv/performance-service.js index f395c077..86cdb41d 100644 --- a/performance/srv/performance-service.js +++ b/performance/srv/performance-service.js @@ -5,6 +5,14 @@ class OrdersService extends cds.ApplicationService { init(){ const { 'Orders.Items':OrderItems } = this.entities + // fill itemCategory at runtime + this.before (['CREATE', 'UPDATE'], async req =>{ + if(req.data.quantity > 500) {req.data.itemCategory = 'Large'} + else if (req.data.quantity > 100) {req.data.itemCategory = 'Medium'} + else {req.data.itemCategory = 'Small'} + }) + // + this.before ('UPDATE', 'Orders', async function(req) { const { ID, Items } = req.data if (Items) for (let { product_ID, quantity } of Items) {