using DataModel.Database; using DataModel.Database.Common; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; namespace Processor; public static class SectionProcessor { /// /// Load one layer of the tree by using the specified depth: /// public static async Task> LoadLayer(int depth) { await using var db = ProcessorMeta.ServiceProvider.GetRequiredService(); var sections = await db.Sections.Where(n => n.Depth == depth).OrderBy(n => n.Id).ToListAsync(); // Ensure, that the database loaded the section's parent: foreach (var section in sections) await db.Entry(section).Reference(n => n.Parent).LoadAsync(); return sections; } /// /// Determine how deep the tree is. /// public static async ValueTask GetDepth() { await using var db = ProcessorMeta.ServiceProvider.GetRequiredService(); if(!await db.Sections.AnyAsync()) { return 0; } return await db.Sections.MaxAsync(s => s.Depth); } /// /// Compute the new sections key and its depth, then store the section in the database. /// public static async Task> AddSection(string text, string? parentKey) { await using var db = ProcessorMeta.ServiceProvider.GetRequiredService(); // Generate the key: var key = await Utils.GenerateCode(text, db.Sections, (n, key) => n.DataKey == key); // In the case, when the user adds a section to the root, handle the insert differently: if (string.IsNullOrWhiteSpace(parentKey)) { var rootSection = new Section { Depth = 0, DataKey = key, Parent = null, Name = text.Trim(), TextElements = new(), }; try { db.Sections.Add(rootSection); await db.SaveChangesAsync(); return new ProcessorResult
(rootSection); } catch (Exception e) { return e.ToProcessorResult
(); } } // Read the parent from the database: var parent = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == parentKey); if (parent is null) throw new ArgumentException($"The section's parent with key {parentKey} does not exist in the database."); // Add the new section to the database: var section = new Section { Name = text.Trim(), DataKey = key, Parent = parent, TextElements = new(), Depth = parent.Depth + 1, }; try { await db.Sections.AddAsync(section); await db.SaveChangesAsync(); return new ProcessorResult
(section); } catch (Exception e) { return e.ToProcessorResult
(); } } public static async Task RemoveSection(string selectedKey) { await using var db = ProcessorMeta.ServiceProvider.GetRequiredService(); await SectionProcessor.RemoveOneSectionAndItsChildren(db, selectedKey); await db.SaveChangesAsync(); } private static async Task RemoveOneSectionAndItsChildren(DataContext db, string selectedKey) { // Remove the section from the database: var section2Delete = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedKey); if (section2Delete is null) throw new ArgumentException($"The section with key {selectedKey} does not exist in the database."); // Next, remove all children of the section, and the children's children, etc.: var children = await db.Sections.Where(n => n.Parent == section2Delete).ToListAsync(); foreach (var child in children) await SectionProcessor.RemoveOneSectionAndItsChildren(db, child.DataKey); db.Sections.Remove(section2Delete); } public static async Task NumberChildren(string selectedKey) { await using var db = ProcessorMeta.ServiceProvider.GetRequiredService(); // Read the section from the database: var section = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedKey); if (section is null) throw new ArgumentException($"The section with key {selectedKey} does not exist in the database."); return await db.Sections.CountAsync(n => n.Parent == section); } public static async Task> RenameSection(string selectedNodeKey, string alteredName) { await using var db = ProcessorMeta.ServiceProvider.GetRequiredService(); // Read the section from the database: var section = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == selectedNodeKey); if (section is null) throw new ArgumentException($"The section with key {selectedNodeKey} does not exist in the database."); // Determine the new key: var newKey = string.Join('_', alteredName.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant(); // Check, if this key already exists: if (await db.Sections.AnyAsync(n => n.DataKey == newKey)) { var rng = new Random(); while (await db.Sections.AnyAsync(n => n.DataKey == newKey)) { // Add a random number to the end of the key: newKey += $"_{rng.Next(1, 10_000)}"; } } section.Name = alteredName; section.DataKey = newKey; try { await db.SaveChangesAsync(); return new ProcessorResult
(section); } catch (Exception e) { return e.ToProcessorResult
(); } } public static async Task
GetSection(string sectionKey) { await using var db = ProcessorMeta.ServiceProvider.GetRequiredService(); var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey); await db.Entry(section).Reference(n => n.Parent).LoadAsync(); return section; } public static async Task GetSectionPath(string sectionKey) { await using var db = ProcessorMeta.ServiceProvider.GetRequiredService(); var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey); // Ensure, that the database loaded the section's parent: await db.Entry(section).Reference(n => n.Parent).LoadAsync(); var path = section.Name; while (section.Parent != null) { section = await db.Sections.FirstAsync(n => n.DataKey == section.Parent.DataKey); // Ensure, that the database loaded the section's parent: await db.Entry(section).Reference(n => n.Parent).LoadAsync(); path = $"{section.Name}/{path}"; } return $"Section's path: {path}"; } }