UNPKG

@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
'use strict'; // 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 : {}; }