UNPKG

@tjc-group/odata-v2-service-metadata

Version:

Limited version of OData metadata response for OData V2, based on odata-v4-service-metadata

594 lines 27.7 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); const odata_v4_metadata_1 = require("@tjc-group/odata-v4-metadata"); const extend = require("extend"); const XmlCreator_1 = require("./XmlCreator"); const metacode = require("./metacode"); class EndPoint extends odata_v4_metadata_1.Edm.EdmItemBase { } __decorate([ metacode.parse, __metadata("design:type", String) ], EndPoint.prototype, "type", void 0); __decorate([ metacode.parse, __metadata("design:type", String) ], EndPoint.prototype, "role", void 0); __decorate([ metacode.parse, __metadata("design:type", String) ], EndPoint.prototype, "multiplicity", void 0); let endPointAttributes = { type: { name: 'Type' }, role: { name: 'Role' }, multiplicity: { name: 'Multiplicity' } }; let associationSetEndPointAttributes = { type: { name: 'EntitySet' }, role: { name: 'Role' } }; class Association extends odata_v4_metadata_1.Edm.EdmItemBase { } __decorate([ metacode.parse, __metadata("design:type", String) ], Association.prototype, "name", void 0); __decorate([ metacode.parse, __metadata("design:type", Array) ], Association.prototype, "ends", void 0); class AssociationSet extends odata_v4_metadata_1.Edm.EdmItemBase { } __decorate([ metacode.parse, __metadata("design:type", String) ], AssociationSet.prototype, "name", void 0); __decorate([ metacode.parse, __metadata("design:type", Association) ], AssociationSet.prototype, "association", void 0); __decorate([ metacode.parse, __metadata("design:type", Array) ], AssociationSet.prototype, "ends", void 0); class SchemaV2 extends odata_v4_metadata_1.Edm.Schema { } class EntityContainerV2 extends odata_v4_metadata_1.Edm.EntityContainer { } class XmlMetadata { constructor(options, edmx) { this.typePropertyAttributes = { name: { name: 'Name' }, type: { name: 'Type' }, nullable: { name: 'Nullable' }, maxLength: { name: 'MaxLength' }, precision: { name: 'Precision' }, scale: { name: 'Scale' }, unicode: { name: 'Unicode' }, SRID: { name: 'SRID' }, defaultValue: { name: 'DefaultValue' } }; this.typeNavigationPropertyAttributes = { name: { name: 'Name' }, type: { name: 'Type' }, nullable: { name: 'Nullable' }, containsTarget: { name: 'ContainsTarget' }, partner: { name: 'Partner' } }; this.typeNavigationPropertyAttributesV2 = { name: { name: 'Name' }, relationship: { name: 'Relationship' }, fromRole: { name: 'FromRole' }, toRole: { name: 'ToRole' } }; this.typeMemberAttributes = { name: { name: 'Name' }, value: { name: 'Value' } }; this.parameterAttributes = { name: { name: 'Name' }, type: { name: 'Type' }, nullable: { name: 'Nullable' }, maxLength: { name: 'MaxLength' }, precision: { name: 'Precision' }, scale: { name: 'Scale' }, unicode: { name: 'Unicode' }, SRID: { name: 'SRID' } }; this.annotationAttributes = { term: { name: 'Term' }, qualifier: { name: 'Qualifier' }, path: { name: 'Path' }, }; this.annotationTypes = { Binary: { name: 'Binary', valueField: 'binary' }, Bool: { name: 'Bool', valueField: 'bool' }, Date: { name: 'Date', valueField: 'date' }, DateTimeOffset: { name: 'DateTimeOffset', valueField: 'dateTimeOffset' }, Decimal: { name: 'Decimal', valueField: 'decimal' }, Duration: { name: 'Duration', valueField: 'duration' }, EnumMember: { name: 'EnumMember', valueField: 'enumMember' }, Float: { name: 'Float', valueField: 'float' }, Guid: { name: 'Guid', valueField: 'guid' }, Int: { name: 'Int', valueField: 'int' }, String: { name: 'String', valueField: 'string' }, TimeOfDay: { name: 'TimeOfDay', valueField: 'timeOfDay' }, PropertyPath: { name: 'PropertyPath', valueField: 'propertyPaths' }, NavigationPropertyPath: { name: 'NavigationPropertyPath', valueField: 'navigationPropertyPaths' }, AnnotationPath: { name: 'AnnotationPath', valueField: 'annotationPaths' }, Null: { name: 'Null', handler: (xml) => { var nullElement = xml.declareElement('Null'); xml.startElement(nullElement); xml.endElementInline(); } } }; this.options = extend({ edmx: "http://schemas.microsoft.com/ado/2007/06/edmx", m: 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata', d: 'http://schemas.microsoft.com/ado/2007/08/dataservices', namespace: 'http://schemas.microsoft.com/ado/2008/09/edm', edmxVersion: '1.0', DataServiceVersion: "2.0", xmlHead: '<?xml version="1.0" encoding="utf-8" standalone="yes"?>', contextNamespace: 'MyContext' }, options); this.metadata = edmx; } processMetadata() { var xml = new XmlCreator_1.Xml.XmlCreator(); var xmlResult = this.options.xmlHead; xml.startDocument(); this.buildEdmx(xml, this.metadata); xml.endDocument(); xmlResult += xml.getXmlString(); return xmlResult; } buildEdmx(xml, edmx) { var edmxElement = xml.declareElement(xml.declareNamespace(this.options.edmx, 'edmx'), 'Edmx'); xml.startElement(edmxElement) .addAttribute(xml.declareAttribute('Version'), "1.0"); this.buildDataServices(xml, edmx.dataServices); xml.endElement(); } buildDataServices(xml, dataservices) { // var ns = xml.declareNamespace(this.options.edmx, 'edmx'); var dataservicesElement = xml.declareElement(xml.declareNamespace(this.options.edmx, 'edmx'), 'DataServices'); var version = xml.declareAttribute('m:DataServiceVersion'); xml.startElement(dataservicesElement) .addAttribute(xml.declareAttribute('xmlns:m'), this.options.m) .addAttribute(version, this.options.DataServiceVersion || "2.0"); this.buildSchema(xml, dataservices.schemas); xml.endElement(); } buildSchema(xml, schemas) { schemas && schemas.forEach(schema => { var xmlns = xml.declareAttribute('xmlns'); var schemaElement = xml.declareElement('Schema'); var ns = xml.declareAttribute('Namespace'); xml.startElement(schemaElement) .addAttribute(xml.declareAttribute('xmlns:d'), this.options.d) .addAttribute(xml.declareAttribute('xmlns:m'), this.options.m) .addAttribute(xmlns, this.options.namespace) .addAttribute(ns, schema.namespace || this.options.contextNamespace || "default"); if (schema.alias) xml.addAttribute(xml.declareAttribute('Alias'), schema.alias); this.buildEntityTypes(xml, schema.entityTypes, schema, schemas); this.buildComplexTypes(xml, schema.complexTypes, schema, schemas); this.buildTypeDefinitions(xml, schema.typeDefinitions); this.buildEnumTypes(xml, schema.enumTypes); // this.buildActions(xml, schema.actions) this.buildFunctions(xml, schema.functions); let schemaV2 = schema; this.buildAssociations(xml, schemaV2.associations, schemaV2, schemas); let entityContainerV2; if (schemaV2.associations) { if (!schemaV2.entityContainer.length) { schemaV2.entityContainer.push(new odata_v4_metadata_1.Edm.EntityContainer({ name: "Container" })); } entityContainerV2 = schema.entityContainer.map(function (container) { let result = container; result.associationSets = []; let schemaV2 = schema; result.associationSets = schemaV2.associations.map(function (association) { return new AssociationSet({ name: association.name + "_Set", association: association, ends: association.ends.map(end => { return new EndPoint({ role: end.role, type: end.type }); }) }); }); return result; }); } this.buildEntityContainer(xml, entityContainerV2); this.buildSchemaAnnotations(xml, schema.annotations); xml.endElement(); }); } buildAssociations(xml, associations, _schema, _allSchemas) { associations && associations.forEach(association => { var element = xml.declareElement('Association'); var name = xml.declareAttribute('Name'); xml.startElement(element) .addAttribute(name, association.name); this.buildAssociationEnds(xml, association.ends); xml.endElement(); }); } buildAssociationEnds(xml, ends) { ends && ends.forEach(endPoint => { var element = xml.declareElement('End'); xml.startElement(element); this.buildAttributes(xml, endPoint, endPointAttributes); xml.endElement(); }); } buildTypeDefinitions(xml, typeDefinitions) { typeDefinitions && typeDefinitions.forEach(typeDefinition => { var rootElement = xml.declareElement('TypeDefinition'); var name = xml.declareAttribute('Name'); xml.startElement(rootElement) .addAttribute(name, typeDefinition.name); if (typeDefinition.underlyingType) xml.addAttribute(xml.declareAttribute('UnderlyingType'), typeDefinition.underlyingType); this.buildAnnotations(xml, typeDefinition.annotations); xml.endElement(); }); } buildEnumTypes(xml, enumTypes) { enumTypes && enumTypes.forEach((enumType) => { var rootElement = xml.declareElement('EnumType'); var name = xml.declareAttribute('Name'); xml.startElement(rootElement) .addAttribute(name, enumType.name); if (enumType.namespace) xml.addAttribute(xml.declareAttribute('Namespace'), enumType.namespace); if (enumType.underlyingType) xml.addAttribute(xml.declareAttribute('UnderlyingType'), enumType.underlyingType); if (enumType.isFlags) xml.addAttribute(xml.declareAttribute('IsFlags'), enumType.isFlags); this.buildEnumMembers(xml, enumType.members); this.buildAnnotations(xml, enumType.annotations); xml.endElement(); }); } buildEntityTypes(xml, entityTypes, _schema, _allSchemas) { entityTypes && entityTypes.forEach(entityType => { this.buildType(xml, entityType, 'EntityType', _schema, _allSchemas); }); } buildComplexTypes(xml, complexTypes, _schema, _allSchemas) { complexTypes && complexTypes.forEach(complexType => { this.buildType(xml, complexType, 'ComplexType', _schema, _allSchemas); }); } buildType(xml, type, xmlElementName, _currentSchema, _allSchemas) { var rootElement = xml.declareElement(xmlElementName); var name = xml.declareAttribute('Name'); xml.startElement(rootElement) .addAttribute(name, type.name); if (type.baseType) xml.addAttribute(xml.declareAttribute('BaseType'), type.baseType); if (type.abstract) xml.addAttribute(xml.declareAttribute('Abstract'), type.abstract); if (type.openType) xml.addAttribute(xml.declareAttribute('OpenType'), type.openType); if (type.hasStream) xml.addAttribute(xml.declareAttribute('HasStream'), type.hasStream); if (type instanceof odata_v4_metadata_1.Edm.EntityType) { this.buildTypeKeys(xml, type.key); } this.buildTypeProperties(xml, type.properties); this.buildTypeNavigationProperties(xml, type.navigationProperties, _currentSchema, _allSchemas); this.buildAnnotations(xml, type.annotations); xml.endElement(); } buildTypeKeys(xml, key) { if (!key) return; var keyElement = xml.declareElement('Key'); var propRef = xml.declareElement('PropertyRef'); var name = xml.declareAttribute('Name'); var keys = key.propertyRefs; if (keys.length > 0) { xml.startElement(keyElement); keys.forEach(keyDef => { xml.startElement(propRef) .addAttribute(name, keyDef.name); if (keyDef.alias) xml.addAttribute(xml.declareAttribute('Alias'), keyDef.alias); xml.endElementInline(); }); xml.endElement(); } } buildTypeProperties(xml, properties) { properties && properties.forEach(property => { var propertyElement = xml.declareElement('Property'); xml.startElement(propertyElement); this.buildAttributes(xml, property, this.typePropertyAttributes); this.buildAnnotations(xml, property.annotations); xml.endElementInline(); }); } buildTypeNavigationProperties(xml, navigationProperties, _schema, _allSchemas) { navigationProperties && navigationProperties.forEach(navigationProperty => { var navigationPropertyElement = xml.declareElement('NavigationProperty'); var schemaV2 = _schema; if (!schemaV2.associations) { schemaV2.associations = []; } var collectionMask = /Collection\(([\w.]+)\)/i; var toType = navigationProperty.type; let ends = []; if (collectionMask.test(navigationProperty.type)) { var parts = toType.match(collectionMask); toType = parts && parts[1]; } var toTypeSchema = _allSchemas.find(schema => { return toType.search(schema.namespace) === 0; }); let relation = navigationProperty.partner + "_to_" + toType.replace(/\./g, "_"); let relationship = relation; let i = 1; while (schemaV2.associations.some(association => association.name == relationship)) { relationship = relationship + "_" + i; i++; } var navigationPropertyV2 = { name: navigationProperty.name, fromRole: navigationProperty.partner + "Principal", toRole: toType.substr(toTypeSchema.namespace.length + 1) + "Dependent", relationship: _schema.namespace + "." + relationship }; ends.push(new EndPoint({ type: _schema.namespace + "." + navigationProperty.partner, role: navigationPropertyV2.fromRole, multiplicity: "1" })); ends.push(new EndPoint({ type: toType, role: navigationPropertyV2.toRole, multiplicity: collectionMask.test(navigationProperty.type) ? "*" : "0..1" })); schemaV2.associations.push(new Association({ name: relationship, ends: ends })); xml.startElement(navigationPropertyElement); this.buildAttributes(xml, navigationPropertyV2, this.typeNavigationPropertyAttributesV2); // this.buildNavPropertyReferentialConstraints(xml, navigationProperty.referentialConstraints) this.buildAnnotations(xml, navigationProperty.annotations); xml.endElementInline(); }); } buildNavPropertyReferentialConstraints(xml, referentialConstraints) { referentialConstraints && referentialConstraints.forEach(referentialConstraint => { var referentialConstraintElement = xml.declareElement('ReferentialConstraint'); xml.startElement(referentialConstraintElement); if (referentialConstraint.property) xml.addAttribute(xml.declareAttribute("Property"), referentialConstraint.property); if (referentialConstraint.referencedProperty) xml.addAttribute(xml.declareAttribute("ReferencedProperty"), referentialConstraint.referencedProperty); xml.endElementInline(); }); } buildEnumMembers(xml, members) { members && members.forEach(member => { var memberElement = xml.declareElement('Member'); xml.startElement(memberElement); this.buildAttributes(xml, member, this.typeMemberAttributes); this.buildAnnotations(xml, member.annotations); xml.endElementInline(); }); } buildAttributes(xml, object, mappings) { var attributes = mappings && Object.keys(mappings); object && attributes && attributes.forEach(prop => { if (typeof object[prop] !== 'undefined' && object[prop] !== null) { var attr = xml.declareAttribute(mappings[prop].name); xml.addAttribute(attr, object[prop].toString()); } }); } buildActions(xml, actions) { actions && actions.forEach(action => { var actionElement = xml.declareElement('Action'); var name = xml.declareAttribute('Name'); xml.startElement(actionElement) .addAttribute(name, action.name); if (typeof action.isBound !== 'undefined') xml.addAttribute(xml.declareAttribute('IsBound'), action.isBound.toString()); if (action.entitySetPath) xml.addAttribute(xml.declareAttribute('EntitySetPath'), action.entitySetPath); this.buildParameters(xml, action.parameters); this.buildReturnType(xml, action.returnType); this.buildAnnotations(xml, action.annotations); xml.endElementInline(); }); } buildFunctions(xml, functions) { functions && functions.forEach(func => { var funcElement = xml.declareElement('Function'); var name = xml.declareAttribute('Name'); xml.startElement(funcElement) .addAttribute(name, func.name); if (typeof func.isBound !== 'undefined') xml.addAttribute(xml.declareAttribute('IsBound'), func.isBound.toString()); if (func.entitySetPath) xml.addAttribute(xml.declareAttribute('EntitySetPath'), func.entitySetPath); if (typeof func.isComposable !== 'undefined') xml.addAttribute(xml.declareAttribute('IsComposable'), func.isComposable.toString()); this.buildParameters(xml, func.parameters); this.buildReturnType(xml, func.returnType); this.buildAnnotations(xml, func.annotations); xml.endElementInline(); }); } buildParameters(xml, parameters) { parameters && parameters.forEach(parameter => { var parameterElement = xml.declareElement('Parameter'); xml.startElement(parameterElement); this.buildAttributes(xml, parameter, this.parameterAttributes); this.buildAnnotations(xml, parameter.annotations); xml.endElementInline(); }); } buildReturnType(xml, returnType) { if (!returnType || typeof returnType.type === 'undefined') return; var parameterElement = xml.declareElement('ReturnType'); var type = xml.declareAttribute('Type'); var nullable = xml.declareAttribute('Nullable'); xml.startElement(parameterElement) .addAttribute(type, returnType.type); if (typeof returnType.nullable !== 'undefined') xml.addAttribute(nullable, returnType.nullable.toString()); this.buildAnnotations(xml, returnType.annotations); xml.endElementInline(); } buildEntityContainer(xml, entityContainers) { entityContainers && entityContainers.forEach(entityContainer => { var entityContainerElement = xml.declareElement('EntityContainer'); var name = xml.declareAttribute('Name'); xml.startElement(entityContainerElement) .addAttribute(name, entityContainer.name) .addAttribute(xml.declareAttribute('m:IsDefaultEntityContainer'), "true"); this.buildEntitySets(xml, entityContainer.entitySets); this.buildAssociationSets(xml, entityContainer.associationSets); this.buildActionImports(xml, entityContainer.actionImports); this.buildFunctionImports(xml, entityContainer.functionImports); xml.endElement(); }); } buildEntitySets(xml, entitySets) { entitySets && entitySets.forEach(entitySet => { var entitySetElement = xml.declareElement('EntitySet'); var name = xml.declareAttribute('Name'); var entityType = xml.declareAttribute('EntityType'); xml.startElement(entitySetElement) .addAttribute(name, entitySet.name) .addAttribute(entityType, entitySet.entityType); this.buildAnnotations(xml, entitySet.annotations); xml.endElementInline(); }); } buildAssociationSets(xml, associationSets) { associationSets && associationSets.forEach(associationSet => { let associationSetElement = xml.declareElement('AssociationSet'); let name = xml.declareAttribute("Name"); xml.startElement(associationSetElement) .addAttribute(name, associationSet.name); this.buildAssociationSetEnds(xml, associationSet.ends); xml.endElementInline(); }); } buildAssociationSetEnds(xml, ends) { ends && ends.forEach(endPoint => { let endElement = xml.declareElement('End'); xml.startElement(endElement); this.buildAttributes(xml, endPoint, associationSetEndPointAttributes); xml.endElementInline(); }); } buildActionImports(xml, actionImports) { actionImports && actionImports.forEach(actionImport => { var actionImportElement = xml.declareElement('ActionImport'); var name = xml.declareAttribute('Name'); var action = xml.declareAttribute('Action'); xml.startElement(actionImportElement) .addAttribute(name, actionImport.name) .addAttribute(action, actionImport.action); this.buildAnnotations(xml, actionImport.annotations); xml.endElementInline(); }); } buildFunctionImports(xml, functionImports) { functionImports && functionImports.forEach(functionImport => { var FunctionImportElement = xml.declareElement('FunctionImport'); var name = xml.declareAttribute('Name'); var func = xml.declareAttribute('Function'); xml.startElement(FunctionImportElement) .addAttribute(name, functionImport.name) .addAttribute(func, functionImport['function']); if (typeof functionImport.includeInServiceDocument !== 'undefined') xml.addAttribute(xml.declareAttribute('IncludeInServiceDocument'), functionImport.includeInServiceDocument.toString()); this.buildAnnotations(xml, functionImport.annotations); xml.endElementInline(); }); } buildSchemaAnnotations(xml, schemaAnnotations) { schemaAnnotations && schemaAnnotations.forEach(schemaAnnotation => { var target = xml.declareAttribute('Target'); var AnnotationsElement = xml.declareElement('Annotations'); xml.startElement(AnnotationsElement) .addAttribute(target, schemaAnnotation.target); if (schemaAnnotation.qualifier) xml.addAttribute(xml.declareAttribute('Qualifier'), schemaAnnotation.qualifier); this.buildAnnotations(xml, schemaAnnotation.annotations); xml.endElementInline(); }); } buildAnnotations(xml, annotations) { annotations && annotations.forEach(annotation => { var AnnotationElement = xml.declareElement('Annotation'); xml.startElement(AnnotationElement); var attributes = Object.keys(this.annotationAttributes); attributes.forEach(prop => { if (typeof annotation[prop] !== 'undefined' && annotation[prop] !== null) { var attr = xml.declareAttribute(this.annotationAttributes[prop].name); xml.addAttribute(attr, annotation[prop].toString()); } }); var annotConfig = this.annotationTypes[annotation.annotationType]; if (annotConfig) { if (annotConfig.handler) { annotConfig.handler(xml, annotation); } else if (annotConfig.valueField) { var value = annotation[annotConfig.valueField]; if (Array.isArray(value)) { this.buildCollectionAnnotation(xml, value, annotConfig, annotation); } else if (typeof value !== 'undefined' && value !== null) { var attr = xml.declareAttribute(annotConfig.name); xml.addAttribute(attr, value.toString()); } } } xml.endElementInline(); }); } buildCollectionAnnotation(xml, value, annotConfig, _) { var collectionElement = xml.declareElement('Collection'); xml.startElement(collectionElement); value.forEach(v => { var valueElement = xml.declareElement(annotConfig.name); xml.startElement(valueElement) .addText(v.toString()) .endElementInline(); }); xml.endElementInline(); } } exports.XmlMetadata = XmlMetadata; //# sourceMappingURL=xmlMetadataV2.js.map