Updated to use srv-to-srv + declared events
This commit is contained in:
@@ -9,7 +9,6 @@ const cds = require ('@sap/cds')
|
|||||||
cds.once('served', async ({CatalogService}) => {
|
cds.once('served', async ({CatalogService}) => {
|
||||||
|
|
||||||
const ReviewsService = await cds.connect.to('ReviewsService')
|
const ReviewsService = await cds.connect.to('ReviewsService')
|
||||||
const messaging = await cds.connect.to('messaging')
|
|
||||||
|
|
||||||
// reflect entity definitions used below...
|
// reflect entity definitions used below...
|
||||||
const { Books } = cds.entities('sap.capire.bookshop')
|
const { Books } = cds.entities('sap.capire.bookshop')
|
||||||
@@ -22,7 +21,7 @@ cds.once('served', async ({CatalogService}) => {
|
|||||||
return SELECT(columns).from(Reviews).limit(limit).where({subject:String(id)})
|
return SELECT(columns).from(Reviews).limit(limit).where({subject:String(id)})
|
||||||
}))
|
}))
|
||||||
|
|
||||||
messaging.on ('reviewed', (msg) => {
|
ReviewsService.on ('reviewed', (msg) => {
|
||||||
console.debug ('> received:', msg.event, msg.data)
|
console.debug ('> received:', msg.event, msg.data)
|
||||||
const { subject, rating } = msg.data
|
const { subject, rating } = msg.data
|
||||||
return UPDATE(Books,subject).with({rating})
|
return UPDATE(Books,subject).with({rating})
|
||||||
|
|||||||
@@ -2,10 +2,17 @@ using { sap.capire.reviews as my } from '../db/schema';
|
|||||||
|
|
||||||
service ReviewsService {
|
service ReviewsService {
|
||||||
|
|
||||||
|
// Sync API
|
||||||
entity Reviews as projection on my.Reviews excluding { likes }
|
entity Reviews as projection on my.Reviews excluding { likes }
|
||||||
action like (review: type of Reviews:ID);
|
action like (review: type of Reviews:ID);
|
||||||
action unlike (review: type of Reviews:ID);
|
action unlike (review: type of Reviews:ID);
|
||||||
|
|
||||||
|
// Async API
|
||||||
|
event reviewed : {
|
||||||
|
subject: type of Reviews:subject;
|
||||||
|
rating: Decimal(2,1)
|
||||||
|
}
|
||||||
|
|
||||||
// Input validation
|
// Input validation
|
||||||
annotate Reviews with {
|
annotate Reviews with {
|
||||||
subject @mandatory;
|
subject @mandatory;
|
||||||
|
|||||||
@@ -4,27 +4,26 @@ module.exports = cds.service.impl (async function(){
|
|||||||
// Get the CSN definition for Reviews from the db schema for sub-sequent queries
|
// Get the CSN definition for Reviews from the db schema for sub-sequent queries
|
||||||
// ( Note: we explicitly specify the namespace to support embedded reuse )
|
// ( Note: we explicitly specify the namespace to support embedded reuse )
|
||||||
const { Reviews, Likes } = this.entities ('sap.capire.reviews')
|
const { Reviews, Likes } = this.entities ('sap.capire.reviews')
|
||||||
const messaging = await cds.connect.to('messaging')
|
|
||||||
|
|
||||||
this.before (['CREATE','UPDATE'], 'Reviews', req => {
|
this.before (['CREATE','UPDATE'], 'Reviews', req => {
|
||||||
if (!req.data.rating) req.data.rating = Math.round(Math.random()*4)+1
|
if (!req.data.rating) req.data.rating = Math.round(Math.random()*4)+1
|
||||||
})
|
})
|
||||||
|
|
||||||
// Emit an event to inform subscribers about new avg ratings for reviewed subjects
|
// Emit an event to inform subscribers about new avg ratings for reviewed subjects
|
||||||
this.after (['CREATE','UPDATE','DELETE'], 'Reviews', async(_,req) => {
|
this.after (['CREATE','UPDATE','DELETE'], 'Reviews', async function(_,req) {
|
||||||
const {subject} = req.data
|
const {subject} = req.data
|
||||||
const {rating} = await cds.transaction(req) .run (
|
const {rating} = await cds.tx(req) .run (
|
||||||
SELECT.one (['round(avg(rating),2) as rating']) .from (Reviews) .where ({subject})
|
SELECT.one (['round(avg(rating),2) as rating']) .from (Reviews) .where ({subject})
|
||||||
)
|
)
|
||||||
global.it || console.log ('< emitting:', 'reviewed', { subject, rating })
|
global.it || console.log ('< emitting:', 'reviewed', { subject, rating })
|
||||||
messaging.tx(req).emit ('reviewed', { subject, rating })
|
this.emit ('reviewed', { subject, rating })
|
||||||
})
|
})
|
||||||
|
|
||||||
// Increment counter for reviews considered helpful
|
// Increment counter for reviews considered helpful
|
||||||
this.on ('like', (req) => {
|
this.on ('like', (req) => {
|
||||||
if (!req.user) return req.reject(400, 'You must be identified to like a review')
|
if (!req.user) return req.reject(400, 'You must be identified to like a review')
|
||||||
const {review} = req.data, {user} = req
|
const {review} = req.data, {user} = req
|
||||||
const tx = cds.transaction(req)
|
const tx = cds.tx(req)
|
||||||
return tx.run ([
|
return tx.run ([
|
||||||
INSERT.into (Likes) .entries ({review_ID: review, user: user.id}),
|
INSERT.into (Likes) .entries ({review_ID: review, user: user.id}),
|
||||||
UPDATE (Reviews) .set({liked: {'+=': 1}}) .where({ID:review})
|
UPDATE (Reviews) .set({liked: {'+=': 1}}) .where({ID:review})
|
||||||
@@ -35,7 +34,7 @@ module.exports = cds.service.impl (async function(){
|
|||||||
this.on ('unlike', async (req) => {
|
this.on ('unlike', async (req) => {
|
||||||
if (!req.user) return req.reject(400, 'You must be identified to remove a former like of yours')
|
if (!req.user) return req.reject(400, 'You must be identified to remove a former like of yours')
|
||||||
const {review} = req.data, {user} = req
|
const {review} = req.data, {user} = req
|
||||||
const tx = cds.transaction(req)
|
const tx = cds.tx(req)
|
||||||
const affectedRows = await tx.run (DELETE.from (Likes) .where ({review_ID: review,user: user.id}))
|
const affectedRows = await tx.run (DELETE.from (Likes) .where ({review_ID: review,user: user.id}))
|
||||||
if (affectedRows === 1) return tx.run (UPDATE (Reviews) .set ({liked: {'-=': 1}}) .where ({ID:review}))
|
if (affectedRows === 1) return tx.run (UPDATE (Reviews) .set ({liked: {'-=': 1}}) .where ({ID:review}))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
const cwd = process.cwd(); process.chdir (__dirname) //> only for internal CI/CD@SAP
|
const cwd = process.cwd(); process.chdir (__dirname) //> only for internal CI/CD@SAP
|
||||||
const cds = require ('./cds'), {expect} = cds.test
|
const cds = require ('./cds'), {expect} = cds.test
|
||||||
const _model = '@capire/reviews'
|
const _model = '@capire/reviews'
|
||||||
let messaging
|
|
||||||
|
|
||||||
|
|
||||||
describe('Messaging', ()=>{
|
describe('Messaging', ()=>{
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
messaging = await cds.connect.to('messaging')
|
|
||||||
})
|
|
||||||
after(()=> process.chdir(cwd))
|
after(()=> process.chdir(cwd))
|
||||||
|
|
||||||
it ('should bootstrap sqlite in-memory db', async()=>{
|
it ('should bootstrap sqlite in-memory db', async()=>{
|
||||||
@@ -24,11 +20,11 @@ describe('Messaging', ()=>{
|
|||||||
|
|
||||||
let N=0, received=[], M=0
|
let N=0, received=[], M=0
|
||||||
it ('should add messaging event handlers', ()=>{
|
it ('should add messaging event handlers', ()=>{
|
||||||
messaging.on('reviewed', (msg,next)=> { received.push(msg); return next() })
|
srv.on('reviewed', (msg,next)=> { received.push(msg); return next() })
|
||||||
})
|
})
|
||||||
|
|
||||||
it ('should add more messaging event handlers', ()=>{
|
it ('should add more messaging event handlers', ()=>{
|
||||||
messaging.on('reviewed', (_,next)=> { ++M; return next() })
|
srv.on('reviewed', (_,next)=> { ++M; return next() })
|
||||||
})
|
})
|
||||||
|
|
||||||
it ('should add review', async ()=>{
|
it ('should add review', async ()=>{
|
||||||
|
|||||||
Reference in New Issue
Block a user