You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
7.4 KiB
200 lines
7.4 KiB
// Author: Gockner, Simon
|
|
// Created: 2020-01-27
|
|
// Copyright(c) 2020 SimonG. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using GBase.Api;
|
|
using GBase.Attributes;
|
|
using GBase.Factories;
|
|
using GBase.FileHandling.Factories;
|
|
using GBase.Interfaces;
|
|
using GBase.Interfaces.FileHandling;
|
|
|
|
namespace GBase
|
|
{
|
|
/// <summary>
|
|
/// A <see cref="IGBase"/> table
|
|
/// </summary>
|
|
public class GBaseTable<T> : IGBaseTable<T> where T : INotifyGBaseEntryChanged
|
|
{
|
|
private readonly IFileHandler _fileHandler;
|
|
private readonly IGBaseColumnFactory _gBaseColumnFactory;
|
|
|
|
/// <summary>
|
|
/// A <see cref="IGBase"/> table
|
|
/// </summary>
|
|
public GBaseTable(IFileHandlerFactory fileHandlerFactory, IGBaseColumnFactory gBaseColumnFactory)
|
|
{
|
|
_fileHandler = fileHandlerFactory.Create();
|
|
_gBaseColumnFactory = gBaseColumnFactory;
|
|
|
|
Columns = new List<IGBaseColumn>();
|
|
Entries = new List<T>();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// The <see cref="System.Type"/> of the class that this <see cref="IGBaseTable"/> represents
|
|
/// </summary>
|
|
public Type Type { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The name of this <see cref="IGBaseTable"/>
|
|
/// </summary>
|
|
public string FolderName { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The <see cref="IGBaseColumn"/>s of this <see cref="IGBaseTable"/>
|
|
/// </summary>
|
|
public List<IGBaseColumn> Columns { get; }
|
|
|
|
/// <summary>
|
|
/// The entries of this <see cref="IGBaseTable"/>
|
|
/// </summary>
|
|
public List<T> Entries { get; }
|
|
|
|
|
|
/// <summary>
|
|
/// Initialize this <see cref="IGBase"/>
|
|
/// </summary>
|
|
/// <param name="type">The <see cref="System.Type"/> of the class that this <see cref="IGBaseTable"/> represents</param>
|
|
/// <param name="databasePath">The path to the database files</param>
|
|
/// <param name="folderName"></param>
|
|
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the asynchronous operation</param>
|
|
/// <returns>True if successful, false if not</returns>
|
|
public async Task<bool> Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken)
|
|
{
|
|
Type = type;
|
|
FolderName = folderName;
|
|
await _fileHandler.Init(databasePath, cancellationToken);
|
|
|
|
//TODO: Init columns list depending on GBaseColumnAttributes set for this GBaseTable
|
|
foreach (var property in type.GetProperties())
|
|
{
|
|
GBaseColumnAttribute gBaseColumnAttribute = property.GetCustomAttribute<GBaseColumnAttribute>();
|
|
if (gBaseColumnAttribute == null)
|
|
continue;
|
|
|
|
IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create();
|
|
AddColumn(gBaseColumn);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a given <see cref="IGBaseColumn"/> to this <see cref="IGBaseTable"/>
|
|
/// </summary>
|
|
/// <param name="column">The given <see cref="IGBaseColumn"/></param>
|
|
/// <returns>True if successful, false if not</returns>
|
|
public bool AddColumn(IGBaseColumn column) //TODO: if a column is added, it has to be added to every entry file as well
|
|
{
|
|
if (Columns.Contains(column))
|
|
return false;
|
|
|
|
Columns.Add(column);
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove a given <see cref="IGBaseColumn"/> from this <see cref="IGBaseTable"/>
|
|
/// </summary>
|
|
/// <param name="column">The given <see cref="IGBaseColumn"/></param>
|
|
/// <returns>True if successful, false if not</returns>
|
|
public bool RemoveColumn(IGBaseColumn column) //TODO: if a column is removed, it has to be removed from every entry file as well
|
|
{
|
|
if (!Columns.Contains(column))
|
|
return false;
|
|
|
|
return Columns.Remove(column);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add an entry that implements <see cref="INotifyGBaseEntryChanged"/> to this <see cref="IGBaseTable"/>
|
|
/// </summary>
|
|
/// <param name="entry">The entry implementing <see cref="INotifyGBaseEntryChanged"/></param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns>True if successful, false if not</returns>
|
|
public async Task<bool> AddEntry(T entry, CancellationToken cancellationToken)
|
|
{
|
|
Entries.Add(entry);
|
|
entry.GBaseEntryChanged += OnGBaseEntryChanged;
|
|
|
|
await _fileHandler.AddEntry(entry, this, cancellationToken);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove an entry that implements <see cref="INotifyGBaseEntryChanged"/> from this <see cref="IGBaseTable"/>
|
|
/// </summary>
|
|
/// <param name="entry">The entry implementing <see cref="INotifyGBaseEntryChanged"/></param>
|
|
/// <returns>True if successful, false if not</returns>
|
|
public async Task<bool> RemoveEntry(T entry)
|
|
{
|
|
if (!Entries.Contains(entry))
|
|
return false;
|
|
|
|
entry.GBaseEntryChanged -= OnGBaseEntryChanged;
|
|
|
|
await _fileHandler.RemoveEntry(entry);
|
|
|
|
return Entries.Remove(entry);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Modify the property of a given entry with the given value
|
|
/// </summary>
|
|
/// <param name="entry">The entry</param>
|
|
/// <param name="propertyName">The name of the property</param>
|
|
/// <param name="value">The new value to set</param>
|
|
/// <returns>True if successful, false if not</returns>
|
|
private bool ModifyEntry(object entry, string propertyName, object value) //TODO: Write to file
|
|
{
|
|
//don't need to change value of property in `Entries` list, the instance is saved there, any property change is already changed there as well
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A <see cref="IGBase"/> entry changed
|
|
/// </summary>
|
|
/// <param name="entry">The entry (sender)</param>
|
|
/// <param name="args">The <see cref="GBaseEntryChangedEventArgs"/></param>
|
|
private void OnGBaseEntryChanged(object entry, GBaseEntryChangedEventArgs args)
|
|
{
|
|
//TODO: Might change, depending on #23
|
|
bool success = ModifyEntry(entry, args.ColumnName, args.Value);
|
|
|
|
if (!success)
|
|
throw new Exception("Failed to handle EntryChanged"); //TODO: Decide what to do here
|
|
}
|
|
|
|
/// <summary>
|
|
/// The <see cref="IAsyncDisposable.DisposeAsync"/> method
|
|
/// </summary>
|
|
/// <returns>A <see cref="ValueTask"/> to await</returns>
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
await _fileHandler.DisposeAsync();
|
|
|
|
foreach (var column in Columns)
|
|
{
|
|
await column.DisposeAsync();
|
|
}
|
|
|
|
Columns.Clear();
|
|
|
|
foreach (var entry in Entries.ToList())
|
|
{
|
|
await RemoveEntry(entry);
|
|
}
|
|
|
|
Entries.Clear();
|
|
}
|
|
}
|
|
} |