cd700dc758
DeepDrftWeb.Services → DeepDrftData; DeepDrftContent.Services → DeepDrftContent.Data. TrackEntity:BaseEntity, TrackRepository:Repository<>, TrackManager:Manager<>+ITrackService. Drops DeepDrftModels PagingParameters/PagedResult in favour of Models.Common.* from BlazorBlocks. InitialCreate migration captures full schema including is_deleted index.
126 lines
3.7 KiB
C#
126 lines
3.7 KiB
C#
using System.Collections;
|
|
using System.Text.Json;
|
|
|
|
namespace DeepDrftContent.Data.FileDatabase.Utils;
|
|
|
|
/// <summary>
|
|
/// A map implementation that uses structural equality for keys by serializing them to JSON.
|
|
/// This provides the same behavior as the TypeScript StructuralMap.
|
|
/// Optimized with caching to avoid repeated serialization.
|
|
/// </summary>
|
|
/// <typeparam name="TKey">The key type</typeparam>
|
|
/// <typeparam name="TValue">The value type</typeparam>
|
|
public class StructuralMap<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>> where TKey : notnull
|
|
{
|
|
private readonly Dictionary<string, KeyValuePair<TKey, TValue>> _innerMap = new();
|
|
private readonly Dictionary<TKey, string> _keyStringCache = new();
|
|
|
|
/// <summary>
|
|
/// Converts a key to its string representation for structural comparison
|
|
/// Uses caching to avoid expensive serialization on repeated lookups
|
|
/// </summary>
|
|
private string GetKeyString(TKey key)
|
|
{
|
|
if (key == null) return "null";
|
|
|
|
// For reference types, use cache to avoid repeated serialization
|
|
if (!typeof(TKey).IsValueType && _keyStringCache.TryGetValue(key, out var cached))
|
|
{
|
|
return cached;
|
|
}
|
|
|
|
var keyString = key switch
|
|
{
|
|
string s => s,
|
|
int or long or float or double or decimal => key.ToString()!,
|
|
_ => JsonSerializer.Serialize(key)
|
|
};
|
|
|
|
// Cache for reference types only (value types are cheap to convert)
|
|
if (!typeof(TKey).IsValueType)
|
|
{
|
|
_keyStringCache[key] = keyString;
|
|
}
|
|
|
|
return keyString;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets a key-value pair in the map
|
|
/// </summary>
|
|
public StructuralMap<TKey, TValue> Set(TKey key, TValue value)
|
|
{
|
|
var keyString = GetKeyString(key);
|
|
_innerMap[keyString] = new KeyValuePair<TKey, TValue>(key, value);
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value by key, or default if not found
|
|
/// </summary>
|
|
public TValue? Get(TKey key)
|
|
{
|
|
var keyString = GetKeyString(key);
|
|
return _innerMap.TryGetValue(keyString, out var pair) ? pair.Value : default;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the map contains the specified key
|
|
/// </summary>
|
|
public bool Has(TKey key)
|
|
{
|
|
var keyString = GetKeyString(key);
|
|
return _innerMap.ContainsKey(keyString);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a key-value pair from the map
|
|
/// </summary>
|
|
public bool Delete(TKey key)
|
|
{
|
|
var keyString = GetKeyString(key);
|
|
return _innerMap.Remove(keyString);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears all entries from the map
|
|
/// </summary>
|
|
public void Clear() => _innerMap.Clear();
|
|
|
|
/// <summary>
|
|
/// Gets the number of entries in the map
|
|
/// </summary>
|
|
public int Size => _innerMap.Count;
|
|
|
|
/// <summary>
|
|
/// Enumerates all key-value pairs
|
|
/// </summary>
|
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
|
{
|
|
return _innerMap.Values.GetEnumerator();
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
|
|
/// <summary>
|
|
/// Gets all keys in the map
|
|
/// </summary>
|
|
public IEnumerable<TKey> Keys => _innerMap.Values.Select(pair => pair.Key);
|
|
|
|
/// <summary>
|
|
/// Gets all values in the map
|
|
/// </summary>
|
|
public IEnumerable<TValue> Values => _innerMap.Values.Select(pair => pair.Value);
|
|
|
|
/// <summary>
|
|
/// Executes a callback for each key-value pair
|
|
/// </summary>
|
|
public void ForEach(Action<TValue, TKey, StructuralMap<TKey, TValue>> callback)
|
|
{
|
|
foreach (var (key, value) in this)
|
|
{
|
|
callback(value, key, this);
|
|
}
|
|
}
|
|
}
|