trader-server
Version:
OData server for testing strategies, simulating and real trading.
995 lines • 90.7 kB
JavaScript
"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) {