Thorsten Sommer
630f014c1a
- Added .NET generator setting for the namespace to use - Added .NET generator setting to choose the default culture - Added get child section method to section processor - Added util to convert any string to a verbatim string literal - Removed redundant variables on exceptions
209 lines
7.8 KiB
C#
209 lines
7.8 KiB
C#
using DataModel.Database;
|
|
using DataModel.Database.Common;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
namespace Processor;
|
|
|
|
public static class SectionProcessor
|
|
{
|
|
/// <summary>
|
|
/// Load one layer of the tree by using the specified depth:
|
|
/// </summary>
|
|
public static async Task<List<Section>> LoadLayer(int depth)
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determine how deep the tree is.
|
|
/// </summary>
|
|
public static async ValueTask<int> GetDepth()
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
if(!await db.Sections.AnyAsync())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return await db.Sections.MaxAsync(s => s.Depth);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compute the new sections key and its depth, then store the section in the database.
|
|
/// </summary>
|
|
public static async Task<ProcessorResult<Section>> AddSection(string text, string? parentKey)
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
|
|
// 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<Section>(rootSection);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return e.ToProcessorResult<Section>();
|
|
}
|
|
}
|
|
|
|
// 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>(section);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return e.ToProcessorResult<Section>();
|
|
}
|
|
}
|
|
|
|
public static async Task RemoveSection(string selectedKey)
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
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<int> NumberChildren(string selectedKey)
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
|
|
// 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<ProcessorResult<Section>> RenameSection(string selectedNodeKey, string alteredName)
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
|
|
// 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>(section);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
return e.ToProcessorResult<Section>();
|
|
}
|
|
}
|
|
|
|
public static async Task<Section> GetSection(string sectionKey)
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
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<string> GetSectionPath(string sectionKey)
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
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}";
|
|
}
|
|
|
|
public static async Task<List<Section>> GetChildSections(string sectionKey)
|
|
{
|
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
|
var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey);
|
|
|
|
return await db.Sections.Where(n => n.Parent == section).ToListAsync();
|
|
}
|
|
} |