using System.Linq.Expressions; using System.Text; using Microsoft.EntityFrameworkCore; namespace Processor; internal static class Utils { private static readonly Random RNG = new(); /// /// Generates a code out of this name. /// /// The name where the code based on /// The data class /// The selector to check, if that key already exists. The string parameter is the current code to check. /// The generated code internal static async Task GenerateCode(string name, DbSet db, Expression> 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, but we have an Expression, though. // Therefore, we have to currying the string away: var typeDbSet = Expression.Parameter(typeof(TDbSet), null); var curriedSelector = Expression.Lambda>( 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>( Expression.Invoke(selector, typeDbSet, Expression.Constant(code)), typeDbSet ); } return code; } public static string MadeVerbatimStringLiteral(string text) { IEnumerable ConvertAll(string source) { foreach(var c in source) if(c == '"') { yield return '"'; yield return '"'; } else yield return c; } var sb = new StringBuilder(); foreach(var c in ConvertAll(text)) sb.Append(c); return sb.ToString(); } }