public override VetoResult AllowPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { // always reset these _clearCurrent.Value = false; _originalDocument.Value = null; _now.Value = SystemTime.UtcNow; if (key == null) return VetoResult.Allowed; // Don't do anything if temporal versioning is inactive for this document type if (!Database.IsTemporalVersioningEnabled(key, metadata)) return VetoResult.Allowed; // Don't allow modifications to revision documents if (key.Contains(TemporalConstants.TemporalKeySeparator)) return VetoResult.Deny("Modifying an existing temporal revision directly is not allowed."); // If no effective date was passed in, use now. var temporal = metadata.GetTemporalMetadata(); if (!temporal.Effective.HasValue) temporal.Effective = _now.Value; return VetoResult.Allowed; }
public override VetoResult AllowPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { // always reset these _clearCurrent.Value = false; _originalDocument.Value = null; _now.Value = SystemTime.UtcNow; if (key == null) { return(VetoResult.Allowed); } // Don't do anything if temporal versioning is inactive for this document type if (!Database.IsTemporalVersioningEnabled(key, metadata)) { return(VetoResult.Allowed); } // Don't allow modifications to revision documents if (key.Contains(TemporalConstants.TemporalKeySeparator)) { return(VetoResult.Deny("Modifying an existing temporal revision directly is not allowed.")); } // If no effective date was passed in, use now. var temporal = metadata.GetTemporalMetadata(); if (!temporal.Effective.HasValue) { temporal.Effective = _now.Value; } return(VetoResult.Allowed); }
public override void OnRead(string key, RavenJObject document, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { // This trigger is only for simple query operations if (key == null || operation != ReadOperation.Query) { return; } // Don't do anything when temporal versioning is not enabled if (!Database.IsTemporalVersioningEnabled(key, metadata)) { return; } // Only operate on temporal revisions var temporal = metadata.GetTemporalMetadata(); if (temporal.Status != TemporalStatus.Revision) { return; } // Send back the revision number temporal.RevisionNumber = int.Parse(key.Split('/').Last()); // When we filtered by effective date, return the document id instead of the revision id if (temporal.Effective.HasValue) { metadata["@id"] = key.Substring(0, key.IndexOf(TemporalConstants.TemporalKeySeparator, StringComparison.Ordinal)); } }
public override ReadVetoResult AllowRead(string key, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { // This trigger is only for simple query operations if (key == null || operation != ReadOperation.Query) return ReadVetoResult.Allowed; // Don't do anything if temporal versioning is inactive for this document type if (!Database.IsTemporalVersioningEnabled(key, metadata)) return ReadVetoResult.Allowed; // If an effective date was passed in, then use it. DateTimeOffset effective; var headerValue = CurrentOperationContext.Headers.Value[TemporalMetadata.RavenTemporalEffective]; if (headerValue == null || !DateTimeOffset.TryParse(headerValue, null, DateTimeStyles.RoundtripKind, out effective)) { // If no effective data passed, return as stored. return ReadVetoResult.Allowed; } // Return the requested effective date in the metadata. var temporal = metadata.GetTemporalMetadata(); temporal.Effective = effective; // Return the result if it's the active revision, or skip it otherwise. return temporal.Status == TemporalStatus.Revision && temporal.EffectiveStart <= effective && effective < temporal.EffectiveUntil && !temporal.Deleted ? ReadVetoResult.Allowed : ReadVetoResult.Ignore; }
public override ReadVetoResult AllowRead(string key, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { // always reset these _temporalVersioningEnabled.Value = false; _effectiveVersionKey.Value = null; _now.Value = SystemTime.UtcNow; if (key == null) return ReadVetoResult.Allowed; // This trigger is only for load operations if (operation != ReadOperation.Load) return ReadVetoResult.Allowed; // Don't do anything if temporal versioning is inactive for this document type _temporalVersioningEnabled.Value = Database.IsTemporalVersioningEnabled(key, metadata); if (!_temporalVersioningEnabled.Value) return ReadVetoResult.Allowed; // Only operate on current temporal documents var temporal = metadata.GetTemporalMetadata(); if (temporal.Status != TemporalStatus.Current) return ReadVetoResult.Allowed; // If an effective date was passed in, then use it. DateTimeOffset effective; var headerValue = CurrentOperationContext.Headers.Value[TemporalMetadata.RavenTemporalEffective]; if (headerValue == null || !DateTimeOffset.TryParse(headerValue, null, DateTimeStyles.RoundtripKind, out effective)) { // If no effective data passed, return current data, as stored, effective now. temporal.Effective = _now.Value; return ReadVetoResult.Allowed; } // Return the requested effective date in the metadata. temporal.Effective = effective; // If the current document is already in range, just return it if (temporal.EffectiveStart <= effective && effective < temporal.EffectiveUntil) return ReadVetoResult.Allowed; // Load the history doc Etag historyEtag; var history = Database.GetTemporalHistoryFor(key, transactionInformation, out historyEtag); // Find the revision that is effective at the date requested var effectiveRevisionInfo = history.Revisions.FirstOrDefault(x => x.Status == TemporalStatus.Revision && x.EffectiveStart <= effective && x.EffectiveUntil > effective); // Return nothing if there is no revision at the effective date if (effectiveRevisionInfo == null) return ReadVetoResult.Ignore; // Hold on to the key so we can use it later in OnRead _effectiveVersionKey.Value = effectiveRevisionInfo.Key; return ReadVetoResult.Allowed; }
public void BeforeDelete(string key, object entityInstance, RavenJObject metadata) { var temporal = metadata.GetTemporalMetadata(); if (temporal.Status == TemporalStatus.NonTemporal) return; var session = (DocumentSession) ThreadLocalSession.Value; var headers = session.DatabaseCommands.OperationsHeaders; var header = string.Format("{0}-{1}", TemporalMetadata.RavenTemporalEffective, key.Replace('/', '-')); var effective = temporal.Effective ?? SystemTime.UtcNow; headers[header] = effective.ToString("o"); }
public void BeforeDelete(string key, object entityInstance, RavenJObject metadata) { var temporal = metadata.GetTemporalMetadata(); if (temporal.Status == TemporalStatus.NonTemporal) return; if (!temporal.Effective.HasValue) throw new InvalidOperationException( "No effective date was set for the temporal delete operation. Be sure to specify an effective date when loading the entity to be deleted."); var session = (DocumentSession) ThreadLocalSession.Value; var headers = session.DatabaseCommands.OperationsHeaders; var header = string.Format("{0}-{1}", TemporalConstants.EffectiveDateHeader, key.Replace('/', '-')); headers[header] = temporal.Effective.Value.ToString("o"); }
public void BeforeDelete(string key, object entityInstance, RavenJObject metadata) { var temporal = metadata.GetTemporalMetadata(); if (temporal.Status == TemporalStatus.NonTemporal) { return; } var session = (DocumentSession)ThreadLocalSession.Value; var headers = session.DatabaseCommands.OperationsHeaders; var header = string.Format("{0}-{1}", TemporalMetadata.RavenTemporalEffective, key.Replace('/', '-')); var effective = temporal.Effective ?? SystemTime.UtcNow; headers[header] = effective.ToString("o"); }
public void BeforeDelete(string key, object entityInstance, RavenJObject metadata) { var temporal = metadata.GetTemporalMetadata(); if (temporal.Status == TemporalStatus.NonTemporal) { return; } if (!temporal.Effective.HasValue) { throw new InvalidOperationException( "No effective date was set for the temporal delete operation. Be sure to specify an effective date when loading the entity to be deleted."); } var session = (DocumentSession)ThreadLocalSession.Value; var headers = session.DatabaseCommands.OperationsHeaders; var header = string.Format("{0}-{1}", TemporalConstants.EffectiveDateHeader, key.Replace('/', '-')); headers[header] = temporal.Effective.Value.ToString("o"); }
public override void OnRead(string key, RavenJObject document, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { // This trigger is only for simple query operations if (key == null || operation != ReadOperation.Query) return; // Don't do anything when temporal versioning is not enabled if (!Database.IsTemporalVersioningEnabled(key, metadata)) return; // Only operate on temporal revisions var temporal = metadata.GetTemporalMetadata(); if (temporal.Status != TemporalStatus.Revision) return; // Send back the revision number temporal.RevisionNumber = int.Parse(key.Split('/').Last()); // When we filtered by effective date, return the document id instead of the revision id if (temporal.Effective.HasValue) metadata["@id"] = key.Substring(0, key.IndexOf(TemporalConstants.TemporalKeySeparator, StringComparison.Ordinal)); }
public override ReadVetoResult AllowRead(string key, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { // This trigger is only for simple query operations if (key == null || operation != ReadOperation.Query) { return(ReadVetoResult.Allowed); } // Don't do anything if temporal versioning is inactive for this document type if (!Database.IsTemporalVersioningEnabled(key, metadata)) { return(ReadVetoResult.Allowed); } // If an effective date was passed in, then use it. DateTimeOffset effective; var headerValue = CurrentOperationContext.Headers.Value[TemporalMetadata.RavenTemporalEffective]; if (headerValue == null || !DateTimeOffset.TryParse(headerValue, null, DateTimeStyles.RoundtripKind, out effective)) { // If no effective data passed, return as stored. return(ReadVetoResult.Allowed); } // Return the requested effective date in the metadata. var temporal = metadata.GetTemporalMetadata(); temporal.Effective = effective; // Return the result if it's the active revision, or skip it otherwise. return(temporal.Status == TemporalStatus.Revision && temporal.EffectiveStart <= effective && effective < temporal.EffectiveUntil && !temporal.Deleted ? ReadVetoResult.Allowed : ReadVetoResult.Ignore); }
public override void OnRead(string key, RavenJObject document, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { if (key == null) return; // If we're loading a revision directly, make sure we have set the rev number in the metadata var temporal = metadata.GetTemporalMetadata(); if (key.Contains(TemporalConstants.TemporalKeySeparator)) temporal.RevisionNumber = int.Parse(key.Split('/').Last()); // Handle migration from nontemporal document if (temporal.Status == TemporalStatus.NonTemporal && _temporalVersioningEnabled.Value) { // Rewrite the document temporally. We specifically do NOT disable triggers on this put. temporal.Effective = DateTimeOffset.MinValue; Database.Put(key, null, new RavenJObject(document), new RavenJObject(metadata), transactionInformation); // Fake out the current document for the return of this load. temporal.Status = TemporalStatus.Current; temporal.RevisionNumber = 1; temporal.Effective = _now.Value; temporal.EffectiveStart = DateTimeOffset.MinValue; temporal.EffectiveUntil = DateTimeOffset.MaxValue; } // If we didn't get a new effective revision key above, just return var effectiveRevisionKey = _effectiveVersionKey.Value; if (effectiveRevisionKey == null) return; _log.Debug("Temporally loading {0} instead of {1}", effectiveRevisionKey, key); using (Database.DisableAllTriggersForCurrentThread()) { // Load the effective document var effectiveRevision = Database.Get(effectiveRevisionKey, transactionInformation); // Replace the resulting document foreach (var prop in document.Keys) document.Remove(prop); var evDoc = effectiveRevision.DataAsJson; foreach (var prop in evDoc.Keys) document.Add(prop, evDoc[prop]); // Replace the resulting metadata foreach (var prop in metadata.Keys) { if (prop != TemporalMetadata.RavenTemporalEffective) metadata.Remove(prop); } var evMetadata = effectiveRevision.Metadata; foreach (var prop in evMetadata.Keys) metadata.Add(prop, evMetadata[prop]); // Send back the revision number also temporal.RevisionNumber = int.Parse(effectiveRevisionKey.Split('/').Last()); } }
public static int PutRevision(this DocumentDatabase database, string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation, DateTime now, bool deleted = false) { Log.Debug("Putting new temporal revision for {0}", key); // The revision is a copy of the document. var revisionDocument = new RavenJObject(document); var revisionMetadata = new RavenJObject(metadata); // Set metadata on the revision var temporal = revisionMetadata.GetTemporalMetadata(); var effective = temporal.EffectiveStart.GetValueOrDefault(); temporal.Status = TemporalStatus.Revision; temporal.Deleted = deleted; temporal.Pending = effective > now; // Store the revision var newRevisionDoc = database.Put(key + TemporalConstants.TemporalKeySeparator, null, revisionDocument, revisionMetadata, transactionInformation); // Get the revision number that was generated var revisionNumber = int.Parse(newRevisionDoc.Key.Split('/').Last()); // Get the history doc and add this revision Etag historyEtag; var history = database.GetTemporalHistoryFor(key, transactionInformation, out historyEtag); history.AddRevision(newRevisionDoc.Key, temporal); if (revisionNumber > 1) { // Artifact any revisions that already exist on or after the new effective date var futureRevisions = history.Revisions.Where(x => x.Key != newRevisionDoc.Key && x.Status == TemporalStatus.Revision && x.EffectiveStart >= effective); foreach (var revisionInfo in futureRevisions) { // in the history revisionInfo.Status = TemporalStatus.Artifact; // on the revision doc database.SetDocumentMetadata(revisionInfo.Key, transactionInformation, TemporalMetadata.RavenDocumentTemporalStatus, TemporalStatus.Artifact.ToString()); } // Update the until date of the last revison prior to this one var lastRevision = history.Revisions.LastOrDefault(x => x.Key != newRevisionDoc.Key && x.Status == TemporalStatus.Revision && x.EffectiveStart < effective); if (lastRevision != null) { // in the history lastRevision.EffectiveUntil = effective; lastRevision.AssertedUntil = now; // on the revision doc var md = new Dictionary <string, RavenJToken> { { TemporalMetadata.RavenDocumentTemporalEffectiveUntil, effective }, { TemporalMetadata.RavenDocumentTemporalAssertedUntil, now } }; database.SetDocumentMetadata(lastRevision.Key, transactionInformation, md); } } // Update the history doc database.SaveTemporalHistoryFor(key, history, transactionInformation, historyEtag); // Reset the activation timer with each put. // This is so future revisions can become current without having to constantly poll. database.StartupTasks.OfType <TemporalActivator>().Single().ResetTimer(effective.UtcDateTime, now); // Return the revision number return(revisionNumber); }
public static int PutRevision(this DocumentDatabase database, string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation, DateTime now, bool deleted = false) { Log.Debug("Putting new temporal revision for {0}", key); // The revision is a copy of the document. var revisionDocument = new RavenJObject(document); var revisionMetadata = new RavenJObject(metadata); // Set metadata on the revision var temporal = revisionMetadata.GetTemporalMetadata(); var effective = temporal.EffectiveStart.GetValueOrDefault(); temporal.Status = TemporalStatus.Revision; temporal.Deleted = deleted; temporal.Pending = effective > now; // Store the revision var newRevisionDoc = database.Put(key + TemporalConstants.TemporalKeySeparator, null, revisionDocument, revisionMetadata, transactionInformation); // Get the revision number that was generated var revisionNumber = int.Parse(newRevisionDoc.Key.Split('/').Last()); // Get the history doc and add this revision Etag historyEtag; var history = database.GetTemporalHistoryFor(key, transactionInformation, out historyEtag); history.AddRevision(newRevisionDoc.Key, temporal); if (revisionNumber > 1) { // Artifact any revisions that already exist on or after the new effective date var futureRevisions = history.Revisions.Where(x => x.Key != newRevisionDoc.Key && x.Status == TemporalStatus.Revision && x.EffectiveStart >= effective); foreach (var revisionInfo in futureRevisions) { // in the history revisionInfo.Status = TemporalStatus.Artifact; // on the revision doc database.SetDocumentMetadata(revisionInfo.Key, transactionInformation, TemporalMetadata.RavenDocumentTemporalStatus, TemporalStatus.Artifact.ToString()); } // Update the until date of the last revison prior to this one var lastRevision = history.Revisions.LastOrDefault(x => x.Key != newRevisionDoc.Key && x.Status == TemporalStatus.Revision && x.EffectiveStart < effective); if (lastRevision != null) { // in the history lastRevision.EffectiveUntil = effective; lastRevision.AssertedUntil = now; // on the revision doc var md = new Dictionary<string, RavenJToken> { { TemporalMetadata.RavenDocumentTemporalEffectiveUntil, effective }, { TemporalMetadata.RavenDocumentTemporalAssertedUntil, now } }; database.SetDocumentMetadata(lastRevision.Key, transactionInformation, md); } } // Update the history doc database.SaveTemporalHistoryFor(key, history, transactionInformation, historyEtag); // Reset the activation timer with each put. // This is so future revisions can become current without having to constantly poll. database.StartupTasks.OfType<TemporalActivator>().Single().ResetTimer(effective.UtcDateTime, now); // Return the revision number return revisionNumber; }
public override ReadVetoResult AllowRead(string key, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { // always reset these _temporalVersioningEnabled.Value = false; _effectiveVersionKey.Value = null; _now.Value = SystemTime.UtcNow; if (key == null) { return(ReadVetoResult.Allowed); } // This trigger is only for load operations if (operation != ReadOperation.Load) { return(ReadVetoResult.Allowed); } // Don't do anything if temporal versioning is inactive for this document type _temporalVersioningEnabled.Value = Database.IsTemporalVersioningEnabled(key, metadata); if (!_temporalVersioningEnabled.Value) { return(ReadVetoResult.Allowed); } // Only operate on current temporal documents var temporal = metadata.GetTemporalMetadata(); if (temporal.Status != TemporalStatus.Current) { return(ReadVetoResult.Allowed); } // If an effective date was passed in, then use it. DateTimeOffset effective; var headerValue = CurrentOperationContext.Headers.Value[TemporalMetadata.RavenTemporalEffective]; if (headerValue == null || !DateTimeOffset.TryParse(headerValue, null, DateTimeStyles.RoundtripKind, out effective)) { // If no effective data passed, return current data, as stored, effective now. temporal.Effective = _now.Value; return(ReadVetoResult.Allowed); } // Return the requested effective date in the metadata. temporal.Effective = effective; // If the current document is already in range, just return it if (temporal.EffectiveStart <= effective && effective < temporal.EffectiveUntil) { return(ReadVetoResult.Allowed); } // Load the history doc Etag historyEtag; var history = Database.GetTemporalHistoryFor(key, transactionInformation, out historyEtag); // Find the revision that is effective at the date requested var effectiveRevisionInfo = history.Revisions.FirstOrDefault(x => x.Status == TemporalStatus.Revision && x.EffectiveStart <= effective && x.EffectiveUntil > effective); // Return nothing if there is no revision at the effective date if (effectiveRevisionInfo == null) { return(ReadVetoResult.Ignore); } // Hold on to the key so we can use it later in OnRead _effectiveVersionKey.Value = effectiveRevisionInfo.Key; return(ReadVetoResult.Allowed); }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (key == null) return; if (key.StartsWith("Raven/" + TemporalConstants.BundleName + "/Raven/")) throw new InvalidOperationException("Cannot version RavenDB system documents!"); // Clear the config cache any time a new configuration is written. if (key.StartsWith("Raven/" + TemporalConstants.BundleName + "/")) TemporalVersioningUtil.ConfigCache.Clear(); if (!Database.IsTemporalVersioningEnabled(key, metadata)) return; using (Database.DisableAllTriggersForCurrentThread()) { // When it's initially written, data is considered effective from the date specified to the end of time. var temporal = metadata.GetTemporalMetadata(); temporal.EffectiveStart = temporal.Effective; temporal.EffectiveUntil = DateTimeOffset.MaxValue; // Set the asserted dates temporal.AssertedStart = _now.Value; temporal.AssertedUntil = DateTimeOffset.MaxValue; // See if the revision we're saving is current. var current = temporal.Effective <= _now.Value; // Don't save the requested date with the document temporal.Effective = null; if (!current) { // When it's not current, then fetch the current one so we can put it back later. // (This would not be necessary if Raven supported "instead of" triggers.) _originalDocument.Value = Database.Get(key, transactionInformation); // If this is the first revision and it's not current, then we don't want to keep a current doc at all. _clearCurrent.Value = _originalDocument.Value == null; } // Always store this new data as a revision document var versionNumber = Database.PutRevision(key, document, metadata, transactionInformation, _now.Value); if (current) { // When it's current, set the appropriate values the document that will be stored temporal.Status = TemporalStatus.Current; temporal.RevisionNumber = versionNumber; } } }
public override void OnRead(string key, RavenJObject document, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { if (key == null) { return; } // If we're loading a revision directly, make sure we have set the rev number in the metadata var temporal = metadata.GetTemporalMetadata(); if (key.Contains(TemporalConstants.TemporalKeySeparator)) { temporal.RevisionNumber = int.Parse(key.Split('/').Last()); } // Handle migration from nontemporal document if (temporal.Status == TemporalStatus.NonTemporal && _temporalVersioningEnabled.Value) { // Rewrite the document temporally. We specifically do NOT disable triggers on this put. temporal.Effective = DateTimeOffset.MinValue; Database.Put(key, null, new RavenJObject(document), new RavenJObject(metadata), transactionInformation); // Fake out the current document for the return of this load. temporal.Status = TemporalStatus.Current; temporal.RevisionNumber = 1; temporal.Effective = _now.Value; temporal.EffectiveStart = DateTimeOffset.MinValue; temporal.EffectiveUntil = DateTimeOffset.MaxValue; } // If we didn't get a new effective revision key above, just return var effectiveRevisionKey = _effectiveVersionKey.Value; if (effectiveRevisionKey == null) { return; } _log.Debug("Temporally loading {0} instead of {1}", effectiveRevisionKey, key); using (Database.DisableAllTriggersForCurrentThread()) { // Load the effective document var effectiveRevision = Database.Get(effectiveRevisionKey, transactionInformation); // Replace the resulting document foreach (var prop in document.Keys) { document.Remove(prop); } var evDoc = effectiveRevision.DataAsJson; foreach (var prop in evDoc.Keys) { document.Add(prop, evDoc[prop]); } // Replace the resulting metadata foreach (var prop in metadata.Keys) { if (prop != TemporalMetadata.RavenTemporalEffective) { metadata.Remove(prop); } } var evMetadata = effectiveRevision.Metadata; foreach (var prop in evMetadata.Keys) { metadata.Add(prop, evMetadata[prop]); } // Send back the revision number also temporal.RevisionNumber = int.Parse(effectiveRevisionKey.Split('/').Last()); } }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (key == null) { return; } if (key.StartsWith("Raven/" + TemporalConstants.BundleName + "/Raven/")) { throw new InvalidOperationException("Cannot version RavenDB system documents!"); } // Clear the config cache any time a new configuration is written. if (key.StartsWith("Raven/" + TemporalConstants.BundleName + "/")) { TemporalVersioningUtil.ConfigCache.Clear(); } if (!Database.IsTemporalVersioningEnabled(key, metadata)) { return; } using (Database.DisableAllTriggersForCurrentThread()) { // When it's initially written, data is considered effective from the date specified to the end of time. var temporal = metadata.GetTemporalMetadata(); temporal.EffectiveStart = temporal.Effective; temporal.EffectiveUntil = DateTimeOffset.MaxValue; // Set the asserted dates temporal.AssertedStart = _now.Value; temporal.AssertedUntil = DateTimeOffset.MaxValue; // See if the revision we're saving is current. var current = temporal.Effective <= _now.Value; // Don't save the requested date with the document temporal.Effective = null; if (!current) { // When it's not current, then fetch the current one so we can put it back later. _originalDocument.Value = Database.Get(key, transactionInformation); // If this is the first revision and it's not current, then we don't want to keep a current doc at all. _clearCurrent.Value = _originalDocument.Value == null; // If this is a future version, then the current doc might need to be updated if (_originalDocument.Value != null) { var originalMetadata = _originalDocument.Value.Metadata.GetTemporalMetadata(); if (originalMetadata.EffectiveUntil > temporal.EffectiveStart) { originalMetadata.EffectiveUntil = temporal.EffectiveStart; originalMetadata.AssertedUntil = _now.Value; } } } // Always store this new data as a revision document var versionNumber = Database.PutRevision(key, document, metadata, transactionInformation, _now.Value); if (current) { // When it's current, set the appropriate values the document that will be stored temporal.Status = TemporalStatus.Current; temporal.RevisionNumber = versionNumber; } } }