protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); DocumentMapping.Map(modelBuilder.Entity <Document>()); DocumentTypeMapping.Map(modelBuilder.Entity <DocumentType>()); }
/// <inheritdoc /> public async Task UpdateDocumentAsync <TDocument>( TDocument document, DocumentTypeMapping <TDocument> mapping, OperationOptions options) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } options = options ?? new OperationOptions(); var documentId = mapping.IdMapper(document); var existingDocument = await GetDocumentByIdAsync(documentId, mapping); if (existingDocument == null) { throw new NebulaStoreException($"Document '{documentId}' for update does not exist"); } var createdTime = existingDocument.CreatedTimestamp; var modifiedTime = DateTime.UtcNow; var dbRecord = CreateDbDocument(document, documentId, mapping, options, createdTime, modifiedTime); await UpdateDocumentAsync(dbRecord, existingDocument); }
public List <IQueryable <VersionedDocumentStoreClient.VersionedDbDocument> > CreateQueryByIds <TDocument>( ICollection <string> ids, DocumentTypeMapping <TDocument> mapping) { if (ids == null) { throw new ArgumentNullException(nameof(ids)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } var batchSize = DbAccess.QueryPolicy.GetIdSearchLimit(ids); var batched = ids.Batch(batchSize); var result = new List <IQueryable <VersionedDocumentStoreClient.VersionedDbDocument> >(); foreach (var batch in batched) { var query = CreateQueryByIdsImpl(batch.ToArray(), mapping); result.Add(query); } return(result); }
/// <inheritdoc /> public async Task <IList <DocumentWithMetadata <TDocument> > > GetDocumentsAsync <TDocument>( DocumentTypeMapping <TDocument> mapping) { if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } var query = QueryClient.CreateQueryAll(mapping); var documents = await ExecuteQueryAsync(query); var result = new List <DocumentWithMetadata <TDocument> >(); foreach (var document in documents) { var docWithMetaData = ReadDocumentWithMetadata(mapping, document); if (docWithMetaData != null) { result.Add(docWithMetaData); } } return(result); }
public LargeDocumentStore(IDocumentDbAccessProvider dbAccessProvider) : base(dbAccessProvider, false) { var config = new DocumentStoreConfigBuilder("LargeStore"); var largeDocumentType = config.AddDocument("LargeDocument"); var attachmentDocumentType = config.AddDocument("AttachmentDocument"); var attachmentType = attachmentDocumentType.AddAttachment("Attachment"); _largeMapping = config.AddDocumentMapping <LargeDocument>(largeDocumentType.Name) .SetIdMapper(x => x.Id.ToString()) .SetPartitionMapper(x => x.Id.ToString()) .Finish(); _smallMapping = config.AddDocumentMapping <SmallDocumentWithLargeAttachment>(attachmentDocumentType.Name) .SetIdMapper(x => x.Id.ToString()) .SetPartitionMapper(x => x.Id.ToString()) .Finish(); _attachmentMapping = _smallMapping.AddAttachmentMapping <LargeDocument>(attachmentType.Name) .Finish(); _config = config.Finish(); _client = CreateStoreLogic(DbAccess, _config); DbAccess.ConfigRegistry.RegisterStoreConfigSource(this); }
/// <inheritdoc /> public async Task <DocumentReadResult <TDocument> > GetDocumentAsync <TDocument>( string id, DocumentTypeMapping <TDocument> mapping) { if (id == null) { throw new ArgumentNullException(nameof(id)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } var query = QueryClient.CreateQueryById(id, mapping); var documents = await ExecuteQueryAsync(query); var document = documents.FirstOrDefault(); if (document == null) { return(null); } return(ReadDocument(mapping, document)); }
/// <inheritdoc /> public async Task UpsertDocumentAsync <TDocument>( TDocument document, DocumentTypeMapping <TDocument> mapping, OperationOptions options) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } options = options ?? new OperationOptions(); var documentId = mapping.IdMapper(document); var existingDocument = await GetDocumentByIdAsync(documentId, mapping); var modifiedTime = DateTime.UtcNow; var createdTime = existingDocument?.CreatedTimestamp ?? modifiedTime; var dbRecord = CreateDbDocument(document, documentId, mapping, options, createdTime, modifiedTime); await UpsertDocumentAsync(dbRecord); }
private UnversionedDbDocument CreateDbDocument <TDocument>( TDocument document, string documentId, DocumentTypeMapping <TDocument> mapping, OperationOptions operationOptions, DateTime createdTime, DateTime modifiedTime) { var dbRecord = new UnversionedDbDocument(); dbRecord.Id = CreateDbRecordId(mapping, documentId); dbRecord.DocumentId = documentId; dbRecord.Service = DbAccess.ConfigManager.ServiceName; dbRecord.PartitionKey = mapping.PartitionKeyMapper(document); dbRecord.Actor = GetActorId(); dbRecord.CreatedTimestamp = createdTime; dbRecord.Timestamp = modifiedTime; if (operationOptions.Ttl.HasValue) { dbRecord.TimeToLive = operationOptions.Ttl.Value; } SetDocumentContent(dbRecord, document, mapping); return(dbRecord); }
private VersionedDocumentReadResult <TDocument> ReadDocumentAsync <TDocument>( string id, DocumentTypeMapping <TDocument> mapping, IList <VersionedDbDocument> documents, VersionedDocumentReadOptions readOptions) { VersionedDbDocument document; DateTime createdTime; DateTime modifiedTime; if (!TryGetLatestDocument(documents, readOptions, out document, out createdTime, out modifiedTime)) { return(null); } 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)); }
/// <inheritdoc /> public async Task <VersionedDocumentQueryResult <TDocument> > GetDocumentsAsync <TDocument>( string query, IEnumerable <DbParameter> parameters, DocumentTypeMapping <TDocument> mapping, VersionedDocumentReadOptions options) { if (query == null) { throw new ArgumentNullException(nameof(query)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } parameters = parameters ?? new DbParameter[0]; var builtQuery = QueryClient.CreateQueryByLatest(mapping, query, parameters); var documents = await ExecuteQueryAsync(builtQuery); if (documents.Count == 0) { return(VersionedDocumentQueryResult <TDocument> .Empty); } options = options ?? new VersionedDocumentReadOptions(); List <VersionedDocumentReadResult <TDocument> > loaded = new List <VersionedDocumentReadResult <TDocument> >(); List <VersionedDocumentReadResult <TDocument> > failed = new List <VersionedDocumentReadResult <TDocument> >(); foreach (var docs in documents.GroupBy(x => x.DocumentId)) { VersionedDbDocument doc; DateTime createdTime; DateTime modifiedTime; if (!TryGetLatestDocument(docs, options, out doc, out createdTime, out modifiedTime)) { // Document exists but the latest version is deleted. continue; } var metadata = new VersionedDocumentMetadata(doc.Version, doc.Deleted, createdTime, modifiedTime, doc.Actor); TDocument content; DocumentReadFailureDetails failure; if (TryGetDocumentContent(doc, mapping, out content, out failure)) { loaded.Add(VersionedDocumentReadResult <TDocument> .CreateOkay(doc.DocumentId, metadata, content)); } else { failed.Add(VersionedDocumentReadResult <TDocument> .CreateFailure(doc.DocumentId, metadata, failure)); } } return(new VersionedDocumentQueryResult <TDocument>(ImmutableList.CreateRange(loaded), ImmutableList.CreateRange(failed))); }
private async Task <UnversionedDbDocument> GetDocumentByIdAsync <TDocument>( string documentId, DocumentTypeMapping <TDocument> mapping) { var query = QueryClient.CreateQueryById(documentId, mapping); var existingDocuments = await ExecuteQueryAsync(query); return(existingDocuments.FirstOrDefault()); }
/// <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)); }
public IQueryable <VersionedDocumentStoreClient.VersionedDbDocument> CreateQueryAll <TDocument>( DocumentTypeMapping <TDocument> mapping) { if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } return(CreateQueryByLatest(mapping, null)); }
private async Task PurgeDocument <TDocument>( VersionedDocumentStoreClient.VersionedDbDocument document, DocumentTypeMapping <TDocument> mapping) { var contentKey = CreateContentKey(mapping); await ExecuteStoredProcedureAsync <PurgeDocumentStoredProcedure>( document.PartitionKey, contentKey, document.DocumentId); }
/// <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 VersionedDocumentReadResult <TDocument> ReadLatestDocumentAsync <TDocument>( string id, DocumentTypeMapping <TDocument> mapping, IList <VersionedDbDocument> documents, VersionedDocumentReadOptions readOptions) { if (!TryGetLatestDocument(documents, readOptions, out var document, out var createdTime, out var modifiedTime)) { return(null); } return(CreateReadResult(id, document, mapping, createdTime, modifiedTime)); }
/// <inheritdoc /> public async Task <DocumentBatchReadResult <TDocument> > GetDocumentsAsync <TDocument>( IEnumerable <string> ids, DocumentTypeMapping <TDocument> mapping) { if (ids == null) { throw new ArgumentNullException(nameof(ids)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } var idSet = new HashSet <string>(ids); if (idSet.Count == 0) { return(DocumentBatchReadResult <TDocument> .Empty); } var query = QueryClient.CreateQueryByIds(idSet, mapping); var documents = await ExecuteQueriesAsync(query); var loaded = new List <DocumentReadResult <TDocument> >(); var failed = new List <DocumentReadResult <TDocument> >(); foreach (var document in documents) { var readResult = ReadDocument(mapping, document); if (readResult.ResultType == DocumentReadResultType.Loaded) { loaded.Add(readResult); } else { failed.Add(readResult); } idSet.Remove(document.DocumentId); } var missing = ImmutableList.CreateRange(idSet); return(new DocumentBatchReadResult <TDocument>( loaded.ToImmutableList(), missing, failed.ToImmutableList())); }
/// <inheritdoc /> public async Task PurgeDocumentsAsync <TDocument>(DocumentTypeMapping <TDocument> mapping) { if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } var query = _queryClient.CreateQueryAll(mapping); var documents = await ExecuteQueryAsync(query); foreach (var document in documents.GroupBy(x => x.DocumentId)) { await PurgeDocument(document.First(), mapping); } }
private DocumentWithMetadata <TDocument> ReadDocumentWithMetadata <TDocument>( DocumentTypeMapping <TDocument> mapping, UnversionedDbDocument document) { var metadata = new DocumentMetadata(document.CreatedTimestamp, document.Timestamp, document.Actor); TDocument content; if (!TryGetDocumentContent(document, mapping, out content, out _)) { return(null); } return(new DocumentWithMetadata <TDocument>(metadata, content)); }
/// <inheritdoc /> public async Task <DocumentQueryResult <TDocument> > GetDocumentsAsync <TDocument>( string query, DocumentTypeMapping <TDocument> mapping) { if (query == null) { throw new ArgumentNullException(nameof(query)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } return(await GetDocumentsAsync(query, null, mapping)); }
/// <inheritdoc /> public async Task <VersionedDocumentQueryResult <TDocument> > GetDocumentsAsync <TDocument>( string query, IEnumerable <DbParameter> parameters, DocumentTypeMapping <TDocument> mapping) { if (query == null) { throw new ArgumentNullException(nameof(query)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } return(await GetDocumentsAsync(query, parameters, mapping, null)); }
private DocumentReadResult <TDocument> ReadDocument <TDocument>( DocumentTypeMapping <TDocument> mapping, UnversionedDbDocument document) { var metadata = new DocumentMetadata(document.CreatedTimestamp, document.Timestamp, document.Actor); TDocument content; DocumentReadFailureDetails failure; if (!TryGetDocumentContent(document, mapping, out content, out failure)) { return(DocumentReadResult <TDocument> .CreateFailure(document.DocumentId, metadata, failure)); } return(DocumentReadResult <TDocument> .CreateOkay(document.DocumentId, metadata, content)); }
private IQueryable <VersionedDocumentStoreClient.VersionedDbDocument> CreateQueryByIdsImpl <TDocument>( ICollection <string> ids, DocumentTypeMapping <TDocument> mapping) { // Optimise queries for a single id to use EQUALS instead of IN. if (ids.Count == 1) { return(CreateQueryById(ids.First(), mapping)); } var inIds = "'" + string.Join("','", ids) + "'"; var query = $"[x].{mapping.IdPropertyName} IN ({inIds})"; return(CreateQueryByLatest(mapping, query)); }
public FlowerStore(IDocumentDbAccessProvider dbAccessProvider) : base(dbAccessProvider, false) { var config = new DocumentStoreConfigBuilder("Flowers"); var documentType = config.AddDocument("Daisy").Finish(); _mapping = config.AddDocumentMapping <Daisy>(documentType.DocumentName) .SetIdMapper(x => x.Id.ToString()) .SetPartitionMapper(x => x.Id.ToString()) .Finish(); _config = config.Finish(); _client = CreateStoreLogic(DbAccess, _config); DbAccess.ConfigRegistry.RegisterStoreConfigSource(this); }
/// <inheritdoc /> public async Task <VersionedDocumentQueryResult <TDocument> > GetDocumentsAsync <TDocument>( string query, DocumentTypeMapping <TDocument> mapping, VersionedDocumentReadOptions options) { if (query == null) { throw new ArgumentNullException(nameof(query)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } return(await GetDocumentsAsync(query, new DbParameter[0], mapping, options)); }
public OrderStore( IDocumentDbAccessProvider dbAccessProvider, IDocumentMetadataSource metadataSource) : base(dbAccessProvider) { var config = new DocumentStoreConfigBuilder("Orders"); var orderDocumentType = config.AddDocument("Order").Finish(); _orderMapping = config.AddDocumentMapping <Order>(orderDocumentType.DocumentName) .SetIdMapper(x => x.Id.ToString()) .SetPartitionMapper(x => x.Id.ToString()) .Finish(); _config = config.Finish(); _client = CreateStoreLogic(DbAccess, _config, metadataSource); }
private VersionedDocumentReadResult <TDocument> ReadDocumentVersionAsync <TDocument>( string id, DocumentTypeMapping <TDocument> mapping, IList <VersionedDbDocument> documents) { var ordered = documents.OrderBy(x => x.Version).ToArray(); if (ordered.Length == 0 || ordered.Length > 2) { return(null); } var firstVersion = ordered[0]; var queriedVersion = ordered[ordered.Length - 1]; return(CreateReadResult(id, queriedVersion, mapping, firstVersion.Timestamp, queriedVersion.Timestamp)); }
/// <inheritdoc /> public async Task PurgeDocumentAsync <TDocument>(string id, DocumentTypeMapping <TDocument> mapping) { if (id == null) { throw new ArgumentNullException(nameof(id)); } var query = _queryClient.CreateQueryById(id, 1, mapping); var documents = await ExecuteQueryAsync(query); var document = documents.FirstOrDefault(); if (document != null) { await PurgeDocument(document, mapping); } }
public IQueryable <VersionedDocumentStoreClient.VersionedDbDocument> CreateQueryAllVersionsById <TDocument>( string id, DocumentTypeMapping <TDocument> mapping) { if (id == null) { throw new ArgumentNullException(nameof(id)); } if (mapping == null) { throw new ArgumentNullException(nameof(mapping)); } var idParameter = new DbParameter("id", id); var query = $"[x].{mapping.IdPropertyName} = @id"; return(CreateQuery(mapping, query, new[] { idParameter })); }
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)); }