using DataModel.Database; using DataModel.Database.Common; using Microsoft.EntityFrameworkCore; namespace Processor; public static class SectionProcessor { /// /// Load one layer of the tree by using the specified depth: /// public static IAsyncEnumerable
LoadLayer(DataContext db, int depth) { return db.Sections.Where(n => n.Depth == depth).OrderBy(n => n.Id).AsAsyncEnumerable(); } /// /// Determine how deep the tree is. /// public static async ValueTask GetDepth(DataContext db) { 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(DataContext db, string text, string? parentKey) { // Remove any whitespaces from the section name, regardless of how many e.g. spaces the user typed: var key = string.Join('_', text.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant(); // Check, if this key already exists: if (await db.Sections.AnyAsync(n => n.DataKey == key)) { var rng = new Random(); while (await db.Sections.AnyAsync(n => n.DataKey == key)) { // Add a random number to the end of the key: key += $"_{rng.Next(1, 10_000)}"; } } // In the case, when the user adds a section to the root, handle the insert differently: if (string.IsNullOrEmpty(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) { 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(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 RemoveSection(db, child.DataKey); db.Sections.Remove(section2Delete); await db.SaveChangesAsync(); } public static async Task NumberChildren(DataContext db, string selectedKey) { // 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(DataContext db, string selectedNodeKey, string alteredName) { // 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 Section GetSection(DataContext db, string sectionKey) => db.Sections.First(n => n.DataKey == sectionKey); public static async Task GetSectionPath(DataContext db, string sectionKey) { 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}"; } }