private bool TryGetLatestDocument( IEnumerable <VersionedDbDocument> documents, VersionedDocumentReadOptions options, out VersionedDbDocument document, out DateTime createdTime, out DateTime modifiedTime) { var ordered = documents.OrderBy(x => x.Version).ToArray(); if (ordered.Length == 0) { document = null; createdTime = default(DateTime); modifiedTime = default(DateTime); return(false); } var first = ordered[0]; var last = ordered[ordered.Length - 1]; if (last.Deleted && !options.IncludeDeleted) { document = null; createdTime = default(DateTime); modifiedTime = default(DateTime); return(false); } createdTime = first.Timestamp; modifiedTime = last.Timestamp; document = last; return(true); }
/// <inheritdoc /> public async Task <VersionedDocumentUpsertResult <TDocument> > UpsertDocumentAsync <TDocument>( TDocument document, DocumentTypeMapping <TDocument> mapping, OperationOptions operationOptions) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } operationOptions = operationOptions ?? new OperationOptions(); var documentId = mapping.IdMapper(document); // Get the newest document version if one exists. var existingDocument = await GetDocumentIncludingDeleted(documentId, mapping); if (existingDocument != null && operationOptions.CheckVersion.HasValue && operationOptions.CheckVersion != existingDocument.Version) { throw new NebulaStoreConcurrencyException("Existing document version does not match the specified check version."); } var version = CalculateNextVersion(existingDocument); var dbRecord = new VersionedDbDocument(); dbRecord.Id = CreateRecordId(documentId, version, mapping); dbRecord.DocumentId = documentId; dbRecord.Service = DbAccess.ConfigManager.ServiceName; dbRecord.PartitionKey = mapping.PartitionKeyMapper(document); dbRecord.Version = version; dbRecord.Actor = GetActorId(); dbRecord.Timestamp = DateTime.UtcNow; SetDocumentContent(dbRecord, document, mapping); await CreateDocumentAsync(dbRecord, existingDocument); var updatedDocument = await GetDocumentAsync(documentId, version, mapping); if (updatedDocument == null) { throw new NebulaStoreException("Failed to retrieve document after successful upsert"); } if (updatedDocument.ResultType == DocumentReadResultType.Failed) { throw new NebulaStoreException($"Failed to retrieve document: {updatedDocument.FailureDetails.Message}"); } return(new VersionedDocumentUpsertResult <TDocument>(documentId, updatedDocument.Metadata, updatedDocument.Document)); }
/// <inheritdoc /> public async Task DeleteDocumentAsync <TDocument>(string id, DocumentTypeMapping <TDocument> mapping, OperationOptions operationOptions) { if (id == null) { throw new ArgumentNullException(nameof(id)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } operationOptions = operationOptions ?? new OperationOptions(); var query = QueryClient.CreateQueryById(id, mapping); var documents = await ExecuteQueryAsync(query); var existingDocument = FindLatestDocumentIncludingDeleted(documents); if (existingDocument == null) { // Document not found. Treated similarly to already deleted. return; } if (operationOptions.CheckVersion.HasValue && operationOptions.CheckVersion != existingDocument.Version) { throw new NebulaStoreConcurrencyException("Existing document version does not match the specified check version"); } // Only perform removal if it is not already deleted. if (existingDocument.Deleted) { // Document already deleted. return; } // Document not deleted. Create deletion record. var version = CalculateNextVersion(existingDocument); var dbRecord = new VersionedDbDocument(); dbRecord.Id = CreateRecordId(id, version, mapping); dbRecord.DocumentId = existingDocument.DocumentId; dbRecord.Service = DbAccess.ConfigManager.ServiceName; dbRecord.PartitionKey = existingDocument.PartitionKey; dbRecord.Version = version; dbRecord.Deleted = true; dbRecord.Actor = GetActorId(); dbRecord.Timestamp = DateTime.UtcNow; SetDocumentContentFromExisting(dbRecord, existingDocument, mapping); await CreateDocumentAsync(dbRecord, existingDocument); }
private int CalculateNextVersion(VersionedDbDocument document) { int version = 1; if (document != null) { version = document.Version + 1; } return(version); }
private bool TryGetLatestDocument( IEnumerable <VersionedDbDocument> documents, VersionedDocumentReadOptions options, out VersionedDbDocument document, out DateTime createdTime, out DateTime modifiedTime) { var ordered = documents.OrderBy(x => x.Version).ToArray(); if (ordered.Length == 0) { document = null; createdTime = default(DateTime); modifiedTime = default(DateTime); return(false); } var first = ordered[0]; var last = ordered[ordered.Length - 1]; if (last.Deleted && !options.IncludeDeleted) { document = null; createdTime = default(DateTime); modifiedTime = default(DateTime); return(false); } if (ordered.Length == 1 && !last.Latest) { // There is only one document returned by the query and that document is not the // latest. That means the query did not match the latest version of the document // because the first document version is always included in latest queries. document = null; createdTime = default(DateTime); modifiedTime = default(DateTime); return(false); } createdTime = first.Timestamp; modifiedTime = last.Timestamp; document = last; return(true); }
private VersionedDocumentReadResult <TDocument> CreateReadResult <TDocument>( string id, VersionedDbDocument document, DocumentTypeMapping <TDocument> mapping, DateTime createdTime, DateTime modifiedTime) { var metadata = new VersionedDocumentMetadata(document.Version, document.Deleted, createdTime, modifiedTime, document.Actor); TDocument content; DocumentReadFailureDetails failure; if (!TryGetDocumentContent(document, mapping, out content, out failure)) { return(VersionedDocumentReadResult <TDocument> .CreateFailure(id, metadata, failure)); } return(VersionedDocumentReadResult <TDocument> .CreateOkay(id, metadata, content)); }
private async Task CreateDocumentAsync(VersionedDbDocument newRecord, VersionedDbDocument existingRecord) { await ExecuteStoredProcedureAsync <CreateDocumentStoredProcedure>(newRecord.PartitionKey, newRecord, existingRecord); }