@sap/xsodata
Version:
Expose data from a HANA database as OData V2 service with help of .xsodata files.
299 lines (254 loc) • 10.3 kB
JavaScript
;
// This module is used only internally from the entityType.js and is not intended to be used publicly.
const EntityType = require('./entityType');
/**
* Mapping of the values of SEMANTIC_TYPE column of the BIMC_DIMENSION_VIEW_HDI / BIMC_VARIABLE_VIEW_HDI DB views to
* the values of sap:semantics OData annotation, which is added to the EDM properties. Only the values in the map are
* supported.
*/
const SEMANTIC_MAPPINGS = {
'currencyCode': 'currency-code',
'unitOfMeasure': 'unit-of-measure',
'date.businessDateFrom': 'dtstart',
'date.businessDateTo': 'dtend',
};
const NAVIGATION_PROPERTY_ANNOTATIONS = {
'sap:creatable': 'false', // deep inserts are not supported
'sap:filterable': 'false', // for now, $filter is not supported for navigation properties
};
// Annotations for the association set, which connects CalcView input parameters (IP) entity set with the entity set
// representing the CalcView results. Such associations cannot be modified, i.e. $links requests are not supported.
const IP_ASSOCIATION_SET_ANNOTATIONS = {
'sap:creatable': 'false',
'sap:updatable': 'false',
'sap:deletable': 'false',
};
exports.createPropertyAnnotations = createPropertyAnnotations;
/**
* Creates object containing the annotations for the specified property of the entityType.
* @param {object} entityType - instance of EntityType, which contains the property, for which the annotations
* should be created. This parameter must be specified.
* @param {object} property - property object having, for example, the following structure:
* {
* KIND: 4,
* COLUMN_NAME: 'IN_VARBINARY',
* SEMANTIC_TYPE: '',
* MANDATORY: 1,
* DESCRIPTION: '',
* SELECTION_TYPE: 'SingleValue',
* MULTILINE: 0
* }
* Such an object can be obtained by calling getProperty() method on an EntityType instance.
* This parameter must be specified.
* @returns {object} object containing the applicable annotations for the specified property, for example:
* {
* "sap:parameter" : "mandatory",
* "sap:label" : "Currency code variable",
* "sap:semantics" : "currency-code"
* }
*/
function createPropertyAnnotations(entityType, property) {
const propertyAnnotations = {};
setPropertyParameter(property, propertyAnnotations);
setPropertyDisplayFormat(property, propertyAnnotations);
setPropertyLabel(property, propertyAnnotations);
setPropertySemantics(property, propertyAnnotations);
setPropertyAggregationRole(entityType, property, propertyAnnotations);
setPropertyUnit(property, propertyAnnotations);
setPropertyText(property, propertyAnnotations);
setPropertyFilterRestriction(property, propertyAnnotations);
setPropertyFilterable(entityType, property, propertyAnnotations);
return propertyAnnotations;
}
exports._setPropertyParameter = setPropertyParameter;
function setPropertyParameter(property, propertyAnnotations) {
if (property.KIND !== EntityType.entityKind.inputParameters) {
return;
}
propertyAnnotations['sap:parameter'] =
property.MANDATORY === 1 ? 'mandatory' : 'optional';
}
function setPropertyDisplayFormat(property, propertyAnnotations) {
if (
property.DATA_TYPE_NAME === 'DATE' ||
property.DATA_TYPE_NAME === 'DAYDATE'
) {
propertyAnnotations['sap:display-format'] = 'Date';
}
}
function setPropertyLabel(property, propertyAnnotations) {
// depending on the property's kind, the different DB column (of the different DB table) contains the description
const labelColumn =
property.KIND === EntityType.entityKind.inputParameters
? 'DESCRIPTION'
: 'COLUMN_CAPTION';
const propertyLabel = property[labelColumn];
if (propertyLabel) {
propertyAnnotations['sap:label'] = propertyLabel;
}
}
exports._setPropertySemantics = setPropertySemantics;
function setPropertySemantics(property, propertyAnnotations) {
let odataSemantic;
if (!property.SEMANTIC_TYPE) {
return;
}
odataSemantic = SEMANTIC_MAPPINGS[property.SEMANTIC_TYPE];
if (odataSemantic) {
propertyAnnotations['sap:semantics'] = odataSemantic;
}
}
function setPropertyAggregationRole(entityType, property, propertyAnnotations) {
if (entityType.isAggregateProperty(property.COLUMN_NAME)) {
propertyAnnotations['sap:aggregation-role'] = 'measure';
} else {
if (
entityType.kind !== EntityType.entityKind.inputParameters &&
(entityType.hasAggregates() || entityType.hasMeasureProperties()) &&
entityType.isInBimcDimensionView(property.COLUMN_NAME)
) {
if (
property.suppressAnnotationDimension &&
property.suppressAnnotationDimension === true
) {
return; // property is used as description text for other property: do not add annotation
}
propertyAnnotations['sap:aggregation-role'] = 'dimension';
}
}
}
function setPropertyUnit(property, propertyAnnotations) {
if (property.UNIT_COLUMN_NAME) {
propertyAnnotations['sap:unit'] = property.UNIT_COLUMN_NAME;
}
}
function setPropertyText(property, propertyAnnotations) {
if (property.DESC_NAME && property.DESC_NAME !== property.COLUMN_NAME) {
propertyAnnotations['sap:text'] = property.DESC_NAME;
}
}
exports._setPropertyFilterRestriction = setPropertyFilterRestriction;
function setPropertyFilterRestriction(property, propertyAnnotations) {
const selectionType = property.SELECTION_TYPE,
multiline = property.MULTILINE;
if (selectionType === 'SingleValue') {
propertyAnnotations['sap:filter-restriction'] =
multiline === 0 ? 'single-value' : 'multi-value';
} else if (selectionType === 'Interval' && multiline === 0) {
propertyAnnotations['sap:filter-restriction'] = 'interval';
}
}
function setPropertyFilterable(entityType, property, propertyAnnotations) {
if (
entityType.isAggregateProperty(property.COLUMN_NAME) ||
property.COLUMN_NAME === entityType.keys.generatedKey
) {
propertyAnnotations['sap:filterable'] = 'false';
}
}
exports.createEntityTypeAnnotations = createEntityTypeAnnotations;
/**
* Creates object containing the annotations for the specified entityType.
*
* @param {object} entityType - instance of EntityType, for which the annotations should be created.
* This parameter must be specified.
*
* @returns {object} object containing the applicable annotations for the specified entity type, for example:
* {
* "sap:semantics" : "aggregate"
* }
*/
function createEntityTypeAnnotations(entityType) {
const entityTypeAnnotations = {};
setEntityTypeSemantics(entityType, entityTypeAnnotations);
return entityTypeAnnotations;
}
exports._setEntityTypeSemantics = setEntityTypeSemantics;
function setEntityTypeSemantics(entityType, entityTypeAnnotations) {
if (entityType.kind === EntityType.entityKind.inputParameters) {
entityTypeAnnotations['sap:semantics'] = 'parameters';
} else if (
entityType.hasAggregates() ||
entityType.hasMeasureProperties()
) {
entityTypeAnnotations['sap:semantics'] = 'aggregate';
}
}
exports.createEntitySetAnnotations = createEntitySetAnnotations;
/**
* Creates object containing the annotations for the entity set of the specified entityType.
*
* @param {object} entityType - instance of EntityType for the entity set, for which the annotations should be created.
* This parameter must be specified.
*
* @returns {object} object containing the applicable annotations for the entity set, for example:
* {
* "sap:addressable" : "false",
* "sap:updatable" : "false"
* }
*/
function createEntitySetAnnotations(entityType) {
const entitySetAnnotations = {};
setEntitySetAddressable(entityType, entitySetAnnotations);
setEntitySetCreatable(entityType, entitySetAnnotations);
setEntitySetUpdatable(entityType, entitySetAnnotations);
setEntitySetDeletable(entityType, entitySetAnnotations);
return entitySetAnnotations;
}
function setEntitySetAddressable(entityType, entitySetAnnotations) {
if (
entityType.kind === EntityType.entityKind.calculationView ||
entityType.kind === EntityType.entityKind.inputParameters
) {
entitySetAnnotations['sap:addressable'] = 'false';
}
}
function setEntitySetCreatable(entityType, entitySetAnnotations) {
if (!entityType.isCreatable()) {
entitySetAnnotations['sap:creatable'] = 'false';
}
}
function setEntitySetUpdatable(entityType, entitySetAnnotations) {
if (!entityType.isUpdatable()) {
entitySetAnnotations['sap:updatable'] = 'false';
}
}
function setEntitySetDeletable(entityType, entitySetAnnotations) {
if (!entityType.isDeletable()) {
entitySetAnnotations['sap:deletable'] = 'false';
}
}
exports.createNavigationPropertyAnnotations =
createNavigationPropertyAnnotations;
/**
* Returns object containing annotations for the navigation property. The method accepts no parameters, because
* the returned annotations are the same for all the navigation properties and describe the operations, which are
* supported by the XSOData service for the navigation properties in general, i.e. regardless of the entity type.
*
* @returns {object} object containing annotations for the navigation property, for example:
* {
* "sap:creatable" : "false",
* "sap:filterable" : "false"
* }
*/
function createNavigationPropertyAnnotations() {
return NAVIGATION_PROPERTY_ANNOTATIONS;
}
exports.createAssociationSetAnnotations = createAssociationSetAnnotations;
/**
* Creates object containing the annotations for the specified associationSet.
*
* @param {object} associationSet - instance of Association, for which the annotations should be created.
* This parameter must be specified.
*
* @returns {object} object containing the applicable annotations for the specified Association Set, for example:
* {
* "sap:creatable" : "false",
* "sap:updatable" : "false"
* }
*/
function createAssociationSetAnnotations(associationSet) {
return associationSet.isInputParametersAssociation
? IP_ASSOCIATION_SET_ANNOTATIONS
: {};
}