Compare commits
7 Commits
new-capire
...
ord-servic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ccd11062a | ||
|
|
20348e0776 | ||
|
|
6acd5338d9 | ||
|
|
413d4de745 | ||
|
|
23bea0f629 | ||
|
|
8c6ba30673 | ||
|
|
06956b1077 |
@@ -19,13 +19,13 @@ const books = Vue.createApp ({
|
|||||||
search: ({target:{value:v}}) => books.fetch(v && '&$search='+v),
|
search: ({target:{value:v}}) => books.fetch(v && '&$search='+v),
|
||||||
|
|
||||||
async fetch (etc='') {
|
async fetch (etc='') {
|
||||||
const {data} = await GET(`/Books?${etc}`)
|
const {data} = await GET(`/ListOfBooks?$expand=genre($select=name),currency($select=symbol)${etc}`)
|
||||||
books.list = data.value
|
books.list = data.value
|
||||||
},
|
},
|
||||||
|
|
||||||
async inspect (eve) {
|
async inspect (eve) {
|
||||||
const book = books.book = books.list [eve.currentTarget.rowIndex-1]
|
const book = books.book = books.list [eve.currentTarget.rowIndex-1]
|
||||||
const res = await GET(`/Book/${book.ID}?$select=descr,stock,image`)
|
const res = await GET(`/Books/${book.ID}?$select=descr,stock,image`)
|
||||||
Object.assign (book, res.data)
|
Object.assign (book, res.data)
|
||||||
books.order = { quantity:1 }
|
books.order = { quantity:1 }
|
||||||
setTimeout (()=> $('form > input').focus(), 111)
|
setTimeout (()=> $('form > input').focus(), 111)
|
||||||
|
|||||||
@@ -45,11 +45,11 @@
|
|||||||
<tr v-for="book in list" v-bind:id="book.ID" v-on:click="inspect">
|
<tr v-for="book in list" v-bind:id="book.ID" v-on:click="inspect">
|
||||||
<td>{{ book.title }}</td>
|
<td>{{ book.title }}</td>
|
||||||
<td>{{ book.author }}</td>
|
<td>{{ book.author }}</td>
|
||||||
<td>{{ book.genre }}</td>
|
<td>{{ book.genre.name }}</td>
|
||||||
<td class="rating-stars">
|
<td class="rating-stars">
|
||||||
{{ ('★'.repeat(Math.round(book.rating))+'☆☆☆☆☆').slice(0,5) }} ({{ book.numberOfReviews }})
|
{{ ('★'.repeat(Math.round(book.rating))+'☆☆☆☆☆').slice(0,5) }} ({{ book.numberOfReviews }})
|
||||||
</td>
|
</td>
|
||||||
<td>{{ book.currency }} {{ book.price }}</td>
|
<td>{{ book.currency && book.currency.symbol }} {{ book.price }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"@cap-js/sqlite": "*"
|
"@cap-js/sqlite": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@cap-js/ord": "2",
|
||||||
"@sap/cds": ">=7",
|
"@sap/cds": ">=7",
|
||||||
"express": "^4.17.1"
|
"express": "^4.17.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using { sap.capire.bookshop as my } from '../db/schema';
|
using { sap.capire.bookshop as my } from '../db/schema';
|
||||||
service AdminService @(requires:'admin', path:'/admin') {
|
service AdminService @(requires:'admin', path:'/admin') {
|
||||||
entity Books as projection on my.Books;
|
entity Books as projection on my.Books;
|
||||||
// entity Authors as projection on my.Authors;
|
entity Authors as projection on my.Authors;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,15 @@ using { sap.capire.bookshop as my } from '../db/schema';
|
|||||||
service CatalogService @(path:'/browse') {
|
service CatalogService @(path:'/browse') {
|
||||||
|
|
||||||
/** For displaying lists of Books */
|
/** For displaying lists of Books */
|
||||||
@readonly entity Books as projection on Book excluding { descr };
|
@readonly entity ListOfBooks as projection on Books
|
||||||
|
excluding { descr };
|
||||||
|
|
||||||
/** For display in details pages */
|
/** For display in details pages */
|
||||||
@readonly entity Book as projection on my.Books { *,
|
@readonly entity Books as projection on my.Books { *,
|
||||||
currency.name as currencyName, // flattened
|
author.name as author
|
||||||
currency.symbol as currency, // flattened
|
} excluding { createdBy, modifiedBy };
|
||||||
author.name as author, // flattened
|
|
||||||
genre.name as genre, // flattened
|
|
||||||
} excluding {
|
|
||||||
createdBy, modifiedBy, // as end users shouldn't see them
|
|
||||||
localized, texts, // as end users don't need them
|
|
||||||
};
|
|
||||||
|
|
||||||
@requires: 'authenticated-user'
|
@requires: 'authenticated-user'
|
||||||
action submitOrder ( book: Book:ID, quantity: Integer ) returns { stock: Integer };
|
action submitOrder ( book: Books:ID, quantity: Integer ) returns { stock: Integer };
|
||||||
event OrderedBook : { book: Book:ID; quantity: Integer; buyer: String };
|
event OrderedBook : { book: Books:ID; quantity: Integer; buyer: String };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ const cds = require('@sap/cds')
|
|||||||
class CatalogService extends cds.ApplicationService { init() {
|
class CatalogService extends cds.ApplicationService { init() {
|
||||||
|
|
||||||
const { Books } = cds.entities('sap.capire.bookshop')
|
const { Books } = cds.entities('sap.capire.bookshop')
|
||||||
const { Books:Book } = this.entities
|
const { ListOfBooks } = this.entities
|
||||||
|
|
||||||
// Add some discount for overstocked books
|
// Add some discount for overstocked books
|
||||||
this.after('each', Book, book => {
|
this.after('each', ListOfBooks, book => {
|
||||||
if (book.stock > 111) book.title += ` -- 11% discount!`
|
if (book.stock > 111) book.title += ` -- 11% discount!`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
@server = http://localhost:4004
|
@server = http://localhost:4004
|
||||||
@me = Authorization: Basic {{$processEnv USER}}:
|
@me = Authorization: Basic {{$processEnv USER}}:
|
||||||
@alice = Authorization: Basic alice:
|
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
### ------------------------------------------------------------------------
|
||||||
@@ -17,11 +16,11 @@ GET {{server}}/browse/$metadata
|
|||||||
|
|
||||||
### ------------------------------------------------------------------------
|
### ------------------------------------------------------------------------
|
||||||
# Browse Books as any user
|
# Browse Books as any user
|
||||||
GET {{server}}/admin/Books?
|
GET {{server}}/browse/ListOfBooks?
|
||||||
# &$select=title,stock
|
# &$select=title,stock
|
||||||
&$expand=genre
|
&$expand=genre
|
||||||
# &sap-language=de
|
# &sap-language=de
|
||||||
{{alice}}
|
{{me}}
|
||||||
|
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
### ------------------------------------------------------------------------
|
||||||
@@ -31,13 +30,13 @@ GET {{server}}/admin/Authors?
|
|||||||
# &$expand=books($select=title;$expand=currency)
|
# &$expand=books($select=title;$expand=currency)
|
||||||
# &$filter=ID eq 101
|
# &$filter=ID eq 101
|
||||||
# &sap-language=de
|
# &sap-language=de
|
||||||
{{alice}}
|
Authorization: Basic alice:
|
||||||
|
|
||||||
### ------------------------------------------------------------------------
|
### ------------------------------------------------------------------------
|
||||||
# Create Author
|
# Create Author
|
||||||
POST {{server}}/admin/Authors
|
POST {{server}}/admin/Authors
|
||||||
Content-Type: application/json;IEEE754Compatible=true
|
Content-Type: application/json;IEEE754Compatible=true
|
||||||
{{alice}}
|
Authorization: Basic alice:
|
||||||
|
|
||||||
{
|
{
|
||||||
"ID": 112,
|
"ID": 112,
|
||||||
@@ -50,7 +49,7 @@ Content-Type: application/json;IEEE754Compatible=true
|
|||||||
# Create book
|
# Create book
|
||||||
POST {{server}}/admin/Books
|
POST {{server}}/admin/Books
|
||||||
Content-Type: application/json;IEEE754Compatible=true
|
Content-Type: application/json;IEEE754Compatible=true
|
||||||
{{alice}}
|
Authorization: Basic alice:
|
||||||
|
|
||||||
{
|
{
|
||||||
"ID": 2,
|
"ID": 2,
|
||||||
@@ -68,7 +67,7 @@ Content-Type: application/json;IEEE754Compatible=true
|
|||||||
# Put image to books
|
# Put image to books
|
||||||
PUT {{server}}/admin/Books(2)/image
|
PUT {{server}}/admin/Books(2)/image
|
||||||
Content-Type: image/png
|
Content-Type: image/png
|
||||||
{{alice}}
|
Authorization: Basic alice:
|
||||||
|
|
||||||
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAADcCAYAAAAbWs+BAAAGwElEQVR4Ae3cwZFbNxBFUY5rkrDTmKAUk5QT03Aa44U22KC7NHptw+DRikVAXf8fzC3u8Hj4R4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgZzAW26USQT+e4HPx+Mz+RRvj0e0kT+SD2cWAQK1gOBqH6sEogKCi3IaRqAWEFztY5VAVEBwUU7DCNQCgqt9rBKICgguymkYgVpAcLWPVQJRAcFFOQ0jUAsIrvaxSiAqILgop2EEagHB1T5WCUQFBBflNIxALSC42scqgaiA4KKchhGoBQRX+1glEBUQXJTTMAK1gOBqH6sEogKCi3IaRqAWeK+Xb1z9iN558fHxcSPS9p2ezx/ROz4e4TtIHt+3j/61hW9f+2+7/+UXbifjewIDAoIbQDWSwE5AcDsZ3xMYEBDcAKqRBHYCgtvJ+J7AgIDgBlCNJLATENxOxvcEBgQEN4BqJIGdgOB2Mr4nMCAguAFUIwnsBAS3k/E9gQEBwQ2gGklgJyC4nYzvCQwICG4A1UgCOwHB7WR8T2BAQHADqEYS2AkIbifjewIDAoIbQDWSwE5AcDsZ3xMYEEjfTzHwiK91B8npd6Q8n8/oGQ/ckRJ9vvQwv3BpUfMIFAKCK3AsEUgLCC4tah6BQkBwBY4lAmkBwaVFzSNQCAiuwLFEIC0guLSoeQQKAcEVOJYIpAUElxY1j0AhILgCxxKBtIDg0qLmESgEBFfgWCKQFhBcWtQ8AoWA4AocSwTSAoJLi5pHoBAQXIFjiUBaQHBpUfMIFAKCK3AsEUgLCC4tah6BQmDgTpPsHSTFs39p6fQ7Q770UsV/Ov19X+2OFL9wxR+rJQJpAcGlRc0jUAgIrsCxRCAtILi0qHkECgHBFTiWCKQFBJcWNY9AISC4AscSgbSA4NKi5hEoBARX4FgikBYQXFrUPAKFgOAKHEsE0gKCS4uaR6AQEFyBY4lAWkBwaVHzCBQCgitwLBFICwguLWoegUJAcAWOJQJpAcGlRc0jUAgIrsCxRCAt8J4eePq89B0ar3ZnyOnve/rfn1+400/I810lILirjtPLnC4guNNPyPNdJSC4q47Ty5wuILjTT8jzXSUguKuO08ucLiC400/I810lILirjtPLnC4guNNPyPNdJSC4q47Ty5wuILjTT8jzXSUguKuO08ucLiC400/I810lILirjtPLnC4guNNPyPNdJSC4q47Ty5wuILjTT8jzXSUguKuO08ucLiC400/I810l8JZ/m78+szP/zI47fJo7Q37vgJ7PHwN/07/3TOv/9gu3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhAcMPAxhNYBQS3avhMYFhg4P6H9J0maYHXuiMlrXf+vOfA33Turf3C5SxNItAKCK4lsoFATkBwOUuTCLQCgmuJbCCQExBcztIkAq2A4FoiGwjkBASXszSJQCsguJbIBgI5AcHlLE0i0AoIriWygUBOQHA5S5MItAKCa4lsIJATEFzO0iQCrYDgWiIbCOQEBJezNIlAKyC4lsgGAjkBweUsTSLQCgiuJbKBQE5AcDlLkwi0Akff//Dz6U+/I6U1/sUNr3bnytl3kPzi4bXb/cK1RDYQyAkILmdpEoFWQHAtkQ0EcgKCy1maRKAVEFxLZAOBnIDgcpYmEWgFBNcS2UAgJyC4nKVJBFoBwbVENhDICQguZ2kSgVZAcC2RDQRyAoLLWZpEoBUQXEtkA4GcgOByliYRaAUE1xLZQCAnILicpUkEWgHBtUQ2EMgJCC5naRKBVkBwLZENBHIC/4M7TXIv+3PS22d24qvdQfL3C/7N5P5i/MLlLE0i0AoIriWygUBOQHA5S5MItAKCa4lsIJATEFzO0iQCrYDgWiIbCOQEBJezNIlAKyC4lsgGAjkBweUsTSLQCgiuJbKBQE5AcDlLkwi0AoJriWwgkBMQXM7SJAKtgOBaIhsI5AQEl7M0iUArILiWyAYCOQHB5SxNItAKCK4lsoFATkBwOUuTCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAvyrwDySEJ2VQgUSoAAAAAElFTkSuQmCC
|
data:image/png;base64,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
|
||||||
|
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ module.exports = async()=>{ // called by server.js
|
|||||||
//
|
//
|
||||||
CatalogService.on ('OrderedBook', async (msg) => {
|
CatalogService.on ('OrderedBook', async (msg) => {
|
||||||
const { book, quantity, buyer } = msg.data
|
const { book, quantity, buyer } = msg.data
|
||||||
const { title, price } = await db.tx(msg).read (Books, book, b => { b.title, b.price })
|
const { title, price } = await db.read (Books, book, b => { b.title, b.price })
|
||||||
return OrdersService.tx(msg).create ('Orders').entries({
|
return OrdersService.create ('Orders').entries({
|
||||||
OrderNo: 'Order at '+ (new Date).toLocaleString(),
|
OrderNo: 'Order at '+ (new Date).toLocaleString(),
|
||||||
Items: [{ product:{ID:`${book}`}, title, price, quantity }],
|
Items: [{ product:{ID:`${book}`}, title, price, quantity }],
|
||||||
buyer, createdBy: buyer
|
buyer, createdBy: buyer
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using CatalogService from '@capire/bookstore';
|
|||||||
//
|
//
|
||||||
// Books Object Page
|
// Books Object Page
|
||||||
//
|
//
|
||||||
annotate CatalogService.Book with @(UI : {
|
annotate CatalogService.Books with @(UI : {
|
||||||
HeaderInfo : {
|
HeaderInfo : {
|
||||||
TypeName : '{i18n>Book}',
|
TypeName : '{i18n>Book}',
|
||||||
TypeNamePlural : '{i18n>Books}',
|
TypeNamePlural : '{i18n>Books}',
|
||||||
@@ -24,7 +24,7 @@ annotate CatalogService.Book with @(UI : {
|
|||||||
FieldGroup #Price : {Data : [
|
FieldGroup #Price : {Data : [
|
||||||
{Value : price},
|
{Value : price},
|
||||||
{
|
{
|
||||||
Value : currencyName,
|
Value : currency.symbol,
|
||||||
Label : '{i18n>Currency}'
|
Label : '{i18n>Currency}'
|
||||||
},
|
},
|
||||||
]},
|
]},
|
||||||
@@ -35,11 +35,11 @@ annotate CatalogService.Book with @(UI : {
|
|||||||
//
|
//
|
||||||
// Books List Page
|
// Books List Page
|
||||||
//
|
//
|
||||||
annotate CatalogService.Book with @(UI : {
|
annotate CatalogService.Books with @(UI : {
|
||||||
SelectionFields : [
|
SelectionFields : [
|
||||||
ID,
|
ID,
|
||||||
price,
|
price,
|
||||||
currencyName
|
currency_code
|
||||||
],
|
],
|
||||||
LineItem : [
|
LineItem : [
|
||||||
{
|
{
|
||||||
@@ -50,10 +50,8 @@ annotate CatalogService.Book with @(UI : {
|
|||||||
Value : author,
|
Value : author,
|
||||||
Label : '{i18n>Author}'
|
Label : '{i18n>Author}'
|
||||||
},
|
},
|
||||||
{Value : genre},
|
{Value : genre.name},
|
||||||
{Value : price},
|
{Value : price},
|
||||||
{Value : currencyName},
|
{Value : currency.symbol},
|
||||||
]
|
]
|
||||||
}) {
|
}, );
|
||||||
currencyName @Common.Label : '{i18n>Currency}';
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ annotate my.Books with @(
|
|||||||
ID,
|
ID,
|
||||||
author_ID,
|
author_ID,
|
||||||
price,
|
price,
|
||||||
|
currency_code
|
||||||
],
|
],
|
||||||
LineItem : [
|
LineItem : [
|
||||||
{ Value: ID, Label: '{i18n>Title}' },
|
{ Value: ID, Label: '{i18n>Title}' },
|
||||||
@@ -25,6 +26,7 @@ annotate my.Books with @(
|
|||||||
{ Value: genre.name },
|
{ Value: genre.name },
|
||||||
{ Value: stock },
|
{ Value: stock },
|
||||||
{ Value: price },
|
{ Value: price },
|
||||||
|
{ Value: currency.symbol },
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@@ -61,7 +63,7 @@ annotate my.Books with {
|
|||||||
title @title: '{i18n>Title}';
|
title @title: '{i18n>Title}';
|
||||||
genre @title: '{i18n>Genre}' @Common: { Text: genre.name, TextArrangement: #TextOnly };
|
genre @title: '{i18n>Genre}' @Common: { Text: genre.name, TextArrangement: #TextOnly };
|
||||||
author @title: '{i18n>Author}' @Common: { Text: author.name, TextArrangement: #TextOnly };
|
author @title: '{i18n>Author}' @Common: { Text: author.name, TextArrangement: #TextOnly };
|
||||||
price @title: '{i18n>Price}' @Measures.ISOCurrency : currency;
|
price @title: '{i18n>Price}' @Measures.ISOCurrency : currency_code;
|
||||||
stock @title: '{i18n>Stock}';
|
stock @title: '{i18n>Stock}';
|
||||||
descr @title: '{i18n>Description}' @UI.MultiLineText;
|
descr @title: '{i18n>Description}' @UI.MultiLineText;
|
||||||
image @title: '{i18n>Image}';
|
image @title: '{i18n>Image}';
|
||||||
|
|||||||
1
ord/cds-plugin.js
Normal file
1
ord/cds-plugin.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// just a dummy tag file to be identified as a plugin
|
||||||
12
ord/package.json
Normal file
12
ord/package.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "@cap-js/ord",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"cds": {
|
||||||
|
"requires": {
|
||||||
|
"SAP ORD Service": {
|
||||||
|
"model": "@cap-js/ord/srv/ord-service",
|
||||||
|
"service": "OrdService"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
ord/srv/ord-service.cds
Normal file
12
ord/srv/ord-service.cds
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// @requires: 'ORDconsumer'
|
||||||
|
@rest @path:'/ord/v1'
|
||||||
|
service OrdService {
|
||||||
|
@readonly entity documents {
|
||||||
|
key id: String;
|
||||||
|
}
|
||||||
|
@readonly entity csn {
|
||||||
|
key id: String;
|
||||||
|
}
|
||||||
|
|
||||||
|
function api (service: String, format: String) returns {};
|
||||||
|
}
|
||||||
73
ord/srv/ord-service.mjs
Normal file
73
ord/srv/ord-service.mjs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import cds from '@sap/cds'
|
||||||
|
export class OrdService extends cds.ApplicationService {
|
||||||
|
init(){
|
||||||
|
|
||||||
|
this.on('READ','documents', req => {
|
||||||
|
let csn = cds.context?.model || cds.model
|
||||||
|
return { ord: csn }
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just an example to do something with id, if given.
|
||||||
|
* Try it out with URLs like that:
|
||||||
|
*
|
||||||
|
* - http://localhost:4004/ord/v1/documents
|
||||||
|
* - http://localhost:4004/ord/v1/documents/CatalogService
|
||||||
|
* - http://localhost:4004/ord/v1/documents/CatalogService.Books
|
||||||
|
* - http://localhost:4004/ord/v1/documents/CatalogService.Authors
|
||||||
|
*/
|
||||||
|
this.on('READ','csn', req => {
|
||||||
|
let csn = cds.context?.model || cds.model
|
||||||
|
let { id } = req.data
|
||||||
|
if (id) csn = csn.definitions[id] || 'not in model!'
|
||||||
|
return { id, csn }
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just an example to serve arbitrary content with a function.
|
||||||
|
* Try it out with URLs like that:
|
||||||
|
*
|
||||||
|
* - http://localhost:4004/ord/v1/api?service=CatalogService
|
||||||
|
* - http://localhost:4004/ord/v1/api?service=CatalogService&format=edmx
|
||||||
|
* - http://localhost:4004/ord/v1/api?service=CatalogService&format=edmx-v2
|
||||||
|
* - http://localhost:4004/ord/v1/api?service=CatalogService&format=openapi
|
||||||
|
*/
|
||||||
|
this.on('api', req => {
|
||||||
|
let csn = cds.context?.model || cds.model
|
||||||
|
let { service, format = 'csn' } = req.data
|
||||||
|
let { res } = req.http
|
||||||
|
if (format === 'csn') {
|
||||||
|
if (!service) return res.send(csn)
|
||||||
|
service = csn.services[service]
|
||||||
|
return res.send({ definitions: [ service, ...service.entities ] .reduce ((all,e) => {
|
||||||
|
let d = all[e.name] = {...e}
|
||||||
|
delete d.projection // not part of the API
|
||||||
|
delete d.query // not part of the API
|
||||||
|
return all
|
||||||
|
},{})})
|
||||||
|
}
|
||||||
|
let api = cds.compile(csn).to[format]({service})
|
||||||
|
return res.send(api)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example how to register arbitrary express routes,
|
||||||
|
* and map them to our service's interface.
|
||||||
|
* Try it out with URLs like that:
|
||||||
|
*
|
||||||
|
* - http://localhost:4004/ord/v1/csn/CatalogService
|
||||||
|
* - http://localhost:4004/ord/v1/edmx/CatalogService
|
||||||
|
* - http://localhost:4004/ord/v1/openapi/CatalogService
|
||||||
|
* - http://localhost:4004/ord/v1/asyncapi/CatalogService
|
||||||
|
*
|
||||||
|
* NOTE: we add cds.middlewares.before to the route, which gives us all
|
||||||
|
* the context and auth handling, which is also available to CAP services.
|
||||||
|
*/
|
||||||
|
cds.app.get (`${this.path}/:api?/:service?`, cds.middlewares.before, req => {
|
||||||
|
const { api, service } = req.params
|
||||||
|
return this.api (service, api)
|
||||||
|
})
|
||||||
|
|
||||||
|
return super.init()
|
||||||
|
}
|
||||||
|
}
|
||||||
111
package-lock.json
generated
111
package-lock.json
generated
@@ -108,14 +108,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cap-js-community/odata-v2-adapter": {
|
"node_modules/@cap-js-community/odata-v2-adapter": {
|
||||||
"version": "1.13.8",
|
"version": "1.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/@cap-js-community/odata-v2-adapter/-/odata-v2-adapter-1.13.8.tgz",
|
"resolved": "https://registry.npmjs.org/@cap-js-community/odata-v2-adapter/-/odata-v2-adapter-1.14.0.tgz",
|
||||||
"integrity": "sha512-IYkUUJLMS8sNL+6H8NOT17pMKweItjEUqV9EctuHw8+pWsFLcK3GehztZrtPS9DfEBOD9tC/aPNU5+b5unmZrQ==",
|
"integrity": "sha512-L4yIHml7Pc3dpSiCCJkOADje7kXgMvAIhFx6ZdeWwBnniPiul++8zCbRMIIjjwFKuujTwjoprb7C4IzZdYlAfQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.20.3",
|
"body-parser": "^1.20.3",
|
||||||
"body-parser-xml": "^2.0.5",
|
"body-parser-xml": "^2.0.5",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.2",
|
||||||
"express-fileupload": "^1.5.1",
|
"express-fileupload": "^1.5.1",
|
||||||
"http-proxy-middleware": "^3.0.3",
|
"http-proxy-middleware": "^3.0.3",
|
||||||
"xml2js": "^0.6.2"
|
"xml2js": "^0.6.2"
|
||||||
@@ -125,17 +125,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cap-js/cds-types": {
|
"node_modules/@cap-js/cds-types": {
|
||||||
"version": "0.8.0",
|
"version": "0.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@cap-js/cds-types/-/cds-types-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@cap-js/cds-types/-/cds-types-0.9.0.tgz",
|
||||||
"integrity": "sha512-iy+Rc4C6tnFuBwTIREcrFBVp0vKVN+iB5WoZFcBX7b5y7rUvK9Pz/5YHplacyQpwzxUc8Iv+CXG6LeWH/b7Qqw==",
|
"integrity": "sha512-AD4WGAOOSszaleQQqheIo0hHm50zk3NejMlHsuG6cLh4EyK/kozvcx8hkWfAkUT/s11fa8OjyMhztFCy8b5DAA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
"license": "SEE LICENSE IN LICENSE",
|
||||||
"dependencies": {
|
|
||||||
"@types/express": "^4.17.21"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@sap/cds": "^8.0.0"
|
"@sap/cds": "^8.0.0",
|
||||||
|
"@types/express": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cap-js/db-service": {
|
"node_modules/@cap-js/db-service": {
|
||||||
@@ -152,9 +150,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cap-js/sqlite": {
|
"node_modules/@cap-js/sqlite": {
|
||||||
"version": "1.7.7",
|
"version": "1.7.8",
|
||||||
"resolved": "https://registry.npmjs.org/@cap-js/sqlite/-/sqlite-1.7.7.tgz",
|
"resolved": "https://registry.npmjs.org/@cap-js/sqlite/-/sqlite-1.7.8.tgz",
|
||||||
"integrity": "sha512-SOmFJMr6pjWOniFRkJsrI0BpQEQT5Q8o+IVZ/LXFj6+bAe0NQQztzxhMQx62V/Px3u58JJM3xkPMU+QC5PcJHw==",
|
"integrity": "sha512-llFn0LGNIdlsfU4KjzyuIMvlQhKxXodq4GIt9yStmmX/av/twwHR8SyUmTJirRH4IkNtpCsuNYpsI+bYO2Xklg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "SEE LICENSE",
|
"license": "SEE LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -259,11 +257,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/core": {
|
"node_modules/@eslint/core": {
|
||||||
"version": "0.9.0",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
|
||||||
"integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==",
|
"integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/json-schema": "^7.0.15"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
@@ -293,9 +294,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.16.0",
|
"version": "9.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz",
|
||||||
"integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==",
|
"integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -313,12 +314,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/plugin-kit": {
|
"node_modules/@eslint/plugin-kit": {
|
||||||
"version": "0.2.3",
|
"version": "0.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz",
|
||||||
"integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==",
|
"integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@eslint/core": "^0.10.0",
|
||||||
"levn": "^0.4.1"
|
"levn": "^0.4.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -389,9 +391,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sap/cds": {
|
"node_modules/@sap/cds": {
|
||||||
"version": "8.5.0",
|
"version": "8.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-8.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-8.6.1.tgz",
|
||||||
"integrity": "sha512-mRiLBPcY5vC1xi21pPqzMtp1HY9FOOFajkiuSArqnwtiyp2fxqWVombuVE9lTB2UyBl9bL8XXwrpjzDftIbnBg==",
|
"integrity": "sha512-JYHRrGs6Tgle5Vmj/o3BaQkOBVcroweOrXhhiUVH6twISy+Yi2cWZdTr0EFFEt94FI1dVqvrVnEM67jEjOQImQ==",
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
"license": "SEE LICENSE IN LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sap/cds-compiler": ">=5.1",
|
"@sap/cds-compiler": ">=5.1",
|
||||||
@@ -464,6 +466,7 @@
|
|||||||
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
|
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/connect": "*",
|
"@types/connect": "*",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@@ -475,6 +478,7 @@
|
|||||||
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
|
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
@@ -491,6 +495,7 @@
|
|||||||
"integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
|
"integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/body-parser": "*",
|
"@types/body-parser": "*",
|
||||||
"@types/express-serve-static-core": "^4.17.33",
|
"@types/express-serve-static-core": "^4.17.33",
|
||||||
@@ -504,6 +509,7 @@
|
|||||||
"integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==",
|
"integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
"@types/qs": "*",
|
"@types/qs": "*",
|
||||||
@@ -516,7 +522,8 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
||||||
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
|
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/http-proxy": {
|
"node_modules/@types/http-proxy": {
|
||||||
"version": "1.17.15",
|
"version": "1.17.15",
|
||||||
@@ -537,7 +544,8 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
||||||
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.5.5",
|
"version": "22.5.5",
|
||||||
@@ -553,14 +561,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz",
|
||||||
"integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==",
|
"integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/range-parser": {
|
"node_modules/@types/range-parser": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
||||||
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
|
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/send": {
|
"node_modules/@types/send": {
|
||||||
"version": "0.17.4",
|
"version": "0.17.4",
|
||||||
@@ -568,6 +578,7 @@
|
|||||||
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
|
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mime": "^1",
|
"@types/mime": "^1",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@@ -579,6 +590,7 @@
|
|||||||
"integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
|
"integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/http-errors": "*",
|
"@types/http-errors": "*",
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@@ -694,9 +706,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.7.8",
|
"version": "1.7.9",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
||||||
"integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==",
|
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1303,19 +1315,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.16.0",
|
"version": "9.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz",
|
||||||
"integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==",
|
"integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.19.0",
|
"@eslint/config-array": "^0.19.0",
|
||||||
"@eslint/core": "^0.9.0",
|
"@eslint/core": "^0.10.0",
|
||||||
"@eslint/eslintrc": "^3.2.0",
|
"@eslint/eslintrc": "^3.2.0",
|
||||||
"@eslint/js": "9.16.0",
|
"@eslint/js": "9.19.0",
|
||||||
"@eslint/plugin-kit": "^0.2.3",
|
"@eslint/plugin-kit": "^0.2.5",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
"@humanwhocodes/retry": "^0.4.1",
|
"@humanwhocodes/retry": "^0.4.1",
|
||||||
@@ -1323,7 +1335,7 @@
|
|||||||
"@types/json-schema": "^7.0.15",
|
"@types/json-schema": "^7.0.15",
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
"chalk": "^4.0.0",
|
"chalk": "^4.0.0",
|
||||||
"cross-spawn": "^7.0.5",
|
"cross-spawn": "^7.0.6",
|
||||||
"debug": "^4.3.2",
|
"debug": "^4.3.2",
|
||||||
"escape-string-regexp": "^4.0.0",
|
"escape-string-regexp": "^4.0.0",
|
||||||
"eslint-scope": "^8.2.0",
|
"eslint-scope": "^8.2.0",
|
||||||
@@ -1479,9 +1491,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.21.1",
|
"version": "4.21.2",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "~1.3.8",
|
"accepts": "~1.3.8",
|
||||||
"array-flatten": "1.1.1",
|
"array-flatten": "1.1.1",
|
||||||
@@ -1502,7 +1515,7 @@
|
|||||||
"methods": "~1.1.2",
|
"methods": "~1.1.2",
|
||||||
"on-finished": "2.4.1",
|
"on-finished": "2.4.1",
|
||||||
"parseurl": "~1.3.3",
|
"parseurl": "~1.3.3",
|
||||||
"path-to-regexp": "0.1.10",
|
"path-to-regexp": "0.1.12",
|
||||||
"proxy-addr": "~2.0.7",
|
"proxy-addr": "~2.0.7",
|
||||||
"qs": "6.13.0",
|
"qs": "6.13.0",
|
||||||
"range-parser": "~1.2.1",
|
"range-parser": "~1.2.1",
|
||||||
@@ -1517,6 +1530,10 @@
|
|||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express-fileupload": {
|
"node_modules/express-fileupload": {
|
||||||
@@ -2441,9 +2458,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-to-regexp": {
|
"node_modules/path-to-regexp": {
|
||||||
"version": "0.1.10",
|
"version": "0.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/pathval": {
|
"node_modules/pathval": {
|
||||||
|
|||||||
99
package.json
99
package.json
@@ -1,51 +1,52 @@
|
|||||||
{
|
{
|
||||||
"name": "@capire/samples",
|
"name": "@capire/samples",
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"description": "A monorepo with several samples for CAP.",
|
"description": "A monorepo with several samples for CAP.",
|
||||||
"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",
|
"author": "daniel.hutzel@sap.com",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sap/cds": ">=8"
|
"@sap/cds": ">=8"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"./bookshop",
|
"./bookshop",
|
||||||
"./bookstore",
|
"./bookstore",
|
||||||
"./common",
|
"./common",
|
||||||
"./data-viewer",
|
"./data-viewer",
|
||||||
"./fiori",
|
"./fiori",
|
||||||
"./hello",
|
"./hello",
|
||||||
"./media",
|
"./media",
|
||||||
"./orders",
|
"./ord",
|
||||||
"./loggers",
|
"./orders",
|
||||||
"./reviews"
|
"./loggers",
|
||||||
],
|
"./reviews"
|
||||||
"devDependencies": {
|
],
|
||||||
"@cap-js/cds-types": "^0",
|
"devDependencies": {
|
||||||
"@cap-js/sqlite": "^1",
|
"@cap-js/cds-types": "^0",
|
||||||
"axios": "^1",
|
"@cap-js/sqlite": "^1",
|
||||||
"chai": "^4.3.4",
|
"axios": "^1",
|
||||||
"chai-as-promised": "^7.1.1",
|
"chai": "^4.3.4",
|
||||||
"chai-subset": "^1.6.0",
|
"chai-as-promised": "^7.1.1",
|
||||||
"eslint": "^9",
|
"chai-subset": "^1.6.0",
|
||||||
"semver": "^7"
|
"eslint": "^9",
|
||||||
},
|
"semver": "^7"
|
||||||
"scripts": {
|
},
|
||||||
"bookshop": "cds watch bookshop",
|
"scripts": {
|
||||||
"start": "cds watch fiori",
|
"bookshop": "cds watch bookshop",
|
||||||
"fiori": "cds watch fiori",
|
"start": "cds watch fiori",
|
||||||
"hello": "cds watch hello",
|
"fiori": "cds watch fiori",
|
||||||
"media": "cds watch media",
|
"hello": "cds watch hello",
|
||||||
"lint": "eslint",
|
"media": "cds watch media",
|
||||||
"test": "npx jest --silent",
|
"lint": "eslint",
|
||||||
"jest": "npx jest --silent",
|
"test": "npx jest --silent",
|
||||||
"mocha": "CDS_TEST_SILENT=y npx mocha",
|
"jest": "npx jest --silent",
|
||||||
"test:hello": "cd hello && npm test"
|
"mocha": "CDS_TEST_SILENT=y npx mocha",
|
||||||
},
|
"test:hello": "cd hello && npm test"
|
||||||
"mocha": {
|
},
|
||||||
"recursive": true,
|
"mocha": {
|
||||||
"parallel": true,
|
"recursive": true,
|
||||||
"timeout": 6666
|
"parallel": true,
|
||||||
},
|
"timeout": 6666
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
},
|
||||||
"private": true
|
"license": "SEE LICENSE IN LICENSE",
|
||||||
|
"private": true
|
||||||
}
|
}
|
||||||
@@ -27,15 +27,15 @@ describe('cap/samples - Localized Data', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('supports queries with $expand', async () => {
|
it('supports queries with $expand', async () => {
|
||||||
const { data } = await GET(`/browse/Book?&$select=title,author,currencyName`, {
|
const { data } = await GET(`/browse/Books?&$select=title,author&$expand=currency`, {
|
||||||
headers: { 'Accept-Language': 'de' },
|
headers: { 'Accept-Language': 'de' },
|
||||||
})
|
})
|
||||||
expect(data.value).to.containSubset([
|
expect(data.value).to.containSubset([
|
||||||
{ title: 'Sturmhöhe', author: 'Emily Brontë', currencyName: 'Pfund' },
|
{ title: 'Sturmhöhe', author: 'Emily Brontë', currency: { name: 'Pfund' } },
|
||||||
{ title: 'Jane Eyre', author: 'Charlotte Brontë', currencyName: 'Pfund' },
|
{ title: 'Jane Eyre', author: 'Charlotte Brontë', currency: { name: 'Pfund' } },
|
||||||
{ title: 'The Raven', author: 'Edgar Allen Poe', currencyName: 'US-Dollar' },
|
{ title: 'The Raven', author: 'Edgar Allen Poe', currency: { name: 'US-Dollar' } },
|
||||||
{ title: 'Eleonora', author: 'Edgar Allen Poe', currencyName: 'US-Dollar' },
|
{ title: 'Eleonora', author: 'Edgar Allen Poe', currency: { name: 'US-Dollar' } },
|
||||||
{ title: 'Catweazle', author: 'Richard Carpenter', currencyName: 'Yen' },
|
{ title: 'Catweazle', author: 'Richard Carpenter', currency: { name: 'Yen' } },
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -12,20 +12,20 @@ describe('cap/samples - Bookshop APIs', () => {
|
|||||||
'odata-version': '4.0',
|
'odata-version': '4.0',
|
||||||
})
|
})
|
||||||
expect(headers['content-type']).to.match(/application\/xml/)
|
expect(headers['content-type']).to.match(/application\/xml/)
|
||||||
expect(data).to.contain('<EntitySet Name="Books" EntityType="CatalogService.Books"/>')
|
expect(data).to.contain('<EntitySet Name="Books" EntityType="CatalogService.Books">')
|
||||||
expect(data).to.contain('<Annotation Term="Common.Label" String="Currency Symbol"/>')
|
expect(data).to.contain('<Annotation Term="Common.Label" String="Currency"/>')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('serves Books?$expand=genre,currency', async () => {
|
it('serves ListOfBooks?$expand=genre,currency', async () => {
|
||||||
const Mystery = { ID: 16, name: 'Mystery', descr: null, parent_ID: 10 }
|
const Mystery = { ID: 16, name: 'Mystery', descr: null, parent_ID: 10 }
|
||||||
const Romance = { ID: 15, name: 'Romance', descr: null, parent_ID: 10 }
|
const Romance = { ID: 15, name: 'Romance', descr: null, parent_ID: 10 }
|
||||||
const USD = { code: 'USD', name: 'US Dollar', descr: null, symbol: '$' }
|
const USD = { code: 'USD', name: 'US Dollar', descr: null, symbol: '$' }
|
||||||
const { data } = await GET `/admin/Books ${{
|
const { data } = await GET `/browse/ListOfBooks ${{
|
||||||
params: { $search: 'Po', $select: `title,author`, $expand:`genre,currency` },
|
params: { $search: 'Po', $select: `title,author`, $expand:`genre,currency` },
|
||||||
}}`
|
}}`
|
||||||
expect(data.value).to.containSubset([
|
expect(data.value).to.containSubset([
|
||||||
{ ID: 251, title: 'The Raven', author_ID: 150, genre:Mystery, currency:USD },
|
{ ID: 251, title: 'The Raven', author: 'Edgar Allen Poe', genre:Mystery, currency:USD },
|
||||||
{ ID: 252, title: 'Eleonora', author_ID: 150, genre:Romance, currency:USD },
|
{ ID: 252, title: 'Eleonora', author: 'Edgar Allen Poe', genre:Romance, currency:USD },
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user