UNPKG

@sap/xsodata

Version:

Expose data from a HANA database as OData V2 service with help of .xsodata files.

284 lines (218 loc) 9.77 kB
'use strict'; var dbutils = require('./../utils/typeConverter'); var typConv = require('./../utils/typeConverter'); var XMLWriter = require('xml-writer'); var contentTypeTools = require('./../utils/checkContentType'); var associationsUtil = require('./../utils/associations'); var Measurement = require('./../utils/measurement'); function writeNavProperty(xw, navigation, associations, entityType, areAnnotationsEnabled) { xw.startElement('NavigationProperty'); xw.writeAttribute('Name', navigation.name); var assocName = navigation.association; var association = associations[assocName]; // xw.writeAttribute('Relationship', xw._ns + '.' + association.name + 'Type'); xw.writeAttribute('FromRole', associationsUtil.createFromRoleString(navigation, association, entityType)); xw.writeAttribute('ToRole', associationsUtil.createToRoleString(navigation, association, entityType)); if (areAnnotationsEnabled) { writeAnnotationAttributes(entityType.getNavigationPropertyAnnotations(navigation.name), xw); } xw.endElement(); } function writeProperty(xw, propertyName, col, entityType, areAnnotationsEnabled) { xw.startElement('Property'); xw.writeAttribute('Name', propertyName); if (entityType.isConcurrentProperty(propertyName)) { xw.writeAttribute('ConcurrencyMode', 'Fixed'); } var oOataType = dbutils.dbTypeNameToODataTypeID(col.DATA_TYPE_NAME); xw.writeAttribute('Type', typConv.oDataTypeIDs[oOataType]); if (col.IS_NULLABLE !== 'TRUE') { xw.writeAttribute('Nullable', 'false'); } if (oOataType === 9) { //String xw.writeAttribute('MaxLength', col.LENGTH); } else if (oOataType === 6) { //Decimal xw.writeAttribute('Precision', col.LENGTH); xw.writeAttribute('Scale', col.SCALE); } if (areAnnotationsEnabled) { writeAnnotationAttributes(entityType.getPropertyAnnotations(propertyName), xw); } xw.endElement(); } function writeAssociationTypes(xw, associations) { // Associations for (var assocName in associations) { if (associations.hasOwnProperty(assocName)) { var assoc = associations[assocName]; xw.startElement('Association'); xw.writeAttribute('Name', assocName + 'Type'); xw.startElement('End'); xw.writeAttribute('Type', xw._ns + '.' + assoc.principal.type + 'Type'); xw.writeAttribute('Role', assoc.principal.type + 'Principal'); xw.writeAttribute('Multiplicity', assoc.principal.multiplicity); xw.endElement(); xw.startElement('End'); xw.writeAttribute('Type', xw._ns + '.' + assoc.dependent.type + 'Type'); xw.writeAttribute('Role', assoc.dependent.type + 'Dependent'); xw.writeAttribute('Multiplicity', assoc.dependent.multiplicity); xw.endElement(); if (assoc.referentialConstraint){ xw.startElement('ReferentialConstraint'); xw.startElement('Principal'); xw.writeAttribute('Role', assoc.principal.type + 'Principal'); xw.startElement('PropertyRef'); xw.writeAttribute('Name', assoc.principal.joinproperties[0]); xw.endElement(); xw.endElement();//Principal xw.startElement('Dependent'); xw.writeAttribute('Role', assoc.dependent.type + 'Dependent'); xw.startElement('PropertyRef'); xw.writeAttribute('Name', assoc.dependent.joinproperties[0]); xw.endElement(); xw.endElement();//Dependent xw.endElement();//ReferentialConstraint } xw.endElement();//Association } } } function writeEntityTypes(xw, entityTypes, associations, areAnnotationsEnabled) { var i, ii, j; /** * @type {EntityType} * */ var entityType = null; for (i = 0; i < entityTypes.length; i++) { entityType = entityTypes[i]; xw.startElement('EntityType'); xw.writeAttribute('Name', entityType.name + 'Type'); if (areAnnotationsEnabled) { writeAnnotationAttributes(entityType.getEntityTypeAnnotations(), xw); } //keys xw.startElement('Key'); entityType.getKeysOrGenKey().forEach(writeKey); xw.endElement(); var props = entityType.getPropertiesWithGenKey(); for (j = 0; j < props.length; j++) { writeProp(props[j], entityType); } //nav properties for (ii = 0; ii < entityType.navProperties.length; ii++) { var navigation = entityType.navProperties[ii]; writeNavProperty(xw, navigation, associations, entityType, areAnnotationsEnabled); } xw.endElement(); } function writeKey(keyName) { xw.startElement('PropertyRef'); xw.writeAttribute('Name', keyName); xw.endElement(); } function writeProp(property, entityType) { writeProperty(xw, property.COLUMN_NAME, property, entityType, areAnnotationsEnabled); } } function writeEntitySets(xw, entityTypes, areAnnotationsEnabled) { for (var i = 0; i < entityTypes.length; i++) { var entityType = entityTypes[i]; xw.startElement('EntitySet'); xw.writeAttribute('Name', entityType.name); xw.writeAttribute('EntityType', xw._ns + '.' + entityType.name + 'Type'); if (areAnnotationsEnabled) { writeAnnotationAttributes(entityType.getEntitySetAnnotations(), xw); } xw.endElement(); } } function writeAssociations(xw, associations, areAnnotationsEnabled) { for (var i = 0; i < associations.length; i++) { var assocication = associations[i]; xw.startElement('AssociationSet'); xw.writeAttribute('Name', assocication.name); xw.writeAttribute('Association', xw._ns + '.' + assocication.name + 'Type'); if (areAnnotationsEnabled) { writeAnnotationAttributes(assocication.getAssociationSetAnnotations(), xw); } xw.startElement('End'); xw.writeAttribute('Role', assocication.principal.type + 'Principal'); xw.writeAttribute('EntitySet', assocication.principal.type); xw.endElement(); xw.startElement('End'); xw.writeAttribute('Role', assocication.dependent.type + 'Dependent'); xw.writeAttribute('EntitySet', assocication.dependent.type); xw.endElement(); xw.endElement();//AssociationSet } } exports.process = function (context, asyncDone) { var response = context.response, format = context.oData.systemQueryParameters.format, areAnnotationsEnabled = context.gModel.areAnnotationsEnabled(); context.logger.silly('metadataprocessor', 'process'); context.payloadType = Measurement.measureSync(contentTypeTools.checkServiceMetadata, context.request, format, 'contentTypeTools.checkServiceMetadata'); var header = { 'Content-Type': context.payloadType + ';charset=utf-8' }; var cacheControl = context.gModel.getSetting('metadata','cache-control'); if (cacheControl) { header['cache-control'] = cacheControl; } response.writeHead(200, header); var writer = function writer(string) { response.write(string); }; var xw = new XMLWriter(true, writer);//change to false for unformatted output //xsodata.scenario xw._ns = context.gModel.getNamespace(); xw.startDocument('1.0', 'utf-8', true); xw.startElement('edmx:Edmx'); xw.writeAttribute('Version', '1.0'); xw.writeAttribute('xmlns:edmx', 'http://schemas.microsoft.com/ado/2007/06/edmx'); if (areAnnotationsEnabled) { xw.writeAttribute('xmlns:sap', 'http://www.sap.com/Protocols/SAPData'); } xw.startElement('edmx:DataServices'); xw.writeAttribute('m:DataServiceVersion', '2.0'); xw.writeAttribute('xmlns:m', 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); xw.startElement('Schema'); xw.writeAttribute('Namespace', xw._ns); xw.writeAttribute('xmlns:d', 'http://schemas.microsoft.com/ado/2007/08/dataservices'); xw.writeAttribute('xmlns:m', 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata'); xw.writeAttribute('xmlns', 'http://schemas.microsoft.com/ado/2008/09/edm'); var entityTypes = context.gModel.getEntityTypes(); var associations = context.gModel.getAssociationsMap(); Measurement.measureSync(writeEntityTypes, xw, entityTypes, associations, areAnnotationsEnabled, 'writeEntityTypes'); Measurement.measureSync(writeAssociationTypes, xw, associations, 'writeAssociationTypes'); //Entity Container xw.startElement('EntityContainer'); xw.writeAttribute('Name', 'v2'); xw.writeAttribute('m:IsDefaultEntityContainer', 'true'); writeEntitySets(xw, entityTypes, areAnnotationsEnabled); writeAssociations(xw, context.gModel.getAssociations(), areAnnotationsEnabled); xw.endElement();//EntityContainer xw.endDocument(); response.write(xw.toString()); return asyncDone(null, context); }; exports._writeAnnotationAttributes = writeAnnotationAttributes; /** * Writes CSDL annotation attributes to the current EDM element. * * @param {Object} annotations - object with the properties representing the annotation attributes * @param {Object} xmlWriter - XMLWriter instance, which is used for the metadata serialization */ function writeAnnotationAttributes(annotations, xmlWriter) { var annotation; if (!annotations) { return; } for (annotation in annotations) { if (annotations.hasOwnProperty(annotation)) { xmlWriter.writeAttribute(annotation, annotations[annotation]); } } } exports.writeEntityTypes = writeEntityTypes;