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}";
}
}