@sap/cds
Version:
SAP Cloud Application Programming Model - CDS for Node.js
92 lines (79 loc) • 3.47 kB
JavaScript
const METADATA = {
$context: '@odata.context',
$count: '@odata.count',
$etag: '@odata.etag',
$metadataEtag: '@odata.metadataEtag',
$bind: '@odata.bind',
$id: '@odata.id',
$delta: '@odata.delta',
$removed: '@odata.removed',
$type: '@odata.type',
$nextLink: '@odata.nextLink',
$deltaLink: '@odata.deltaLink',
$editLink: '@odata.editLink',
$readLink: '@odata.readLink',
$navigationLink: '@odata.navigationLink',
$associationLink: '@odata.associationLink',
$mediaEditLink: '@odata.mediaEditLink',
$mediaReadLink: '@odata.mediaReadLink',
$mediaContentType: '@odata.mediaContentType',
$mediaContentDispositionFilename: '@odata.mediaContentDispositionFilename', // > not supported by okra
$mediaContentDispositionType: '@odata.mediaContentDispositionType', // > not supported by okra
$mediaEtag: '@odata.mediaEtag'
}
const KEYSTOCLEANUP = {
// REVISIT: should probably be handled in RemoteService's handle()
// do not set "@odata.context" as it may be inherited of remote service
$context: true,
// REVISIT: okra doesn't support content disposition
$mediaContentDispositionFilename: true,
$mediaContentDispositionType: true
}
const _rewriteMetadataDeep = result => {
for (const key in result) {
const value = result[key]
if (typeof value === 'object' && value != null) _rewriteMetadataDeep(value)
if (key in METADATA && !KEYSTOCLEANUP[key]) {
result[METADATA[key]] = value
delete result[key]
}
}
}
/**
* Constructs the odata result object from the result of the service call as well as the provided metadata and additional options.
*
* @param {*} result - the result of the service call, i.e., the payload to return to the client
* @param {object} metadata - odata metadata
* @param {string} metadata.context - @odata.context
* @param {object} [options] - additional options/ instructions
* @param {boolean} [options.isCollection] - whether the result shall be a collection
* @param {string} [options.property] - the name of the requested single property, if any
* @returns {object} - the odata result
*/
module.exports = function getODataResult(result, metadata, options = {}) {
if (result == null) return
const { isCollection, property } = options
if (isCollection && !Array.isArray(result)) result = [result]
else if (!isCollection && Array.isArray(result)) result = result[0]
if (result === undefined) return
// make sure @odata.context is the first element (per OData spec)
const odataResult = { [METADATA.$context]: metadata.context }
// Normalization of result to array or object has already been done above based on isCollection
// -> we can assume result is already in the correct shape for further processing below
const resultIsArray = Array.isArray(result)
const resultIsPlainObject = typeof result === 'object' && !resultIsArray && !Buffer.isBuffer(result)
if (resultIsPlainObject || resultIsArray) {
// copy metadata from result to odataResult
for (const key in METADATA) {
if (!(key in result)) continue
if (!KEYSTOCLEANUP[key]) odataResult[METADATA[key]] = result[key]
}
// rewrite metadata in result
_rewriteMetadataDeep(result)
}
// add result to odataResult
if (property) return { ...odataResult, value: result[property] }
if (resultIsPlainObject) return { ...odataResult, ...result }
// Result is a primitive value, an Array or a Buffer
return { ...odataResult, value: result }
}