Fixes #29 by generating valid keys
This commit is contained in:
parent
d36a258392
commit
0e4a99332b
@ -42,21 +42,10 @@ public static class SectionProcessor
|
|||||||
public static async Task<ProcessorResult<Section>> AddSection(string text, string? parentKey)
|
public static async Task<ProcessorResult<Section>> AddSection(string text, string? parentKey)
|
||||||
{
|
{
|
||||||
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
|
||||||
|
|
||||||
// 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)}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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:
|
// In the case, when the user adds a section to the root, handle the insert differently:
|
||||||
if (string.IsNullOrWhiteSpace(parentKey))
|
if (string.IsNullOrWhiteSpace(parentKey))
|
||||||
{
|
{
|
||||||
|
@ -23,20 +23,9 @@ public static class TextElementProcessor
|
|||||||
var currentSection = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == currentSectionKey);
|
var currentSection = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == currentSectionKey);
|
||||||
if (currentSection is null)
|
if (currentSection is null)
|
||||||
throw new ArgumentOutOfRangeException(nameof(currentSectionKey));
|
throw new ArgumentOutOfRangeException(nameof(currentSectionKey));
|
||||||
|
|
||||||
// Remove any whitespaces from the element name, regardless of how many e.g. spaces the user typed:
|
|
||||||
var code = string.Join('_', elementName.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant();
|
|
||||||
|
|
||||||
// Check, if this key already exists:
|
// Generate a code:
|
||||||
if (await db.TextElements.AnyAsync(n => n.Section == currentSection && n.Code == code))
|
var code = await Utils.GenerateCode(elementName, db.TextElements, (n, code) => n.Section == currentSection && n.Code == code);
|
||||||
{
|
|
||||||
var rng = new Random();
|
|
||||||
while (await db.TextElements.AnyAsync(n => n.Section == currentSection && n.Code == code))
|
|
||||||
{
|
|
||||||
// Add a random number to the end of the key:
|
|
||||||
code += $"_{rng.Next(1, 10_000)}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var textElement = new TextElement
|
var textElement = new TextElement
|
||||||
{
|
{
|
||||||
|
49
I18N Commander/Processor/Utils.cs
Normal file
49
I18N Commander/Processor/Utils.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Processor;
|
||||||
|
|
||||||
|
internal static class Utils
|
||||||
|
{
|
||||||
|
private static readonly Random RNG = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a code out of this name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name where the code based on</param>
|
||||||
|
/// <param name="db">The data class</param>
|
||||||
|
/// <param name="selector">The selector to check, if that key already exists. The string parameter is the current code to check.</param>
|
||||||
|
/// <returns>The generated code</returns>
|
||||||
|
internal static async Task<string> GenerateCode<TDbSet>(string name, DbSet<TDbSet> db, Expression<Func<TDbSet, string, bool>> selector) where TDbSet : class
|
||||||
|
{
|
||||||
|
// Filter all non-alphanumeric characters from the name by allowing only A-Z, a-z, 0-9, and spaces from the ASCII table:
|
||||||
|
name = new string(name.Where(c => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '0' and <= '9' or ' ').ToArray());
|
||||||
|
|
||||||
|
// Remove any whitespaces from the element name, regardless of how many e.g. spaces the user typed:
|
||||||
|
var code = string.Join('_', name.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant();
|
||||||
|
|
||||||
|
//
|
||||||
|
// The Any() query want's an Expression<T, bool>, but we have an Expression<T, string, bool>, though.
|
||||||
|
// Therefore, we have to currying the string away:
|
||||||
|
var typeDbSet = Expression.Parameter(typeof(TDbSet), null);
|
||||||
|
var curriedSelector = Expression.Lambda<Func<TDbSet, bool>>(
|
||||||
|
Expression.Invoke(selector, typeDbSet, Expression.Constant(code)),
|
||||||
|
typeDbSet
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check, if this key already exists. If so, add a random number to the end of the key:
|
||||||
|
if (await db.AnyAsync(curriedSelector))
|
||||||
|
while (await db.AnyAsync(curriedSelector))
|
||||||
|
{
|
||||||
|
code += $"_{RNG.Next(1, 10_000)}";
|
||||||
|
|
||||||
|
// Due to the changed code & since the string is a constant, we have to re-currying the string away:
|
||||||
|
curriedSelector = Expression.Lambda<Func<TDbSet, bool>>(
|
||||||
|
Expression.Invoke(selector, typeDbSet, Expression.Constant(code)),
|
||||||
|
typeDbSet
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user