ravendb
Version:
RavenDB client for Node.js
124 lines • 5.39 kB
JavaScript
import { ClusterRequestExecutor } from "../../Http/ClusterRequestExecutor.js";
import { ServerWideOperationCompletionAwaiter } from "../../ServerWide/Operations/ServerWideOperationCompletionAwaiter.js";
import { getLogger } from "../../Utility/LogUtil.js";
import { throwError } from "../../Exceptions/index.js";
import { StringUtil } from "../../Utility/StringUtil.js";
import { GetBuildNumberOperation } from "../../ServerWide/Operations/GetBuildNumberOperation.js";
const log = getLogger({ module: "ServerOperationExecutor" });
export class ServerOperationExecutor {
_cache;
_nodeTag;
_store;
_requestExecutor;
_initialRequestExecutor;
constructor(store, requestExecutor, initialRequestExecutor, cache, nodeTag) {
requestExecutor = requestExecutor || ServerOperationExecutor._createRequestExecutor(store);
cache = cache || new Map();
if (!store) {
throwError("InvalidArgumentException", "Store cannot be null");
}
if (!requestExecutor) {
throwError("InvalidArgumentException", "RequestExecutor cannot be null");
}
this._store = store;
this._requestExecutor = requestExecutor;
this._initialRequestExecutor = initialRequestExecutor;
this._nodeTag = nodeTag;
this._cache = cache;
store.registerEvents(this._requestExecutor);
if (!nodeTag) {
store.once("afterDispose", (callback) => {
log.info("Dispose request executor.");
this._requestExecutor.dispose();
callback();
});
}
}
async forNode(nodeTag) {
if (StringUtil.isNullOrWhitespace(nodeTag)) {
throwError("InvalidArgumentException", "Value cannot be null or whitespace.");
}
if ((!nodeTag && !this._nodeTag) || StringUtil.equalsIgnoreCase(this._nodeTag, nodeTag)) {
return this;
}
if (this._store.conventions.disableTopologyUpdates) {
throwError("InvalidOperationException", "Cannot switch server operation executor, because conventions.disableTopologyUpdates is set to 'true'");
}
const existingValue = this._cache.get(nodeTag.toLowerCase());
if (existingValue) {
return existingValue;
}
const requestExecutor = this._initialRequestExecutor || this._requestExecutor;
const topology = await this._getTopology(requestExecutor);
const node = topology.nodes
.find(x => StringUtil.equalsIgnoreCase(x.clusterTag, nodeTag));
if (!node) {
const availableNodes = topology
.nodes
.map(x => x.clusterTag)
.join(", ");
throwError("InvalidOperationException", "Could not find node '" + nodeTag + "' in the topology. Available nodes: " + availableNodes);
}
const clusterExecutor = ClusterRequestExecutor.createForSingleNode(node.url, {
authOptions: this._store.authOptions
});
return new ServerOperationExecutor(this._store, clusterExecutor, requestExecutor, this._cache, node.clusterTag);
}
async send(operation) {
const command = operation.getCommand(this._requestExecutor.conventions);
await this._requestExecutor.execute(command);
if (operation.resultType === "OperationId") {
const idResult = command.result;
return new ServerWideOperationCompletionAwaiter(this._requestExecutor, this._requestExecutor.conventions, idResult.operationId, command.selectedNodeTag || idResult.operationNodeTag);
}
return command.result;
}
dispose() {
if (this._nodeTag) {
return;
}
if (this._requestExecutor) {
this._requestExecutor.dispose();
}
if (this._cache) {
for (const [key, value] of this._cache.entries()) {
const requestExecutor = value._requestExecutor;
if (requestExecutor) {
requestExecutor.dispose();
}
}
this._cache.clear();
}
}
async _getTopology(requestExecutor) {
let topology = null;
try {
topology = requestExecutor.getTopology();
if (!topology) {
// a bit rude way to make sure that topology has been refreshed
// but it handles a case when first topology update failed
const operation = new GetBuildNumberOperation();
const command = operation.getCommand(requestExecutor.conventions);
await requestExecutor.execute(command);
topology = requestExecutor.getTopology();
}
}
catch {
// ignored
}
if (!topology) {
throwError("InvalidOperationException", "Could not fetch the topology");
}
return topology;
}
static _createRequestExecutor(store) {
const args = {
authOptions: store.authOptions,
documentConventions: store.conventions
};
return store.conventions.disableTopologyUpdates
? ClusterRequestExecutor.createForSingleNode(store.urls[0], args)
: ClusterRequestExecutor.create(store.urls, args);
}
}
//# sourceMappingURL=ServerOperationExecutor.js.map