UNPKG

ravendb

Version:
211 lines 8.17 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MultiGetCommand = void 0; const RavenCommand_js_1 = require("../../../Http/RavenCommand.js"); const GetResponse_js_1 = require("./GetResponse.js"); const StatusCode_js_1 = require("../../../Http/StatusCode.js"); const HttpUtil_js_1 = require("../../../Utility/HttpUtil.js"); const index_js_1 = require("../../../Exceptions/index.js"); const Constants_js_1 = require("../../../Constants.js"); const ObjectUtil_js_1 = require("../../../Utility/ObjectUtil.js"); class MultiGetCommand extends RavenCommand_js_1.RavenCommand { _requestExecutor; _httpCache; _commands; _sessionInfo; _conventions; _baseUrl; _cached; aggressivelyCached; constructor(requestExecutor, conventions, commands, sessionInfo) { super(); this._requestExecutor = requestExecutor; if (!requestExecutor) { (0, index_js_1.throwError)("InvalidArgumentException", "RequestExecutor cannot be null"); } this._httpCache = requestExecutor.cache; if (!commands) { (0, index_js_1.throwError)("InvalidArgumentException", "Commands cannot be null"); } this._commands = commands; this._conventions = conventions; this._sessionInfo = sessionInfo; this._responseType = "Raw"; } _getCacheKey(command) { const url = this._baseUrl + command.urlAndQuery; return (command.method || "GET") + "-" + url; } createRequest(node) { this._baseUrl = node.url + "/databases/" + node.database; const requests = []; const bodyObj = { Requests: requests }; const request = { uri: this._baseUrl + "/multi_get", method: "POST", headers: this._headers().typeAppJson().build(), }; if ((!this._sessionInfo || !this._sessionInfo.noCaching) && this._maybeReadAllFromCache(this._requestExecutor.aggressiveCaching)) { this.aggressivelyCached = true; return null; // aggressively cached } for (const command of this._commands) { const req = { Url: "/databases/" + node.database + command.url, Query: command.query, Method: command.method || "GET", Headers: command.headers, Content: command.body }; requests.push(req); } request.body = JSON.stringify(bodyObj); return request; } _maybeReadAllFromCache(options) { this.closeCache(); let readAllFromCache = !!options; for (let i = 0; i < this._commands.length; i++) { const command = this._commands[i]; if (Constants_js_1.HEADERS.IF_NONE_MATCH in command.headers) { continue; // command already explicitly handling setting this, let's not touch it. } const cacheKey = this._getCacheKey(command); let changeVector; let cachedRef; const cachedItem = this._httpCache.get(cacheKey, c => { changeVector = c.changeVector; cachedRef = c.response; }); if (!cachedItem.item) { readAllFromCache = false; continue; } if (readAllFromCache && cachedItem.age > options.duration || !command.canCacheAggressively) { readAllFromCache = false; } command.headers[Constants_js_1.HEADERS.IF_NONE_MATCH] = changeVector; if (!this._cached) { this._cached = new Cached(this._commands.length); } this._cached.values[i] = [cachedItem, cachedRef]; } if (readAllFromCache) { try { this.result = []; for (let i = 0; i < this._commands.length; i++) { const itemAndCached = this._cached.values[i]; const getResponse = new GetResponse_js_1.GetResponse(); getResponse.result = itemAndCached[1]; getResponse.statusCode = StatusCode_js_1.StatusCodes.NotModified; this.result.push(getResponse); } } finally { this._cached.dispose(); } this._cached = null; } return readAllFromCache; } async setResponseAsync(bodyStream, fromCache) { if (!bodyStream) { this._throwInvalidResponse(); } try { const result = await this._pipeline() .parseJsonSync() .process(bodyStream); const responses = result.Results.map(item => MultiGetCommand._mapToLocalObject(item)); this.result = []; for (let i = 0; i < responses.length; i++) { const res = responses[i]; const command = this._commands[i]; this._maybeSetCache(res, command, i); if (this._cached && res.statusCode === StatusCode_js_1.StatusCodes.NotModified) { const clonedResponse = new GetResponse_js_1.GetResponse(); clonedResponse.result = this._cached.values[i][1]; clonedResponse.statusCode = StatusCode_js_1.StatusCodes.NotModified; this.result.push(clonedResponse); } else { this.result.push(GetResponse_js_1.GetResponse.create(res)); } } return null; } finally { if (this._cached) { this._cached.dispose(); } } } _maybeSetCache(getResponse, command, cachedIndex) { if (getResponse.statusCode === StatusCode_js_1.StatusCodes.NotModified) { // if not modified - update age if (this._cached) { this._cached.values[cachedIndex][0].notModified(); } return; } const cacheKey = this._getCacheKey(command); const result = getResponse.result; if (!result) { this._httpCache.setNotFound(cacheKey); return; } const changeVector = (0, HttpUtil_js_1.getEtagHeader)(getResponse.headers); if (!changeVector) { return; } this._httpCache.set(cacheKey, changeVector, result); } get isReadRequest() { return false; } dispose() { this.closeCache(); } closeCache() { //If _cached is not null - it means that the client approached with this multitask request to node and the request failed. //and now client tries to send it to another node. if (this._cached) { this._cached.dispose(); this._cached = null; // The client sends the commands. // Some of which could be saved in cache with a response // that includes the change vector that received from the old fallen node. // The client can't use those responses because their URLs are different // (include the IP and port of the old node), because of that the client // needs to get those docs again from the new node. for (const command of this._commands) { delete command.headers[Constants_js_1.HEADERS.IF_NONE_MATCH]; } } } static _mapToLocalObject(json) { // convert from Pascal to camel on top level only const item = {}; for (const [key, value] of Object.entries(json)) { item[ObjectUtil_js_1.ObjectUtil.camelCase(key)] = value; } item.result = item.result ? JSON.stringify(item.result) : null; return item; } } exports.MultiGetCommand = MultiGetCommand; class Cached { _size; values; constructor(size) { this._size = size; this.values = new Array(size); } dispose() { if (!this.values) { return; } this.values = null; } } //# sourceMappingURL=MultiGetCommand.js.map