@configurator/ravendb
Version:
RavenDB client for Node.js
1,087 lines • 72.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeletedEntitiesHolder = exports.DocumentsByEntityHolder = exports.InMemoryDocumentSessionOperations = void 0;
const EntityToJson_1 = require("./EntityToJson");
const IDocumentSession_1 = require("./IDocumentSession");
const SessionEvents_1 = require("./SessionEvents");
const Exceptions_1 = require("../../Exceptions");
const DocumentsById_1 = require("./DocumentsById");
const DocumentInfo_1 = require("./DocumentInfo");
const CommandData_1 = require("../Commands/CommandData");
const GenerateEntityIdOnTheClient_1 = require("../Identity/GenerateEntityIdOnTheClient");
const Json_1 = require("../../Mapping/Json");
const Constants_1 = require("../../Constants");
const DateUtil_1 = require("../../Utility/DateUtil");
const ObjectUtil_1 = require("../../Utility/ObjectUtil");
const IncludesUtil_1 = require("./IncludesUtil");
const TypeUtil_1 = require("../../Utility/TypeUtil");
const IdTypeAndName_1 = require("../IdTypeAndName");
const DocumentsChanges_1 = require("./DocumentsChanges");
const events_1 = require("events");
const JsonOperation_1 = require("../../Mapping/JsonOperation");
const Serializer_1 = require("../../Mapping/Json/Serializer");
const MetadataAsDictionary_1 = require("../../Mapping/MetadataAsDictionary");
const CaseInsensitiveKeysMap_1 = require("../../Primitives/CaseInsensitiveKeysMap");
const CaseInsensitiveStringSet_1 = require("../../Primitives/CaseInsensitiveStringSet");
const SessionOperationExecutor_1 = require("../Operations/SessionOperationExecutor");
const StringUtil_1 = require("../../Utility/StringUtil");
const ForceRevisionCommandData_1 = require("../Commands/Batches/ForceRevisionCommandData");
const TimeSeriesRangeResult_1 = require("../Operations/TimeSeries/TimeSeriesRangeResult");
const DatesComparator_1 = require("../../Primitives/DatesComparator");
const GetTimeSeriesOperation_1 = require("../Operations/TimeSeries/GetTimeSeriesOperation");
class InMemoryDocumentSessionOperations extends events_1.EventEmitter {
get id() {
return this._id;
}
get externalState() {
if (!this._externalState) {
this._externalState = new Map();
}
return this._externalState;
}
getCurrentSessionNode() {
return this.sessionInfo.getCurrentSessionNode(this._requestExecutor);
}
get countersByDocId() {
if (!this._countersByDocId) {
this._countersByDocId = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
}
return this._countersByDocId;
}
get timeSeriesByDocId() {
if (!this._timeSeriesByDocId) {
this._timeSeriesByDocId = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
}
return this._timeSeriesByDocId;
}
get databaseName() {
return this._databaseName;
}
get documentStore() {
return this._documentStore;
}
get requestExecutor() {
return this._requestExecutor;
}
get sessionInfo() {
return this._sessionInfo;
}
get operations() {
if (!this._operationExecutor) {
this._operationExecutor = new SessionOperationExecutor_1.SessionOperationExecutor(this);
}
return this._operationExecutor;
}
get numberOfRequests() {
return this._numberOfRequests;
}
getNumberOfEntitiesInUnitOfWork() {
return this.documentsByEntity.size;
}
get storeIdentifier() {
return `${this._documentStore.identifier};${this._databaseName}`;
}
get conventions() {
return this._requestExecutor.conventions;
}
get deferredCommands() {
return this._deferredCommands;
}
get deferredCommandsCount() {
return this._deferredCommands.length;
}
get generateEntityIdOnTheClient() {
return this._generateEntityIdOnTheClient;
}
get entityToJson() {
return this._entityToJson;
}
constructor(documentStore, id, options) {
super();
this._pendingLazyOperations = [];
this._hash = ++InMemoryDocumentSessionOperations._instancesCounter;
this._jsonSerializer = Serializer_1.JsonSerializer.getDefaultForCommandPayload();
this._knownMissingIds = CaseInsensitiveStringSet_1.CaseInsensitiveStringSet.create();
this.documentsById = new DocumentsById_1.DocumentsById();
this.idsForCreatingForcedRevisions = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
this.includedDocumentsById = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
this.includeRevisionsByChangeVector = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
this.includeRevisionsIdByDateTimeBefore = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
this.documentsByEntity = new DocumentsByEntityHolder();
this.deletedEntities = new DeletedEntitiesHolder();
this._numberOfRequests = 0;
this._deferredCommands = [];
this.deferredCommandsMap = new Map();
this._generateDocumentKeysOnStore = true;
this._id = id;
this._databaseName = options.database || documentStore.database;
if (StringUtil_1.StringUtil.isNullOrWhitespace(this._databaseName)) {
InMemoryDocumentSessionOperations._throwNoDatabase();
}
this._documentStore = documentStore;
this._requestExecutor =
options.requestExecutor || documentStore.getRequestExecutor(this._databaseName);
this.noTracking = options.noTracking;
this.useOptimisticConcurrency = this._requestExecutor.conventions.isUseOptimisticConcurrency();
this.maxNumberOfRequestsPerSession = this._requestExecutor.conventions.maxNumberOfRequestsPerSession;
this._generateEntityIdOnTheClient =
new GenerateEntityIdOnTheClient_1.GenerateEntityIdOnTheClient(this._requestExecutor.conventions, (obj) => this._generateId(obj));
this._entityToJson = new EntityToJson_1.EntityToJson(this);
this._sessionInfo = new IDocumentSession_1.SessionInfo(this, options, documentStore);
this._transactionMode = options.transactionMode;
this.disableAtomicDocumentWritesInClusterWideTransaction = options.disableAtomicDocumentWritesInClusterWideTransaction;
}
getMetadataFor(instance) {
if (!instance) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Instance cannot be null or undefined.");
}
const documentInfo = this._getDocumentInfo(instance);
return this._makeMetadataInstance(documentInfo);
}
getCountersFor(instance) {
if (!instance) {
(0, Exceptions_1.throwError)("InvalidArgumentException", "Instance cannot be null.");
}
const documentInfo = this._getDocumentInfo(instance);
const countersArray = documentInfo.metadata[Constants_1.CONSTANTS.Documents.Metadata.COUNTERS];
if (!countersArray) {
return null;
}
return countersArray;
}
getTimeSeriesFor(instance) {
if (!instance) {
(0, Exceptions_1.throwError)("InvalidArgumentException", "Instance cannot be null");
}
const documentInfo = this._getDocumentInfo(instance);
return documentInfo.metadata[Constants_1.CONSTANTS.Documents.Metadata.TIME_SERIES] || [];
}
_makeMetadataInstance(docInfo) {
const metadataInstance = docInfo.metadataInstance;
if (metadataInstance) {
return metadataInstance;
}
const metadataAsJson = docInfo.metadata;
const metadata = (0, MetadataAsDictionary_1.createMetadataDictionary)({ raw: metadataAsJson });
docInfo.entity[Constants_1.CONSTANTS.Documents.Metadata.KEY] = docInfo.metadataInstance = metadata;
return metadata;
}
_getDocumentInfo(instance) {
const documentInfo = this.documentsByEntity.get(instance);
if (documentInfo) {
return documentInfo;
}
let idRef;
if (!this._generateEntityIdOnTheClient.tryGetIdFromInstance(instance, (_idRef) => idRef = _idRef)) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Could not find the document id for " + instance);
}
this._assertNoNonUniqueInstance(instance, idRef);
(0, Exceptions_1.throwError)("InvalidArgumentException", "Document " + idRef + " doesn't exist in the session");
}
_assertNoNonUniqueInstance(entity, id) {
if (!id
|| id[id.length - 1] === "|"
|| id[id.length - 1] === this.conventions.identityPartsSeparator) {
return;
}
const info = this.documentsById.getValue(id);
if (!info || info.entity === entity) {
return;
}
(0, Exceptions_1.throwError)("NonUniqueObjectException", "Attempted to associate a different object with id '" + id + "'.");
}
getChangeVectorFor(instance) {
if (!instance) {
(0, Exceptions_1.throwError)("InvalidArgumentException", "Instance cannot be null or undefined.");
}
const documentInfo = this._getDocumentInfo(instance);
const changeVector = documentInfo.metadata[Constants_1.CONSTANTS.Documents.Metadata.CHANGE_VECTOR];
if (changeVector) {
return changeVector.toString();
}
return null;
}
getLastModifiedFor(instance) {
if (!instance) {
(0, Exceptions_1.throwError)("InvalidArgumentException", "Instance cannot be null or undefined.");
}
const documentInfo = this._getDocumentInfo(instance);
const lastModified = documentInfo.metadata["@last-modified"];
return DateUtil_1.DateUtil.default.parse(lastModified);
}
isLoaded(id) {
return this.isLoadedOrDeleted(id);
}
isLoadedOrDeleted(id) {
const documentInfo = this.documentsById.getValue(id);
return !!(documentInfo && (documentInfo.document || documentInfo.entity))
|| this.isDeleted(id)
|| this.includedDocumentsById.has(id);
}
isDeleted(id) {
return this._knownMissingIds.has(id);
}
getDocumentId(instance) {
if (!instance) {
return null;
}
const value = this.documentsByEntity.get(instance);
return value ? value.id : null;
}
incrementRequestCount() {
if (++this._numberOfRequests > this.maxNumberOfRequestsPerSession) {
(0, Exceptions_1.throwError)("InvalidOperationException", `The maximum number of requests (${this.maxNumberOfRequestsPerSession}) allowed for this session has been reached.` +
"Raven limits the number of remote calls that a session is allowed to make as an early warning system. Sessions are expected to be short lived, and " +
"Raven provides facilities like load(string[] keys) to load multiple documents at once and batch saves (call SaveChanges() only once)." +
"You can increase the limit by setting DocumentConvention.MaxNumberOfRequestsPerSession or MaxNumberOfRequestsPerSession, but it is" +
"advisable that you'll look into reducing the number of remote calls first, since that will speed up your application significantly and result in a" +
"more responsive application.");
}
}
checkIfAllChangeVectorsAreAlreadyIncluded(changeVectors) {
if (!this.includeRevisionsByChangeVector) {
return false;
}
for (const cv of changeVectors) {
if (!this.includeRevisionsByChangeVector.has(cv)) {
return false;
}
}
return true;
}
checkIfRevisionByDateTimeBeforeAlreadyIncluded(id, dateTime) {
if (!this.includeRevisionsIdByDateTimeBefore) {
return false;
}
const dictionaryDateTimeToDocument = this.includeRevisionsIdByDateTimeBefore.get(id);
return dictionaryDateTimeToDocument && dictionaryDateTimeToDocument.has(dateTime.getTime());
}
checkIfIdAlreadyIncluded(ids, includes) {
for (const id of ids) {
if (this._knownMissingIds.has(id)) {
continue;
}
let documentInfo = this.documentsById.getValue(id);
if (!documentInfo) {
documentInfo = this.includedDocumentsById.get(id);
if (!documentInfo) {
return false;
}
}
if (!documentInfo.entity && !documentInfo.document) {
return false;
}
if (!includes) {
continue;
}
for (const include of includes) {
let hasAll = true;
IncludesUtil_1.IncludesUtil.include(documentInfo.document, include, (includeId) => {
hasAll = hasAll && this.isLoaded(includeId);
});
if (!hasAll) {
return false;
}
}
}
return true;
}
trackEntity(entityType, idOrDocumentInfo, document, metadata, noTracking) {
let id;
if (TypeUtil_1.TypeUtil.isObject(idOrDocumentInfo)) {
const info = idOrDocumentInfo;
return this.trackEntity(entityType, info.id, info.document, info.metadata, this.noTracking);
}
else {
id = idOrDocumentInfo;
}
noTracking = this.noTracking || noTracking;
if (!id) {
return this._deserializeFromTransformer(entityType, null, document, false);
}
let docInfo = this.documentsById.getValue(id);
if (docInfo) {
if (!docInfo.entity) {
docInfo.entity = this.entityToJson.convertToEntity(entityType, id, document, !noTracking);
this._makeMetadataInstance(docInfo);
}
if (!noTracking) {
this.includedDocumentsById.delete(id);
this.documentsByEntity.put(docInfo.entity, docInfo);
}
this.onAfterConversionToEntityInvoke(id, docInfo.document, docInfo.entity);
return docInfo.entity;
}
docInfo = this.includedDocumentsById.get(id);
if (docInfo) {
if (!docInfo.entity) {
docInfo.entity = this.entityToJson.convertToEntity(entityType, id, document, !noTracking);
this._makeMetadataInstance(docInfo);
}
if (!noTracking) {
this.includedDocumentsById.delete(id);
this.documentsById.add(docInfo);
this.documentsByEntity.put(docInfo.entity, docInfo);
}
this.onAfterConversionToEntityInvoke(id, docInfo.document, docInfo.entity);
return docInfo.entity;
}
const entity = this.entityToJson.convertToEntity(entityType, id, document, !noTracking);
const changeVector = metadata[Constants_1.CONSTANTS.Documents.Metadata.CHANGE_VECTOR];
if (!changeVector) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Document " + id + " must have Change Vector.");
}
if (!noTracking) {
const newDocumentInfo = new DocumentInfo_1.DocumentInfo();
newDocumentInfo.id = id;
newDocumentInfo.document = document;
newDocumentInfo.metadata = metadata;
newDocumentInfo.entity = entity;
newDocumentInfo.changeVector = changeVector;
this.documentsById.add(newDocumentInfo);
this.documentsByEntity.put(entity, newDocumentInfo);
this._makeMetadataInstance(newDocumentInfo);
}
this.onAfterConversionToEntityInvoke(id, document, entity);
return entity;
}
registerExternalLoadedIntoTheSession(info) {
if (this.noTracking) {
return;
}
const existing = this.documentsById.getValue(info.id);
if (existing) {
if (existing.entity === info.entity) {
return;
}
(0, Exceptions_1.throwError)("InvalidOperationException", "The document " + info.id + " is already in the session with a different entity instance.");
}
const existingEntity = this.documentsByEntity.get(info.entity);
if (existingEntity) {
if (StringUtil_1.StringUtil.equalsIgnoreCase(existingEntity.id, info.id)) {
return;
}
(0, Exceptions_1.throwError)("InvalidOperationException", "Attempted to load an entity with id "
+ info.id
+ ", but the entity instance already exists in the session with id: " + existing.id);
}
this.documentsByEntity.put(info.entity, info);
this.documentsById.add(info);
this.includedDocumentsById.delete(info.id);
}
_deserializeFromTransformer(clazz, id, document, trackEntity) {
const entity = this.entityToJson.convertToEntity(clazz, id, document, trackEntity);
this.onAfterConversionToEntityInvoke(id, document, entity);
return entity;
}
registerIncludes(includes) {
if (this.noTracking) {
return;
}
if (!includes) {
return;
}
for (const fieldName of Object.keys(includes)) {
const fieldValue = includes[fieldName];
if (TypeUtil_1.TypeUtil.isNullOrUndefined(fieldValue)) {
continue;
}
const newDocumentInfo = DocumentInfo_1.DocumentInfo.getNewDocumentInfo(fieldValue);
if ((0, Json_1.tryGetConflict)(newDocumentInfo.metadata)) {
continue;
}
this.includedDocumentsById.set(newDocumentInfo.id, newDocumentInfo);
}
}
registerRevisionIncludes(revisionIncludes) {
if (this.noTracking) {
return;
}
if (!revisionIncludes) {
return;
}
if (!this.includeRevisionsByChangeVector) {
this.includeRevisionsByChangeVector = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
}
if (!this.includeRevisionsIdByDateTimeBefore) {
this.includeRevisionsIdByDateTimeBefore = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
}
for (const obj of revisionIncludes) {
if (!obj) {
continue;
}
const json = obj;
const id = json.Id;
const changeVector = json.ChangeVector;
const beforeAsText = json.Before;
const dateTime = beforeAsText ? DateUtil_1.DateUtil.utc.parse(beforeAsText) : null;
const revision = json.Revision;
this.includeRevisionsByChangeVector.set(changeVector, DocumentInfo_1.DocumentInfo.getNewDocumentInfo(revision));
if (dateTime && !StringUtil_1.StringUtil.isNullOrWhitespace(id)) {
const map = new Map();
this.includeRevisionsIdByDateTimeBefore.set(id, map);
const documentInfo = new DocumentInfo_1.DocumentInfo();
documentInfo.document = revision;
map.set(dateTime.getTime(), documentInfo);
}
}
}
registerMissingIncludes(results, includes, includePaths) {
if (this.noTracking) {
return;
}
if (!includePaths || !includePaths.length) {
return;
}
for (const result of results) {
for (const include of includePaths) {
if (include === Constants_1.CONSTANTS.Documents.Indexing.Fields.DOCUMENT_ID_FIELD_NAME) {
continue;
}
IncludesUtil_1.IncludesUtil.include(result, include, id => {
if (!id) {
return;
}
if (this.isLoaded(id)) {
return;
}
const document = includes[id];
if (document) {
const metadata = document.get(Constants_1.CONSTANTS.Documents.Metadata.KEY);
if ((0, Json_1.tryGetConflict)(metadata)) {
return;
}
}
this.registerMissing(id);
});
}
}
}
registerMissing(idOrIds) {
if (this.noTracking) {
return;
}
if (TypeUtil_1.TypeUtil.isArray(idOrIds)) {
for (const id of idOrIds) {
this._knownMissingIds.add(id);
}
}
else {
this._knownMissingIds.add(idOrIds);
}
}
unregisterMissing(id) {
this._knownMissingIds.delete(id);
}
registerCounters(resultCounters, idsOrCountersToInclude, countersToInclude, gotAll) {
if (Array.isArray(idsOrCountersToInclude)) {
this._registerCountersWithIdsList(resultCounters, idsOrCountersToInclude, countersToInclude, gotAll);
}
else {
this._registerCountersWithCountersToIncludeObj(resultCounters, idsOrCountersToInclude);
}
}
_registerCountersWithIdsList(resultCounters, ids, countersToInclude, gotAll) {
if (this.noTracking) {
return;
}
if (!resultCounters || Object.keys(resultCounters).length === 0) {
if (gotAll) {
for (const id of ids) {
this._setGotAllCountersForDocument(id);
}
return;
}
}
else {
this._registerCountersInternal(resultCounters, null, false, gotAll);
}
this._registerMissingCounters(ids, countersToInclude);
}
_registerCountersWithCountersToIncludeObj(resultCounters, countersToInclude) {
if (this.noTracking) {
return;
}
if (!resultCounters || Object.keys(resultCounters).length === 0) {
this._setGotAllInCacheIfNeeded(countersToInclude);
}
else {
this._registerCountersInternal(resultCounters, countersToInclude, true, false);
}
this._registerMissingCounters(countersToInclude);
}
_registerCountersInternal(resultCounters, countersToInclude, fromQueryResult, gotAll) {
for (const [field, value] of Object.entries(resultCounters)) {
if (!value) {
continue;
}
let counters = [];
if (fromQueryResult) {
counters = countersToInclude[field];
gotAll = counters && counters.length === 0;
}
if (value.length === 0 && !gotAll) {
const cache = this.countersByDocId.get(field);
if (!cache) {
continue;
}
for (const counter of counters) {
cache.data.delete(counter);
}
this._countersByDocId.set(field, cache);
continue;
}
this._registerCountersForDocument(field, gotAll, value, countersToInclude);
}
}
_registerCountersForDocument(id, gotAll, counters, countersToInclude) {
let cache = this.countersByDocId.get(id);
if (!cache) {
cache = { gotAll, data: CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create() };
}
const deletedCounters = cache.data.size === 0
? new Set()
: (countersToInclude[id].length === 0 ? new Set(cache.data.keys()) : new Set(countersToInclude[id]));
for (const counterJson of counters) {
if (!counterJson) {
continue;
}
const counterName = counterJson["counterName"];
const totalValue = counterJson["totalValue"];
if (counterName && totalValue) {
cache.data.set(counterName, totalValue);
deletedCounters.delete(counterName);
}
}
if (deletedCounters.size > 0) {
for (const name of deletedCounters) {
cache.data.delete(name);
}
}
cache.gotAll = gotAll;
this._countersByDocId.set(id, cache);
}
_setGotAllInCacheIfNeeded(countersToInclude) {
for (const [key, value] of Object.entries(countersToInclude)) {
if (value.length > 0) {
continue;
}
this._setGotAllCountersForDocument(key);
}
}
_setGotAllCountersForDocument(id) {
let cache = this.countersByDocId.get(id);
if (!cache) {
cache = { gotAll: false, data: CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create() };
}
cache.gotAll = true;
this._countersByDocId.set(id, cache);
}
_registerMissingCounters(idsOrCountersToInclude, countersToInclude) {
if (Array.isArray(idsOrCountersToInclude)) {
this._registerMissingCountersWithIdsList(idsOrCountersToInclude, countersToInclude);
}
else {
this._registerMissingCountersWithCountersToIncludeObj(idsOrCountersToInclude);
}
}
registerTimeSeries(resultTimeSeries) {
if (this.noTracking || !resultTimeSeries) {
return;
}
for (const [id, perDocTs] of Object.entries(resultTimeSeries)) {
if (!perDocTs) {
continue;
}
let cache = this.timeSeriesByDocId.get(id);
if (!cache) {
cache = CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create();
this.timeSeriesByDocId.set(id, cache);
}
if (!TypeUtil_1.TypeUtil.isObject(perDocTs)) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Unable to read time series range results on document: '" + id + "'.");
}
for (const [name, perNameTs] of Object.entries(perDocTs)) {
if (!perNameTs) {
continue;
}
if (!TypeUtil_1.TypeUtil.isArray(perNameTs)) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Unable to read time series range results on document: '" + id + "', time series: '" + name + "'.");
}
for (const range of perNameTs) {
const newRange = InMemoryDocumentSessionOperations._parseTimeSeriesRangeResult(range, id, name, this.conventions);
InMemoryDocumentSessionOperations._addToCache(cache, newRange, name);
}
}
}
}
static _addToCache(cache, newRange, name) {
const localRanges = cache.get(name);
if (!localRanges || !localRanges.length) {
cache.set(name, [newRange]);
return;
}
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.leftDate)(localRanges[0].from), (0, DatesComparator_1.rightDate)(newRange.to)) > 0
|| DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.rightDate)(localRanges[localRanges.length - 1].to), (0, DatesComparator_1.leftDate)(newRange.from)) < 0) {
const index = DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.leftDate)(localRanges[0].from), (0, DatesComparator_1.rightDate)(newRange.to)) > 0 ? 0 : localRanges.length;
localRanges.splice(index, 0, newRange);
return;
}
let toRangeIndex;
let fromRangeIndex = -1;
let rangeAlreadyInCache = false;
for (toRangeIndex = 0; toRangeIndex < localRanges.length; toRangeIndex++) {
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.leftDate)(localRanges[toRangeIndex].from), (0, DatesComparator_1.leftDate)(newRange.from)) <= 0) {
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.rightDate)(localRanges[toRangeIndex].to), (0, DatesComparator_1.rightDate)(newRange.to)) >= 0) {
rangeAlreadyInCache = true;
break;
}
fromRangeIndex = toRangeIndex;
continue;
}
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.rightDate)(localRanges[toRangeIndex].to), (0, DatesComparator_1.rightDate)(newRange.to)) >= 0) {
break;
}
}
if (rangeAlreadyInCache) {
InMemoryDocumentSessionOperations._updateExistingRange(localRanges[toRangeIndex], newRange);
return;
}
const mergedValues = InMemoryDocumentSessionOperations._mergeRanges(fromRangeIndex, toRangeIndex, localRanges, newRange);
InMemoryDocumentSessionOperations.addToCache(name, newRange.from, newRange.to, fromRangeIndex, toRangeIndex, localRanges, cache, mergedValues);
}
static addToCache(timeseries, from, to, fromRangeIndex, toRangeIndex, ranges, cache, values) {
if (fromRangeIndex === -1) {
if (toRangeIndex === ranges.length) {
const timeSeriesRangeResult = new TimeSeriesRangeResult_1.TimeSeriesRangeResult();
timeSeriesRangeResult.from = from;
timeSeriesRangeResult.to = to;
timeSeriesRangeResult.entries = values;
const result = [];
result.push(timeSeriesRangeResult);
cache.set(timeseries, result);
return;
}
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.leftDate)(ranges[toRangeIndex].from), (0, DatesComparator_1.rightDate)(to)) > 0) {
ranges.splice(0, toRangeIndex);
const timeSeriesRangeResult = new TimeSeriesRangeResult_1.TimeSeriesRangeResult();
timeSeriesRangeResult.from = from;
timeSeriesRangeResult.to = to;
timeSeriesRangeResult.entries = values;
ranges.splice(0, 0, timeSeriesRangeResult);
return;
}
ranges[toRangeIndex].from = from;
ranges[toRangeIndex].entries = values;
ranges.splice(0, toRangeIndex);
return;
}
if (toRangeIndex === ranges.length) {
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.rightDate)(ranges[fromRangeIndex].to), (0, DatesComparator_1.leftDate)(from)) < 0) {
ranges.splice(fromRangeIndex + 1, ranges.length - fromRangeIndex - 1);
const timeSeriesRangeResult = new TimeSeriesRangeResult_1.TimeSeriesRangeResult();
timeSeriesRangeResult.from = from;
timeSeriesRangeResult.to = to;
timeSeriesRangeResult.entries = values;
ranges.push(timeSeriesRangeResult);
return;
}
ranges[fromRangeIndex].to = to;
ranges[fromRangeIndex].entries = values;
ranges.splice(fromRangeIndex + 1, ranges.length - fromRangeIndex - 1);
return;
}
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.rightDate)(ranges[fromRangeIndex].to), (0, DatesComparator_1.leftDate)(from)) < 0) {
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.leftDate)(ranges[toRangeIndex].from), (0, DatesComparator_1.rightDate)(to)) > 0) {
ranges.splice(fromRangeIndex + 1, toRangeIndex - fromRangeIndex - 1);
const timeSeriesRangeResult = new TimeSeriesRangeResult_1.TimeSeriesRangeResult();
timeSeriesRangeResult.from = from;
timeSeriesRangeResult.to = to;
timeSeriesRangeResult.entries = values;
ranges.splice(fromRangeIndex + 1, 0, timeSeriesRangeResult);
return;
}
ranges.splice(fromRangeIndex + 1, toRangeIndex - fromRangeIndex - 1);
ranges[toRangeIndex].from = from;
ranges[toRangeIndex].entries = values;
return;
}
if (DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.leftDate)(ranges[toRangeIndex].from), (0, DatesComparator_1.rightDate)(to)) > 0) {
ranges[fromRangeIndex].to = to;
ranges[fromRangeIndex].entries = values;
ranges.splice(fromRangeIndex + 1, toRangeIndex - fromRangeIndex - 1);
return;
}
ranges[fromRangeIndex].to = ranges[toRangeIndex].to;
ranges[fromRangeIndex].entries = values;
ranges.splice(fromRangeIndex + 1, toRangeIndex - fromRangeIndex);
}
static _parseTimeSeriesRangeResult(json, id, databaseName, conventions) {
return (0, GetTimeSeriesOperation_1.reviveTimeSeriesRangeResult)(json, conventions);
}
static _mergeRanges(fromRangeIndex, toRangeIndex, localRanges, newRange) {
const mergedValues = [];
if (fromRangeIndex !== -1 && localRanges[fromRangeIndex].to.getTime() >= newRange.from.getTime()) {
for (const val of localRanges[fromRangeIndex].entries) {
if (val.timestamp.getTime() >= newRange.from.getTime()) {
break;
}
mergedValues.push(val);
}
}
mergedValues.push(...newRange.entries);
if (toRangeIndex < localRanges.length
&& DatesComparator_1.DatesComparator.compare((0, DatesComparator_1.leftDate)(localRanges[toRangeIndex].from), (0, DatesComparator_1.rightDate)(newRange.to)) <= 0) {
for (const val of localRanges[toRangeIndex].entries) {
if (val.timestamp.getTime() <= newRange.to.getTime()) {
continue;
}
mergedValues.push(val);
}
}
return mergedValues;
}
static _updateExistingRange(localRange, newRange) {
const newValues = [];
let index;
for (index = 0; index < localRange.entries.length; index++) {
if (localRange.entries[index].timestamp.getTime() >= newRange.from.getTime()) {
break;
}
newValues.push(localRange.entries[index]);
}
newValues.push(...newRange.entries);
localRange.entries.forEach(item => {
if (item.timestamp.getTime() <= newRange.to.getTime()) {
return;
}
newValues.push(item);
});
localRange.entries = newValues;
}
_registerMissingCountersWithCountersToIncludeObj(countersToInclude) {
if (!countersToInclude) {
return;
}
for (const [key, value] of Object.entries(countersToInclude)) {
let cache = this.countersByDocId.get(key);
if (!cache) {
cache = { gotAll: false, data: CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create() };
this.countersByDocId.set(key, cache);
}
for (const counter of value) {
if (cache.data.has(counter)) {
continue;
}
cache.data.set(counter, null);
}
}
}
_registerMissingCountersWithIdsList(ids, countersToInclude) {
if (!countersToInclude) {
return;
}
for (const counter of countersToInclude) {
for (const id of ids) {
let cache = this.countersByDocId.get(id);
if (!cache) {
cache = { gotAll: false, data: CaseInsensitiveKeysMap_1.CaseInsensitiveKeysMap.create() };
this.countersByDocId.set(id, cache);
}
if (cache.data.has(counter)) {
continue;
}
cache.data.set(counter, null);
}
}
}
store(entity, id, docTypeOrOptions) {
let documentType = null;
let options = {};
if (TypeUtil_1.TypeUtil.isDocumentType(docTypeOrOptions)) {
documentType = docTypeOrOptions;
}
else if (TypeUtil_1.TypeUtil.isObject(docTypeOrOptions)) {
options = docTypeOrOptions;
}
const changeVector = options.changeVector;
documentType = documentType || options.documentType;
this.conventions.tryRegisterJsType(documentType);
if (entity.constructor !== Object) {
this.conventions.tryRegisterJsType(entity.constructor);
}
let forceConcurrencyCheck;
if (!TypeUtil_1.TypeUtil.isUndefined(changeVector)) {
forceConcurrencyCheck = changeVector === null ? "Disabled" : "Forced";
}
else if (!TypeUtil_1.TypeUtil.isNullOrUndefined(id)) {
forceConcurrencyCheck = "Auto";
}
else {
const hasId = this._generateEntityIdOnTheClient.tryGetIdFromInstance(entity);
forceConcurrencyCheck = !hasId ? "Forced" : "Auto";
}
return this._storeInternal(entity, changeVector, id, forceConcurrencyCheck, documentType);
}
async _storeInternal(entity, changeVector, id, forceConcurrencyCheck, documentType) {
if (this.noTracking) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Cannot store entity. Entity tracking is disabled in this session.");
}
if (!entity) {
(0, Exceptions_1.throwError)("InvalidArgumentException", "Entity cannot be null or undefined.");
}
const value = this.documentsByEntity.get(entity);
if (value) {
if (id && !StringUtil_1.StringUtil.equalsIgnoreCase(value.id, id)) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Cannot store the same entity (id: " + value.id + ") with different id (" + id + ")");
}
value.changeVector = changeVector || value.changeVector;
value.concurrencyCheckMode = forceConcurrencyCheck;
return;
}
if (!id) {
if (this._generateDocumentKeysOnStore) {
id = await this._generateEntityIdOnTheClient.generateDocumentKeyForStorage(entity);
}
else {
this._rememberEntityForDocumentIdGeneration(entity);
}
}
else {
this.generateEntityIdOnTheClient.trySetIdentity(entity, id);
}
const cmdKey = IdTypeAndName_1.IdTypeAndName.keyFor(id, "ClientAnyCommand", null);
if (this.deferredCommandsMap.has(cmdKey)) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Can't store document, there is a deferred command registered "
+ "for this document in the session. Document id: " + id);
}
if (this.deletedEntities.contains(entity)) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Can't store object, it was already deleted in this session. Document id: " + id);
}
this._assertNoNonUniqueInstance(entity, id);
const conventions = this._requestExecutor.conventions;
const typeDesc = conventions.getJsTypeByDocumentType(documentType);
const collectionName = documentType
? conventions.getCollectionNameForType(typeDesc)
: conventions.getCollectionNameForEntity(entity);
const metadata = {};
if (collectionName) {
metadata[Constants_1.CONSTANTS.Documents.Metadata.COLLECTION] = collectionName;
}
const entityType = documentType
? conventions.getJsTypeByDocumentType(documentType)
: conventions.getTypeDescriptorByEntity(entity);
const jsType = conventions.getJsTypeName(entityType);
if (jsType) {
metadata[Constants_1.CONSTANTS.Documents.Metadata.RAVEN_JS_TYPE] = jsType;
}
if (id) {
this._knownMissingIds.delete(id);
}
this._storeEntityInUnitOfWork(id, entity, changeVector, metadata, forceConcurrencyCheck, documentType);
}
_storeEntityInUnitOfWork(id, entity, changeVector, metadata, forceConcurrencyCheck, documentType) {
if (id) {
this._knownMissingIds.delete(id);
}
if (this.transactionMode === "ClusterWide") {
if (!changeVector) {
let changeVectorInner;
if (this.clusterSession.tryGetMissingAtomicGuardFor(id, r => changeVectorInner = r)) {
changeVector = changeVectorInner;
}
}
}
const documentInfo = new DocumentInfo_1.DocumentInfo();
documentInfo.id = id;
documentInfo.metadata = metadata;
documentInfo.changeVector = changeVector;
documentInfo.concurrencyCheckMode = forceConcurrencyCheck;
documentInfo.entity = entity;
documentInfo.newDocument = true;
documentInfo.document = null;
this.documentsByEntity.put(entity, documentInfo);
if (id) {
this.documentsById.add(documentInfo);
}
}
_rememberEntityForDocumentIdGeneration(entity) {
(0, Exceptions_1.throwError)("NotImplementedException", "You cannot set GenerateDocumentIdsOnStore to false"
+ " without implementing RememberEntityForDocumentIdGeneration");
}
prepareForSaveChanges() {
const result = this._newSaveChangesData();
const deferredCommandsCount = this._deferredCommands.length;
this._prepareForEntitiesDeletion(result, null);
this._prepareForEntitiesPuts(result);
this._prepareForCreatingRevisionsFromIds(result);
this._prepareCompareExchangeEntities(result);
if (this._deferredCommands.length > deferredCommandsCount) {
for (let i = deferredCommandsCount; i < this._deferredCommands.length; i++) {
result.deferredCommands.push(this._deferredCommands[i]);
}
for (const item of this.deferredCommandsMap.entries()) {
result.deferredCommandsMap.set(item[0], item[1]);
}
}
for (const deferredCommand of result.deferredCommands) {
if (deferredCommand.onBeforeSaveChanges) {
deferredCommand.onBeforeSaveChanges(this);
}
}
return result;
}
validateClusterTransaction(result) {
if (this._transactionMode !== "ClusterWide") {
return;
}
if (this.useOptimisticConcurrency) {
(0, Exceptions_1.throwError)("InvalidOperationException", "useOptimisticConcurrency is not supported with TransactionMode set to "
+ "ClusterWide");
}
for (const commandData of result.sessionCommands) {
switch (commandData.type) {
case "PUT":
case "DELETE":
if (commandData.changeVector) {
(0, Exceptions_1.throwError)("InvalidOperationException", "Optimistic concurrency for "
+ commandData.id + " is not supported when using a cluster transaction.");
}
break;
case "CompareExchangeDELETE":
case "CompareExchangePUT":
break;
default:
(0, Exceptions_1.throwError)("InvalidOperationException", "The command '" + commandData.type + "' is not supported in a cluster session.");
}
}
}
_updateSessionAfterSaveChanges(result) {
const returnedTransactionIndex = result.transactionIndex;
this._documentStore.setLastTransactionIndex(this.databaseName, returnedTransactionIndex);
this.sessionInfo.lastClusterTransactionIndex = returnedTransactionIndex;
}
onBeforeConversionToDocumentInvoke(id, entity) {
const args = new SessionEvents_1.BeforeConversionToDocumentEventArgs(this, id, entity);
this.emit("beforeConversionToDocument", args);
}
onAfterConversionToDocumentInvoke(id, entity, document) {
if (this.listenerCount("afterConversionToDocument")) {
const eventArgs = new SessionEvents_1.AfterConversionToDocumentEventArgs(this, id, entity, document);
this.emit("afterConversionToDocument", eventArgs);
if (eventArgs.document.value && eventArgs.document.value !== document.value) {
document.value = eventArgs.document.value;
}
}
}
onBeforeConversionToEntityInvoke(id, type, document) {
if (this.listenerCount("beforeConversionToEntity")) {
const eventArgs = new SessionEvents_1.BeforeConversionToEntityEventArgs(this, id, type, document.value);
this.emit("beforeConversionToEntity", eventArgs);
if (eventArgs.document && eventArgs.document !== document) {
document.value = eventArgs.document;
}
}
}
onAfterConversionToEntityInvoke(id, document, entity) {
const eventArgs = new SessionEvents_1.AfterConversionToEntityEventArgs(this, id, document, entity);
this.emit("afterConversionToEntity", eventArgs);
}
_prepareCompareExchangeEntities(result) {
if (!this._hasClusterSession()) {
return;
}
const clusterTransactionOperations = this.clusterSession;
if (!clusterTransactionOperations.numberOfTrackedCompareExchangeValues) {
return;
}
if (this._transactionMode !== "ClusterWide") {
(0, Exceptions_1.throwError)("InvalidOperationException", "Performing cluster transaction operation require the TransactionMode to be set to ClusterWide");
}
this.clusterSession.prepareCompareExchangeEntities(result);
}
_newSaveChangesData() {
return new CommandData_1.SaveChangesData({
deferredCommands: [...this._deferredCommands],
deferredCommandsMap: new Map(this.deferredCommandsMap),
options: this._saveChangesOptions,
session: this
});
}
_prepareForCreatingRevisionsFromIds(result) {
for (const idEntry of this.idsForCreatingForcedRevisions.keys()) {
result.sessionCommands.push(new ForceRevisionCommandData_1.ForceRevisionCommandData(idEntry));
}
this.idsForCreatingForcedRevisions.clear();
}
_prepareForEntitiesDeletion(result, changes) {
const deletes = this.deletedEntities.prepareEntitiesDeletes();
try {
for (const deletedEntity of this.deletedEntities) {
let documentInfo = this.documentsByEntity.get(deletedEntity.entity);
if (!documentInfo) {
continue;
}
if (changes) {
const docChanges = [];
const change = new DocumentsChanges_1.DocumentsChanges();
change.fieldNewValue = "";
change.fieldOldValue = "";
change.change = "DocumentDeleted";
docChanges.push(change);
changes[documentInfo.id] = docChanges;
}
else {
const command = result.deferredCommandsMap.get(IdTypeAndName_1.IdTypeAndName.keyFor(documentInfo.id, "ClientAnyCommand", null));
if (command) {
InMemoryDocumentSessionOperations._throwInvalidDeletedDocumentWithDeferredCommand(command);
}
let changeVector = null;
documentInfo = this.documentsById.getValue(documentInfo.id);
if (documentInfo) {
changeVector = documentInfo.changeVector;
if (documentInfo.entity) {
result.onSuccess.removeDocumentByEntity(documentInfo.entity);
result.entities.push(documentInfo.entity);
}
result.onSuccess.removeDocumentById(documentInfo.id);
}
if (!this.useOptimisticConcurrency) {
changeVector = null;
}
const beforeDeleteEventArgs = new SessionEvents_1.SessionBeforeDeleteEventArgs(this, documentInfo.id, documentInfo.entity);
this.emit("beforeDelete", beforeDeleteEventArgs);
result.sessionCommands.push(new CommandData_1.DeleteCommandData(documentInfo.id, changeVector, documentInfo.changeVector));
}
if (!changes) {
result.onSuccess.clearDeletedEntities();
}
}
}
finally {
deletes.dispose();
}
}
_prepareForEntitiesPuts(result) {
const putsContext = this.documentsByEntity.prepareEntitiesPuts();
try {
const shouldIgnoreEntityChanges = this.conventions.shouldIgnoreEntityChanges;
for (const entry of this.documentsByEntity) {
const { key: entityKey, value: entityValue } = entry;
if (entityValue.ignoreChanges) {
continue;
}
if (shouldIgnoreEntityChanges) {
if (shouldIgnoreEntityChanges(this, entry.value.entity, entry.value.id)) {
continue;
}
}
if (this.isDeleted(entityValue.id)) {
continue;
}
const dirtyMetadata = InMemoryDocumentSessionOperations._updateMetadataModifications(entityValue);
let document = this.entityToJson.convertEntityToJson(entityKey, entityValue);
if (!this._entityChanged(document, entityValue, null) && !dirtyMetadata) {
continue;
}
const command = result.deferredCommandsMap.get(IdT