@configurator/ravendb
Version:
RavenDB client for Node.js
254 lines • 10.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DocumentStore = void 0;
const uuid_1 = require("uuid");
const BluebirdPromise = require("bluebird");
const Exceptions_1 = require("../Exceptions");
const RequestExecutor_1 = require("../Http/RequestExecutor");
const LogUtil_1 = require("../Utility/LogUtil");
const DocumentStoreBase_1 = require("./DocumentStoreBase");
const MaintenanceOperationExecutor_1 = require("./Operations/MaintenanceOperationExecutor");
const OperationExecutor_1 = require("./Operations/OperationExecutor");
const DocumentSession_1 = require("./Session/DocumentSession");
const BulkInsertOperation_1 = require("./BulkInsertOperation");
const DatabaseChanges_1 = require("./Changes/DatabaseChanges");
const DatabaseSmuggler_1 = require("./Smuggler/DatabaseSmuggler");
const MultiDatabaseHiLoIdGenerator_1 = require("./Identity/MultiDatabaseHiLoIdGenerator");
const TypeUtil_1 = require("../Utility/TypeUtil");
const log = (0, LogUtil_1.getLogger)({ module: "DocumentStore" });
class DocumentStore extends DocumentStoreBase_1.DocumentStoreBase {
constructor(urls, database, authOptions) {
super();
this._log = (0, LogUtil_1.getLogger)({ module: "DocumentStore-" + Math.floor(Math.random() * 1000) });
this._databaseChanges = new Map();
this._requestExecutors = new Map();
this._database = database;
this.authOptions = authOptions;
this.urls = Array.isArray(urls)
? urls
: [urls];
}
_getDatabaseChangesCacheKey(options) {
return options.databaseName.toLowerCase() + "/" + (options.nodeTag || "<null>");
}
get identifier() {
if (this._identifier) {
return this._identifier;
}
if (!this._urls) {
return null;
}
const urlsString = this._urls.join(", ");
if (this._database) {
return `${urlsString} DB: ${this._database}`;
}
return urlsString;
}
set identifier(identifier) {
this._identifier = identifier;
}
get hiLoIdGenerator() {
return this._multiDbHiLo;
}
dispose() {
this._log.info("Dispose.");
this.emit("beforeDispose");
this._databaseChanges.forEach(change => change.dispose());
const disposeChain = BluebirdPromise.resolve();
disposeChain
.then(() => {
if (this._multiDbHiLo) {
return Promise.resolve()
.then(() => this._multiDbHiLo.returnUnusedRange())
.catch(err => this._log.warn("Error returning unused ID range.", err));
}
})
.then(() => {
this._disposed = true;
this.subscriptions.dispose();
return new BluebirdPromise((resolve, reject) => {
let listenersExecCallbacksCount = 0;
const listenersCount = this.listenerCount("afterDispose");
if (listenersCount === 0) {
resolve();
}
else {
this.emit("afterDispose", () => {
if (listenersCount === ++listenersExecCallbacksCount) {
resolve();
}
});
}
})
.timeout(5000)
.catch((err) => this._log.warn(`Error handling 'afterDispose'`, err));
})
.then(() => {
this._log.info(`Disposing request executors ${this._requestExecutors.size}`);
this._requestExecutors.forEach((executor, db) => {
try {
executor.dispose();
}
catch (err) {
this._log.warn(err, `Error disposing request executor.`);
}
});
})
.finally(() => this.emit("executorsDisposed"));
}
openSession(databaseOrSessionOptions) {
if (!databaseOrSessionOptions) {
const sessionOptions = {
disableAtomicDocumentWritesInClusterWideTransaction: this.conventions.disableAtomicDocumentWritesInClusterWideTransaction
};
return this.openSession(sessionOptions);
}
this.assertInitialized();
this._ensureNotDisposed();
if (typeof (databaseOrSessionOptions) === "string") {
return this.openSession({
database: databaseOrSessionOptions,
disableAtomicDocumentWritesInClusterWideTransaction: this.conventions.disableAtomicDocumentWritesInClusterWideTransaction
});
}
databaseOrSessionOptions = databaseOrSessionOptions || {};
const sessionOpts = databaseOrSessionOptions;
const sessionId = (0, uuid_1.v4)();
const session = new DocumentSession_1.DocumentSession(this, sessionId, sessionOpts);
this.registerEvents(session);
this.emit("sessionCreated", { session });
return session;
}
getRequestExecutor(database) {
this.assertInitialized();
database = this.getEffectiveDatabase(database);
const databaseLower = database.toLowerCase();
let executor = this._requestExecutors.get(databaseLower);
if (executor) {
return executor;
}
const createRequestExecutor = () => {
const requestExecutor = RequestExecutor_1.RequestExecutor.create(this.urls, database, {
authOptions: this.authOptions,
documentConventions: this.conventions
});
this.registerEvents(requestExecutor);
return requestExecutor;
};
const createRequestExecutorForSingleNode = () => {
const forSingleNode = RequestExecutor_1.RequestExecutor.createForSingleNodeWithConfigurationUpdates(this.urls[0], database, {
authOptions: this.authOptions,
documentConventions: this.conventions
});
this.registerEvents(forSingleNode);
return forSingleNode;
};
if (!this.conventions.disableTopologyUpdates) {
executor = createRequestExecutor();
}
else {
executor = createRequestExecutorForSingleNode();
}
this._log.info(`New request executor for database ${database}`);
this._requestExecutors.set(databaseLower, executor);
return executor;
}
requestTimeout(timeoutInMs, database) {
this.assertInitialized();
database = this.getEffectiveDatabase(database);
if (!database) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Cannot use requestTimeout without a default database defined " +
"unless 'database' parameter is provided. Did you forget to pass 'database' parameter?");
}
const requestExecutor = this.getRequestExecutor(database);
const oldTimeout = requestExecutor.defaultTimeout;
requestExecutor.defaultTimeout = timeoutInMs;
return {
dispose: () => requestExecutor.defaultTimeout = oldTimeout
};
}
initialize() {
if (this._initialized) {
return this;
}
this._assertValidConfiguration();
RequestExecutor_1.RequestExecutor.validateUrls(this.urls, this.authOptions);
try {
if (!this.conventions.documentIdGenerator) {
const generator = new MultiDatabaseHiLoIdGenerator_1.MultiDatabaseHiLoIdGenerator(this);
this._multiDbHiLo = generator;
this.conventions.documentIdGenerator =
(dbName, entity) => generator.generateDocumentId(dbName, entity);
}
this.conventions.freeze();
this._initialized = true;
}
catch (e) {
this.dispose();
throw e;
}
return this;
}
_assertValidConfiguration() {
if (!this._urls || !this._urls.length) {
(0, Exceptions_1.throwError)("InvalidArgumentException", "Document store URLs cannot be empty");
}
super._assertValidConfiguration();
}
changes(database, nodeTag) {
this.assertInitialized();
const changesOptions = {
databaseName: database || this.database,
nodeTag
};
const cacheKey = this._getDatabaseChangesCacheKey(changesOptions);
if (this._databaseChanges.has(cacheKey)) {
return this._databaseChanges.get(cacheKey);
}
const newChanges = this._createDatabaseChanges(changesOptions);
this._databaseChanges.set(cacheKey, newChanges);
return newChanges;
}
_createDatabaseChanges(node) {
return new DatabaseChanges_1.DatabaseChanges(this.getRequestExecutor(node.databaseName), node.databaseName, () => this._databaseChanges.delete(this._getDatabaseChangesCacheKey(node)), node.nodeTag);
}
getLastDatabaseChangesStateException(database, nodeTag) {
const node = {
databaseName: database || this.database,
nodeTag
};
const cacheKey = this._getDatabaseChangesCacheKey(node);
const databaseChanges = this._databaseChanges.get(cacheKey);
if (databaseChanges) {
return databaseChanges.lastConnectionStateException;
}
return null;
}
get maintenance() {
this.assertInitialized();
if (!this._maintenanceOperationExecutor) {
this._maintenanceOperationExecutor = new MaintenanceOperationExecutor_1.MaintenanceOperationExecutor(this);
}
return this._maintenanceOperationExecutor;
}
get smuggler() {
if (!this._smuggler) {
this._smuggler = new DatabaseSmuggler_1.DatabaseSmuggler(this);
}
return this._smuggler;
}
get operations() {
if (!this._operationExecutor) {
this._operationExecutor = new OperationExecutor_1.OperationExecutor(this);
}
return this._operationExecutor;
}
bulkInsert(databaseOrOptions, optionalOptions) {
this.assertInitialized();
const database = TypeUtil_1.TypeUtil.isString(databaseOrOptions) ? this.getEffectiveDatabase(databaseOrOptions) : this.getEffectiveDatabase(null);
const options = TypeUtil_1.TypeUtil.isString(databaseOrOptions) ? optionalOptions : databaseOrOptions;
return new BulkInsertOperation_1.BulkInsertOperation(database, this, options);
}
}
exports.DocumentStore = DocumentStore;
//# sourceMappingURL=DocumentStore.js.map