async Task <Entities.Document> ReindexDocumentAsync(Entities.Document document, long index) { var q = new DynamicQuery ( "select * from c where c.entity = @entity and c.instance = @instance " + "and c.projectId = @projectId and c.documentId = @documentId order by c.date.epoch desc", new { entity = Entities.DocumentVersion.Entity, instance = document.Instance, projectId = document.ProjectId, documentId = document.Identifier } ); var documentVersions = await GetDocumentVersionsAsync(q).ConfigureAwait(false); var docv = new List <Task>(); var di = new Uri(document.Identifier).ToKotoriDocumentIdentifier(); var docId = di.ProjectId.ToKotoriDocumentUri(di.DocumentType, di.DocumentTypeId, di.DocumentId, index).ToString(); foreach (var dv in documentVersions) { dv.DocumentId = docId; docv.Add(_repoDocumentVersion.UpsertAsync(dv)); } Task.WaitAll(docv.ToArray()); document.Identifier = docId; return(await _repoDocument.ReplaceAsync(document).ConfigureAwait(false)); }
async Task <bool> DeleteDocumentAsync(Entities.Document document) { var metaObj = JObject.FromObject(document.Meta); Dictionary <string, object> meta2 = metaObj.ToObject <Dictionary <string, object> >(); await DeleteDocumentVersionsAsync(document).ConfigureAwait(false); var result = await _repoDocument.DeleteAsync(document.Id).ConfigureAwait(false); var nonIndexedFields = new List <string>(); if (meta2 != null) { foreach (var key in meta2.Keys) { var q = new DynamicQuery ( "select count(1) as number from c where c.entity = @entity and c.instance = @instance " + $"and c.projectId = @projectId and is_defined(c.meta[\"{key}\"])", new { entity = Entities.Document.Entity, instance = document.Instance, projectId = document.ProjectId } ); var sql = q.ToSqlQuery(); var counts = await _repoDocumentCount.GetListAsync(q).ConfigureAwait(false); var n = counts.Sum(x => x.Number); if (n == 0) { nonIndexedFields.Add(key); } } if (nonIndexedFields.Any()) { var docType = await FindDocumentTypeAsync(document.Instance, new Uri(document.ProjectId), new Uri(document.DocumentTypeId)).ConfigureAwait(false); if (docType != null) { var indexes = docType.Indexes.ToList(); indexes.RemoveAll(i => nonIndexedFields.Any(i2 => i2.Equals(i.From, StringComparison.OrdinalIgnoreCase))); docType.Indexes = indexes; await _repoDocumentType.ReplaceAsync(docType).ConfigureAwait(false); } } } return(result); }
async Task <bool> DeleteDocumentVersionsAsync(Entities.Document document) { var q = new DynamicQuery ( "select c.id as Id from c where c.entity = @entity and c.instance = @instance " + "and c.projectId = @projectId and c.documentId = @documentId", new { entity = Entities.DocumentVersion.Entity, instance = document.Instance, projectId = document.ProjectId, documentId = document.Identifier } ); var items = await _repoDynamic.GetListAsync(q).ConfigureAwait(false); foreach (var item in items) { await _repoDynamic.DeleteAsync(item.Id).ConfigureAwait(false); } return(true); }
async Task <Entities.Document> UpsertDocumentAsync(Entities.Document document) { await CreateDocumentVersionAsync(document).ConfigureAwait(false); return(await _repoDocument.UpsertAsync(document).ConfigureAwait(false)); }
internal async Task <Entities.Document> FindDocumentByIdAsync(string instance, Uri projectId, Uri documentId, long?version) { // get actual version if (version == null) { var q = new DynamicQuery ( "select * from c where c.entity = @entity and c.instance = @instance and c.projectId = @projectId and c.identifier = @identifier", new { entity = Entities.Document.Entity, instance, projectId = projectId.ToString(), identifier = documentId.ToString() } ); var document = await _repoDocument.GetFirstOrDefaultAsync(q).ConfigureAwait(false); return(document); } // get document from snapshot var q2 = new DynamicQuery ( "select * from c where c.entity = @entity and c.instance = @instance and c.projectId = @projectId and c.documentId = @identifier and c.version = @version", new { entity = Entities.DocumentVersion.Entity, instance, projectId = projectId.ToString(), identifier = documentId.ToString(), version } ); var x = q2.ToSqlQuerySpec().ToSqlQuery(); var documentVersion = await _repoDocumentVersion.GetFirstOrDefaultAsync(q2).ConfigureAwait(false); if (documentVersion == null) { return(null); } var newDocument = new Entities.Document ( documentVersion.Instance, documentVersion.ProjectId, documentVersion.DocumentId, documentVersion.DocumentTypeId, documentVersion.Hash, documentVersion.Document.Slug, documentVersion.Document.OriginalMeta, documentVersion.Document.Meta, documentVersion.Document.Content, documentVersion.Document.Date == null ? (DateTime?)null : documentVersion.Document.Date.DateTime, documentVersion.Document.Draft, documentVersion.Version ); return(newDocument); }
public async Task <OperationResult> UpsertDocumentAsync(IUpsertDocument command) { var projectUri = command.ProjectId.ToKotoriProjectUri(); var documentTypeUri = command.ProjectId.ToKotoriDocumentTypeUri(command.DocumentType, command.DocumentTypeId); var documentUri = command.ProjectId.ToKotoriDocumentUri(command.DocumentType, command.DocumentTypeId, command.DocumentId, command.Index); var project = await FindProjectAsync(command.Instance, projectUri).ConfigureAwait(false); if (project == null) { throw new KotoriProjectException(command.ProjectId, "Project does not exist.") { StatusCode = System.Net.HttpStatusCode.NotFound } } ; if (command.DocumentType == Enums.DocumentType.Content) { var result = await UpsertDocumentHelperAsync ( command.CreateOnly, command.Instance, command.ProjectId, command.DocumentType, command.DocumentTypeId, command.DocumentId, command.Index, command.Content, command.Date, command.Draft ).ConfigureAwait(false); return(result); } if (command.DocumentType == Enums.DocumentType.Data) { var idx = command.Index; var data = new Data(command.DocumentId, command.Content); var documents = data.GetDocuments(); var sql = DocumentDbHelpers.CreateDynamicQueryForDocumentSearch ( command.Instance, projectUri, documentTypeUri, null, "count(1) as number", null, null, true, true ); var count = await CountDocumentsAsync(sql).ConfigureAwait(false); if (idx == null) { idx = count; } if (idx > count) { throw new KotoriDocumentException(command.DocumentId, $"When creating data document at a particular index, your index must be 0 - {count}."); } OperationResult lastResult = null; for (var dc = 0; dc < documents.Count; dc++) { var jo = JObject.FromObject(documents[dc]); var dic = jo.ToObject <Dictionary <string, object> >(); var doc = Markdown.ConstructDocument(dic, null); var finalIndex = idx == null ? dc : idx + dc; lastResult = await UpsertDocumentHelperAsync( command.CreateOnly, command.Instance, command.ProjectId, command.DocumentType, command.DocumentTypeId, command.DocumentId, finalIndex, doc, command.Date, command.Draft ); } return(lastResult); } throw new KotoriDocumentException(command.DocumentId, "Unknown document type."); } async Task <OperationResult> UpsertDocumentHelperAsync(bool createOnly, string instance, string projectId, Enums.DocumentType documentType, string documentTypeId, string documentId, long?index, string content, DateTime?date, bool?draft) { var projectUri = projectId.ToKotoriProjectUri(); var documentTypeUri = projectId.ToKotoriDocumentTypeUri(documentType, documentTypeId); var documentUri = projectId.ToKotoriDocumentUri(documentType, documentTypeId, documentId, index); var documentType2 = await FindDocumentTypeAsync(instance, projectUri, documentTypeUri).ConfigureAwait(false); var transformation = new Transformation(documentTypeUri.ToKotoriDocumentTypeIdentifier().DocumentTypeId, documentType2?.Transformations); var document = new Markdown(documentUri.ToKotoriDocumentIdentifier(), content, transformation, date, draft); var documentTypeId2 = documentTypeUri.ToKotoriDocumentTypeIdentifier(); IDocumentResult documentResult = null; documentResult = document.Process(); if (documentType == Enums.DocumentType.Content) { var slug = await FindDocumentBySlugAsync(instance, projectUri, documentResult.Slug, documentUri).ConfigureAwait(false); if (slug != null) { throw new KotoriDocumentException(documentId, $"Slug '{documentResult.Slug}' is already being used for another document."); } } documentType2 = await UpsertDocumentTypeAsync ( instance, documentTypeId2, new UpdateToken <dynamic>(DocumentHelpers.CleanUpMeta(documentResult.Meta), false), new UpdateToken <string>(null, true) ).ConfigureAwait(false); transformation = new Transformation(documentTypeUri.ToKotoriDocumentTypeIdentifier().DocumentTypeId, documentType2.Transformations); document = new Markdown(documentUri.ToKotoriDocumentIdentifier(), content, transformation, date, draft); documentResult = document.Process(); var d = await FindDocumentByIdAsync(instance, projectUri, documentUri, null).ConfigureAwait(false); var isNew = d == null; var id = d?.Id; if (!isNew) { if (createOnly && documentType == Enums.DocumentType.Content) { throw new KotoriDocumentException(documentId, "Document cannot be created. It already exists."); } } long version = 0; if (d != null) { version = d.Version + 1; } d = new Entities.Document ( instance, projectUri.ToString(), documentUri.ToString(), documentTypeUri.ToString(), documentResult.Hash, documentResult.Slug, documentResult.OriginalMeta, documentResult.Meta, documentResult.Content, documentResult.Date, documentResult.Draft, version ) { Id = id }; var newDocument = await UpsertDocumentAsync(d).ConfigureAwait(false); var result = new OperationResult(newDocument, isNew); return(result); } }