using InABox.Core; namespace InABox.Database; public delegate void LogEvent(LogType type, string message); public interface IProviderFactory { string URL { get; set; } Type[] Types { get; set; } void ForceRecreateViews(); void Start(); IProvider NewProvider(Logger logger); } public interface IProvider { Logger Logger { get; set; } IEnumerable List(Filter? filter = null, Columns? columns = null, SortOrder? sort = null, CoreRange? range = null) where T : Entity, new(); bool TableExists(); bool TableExists(Type t); bool TableExists(string name); CoreTable? GetTable(); CoreTable? GetTable(Type t); CoreTable? GetTable(string name); void DropTable(); void DropTable(Type t); void DropTable(string name); IEnumerable List(string sql); CoreTable Query(string sql); int Update(string sql); CoreTable Query(Filter? filter = null, Columns? columns = null, SortOrder? sort = null, CoreRange? range = null, bool log = false, bool distinct = false) where T : Entity, new(); CoreTable Query(Type type, IFilter? filter = null, IColumns? columns = null, ISortOrder? sort = null, CoreRange? range = null, bool log = false, bool distinct = false); /// /// Same as , but only for deleted items /// CoreTable QueryDeleted(Deletion deletion, Filter? filter = null, Columns? columns = null, SortOrder? sort = null, CoreRange? range = null, bool deleted = false) where T : Entity, new(); T[] Load(Filter? filter = null, SortOrder? sort = null, CoreRange? range = null) where T : Entity, new(); void Save(T entity) where T : Entity; void Save(IEnumerable entities) where T : Entity; void Save(Type type, Entity entity); void Save(Type type, IEnumerable entities); void Delete(T entity, string userID) where T : Entity, new(); void Delete(IEnumerable entities, string userID) where T : Entity, new(); void Purge(T entity) where T : Entity; void Purge(IEnumerable entities) where T : Entity; void Purge(Deletion deletion); void Recover(Deletion deletion); List GetDeletionTypes(Deletion deletion); } public static class ProviderExtensions { public static void EnsureColumns(this IProvider provider, TEntity entity, Columns columns) where TEntity : Entity, new() { var newColumns = Columns.None() .AddRange(columns.Where(x => !entity.HasColumn(x.Property))); if (newColumns.Count > 0) { var row = provider.Query(new Filter(x => x.ID).IsEqualTo(entity.ID), newColumns).Rows.FirstOrDefault(); row?.FillObject(entity); } } public static void EnsureColumns(this IProvider provider, ICollection entities, Columns columns) where TEntity : Entity, IRemotable, new() { var newColumns = Columns.None() .AddRange(columns.Where(x => entities.Any(entity => !entity.HasColumn(x.Property)))); if (newColumns.Count > 0) { newColumns.Add(x => x.ID); var table = provider.Query(new Filter(x => x.ID).InList(entities.Select(x => x.ID).ToArray()), newColumns); foreach(var row in table.Rows) { var id = row.Get(x => x.ID); var entity = entities.FirstOrDefault(x => x.ID == id); if(entity is null) { // Shouldn't happen, but just in case. continue; } row?.FillObject(entity); } } } private class ProviderQueryProvider(IProvider provider) : IQueryProvider where TEntity : Entity, new() { private IProvider Provider = provider; public CoreTable Query(Filter? filter = null, Columns? columns = null, SortOrder? sort = null, CoreRange? range = null) { return Provider.Query(filter, columns, sort, range); } } public static IQueryProvider QueryProvider(this IProvider provider) where TEntity : Entity, new() { return new ProviderQueryProvider(provider); } }