UNPKG

trader-server

Version:

OData server for testing strategies, simulating and real trading.

535 lines (412 loc) 20.9 kB
import { Edm } from 'odata-v4-metadata' import * as extend from 'extend' import { Xml } from './XmlCreator' export class XmlMetadata { public metadata: Edm.Edmx private options: any constructor(options: any, edmx: Edm.Edmx) { this.options = extend({ edmx: 'http://docs.oasis-open.org/odata/ns/edmx', m: 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata', d: 'http://schemas.microsoft.com/ado/2007/08/dataservices', namespace: 'http://docs.oasis-open.org/odata/ns/edm', edmxVersion: '4.0', xmlHead: '<?xml version="1.0" encoding="UTF-8"?>', contextNamespace: 'MyContext' }, options) this.metadata = edmx } processMetadata() { var xml = new Xml.XmlCreator() var xmlResult = this.options.xmlHead xml.startDocument() this.buildEdmx(xml, this.metadata) xml.endDocument() xmlResult += xml.getXmlString() return xmlResult } buildEdmx(xml: Xml.XmlCreator, edmx: Edm.Edmx) { var ns = xml.declareNamespace(this.options.edmx, 'edmx'); var edmxElement = xml.declareElement(ns, 'Edmx'); var version = xml.declareAttribute('Version'); xml.startElement(edmxElement) .addAttribute(version, edmx.version || this.options.edmxVersion); this.buildDataServices(xml, edmx.dataServices); xml.endElement(); } buildDataServices(xml: Xml.XmlCreator, dataservices: Edm.DataServices) { var ns = xml.declareNamespace(this.options.edmx, 'edmx'); var dataservicesElement = xml.declareElement(ns, 'DataServices'); xml.startElement(dataservicesElement) this.buildSchema(xml, dataservices.schemas); xml.endElement(); } buildSchema(xml: Xml.XmlCreator, schemas: Edm.Schema[]) { schemas && schemas.forEach(schema => { var xmlns = xml.declareAttribute('xmlns'); var schemaElement = xml.declareElement('Schema'); var ns = xml.declareAttribute('Namespace'); xml.startElement(schemaElement) .addAttribute(xmlns, this.options.namespace) .addAttribute(ns, schema.namespace || this.options.contextNamespace); if (schema.alias) xml.addAttribute(xml.declareAttribute('Alias'), schema.alias); this.buildEntityTypes(xml, schema.entityTypes) this.buildComplexTypes(xml, schema.complexTypes) this.buildTypeDefinitions(xml, schema.typeDefinitions) this.buildEnumTypes(xml, schema.enumTypes) this.buildActions(xml, schema.actions) this.buildFunctions(xml, schema.functions) this.buildEntityContainer(xml, schema.entityContainer); this.buildSchemaAnnotations(xml, schema.annotations) xml.endElement(); }) } buildTypeDefinitions(xml: Xml.XmlCreator, typeDefinitions: Edm.TypeDefinition[]) { 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: Xml.XmlCreator, enumTypes: Edm.EnumType[]) { enumTypes && enumTypes.forEach((enumType: Edm.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: Xml.XmlCreator, entityTypes: Edm.EntityType[]) { entityTypes && entityTypes.forEach(entityType => { this.buildType(xml, entityType, 'EntityType') }) } buildComplexTypes(xml: Xml.XmlCreator, complexTypes: Edm.ComplexType[]) { complexTypes && complexTypes.forEach(complexType => { this.buildType(xml, complexType, 'ComplexType') }) } buildType(xml: Xml.XmlCreator, type: Edm.EntityType | Edm.ComplexType, xmlElementName: string) { 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 Edm.EntityType){ this.buildTypeKeys(xml, (<Edm.EntityType>type).key) } this.buildTypeProperties(xml, type.properties) this.buildTypeNavigationProperties(xml, type.navigationProperties) this.buildAnnotations(xml, type.annotations) xml.endElement() } buildTypeKeys(xml: Xml.XmlCreator, key: Edm.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: Xml.XmlCreator, properties: Edm.Property[]) { 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(); }) } typePropertyAttributes: Object = { 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' } } buildTypeNavigationProperties(xml: Xml.XmlCreator, navigationProperties: Edm.NavigationProperty[]) { navigationProperties && navigationProperties.forEach(navigationProperty => { var navigationPropertyElement = xml.declareElement('NavigationProperty'); xml.startElement(navigationPropertyElement); this.buildAttributes(xml, navigationProperty, this.typeNavigationPropertyAttributes) this.buildNavPropertyReferentialConstraints(xml, navigationProperty.referentialConstraints) this.buildAnnotations(xml, navigationProperty.annotations) xml.endElementInline(); }) } buildNavPropertyReferentialConstraints(xml: Xml.XmlCreator, referentialConstraints: Edm.ReferentialConstraint[]) { 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(); }) } typeNavigationPropertyAttributes: Object = { name: { name: 'Name' }, type: { name: 'Type' }, nullable: { name: 'Nullable' }, containsTarget: { name: 'ContainsTarget' }, partner: { name: 'Partner' } } buildEnumMembers(xml: Xml.XmlCreator, members: Edm.Member[]) { 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(); }) } typeMemberAttributes: Object = { name: { name: 'Name' }, value: { name: 'Value' } } buildAttributes(xml: Xml.XmlCreator, object: any, mappings: any) { 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: Xml.XmlCreator, actions: Edm.Action[]){ 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: Xml.XmlCreator, functions: Edm.Function[]){ 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: Xml.XmlCreator, parameters: Edm.Parameter[]){ 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(); }) } parameterAttributes: Object = { name: { name: 'Name' }, type: { name: 'Type' }, nullable: { name: 'Nullable' }, maxLength: { name: 'MaxLength' }, precision: { name: 'Precision' }, scale: { name: 'Scale' }, unicode: { name: 'Unicode' }, SRID: { name: 'SRID' } } buildReturnType(xml: Xml.XmlCreator, returnType: Edm.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: Xml.XmlCreator, entityContainers: Edm.EntityContainer[]) { entityContainers && entityContainers.forEach(entityContainer => { var entityContainerElement = xml.declareElement('EntityContainer'); var name = xml.declareAttribute('Name'); xml.startElement(entityContainerElement) .addAttribute(name, entityContainer.name) this.buildEntitySets(xml, entityContainer.entitySets) this.buildActionImports(xml, entityContainer.actionImports) this.buildFunctionImports(xml, entityContainer.functionImports) xml.endElement(); }) } buildEntitySets(xml: Xml.XmlCreator, entitySets: Edm.EntitySet[]) { 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(); }) } buildActionImports(xml: Xml.XmlCreator, actionImports: Edm.ActionImport[]){ 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: Xml.XmlCreator, functionImports: Edm.FunctionImport[]){ 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: Xml.XmlCreator, schemaAnnotations: Edm.Annotations[]) { 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: Xml.XmlCreator, annotations: Edm.Annotation[]) { 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: Xml.XmlCreator, value: any[], annotConfig: any, _: Edm.Annotation) { 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(); } annotationAttributes: Object = { term: { name: 'Term' }, qualifier: { name: 'Qualifier' }, path: { name: 'Path' }, } annotationTypes: Object = { 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(); } } } }