diff --git a/Pilz/Data/Json/JsonDataContainer.cs b/Pilz/Data/Json/JsonDataContainer.cs new file mode 100644 index 0000000..5428060 --- /dev/null +++ b/Pilz/Data/Json/JsonDataContainer.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; + +namespace Pilz.Data.Json; + +public abstract class JsonDataContainer +{ + [JsonProperty("Sets")] + protected readonly HashSet sets = []; + + public virtual HashSet? Set(bool allowCreate) where T : class, IDataObject + { + var list = sets.OfType>().FirstOrDefault(); + + if (list == null && allowCreate) + { + list = []; + sets.Add(list); + } + + return list; + } + + protected virtual JsonSerializer GetSerializer() + { + var serializer = JsonSerializer.CreateDefault(); + serializer.TypeNameHandling = TypeNameHandling.Auto; + return serializer; + } + + public abstract void Read(); + + public abstract void Flush(); +} diff --git a/Pilz/Data/Json/JsonDataManager.cs b/Pilz/Data/Json/JsonDataManager.cs new file mode 100644 index 0000000..f0e768d --- /dev/null +++ b/Pilz/Data/Json/JsonDataManager.cs @@ -0,0 +1,39 @@ +namespace Pilz.Data.Json; + +public class JsonDataManager(JsonDataContainer container) : DataManager +{ + public bool AutoFlush { get; set; } + + protected override T? FindEntity(int id) where T : class + { + return container.Set(false)?.FirstOrDefault(n => n.Id.Equals(id)); + } + + protected override IQueryable GetEntitySet() + { + return container.Set(false).AsQueryable(); + } + + protected override void RemoveEntity(T obj) + { + container.Set(false)?.Remove(obj); + } + + protected override void UpdateEntity(T obj) + { + var set = container.Set(true); + if (!set.Contains(obj)) + set.Add(obj); + } + + protected override void SaveChanges() + { + if (AutoFlush) + Flush(); + } + + public virtual void Flush() + { + container.Flush(); + } +} diff --git a/Pilz/Data/Json/JsonFileContainer.cs b/Pilz/Data/Json/JsonFileContainer.cs new file mode 100644 index 0000000..a30b23a --- /dev/null +++ b/Pilz/Data/Json/JsonFileContainer.cs @@ -0,0 +1,18 @@ +using System.IO; + +namespace Pilz.Data.Json; + +public class JsonFileContainer(string filePath) : JsonDataContainer +{ + public override void Read() + { + using var sw = new StreamReader(filePath); + GetSerializer().Populate(sw, this); + } + + public override void Flush() + { + using var sw = new StreamWriter(filePath, false); + GetSerializer().Serialize(sw, this); + } +} diff --git a/Pilz/Data/Json/JsonStreamContainer.cs b/Pilz/Data/Json/JsonStreamContainer.cs new file mode 100644 index 0000000..359c2e1 --- /dev/null +++ b/Pilz/Data/Json/JsonStreamContainer.cs @@ -0,0 +1,19 @@ +namespace Pilz.Data.Json; + +public class JsonStreamContainer(Stream stream) : JsonDataContainer +{ + public override void Read() + { + using var sw = new StreamReader(stream); + stream.Position = 0; + GetSerializer().Populate(sw, this); + } + + public override void Flush() + { + using var sw = new StreamWriter(stream); + stream.Position = 0; + GetSerializer().Serialize(sw, this); + stream.SetLength(stream.Position); + } +} diff --git a/Pilz/Data/Json/JsonVoidContainer.cs b/Pilz/Data/Json/JsonVoidContainer.cs new file mode 100644 index 0000000..f041485 --- /dev/null +++ b/Pilz/Data/Json/JsonVoidContainer.cs @@ -0,0 +1,14 @@ +namespace Pilz.Data.Json; + +public class JsonVoidContainer : JsonDataContainer +{ + public override void Read() + { + // Nothing todo here. + } + + public override void Flush() + { + // Nothing todo here. + } +} diff --git a/Pilz/Data/ObjectStore.cs b/Pilz/Data/ObjectStore.cs new file mode 100644 index 0000000..1b35548 --- /dev/null +++ b/Pilz/Data/ObjectStore.cs @@ -0,0 +1,107 @@ +using Newtonsoft.Json; + +namespace Pilz.Data; + +/// +/// An object store using keys to identifiy the objects. Can be used for caching. +/// +public class ObjectStore +{ + [JsonProperty("Objects")] + private readonly Dictionary objects = []; + + /// + /// Gets an object by the given ID and type identifier. It will be created if it doesn't exist yet. + /// + /// The type identifier of the object to return or create. + /// The key to identify the object. + /// Allow creation of the object if it doesn't exist yet. + /// + public virtual T Get(string key, bool allowCreate) + { + if (!objects.TryGetValue(key, out var cache)) + { + cache = Activator.CreateInstance(); + + if (cache != null) + objects.Add(key, cache); + } + + if (cache is not T cacheT) + throw new NullReferenceException("Cache could not be initialized."); + + return cacheT; + } + + /// + /// Gets an object by the given ID and type identifier. + /// + /// The type identifier of the object to return. + /// The key to identify the object. + /// + public virtual T Get(string key) + { + return Get(key, false); + } + + /// + /// Gets an object by the type identifier. + /// + /// + /// This method can be potentially unsafe if the same type is available multiple times in the store. If unsure, use the key identifier to identify the object as a safer way. + /// + /// The type identifier of the object to return. + /// + public virtual T Get() + { + return objects.Values.OfType().FirstOrDefault(); + } + + /// + /// Gets an object by the given ID and type identifier. It will be created if it doesn't exist yet. + /// + /// + /// The key to identify the object. + /// + public virtual object? Get(string key) + { + if (!objects.TryGetValue(key, out var cache)) + cache = null; + + return cache; + } + + /// + /// Removes an object by its key. + /// + /// The key to identify the object. + public virtual void Remove(string key) + { + objects.Remove(key); + } + + /// + /// Removes an object from the store by its key. + /// + /// The object to remove. + public virtual void Remove(object value) + { + var kvp = objects.FirstOrDefault(kvp => kvp.Value == value); + if (kvp.Key != null) + objects.Remove(kvp.Key); + } + + /// + /// Removes an object from the store by its key. + /// + /// + /// This method can be potentially unsafe if the same type is available multiple times in the store. If unsure, use the key identifier to identify the object as a safer way. + /// + /// The object to remove. + public virtual void Remove(T value) + { + var kvp = objects.FirstOrDefault(kvp => kvp.Value is T valueT && valueT.Equals(value)); + if (kvp.Key != null) + objects.Remove(kvp.Key); + } +} diff --git a/Pilz/Pilz.csproj b/Pilz/Pilz.csproj index 9361e1d..3a26265 100644 --- a/Pilz/Pilz.csproj +++ b/Pilz/Pilz.csproj @@ -5,7 +5,7 @@ latest enable annotations - 2.3.6 + 2.4.0