From 790a3d779078e3e41ea606461bbaab6b66d882f8 Mon Sep 17 00:00:00 2001 From: D024504 Date: Thu, 29 Aug 2024 09:06:00 +0200 Subject: [PATCH] Use `Core.ContentID` in actions --- ...Common.CorrespondingContentIDs-sample.json | 42 +++++++++++++ .../Common.CorrespondingContentIDs-sample.xml | 41 ++++++++++++ vocabularies/Common.json | 35 +++++++++++ vocabularies/Common.md | 48 ++++++++++++++ vocabularies/Common.xml | 62 +++++++++++++++++++ 5 files changed, 228 insertions(+) create mode 100644 examples/Common.CorrespondingContentIDs-sample.json create mode 100644 examples/Common.CorrespondingContentIDs-sample.xml diff --git a/examples/Common.CorrespondingContentIDs-sample.json b/examples/Common.CorrespondingContentIDs-sample.json new file mode 100644 index 00000000..82188075 --- /dev/null +++ b/examples/Common.CorrespondingContentIDs-sample.json @@ -0,0 +1,42 @@ +{ + "$Version": "4.0", + "$Reference": { + "https://sap.github.io/odata-vocabularies/vocabularies/Common.json": { + "$Include": [{ "$Namespace": "com.sap.vocabularies.Common.v1", "$Alias": "Common" }] + } + }, + "corresponding.sample": { + "$Alias": "self", + "SalesQuotation": { "$Kind": "EntityType", "id": { "$Nullable": true } }, + "SalesQuotationItemToBeCopied": { "$Kind": "ComplexType", "product": { "$Nullable": true } }, + "SalesOrder": { + "$Kind": "EntityType", + "Items": { "$Kind": "NavigationProperty", "$Collection": true, "$Type": "self.SalesOrderItem" } + }, + "SalesOrderItem": { + "$Kind": "EntityType", + "Discounts": { "$Kind": "NavigationProperty", "$Collection": true, "$Type": "self.SalesOrderItemDiscount" } + }, + "SalesOrderItemDiscount": { + "$Kind": "EntityType", + "percent": { "$Type": "Edm.Decimal", "$Nullable": true, "$Scale": 0 } + }, + "CreateSalesOrder": [ + { + "$Kind": "Action", + "$IsBound": true, + "$Parameter": [ + { "$Name": "_it", "$Type": "self.SalesQuotation" }, + { "$Name": "items", "$Collection": true, "$Type": "self.SalesQuotationItemToBeCopied" } + ], + "$ReturnType": { "$Type": "self.SalesOrder" }, + "@Common.CorrespondingContentIDs": [{ "ParameterValue": "items", "ReturnedEntity": "$ReturnType/Items" }] + } + ], + "default": { + "$Kind": "EntityContainer", + "SalesQuotations": { "$Collection": true, "$Type": "self.SalesQuotation" } + } + }, + "$EntityContainer": "corresponding.sample.default" +} diff --git a/examples/Common.CorrespondingContentIDs-sample.xml b/examples/Common.CorrespondingContentIDs-sample.xml new file mode 100644 index 00000000..7ab191f5 --- /dev/null +++ b/examples/Common.CorrespondingContentIDs-sample.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vocabularies/Common.json b/vocabularies/Common.json index 548852c0..4523fdff 100644 --- a/vocabularies/Common.json +++ b/vocabularies/Common.json @@ -1316,6 +1316,41 @@ "@Common.Experimental": true, "@Core.IsURL": true, "@Core.Description": "Base URL for WebSocket connections" + }, + "CorrespondingContentIDs": { + "$Kind": "Term", + "$Collection": true, + "$Type": "Common.CorrespondingContentID", + "$AppliesTo": ["Action"], + "@Common.Experimental": true, + "@Core.Description": "Correspondence between `Core.ContentID` in a parameter and in the return type of an action", + "@Core.LongDescription": "If values in the action invocation are annotated with `Core.ContentID`,\n the corresponding entities returned by the action are annotated with the same `Core.ContentID`\n and can thus be referenced in subsequent requests within the same batch request." + }, + "CorrespondingContentID": { + "$Kind": "ComplexType", + "@Common.Experimental": true, + "@Core.Description": "Establishes a correspondence between a value or entity in a parameter and in the return type", + "@Core.LongDescription": "Given a sales quotation with items for coffee, sugar and paper,\nthe following $batch request to [this service](../examples/Common.CorrespondingContentIDs-sample.xml)\ninvokes an action to create a sales order for sugar and paper\nand adds a 10% discount for the sugar.\n```json\n{\n \"requests\": [\n {\n \"id\": \"1\",\n \"method\": \"post\",\n \"url\": \"/service/SalesQuotation(68)/self.CreateSalesOrder\",\n \"body\": {\n \"items\": [\n {\"product\": \"Sugar\", \"@Core.ContentID\": \"I1\"},\n {\"product\": \"Paper\"}\n ]\n }\n },\n {\n \"id\": \"2\",\n \"dependsOn\": [ \"1\" ],\n \"method\": \"post\",\n \"url\": \"$I1/Discounts\",\n \"body\": {\n \"percent\": 10\n }\n }\n ]\n}\n```\nIn the response to the action invocation the sales order item for the sugar is annotated\nwith `\"@Core.ContentID\": \"I1\"`. The subsequent POST request can reference this item without knowing its key.\n\nExactly one of `ParameterValue` and `ParameterEntity` and\nexactly one of `ReturnedValue` and `ReturnedEntity` and must be given.", + "ParameterValue": { + "$Type": "Edm.PropertyPath", + "$Nullable": true, + "@Core.Description": "Path to a value in a parameter that may be annotated with `Core.ContentID`" + }, + "ParameterEntity": { + "$Type": "Edm.NavigationPropertyPath", + "$Nullable": true, + "@Core.Description": "Path to an entity in a parameter that may be annotated with `Core.ContentID`" + }, + "ReturnedValue": { + "$Type": "Edm.PropertyPath", + "$Nullable": true, + "@Core.Description": "Path to a value in the return type that will be annotated with the same `Core.ContentID`" + }, + "ReturnedEntity": { + "$Type": "Edm.NavigationPropertyPath", + "$Nullable": true, + "@Core.Description": "Path to an entity in the return type that will be annotated with the same `Core.ContentID`" + } } } } diff --git a/vocabularies/Common.md b/vocabularies/Common.md index c2469172..1d225eab 100644 --- a/vocabularies/Common.md +++ b/vocabularies/Common.md @@ -111,6 +111,7 @@ Term|Type|Description [mediaUploadLink](Common.xml#L1457) *([Experimental](Common.md#Experimental))*|URL|URL for uploading new media content to a Document Management Service
In contrast to the `@odata.mediaEditLink` this URL allows to upload new media content without directly changing a stream property or media resource. The upload request typically uses HTTP POST with `Content-Type: multipart/form-data` following RFC 7578. The upload request must contain one multipart representing the content of the file. The `name` parameter in the `Content-Disposition` header (as described in RFC 7578) is irrelevant, but the `filename` parameter is expected. If the request succeeds the response will contain a JSON body of `Content-Type: application/json` with a JSON property `readLink`. The newly uploaded media resource can be linked to the stream property by changing the `@odata.mediaReadLink` to the value of this `readLink` in a subsequent PATCH request to the OData entity. [PrimitivePropertyPath](Common.xml#L1472) *([Experimental](Common.md#Experimental))*|[Tag](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#Tag)|A term or term property with this tag whose type is (a collection of) `Edm.PropertyPath` MUST resolve to a primitive structural property [WebSocketBaseURL](Common.xml#L1477) *([Experimental](Common.md#Experimental))*|URL|Base URL for WebSocket connections +[CorrespondingContentIDs](Common.xml#L1483) *([Experimental](Common.md#Experimental))*|\[[CorrespondingContentID](#CorrespondingContentID)\]|Correspondence between `Core.ContentID` in a parameter and in the return type of an action
If values in the action invocation are annotated with `Core.ContentID`, the corresponding entities returned by the action are annotated with the same `Core.ContentID` and can thus be referenced in subsequent requests within the same batch request. ## [TextFormatType](Common.xml#L120) @@ -441,3 +442,50 @@ Use terms [Aggregation.RecursiveHierarchy](https://github.com/oasis-tcs/odata-vo **Type:** String User ID + + +## [CorrespondingContentID](Common.xml#L1492) *([Experimental](Common.md#Experimental))* +Establishes a correspondence between a value or entity in a parameter and in the return type + +Given a sales quotation with items for coffee, sugar and paper, +the following $batch request to [this service](../examples/Common.CorrespondingContentIDs-sample.xml) +invokes an action to create a sales order for sugar and paper +and adds a 10% discount for the sugar. +```json +{ + "requests": [ + { + "id": "1", + "method": "post", + "url": "/service/SalesQuotation(68)/self.CreateSalesOrder", + "body": { + "items": [ + {"product": "Sugar", "@Core.ContentID": "I1"}, + {"product": "Paper"} + ] + } + }, + { + "id": "2", + "dependsOn": [ "1" ], + "method": "post", + "url": "$I1/Discounts", + "body": { + "percent": 10 + } + } + ] +} +``` +In the response to the action invocation the sales order item for the sugar is annotated +with `"@Core.ContentID": "I1"`. The subsequent POST request can reference this item without knowing its key. + +Exactly one of `ParameterValue` and `ParameterEntity` and +exactly one of `ReturnedValue` and `ReturnedEntity` and must be given. + +Property|Type|Description +:-------|:---|:---------- +[ParameterValue](Common.xml#L1532)|PropertyPath?|Path to a value in a parameter that may be annotated with `Core.ContentID` +[ParameterEntity](Common.xml#L1535)|NavigationPropertyPath?|Path to an entity in a parameter that may be annotated with `Core.ContentID` +[ReturnedValue](Common.xml#L1538)|PropertyPath?|Path to a value in the return type that will be annotated with the same `Core.ContentID` +[ReturnedEntity](Common.xml#L1541)|NavigationPropertyPath?|Path to an entity in the return type that will be annotated with the same `Core.ContentID` diff --git a/vocabularies/Common.xml b/vocabularies/Common.xml index e5253471..c85d2aeb 100644 --- a/vocabularies/Common.xml +++ b/vocabularies/Common.xml @@ -1480,6 +1480,68 @@ If the request succeeds the response will contain a JSON body of `Content-Type: + + + + + If values in the action invocation are annotated with `Core.ContentID`, + the corresponding values returned by the action are annotated with the same `Core.ContentID` + and can thus be referenced in subsequent requests within the same batch request. + + + + + + + Given a sales quotation with items for coffee, sugar and paper, +the following $batch request to [this service](../examples/Common.CorrespondingContentIDs-sample.xml) +invokes an action to create a sales order for sugar and paper +and adds a 10% discount for the sugar. +```json +{ + "requests": [ + { + "id": "1", + "method": "post", + "url": "/service/SalesQuotation(68)/self.CreateSalesOrder", + "body": { + "items": [ + {"product": "Sugar", "@Core.ContentID": "I1"}, + {"product": "Paper"} + ] + } + }, + { + "id": "2", + "dependsOn": [ "1" ], + "method": "post", + "url": "$I1/Discounts", + "body": { + "percent": 10 + } + } + ] +} +``` +In the response to the action invocation the sales order item for the sugar is annotated +with `"@Core.ContentID": "I1"`. The subsequent POST request can reference this item without knowing its key. + +Exactly one of `ParameterValue` and `ParameterEntity` and +exactly one of `ReturnedValue` and `ReturnedEntity` and must be given. + + + + + + + + + + + + + +