trader-server
Version:
OData server for testing strategies, simulating and real trading.
459 lines • 23.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const controller_1 = require("./controller");
const Edm = require("./edm");
const odata = require("./odata");
const utils_1 = require("./utils");
function createMetadataJSON(server) {
if (!server.namespace)
server.namespace = "Default";
const containerType = Object.getPrototypeOf(server.container).constructor;
if (containerType != Edm.ContainerBase && !containerType.namespace)
containerType.namespace = server.namespace;
const definition = {
version: "4.0",
dataServices: {
schema: []
}
};
const getAllOperations = function (target) {
let ops = Edm.getOperations(target);
let ret = {};
ops.forEach(op => ret[op] = target);
target = Object.getPrototypeOf(target.prototype);
if (target instanceof controller_1.ODataController)
ret = Object.assign(getAllOperations(target.constructor), ret);
return ret;
};
const propNames = utils_1.getAllPropertyNames(server.prototype).filter(it => it != "constructor");
const entitySets = odata.getPublicControllers(server);
const resolveTypeDefinition = (elementType, prop, namespace, getType = Edm.getType, getTypeName = Edm.getTypeName) => {
let defType = getType(elementType, prop, server.container);
let defName = server.container.resolve(defType);
let defNamespace = containerType.namespace || namespace;
let defDefinition;
if (!defName) {
defName = defType["@odata.type"] || (defType["prototype"] && defType["prototype"]["@odata.type"]) || prop;
if (defName.indexOf(".") > 0) {
defNamespace = defName.slice(0, defName.lastIndexOf("."));
defName = defName.slice(defName.lastIndexOf(".") + 1);
}
defDefinition = {
name: defName,
underlyingType: getTypeName(defType, undefined, server.container) || "System.Object"
};
}
else {
if (defName.indexOf(".") > 0) {
defNamespace = defName.slice(0, defName.lastIndexOf("."));
defName = defName.slice(defName.lastIndexOf(".") + 1);
}
defDefinition = {
name: defName,
underlyingType: getTypeName(containerType, defName, server.container) || "System.Object"
};
}
let defSchema = definition.dataServices.schema.filter((schema) => schema.namespace == defNamespace)[0];
if (!defSchema) {
defSchema = {
namespace: defNamespace,
typeDefinition: [],
enumType: [],
entityType: [],
complexType: [],
action: [],
function: [],
entityContainer: [],
annotation: []
};
definition.dataServices.schema.unshift(defSchema);
}
if (!defSchema.typeDefinition.filter(et => et.name == defName)[0]) {
defSchema.typeDefinition.push(defDefinition);
}
return `${defNamespace}.${defName}`;
};
const resolveEnumType = (elementType, prop, namespace, enumType, enumName) => {
enumType = enumType || Edm.getType(elementType, prop, server.container);
enumName = enumName || Edm.getTypeName(elementType, prop, server.container);
let enumNamespace = odata.getNamespace(containerType, server.container.resolve(enumType)) || namespace;
let enumDefinition;
if (!enumName) {
enumName = enumType["@odata.type"] || prop;
enumDefinition = {
name: enumName,
underlyingType: Edm.getTypeName(elementType, prop, server.container),
isFlags: Edm.isFlags(elementType, prop),
member: [],
annotation: Edm.getAnnotations(enumType)
};
}
else {
if (enumName.indexOf(".") > 0) {
enumNamespace = enumName.slice(0, enumName.lastIndexOf("."));
enumName = enumName.slice(enumName.lastIndexOf(".") + 1);
}
enumDefinition = {
name: enumName,
underlyingType: Edm.getTypeName(containerType, `${enumNamespace}.${enumName}`, server.container) || Edm.getTypeName(containerType, enumName, server.container) || "Edm.Int32",
isFlags: Edm.isFlags(containerType, `${enumNamespace}.${enumName}`) || Edm.isFlags(containerType, enumName),
member: [],
annotation: Edm.getAnnotations(enumType)
};
}
let enumSchema = definition.dataServices.schema.filter((schema) => schema.namespace == enumNamespace)[0];
if (!enumSchema) {
enumSchema = {
namespace: enumNamespace,
typeDefinition: [],
enumType: [],
entityType: [],
complexType: [],
action: [],
function: [],
entityContainer: [],
annotation: []
};
definition.dataServices.schema.unshift(enumSchema);
}
if (!enumSchema.enumType.filter(et => et.name == enumName)[0]) {
Object.keys(enumType).forEach((member) => {
if (!(/^[0-9@]/.test(member) || enumType[member] == "@odata.type")) {
enumDefinition.member.push({
name: member,
value: enumType[member],
annotation: Edm.getAnnotations(enumType, member)
});
}
});
enumSchema.enumType.push(enumDefinition);
}
return `${enumNamespace}.${enumName}`;
};
const resolveOperation = (elementType, prop, namespace, isBound, boundType) => {
let type = Edm.getReturnType(elementType, prop, server.container);
if (Edm.isTypeDefinition(elementType, prop)) {
type = resolveTypeDefinition(elementType, prop, namespace, Edm.getReturnType);
}
else if (Edm.isEnumType(elementType, prop)) {
type = resolveEnumType(elementType, prop, namespace);
}
else if (typeof type == "function") {
let definitionContainer = Edm.isEntityType(type) ? "entityType" : "complexType";
let resolvedType = resolveType(type, elementType, prop);
if (resolvedType && !resolvedType.schema[definitionContainer].filter(et => et.name == resolvedType.definition.name)[0]) {
resolvedType.schema[definitionContainer].push(resolvedType.definition);
}
}
let returnType = Edm.getReturnTypeName(elementType, prop, server.container);
let parameters = Edm.getParameters(elementType, prop).map(p => {
let param = Object.assign({}, p);
if (typeof param.type != "string") {
let resolvedContainerType = server.container.resolve(param.type) || param.type.name;
if (Edm.isTypeDefinition(param.type)) {
param.type = resolveTypeDefinition(containerType, resolvedContainerType, namespace, Edm.getType, () => {
return Edm.getTypeName(containerType, resolvedContainerType, server.container);
});
}
else if (Edm.isEnumType(param.type)) {
param.type = resolveEnumType(containerType, resolvedContainerType, namespace, param.type, resolvedContainerType);
}
else {
if (typeof param.type == "function") {
let definitionContainer = Edm.isEntityType(param.type) ? "entityType" : "complexType";
let resolvedType = resolveType(param.type, elementType, prop, undefined, resolvedContainerType.indexOf(".") > 0 ? resolvedContainerType : `${param.type.namespace || namespace}.${resolvedContainerType}`);
if (resolvedType && !resolvedType.schema[definitionContainer].filter(et => et.name == resolvedType.definition.name)[0]) {
resolvedType.schema[definitionContainer].push(resolvedType.definition);
}
}
if (resolvedContainerType.indexOf(".") > 0) {
param.type = resolvedContainerType;
}
else {
param.type = `${param.type.namespace || odata.getNamespace(containerType, resolvedContainerType) || namespace}.${resolvedContainerType}`;
}
}
}
return param;
});
if (isBound) {
parameters.unshift({
name: "bindingParameter",
type: boundType
});
}
return {
name: prop,
isBound: isBound || false,
parameter: parameters,
returnType: { type: returnType }
};
};
const resolveImport = (operationSchema, i, definition, type) => {
operationSchema[type].push(definition);
let containerName = server.prototype[i].containerName || "Default";
let entityContainer = operationSchema.entityContainer.find(ec => ec.name == containerName);
if (!entityContainer) {
entityContainer = {
name: containerName,
entitySet: [],
actionImport: [],
functionImport: []
};
operationSchema.entityContainer.unshift(entityContainer);
}
entityContainer[`${type}Import`].push({
name: i,
[type]: (server.prototype[i].namespace || server.namespace) + "." + i
});
};
let resolvingTypes = [];
const resolveType = (elementType, parent, prop, baseType, paramTypeName) => {
if (resolvingTypes.indexOf(elementType) >= 0)
return null;
resolvingTypes.push(elementType);
if (!elementType.namespace)
elementType.namespace = server.container.resolve(elementType) ? (containerType.namespace || parent.namespace) : parent.namespace;
let typeName = paramTypeName || Edm.getTypeName(parent, prop, server.container) || elementType.name;
if (typeName.indexOf('Collection') == 0)
typeName = elementType.name;
let typeDefinition = {
name: typeName.split('.').pop(),
baseType: baseType ? (baseType.namespace || server.namespace) + "." + baseType.name : undefined,
key: [],
property: [],
navigationProperty: [],
annotation: Edm.getAnnotations(elementType),
openType: Edm.isOpenType(elementType) || elementType === Object,
hasStream: Edm.isMediaEntity(elementType)
};
let namespace = elementType.namespace || parent.namespace || server.namespace;
let typeSchema = definition.dataServices.schema.filter((schema) => schema.namespace == namespace)[0];
if (!typeSchema) {
typeSchema = {
namespace: namespace,
typeDefinition: [],
enumType: [],
entityType: [],
complexType: [],
action: [],
function: [],
entityContainer: [],
annotation: []
};
definition.dataServices.schema.unshift(typeSchema);
}
let properties = Edm.getProperties(elementType.prototype);
properties.forEach((prop) => {
let propertyDefinition = {
name: prop,
type: Edm.getTypeName(elementType, prop, server.container),
nullable: Edm.isNullable(elementType, prop),
maxLength: Edm.getMaxLength(elementType, prop),
precision: Edm.getPrecision(elementType, prop),
scale: Edm.getScale(elementType, prop),
unicode: Edm.isUnicode(elementType, prop),
SRID: Edm.getSRID(elementType, prop),
concurrencyMode: Edm.getConcurrencyMode(elementType, prop),
defaultValue: Edm.getDefaultValue(elementType, prop),
annotation: Edm.getAnnotations(elementType, prop),
partner: Edm.getPartner(elementType, prop)
};
if (Edm.isKey(elementType, prop)) {
typeDefinition.key.push({
propertyRef: [{
name: prop
}]
});
propertyDefinition.nullable = false;
}
if (Edm.isComputed(elementType, prop)) {
propertyDefinition.annotation.unshift({
term: "Org.OData.Core.V1.Computed",
bool: true
});
}
if (Edm.isTypeDefinition(elementType, prop)) {
propertyDefinition.type = resolveTypeDefinition(elementType, prop, namespace);
}
else if (Edm.isEnumType(elementType, prop)) {
propertyDefinition.type = resolveEnumType(elementType, prop, namespace);
}
else {
let type = Edm.getType(elementType, prop, server.container);
if (typeof type == "function") {
let definitionContainer = Edm.isEntityType(elementType, prop) ? "entityType" : "complexType";
let resolvedType = resolveType(type, elementType, prop);
if (resolvedType && !resolvedType.schema[definitionContainer].filter(et => et.name == resolvedType.definition.name)[0]) {
resolvedType.schema[definitionContainer].push(resolvedType.definition);
}
if (definitionContainer == "entityType") {
typeDefinition.navigationProperty.push(propertyDefinition);
return;
}
}
}
typeDefinition.property.push(propertyDefinition);
});
let operations = getAllOperations(elementType);
Object.keys(operations).forEach((operation) => {
let namespace = operations[operation].prototype[operation].namespace || elementType.namespace || parent.namespace || server.namespace;
let elementTypeNamespace = elementType.namespace || parent.namespace || server.namespace;
let operationSchema = definition.dataServices.schema.filter((schema) => schema.namespace == namespace)[0];
if (!operationSchema) {
operationSchema = {
namespace: namespace,
typeDefinition: [],
enumType: [],
entityType: [],
complexType: [],
action: [],
function: [],
entityContainer: [],
annotation: []
};
definition.dataServices.schema.unshift(operationSchema);
}
if (Edm.isFunction(operations[operation], operation)) {
operationSchema.function.push(resolveOperation(operations[operation], operation, namespace, true, `${elementTypeNamespace}.${elementType.name}`));
}
if (Edm.isAction(operations[operation], operation)) {
operationSchema.action.push(resolveOperation(operations[operation], operation, namespace, true, `${elementTypeNamespace}.${elementType.name}`));
}
});
let __proto__ = Object.getPrototypeOf(elementType.prototype);
if (!baseType && __proto__)
baseType = __proto__.constructor;
if (baseType && baseType != Object && Edm.getProperties(baseType.prototype).length > 0) {
let resolvedType = resolveType(baseType, elementType, prop);
typeDefinition.baseType = (baseType.namespace || server.namespace) + "." + baseType.name;
let definitionContainer = Edm.isEntityType(baseType) ? "entityType" : "complexType";
if (resolvedType && !resolvedType.schema[definitionContainer].filter(et => et.name == resolvedType.definition.name)[0]) {
resolvedType.schema[definitionContainer].push(resolvedType.definition);
}
}
let children = Edm.getChildren(elementType);
children.forEach((child) => {
let resolvedType = resolveType(child, elementType, prop, elementType);
let definitionContainer = Edm.isEntityType(child) ? "entityType" : "complexType";
if (resolvedType && !resolvedType.schema.entityType.filter(et => et.name == resolvedType.definition.name)[0]) {
resolvedType.schema[definitionContainer].push(resolvedType.definition);
}
});
return {
schema: typeSchema,
definition: typeDefinition
};
};
propNames.forEach((i) => {
if (i != "$metadata" && server.prototype[i]) {
if (server.prototype[i].prototype instanceof controller_1.ODataController) {
let ctrl = server.prototype[i];
if (!ctrl.namespace)
ctrl.namespace = server.namespace;
let elementType = ctrl.prototype.elementType;
let containerName = ctrl.containerName || "Default";
let ctrlSchema = definition.dataServices.schema.find((schema) => schema.namespace == ctrl.namespace);
if (!ctrlSchema) {
ctrlSchema = {
namespace: ctrl.namespace,
typeDefinition: [],
enumType: [],
entityType: [],
complexType: [],
action: [],
function: [],
entityContainer: [],
annotation: []
};
definition.dataServices.schema.unshift(ctrlSchema);
}
for (var es in entitySets) {
if (entitySets[es] == ctrl) {
let entityContainer = ctrlSchema.entityContainer.find(ec => ec.name == containerName);
if (!entityContainer) {
entityContainer = {
name: containerName,
entitySet: [],
actionImport: [],
functionImport: []
};
ctrlSchema.entityContainer.unshift(entityContainer);
}
entityContainer.entitySet.push({
name: es,
entityType: Edm.getTypeName(server, i, server.container) || ((elementType.namespace || server.namespace) + "." + elementType.name)
});
}
}
let resolvedType = resolveType(elementType, server, i);
if (resolvedType && !resolvedType.schema.entityType.filter(et => et.name == resolvedType.definition.name)[0]) {
resolvedType.schema.entityType.push(resolvedType.definition);
}
let operations = getAllOperations(ctrl);
Object.keys(operations).forEach((operation) => {
let namespace = operations[operation].prototype[operation].namespace || elementType.namespace || server.namespace;
let elementTypeNamespace = elementType.namespace || server.namespace;
let operationSchema = definition.dataServices.schema.filter((schema) => schema.namespace == namespace)[0];
if (!operationSchema) {
operationSchema = {
namespace: namespace,
typeDefinition: [],
enumType: [],
entityType: [],
complexType: [],
action: [],
function: [],
entityContainer: [],
annotation: []
};
definition.dataServices.schema.unshift(operationSchema);
}
if (Edm.isFunction(operations[operation], operation)) {
operationSchema.function.push(resolveOperation(operations[operation], operation, namespace, true, `Collection(${elementTypeNamespace}.${ctrl.prototype.elementType.name})`));
}
if (Edm.isAction(operations[operation], operation)) {
operationSchema.action.push(resolveOperation(operations[operation], operation, namespace, true, `Collection(${elementTypeNamespace}.${ctrl.prototype.elementType.name})`));
}
});
}
}
});
propNames.forEach((i) => {
if (i != "$metadata" && server.prototype[i]) {
let operationNamespace = server.prototype[i].namespace || server.namespace;
let operationSchema = definition.dataServices.schema.filter((schema) => schema.namespace == operationNamespace)[0];
if (!operationSchema) {
operationSchema = {
namespace: operationNamespace,
typeDefinition: [],
enumType: [],
entityType: [],
complexType: [],
action: [],
function: [],
entityContainer: [],
annotation: []
};
definition.dataServices.schema.unshift(operationSchema);
}
if (Edm.isActionImport(server, i)) {
resolveImport(operationSchema, i, resolveOperation(server, i, operationNamespace), "action");
}
if (Edm.isFunctionImport(server, i)) {
resolveImport(operationSchema, i, resolveOperation(server, i, operationNamespace), "function");
}
}
});
definition.dataServices.schema = definition.dataServices.schema.sort((a, b) => a.namespace.localeCompare(b.namespace));
definition.dataServices.schema.forEach((schema) => {
schema.typeDefinition = schema.typeDefinition.sort((a, b) => a.name.localeCompare(b.name));
schema.enumType = schema.enumType.sort((a, b) => a.name.localeCompare(b.name));
schema.entityType = schema.entityType.sort((a, b) => a.name.localeCompare(b.name));
schema.complexType = schema.complexType.sort((a, b) => a.name.localeCompare(b.name));
schema.entityContainer = schema.entityContainer.sort((a, b) => a.name.localeCompare(b.name));
});
return definition;
}
exports.createMetadataJSON = createMetadataJSON;
//# sourceMappingURL=metadata.js.map