diff --git a/README.md b/README.md index 9c94df18..dce6bb91 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,17 @@ In case you've a question, find a bug, or otherwise need support, use our [commu Copyright (c) 2021 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.txt) file. +# Suppliers - in progress for Service Consumption - + ## TODOs -1. Move `Suppliers` out of `API_BUSINESS_PARTNER` - remove additional lines in monkey patch --> Uwe -2. Fix problem with `await S4bupa.read (Suppliers).where('ID in',IDs)` --> Johannes -3. \ No newline at end of file +1. Fix problem with `await S4bupa.read (Suppliers).where('ID in',IDs)` --> Johannes +2. Fix issues when running in same process +3. Automated tests + +## Usage + +1. Run: `PORT=5001 cds mock API_BUSINESS_PARTNER` +2. Wait until startup is completed +3. Run in a 2nd terminal: `cds serve all --with-mocks --in-memory` +4. Now, you can issues the requests listed in `suppliers/requests.http` \ No newline at end of file diff --git a/suppliers/package.json b/suppliers/package.json index 109d8caa..1193c73b 100644 --- a/suppliers/package.json +++ b/suppliers/package.json @@ -18,6 +18,11 @@ "API_BUSINESS_PARTNER": { "kind": "odata", "model": "srv/external/API_BUSINESS_PARTNER" + }, + "[development]": { + "messaging": { + "kind": "file-based-messaging" + } } } } diff --git a/suppliers/requests.http b/suppliers/requests.http index 8877829c..5a28c19d 100644 --- a/suppliers/requests.http +++ b/suppliers/requests.http @@ -1,9 +1,9 @@ @server = http://localhost:4004 -@bpServer = http://localhost:59847 +@bpServer = http://localhost:5001 @authAlice = Authorization: Basic alice: -PATCH {{server}}/api-business-partner/A_BusinessPartner('ACME') +PATCH {{bpServer}}/api-business-partner/A_BusinessPartner('ACME') Content-Type: application/json { diff --git a/suppliers/srv/external/API_BUSINESS_PARTNER.js b/suppliers/srv/external/API_BUSINESS_PARTNER.js index d3f696d4..dcb2e7b6 100644 --- a/suppliers/srv/external/API_BUSINESS_PARTNER.js +++ b/suppliers/srv/external/API_BUSINESS_PARTNER.js @@ -1,10 +1,11 @@ const cds = require('@sap/cds'); -module.exports = cds.service.impl(function (srv) { +module.exports = cds.service.impl(async function (srv) { + const messaging = await cds.connect.to('messaging') const { A_BusinessPartner } = this.entities; srv.after('UPDATE', A_BusinessPartner, data => { console.log(`>>> BusinessPartner updated ${data.BusinessPartner}`); - srv.emit("BusinessPartners/Changed", { businessPartners: [ data.BusinessPartner ] }); + messaging.emit("BusinessPartners/Changed", { businessPartners: [ data.BusinessPartner ] }); }); }); diff --git a/suppliers/srv/external/data/API_BUSINESS_PARTNER-Suppliers.csv b/suppliers/srv/external/data/sap.capire.bookshop-Suppliers.csv similarity index 63% rename from suppliers/srv/external/data/API_BUSINESS_PARTNER-Suppliers.csv rename to suppliers/srv/external/data/sap.capire.bookshop-Suppliers.csv index cbb3ca2e..9648db87 100644 --- a/suppliers/srv/external/data/API_BUSINESS_PARTNER-Suppliers.csv +++ b/suppliers/srv/external/data/sap.capire.bookshop-Suppliers.csv @@ -1,5 +1,5 @@ ID;name -ACME;A Company Making Everything +ACME;A Company Making Everything (X) B4U;Books for You S&C;Shakespeare & Co. WSL;Waterstones diff --git a/suppliers/srv/mashup.cds b/suppliers/srv/mashup.cds index 6a445aba..173f5ab4 100644 --- a/suppliers/srv/mashup.cds +++ b/suppliers/srv/mashup.cds @@ -3,9 +3,12 @@ you actually want to use from there. */ +using { sap.capire.bookshop as bookshop } from '@capire/bookshop'; using { API_BUSINESS_PARTNER as S4 } from './external/API_BUSINESS_PARTNER.csn'; -extend service S4 with { - entity Suppliers as projection on S4.A_BusinessPartner { + +@cds.autoexpose // or expose explicitly in Catalog and AdminService +@cds.persistence: {table,skip:false} // add persistency +entity sap.capire.bookshop.Suppliers as projection on S4.A_BusinessPartner { // TODO: Aliases not supported in Java, yet? key BusinessPartner as ID, BusinessPartnerFullName as name, @@ -21,27 +24,28 @@ extend service S4 with { // REVISIT: following is not supported so far in cqn2odata... // to_BusinessPartnerAddress.CityCode as city, // to_BusinessPartnerAddress.CityName as city_name, - } - - - // REVISIT: Alternative idea to use a specific replication view, but request data from - // a different view and manual map values. - // entity ReplicatedSuppliers as projection on Suppliers { - // ID, - // name, - // to_BusinessPartnerAddress.CityCode as city, - // to_BusinessPartnerAddress.CityName as city_name - // } } +// REVISIT: Alternative idea to use a specific replication view, but request data from +// a different view and manual map values. +// entity ReplicatedSuppliers as projection on Suppliers { +// ID, +// name, +// to_BusinessPartnerAddress.CityCode as city, +// to_BusinessPartnerAddress.CityName as city_name +// } + + + + /* You can mashup entities from external services, or projections thereof, with your project's own entities */ using { sap.capire.bookshop.Books, CatalogService } from '@capire/bookshop'; extend Books with { - supplier : Association to S4.Suppliers; + supplier : Association to bookshop.Suppliers; } @@ -51,15 +55,9 @@ extend Books with { addressed to your services into calls to the external service. */ extend service AdminService with { - entity Suppliers as projection on S4.Suppliers; + entity Suppliers as projection on bookshop.Suppliers; } -/* - Optionally add a local persistence to keep replicas of external - entities to have data in fast access locally; much like a cache. - */ -annotate S4.Suppliers with @cds.persistence:{table,skip:false}; - /** Having locally cached replicas also allows us to display supplier data in lists of books, which otherwise would generate unwanted diff --git a/suppliers/srv/mashup.js b/suppliers/srv/mashup.js index 2fdb1ac6..5c70556e 100644 --- a/suppliers/srv/mashup.js +++ b/suppliers/srv/mashup.js @@ -10,9 +10,10 @@ module.exports = async()=>{ // called by server.js const S4bupa = await cds.connect.to('API_BUSINESS_PARTNER') //> external S4 service const admin = await cds.connect.to('AdminService') //> local domain service const db = await cds.connect.to('db') //> our primary database + const messaging = await cds.connect.to('messaging'); // Reflect CDS definition of the Suppliers entity - const { Suppliers } = S4bupa.entities + const Suppliers = db.entities["sap.capire.bookshop.Suppliers"]; admin.prepend (()=>{ //> to ensure our .on handlers below go before the default ones @@ -38,9 +39,9 @@ module.exports = async()=>{ // called by server.js }) // Subscribe to changes in the S4 origin of Suppliers data - // REVISIT: cds context is still from the UPDAT method when running in same programm, but should + // REVISIT: cds context is still from the UPDATE method when running in same programm, but should // be a separate - S4bupa.on ('BusinessPartners/Changed', async msg => { //> would be great if we had batch events from S/4 + messaging.on ('BusinessPartners/Changed', async msg => { //> would be great if we had batch events from S/4 await new Promise( resolve => setTimeout( resolve, 1000 )); const tx = cds.db.tx(msg); let replicas = await tx.run(SELECT('ID').from (Suppliers) .where ('ID in', msg.data.businessPartners)); @@ -79,4 +80,25 @@ module.exports = async()=>{ // called by server.js )) } + + { + // one server: returns AdminSuppliers + // two servers: returns A_BusinessPartner + const tx = S4bupa.tx({}); + let result = await tx.run(SELECT('*').from ('AdminService.Suppliers') .where ('ID =', 'ACME')); + tx.commit(); + console.log(result); + } + + { + // one server: returns AdminSuppliers + // two servers: returns AdminSuppliers + const tx = db.tx({}); + let result = await db.run(SELECT('*').from ('AdminService.Suppliers') .where ('ID =', 'ACME')); + tx.commit(); + console.log(result); + } + + //process.exit(0); + }