@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
JavaScript
;
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