UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

1,491 lines (1,332 loc) 189 kB
/*! * OpenUI5 * (c) Copyright 2009-2021 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ // Disable some ESLint rules. camelcase (some "_" in names to indicate indexed variables (like in math)), valid-jsdoc (not completed yet), no-warning-comments (some TODOs are left) // All other warnings, errors should be resolved /*eslint-disable camelcase, valid-jsdoc, no-warning-comments */ // Provides API for analytical extensions in OData service metadata sap.ui.define([ 'sap/ui/model/Filter', 'sap/ui/model/FilterOperator', 'sap/ui/model/Sorter', './AnalyticalVersionInfo', "sap/base/security/encodeURL" ], function(Filter, FilterOperator, Sorter, AnalyticalVersionInfo, encodeURL) { "use strict"; /** * The OData4Analytics API is purely experimental, not yet functionally complete * and not meant for productive usage. At present, its only purpose is to * demonstrate how easy analytical extensions of OData4SAP can be consumed. * * <em>USE OBJECTS VIA METHODS ONLY - DO NOT ACCESS JAVASCRIPT OBJECT PROPERTIES DIRECTLY !</em> * * Lazy initialization of attributes will cause unexpected values when you * access object attributes directly. * * @author SAP SE * @experimental This module is only for experimental use! * @namespace * @alias sap.ui.model.analytics.odata4analytics * @protected */ var odata4analytics = odata4analytics || {}, rOnlyDigits = /^\d+$/; odata4analytics.constants = {}; odata4analytics.constants["SAP_NAMESPACE"] = "http://www.sap.com/Protocols/SAPData"; odata4analytics.constants["VERSION"] = "0.7"; odata4analytics.helper = { /* * @param {object[]} [aOldColumns] * @param {object[]} aNewColumns * @param {function} [fnFormatterChanged] * called for each column where only a formatter has changed * @returns {number} 0: same, 1: only formatters changed, 2: important changes */ deepEqual : function (aOldColumns, aNewColumns, fnFormatterChanged) { var oNewColumn, oOldColumn, iResult = 0, i, n; if (!aOldColumns || aOldColumns.length !== aNewColumns.length) { return 2; } if (aOldColumns !== aNewColumns) { for (i = 0, n = aOldColumns.length; i < n; i += 1) { oOldColumn = aOldColumns[i]; oNewColumn = aNewColumns[i]; if (oOldColumn.grouped !== oNewColumn.grouped || oOldColumn.inResult !== oNewColumn.inResult || oOldColumn.level !== oNewColumn.level || oOldColumn.name !== oNewColumn.name || oOldColumn.total !== oNewColumn.total || oOldColumn.visible !== oNewColumn.visible) { return 2; } if (oOldColumn.formatter !== oNewColumn.formatter) { iResult = 1; if (fnFormatterChanged) { fnFormatterChanged(oNewColumn); } } } } return iResult; }, /* * Old helpers that got replaced by robust functions provided by the UI5 ODataModel */ /* renderPropertyKeyValue : function(sKeyValue, sPropertyEDMTypeName) { if (typeof sKeyValue == "string" && sKeyValue.charAt(0) == "'") throw "Illegal property value starting with a quote"; switch (sPropertyEDMTypeName) { case 'Edm.String': return "'" + sKeyValue + "'"; case 'Edm.DateTime': return "datetime'" + sKeyValue + "'"; case 'Edm.Guid': return "guid'" + sKeyValue + "'"; case 'Edm.Time': return "time'" + sKeyValue + "'"; case 'Edm.DateTimeOffset': return "datetimeoffset'" + sKeyValue + "'"; default: return sKeyValue; } }, renderPropertyFilterValue : function(sFilterValue, sPropertyEDMTypeName) { if (typeof sFilterValue == "string" && sFilterValue.charAt(0) == "'") throw "Illegal property value starting with a quote"; switch (sPropertyEDMTypeName) { case 'Edm.String': return "'" + sFilterValue + "'"; case 'Edm.DateTime': return "datetime'" + sFilterValue + "'"; case 'Edm.Guid': return "guid'" + sFilterValue + "'"; case 'Edm.Time': return "time'" + sFilterValue + "'"; case 'Edm.DateTimeOffset': return "datetimeoffset'" + sFilterValue + "'"; default: return sFilterValue; } }, */ tokenizeNametoLabelText : function(sName) { var sLabel = ""; // remove leading 'P_' often used for parameter properties on HANA sLabel = sName.replace(/^P_(.*)/, "$1"); // split UpperCamelCase in words (treat numbers and _ as upper case) sLabel = sLabel.replace(/([^A-Z0-9_]+)([A-Z0-9_])/g, "$1 $2"); // split acronyms in words sLabel = sLabel.replace(/([A-Z0-9_]{2,})([A-Z0-9_])([^A-Z0-9_]+)/g, "$1 $2$3"); // remove trailing _E sLabel = sLabel.replace(/(.*) _E$/, "$1"); // remove underscores that were identified as upper case sLabel = sLabel.replace(/(.*) _(.*)/g, "$1 $2"); return sLabel; } }; /** * Create a representation of the analytical semantics of OData service metadata * * @param {object} * oModelReference An instance of ReferenceByURI, ReferenceByModel or * ReferenceWithWorkaround for locating the OData service. * @param {object} * [mParameter] Additional parameters for controlling the model construction. Currently supported are: * <li> sAnnotationJSONDoc - A JSON document providing extra annotations to the elements of the * structure of the given service * </li> * <li> modelVersion - Parameter to define which ODataModel version should be used, in you use * 'odata4analytics.Model.ReferenceByURI': 1 (default), 2 * see also: AnalyticalVersionInfo constants * </li> * * @class Representation of an OData model with analytical annotations defined * by OData4SAP. * @name sap.ui.model.analytics.odata4analytics.Model * @public */ odata4analytics.Model = function(oModelReference, mParameter) { this._init(oModelReference, mParameter); }; /** * Create a reference to an OData model by the URI of the related OData service. * * @param {string} * sURI holding the URI. * * @class Handle to an OData model by the URI pointing to it. * @name sap.ui.model.analytics.odata4analytics.Model.ReferenceByURI * @public */ odata4analytics.Model.ReferenceByURI = function(sURI) { return { sServiceURI : sURI }; }; /** * Create a reference to an OData model already loaded elsewhere with the help * of SAPUI5. * * @param {object} * oModel holding the OData model. * * @class Handle to an already instantiated SAPUI5 OData model. * @name sap.ui.model.analytics.odata4analytics.Model.ReferenceByModel * @public */ odata4analytics.Model.ReferenceByModel = function(oModel) { return { oModel : oModel }; }; /** * Create a reference to an OData model having certain workarounds activated. A * workaround is an implementation that changes the standard behavior of the API * to overcome some gap or limitation in the OData provider. The workaround * implementation can be conditionally activated by passing the identifier in * the constructor. * * Known workaround identifiers are: * * <li>"CreateLabelsFromTechnicalNames" - If a property has no label text, it * gets generated from the property name.</li> * * <li>"IdentifyTextPropertiesByName" -If a dimension property has no text and * another property with the same name and an appended "Name", "Text" etc. * exists, they are linked via annotation.</li> * * * @param {object} * oModel holding a reference to the OData model, obtained * by odata4analytics.Model.ReferenceByModel or by * sap.odata4analytics.Model.ReferenceByURI. * @param {string[]} * aWorkaroundID listing all workarounds to be applied. * * @class Handle to an already instantiated SAPUI5 OData model. * @name sap.ui.model.analytics.odata4analytics.Model.ReferenceWithWorkaround * @public */ odata4analytics.Model.ReferenceWithWorkaround = function(oModel, aWorkaroundID) { return { oModelReference : oModel, aWorkaroundID : aWorkaroundID }; }; odata4analytics.Model.prototype = { /** * initialize a new object * * @private */ _init : function(oModelReference, mParameter) { if (typeof mParameter == "string") { throw "Deprecated second argument: Adjust your invocation by passing an object with a property sAnnotationJSONDoc as a second argument instead"; } this._mParameter = mParameter; var that = this; /* * get access to OData model */ this._oActivatedWorkarounds = {}; if (oModelReference && oModelReference.aWorkaroundID) { for (var i = -1, sID; (sID = oModelReference.aWorkaroundID[++i]) !== undefined;) { this._oActivatedWorkarounds[sID] = true; } oModelReference = oModelReference.oModelReference; } // check proper usage if (!oModelReference || (!oModelReference.sServiceURI && !oModelReference.oModel)) { throw "Usage with oModelReference being an instance of Model.ReferenceByURI or Model.ReferenceByModel"; } //check if a model is given, or we need to create one from the service URI if (oModelReference.oModel) { this._oModel = oModelReference.oModel; // find out which model version we are running this._iVersion = AnalyticalVersionInfo.getVersion(this._oModel); checkForMetadata(); } else if (mParameter && mParameter.modelVersion === AnalyticalVersionInfo.V2) { // Check if the user wants a V2 model var V2ODataModel = sap.ui.requireSync("sap/ui/model/odata/v2/ODataModel"); this._oModel = new V2ODataModel(oModelReference.sServiceURI); this._iVersion = AnalyticalVersionInfo.V2; checkForMetadata(); } else { //default is V1 Model var ODataModel = sap.ui.requireSync("sap/ui/model/odata/ODataModel"); this._oModel = new ODataModel(oModelReference.sServiceURI); this._iVersion = AnalyticalVersionInfo.V1; checkForMetadata(); } if (this._oModel.getServiceMetadata() && this._oModel.getServiceMetadata().dataServices == undefined) { throw "Model could not be loaded"; } /** * Check if the metadata is already available, if not defere the interpretation of the Metadata */ function checkForMetadata() { // V2 supports asynchronous loading of metadata // we have to register for the MetadataLoaded Event in case, the data is not loaded already if (!that._oModel.getServiceMetadata()) { that._oModel.attachMetadataLoaded(processMetadata); } else { // metadata already loaded processMetadata(); } } /** * Kickstart the interpretation of the metadata, * either called directly if metadata is available, or deferred and then * executed via callback by the model during the metadata loaded event. */ function processMetadata () { //only interprete the metadata if the analytics model was not initialised yet if (that.bIsInitialized) { return; } //mark analytics model as initialized that.bIsInitialized = true; /* * add extra annotations if provided */ if (mParameter && mParameter.sAnnotationJSONDoc) { that.mergeV2Annotations(mParameter.sAnnotationJSONDoc); } that._interpreteMetadata(that._oModel.getServiceMetadata().dataServices); } }, /** * @private */ _interpreteMetadata: function (oMetadata) { /* * parse OData model for analytic queries */ this._oQueryResultSet = {}; this._oParameterizationSet = {}; this._oEntityTypeSet = {}; this._oEntitySetSet = {}; this._oEntityTypeNameToEntitySetMap = {}; // loop over all schemas and entity containers // TODO: extend this implementation to support many schemas var oSchema = this._oModel.getServiceMetadata().dataServices.schema[0]; // remember default container for (var j = -1, oContainer; (oContainer = oSchema.entityContainer[++j]) !== undefined;) { if (oContainer.isDefaultEntityContainer == "true") { this._oDefaultEntityContainer = oContainer; break; } } var aEntityType = oSchema.entityType; // A. preparation // A.1 collect all relevant OData entity types representing query // results, parameters var aQueryResultEntityTypes = [], aParameterEntityTypes = [], aUnsortedEntityTypes = []; for (var k = -1, oType; (oType = aEntityType[++k]) !== undefined;) { var bProcessed = false; if (oType.extensions != undefined) { for (var l = -1, oExtension; (oExtension = oType.extensions[++l]) !== undefined;) { if (oExtension.namespace == odata4analytics.constants.SAP_NAMESPACE && oExtension.name == "semantics") { bProcessed = true; switch (oExtension.value) { case "aggregate": aQueryResultEntityTypes.push(oType); break; case "parameters": aParameterEntityTypes.push(oType); break; default: aUnsortedEntityTypes.push(oType); } } if (bProcessed) { continue; } } if (!bProcessed) { aUnsortedEntityTypes.push(oType); } } else { aUnsortedEntityTypes.push(oType); } } // A.2 create entity type representations for the unsorted types for (var m = -1, oType2; (oType2 = aUnsortedEntityTypes[++m]) !== undefined;) { var oEntityType = new odata4analytics.EntityType(this._oModel.getServiceMetadata(), oSchema, oType2); this._oEntityTypeSet[oEntityType.getQName()] = oEntityType; var aEntitySet = this._getEntitySetsOfType(oSchema, oEntityType.getQName()); if (aEntitySet.length == 0) { throw "Invalid consumption model: No entity set for entity type " + oEntityType.getQName() + " found"; } if (aEntitySet.length > 1) { throw "Unsupported consumption model: More than one entity set for entity type " + oEntityType.getQName() + " found"; } var oEntitySet = new odata4analytics.EntitySet(this._oModel.getServiceMetadata(), oSchema, aEntitySet[0][0], aEntitySet[0][1], oEntityType); this._oEntitySetSet[oEntitySet.getQName()] = oEntitySet; this._oEntityTypeNameToEntitySetMap[oEntityType.getQName()] = oEntitySet; } // B. create objects for the analytical extensions of these entity types // B.1 create parameters // temporary storage for lookup of entity *types* annotated with // parameters semantics var oParameterizationEntityTypeSet = {}; for (var n = -1, oType3; (oType3 = aParameterEntityTypes[++n]) !== undefined;) { // B.1.1 create object for OData entity type var oEntityType2 = new odata4analytics.EntityType(this._oModel.getServiceMetadata(), oSchema, oType3); this._oEntityTypeSet[oEntityType2.getQName()] = oEntityType2; // B.1.2 get sets with this type var aEntitySet2 = this._getEntitySetsOfType(oSchema, oEntityType2.getQName()); if (aEntitySet2.length == 0) { throw "Invalid consumption model: No entity set for parameter entity type " + oEntityType2.getQName() + " found"; } if (aEntitySet2.length > 1) { throw "Unsupported consumption model: More than one entity set for parameter entity type " + oEntityType2.getQName() + " found"; } // B.1.3 create object for OData entity set var oEntitySet2 = new odata4analytics.EntitySet(this._oModel.getServiceMetadata(), oSchema, aEntitySet2[0][0], aEntitySet2[0][1], oEntityType2); this._oEntitySetSet[oEntitySet2.getQName()] = oEntitySet2; this._oEntityTypeNameToEntitySetMap[oEntityType2.getQName()] = oEntitySet2; // B.1.4 create object for parameters and related OData entity var oParameterization = new odata4analytics.Parameterization(oEntityType2, oEntitySet2); this._oParameterizationSet[oParameterization.getName()] = oParameterization; oParameterizationEntityTypeSet[oEntityType2.getQName()] = oParameterization; // B.1.5 recognize all available parameter value helps var sParameterizationEntityTypeQTypeName = oEntityType2.getQName(); if (oSchema.association != undefined) { for (var p = -1, oAssoc; (oAssoc = oSchema.association[++p]) !== undefined;) { // value help always established by a referential constraint // on an association if (oAssoc.referentialConstraint == undefined) { continue; } var sParameterValueHelpEntityTypeQTypeName = null; // B.1.5.1 relevant only if one end has same type as the // given parameterization entity type if (oAssoc.end[0].type == sParameterizationEntityTypeQTypeName && oAssoc.end[0].multiplicity == "*" && oAssoc.end[1].multiplicity == "1") { sParameterValueHelpEntityTypeQTypeName = oAssoc.end[1].type; } else if (oAssoc.end[1].type == sParameterizationEntityTypeQTypeName && oAssoc.end[1].multiplicity == "*" && oAssoc.end[0].multiplicity == "1") { sParameterValueHelpEntityTypeQTypeName = oAssoc.end[0].type; } if (!sParameterValueHelpEntityTypeQTypeName) { continue; } // B.1.5.2 check if the referential constraint declares a // parameter property as dependent if (oAssoc.referentialConstraint.dependent.propertyRef.length != 1) { continue; } var oParameter = oParameterization.findParameterByName(oAssoc.referentialConstraint.dependent.propertyRef[0].name); if (oParameter == null) { continue; } // B.1.5.3 Register the recognized parameter value help // entity type and set and link them to the parameter var oValueListEntityType = this._oEntityTypeSet[sParameterValueHelpEntityTypeQTypeName]; var oValueListEntitySet = this._oEntityTypeNameToEntitySetMap[sParameterValueHelpEntityTypeQTypeName]; oParameter.setValueSetEntity(oValueListEntityType, oValueListEntitySet); } } } // B.2 // B.2 create analytic queries for (var r = -1, oType4; (oType4 = aQueryResultEntityTypes[++r]) !== undefined;) { // B.2.1 create object for OData entity var oEntityType3 = new odata4analytics.EntityType(this._oModel.getServiceMetadata(), oSchema, oType4); this._oEntityTypeSet[oEntityType3.getQName()] = oEntityType3; var sQueryResultEntityTypeQTypeName = oEntityType3.getQName(); // B.2.2 find assocs to parameter entity types var oParameterization3 = null; var oAssocFromParamsToResult = null; if (oSchema.association != undefined) { for (var s = -1, oAssoc2; (oAssoc2 = oSchema.association[++s]) !== undefined;) { var sParameterEntityTypeQTypeName = null; if (oAssoc2.end[0].type == sQueryResultEntityTypeQTypeName) { sParameterEntityTypeQTypeName = oAssoc2.end[1].type; } else if (oAssoc2.end[1].type == sQueryResultEntityTypeQTypeName) { sParameterEntityTypeQTypeName = oAssoc2.end[0].type; } else { continue; } // B.2.2.2 fetch Parameterization object if any var oMatchingParameterization = null; oMatchingParameterization = oParameterizationEntityTypeSet[sParameterEntityTypeQTypeName]; if (oMatchingParameterization != null) { if (oParameterization3 != null) { // TODO: extend this implementation to support more // than one related parameter entity type throw "LIMITATION: Unable to handle multiple parameter entity types of query entity " + oEntityType3.name; } else { oParameterization3 = oMatchingParameterization; oAssocFromParamsToResult = oAssoc2; } } } } // B.2.3 get sets with this type var aEntitySet3 = this._getEntitySetsOfType(oSchema, oEntityType3.getQName()); if (aEntitySet3.length != 1) { throw "Invalid consumption model: There must be exactly one entity set for an entity type annotated with aggregating semantics"; } // B.2.4 create object for OData entity set of analytic query result var oEntitySet3 = new odata4analytics.EntitySet(this._oModel.getServiceMetadata(), oSchema, aEntitySet3[0][0], aEntitySet3[0][1], oEntityType3); this._oEntitySetSet[oEntitySet3.getQName()] = oEntitySet3; this._oEntityTypeNameToEntitySetMap[oEntityType3.getQName()] = oEntitySet3; // B.2.5 create object for analytic query result, related OData // entity type and set and (if any) related parameters // object var oQueryResult = new odata4analytics.QueryResult(this, oEntityType3, oEntitySet3, oParameterization3); this._oQueryResultSet[oQueryResult.getName()] = oQueryResult; // B.2.6 set target result for found parameterization if (oParameterization3) { oParameterization3.setTargetQueryResult(oQueryResult, oAssocFromParamsToResult); } // B.2.7 recognize all available dimension value helps if (oSchema.association != undefined) { for (var t = -1, oAssoc3; (oAssoc3 = oSchema.association[++t]) !== undefined;) { // value help always established by a referential constraint // on an association if (oAssoc3.referentialConstraint == undefined) { continue; } var sDimensionValueHelpEntityTypeQTypeName = null; // B.2.7.1 relevant only if one end has same type as the // given query result entity type if (oAssoc3.end[0].type == sQueryResultEntityTypeQTypeName && oAssoc3.end[0].multiplicity == "*" && oAssoc3.end[1].multiplicity == "1") { sDimensionValueHelpEntityTypeQTypeName = oAssoc3.end[1].type; } else if (oAssoc3.end[1].type == sQueryResultEntityTypeQTypeName && oAssoc3.end[1].multiplicity == "*" && oAssoc3.end[0].multiplicity == "1") { sDimensionValueHelpEntityTypeQTypeName = oAssoc3.end[0].type; } if (!sDimensionValueHelpEntityTypeQTypeName) { continue; } // B.2.7.2 check if the referential constraint declares a // dimension property as dependent if (oAssoc3.referentialConstraint.dependent.propertyRef.length != 1) { continue; } var oDimension = oQueryResult.findDimensionByName(oAssoc3.referentialConstraint.dependent.propertyRef[0].name); if (oDimension == null) { continue; } // B.2.7.3 Register the recognized dimension value help // entity set and link it to the dimension var oDimensionMembersEntitySet = this._oEntityTypeNameToEntitySetMap[sDimensionValueHelpEntityTypeQTypeName]; oDimension.setMembersEntitySet(oDimensionMembersEntitySet); } } } }, /* * Control data for adding extra annotations to service metadata * * @private */ oUI5ODataModelAnnotatableObject : { objectName : "schema", keyPropName : "namespace", extensions : true, aSubObject : [ { objectName : "entityType", keyPropName : "name", extensions : true, aSubObject : [ { objectName : "property", keyPropName : "name", aSubObject : [], extensions : true } ] }, { objectName : "entityContainer", keyPropName : "name", extensions : false, aSubObject : [ { objectName : "entitySet", keyPropName : "name", extensions : true, aSubObject : [] } ] } ] }, /* * merging extra annotations with provided service metadata * * @private */ mergeV2Annotations : function(sAnnotationJSONDoc) { var oAnnotation = null; try { oAnnotation = JSON.parse(sAnnotationJSONDoc); } catch (exception) { return; } var oMetadata; try { oMetadata = this._oModel.getServiceMetadata().dataServices; } catch (exception) { return; } // find "schema" entry in annotation document for ( var propName in oAnnotation) { if (!(this.oUI5ODataModelAnnotatableObject.objectName == propName)) { continue; } if (!(oAnnotation[propName] instanceof Array)) { continue; } this.mergeV2AnnotationLevel(oMetadata[this.oUI5ODataModelAnnotatableObject.objectName], oAnnotation[this.oUI5ODataModelAnnotatableObject.objectName], this.oUI5ODataModelAnnotatableObject); break; } return; }, /* * merging extra annotations with a given service metadata object * * @private */ mergeV2AnnotationLevel : function(aMetadata, aAnnotation, oUI5ODataModelAnnotatableObject) { for (var i = -1, oAnnotation; (oAnnotation = aAnnotation[++i]) !== undefined;) { for (var j = -1, oMetadata; (oMetadata = aMetadata[++j]) !== undefined;) { if (!(oAnnotation[oUI5ODataModelAnnotatableObject.keyPropName] == oMetadata[oUI5ODataModelAnnotatableObject.keyPropName])) { continue; } // found match: apply extensions from oAnnotation object to // oMetadata object if (oAnnotation["extensions"] != undefined) { if (oMetadata["extensions"] == undefined) { oMetadata["extensions"] = []; } for (var l = -1, oAnnotationExtension; (oAnnotationExtension = oAnnotation["extensions"][++l]) !== undefined;) { var bFound = false; for (var m = -1, oMetadataExtension; (oMetadataExtension = oMetadata["extensions"][++m]) !== undefined;) { if (oAnnotationExtension.name == oMetadataExtension.name && oAnnotationExtension.namespace == oMetadataExtension.namespace) { oMetadataExtension.value = oAnnotationExtension.value; bFound = true; break; } } if (!bFound) { oMetadata["extensions"].push(oAnnotationExtension); } } } // walk down to sub objects for (var k = -1, oUI5ODataModelAnnotatableSubObject; (oUI5ODataModelAnnotatableSubObject = oUI5ODataModelAnnotatableObject.aSubObject[++k]) !== undefined;) { for ( var propName in oAnnotation) { if (!(oUI5ODataModelAnnotatableSubObject.objectName == propName)) { continue; } if (!(oAnnotation[oUI5ODataModelAnnotatableSubObject.objectName] instanceof Array)) { continue; } if ((oMetadata[oUI5ODataModelAnnotatableSubObject.objectName] == undefined) || (!(oMetadata[oUI5ODataModelAnnotatableSubObject.objectName] instanceof Array))) { continue; } this.mergeV2AnnotationLevel(oMetadata[oUI5ODataModelAnnotatableSubObject.objectName], oAnnotation[oUI5ODataModelAnnotatableSubObject.objectName], oUI5ODataModelAnnotatableSubObject); break; } } } } return; }, /** * Find analytic query result by name * * @param {string} * sName Fully qualified name of query result entity set * @returns {sap.ui.model.analytics.odata4analytics.QueryResult} The query result object * with this name or null if it does not exist * @public * @function * @name sap.ui.model.analytics.odata4analytics.Model#findQueryResultByName */ findQueryResultByName : function(sName) { var oQueryResult = this._oQueryResultSet[sName]; // Everybody should have a second chance: // If the name was not fully qualified, check if it is in the default // container if (!oQueryResult && this._oDefaultEntityContainer) { var sQName = this._oDefaultEntityContainer.name + "." + sName; oQueryResult = this._oQueryResultSet[sQName]; } return oQueryResult; }, /** * Get the names of all query results (entity sets) offered by the model * * @returns {string[]} List of all query result names * @public * @function * @name sap.ui.model.analytics.odata4analytics.Model#getAllQueryResultNames */ getAllQueryResultNames : function() { if (this._aQueryResultNames) { return this._aQueryResultNames; } this._aQueryResultNames = new Array(0); for ( var sName in this._oQueryResultSet) { this._aQueryResultNames.push(this._oQueryResultSet[sName].getName()); } return this._aQueryResultNames; }, /** * Get all query results offered by the model * * @returns {object} An object with individual JS properties for each query * result included in the model. The JS object properties all are * objects of type odata4analytics.QueryResult. The names * of the JS object properties are given by the entity set names * representing the query results. * @public * @function * @name sap.ui.model.analytics.odata4analytics.Model#getAllQueryResults */ getAllQueryResults : function() { return this._oQueryResultSet; }, /** * Get underlying OData model provided by SAPUI5 * * @returns {object} The SAPUI5 representation of the model. * @public * @function * @name sap.ui.model.analytics.odata4analytics.Model#getODataModel */ getODataModel : function() { return this._oModel; }, /** * Private methods */ /** * Find entity sets of a given type * * @private */ _getEntitySetsOfType : function(oSchema, sQTypeName) { var aEntitySet = []; for (var i = -1, oEntityContainer; (oEntityContainer = oSchema.entityContainer[++i]) !== undefined;) { for (var j = -1, oEntitySet; (oEntitySet = oEntityContainer.entitySet[++j]) !== undefined;) { if (oEntitySet.entityType == sQTypeName) { aEntitySet.push([ oEntityContainer, oEntitySet ]); } } } return aEntitySet; }, /** * Private member attributes */ _mParameter : null, _oModel : null, _oDefaultEntityContainer : null, _aQueryResultNames : null, _oQueryResultSet : null, _oParameterizationSet : null, _oEntityTypeSet : null, _oEntitySetSet : null, _oEntityTypeNameToEntitySetMap : null, _oActivatedWorkarounds : null }; /** ******************************************************************** */ /** * Create a representation of an analytic query. Do not create your own instances. * * @param {sap.ui.model.analytics.odata4analytics.Model} * oModel The analytical model containing this query result entity * set * @param {sap.ui.model.analytics.odata4analytics.EntityType} * oEntityType The OData entity type for this query * @param {sap.ui.model.analytics.odata4analytics.EntitySet} * oEntitySet The OData entity set for this query offered by the * OData service * @param {sap.ui.model.analytics.odata4analytics.Parameterization} * oParameterization The parameterization of this query, if any * * @this (QueryResult) * * @class Representation of an entity type annotated with * sap:semantics="aggregate". * @name sap.ui.model.analytics.odata4analytics.QueryResult * @public */ odata4analytics.QueryResult = function(oModel, oEntityType, oEntitySet, oParameterization) { this._init(oModel, oEntityType, oEntitySet, oParameterization); }; odata4analytics.QueryResult.prototype = { /** * initialize new object * * @private */ _init : function(oModel, oEntityType, oEntitySet, oParameterization, oAssocFromParamsToResult) { this._oModel = oModel; this._oEntityType = oEntityType; this._oEntitySet = oEntitySet; this._oParameterization = oParameterization; this._oDimensionSet = {}; this._oMeasureSet = {}; // parse entity type for analytic semantics described by annotations var aProperty = oEntityType.getTypeDescription().property; var oAttributeForPropertySet = {}; for (var i = -1, oProperty; (oProperty = aProperty[++i]) !== undefined;) { if (oProperty.extensions == undefined) { continue; } for (var j = -1, oExtension; (oExtension = oProperty.extensions[++j]) !== undefined;) { if (!oExtension.namespace == odata4analytics.constants.SAP_NAMESPACE) { continue; } switch (oExtension.name) { case "aggregation-role": switch (oExtension.value) { case "dimension": { var oDimension = new odata4analytics.Dimension(this, oProperty); this._oDimensionSet[oDimension.getName()] = oDimension; break; } case "measure": { var oMeasure = new odata4analytics.Measure(this, oProperty); this._oMeasureSet[oMeasure.getName()] = oMeasure; break; } case "totaled-properties-list": this._oTotaledPropertyListProperty = oProperty; break; default: } break; case "attribute-for": { var oDimensionAttribute = new odata4analytics.DimensionAttribute(this, oProperty); var oKeyProperty = oDimensionAttribute.getKeyProperty(); oAttributeForPropertySet[oKeyProperty.name] = oDimensionAttribute; break; } default: } } } // assign dimension attributes to the respective dimension objects for ( var sDimensionAttributeName in oAttributeForPropertySet) { var oDimensionAttribute2 = oAttributeForPropertySet[sDimensionAttributeName]; oDimensionAttribute2.getDimension().addAttribute(oDimensionAttribute2); } // apply workaround for missing text properties if requested if (oModel._oActivatedWorkarounds.IdentifyTextPropertiesByName) { var aMatchedTextPropertyName = []; for ( var oDimName in this._oDimensionSet) { var oDimension2 = this._oDimensionSet[oDimName]; if (!oDimension2.getTextProperty()) { var oTextProperty = null; // order of matching is // significant! oTextProperty = oEntityType.findPropertyByName(oDimName + "Name"); if (!oTextProperty) { oTextProperty = oEntityType.findPropertyByName(oDimName + "Text"); } if (!oTextProperty) { oTextProperty = oEntityType.findPropertyByName(oDimName + "Desc"); } if (!oTextProperty) { oTextProperty = oEntityType.findPropertyByName(oDimName + "Description"); } if (oTextProperty) { // any match? oDimension2.setTextProperty(oTextProperty); // link // dimension // with text // property aMatchedTextPropertyName.push(oTextProperty.name); } } } // make sure that any matched text property is not exposed as // dimension (according to spec) for (var t = -1, sPropertyName; (sPropertyName = aMatchedTextPropertyName[++t]) !== undefined;) { delete this._oDimensionSet[sPropertyName]; } } }, /** * Get the name of the query result * * @returns {string} The fully qualified name of the query result, which is * identical with the name of the entity set representing the query * result in the OData service * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getName */ getName : function() { return this.getEntitySet().getQName(); }, /** * Get the parameterization of this query result * * @returns {sap.ui.model.analytics.odata4analytics.Parameterization} The object for the * parameterization or null if the query result is not * parameterized * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getParameterization */ getParameterization : function() { return this._oParameterization; }, /** * Get the names of all dimensions included in the query result * * @returns {string[]} List of all dimension names * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getAllDimensionNames */ getAllDimensionNames : function() { if (this._aDimensionNames) { return this._aDimensionNames; } this._aDimensionNames = []; for ( var sName in this._oDimensionSet) { this._aDimensionNames.push(this._oDimensionSet[sName].getName()); } return this._aDimensionNames; }, /** * Get all dimensions included in this query result * * @returns {object} An object with individual JS properties for each * dimension included in the query result. The JS object properties * all are objects of type odata4analytics.Dimension. The * names of the JS object properties are given by the OData entity * type property names representing the dimension keys. * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getAllDimensions */ getAllDimensions : function() { return this._oDimensionSet; }, /** * Get the names of all measures included in the query result * * @returns {string[]} List of all measure names * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getAllMeasureNames */ getAllMeasureNames : function() { if (this._aMeasureNames) { return this._aMeasureNames; } this._aMeasureNames = []; for ( var sName in this._oMeasureSet) { this._aMeasureNames.push(this._oMeasureSet[sName].getName()); } return this._aMeasureNames; }, /** * Get all measures included in this query result * * @returns {object} An object with individual JS properties for each * measure included in the query result. The JS object properties * all are objects of type odata4analytics.Measure. The * names of the JS object properties are given by the OData entity * type property names representing the measure raw values. * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getAllMeasures */ getAllMeasures : function() { return this._oMeasureSet; }, /** * Find dimension by name * * @param {string} * sName Dimension name * @returns {sap.ui.model.analytics.odata4analytics.Dimension} The dimension object with * this name or null if it does not exist * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#findDimensionByName */ findDimensionByName : function(sName) { return this._oDimensionSet[sName]; }, /** * Find dimension by property name * * @param {string} * sName Property name * @returns {sap.ui.model.analytics.odata4analytics.Dimension} The dimension object to * which the given property name is related, because the property * holds the dimension key, its text, or is an attribute of this * dimension. If no such dimension exists, null is returned. * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#findDimensionByPropertyName */ findDimensionByPropertyName : function(sName) { if (this._oDimensionSet[sName]) { // the easy case return this._oDimensionSet[sName]; } for ( var sDimensionName in this._oDimensionSet) { var oDimension = this._oDimensionSet[sDimensionName]; var oTextProperty = oDimension.getTextProperty(); if (oTextProperty && oTextProperty.name == sName) { return oDimension; } if (oDimension.findAttributeByName(sName)) { return oDimension; } } return null; }, /** * Get property holding the totaled property list * * @returns {object} The datajs object representing this property * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getTotaledPropertiesListProperty */ getTotaledPropertiesListProperty : function() { return this._oTotaledPropertyListProperty; }, /** * Find measure by name * * @param {string} * sName Measure name * @returns {sap.ui.model.analytics.odata4analytics.Measure} The measure object with this * name or null if it does not exist * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#findMeasureByName */ findMeasureByName : function(sName) { return this._oMeasureSet[sName]; }, /** * Find measure by property name * * @param {string} * sName Property name * @returns {sap.ui.model.analytics.odata4analytics.Measure} The measure object to which * the given property name is related, because the property holds * the raw measure value or its formatted value. If no such measure * exists, null is returned. * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#findMeasureByPropertyName */ findMeasureByPropertyName : function(sName) { if (this._oMeasureSet[sName]) { // the easy case return this._oMeasureSet[sName]; } for ( var sMeasureName in this._oMeasureSet) { var oMeasure = this._oMeasureSet[sMeasureName]; var oFormattedValueProperty = oMeasure.getFormattedValueProperty(); if (oFormattedValueProperty && oFormattedValueProperty.name == sName) { return oMeasure; } } return null; }, /** * Get the analytical model containing the entity set for this query result * * @returns {object} The analytical representation of the OData model * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getModel */ getModel : function() { return this._oModel; }, /** * Get the entity type defining the type of this query result in the OData * model * * @returns {sap.ui.model.analytics.odata4analytics.EntityType} The OData entity type for * this query result * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getEntityType */ getEntityType : function() { return this._oEntityType; }, /** * Get the entity set representing this query result in the OData model * * @returns {sap.ui.model.analytics.odata4analytics.EntitySet} The OData entity set * representing this query result * @public * @function * @name sap.ui.model.analytics.odata4analytics.QueryResult#getEntitySet */ getEntitySet : function() { return this._oEntitySet; }, /** * Private member attributes */ _oModel : null, _oEntityType : null, _oEntitySet : null, _oParameterization : null, _aDimensionNames : null, _oDimensionSet : null, _aMeasureNames : null, _oMeasureSet : null, _oTotaledPropertyListProperty : null }; /** ******************************************************************** */ /** * Create a representation of a parameterization for an analytic query. Do not create your own instances. * * @param {sap.ui.model.analytics.odata4analytics.EntityType} * oEntityType The OData entity type for this parameterization * @param {sap.ui.model.analytics.odata4analytics.EntitySet} * oEntitySet The OData entity set for this parameterization offered * by the OData service * * @class Representation of an entity type annotated with * sap:semantics="parameters". * @name sap.ui.model.analytics.odata4analytics.Parameterization * @public */ odata4analytics.Parameterization = function(oEntityType, oEntitySet) { this._init(oEntityType, oEntitySet); }; odata4analytics.Parameterization.prototype = { /** * @private */ _init : function(oEntityType, oEntitySet) { this._oEntityType = oEntityType; this._oEntitySet = oEntitySet; this._oParameterSet = {}; // parse entity type for analytic semantics described by annotations var aProperty = oEntityType.getTypeDescription().property; for (var i = -1, oProperty; (oProperty = aProperty[++i]) !== undefined;) { if (oProperty.extensions == undefined) { continue; } for (var j = -1, oExtension; (oExtension = oProperty.extensions[++j]) !== undefined;) { if (!oExtension.namespace == odata4analytics.constants.SAP_NAMESPACE) { continue; } switch (oExtension.name) { // process parameter semantics case "parameter": { var oParameter = new odata4analytics.Parameter(this, oProperty); this._oParameterSet[oParameter.getName()] = oParameter; break; } default: } } } }, // to be called only by Model objects setTargetQueryResult : function(oQueryResult, oAssociation) { this._oQueryResult = oQueryResult; var sQAssocName = this._oEntityType.getSchema().namespace + "." + oAssociation.name; var aNavProp = this._oEntityType.getTypeDescription().navigationProperty; if (!aNavProp) { throw "Invalid consumption model: Parameters entity type lacks navigation property for association to query result entity type"; } for (var i = -1, oNavProp; (oNavProp = aNavProp[++i]) !== undefined;) { if (oNavProp.relationship == sQAssocName) { this._oNavPropToQueryResult = oNavProp.name; } } if (!this._oNavPropToQueryResult) { throw "Invalid consumption model: Parameters entity type lacks navigation property for association to query result entity type"; } }, getTargetQueryResult : function() { if (!this._oQueryResult) { throw "No target query result set"; } return this._oQueryResult; }, /** * Get the name of the parameter * * @returns {string} The name of the parameterization, which is identical * with the name of the entity set representing the * parameterization in the OData service * @public * @function * @name sap.ui.model.analytics.odata4analytics.Parameterization#getName */ getName : function() { return this.getEntitySet().getQName(); }, /** * Get the names of all parameters part of the parameterization * * @returns {string[]} List of all parameter names * @public * @function * @name sap.ui.model.analytics.odata4analytics.Parameterization#getAllParameterNames */ getAllParameterNames : function() { if (this._aParameterNames) { return this._aParameterNames; } this._aParameterNames = []; for ( var sName in this._oParameterSet) { this._aParameterNames.push(this._oParameterSet[sName].getName()); } return this._aParameterNames; }, /** * Get all parameters included in this parameterization * * @returns {object} An object with individual JS properties for each * parameter included in the query result. The JS object properties * all are objects of type odata4analytics.Parameter. The * names of the JS object properties are given by the OData entity * type property names representing the parameter keys. * @public * @function * @name sap.ui.model.analytics.odata4analytics.Parameterization#getAllParameters */ getAllParameters : function() { return this._oParameterSet; }, /** * Find parameter by name * * @param {string} * sName Parameter name * @returns {sap.ui.model.analytics.odata4analytics.Parameter} The parameter object with * this name or null if it does not exist * @public * @function * @name sap.ui.model.analytics.odata4analytics.Parameterization#findParameterByName */ findParameterByName : function(sName) { return this._oParameterSet[sName]; }, /** * Get navigation property to query result * * @returns {sap.ui.model.analytics.odata4analytics.QueryResult} The parameter object with * this name or null if it does not exist * @public * @function * @name sap.ui.model.analytics.odata4analytics.Parameterization#getNavigationPropertyToQueryResult */ getNavigationPropertyToQueryResult : function() { return this._oNavPropToQueryResult; }, /** * Get the entity type defining the type of this query result in the OData * model * * @returns {sap.ui.model.analytics.odata4analytics.EntityType} The OData entity type for * this query result * @public * @function * @name sap.ui.model.analytics.odata4analytics.Parameterization#getEntityType */ getEntityType : function() { return this._oEntityType; }, /** * Get the entity set representing this query result in the OData model * * @returns {sap.ui.model.analytics.odata4analytics.EntitySet} The OData entity set * representing this query result * @public * @function * @name sap.ui.model.analytics.odata4analytics.Parameterization#getEntitySet */ getEntitySet : function() { return this._oEntitySet; }, /** * Private member attributes */ _oEntityType : null, _oEntitySet : null, _oQueryResult : null, _oNavPropToQueryResult : null, _aParameterNames : null, _oParameterSet : null }; /** ******************************************************************** */ /** * Create a representation of a single parameter contained in a parameterization. Do not create your own instances. * * @param {sap.ui.model.analytics.odata4analytics.Parameterization} * oParameterization The parameterization containing this parameter * @param {object} * oProperty The datajs object object representing the text property * * @class Representation of a property annotated with sap:parameter. * @name sap.ui.model.analytics.odata4analytics.Parameter * @public */ odata4analytics.Parameter = function(oParameterization, oProperty) { this._init(oParameterization, oProperty); }; odata4analytics.Parameter.prototype = { /** * @private */ _init : function(oParameterization, oProperty) { this._oParameterization = oParameterization; this._oProperty = oProperty; var oEntityType = oParameterization.getEntityType(); if (oProperty.extensions != undefined) { for (var i = -1, oExtension; (oExtension = oProperty.extensions[++i]) !== undefined;) { if (!oExtension.namespace == odata4analytics.constants.SAP_NAMESPACE) { continue; } switch (oExtension.name) { case "parameter": switch (oExtension.value) { case "mandatory": this._bRequired = true; break; case "optional": this._bRequired = false; break; default: throw "Invalid annotation value for parameter property"; } break; case "label": this._sLabelText = oExtension.value; break; case "text": this._oTextProperty = oEntityType.findPropertyByName(oExtension.value); break; case "upper-boundary": this._bIntervalBoundaryParameter = true;