@sap-cloud-sdk/odata-common
Version:
SAP Cloud SDK for JavaScript common functions of OData client generator and OpenAPI clint generator.
175 lines • 8.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.entityDeserializer = entityDeserializer;
exports.extractEtagFromHeader = extractEtagFromHeader;
exports.extractCustomFields = extractCustomFields;
const util_1 = require("@sap-cloud-sdk/util");
const de_serializers_1 = require("./de-serializers");
const entity_base_1 = require("./entity-base");
const edm_types_1 = require("./edm-types");
const selectable_1 = require("./selectable");
const logger = (0, util_1.createLogger)({
package: 'odata-common',
messageContext: 'entity-deserializer'
});
/**
* Constructs an entityDeserializer given the OData v2 or v4 specific methods.
* The concrete deserializers are created in odata/v2/entity-deserializer.ts and odata/v4/entity-deserializer.ts.
* @param deSerializers - (De-)serializers used for transformation.
* @param extractODataETag - Extractor for the ETag.
* @param extractDataFromOneToManyLink - Extractor for data related to one to many links.
* @returns An entity deserializer as defined by {@link EntityDeserializer}.
*/
function entityDeserializer(deSerializers, extractODataETag, extractDataFromOneToManyLink) {
const edmToTs = (0, de_serializers_1.createValueDeserializer)(deSerializers);
/**
* Converts the JSON payload for a single entity into an instance of the corresponding generated entity class.
* It sets the remote state to the data provided by the JSON payload.
* If a version identifier is found in the '__metadata' or in the request header, the method also sets it.
* @param json - The JSON payload.
* @param entityApi - Entity API to deserialize for.
* @param requestHeader - Optional parameter which may be used to add a version identifier (ETag) to the entity.
* @returns An instance of the entity class.
*/
function deserializeEntity(json, entityApi, requestHeader) {
const etag = extractODataETag(json) || extractEtagFromHeader(requestHeader);
return Object.values(entityApi.schema)
.filter(field => (0, entity_base_1.isSelectedProperty)(json, field))
.reduce((entity, staticField) => {
entity[(0, util_1.camelCase)(staticField._fieldName)] = getFieldValue(json, staticField);
return entity;
}, new entityApi.entityConstructor(entityApi))
.setCustomFields(extractCustomFields(json, entityApi.schema))
.setVersionIdentifier(etag)
.setOrInitializeRemoteState();
}
function getFieldValue(json, field) {
if (field instanceof selectable_1.EdmTypeField) {
return edmToTs(json[field._fieldName], field.edmType);
}
if (field instanceof selectable_1.Link) {
return getLinkFromJson(json, field);
}
if (field instanceof selectable_1.ComplexTypeField) {
if (json[field._fieldName]) {
return field._complexType
? deserializeComplexType(json[field._fieldName], field._complexType)
: deserializeComplexTypeLegacy(json[field._fieldName], field);
}
return json[field._fieldName];
}
if (field instanceof selectable_1.CollectionField) {
return deserializeCollectionType(json[field._fieldName], field._fieldType);
}
if (field instanceof selectable_1.EnumField) {
return json[field._fieldName];
}
}
function getLinkFromJson(json, link) {
return link instanceof selectable_1.OneToOneLink
? getSingleLinkFromJson(json, link)
: getMultiLinkFromJson(json, link);
}
// Be careful: if the return type is changed to `LinkedEntityT | undefined`, the test 'navigation properties should never be undefined' of the 'business-partner.spec.ts' will fail.
// Not sure the purpose of the usage of null.
function getSingleLinkFromJson(json, link) {
if ((0, entity_base_1.isExpandedProperty)(json, link)) {
return deserializeEntity(json[link._fieldName], link._linkedEntityApi);
}
return null;
}
function getMultiLinkFromJson(json, link) {
if ((0, entity_base_1.isSelectedProperty)(json, link)) {
const results = extractDataFromOneToManyLink(json[link._fieldName]);
return results.map(linkJson => deserializeEntity(linkJson, link._linkedEntityApi));
}
}
// TODO: get rid of this function in v2.0
function deserializeComplexTypeLegacy(json, complexTypeField) {
logger.warn('It seems that you are using an outdated OData client. To make this warning disappear, please regenerate your client using the latest version of the SAP Cloud SDK generator.');
if (json === null) {
return null;
}
return Object.entries(complexTypeField)
.filter(([, field]) => (field instanceof selectable_1.EdmTypeField ||
field instanceof selectable_1.ComplexTypeField) &&
typeof json[field._fieldName] !== 'undefined')
.reduce((complexTypeObject, [fieldName, field]) => ({
...complexTypeObject,
[(0, util_1.camelCase)(fieldName)]: field instanceof selectable_1.EdmTypeField
? edmToTs(json[field._fieldName], field.edmType)
: deserializeComplexTypeLegacy(json[field._fieldName], field)
}), {});
}
function deserializeComplexTypeProperty(propertyValue, propertyMetadata) {
if (propertyMetadata.isCollection) {
return deserializeCollectionType(propertyValue, propertyMetadata.type);
}
if ((0, selectable_1.isComplexTypeNameSpace)(propertyMetadata.type)) {
return deserializeComplexType(propertyValue, propertyMetadata.type);
}
return edmToTs(propertyValue, propertyMetadata.type);
}
function deserializeComplexType(json, complexType) {
if (json === null) {
return null;
}
return complexType._propertyMetadata
.map(property => ({
...(typeof json[property.originalName] !== 'undefined' && {
[property.name]: deserializeComplexTypeProperty(json[property.originalName], property)
})
}))
.reduce((complexTypeInstance, property) => ({
...complexTypeInstance,
...property
}));
}
function deserializeCollectionType(json, fieldType) {
if ((0, edm_types_1.isEdmType)(fieldType)) {
return json.map(val => edmToTs(val, fieldType));
}
if ((0, selectable_1.isComplexTypeNameSpace)(fieldType)) {
return json.map(val => deserializeComplexType(val, fieldType));
}
// Enum
return json;
}
return {
deserializeEntity,
deserializeComplexType
};
}
/**
* Extract eTag from custom header ignoring case.
* @param headers - Headers from which the etag is extracted.
* @returns string | undefined
* @internal
*/
function extractEtagFromHeader(headers) {
return (0, util_1.pickValueIgnoreCase)(headers, 'etag');
}
/**
* Extracts all custom fields from the JSON payload for a single entity.
* In this context, a custom fields is every property that is not known in the corresponding entity class.
* @param json - The JSON payload.
* @param schema - TODO
* @returns An object containing the custom fields as key-value pairs.
* @internal
*/
function extractCustomFields(json, schema) {
const regularODataProperties = [
'__metadata',
'__deferred',
// type assertion for backwards compatibility, TODO: remove in v2.0
...Object.values(schema).map(field => field._fieldName)
];
const regularFields = new Set(regularODataProperties);
return Object.keys(json)
.filter(key => !regularFields.has(key))
.reduce((customFields, key) => {
customFields[key] = json[key];
return customFields;
}, {});
}
//# sourceMappingURL=entity-deserializer.js.map