Files
openF1-Manager/scripts/ApiModelSerializer.cs
2025-09-07 14:57:10 +02:00

96 lines
3.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Godot;
using Godot.Collections;
using openF1Manager.scripts;
public static class ApiModelSerializer
{
public static string ToQueryString(object model, string baseAddress)
{
var query = System.Web.HttpUtility.ParseQueryString(string.Empty);
foreach (var (key, value) in EnumerateKeyValues(model))
{
if (!string.IsNullOrWhiteSpace(value))
query[key] = value;
}
var queryString = query.ToString();
return string.IsNullOrEmpty(queryString) ? baseAddress : $"{baseAddress}?{queryString}";
}
public static void PopulateFromDictionary(object model, Godot.Collections.Dictionary dict)
{
var type = model.GetType();
foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (!prop.CanWrite) continue;
var attr = prop.GetCustomAttribute<ApiFieldAttribute>();
var key = attr?.Key ?? ToSnakeCase(prop.Name);
// Try snake_case first, then camelCase fallbacks
if (!TryGet(dict, key, out var str) && !TryGet(dict, SnakeToCamel(key), out str))
continue;
// You can add type conversions if needed; here we only set strings
if (prop.PropertyType == typeof(string) || prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(int) || prop.PropertyType == typeof(float))
prop.SetValue(model, str);
}
}
private static bool TryGet(Dictionary dict, string key, out string value)
{
if (dict.ContainsKey(key) && dict[key].VariantType != Variant.Type.Nil)
{
value = dict[key].ToString();
return true;
}
value = string.Empty;
return false;
}
private static IEnumerable<(string Key, string Value)> EnumerateKeyValues(object model)
{
var type = model.GetType();
foreach (var prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (!prop.CanRead) continue;
var value = prop.GetValue(model)?.ToString();
var attr = prop.GetCustomAttribute<ApiFieldAttribute>();
var key = attr?.Key ?? ToSnakeCase(prop.Name);
yield return (key, value);
}
}
private static string ToSnakeCase(string name)
{
var sb = new StringBuilder();
for (int i = 0; i < name.Length; i++)
{
var c = name[i];
sb.Append(i > 0 && char.IsUpper(c) ? "_" + char.ToLower(c) : c.ToString());
}
return sb.ToString();
}
private static string SnakeToCamel(string name)
{
var sb = new StringBuilder();
sb.Append(char.ToLower(name[0]));
for (int i = 1; i < name.Length; i++)
{
var c = name[i];
sb.Append(char.IsUpper(c) ? char.ToLower(c) : c);
}
return sb.ToString();
}
}