UNPKG

trader-server

Version:

OData server for testing strategies, simulating and real trading.

995 lines 90.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const lexer_1 = require("odata-v4-parser/lib/lexer"); const url = require("url"); const qs = require("qs"); const util = require("util"); const deepmerge = require("deepmerge"); const stream_1 = require("stream"); const utils_1 = require("./utils"); const result_1 = require("./result"); const controller_1 = require("./controller"); const visitor_1 = require("./visitor"); const Edm = require("./edm"); const odata = require("./odata"); const error_1 = require("./error"); const getODataRoot = function (context) { return (context.protocol || "http") + "://" + (context.host || "localhost") + (context.base || ""); }; const createODataContext = function (context, entitySets, server, resourcePath, processor) { let odataContextBase = getODataRoot(context) + "/$metadata#"; let odataContext = ""; let prevResource = null; let prevType = server; let selectContext = ""; if (processor.query && processor.query.$select) { selectContext = `(${processor.query.$select})`; } resourcePath.navigation.forEach((baseResource, i) => { let next = resourcePath.navigation[i + 1]; let selectContextPart = (i == resourcePath.navigation.length - 1) ? selectContext : ""; if (next && next.type == lexer_1.TokenType.RefExpression) return; if (baseResource.type == lexer_1.TokenType.QualifiedEntityTypeName || baseResource.type == lexer_1.TokenType.QualifiedComplexTypeName) { return odataContext += `/${baseResource.name}`; } if (baseResource.type == lexer_1.TokenType.EntitySetName) { prevResource = baseResource; prevType = baseResource.key ? entitySets[baseResource.name].prototype.elementType : entitySets[baseResource.name]; odataContext += baseResource.name; odataContext += selectContextPart; if (baseResource.key && resourcePath.navigation.indexOf(baseResource) == resourcePath.navigation.length - 1) return odataContext += "/$entity"; if (baseResource.key) { if (baseResource.key.length > 1) { return odataContext += "(" + baseResource.key.map((key) => `${key.name}=${decodeURIComponent(key.raw)}`).join(",") + ")"; } else { return odataContext += "(" + decodeURIComponent(baseResource.key[0].raw) + ")"; } } } else if (getResourcePartFunction(baseResource.type) && !(baseResource.name in expCalls)) { odataContext = ""; if (prevResource) { let target = prevType || entitySets[prevResource.name]; if (!target) return; let propertyKey = baseResource.name.split(".").pop(); let returnType = Edm.getReturnType(target, propertyKey, server.container); let returnTypeName = Edm.getReturnTypeName(target, propertyKey, server.container); if (typeof returnType == "function") { prevType = returnType; let ctrl = server.getController(returnType); let entitySet = null; for (let prop in entitySets) { if (entitySets[prop] == ctrl) { entitySet = prop; break; } } returnType = entitySet ? entitySet + (returnTypeName.indexOf("Collection") == 0 ? selectContextPart : selectContextPart + "/$entity") : returnTypeName; } else returnType = returnTypeName; return odataContext += returnType; } else { let call = baseResource.name; let returnType = Edm.getReturnType(server, call, server.container); let returnTypeName = Edm.getReturnTypeName(server, call, server.container); if (typeof returnType == "function") { prevType = returnType; let ctrl = server.getController(returnType); let entitySet = null; for (let prop in entitySets) { if (entitySets[prop] == ctrl) { entitySet = prop; break; } } returnType = entitySet ? entitySet + (returnTypeName.indexOf("Collection") == 0 ? selectContextPart : selectContextPart + "/$entity") : returnTypeName; } else returnType = returnTypeName; return odataContext += returnType; } } if (baseResource.type == lexer_1.TokenType.EntityCollectionNavigationProperty) { prevResource = baseResource; odataContext += "/" + baseResource.name; prevType = baseResource.key ? Edm.getType(prevType, baseResource.name, server.container) : server.getController(Edm.getType(prevType, baseResource.name, server.container)); let ctrl = server.getController(prevType); let entitySet = null; for (let prop in entitySets) { if (entitySets[prop] == ctrl) { entitySet = prop; break; } } if (entitySet) odataContext = entitySet; odataContext += selectContextPart; if (baseResource.key && resourcePath.navigation.indexOf(baseResource) == resourcePath.navigation.length - 1) return odataContext += "/$entity"; if (baseResource.key) { if (baseResource.key.length > 1) { return odataContext += "(" + baseResource.key.map((key) => `${key.name}=${decodeURIComponent(key.raw)}`).join(",") + ")"; } else { return odataContext += "(" + decodeURIComponent(baseResource.key[0].raw) + ")"; } } return odataContext; } if (baseResource.type == lexer_1.TokenType.EntityNavigationProperty) { prevResource = baseResource; prevType = Edm.getType(prevType, baseResource.name, server.container); let ctrl = server.getController(prevType); let entitySet = null; for (let prop in entitySets) { if (entitySets[prop] == ctrl) { entitySet = prop; break; } } return entitySet ? odataContext = entitySet + selectContextPart + "/$entity" : odataContext += "/" + baseResource.name; } if (baseResource.type == lexer_1.TokenType.PrimitiveProperty || baseResource.type == lexer_1.TokenType.PrimitiveCollectionProperty || baseResource.type == lexer_1.TokenType.ComplexProperty || baseResource.type == lexer_1.TokenType.ComplexCollectionProperty) { prevType = Edm.getType(prevType, baseResource.name, server.container); return odataContext += "/" + baseResource.name; } }); return odataContextBase + odataContext; }; const fnCaller = function (fn, params) { params = params || {}; let fnParams; fnParams = utils_1.getFunctionParameters(fn); for (var i = 0; i < fnParams.length; i++) { fnParams[i] = params[fnParams[i]]; } return fn.apply(this, fnParams); }; const ODataRequestMethods = ["get", "post", "put", "patch", "delete"]; const ODataRequestResult = { get: result_1.ODataResult.Ok, post: result_1.ODataResult.Created, put: (result, contentType) => { return (result ? result_1.ODataResult.Created : result_1.ODataResult.NoContent)(result, contentType); }, patch: result_1.ODataResult.NoContent, delete: result_1.ODataResult.NoContent }; const expCalls = { $count: function () { return this.body && this.body.value ? (this.body.value.length || 0) : 0; }, $value: function (processor) { return tslib_1.__awaiter(this, void 0, void 0, function* () { try { let prevPart = processor.resourcePath.navigation[processor.resourcePath.navigation.length - 2]; let fn = odata.findODataMethod(processor.ctrl, `${processor.method}/${prevPart.name}/$value`, prevPart.key || []); if (!fn && typeof this.elementType == "function" && Edm.isMediaEntity(this.elementType)) { fn = odata.findODataMethod(processor.ctrl, `${processor.method}/$value`, prevPart.key || []); } if (fn) { let ctrl = processor.ctrl; let params = {}; if (prevPart.key) prevPart.key.forEach((key) => params[key.name] = key.value); let fnDesc = fn; yield processor.__applyParams(ctrl, fnDesc.call, params, processor.url.query, this); fn = ctrl.prototype[fnDesc.call]; if (fnDesc.key.length == 1 && prevPart.key.length == 1 && fnDesc.key[0].to != prevPart.key[0].name) { params[fnDesc.key[0].to] = params[prevPart.key[0].name]; delete params[prevPart.key[0].name]; } else { for (let i = 0; i < fnDesc.key.length; i++) { if (fnDesc.key[i].to != fnDesc.key[i].from) { params[fnDesc.key[i].to] = params[fnDesc.key[i].from]; delete params[fnDesc.key[i].from]; } } } let currentResult = fnCaller.call(ctrl, fn, params); if (utils_1.isIterator(fn)) { currentResult = run(currentResult, defaultHandlers); } if (!utils_1.isPromise(currentResult)) { currentResult = Promise.resolve(currentResult); } if (prevPart.type == "PrimitiveProperty" || prevPart.type == "PrimitiveKeyProperty") return currentResult.then(value => value.toString()); return currentResult; } else { if (this.stream) return Promise.resolve(this.stream); if (this.body) { let result = this.body.value || this.body; for (let prop in result) { if (prop.indexOf("@odata") >= 0) delete result[prop]; } result = result.value || result; if (typeof result == "object" && (prevPart.type == "PrimitiveProperty" || prevPart.type == "PrimitiveKeyProperty")) return Promise.resolve(result.toString()); return Promise.resolve(result); } } } catch (err) { return Promise.reject(err); } }); }, $ref: function (processor) { return tslib_1.__awaiter(this, void 0, void 0, function* () { try { let prevPart = processor.resourcePath.navigation[processor.resourcePath.navigation.length - 2]; let routePart = processor.resourcePath.navigation[processor.resourcePath.navigation.length - 3]; let fn = odata.findODataMethod(processor.prevCtrl, processor.method + "/" + prevPart.name + "/$ref", routePart.key || []); if (processor.method == "get") { return { "@odata.context": `${getODataRoot(processor.context)}/$metadata#$ref`, "@odata.id": `${this.body["@odata.id"]}/${prevPart.name}` }; } if (!fn) throw new error_1.ResourceNotFoundError(); let linkUrl = (processor.resourcePath.id || (processor.body || {})["@odata.id"] || "").replace(getODataRoot(processor.context), ""); let linkAst, linkPath, linkPart; if (linkUrl) { linkUrl = decodeURIComponent(linkUrl); processor.emit("header", { "OData-EntityId": linkUrl }); linkAst = processor.serverType.parser.odataUri(linkUrl, { metadata: processor.serverType.$metadata().edmx }); linkPath = yield new visitor_1.ResourcePathVisitor(processor.serverType, processor.entitySets).Visit(linkAst); linkPart = linkPath.navigation[linkPath.navigation.length - 1]; } else linkPart = prevPart; let ctrl = processor.prevCtrl; let params = {}; if (routePart.key) routePart.key.forEach((key) => params[key.name] = key.value); let fnDesc = fn; yield processor.__applyParams(ctrl, fnDesc.call, params, processor.url.query, this); fn = ctrl.prototype[fnDesc.call]; if (fnDesc.key.length == 1 && routePart.key.length == 1 && fnDesc.key[0].to != routePart.key[0].name) { params[fnDesc.key[0].to] = params[routePart.key[0].name]; delete params[routePart.key[0].name]; } else { for (let i = 0; i < fnDesc.key.length; i++) { if (fnDesc.key[i].to != fnDesc.key[i].from) { params[fnDesc.key[i].to] = params[fnDesc.key[i].from]; delete params[fnDesc.key[i].from]; } } } let linkParams = {}; if (linkPart.key) linkPart.key.forEach((key) => linkParams[key.name] = key.value); if (fnDesc.link.length == 1 && linkPart.key.length == 1 && fnDesc.link[0].to != linkPart.key[0].name) { params[fnDesc.link[0].to] = linkParams[linkPart.key[0].name]; } else { for (let i = 0; i < fnDesc.link.length; i++) { params[fnDesc.link[i].to] = linkParams[fnDesc.link[i].from]; } } let currentResult = fnCaller.call(ctrl, fn, params); if (utils_1.isIterator(fn)) { currentResult = run(currentResult, defaultHandlers); } if (!utils_1.isPromise(currentResult)) { currentResult = Promise.resolve(currentResult); } return currentResult; } catch (err) { return Promise.reject(err); } }); } }; const getResourcePartFunction = (type) => { switch (type) { case "PrimitiveFunctionImportCall": case "PrimitiveCollectionFunctionImportCall": case "ComplexFunctionImportCall": case "ComplexCollectionFunctionImportCall": case "EntityFunctionImportCall": case "EntityCollectionFunctionImportCall": case "ActionImportCall": case "ActionImport": return "__actionOrFunctionImport"; case "BoundPrimitiveFunctionCall": case "BoundPrimitiveCollectionFunctionCall": case "BoundComplexFunctionCall": case "BoundComplexCollectionFunctionCall": case "BoundEntityFunctionCall": case "BoundEntityCollectionFunctionCall": case "BoundActionCall": case "BoundAction": case "CountExpression": case "ValueExpression": case "RefExpression": return "__actionOrFunction"; default: return null; } }; const jsPrimitiveTypes = [ Object, String, Boolean, Number, Date ]; const writeMethods = [ "delete", "post", "put", "patch" ]; var ODataGeneratorHandlers; (function (ODataGeneratorHandlers) { function PromiseHandler(request, next) { if (utils_1.isPromise(request)) { return request.then(next); } } ODataGeneratorHandlers.PromiseHandler = PromiseHandler; function StreamHandler(request, next) { if (utils_1.isStream(request)) { return new Promise((resolve, reject) => { request.on("end", resolve); request.on("error", reject); }).then(next); } } ODataGeneratorHandlers.StreamHandler = StreamHandler; function GeneratorHandler(request, next) { if (utils_1.isIterator(request)) { return run(request(), defaultHandlers).then(next); } } ODataGeneratorHandlers.GeneratorHandler = GeneratorHandler; })(ODataGeneratorHandlers = exports.ODataGeneratorHandlers || (exports.ODataGeneratorHandlers = {})); const defaultHandlers = [ ODataGeneratorHandlers.GeneratorHandler, ODataGeneratorHandlers.PromiseHandler, ODataGeneratorHandlers.StreamHandler ]; function run(iterator, handlers) { function id(x) { return x; } function iterate(value) { let next = iterator.next(value); let request = next.value; let nextAction = next.done ? id : iterate; for (let handler of handlers) { let action = handler(request, nextAction); if (typeof action != "undefined") return action; } return nextAction(request); } return iterate(); } class ODataStreamWrapper extends stream_1.Transform { constructor() { super({ objectMode: true }); this.buffer = []; } _transform(chunk, _, done) { this.buffer.push(chunk); if (typeof done == "function") done(); } _flush(done) { if (typeof done == "function") done(); } toPromise() { return new Promise((resolve, reject) => { this.on("finish", () => { resolve(this.buffer); }); this.on("error", reject); }); } } class StreamWrapper { constructor(value) { this.stream = value; } } var ODataMetadataType; (function (ODataMetadataType) { ODataMetadataType[ODataMetadataType["minimal"] = 0] = "minimal"; ODataMetadataType[ODataMetadataType["full"] = 1] = "full"; ODataMetadataType[ODataMetadataType["none"] = 2] = "none"; })(ODataMetadataType = exports.ODataMetadataType || (exports.ODataMetadataType = {})); class ODataProcessor extends stream_1.Transform { constructor(context, server, options) { super({ objectMode: true }); this.streamStart = false; this.streamEnabled = false; this.streamObject = false; this.streamEnd = false; this.resultCount = 0; this.context = context; this.serverType = server; this.options = options || {}; let method = this.method = context.method.toLowerCase(); if (ODataRequestMethods.indexOf(method) < 0) throw new error_1.MethodNotAllowedError(); context.url = decodeURIComponent(context.url); this.url = url.parse(context.url); this.query = qs.parse(this.url.query); let ast = this.serverType.parser.odataUri(context.url, { metadata: this.serverType.$metadata().edmx }); if (this.serverType.validator) { this.serverType.validator(ast); } let entitySets = this.entitySets = odata.getPublicControllers(this.serverType); this.workflow = [(body) => tslib_1.__awaiter(this, void 0, void 0, function* () { let resourcePath = this.resourcePath = yield new visitor_1.ResourcePathVisitor(this.serverType, this.entitySets).Visit(ast); this.odataContext = createODataContext(context, entitySets, server, resourcePath, this); if (resourcePath.navigation.length == 0) throw new error_1.ResourceNotFoundError(); this.workflow.push(...resourcePath.navigation.map((part, i) => { let next = resourcePath.navigation[i + 1]; if (next && next.type == lexer_1.TokenType.RefExpression) return null; let fn = getResourcePartFunction(part.type) || ("__" + part.type); switch (fn) { case "__actionOrFunction": return this.__actionOrFunction.call(this, part); case "__actionOrFunctionImport": return this.__actionOrFunctionImport.call(this, part); case "__QualifiedEntityTypeName": case "__QualifiedComplexTypeName": return this.__qualifiedTypeName.call(this, part); case "__PrimitiveKeyProperty": case "__PrimitiveCollectionProperty": case "__ComplexProperty": case "__ComplexCollectionProperty": case "__PrimitiveProperty": return this.__PrimitiveProperty.call(this, part); case "__EntitySetName": return this.__EntitySetName.call(this, part); case "__EntityCollectionNavigationProperty": return this.__EntityCollectionNavigationProperty.call(this, part); case "__EntityNavigationProperty": return this.__EntityNavigationProperty.call(this, part); default: return null; } }).filter(it => !!it)); this.workflow.push((result) => { if (result && result.statusCode && result.statusCode == 201) { this.emit("header", { "Location": result.body["@odata.id"] }); } return Promise.resolve(result); }); return body; })]; } _transform(chunk, _, done) { if (this.streamEnabled) { if (!(chunk instanceof Buffer)) { this.streamObject = true; if (!this.streamStart) { if (!this.options.objectMode) { this.push("{"); if (this.options.metadata != ODataMetadataType.none) { this.push(`"@odata.context":"${this.odataContext}",`); } this.push('"value":['); } } else if (!this.options.objectMode && this.resultCount > 0) this.push(','); try { this.streamStart = true; if (chunk instanceof Object) { if (chunk["@odata.count"] || chunk.inlinecount) { this.streamInlineCount = chunk["@odata.count"] || chunk.inlinecount; if (Object.keys(chunk).length == 1) { return typeof done == "function" ? done() : null; } else { delete chunk["@odata.count"]; delete chunk.inlinecount; } } let entity = {}; let defer; if (this.ctrl) defer = this.__appendLinks(this.ctrl, this.elementType || this.ctrl.prototype.elementType, entity, chunk); let deferConvert = this.__convertEntity(entity, chunk, this.elementType || this.ctrl.prototype.elementType, this.resourcePath.includes, this.resourcePath.select); defer = defer ? defer.then(_ => deferConvert) : deferConvert; defer.then(() => { chunk = this.options.objectMode ? entity : JSON.stringify(entity); this.push(chunk); this.resultCount++; if (typeof done == "function") done(); }, (err) => { console.log(err); if (typeof done == "function") done(err); }); } else { this.push(JSON.stringify(chunk)); this.resultCount++; if (typeof done == "function") done(); } } catch (err) { console.log(err); if (typeof done == "function") done(err); } } else { this.streamStart = true; this.push(chunk); this.resultCount++; if (typeof done == "function") done(); } } else { this.resultCount++; if (typeof done == "function") done(); } } _flush(done) { if (this.streamEnabled && this.streamObject) { if (this.options.objectMode) { let flushObject = { value: [], elementType: this.elementType || this.ctrl.prototype.elementType }; if (this.options.metadata != ODataMetadataType.none) { flushObject["@odata.context"] = this.odataContext; } if (this.streamStart && typeof this.streamInlineCount == "number") { flushObject["@odata.count"] = this.streamInlineCount; } this.push(flushObject); } else { if (this.streamStart) { if (typeof this.streamInlineCount == "number") { this.push(`],"@odata.count":${this.streamInlineCount}}`); } else this.push("]}"); } else { if (this.options.metadata == ODataMetadataType.none) { this.push('{"value":[]}'); } else { this.push(`{"@odata.context":"${this.odataContext}","value":[]}`); } } } } else if (this.streamEnabled && !this.streamStart) { if (this.options.metadata == ODataMetadataType.none) { this.push('{"value":[]}'); } else { this.push(`{"@odata.context":"${this.odataContext}","value":[]}`); } } this.streamEnd = true; if (typeof done == "function") done(); } __qualifiedTypeName(part) { return (result) => { result.elementType = part.node[visitor_1.ODATA_TYPE]; return result; }; } __EntityCollectionNavigationProperty(part) { return (result) => tslib_1.__awaiter(this, void 0, void 0, function* () { try { let resultType = result.elementType; let elementType = Edm.getType(resultType, part.name, this.serverType.container); let partIndex = this.resourcePath.navigation.indexOf(part); let method = writeMethods.indexOf(this.method) >= 0 && partIndex < this.resourcePath.navigation.length - 1 ? "get" : this.method; let fn = odata.findODataMethod(this.ctrl, `${method}/${part.name}`, part.key); if (fn) { let ctrl = this.ctrl; let fnDesc = fn; let params = {}; if (part.key) part.key.forEach((key) => params[key.name] = key.value); yield this.__applyParams(ctrl, fnDesc.call, params, this.url.query, result); fn = ctrl.prototype[fnDesc.call]; if (fnDesc.key.length == 1 && part.key.length == 1 && fnDesc.key[0].to != part.key[0].name) { params[fnDesc.key[0].to] = params[part.key[0].name]; delete params[part.key[0].name]; } else { for (let i = 0; i < fnDesc.key.length; i++) { if (fnDesc.key[i].to != fnDesc.key[i].from) { params[fnDesc.key[i].to] = params[fnDesc.key[i].from]; delete params[fnDesc.key[i].from]; } } } if (part.key) part.key.forEach((key) => params[key.name] = key.value); this.elementType = elementType; return this.__read(ctrl, part, params, result, fn, elementType).then((result) => { this.ctrl = this.serverType.getController(elementType); return result; }); } else { let ctrl = this.serverType.getController(elementType); let foreignKeys = Edm.getForeignKeys(resultType, part.name); let typeKeys = Edm.getKeyProperties(resultType); result.foreignKeys = {}; let foreignFilter = (yield Promise.all(foreignKeys.map((key) => tslib_1.__awaiter(this, void 0, void 0, function* () { result.foreignKeys[key] = result.body[typeKeys[0]]; return `${key} eq ${yield Edm.escape(result.body[typeKeys[0]], Edm.getTypeName(elementType, key, this.serverType.container))}`; })))).join(" and "); let params = {}; if (part.key) part.key.forEach((key) => params[key.name] = key.value); return this.__read(ctrl, part, params, result, foreignFilter); } } catch (err) { return Promise.reject(err); } }); } __EntityNavigationProperty(part) { return (result) => tslib_1.__awaiter(this, void 0, void 0, function* () { try { let resultType = result.elementType; let elementType = Edm.getType(resultType, part.name, this.serverType.container); let partIndex = this.resourcePath.navigation.indexOf(part); let method = writeMethods.indexOf(this.method) >= 0 && partIndex < this.resourcePath.navigation.length - 1 ? "get" : this.method; let fn = odata.findODataMethod(this.ctrl, `${method}/${part.name}`, part.key); if (fn) { let ctrl = this.ctrl; let fnDesc = fn; let params = {}; if (part.key) part.key.forEach((key) => params[key.name] = key.value); yield this.__applyParams(ctrl, fnDesc.call, params, this.url.query, result); fn = ctrl.prototype[fnDesc.call]; if (fnDesc.key.length == 1 && part.key.length == 1 && fnDesc.key[0].to != part.key[0].name) { params[fnDesc.key[0].to] = params[part.key[0].name]; delete params[part.key[0].name]; } else { for (let i = 0; i < fnDesc.key.length; i++) { if (fnDesc.key[i].to != fnDesc.key[i].from) { params[fnDesc.key[i].to] = params[fnDesc.key[i].from]; delete params[fnDesc.key[i].from]; } } } this.elementType = elementType; return this.__read(ctrl, part, params, result, fn, elementType).then((result) => { this.ctrl = this.serverType.getController(elementType); return result; }); } else { let ctrl = this.serverType.getController(elementType); let foreignKeys = Edm.getForeignKeys(resultType, part.name); result.foreignKeys = {}; part.key = foreignKeys.map((key) => { result.foreignKeys[key] = result.body[key]; return { name: key, value: result.body[key] }; }); let params = {}; if (part.key) part.key.forEach((key) => params[key.name] = key.value); return this.__read(ctrl, part, params, result); } } catch (err) { return Promise.reject(err); } }); } __PrimitiveProperty(part) { return (result) => tslib_1.__awaiter(this, void 0, void 0, function* () { try { return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () { this.__enableStreaming(part); let currentResult; let prevPart = this.resourcePath.navigation[this.resourcePath.navigation.indexOf(part) - 1]; let fn = odata.findODataMethod(this.ctrl, `${this.method}/${part.name}`, prevPart.key || []) || odata.findODataMethod(this.ctrl, `${this.method}/${part.name}/$value`, prevPart.key || []); if (!fn && this.method != "get") { fn = this.method == "delete" ? odata.findODataMethod(this.ctrl, "patch", prevPart.key || []) : odata.findODataMethod(this.ctrl, `${this.method}`, prevPart.key || []); if (fn) { let body = this.body; if (Edm.getTypeName(result.elementType, part.name, this.serverType.container) != "Edm.Stream") body = body.body || body; this.body = {}; this.body[part.name] = this.method == "delete" ? null : body.value || body; } } if (fn) { let ctrl = this.prevCtrl; let params = {}; if (prevPart.key) prevPart.key.forEach((key) => params[key.name] = key.value); let fnDesc = fn; yield this.__applyParams(ctrl, fnDesc.call, params, this.url.query, result); fn = ctrl.prototype[fnDesc.call]; if (fnDesc.key.length == 1 && prevPart.key.length == 1 && fnDesc.key[0].to != prevPart.key[0].name) { params[fnDesc.key[0].to] = params[prevPart.key[0].name]; delete params[prevPart.key[0].name]; } else { for (let i = 0; i < fnDesc.key.length; i++) { if (fnDesc.key[i].to != fnDesc.key[i].from) { params[fnDesc.key[i].to] = params[fnDesc.key[i].from]; delete params[fnDesc.key[i].from]; } } } this.elementType = Edm.getType(result.elementType, part.name, this.serverType.container) || Object; if (typeof this.elementType == "string") this.elementType = Object; currentResult = fnCaller.call(ctrl, fn, params); if (utils_1.isIterator(fn)) { currentResult = run(currentResult, defaultHandlers); } if (!utils_1.isPromise(currentResult)) { currentResult = Promise.resolve(currentResult); } } else { let value = result.body[part.name]; if (value instanceof StreamWrapper) { value = value.stream; } currentResult = Promise.resolve(value); } if (this.method == "get") { currentResult.then((value) => { try { result.body = { "@odata.context": this.options.metadata != ODataMetadataType.none ? result.body["@odata.context"] : undefined, value: value }; let elementType = result.elementType; //if (value instanceof Object) result.elementType = Edm.isEnumType(result.elementType, part.name) ? Edm.getTypeName(result.elementType, part.name, this.serverType.container) : Edm.getType(result.elementType, part.name, this.serverType.container) || Object; if (value && (utils_1.isStream(value) || utils_1.isStream(value.stream))) { this.emit("header", { "Content-Type": Edm.getContentType(elementType.prototype, part.name) || value.contentType || "application/octet-stream" }); if (value.stream) value = value.stream; value.pipe(this); value.on("end", resolve); value.on("error", reject); } else { if (this.streamEnabled && this.streamStart) delete result.body; if (result.stream) delete result.stream; resolve(result); } } catch (err) { console.log(err); reject(err); } }, reject); } else { result_1.ODataResult.NoContent(currentResult).then(resolve, reject); } })); } catch (err) { return Promise.reject(err); } }); } __read(ctrl, part, params, data, filter, elementType, include, select) { return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () { try { select = select || this.resourcePath.select; if (this.ctrl) this.prevCtrl = this.ctrl; else this.prevCtrl = ctrl; this.ctrl = ctrl; let method = writeMethods.indexOf(this.method) >= 0 && this.resourcePath.navigation.indexOf(part) < this.resourcePath.navigation.length - 1 ? "get" : this.method; this.instance = new ctrl(); let fn; if (typeof filter == "string" || !filter) { fn = odata.findODataMethod(ctrl, method, part.key); if (!fn) return reject(new error_1.ResourceNotFoundError()); let queryString = filter ? `$filter=${filter}` : (include || this.url).query; if (include && filter && include.query && !include.query.$filter) { include.query.$filter = filter; queryString = Object.keys(include.query).map(p => { return `${p}=${include.query[p]}`; }).join("&"); } else if ((include && filter && include.query) || (!include && this.resourcePath.navigation.indexOf(part) == this.resourcePath.navigation.length - 1)) { queryString = Object.keys((include || this).query).map(p => { if (p == "$filter" && filter) { (include || this).query[p] = `(${(include || this).query[p]}) and (${filter})`; } return `${p}=${(include || this).query[p]}`; }).join("&") || queryString; } if (queryString && typeof queryString == "object") { queryString = Object.keys(queryString).map(p => { return `${p}=${queryString[p]}`; }).join("&"); } if (typeof fn != "function") { let fnDesc = fn; fn = ctrl.prototype[fnDesc.call]; if (fnDesc.key.length == 1 && part.key.length == 1 && fnDesc.key[0].to != part.key[0].name) { params[fnDesc.key[0].to] = params[part.key[0].name]; delete params[part.key[0].name]; } else { for (let i = 0; i < fnDesc.key.length; i++) { if (fnDesc.key[i].to != fnDesc.key[i].from) { params[fnDesc.key[i].to] = params[fnDesc.key[i].from]; delete params[fnDesc.key[i].from]; } } } yield this.__applyParams(ctrl, fnDesc.call, params, queryString, undefined, include); } else yield this.__applyParams(ctrl, method, params, queryString, undefined, include); } else fn = filter; if (!include) this.__enableStreaming(part); let currentResult; switch (method) { case "get": case "delete": currentResult = fnCaller.call(ctrl, fn, params); break; case "post": this.odataContext += "/$entity"; case "put": case "patch": let body = data ? Object.assign(this.body || {}, data.foreignKeys) : this.body; let bodyParam = odata.getBodyParameter(ctrl, fn.name); let typeParam = odata.getTypeParameter(ctrl, fn.name); if (typeParam) { params[typeParam] = (body["@odata.type"] || (`${ctrl.prototype.elementType.namespace}.${ctrl.prototype.elementType.name}`)).replace(/^#/, ""); } if (bodyParam) { yield this.__deserialize(body, ctrl.prototype.elementType); this.__stripOData(body); params[bodyParam] = body; } if (!part.key) { let properties = Edm.getProperties((elementType || ctrl.prototype.elementType).prototype); properties.forEach((prop) => { if (Edm.isKey(elementType || ctrl.prototype.elementType, prop)) { params[prop] = (this.body || {})[prop] || ((data || {}).body || {})[prop]; } }); } currentResult = fnCaller.call(ctrl, fn, params); break; } if (utils_1.isIterator(fn)) { currentResult = run(currentResult, defaultHandlers); } if (!utils_1.isPromise(currentResult)) { currentResult = Promise.resolve(currentResult); } return currentResult.then((result) => { if (utils_1.isStream(result) && include) { include.streamPromise.then((result) => { ODataRequestResult[method](result).then((result) => { if (elementType) result.elementType = elementType; return this.__appendODataContext(result, elementType || this.ctrl.prototype.elementType, (include || this.resourcePath).includes, select).then(() => { resolve(result); }, reject); }, reject); }, reject); } else if (utils_1.isStream(result) && (!part.key || !Edm.isMediaEntity(elementType || this.ctrl.prototype.elementType))) { result.on("end", () => resolve(ODataRequestResult[method]())); result.on("error", reject); } else if (!(result instanceof result_1.ODataResult)) { return ODataRequestResult[method](result).then((result) => { if (!this.streamStart && writeMethods.indexOf(this.method) < 0 && !result.body) return reject(new error_1.ResourceNotFoundError()); try { if (elementType) result.elementType = elementType; this.__appendODataContext(result, elementType || this.ctrl.prototype.elementType, (include || this.resourcePath).includes, select).then(() => { if (!this.streamEnd && this.streamEnabled && this.streamStart) this.on("end", () => resolve(result)); else resolve(result); }, reject); } catch (err) { reject(err); } }, reject); } else { try { if (elementType) result.elementType = elementType; this.__appendODataContext(result, elementType || this.ctrl.prototype.elementType, (include || this.resourcePath).includes, select).then(() => { if (!this.streamEnd && this.streamEnabled && this.streamStart) this.on("end", () => resolve(result)); else resolve(result); }, reject); } catch (err) { reject(err); } } }, reject); } catch (err) { reject(err); } })); } __deserialize(obj, type) { return tslib_1.__awaiter(this, void 0, void 0, function* () { for (let prop in obj) {