Глобальный рефакторинг пространств имён
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NpgsqlTypes;
|
||||
using Pf2e.Database.Model.Common.I18n;
|
||||
|
||||
namespace Pf2e.Scrapper.Processors;
|
||||
|
||||
/// <summary>
|
||||
/// Класс для работы с JSON-объектом.
|
||||
/// </summary>
|
||||
/// <param name="name">Название объекта, ассоциированного с вводом.</param>
|
||||
/// <param name="input">JSON-объект, который будет использоваться для доступа к данным.</param>
|
||||
/// <param name="enumSolvers">[DI] Набор интерфейсов, разрешающих значения перечислений.</param>
|
||||
internal class ProcessorInput(string name, JObject input, IEnumerable<IEnumSolver> enumSolvers)
|
||||
{
|
||||
/// <summary>
|
||||
/// Название объекта, ассоциированного с вводом.
|
||||
/// </summary>
|
||||
public string Name { get; } = name;
|
||||
|
||||
/// <summary>
|
||||
/// Входящий JSON-объект, который содержит данные для обработки.
|
||||
/// </summary>
|
||||
public JObject Input { get; } = input;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейсы, разрешающие значения перечислений.
|
||||
/// </summary>
|
||||
public IEnumerable<IEnumSolver> EnumSolvers { get; } = enumSolvers;
|
||||
|
||||
/// <summary>
|
||||
/// Значение из JSON по заданному пути, которое обязательно должно существовать.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь в JSON.</param>
|
||||
/// <returns>Объект типа `T` или `null`, если не удалось найти значение.</returns>
|
||||
/// <exception cref="NullReferenceException">Если значение не найдено.</exception>
|
||||
public virtual T GetRequired<T>(string path)
|
||||
{
|
||||
JToken token =
|
||||
Input.SelectToken(path) ?? throw new NullReferenceException($"'{path}' is null");
|
||||
|
||||
return token.ToObject<T>() ?? throw new NullReferenceException($"'{path}' is null");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Значение из JSON по заданному пути, которое может не существовать.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь в JSON</param>
|
||||
/// <returns>Объект типа `T` или `null`, если значение не найдено</returns>
|
||||
public virtual T? GetOptional<T>(string path)
|
||||
{
|
||||
JToken? token = Input.SelectToken(path) ?? null;
|
||||
|
||||
return (token is null || token.Type == JTokenType.Null)
|
||||
? default!
|
||||
: token.ToObject<T>() ?? default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Значение из JSON по заданному пути с возможностью предоставить значение по умолчанию.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь в JSON.</param>
|
||||
/// <param name="defaultValue">Значение, которое возвращается, если значение не найдено.</param>
|
||||
/// <returns>Объект типа `T` или `defaultValue`, если значение не найдено.</returns>
|
||||
public virtual T GetOptional<T>(string path, T defaultValue)
|
||||
{
|
||||
JToken? token = Input.SelectToken(path) ?? null;
|
||||
if (token is null || token.Type == JTokenType.Null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return token.ToObject<T>() ?? defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Преобразование значения из JSON по заданному пути в перечисление с использованием `PgName` атрибута.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь в JSON.</param>
|
||||
/// <returns>Перечисление T или выбрасывает исключение, если значение не соответствует жодному варианту.</returns>
|
||||
public virtual T EnumRequired<T>(string path)
|
||||
where T : Enum
|
||||
{
|
||||
string value =
|
||||
GetOptional<string>(path)
|
||||
?? throw new NullReferenceException($"Value in path {path} null or not exists");
|
||||
|
||||
return Enum<T>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Преобразование значения из JSON по заданному пути в перечисление с возможностью предоставить значение по умолчанию.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь в JSON</param>
|
||||
/// <param name="defaultValue">Значение, которое возвращается, если значение не найдено.</param>
|
||||
/// <returns>Значение перечисления T или defaultValue</returns>
|
||||
public virtual T EnumOptional<T>(string path, T defaultValue)
|
||||
where T : Enum
|
||||
{
|
||||
string? value = GetOptional<string>(path);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Enum<T>(value);
|
||||
}
|
||||
catch (InvalidEnumStringException)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Преобразование значения из JSON по заданному пути в строку локализации для заданного типа локализации.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь в JSON.</param>
|
||||
/// <param name="type">Тип локализации.</param>
|
||||
/// <returns>Объект <see cref="LocaleString"/> с добавленным значением для заданного типа.</returns>
|
||||
public virtual LocaleString GetRequiredLocale(string path, LocaleType type)
|
||||
{
|
||||
return new() { [type] = GetRequired<string>(path) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Преобразование значения из JSON по заданному пути в строку локализации для заданного типа локализации.
|
||||
/// </summary>
|
||||
/// <param name="path">Путь в JSON.</param>
|
||||
/// <param name="type">Тип локализации.</param>
|
||||
/// <returns>Объект <see cref="LocaleString"/> или null, если значение не найдено.</returns>
|
||||
public virtual LocaleString? GetOptionalLocale(string path, LocaleType type)
|
||||
{
|
||||
string? value = GetOptional<string>(path);
|
||||
if (value is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new() { [type] = value };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Преобразование значения из JSON в перечисление.
|
||||
/// </summary>
|
||||
/// <param name="value">Значение, которое нужно преобразовать</param>
|
||||
/// <returns>Объект типа `T`, если преобразование успешно, иначе выбрасывает исключение</returns>
|
||||
public virtual T Enum<T>(string value)
|
||||
where T : Enum
|
||||
{
|
||||
IEnumerable<EnumSolver<T>> solvers = EnumSolvers
|
||||
.Where(solver => solver.GetType().IsAssignableTo(typeof(EnumSolver<T>)))
|
||||
.Cast<EnumSolver<T>>();
|
||||
|
||||
foreach (EnumSolver<T> solver in solvers)
|
||||
{
|
||||
T? result = solver.SolveEnum(value);
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (System.Reflection.FieldInfo field in typeof(T).GetFields())
|
||||
{
|
||||
List<string> variants = [field.Name];
|
||||
|
||||
if (
|
||||
Attribute.GetCustomAttribute(field, typeof(PgNameAttribute))
|
||||
is PgNameAttribute pgAttribute
|
||||
)
|
||||
{
|
||||
variants.Add(pgAttribute.PgName);
|
||||
}
|
||||
|
||||
if (variants.Contains(value))
|
||||
{
|
||||
return (T)field.GetValue(null)!;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidEnumStringException(typeof(T), value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создание контрольной суммы объекта.
|
||||
/// </summary>
|
||||
/// <param name="isLowercase">Использовать шестнадцатеричные цифры в нижнем регистре.</param>
|
||||
/// <returns>Контрольная сумма объекта.</returns>
|
||||
public string Md5(bool isLowercase = false)
|
||||
{
|
||||
byte[] byteHash = MD5.HashData(Encoding.UTF8.GetBytes(Input.ToString()));
|
||||
string hash = Convert.ToHexString(byteHash).Replace("-", "");
|
||||
return isLowercase ? hash.ToLower() : hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Исключение при неверном значении для перечисленния.
|
||||
/// </summary>
|
||||
/// <param name="type">Тип перечисленния.</param>
|
||||
/// <param name="value">Некорректное значение.</param>
|
||||
public class InvalidEnumStringException(Type type, string value)
|
||||
: Exception($"Invalid value '{value}' for enum type {type.FullName}.") { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс для решения значений перечислений.
|
||||
/// </summary>
|
||||
internal interface IEnumSolver { }
|
||||
|
||||
/// <summary>
|
||||
/// Абстрактный класс для разрешения значений перечислений.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEnum">Тип перечисления, который будет разрешаться.</typeparam>
|
||||
public abstract class EnumSolver<TEnum> : IEnumSolver
|
||||
where TEnum : Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// Словарь, содержащий данные для разрешения значений перечислений.
|
||||
/// </summary>
|
||||
public abstract Dictionary<string, TEnum> Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Метод для разрешения значения перечисления по строковому вводу.
|
||||
/// </summary>
|
||||
/// <param name="input">Строка, представляющая значение перечисления.</param>
|
||||
/// <returns>Элемент перечисления <typeparamref name="TEnum"/>, если найден; иначе <c>null</c>.</returns>
|
||||
public TEnum? SolveEnum(string input)
|
||||
{
|
||||
return Data.GetValueOrDefault(input);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user