ravendb
Version:
RavenDB client for Node.js
269 lines • 13.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DocumentSubscriptions = void 0;
const TypeUtil_js_1 = require("../../Utility/TypeUtil.js");
const index_js_1 = require("../../Exceptions/index.js");
const CreateSubscriptionCommand_js_1 = require("../Commands/CreateSubscriptionCommand.js");
const SubscriptionWorker_js_1 = require("./SubscriptionWorker.js");
const DeleteSubscriptionCommand_js_1 = require("../Commands/DeleteSubscriptionCommand.js");
const StringUtil_js_1 = require("../../Utility/StringUtil.js");
const GetSubscriptionStateCommand_js_1 = require("../Commands/GetSubscriptionStateCommand.js");
const DropSubscriptionConnectionCommand_js_1 = require("../Commands/DropSubscriptionConnectionCommand.js");
const GetSubscriptionsCommand_js_1 = require("../Commands/GetSubscriptionsCommand.js");
const ToggleOngoingTaskStateOperation_js_1 = require("../Operations/OngoingTasks/ToggleOngoingTaskStateOperation.js");
const SubscriptionIncludeBuilder_js_1 = require("../Session/Loaders/SubscriptionIncludeBuilder.js");
const IncludesUtil_js_1 = require("../Session/IncludesUtil.js");
const StringBuilder_js_1 = require("../../Utility/StringBuilder.js");
const UpdateSubscriptionCommand_js_1 = require("../Commands/UpdateSubscriptionCommand.js");
const CounterIncludesToken_js_1 = require("../Session/Tokens/CounterIncludesToken.js");
const TimeSeriesIncludesToken_js_1 = require("../Session/Tokens/TimeSeriesIncludesToken.js");
const QueryToken_js_1 = require("../Session/Tokens/QueryToken.js");
const OsUtil_js_1 = require("../../Utility/OsUtil.js");
const INCLUDE_REVISIONS_RQL = " (Revisions = true)";
class DocumentSubscriptions {
_store;
_subscriptions = new Map();
constructor(store) {
this._store = store;
}
/**
* Creates a data subscription in a database. The subscription will expose all
* documents that match the specified subscription options for a given type.
*/
async create(optionsOrDocumentType, database) {
let options = null;
if (TypeUtil_js_1.TypeUtil.isDocumentType(optionsOrDocumentType)) {
options = {
documentType: optionsOrDocumentType
};
return this.create(this._ensureCriteria(options, false), database);
}
else {
options = this._ensureCriteria(optionsOrDocumentType, false);
}
if (!options) {
(0, index_js_1.throwError)("InvalidArgumentException", "Cannot create a subscription if options are null");
}
if (!options.query) {
(0, index_js_1.throwError)("InvalidArgumentException", "Cannot create a subscription if the script is null");
}
const requestExecutor = this._store.getRequestExecutor(this._store.getEffectiveDatabase(database));
const command = new CreateSubscriptionCommand_js_1.CreateSubscriptionCommand(options);
await requestExecutor.execute(command);
return command.result.name;
}
/**
* Creates a data subscription in a database. The subscription will expose all documents
* that match the specified subscription options for a given type.
*/
createForRevisions(options, database) {
options = options || {};
return this.create(this._ensureCriteria(options, true), database);
}
_ensureCriteria(criteria, revisions) {
if (!criteria) {
criteria = {};
}
const objectDescriptor = this._store.conventions.getJsTypeByDocumentType(criteria.documentType);
const collectionName = this._store.conventions.getCollectionNameForType(objectDescriptor);
let queryBuilder;
if (criteria.query) {
queryBuilder = new StringBuilder_js_1.StringBuilder(criteria.query);
}
else {
queryBuilder = new StringBuilder_js_1.StringBuilder("from '");
StringUtil_js_1.StringUtil.escapeString(queryBuilder, collectionName);
queryBuilder.append("'");
if (revisions) {
queryBuilder.append(INCLUDE_REVISIONS_RQL);
}
queryBuilder.append(" as doc");
}
if (criteria.includes) {
const builder = new SubscriptionIncludeBuilder_js_1.SubscriptionIncludeBuilder(this._store.conventions);
criteria.includes(builder);
let numberOfIncludesAdded = 0;
if (builder.documentsToInclude && builder.documentsToInclude.size) {
queryBuilder.append(OsUtil_js_1.EOL + "include ");
for (const inc of builder.documentsToInclude) {
const include = "doc." + inc;
if (numberOfIncludesAdded > 0) {
queryBuilder.append(",");
}
let escapedInclude;
if (IncludesUtil_js_1.IncludesUtil.requiresQuotes(include, x => escapedInclude = x)) {
queryBuilder
.append("'")
.append(escapedInclude)
.append("'");
}
else {
queryBuilder
.append(QueryToken_js_1.QueryToken.isKeyword(include) ? "'" + include + "'" : include);
}
numberOfIncludesAdded++;
}
}
if (builder.isAllCounters) {
if (!numberOfIncludesAdded) {
queryBuilder
.append(OsUtil_js_1.EOL)
.append("include ");
}
const token = CounterIncludesToken_js_1.CounterIncludesToken.all("");
token.writeTo(queryBuilder);
numberOfIncludesAdded++;
}
else if (builder.countersToInclude && builder.countersToInclude.size) {
if (!numberOfIncludesAdded) {
queryBuilder
.append(OsUtil_js_1.EOL)
.append("include ");
}
for (const counterName of builder.countersToInclude) {
if (numberOfIncludesAdded > 0) {
queryBuilder.append(",");
}
const token = CounterIncludesToken_js_1.CounterIncludesToken.create("", counterName);
token.writeTo(queryBuilder);
numberOfIncludesAdded++;
}
}
if (builder.timeSeriesToInclude) {
for (const timeSeriesRange of builder.timeSeriesToInclude) {
if (numberOfIncludesAdded === 0) {
queryBuilder
.append(OsUtil_js_1.EOL)
.append("include ");
}
if (numberOfIncludesAdded > 0) {
queryBuilder.append(",");
}
const token = TimeSeriesIncludesToken_js_1.TimeSeriesIncludesToken.create("", timeSeriesRange);
token.writeTo(queryBuilder);
numberOfIncludesAdded++;
}
}
}
criteria.query = queryBuilder.toString();
return criteria;
}
/**
* It opens a subscription and starts pulling documents since a last processed document for that subscription.
* The connection options determine client and server cooperation rules like document batch sizes
* or a timeout in a matter of which a client needs to acknowledge that batch has been processed.
* The acknowledgment is sent after all documents are processed by subscription's handlers.
*
* There can be only a single client that is connected to a subscription.
*/
getSubscriptionWorker(optionsOrSubscriptionName, database) {
if (TypeUtil_js_1.TypeUtil.isString(optionsOrSubscriptionName)) {
return this.getSubscriptionWorker({
subscriptionName: optionsOrSubscriptionName
}, database);
}
const options = optionsOrSubscriptionName;
this._store.assertInitialized();
if (!options) {
(0, index_js_1.throwError)("InvalidArgumentException", "Cannot open a subscription if options are null");
}
const subscription = new SubscriptionWorker_js_1.SubscriptionWorker(options, false, this._store, database);
subscription.on("end", () => this._subscriptions.delete(subscription));
this._subscriptions.set(subscription, true);
return subscription;
}
/**
* It opens a subscription and starts pulling documents since a last processed document for that subscription.
* The connection options determine client and server cooperation rules like document batch sizes
* or a timeout in a matter of which a client needs to acknowledge that batch has been processed.
* The acknowledgment is sent after all documents are processed by subscription's handlers.
*
* There can be only a single client that is connected to a subscription.
*/
getSubscriptionWorkerForRevisions(optionsOrSubscriptionName, database) {
if (TypeUtil_js_1.TypeUtil.isString(optionsOrSubscriptionName)) {
return this.getSubscriptionWorkerForRevisions({
subscriptionName: optionsOrSubscriptionName,
}, database);
}
const options = optionsOrSubscriptionName;
const subscription = new SubscriptionWorker_js_1.SubscriptionWorker(options, true, this._store, database);
subscription.on("end", () => this._subscriptions.delete(subscription));
this._subscriptions.set(subscription, true);
return subscription;
}
/**
* It downloads a list of all existing subscriptions in a database.
*/
async getSubscriptions(start, take, database) {
const requestExecutor = this._store.getRequestExecutor(this._store.getEffectiveDatabase(database));
const command = new GetSubscriptionsCommand_js_1.GetSubscriptionsCommand(start, take);
await requestExecutor.execute(command);
return command.result;
}
/**
* Delete a subscription.
*/
async delete(name, database) {
const requestExecutor = this._store.getRequestExecutor(this._store.getEffectiveDatabase(database));
const command = new DeleteSubscriptionCommand_js_1.DeleteSubscriptionCommand(name);
return requestExecutor.execute(command);
}
/**
* Returns subscription definition and it's current state
*/
async getSubscriptionState(subscriptionName, database) {
if (StringUtil_js_1.StringUtil.isNullOrEmpty(subscriptionName)) {
(0, index_js_1.throwError)("InvalidArgumentException", "SubscriptionName cannot be null");
}
const requestExecutor = this._store.getRequestExecutor(this._store.getEffectiveDatabase(database));
const command = new GetSubscriptionStateCommand_js_1.GetSubscriptionStateCommand(subscriptionName);
await requestExecutor.execute(command);
return command.result;
}
dispose() {
if (!this._subscriptions.size) {
return;
}
for (const [key, value] of this._subscriptions.entries())
key.dispose();
}
async dropSubscriptionWorker(worker, database = null) {
database ??= this._store.database;
const requestExecutor = this._store.getRequestExecutor(database);
const command = new DropSubscriptionConnectionCommand_js_1.DropSubscriptionConnectionCommand(worker.subscriptionName, worker.getWorkerId());
await requestExecutor.execute(command);
}
/**
* Force server to close all current client subscription connections to the server
*/
async dropConnection(name, database) {
const requestExecutor = this._store.getRequestExecutor(this._store.getEffectiveDatabase(database));
const command = new DropSubscriptionConnectionCommand_js_1.DropSubscriptionConnectionCommand(name);
return requestExecutor.execute(command);
}
async enable(name, database) {
const operation = new ToggleOngoingTaskStateOperation_js_1.ToggleOngoingTaskStateOperation(name, "Subscription", false);
await this._store.maintenance.forDatabase(this._store.getEffectiveDatabase(database))
.send(operation);
}
async disable(name, database) {
const operation = new ToggleOngoingTaskStateOperation_js_1.ToggleOngoingTaskStateOperation(name, "Subscription", true);
await this._store.maintenance.forDatabase(this._store.getEffectiveDatabase(database))
.send(operation);
}
async update(options, database) {
if (!options) {
(0, index_js_1.throwError)("InvalidArgumentException", "Cannot update a subscription if options is null");
}
if (StringUtil_js_1.StringUtil.isNullOrEmpty(options.name) && !options.id) {
(0, index_js_1.throwError)("InvalidArgumentException", "Cannot update a subscription if both options.name and options.if are null");
}
const requestExecutor = this._store.getRequestExecutor(database);
const command = new UpdateSubscriptionCommand_js_1.UpdateSubscriptionCommand(options);
await requestExecutor.execute(command, null);
return command.result.name;
}
}
exports.DocumentSubscriptions = DocumentSubscriptions;
//# sourceMappingURL=DocumentSubscriptions.js.map