49 lines
2.3 KiB
C#
49 lines
2.3 KiB
C#
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;
|
|
}
|
|
} |