Improve data handling #25, still work in progress
master
Simon G 5 years ago committed by GitHub
commit 23317c098e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .idea/.idea.GBase/.idea/encodings.xml
  2. 1
      GBase.sln.DotSettings
  3. 5
      GBase/Attributes/GBaseTableAttribute.cs
  4. 8
      GBase/DataHandling/Cache/XmlDataHandlerCache.cs
  5. 17
      GBase/DataHandling/Exceptions/InvalidXmlFileException.cs
  6. 13
      GBase/DataHandling/Factories/IDataHandlerFactory.cs
  7. 3
      GBase/DataHandling/Factories/IXmlDataReaderFactory.cs
  8. 4
      GBase/DataHandling/Factories/IXmlDataWriterFactory.cs
  9. 13
      GBase/DataHandling/Factories/Pool/IPoolItemFactory.cs
  10. 13
      GBase/DataHandling/Factories/Pool/IPoolRequestFactory.cs
  11. 14
      GBase/DataHandling/Factories/Pool/PoolItemFactory.cs
  12. 101
      GBase/DataHandling/Pool/DataHandlerPool.cs
  13. 19
      GBase/DataHandling/Pool/PoolItem.cs
  14. 18
      GBase/DataHandling/Pool/PoolRequest.cs
  15. 81
      GBase/DataHandling/XmlDataHandler.cs
  16. 65
      GBase/DataHandling/XmlDataReader.cs
  17. 156
      GBase/DataHandling/XmlDataWriter.cs
  18. 27
      GBase/Exceptions/InvalidTableTypeException.cs
  19. 23
      GBase/Exceptions/MissingTableException.cs
  20. 45
      GBase/Factories/GBaseTableFactory.cs
  21. 2
      GBase/Factories/IGBaseColumnFactory.cs
  22. 3
      GBase/Factories/IGBaseTableFactory.cs
  23. 17
      GBase/FileHandling/Exceptions/FileNotExistingException.cs
  24. 114
      GBase/FileHandling/FileHandler.cs
  25. 32
      GBase/FileHandling/GBaseFile.cs
  26. 59
      GBase/GBase.cs
  27. 409
      GBase/GBase.xml
  28. 6
      GBase/GBaseColumn.cs
  29. 47
      GBase/GBaseObject.cs
  30. 88
      GBase/GBaseTable.cs
  31. 17
      GBase/Installers/DataHandlingInstaller.cs
  32. 3
      GBase/Installers/GBaseInstaller.cs
  33. 6
      GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs
  34. 26
      GBase/Interfaces/DataHandling/IDataHandler.cs
  35. 14
      GBase/Interfaces/DataHandling/IDataReader.cs
  36. 28
      GBase/Interfaces/DataHandling/IDataWriter.cs
  37. 15
      GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs
  38. 12
      GBase/Interfaces/DataHandling/Pool/IPoolItem.cs
  39. 14
      GBase/Interfaces/DataHandling/Pool/IPoolRequest.cs
  40. 39
      GBase/Interfaces/FileHandling/IFileHandler.cs
  41. 19
      GBase/Interfaces/FileHandling/IGBaseFile.cs
  42. 8
      GBase/Interfaces/IGBase.cs
  43. 2
      GBase/Interfaces/IGBaseColumn.cs
  44. 60
      GBase/Interfaces/IGBaseTable.cs
  45. 41
      GBaseStructure.md
  46. 26
      Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs
  47. 163
      Test.GBase/DataHandling/XmlDataHandlerTest.cs
  48. 56
      Test.GBase/GBaseIntegrationTest/GBaseIntegrationTest.cs
  49. 26
      Test.GBase/GBaseIntegrationTest/Group.cs
  50. 15
      Test.GBase/GBaseIntegrationTest/IGroup.cs
  51. 14
      Test.GBase/GBaseIntegrationTest/IItem.cs
  52. 34
      Test.GBase/GBaseIntegrationTest/Item.cs
  53. 54
      Test.GBase/GBaseIntegrationTest/Model.cs
  54. 15
      Test.GBase/GBaseIntegrationTest/Settings.cs
  55. 20
      Test.GBase/GBaseTableIntegrationTest.cs
  56. 2
      Test.GBase/TestClasses/Foo.cs

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

@ -2,5 +2,6 @@
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderText/@EntryValue">Author: $USER_NAME$&#xD;
Created: $CREATED_YEAR$-$CREATED_MONTH$-$CREATED_DAY$&#xD;
Copyright(c) $CREATED_YEAR$ SimonG. All Rights Reserved.</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String></wpf:ResourceDictionary>

@ -13,6 +13,11 @@ namespace GBase.Attributes
[AttributeUsage(AttributeTargets.Class)]
public class GBaseTableAttribute : Attribute //TODO: Decide how to handle enums (as table or their own type)
{
public GBaseTableAttribute(string folderName)
{
FolderName = folderName;
}
public string FolderName { get; }
}
}

@ -4,7 +4,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using GBase.DataHandling.Cache.Factories;
using GBase.Interfaces.DataHandling.Cache;
@ -103,9 +105,11 @@ namespace GBase.DataHandling.Cache
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
public async Task<IEnumerable<TProperty>> TryGetValues<T, TProperty>(string propertyName)
public async Task<IEnumerable<TProperty>> TryGetValues<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken)
{
IXmlDataHandlerCacheEntry entry = _cache.FirstOrDefault(e => e.Type == typeof(T));
IDataHandlerCachePropertyEntry property = entry?.Properties.FirstOrDefault(p => p.PropertyName.Equals(propertyName));
@ -114,7 +118,7 @@ namespace GBase.DataHandling.Cache
if (!property.IsInitialized) //initialize property by reading the values from the xml
{
List<TProperty> values = (await _xmlDataReader.Read<T, TProperty>(propertyName))?.ToList();
List<TProperty> values = (await _xmlDataReader.Read<T, TProperty>(file, propertyName, cancellationToken))?.ToList();
if (values != null)
{
foreach (TProperty value in values.Where(value => !property.Values.Any(v => v.Equals(value))))

@ -0,0 +1,17 @@
// Author: Gockner, Simon
// Created: 2020-11-09
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase.DataHandling.Exceptions
{
public class InvalidXmlFileException : Exception
{
public InvalidXmlFileException(string message)
: base(message)
{
}
}
}

@ -0,0 +1,13 @@
// Author: Simon Gockner
// Created: 2020-09-19
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Interfaces.DataHandling;
namespace GBase.DataHandling.Factories
{
public interface IDataHandlerFactory
{
IDataHandler Create();
}
}

@ -14,8 +14,7 @@ namespace GBase.DataHandling.Factories
/// <summary>
/// Creates an <see cref="IXmlDataReader"/>
/// </summary>
/// <param name="path">The path to the xml file</param>
/// <returns>A newly created instance of the implementation for <see cref="IXmlDataReader"/></returns>
IXmlDataReader Create(string path);
IXmlDataReader Create();
}
}

@ -14,9 +14,7 @@ namespace GBase.DataHandling.Factories
/// <summary>
/// Creates an <see cref="IXmlDataWriter"/>
/// </summary>
/// <param name="path">The path to the xml file</param>
/// <param name="rootElementName">The root element name of the xml file</param>
/// <returns>A newly created instance of the implementation for <see cref="IXmlDataWriter"/></returns>
IXmlDataWriter Create(string path, string rootElementName);
IXmlDataWriter Create();
}
}

@ -0,0 +1,13 @@
// Author: Simon Gockner
// Created: 2020-09-19
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Interfaces.DataHandling.Pool;
namespace GBase.DataHandling.Factories.Pool
{
public interface IPoolItemFactory
{
IPoolItem<T> Create<T>(T item);
}
}

@ -0,0 +1,13 @@
// Author: Simon Gockner
// Created: 2020-09-19
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Interfaces.DataHandling.Pool;
namespace GBase.DataHandling.Factories.Pool
{
public interface IPoolRequestFactory
{
IPoolRequest Create(object requester);
}
}

@ -0,0 +1,14 @@
// Author: Simon Gockner
// Created: 2020-09-19
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.DataHandling.Pool;
using GBase.Interfaces.DataHandling.Pool;
namespace GBase.DataHandling.Factories.Pool
{
public class PoolItemFactory : IPoolItemFactory
{
public IPoolItem<T> Create<T>(T item) => new PoolItem<T>(item);
}
}

@ -0,0 +1,101 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using GBase.DataHandling.Factories;
using GBase.DataHandling.Factories.Pool;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Pool;
namespace GBase.DataHandling.Pool
{
public class DataHandlerPool : IDataHandlerPool
{
private readonly int _availableDataHandlers;
private readonly IPoolItemFactory _poolItemFactory;
private readonly IPoolRequestFactory _poolRequestFactory;
private readonly IDataHandlerFactory _dataHandlerFactory;
private readonly List<IPoolItem<IDataHandler>> _pool;
private readonly List<IPoolRequest> _waitingRequesters;
public DataHandlerPool(int availableDataHandlers,
IPoolItemFactory poolItemFactory,
IPoolRequestFactory poolRequestFactory,
IDataHandlerFactory dataHandlerFactory)
{
_availableDataHandlers = availableDataHandlers;
_poolItemFactory = poolItemFactory;
_poolRequestFactory = poolRequestFactory;
_dataHandlerFactory = dataHandlerFactory;
_pool = new List<IPoolItem<IDataHandler>>();
_waitingRequesters = new List<IPoolRequest>();
}
public async Task<IDataHandler> RequestDataHandler(object requester, bool overwrite, CancellationToken cancellationToken)
{
if (_pool.All(i => i.InUse) && _pool.Count == _availableDataHandlers) //no free dataHandlers available
return await WaitForDataHandler(requester, cancellationToken);
else if (_pool.All(i => i.InUse)) //every existing dataHandler is used -> create a new one
return CreateDataHandler(overwrite);
else //there are unused dataHandlers existing
return GetDataHandler();
}
private async Task<IDataHandler> WaitForDataHandler(object requester, CancellationToken cancellationToken)
{
IDataHandler dataHandler = null;
IPoolRequest request = _poolRequestFactory.Create(requester);
while (dataHandler == null)
{
if (_waitingRequesters.Contains(request) && _waitingRequesters.IndexOf(request) == 0) //request is in list and is first
{
if (_pool.Any(i => !i.InUse))
dataHandler = GetDataHandler();
else
await Task.Delay(1000, cancellationToken);
}
else if (_waitingRequesters.Contains(request)) //request is in list but not first
await Task.Delay(1000, cancellationToken);
else
_waitingRequesters.Add(request);
}
_waitingRequesters.Remove(request);
return dataHandler;
}
private IDataHandler CreateDataHandler(bool overwrite)
{
IPoolItem<IDataHandler> item = _poolItemFactory.Create(_dataHandlerFactory.Create());
item.Item.Init(overwrite);
_pool.Add(item);
item.InUse = true;
return item.Item;
}
private IDataHandler GetDataHandler()
{
IPoolItem<IDataHandler> item = _pool.First(i => !i.InUse);
item.InUse = true;
return item.Item;
}
public async ValueTask DisposeAsync()
{
while (_waitingRequesters.Any())
{
await Task.Delay(1000);
}
}
}
}

@ -0,0 +1,19 @@
// Author: Simon Gockner
// Created: 2020-09-19
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Interfaces.DataHandling.Pool;
namespace GBase.DataHandling.Pool
{
public class PoolItem<T> : IPoolItem<T>
{
public PoolItem(T item)
{
Item = item;
}
public T Item { get; }
public bool InUse { get; set; }
}
}

@ -0,0 +1,18 @@
// Author: Simon Gockner
// Created: 2020-09-19
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Interfaces.DataHandling.Pool;
namespace GBase.DataHandling.Pool
{
public class PoolRequest : IPoolRequest
{
public PoolRequest(object requester)
{
Requester = requester;
}
public object Requester { get; }
}
}

@ -5,12 +5,15 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using GBase.DataHandling.Cache.Factories;
using GBase.DataHandling.Factories;
using GBase.Helpers;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Xml;
using GBase.Interfaces.DataHandling.Xml.Cache;
@ -46,18 +49,15 @@ namespace GBase.DataHandling
/// A <see cref="IDataHandler"/> that handles its data in an xml file
/// </summary>
/// <param name="path">The path to the xml file</param>
/// <param name="rootElementName">The root element name of the xml file</param>
/// <param name="xmlDataReaderFactory">The <see cref="IXmlDataReader"/> factory</param>
/// <param name="xmlDataWriterFactory">The <see cref="IXmlDataWriter"/> factory</param>
/// <param name="xmlDataHandlerCacheFactory">The <see cref="IXmlDataHandlerCache"/> factory</param>
public XmlDataHandler(string path,
string rootElementName,
IXmlDataReaderFactory xmlDataReaderFactory,
public XmlDataHandler(IXmlDataReaderFactory xmlDataReaderFactory,
IXmlDataWriterFactory xmlDataWriterFactory,
IXmlDataHandlerCacheFactory xmlDataHandlerCacheFactory)
{
_xmlDataWriter = xmlDataWriterFactory.Create(path, rootElementName);
_xmlDataReader = xmlDataReaderFactory.Create(path);
_xmlDataWriter = xmlDataWriterFactory.Create();
_xmlDataReader = xmlDataReaderFactory.Create();
_cache = xmlDataHandlerCacheFactory.Create(_xmlDataReader);
}
@ -66,35 +66,58 @@ namespace GBase.DataHandling
/// Initialize the <see cref="XmlDataHandler"/>
/// </summary>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
public async Task<bool> Init(bool overwrite, CancellationToken cancellationToken)
public bool Init(bool overwrite)
{
if (_isInitialized)
return false;
_overwrite = overwrite;
if (!await _xmlDataWriter.Init(cancellationToken))
return false;
_isInitialized = true;
return true;
}
if (!await _xmlDataReader.Init(cancellationToken))
public async Task<bool> AddEntry<T>(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken)
{
if (!await _xmlDataWriter.InitFile(entryFile, table.Type.Name, cancellationToken))
return false;
_isInitialized = true;
foreach (var column in table.Columns)
{
//TODO: Set value for each column
PropertyInfo property = entry.GetType().GetProperty(column.Name);
if (property == null)
continue; //TODO: What to do in this case? (Shouldn't really happen...)
string valueString;
if (property.PropertyType != typeof(string) && property.GetValue(entry) is IEnumerable enumerable)
valueString = enumerable.ToGBaseString();
else
valueString = property.GetValue(entry).ToString();
await _xmlDataWriter.Write<T>(entryFile, property.Name, valueString, property.PropertyType, _overwrite, cancellationToken);
}
return true;
}
public Task<bool> RemoveEntry<T>(T entry)
{
throw new NotImplementedException();
}
/// <summary>
/// Set the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="entryFile"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task SetValue<T, TProperty>(string propertyName, TProperty value)
public async Task SetValue<T, TProperty>(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken)
{
if (value == null)
return;
@ -106,7 +129,7 @@ namespace GBase.DataHandling
valueString = value.ToString();
await _cache.SetValue<T, TProperty>(propertyName, value, _overwrite);
await _xmlDataWriter.Write<T, TProperty>(propertyName, valueString, _overwrite);
await _xmlDataWriter.Write<T, TProperty>(entryFile, propertyName, valueString, _overwrite, cancellationToken);
}
/// <summary>
@ -114,10 +137,12 @@ namespace GBase.DataHandling
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="entryFile"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task RemoveValue<T, TProperty>(string propertyName, TProperty value)
public async Task RemoveValue<T, TProperty>(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken)
{
if (value == null)
return;
@ -129,7 +154,7 @@ namespace GBase.DataHandling
valueString = value.ToString();
await _cache.TryRemoveValue<T, TProperty>(propertyName, value);
await _xmlDataWriter.Remove<T, TProperty>(propertyName, valueString);
await _xmlDataWriter.Remove<T, TProperty>(entryFile, propertyName, valueString, cancellationToken);
}
/// <summary>
@ -137,11 +162,13 @@ namespace GBase.DataHandling
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></param>
/// <returns>The value for the given property</returns>
public async Task<TProperty> GetValue<T, TProperty>(string propertyName)
public async Task<TProperty> GetValue<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken)
{
IEnumerable<TProperty> enumerable = await GetValues<T, TProperty>(propertyName);
IEnumerable<TProperty> enumerable = await GetValues<T, TProperty>(file, propertyName, cancellationToken);
return enumerable == null ? default : enumerable.FirstOrDefault();
}
@ -150,25 +177,17 @@ namespace GBase.DataHandling
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
public async Task<IEnumerable<TProperty>> GetValues<T, TProperty>(string propertyName)
public async Task<IEnumerable<TProperty>> GetValues<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken)
{
IEnumerable<TProperty> cachedValues = await _cache.TryGetValues<T, TProperty>(propertyName);
IEnumerable<TProperty> cachedValues = await _cache.TryGetValues<T, TProperty>(file, propertyName, cancellationToken);
if (cachedValues != null)
return cachedValues;
return await _xmlDataReader.Read<T, TProperty>(propertyName);
}
/// <summary>
/// Dispose used resources asynchronously
/// </summary>
/// <returns>A <see cref="ValueTask"/> to await</returns>
public async ValueTask DisposeAsync()
{
await _xmlDataReader.DisposeAsync();
await _xmlDataWriter.DisposeAsync();
return await _xmlDataReader.Read<T, TProperty>(file, propertyName, cancellationToken);
}
}
}

@ -10,6 +10,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using GBase.DataHandling.Exceptions;
using GBase.Helpers;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Xml;
@ -21,65 +22,34 @@ namespace GBase.DataHandling
/// </summary>
public class XmlDataReader : IXmlDataReader
{
private readonly FileStream _file;
private XDocument _xmlDocument;
private XElement _rootElement;
private bool _isInitialized;
private CancellationToken _cancellationToken;
/// <summary>
/// A <see cref="IDataReader"/> that reads from a xml file
/// </summary>
/// <param name="path">The path to the xml file</param>
public XmlDataReader(string path)
{
_file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
/// <summary>
/// Initialize the <see cref="XmlDataReader"/>
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
/// <exception cref="Exception">No root element found</exception>
public async Task<bool> Init(CancellationToken cancellationToken)
{
if (_isInitialized)
return false;
_cancellationToken = cancellationToken;
_xmlDocument = await XDocument.LoadAsync(_file, LoadOptions.None, _cancellationToken);
_rootElement = _xmlDocument.Root;
if (_rootElement == null)
throw new Exception("No root element found.");
_isInitialized = true;
return true;
}
/// <summary>
/// Read the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></param>
/// <returns>The data of the given property, null if no data found</returns>
/// <exception cref="ArgumentNullException"><paramref name="propertyName"/></exception>
/// <exception cref="InvalidOperationException">Invalid <see cref="Type"/> found for the read object</exception>
public async Task<IEnumerable<TProperty>> Read<T, TProperty>(string propertyName)
public async Task<IEnumerable<TProperty>> Read<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken)
//TODO: Read currently doesn't work for newly added items -> probably because file was loaded before new items were added; is probably not a problem -> cache
{
string typeName = typeof(T).FullName;
if (typeName == null)
throw new ArgumentNullException(nameof(typeName));
XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken);
file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
return await Task.Run(() =>
{
XElement typeElement = _rootElement.Element(typeName);
XElement propertyElement = typeElement?.Element(propertyName);
XElement rootElement = xmlDocument.Root;
if (rootElement == null)
throw new InvalidXmlFileException("No root element is set.");
XElement propertyElement = rootElement.Element(propertyName);
XAttribute propertyTypeAttribute = propertyElement?.Attribute(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME);
if (propertyTypeAttribute == null)
return null;
@ -98,16 +68,7 @@ namespace GBase.DataHandling
return values.Select(Enumerables.ConvertToGBaseEnumerable<TProperty>).ToList();
return values.Select(value => (TProperty)Convert.ChangeType(value, typeof(TProperty))).ToList();
}, _cancellationToken);
}
/// <summary>
/// Dispose used resources asynchronously
/// </summary>
/// <returns>A <see cref="ValueTask"/> to await</returns>
public async ValueTask DisposeAsync()
{
await _file.DisposeAsync();
}, cancellationToken);
}
}
}

@ -8,6 +8,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using GBase.DataHandling.Exceptions;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Xml;
@ -18,115 +19,96 @@ namespace GBase.DataHandling
/// </summary>
public class XmlDataWriter : IXmlDataWriter
{
private readonly string _rootElementName;
private readonly FileStream _file;
private XDocument _xmlDocument;
private XElement _rootElement;
private bool _isInitialized;
private CancellationToken _cancellationToken;
/// <summary>
/// A <see cref="IDataWriter"/> that writes to an xml file
/// </summary>
/// <param name="path">The path to the xml file</param>
/// <param name="rootElementName">The root element name of the xml file</param>
public XmlDataWriter(string path, string rootElementName)
{
_rootElementName = rootElementName;
_file = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
}
/// <summary>
/// Initialize the <see cref="XmlDataWriter"/>
/// </summary>
/// <param name="file"></param>
/// <param name="rootElementName"></param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
/// <exception cref="Exception">No root element found</exception>
public async Task<bool> Init(CancellationToken cancellationToken)
public async Task<bool> InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken)
{
if (_isInitialized)
return false;
//if the xml file isn't empty, return
if (file.Length > 3) //> 3 because of BOM
return true; //TODO: Don't return bool?
XDocument xmlDocument = new XDocument();
xmlDocument.Add(new XElement(rootElementName));
file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken);
_cancellationToken = cancellationToken;
//if the xml file is empty, write the root element
if (_file.Length <= 3) //<= 3 because of BOM
{
_xmlDocument = new XDocument();
_xmlDocument.Add(new XElement(_rootElementName));
_file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, cancellationToken);
}
else
{
_xmlDocument = await XDocument.LoadAsync(_file, LoadOptions.None, _cancellationToken);
}
_rootElement = _xmlDocument.Root;//?.Element(_rootElementName);
if (_rootElement == null)
throw new Exception("No root element found.");
_isInitialized = true;
return true;
}
/// <summary>
/// Write the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value of the property</param>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task Write<T, TProperty>(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken) =>
await Write<T>(file, propertyName, value, typeof(TProperty), overwrite, cancellationToken);
/// <summary>
/// Write the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value of the property</param>
/// <param name="propertyType"></param>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
/// <exception cref="ArgumentNullException"><paramref name="propertyName"/></exception>
public async Task Write<T, TProperty>(string propertyName, string value, bool overwrite)
/// <exception cref="InvalidXmlFileException">No root element is set</exception>
public async Task Write<T>(FileStream file, string propertyName, string value, Type propertyType, bool overwrite, CancellationToken cancellationToken)
{
string typeName = typeof(T).FullName;
if (typeName == null)
throw new ArgumentNullException(nameof(typeName));
_file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
XElement typeElement = _rootElement.Element(typeName);
if (typeElement != null) //type element already exists
file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken);
file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
XElement rootElement = xmlDocument.Root;
if (rootElement == null)
throw new InvalidXmlFileException("No root element is set.");
XElement propertyElement = rootElement.Element(propertyName);
if (propertyElement != null) //property element already exists
{
XElement propertyElement = typeElement.Element(propertyName);
if (propertyElement != null) //property element already exists
XElement valueElement = propertyElement.Element(XmlDataHandler.VALUE_ELEMENT_NAME);
if (valueElement != null && overwrite) //value element exists and overwrite is true
{
XElement valueElement = propertyElement.Element(XmlDataHandler.VALUE_ELEMENT_NAME);
if (valueElement != null && overwrite) //value element exists and overwrite is true
{
valueElement.Value = value; //overwrite existing value
}
else if (!overwrite && propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).Any(v => v.Value.Equals(value))) //no overwrite and same value exists already
{
XElement sameValueElement = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).First(v => v.Value.Equals(value));
sameValueElement.Remove(); //remove the already existing value from its current position
propertyElement.AddFirst(sameValueElement); //add it as the first element again
}
else //no value element exists or overwrite is false
propertyElement.AddFirst(new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //add a new value element
valueElement.Value = value; //overwrite existing value
}
else //property element doesn't exist
else if (!overwrite && propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).Any(v => v.Value.Equals(value))) //no overwrite and same value exists already
{
propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element
propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute
typeElement.Add(propertyElement); //create new property element with the value element
XElement sameValueElement = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).First(v => v.Value.Equals(value));
sameValueElement.Remove(); //remove the already existing value from its current position
propertyElement.AddFirst(sameValueElement); //add it as the first element again
}
else //no value element exists or overwrite is false
propertyElement.AddFirst(new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //add a new value element
}
else //type element doesn't exist
else //property element doesn't exist
{
XElement propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element
propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute
propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element
propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, propertyType.FullName); //add the property type attribute
_rootElement.Add(new XElement(typeName, propertyElement)); //create a new type element with the new property element
rootElement.Add(propertyElement); //create new property element with the value element
}
//TODO: check if whole file is overwritten (probably) -> performance issues for large files?
await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, _cancellationToken); //save the document with the added elements
await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); //save the document with the added elements
}
/// <summary>
@ -134,19 +116,27 @@ namespace GBase.DataHandling
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
/// <exception cref="ArgumentNullException"><paramref name="propertyName"/></exception>
public async Task Remove<T, TProperty>(string propertyName, string value)
/// <exception cref="InvalidXmlFileException">No root element is set</exception>
public async Task Remove<T, TProperty>(FileStream file, string propertyName, string value, CancellationToken cancellationToken)
{
string typeName = typeof(T).FullName;
if (typeName == null)
throw new ArgumentNullException(nameof(typeName));
_file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken);
file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
XElement typeElement = _rootElement.Element(typeName);
XElement rootElement = xmlDocument.Root;
if (rootElement == null)
throw new InvalidXmlFileException("No root element is set.");
XElement typeElement = rootElement.Element(typeName);
XElement propertyElement = typeElement?.Element(propertyName);
XElement valueElement = propertyElement?.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).FirstOrDefault(e => e.Value.Equals(value));
if (valueElement == null)
@ -155,17 +145,7 @@ namespace GBase.DataHandling
valueElement.Remove();
//TODO: check if whole file is overwritten (probably) -> performance issues for large files?
await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, _cancellationToken); //save the document with the added elements
}
/// <summary>
/// Dispose used resources asynchronously
/// </summary>
/// <returns>A <see cref="ValueTask"/> to await</returns>
public async ValueTask DisposeAsync()
{
await _xmlDocument.SaveAsync(_file, SaveOptions.None, _cancellationToken);
await _file.DisposeAsync();
await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); //save the document with the added elements
}
}
}

@ -0,0 +1,27 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using GBase.Api;
namespace GBase.Exceptions
{
/// <summary>
/// <see cref="Exception"/> that the passed table type doesn't implement <see cref="INotifyGBaseEntryChanged"/>"/>
/// </summary>
public class InvalidTableTypeException : Exception
{
/// <summary>
/// <see cref="Exception"/> that the passed table type doesn't implement <see cref="INotifyGBaseEntryChanged"/>"/>
/// </summary>
/// <param name="type">The table type</param>
public InvalidTableTypeException(Type type)
: base($"Table type ({type}) doesn't implement {nameof(INotifyGBaseEntryChanged)}.")
{
Type = type;
}
public Type Type { get; }
}
}

@ -0,0 +1,23 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase.Exceptions
{
/// <summary>
/// <see cref="Exception"/> that the table for the given <see cref="Type"/> is missing
/// </summary>
public class MissingTableException<T> : Exception
{
/// <summary>
/// <see cref="Exception"/> that the table for the given <see cref="Type"/> is missing
/// </summary>
public MissingTableException()
: base($"There is no table for type {typeof(T)}.")
{
}
}
}

@ -0,0 +1,45 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using GBase.FileHandling.Factories;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling.Pool;
using GBase.Interfaces.FileHandling;
namespace GBase.Factories
{
/// <summary>
/// Factory for the <see cref="IGBaseTable"/>
/// </summary>
public class GBaseTableFactory : IGBaseTableFactory
{
private readonly IFileHandlerFactory _fileHandlerFactory;
private readonly IDataHandlerPool _dataHandlerPool;
private readonly IGBaseColumnFactory _gBaseColumnFactory;
/// <summary>
/// Factory for the <see cref="IGBaseTable"/>
/// </summary>
/// <param name="fileHandlerFactory">Factory for the <see cref="IFileHandler"/></param>
/// <param name="dataHandlerPool"></param>
/// <param name="gBaseColumnFactory">Factory for the <see cref="IGBaseColumn"/></param>
public GBaseTableFactory(IFileHandlerFactory fileHandlerFactory, IDataHandlerPool dataHandlerPool, IGBaseColumnFactory gBaseColumnFactory)
{
_fileHandlerFactory = fileHandlerFactory;
_dataHandlerPool = dataHandlerPool;
_gBaseColumnFactory = gBaseColumnFactory;
}
/// <summary>
/// Creates an <see cref="IGBaseTable"/>
/// </summary>
/// <returns>A newly created instance of the implementation for <see cref="IGBaseTable"/></returns>
public IGBaseTable Create(Type type)
{
Type gBaseTableType = typeof(GBaseTable<>).MakeGenericType(type);
return (IGBaseTable) Activator.CreateInstance(gBaseTableType, _fileHandlerFactory, _dataHandlerPool, _gBaseColumnFactory);
}
}
}

@ -16,6 +16,6 @@ namespace GBase.Factories
/// Creates an <see cref="IGBaseColumn"/>
/// </summary>
/// <returns>A newly created instance of the implementation for <see cref="IGBaseColumn"/></returns>
IGBaseColumn Create();
IGBaseColumn Create(string name);
}
}

@ -3,6 +3,7 @@
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using GBase.Interfaces;
namespace GBase.Factories
@ -16,6 +17,6 @@ namespace GBase.Factories
/// Creates an <see cref="IGBaseTable"/>
/// </summary>
/// <returns>A newly created instance of the implementation for <see cref="IGBaseTable"/></returns>
IGBaseTable Create();
IGBaseTable Create(Type type);
}
}

@ -0,0 +1,17 @@
// Author: Gockner, Simon
// Created: 2020-11-10
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase.FileHandling.Exceptions
{
public class FileNotExistingException<T> : Exception
{
public FileNotExistingException()
: base($"File for the given type {typeof(T)} is not existing.")
{
}
}
}

@ -2,13 +2,13 @@
// Created: 2020-02-12
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using GBase.DataHandling.Factories;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Xml;
using GBase.FileHandling.Exceptions;
using GBase.Interfaces;
using GBase.Interfaces.FileHandling;
namespace GBase.FileHandling
@ -18,22 +18,22 @@ namespace GBase.FileHandling
/// </summary>
public class FileHandler : IFileHandler
{
private readonly IXmlDataHandlerFactory _dataHandlerFactory;
/// <summary>
/// The file extension for all GBase tables
/// </summary>
public const string GBASE_TABLE_FILE_EXTENSION = "gb";
private readonly List<IGBaseFile> _files;
private string _path;
/// <summary>
/// Internal file handler
/// </summary>
/// <param name="xmlDataHandlerFactory">Factory for the <see cref="IXmlDataHandler"/></param>
public FileHandler(IXmlDataHandlerFactory xmlDataHandlerFactory)
public FileHandler()
{
_dataHandlerFactory = xmlDataHandlerFactory;
_files = new List<IGBaseFile>();
}
/// <summary>
/// The <see cref="IDataHandler"/> of this <see cref="IFileHandler"/>
/// </summary>
private IDataHandler DataHandler { get; set; }
/// <summary>
/// Initialize this <see cref="IFileHandler"/>
/// </summary>
@ -42,60 +42,48 @@ namespace GBase.FileHandling
/// <returns>True if successful, false if not</returns>
public async Task<bool> Init(string path, CancellationToken cancellationToken)
{
DataHandler = _dataHandlerFactory.Create();
bool success = await DataHandler.Init(false, cancellationToken);
return success;
_path = path;
return true; //TODO: initialize existing files
}
/// <summary>
/// Set the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task SetValue<T, TProperty>(string propertyName, TProperty value)
public IGBaseFile CreateEntryFile<T>(T entry, IGBaseTable table)
{
await DataHandler.SetValue<T, TProperty>(propertyName, value);
}
string directoryPath = Path.Combine(_path, table.FolderName);
//create directory if it doesn't exist
Directory.CreateDirectory(directoryPath);
//create new entry file
string filePath = $"{Path.Combine(directoryPath, entry.ToString())}.{GBASE_TABLE_FILE_EXTENSION}";
FileStream entryFile = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); //TODO: Stream has to be disposed
IGBaseFile file = new GBaseFile(entry, entryFile, filePath);
_files.Add(file);
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task RemoveValue<T, TProperty>(string propertyName, TProperty value)
{
await DataHandler.RemoveValue<T, TProperty>(propertyName, value);
return file.UseFile();
}
/// <summary>
/// Get the value for the given property, if multiple values are set the first is returned
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>The value for the given property</returns>
public async Task<TProperty> GetValue<T, TProperty>(string propertyName)
public async Task<bool> DeleteEntryFile<T>(T entry)
{
return await DataHandler.GetValue<T, TProperty>(propertyName);
IGBaseFile file = _files.FirstOrDefault(f => f.Entry.Equals(entry));
if (file == default)
return false;
await file.File.DisposeAsync();
File.Delete(file.FilePath);
return true;
}
/// <summary>
/// Get all the values that are set for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
public async Task<IEnumerable<TProperty>> GetValues<T, TProperty>(string propertyName)
public async Task<IGBaseFile> RequestEntryFile<T>(T entry)
{
return await DataHandler.GetValues<T, TProperty>(propertyName);
IGBaseFile file = _files.FirstOrDefault(f => f.Entry.Equals(entry));
if (file == default)
throw new FileNotExistingException<T>();
if (file.InUse)
await Task.Delay(1000);
return file.UseFile();
}
/// <summary>
@ -104,7 +92,15 @@ namespace GBase.FileHandling
/// <returns>A <see cref="ValueTask"/> to await</returns>
public async ValueTask DisposeAsync()
{
await DataHandler.DisposeAsync();
while (_files.Any(f => f.InUse))
{
await Task.Delay(1000);
}
foreach (var file in _files)
{
await file.File.DisposeAsync();
}
}
}
}

@ -0,0 +1,32 @@
// Author: Gockner, Simon
// Created: 2020-11-10
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.IO;
using GBase.Interfaces.FileHandling;
namespace GBase.FileHandling
{
public class GBaseFile : IGBaseFile
{
public GBaseFile(object entry, FileStream file, string filePath)
{
Entry = entry;
File = file;
FilePath = filePath;
}
public object Entry { get; }
public FileStream File { get; }
public string FilePath { get; }
public bool InUse { get; private set; }
public IGBaseFile UseFile()
{
InUse = true;
return this;
}
public void Dispose() => InUse = false;
}
}

@ -9,6 +9,7 @@ using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using GBase.Attributes;
using GBase.Exceptions;
using GBase.Factories;
using GBase.Interfaces;
using GBase.Interfaces.Settings;
@ -20,11 +21,6 @@ namespace GBase
/// </summary>
public class GBase : IGBase
{
/// <summary>
/// The file extension for all GBase tables
/// </summary>
public const string GBASE_TABLE_FILE_EXTENSION = "gb"; //TODO: Find correct place for this const
private readonly IGBaseTableFactory _gBaseTableFactory;
/// <summary>
@ -74,8 +70,8 @@ namespace GBase
if (gBaseTableAttribute == null)
continue;
IGBaseTable gBaseTable = _gBaseTableFactory.Create();
await gBaseTable.Init(type, type.Name, Settings.DatabasePath, cancellationToken);
IGBaseTable gBaseTable = _gBaseTableFactory.Create(type);
await gBaseTable.Init(type, Settings.DatabasePath, gBaseTableAttribute.FolderName, cancellationToken);
AddTable(gBaseTable);
}
@ -93,13 +89,23 @@ namespace GBase
if (Tables.Contains(table))
return false;
if (Tables.Any(t => t.Name.Equals(table.Name)))
if (Tables.Any(t => t.FolderName.Equals(table.FolderName)))
return false;
Tables.Add(table);
return true;
}
public IGBaseTable<T> GetTable<T>()
{
if (Tables.OfType<IGBaseTable<T>>().Any())
return Tables.OfType<IGBaseTable<T>>().First();
throw new MissingTableException<T>();
// //TODO: This probably doesn't work, because even though t.Type : T, IGBaseTable<t.Type> !: IGBaseTable<T>
// return (IGBaseTable<T>) Convert.ChangeType(Tables.FirstOrDefault(t => typeof(T).IsAssignableFrom(t.Type)), typeof(IGBaseTable<T>)); //TestMe
}
/// <summary>
/// Removes a given <see cref="IGBaseTable"/> from this <see cref="GBase"/>
/// </summary>
@ -113,6 +119,43 @@ namespace GBase
return Tables.Remove(table);
}
public async Task<bool> AddEntry<T>(T entry, CancellationToken cancellationToken)
{
IGBaseTable<T> table = GetTable<T>();
if (table == null)
throw new MissingTableException<T>();
return await table.AddEntry(entry, cancellationToken);
}
public async Task SetValue<T, TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken)
{
IGBaseTable<T> table = GetTable<T>();
if (table == null)
throw new MissingTableException<T>();
await table.SetValue(entry, propertyName, value, cancellationToken);
}
public async Task<TProperty> GetValue<T, TProperty>(T entry, string propertyName, CancellationToken cancellationToken)
{
IGBaseTable<T> table = GetTable<T>();
if (table == null)
throw new MissingTableException<T>();
return await table.GetValue<TProperty>(entry, propertyName, cancellationToken);
}
public async Task<IEnumerable<TProperty>> GetValues<T, TProperty>(T entry, string propertyName, CancellationToken cancellationToken)
{
IGBaseTable<T> table = GetTable<T>();
if (table == null)
throw new MissingTableException<T>();
return await table.GetValues<TProperty>(entry, propertyName, cancellationToken);
}
/// <summary>
/// Dispose used resources asynchronously
/// </summary>

@ -87,13 +87,15 @@
<param name="value">The value to set</param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.DataHandling.Cache.XmlDataHandlerCache.TryGetValues``2(System.String)">
<member name="M:GBase.DataHandling.Cache.XmlDataHandlerCache.TryGetValues``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Try to get values from the cache for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> that implements the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="cancellationToken"></param>
<returns>An <see cref="T:System.Collections.Generic.IEnumerable`1"/> with all the values for the property</returns>
</member>
<member name="T:GBase.DataHandling.Cache.XmlDataHandlerCacheEntry">
@ -163,11 +165,10 @@
Factory for the <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataReader"/>
</summary>
</member>
<member name="M:GBase.DataHandling.Factories.IXmlDataReaderFactory.Create(System.String)">
<member name="M:GBase.DataHandling.Factories.IXmlDataReaderFactory.Create">
<summary>
Creates an <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataReader"/>
</summary>
<param name="path">The path to the xml file</param>
<returns>A newly created instance of the implementation for <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataReader"/></returns>
</member>
<member name="T:GBase.DataHandling.Factories.IXmlDataWriterFactory">
@ -175,12 +176,10 @@
Factory for the <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataWriter"/>
</summary>
</member>
<member name="M:GBase.DataHandling.Factories.IXmlDataWriterFactory.Create(System.String,System.String)">
<member name="M:GBase.DataHandling.Factories.IXmlDataWriterFactory.Create">
<summary>
Creates an <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataWriter"/>
</summary>
<param name="path">The path to the xml file</param>
<param name="rootElementName">The root element name of the xml file</param>
<returns>A newly created instance of the implementation for <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataWriter"/></returns>
</member>
<member name="T:GBase.DataHandling.XmlDataHandler">
@ -198,152 +197,142 @@
The attribute name of the value <see cref="T:System.Type"/> attribute
</summary>
</member>
<member name="M:GBase.DataHandling.XmlDataHandler.#ctor(System.String,System.String,GBase.DataHandling.Factories.IXmlDataReaderFactory,GBase.DataHandling.Factories.IXmlDataWriterFactory,GBase.DataHandling.Cache.Factories.IXmlDataHandlerCacheFactory)">
<member name="M:GBase.DataHandling.XmlDataHandler.#ctor(GBase.DataHandling.Factories.IXmlDataReaderFactory,GBase.DataHandling.Factories.IXmlDataWriterFactory,GBase.DataHandling.Cache.Factories.IXmlDataHandlerCacheFactory)">
<summary>
A <see cref="T:GBase.Interfaces.DataHandling.IDataHandler"/> that handles its data in an xml file
</summary>
<param name="path">The path to the xml file</param>
<param name="rootElementName">The root element name of the xml file</param>
<param name="xmlDataReaderFactory">The <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataReader"/> factory</param>
<param name="xmlDataWriterFactory">The <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataWriter"/> factory</param>
<param name="xmlDataHandlerCacheFactory">The <see cref="T:GBase.Interfaces.DataHandling.Xml.Cache.IXmlDataHandlerCache"/> factory</param>
</member>
<member name="M:GBase.DataHandling.XmlDataHandler.Init(System.Boolean,System.Threading.CancellationToken)">
<member name="M:GBase.DataHandling.XmlDataHandler.Init(System.Boolean)">
<summary>
Initialize the <see cref="T:GBase.DataHandling.XmlDataHandler"/>
</summary>
<param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the async operation</param>
<returns>Returns true if successful, false if not</returns>
</member>
<member name="M:GBase.DataHandling.XmlDataHandler.SetValue``2(System.String,``1)">
<member name="M:GBase.DataHandling.XmlDataHandler.SetValue``2(System.IO.FileStream,System.String,``1,System.Threading.CancellationToken)">
<summary>
Set the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> that implements the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="entryFile"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.DataHandling.XmlDataHandler.RemoveValue``2(System.String,``1)">
<member name="M:GBase.DataHandling.XmlDataHandler.RemoveValue``2(System.IO.FileStream,System.String,``1,System.Threading.CancellationToken)">
<summary>
Remove the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="entryFile"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.DataHandling.XmlDataHandler.GetValue``2(System.String)">
<member name="M:GBase.DataHandling.XmlDataHandler.GetValue``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Get the value for the given property, if multiple values are set the first is returned
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> that implements the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="cancellationToken"></param>
<returns>The value for the given property</returns>
</member>
<member name="M:GBase.DataHandling.XmlDataHandler.GetValues``2(System.String)">
<member name="M:GBase.DataHandling.XmlDataHandler.GetValues``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Get all the values that are set for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> that implements the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="cancellationToken"></param>
<returns>An <see cref="T:System.Collections.Generic.IEnumerable`1"/> with all the values for the property</returns>
</member>
<member name="M:GBase.DataHandling.XmlDataHandler.DisposeAsync">
<summary>
Dispose used resources asynchronously
</summary>
<returns>A <see cref="T:System.Threading.Tasks.ValueTask"/> to await</returns>
</member>
<member name="T:GBase.DataHandling.XmlDataReader">
<summary>
A <see cref="T:GBase.Interfaces.DataHandling.IDataReader"/> that reads from a xml file
</summary>
</member>
<member name="M:GBase.DataHandling.XmlDataReader.#ctor(System.String)">
<summary>
A <see cref="T:GBase.Interfaces.DataHandling.IDataReader"/> that reads from a xml file
</summary>
<param name="path">The path to the xml file</param>
</member>
<member name="M:GBase.DataHandling.XmlDataReader.Init(System.Threading.CancellationToken)">
<summary>
Initialize the <see cref="T:GBase.DataHandling.XmlDataReader"/>
</summary>
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the async operation</param>
<returns>Returns true if successful, false if not</returns>
<exception cref="T:System.Exception">No root element found</exception>
</member>
<member name="M:GBase.DataHandling.XmlDataReader.Read``2(System.String)">
<member name="M:GBase.DataHandling.XmlDataReader.Read``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Read the data of a property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/></typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="cancellationToken"></param>
<returns>The data of the given property, null if no data found</returns>
<exception cref="T:System.ArgumentNullException"><paramref name="propertyName"/></exception>
<exception cref="T:System.InvalidOperationException">Invalid <see cref="T:System.Type"/> found for the read object</exception>
</member>
<member name="M:GBase.DataHandling.XmlDataReader.DisposeAsync">
<summary>
Dispose used resources asynchronously
</summary>
<returns>A <see cref="T:System.Threading.Tasks.ValueTask"/> to await</returns>
</member>
<member name="T:GBase.DataHandling.XmlDataWriter">
<summary>
A <see cref="T:GBase.Interfaces.DataHandling.IDataWriter"/> that writes to a xml file
</summary>
</member>
<member name="M:GBase.DataHandling.XmlDataWriter.#ctor(System.String,System.String)">
<summary>
A <see cref="T:GBase.Interfaces.DataHandling.IDataWriter"/> that writes to an xml file
</summary>
<param name="path">The path to the xml file</param>
<param name="rootElementName">The root element name of the xml file</param>
</member>
<member name="M:GBase.DataHandling.XmlDataWriter.Init(System.Threading.CancellationToken)">
<member name="M:GBase.DataHandling.XmlDataWriter.InitFile(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Initialize the <see cref="T:GBase.DataHandling.XmlDataWriter"/>
</summary>
<param name="file"></param>
<param name="rootElementName"></param>
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the async operation</param>
<returns>Returns true if successful, false if not</returns>
<exception cref="T:System.Exception">No root element found</exception>
</member>
<member name="M:GBase.DataHandling.XmlDataWriter.Write``2(System.String,System.String,System.Boolean)">
<member name="M:GBase.DataHandling.XmlDataWriter.Write``2(System.IO.FileStream,System.String,System.String,System.Boolean,System.Threading.CancellationToken)">
<summary>
Write the data of a property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> that implements the property</typeparam>
<typeparam name="T">The <see cref="T:System.Type"/></typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value of the property</param>
<param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.DataHandling.XmlDataWriter.Write``1(System.IO.FileStream,System.String,System.String,System.Type,System.Boolean,System.Threading.CancellationToken)">
<summary>
Write the data of a property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> that implements the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value of the property</param>
<param name="propertyType"></param>
<param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
<exception cref="T:System.ArgumentNullException"><paramref name="propertyName"/></exception>
<exception cref="T:GBase.DataHandling.Exceptions.InvalidXmlFileException">No root element is set</exception>
</member>
<member name="M:GBase.DataHandling.XmlDataWriter.Remove``2(System.String,System.String)">
<member name="M:GBase.DataHandling.XmlDataWriter.Remove``2(System.IO.FileStream,System.String,System.String,System.Threading.CancellationToken)">
<summary>
Remove the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
<exception cref="T:System.ArgumentNullException"><paramref name="propertyName"/></exception>
</member>
<member name="M:GBase.DataHandling.XmlDataWriter.DisposeAsync">
<summary>
Dispose used resources asynchronously
</summary>
<returns>A <see cref="T:System.Threading.Tasks.ValueTask"/> to await</returns>
<exception cref="T:GBase.DataHandling.Exceptions.InvalidXmlFileException">No root element is set</exception>
</member>
<member name="T:GBase.Exceptions.InterfaceEnumerablePassedException">
<summary>
@ -361,12 +350,52 @@
The <see cref="T:System.Type"/> of the passed interface
</summary>
</member>
<member name="T:GBase.Exceptions.InvalidTableTypeException">
<summary>
<see cref="T:System.Exception"/> that the passed table type doesn't implement <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/>"/>
</summary>
</member>
<member name="M:GBase.Exceptions.InvalidTableTypeException.#ctor(System.Type)">
<summary>
<see cref="T:System.Exception"/> that the passed table type doesn't implement <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/>"/>
</summary>
<param name="type">The table type</param>
</member>
<member name="T:GBase.Exceptions.MissingTableException`1">
<summary>
<see cref="T:System.Exception"/> that the table for the given <see cref="T:System.Type"/> is missing
</summary>
</member>
<member name="M:GBase.Exceptions.MissingTableException`1.#ctor">
<summary>
<see cref="T:System.Exception"/> that the table for the given <see cref="T:System.Type"/> is missing
</summary>
</member>
<member name="T:GBase.Factories.GBaseTableFactory">
<summary>
Factory for the <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="M:GBase.Factories.GBaseTableFactory.#ctor(GBase.FileHandling.Factories.IFileHandlerFactory,GBase.Interfaces.DataHandling.Pool.IDataHandlerPool,GBase.Factories.IGBaseColumnFactory)">
<summary>
Factory for the <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="fileHandlerFactory">Factory for the <see cref="T:GBase.Interfaces.FileHandling.IFileHandler"/></param>
<param name="dataHandlerPool"></param>
<param name="gBaseColumnFactory">Factory for the <see cref="T:GBase.Interfaces.IGBaseColumn"/></param>
</member>
<member name="M:GBase.Factories.GBaseTableFactory.Create(System.Type)">
<summary>
Creates an <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<returns>A newly created instance of the implementation for <see cref="T:GBase.Interfaces.IGBaseTable"/></returns>
</member>
<member name="T:GBase.Factories.IGBaseColumnFactory">
<summary>
Factory for the <see cref="T:GBase.Interfaces.IGBaseColumn"/>
</summary>
</member>
<member name="M:GBase.Factories.IGBaseColumnFactory.Create">
<member name="M:GBase.Factories.IGBaseColumnFactory.Create(System.String)">
<summary>
Creates an <see cref="T:GBase.Interfaces.IGBaseColumn"/>
</summary>
@ -389,7 +418,7 @@
Factory for the <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="M:GBase.Factories.IGBaseTableFactory.Create">
<member name="M:GBase.Factories.IGBaseTableFactory.Create(System.Type)">
<summary>
Creates an <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
@ -411,15 +440,14 @@
Internal file handler
</summary>
</member>
<member name="M:GBase.FileHandling.FileHandler.#ctor(GBase.DataHandling.Factories.IXmlDataHandlerFactory)">
<member name="F:GBase.FileHandling.FileHandler.GBASE_TABLE_FILE_EXTENSION">
<summary>
Internal file handler
The file extension for all GBase tables
</summary>
<param name="xmlDataHandlerFactory">Factory for the <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataHandler"/></param>
</member>
<member name="P:GBase.FileHandling.FileHandler.DataHandler">
<member name="M:GBase.FileHandling.FileHandler.#ctor">
<summary>
The <see cref="T:GBase.Interfaces.DataHandling.IDataHandler"/> of this <see cref="T:GBase.Interfaces.FileHandling.IFileHandler"/>
Internal file handler
</summary>
</member>
<member name="M:GBase.FileHandling.FileHandler.Init(System.String,System.Threading.CancellationToken)">
@ -430,44 +458,6 @@
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the asynchronous operation</param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.FileHandling.FileHandler.SetValue``2(System.String,``1)">
<summary>
Set the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.FileHandling.FileHandler.RemoveValue``2(System.String,``1)">
<summary>
Remove the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.FileHandling.FileHandler.GetValue``2(System.String)">
<summary>
Get the value for the given property, if multiple values are set the first is returned
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="propertyName">The name of the property</param>
<returns>The value for the given property</returns>
</member>
<member name="M:GBase.FileHandling.FileHandler.GetValues``2(System.String)">
<summary>
Get all the values that are set for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="propertyName">The name of the property</param>
<returns>An <see cref="T:System.Collections.Generic.IEnumerable`1"/> with all the values for the property</returns>
</member>
<member name="M:GBase.FileHandling.FileHandler.DisposeAsync">
<summary>
Dispose used resources asynchronously
@ -479,11 +469,6 @@
The base class of the GBase database
</summary>
</member>
<member name="F:GBase.GBase.GBASE_TABLE_FILE_EXTENSION">
<summary>
The file extension for all GBase tables
</summary>
</member>
<member name="M:GBase.GBase.#ctor(GBase.Interfaces.Settings.IGBaseSettings,GBase.Factories.IGBaseTableFactory)">
<summary>
The base class of the GBase database
@ -540,7 +525,7 @@
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="M:GBase.GBaseColumn.#ctor">
<member name="M:GBase.GBaseColumn.#ctor(System.String)">
<summary>
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
@ -551,91 +536,96 @@
</summary>
<returns>A <see cref="T:System.Threading.Tasks.ValueTask"/> to await</returns>
</member>
<member name="T:GBase.GBaseTable">
<member name="T:GBase.GBaseObject`1">
<summary>
GBase object that supplies inheriting classes with methods to get data from a <see cref="T:GBase.Interfaces.IGBase"/>
</summary>
</member>
<member name="M:GBase.GBaseObject`1.#ctor(GBase.Interfaces.IGBase)">
<summary>
GBase object that allows conversion from <see cref="T:System.String"/>
</summary>
<exception cref="T:GBase.Exceptions.MissingTableException`1">No table for <typeparamref name="T"/> is existing</exception>
</member>
<member name="M:GBase.GBaseObject`1.InitializeFromString(System.String)">
<summary>
Initialize this <see cref="T:GBase.GBaseObject`1"/> from a given <see cref="T:System.String"/>
</summary>
<param name="string">The given <see cref="T:System.String"/></param>
</member>
<member name="T:GBase.GBaseTable`1">
<summary>
A <see cref="T:GBase.Interfaces.IGBase"/> table
</summary>
</member>
<member name="M:GBase.GBaseTable.#ctor(GBase.FileHandling.Factories.IFileHandlerFactory,GBase.Factories.IGBaseColumnFactory)">
<member name="M:GBase.GBaseTable`1.#ctor(GBase.FileHandling.Factories.IFileHandlerFactory,GBase.Interfaces.DataHandling.Pool.IDataHandlerPool,GBase.Factories.IGBaseColumnFactory)">
<summary>
A <see cref="T:GBase.Interfaces.IGBase"/> table
</summary>
<param name="fileHandlerFactory"></param>
<param name="dataHandlerPool">The <see cref="T:GBase.Interfaces.DataHandling.Pool.IDataHandlerPool"/></param>
<param name="gBaseColumnFactory"></param>
</member>
<member name="P:GBase.GBaseTable.Type">
<member name="P:GBase.GBaseTable`1.Type">
<summary>
The <see cref="T:System.Type"/> of the class that this <see cref="T:GBase.Interfaces.IGBaseTable"/> represents
</summary>
</member>
<member name="P:GBase.GBaseTable.Name">
<member name="P:GBase.GBaseTable`1.FolderName">
<summary>
The name of this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="P:GBase.GBaseTable.Columns">
<member name="P:GBase.GBaseTable`1.Columns">
<summary>
The <see cref="T:GBase.Interfaces.IGBaseColumn"/>s of this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="P:GBase.GBaseTable.Entries">
<member name="P:GBase.GBaseTable`1.Entries">
<summary>
The entries of this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="M:GBase.GBaseTable.Init(System.Type,System.String,System.String,System.Threading.CancellationToken)">
<member name="M:GBase.GBaseTable`1.Init(System.Type,System.String,System.String,System.Threading.CancellationToken)">
<summary>
Initialize this <see cref="T:GBase.Interfaces.IGBase"/>
</summary>
<param name="type">The <see cref="T:System.Type"/> of the class that this <see cref="T:GBase.Interfaces.IGBaseTable"/> represents</param>
<param name="name">The name of this <see cref="T:GBase.Interfaces.IGBaseTable"/></param>
<param name="databasePath">The path to the database files</param>
<param name="folderName"></param>
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the asynchronous operation</param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.GBaseTable.AddColumn(GBase.Interfaces.IGBaseColumn)">
<member name="M:GBase.GBaseTable`1.AddColumn(GBase.Interfaces.IGBaseColumn)">
<summary>
Add a given <see cref="T:GBase.Interfaces.IGBaseColumn"/> to this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="column">The given <see cref="T:GBase.Interfaces.IGBaseColumn"/></param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.GBaseTable.RemoveColumn(GBase.Interfaces.IGBaseColumn)">
<member name="M:GBase.GBaseTable`1.RemoveColumn(GBase.Interfaces.IGBaseColumn)">
<summary>
Remove a given <see cref="T:GBase.Interfaces.IGBaseColumn"/> from this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="column">The given <see cref="T:GBase.Interfaces.IGBaseColumn"/></param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.GBaseTable.AddEntry(GBase.Api.INotifyGBaseEntryChanged)">
<member name="M:GBase.GBaseTable`1.AddEntry(`0,System.Threading.CancellationToken)">
<summary>
Add an entry that implements <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/> to this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/></param>
<param name="cancellationToken"></param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.GBaseTable.RemoveEntry(GBase.Api.INotifyGBaseEntryChanged)">
<member name="M:GBase.GBaseTable`1.RemoveEntry(`0)">
<summary>
Remove an entry that implements <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/> from this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/></param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.GBaseTable.ModifyEntry(System.Object,System.String,System.Object)">
<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>
</member>
<member name="M:GBase.GBaseTable.OnGBaseEntryChanged(System.Object,GBase.Api.GBaseEntryChangedEventArgs)">
<summary>
A <see cref="T:GBase.Interfaces.IGBase"/> entry changed
</summary>
<param name="entry">The entry (sender)</param>
<param name="args">The <see cref="T:GBase.Api.GBaseEntryChangedEventArgs"/></param>
</member>
<member name="M:GBase.GBaseTable.DisposeAsync">
<member name="M:GBase.GBaseTable`1.DisposeAsync">
<summary>
The <see cref="M:System.IAsyncDisposable.DisposeAsync"/> method
</summary>
@ -707,13 +697,15 @@
<param name="value">The value to set</param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.Cache.IDataHandlerCache.TryGetValues``2(System.String)">
<member name="M:GBase.Interfaces.DataHandling.Cache.IDataHandlerCache.TryGetValues``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Try to get values from the cache for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> that implements the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="cancellationToken"></param>
<returns>An <see cref="T:System.Collections.Generic.IEnumerable`1"/> with all the values for the property</returns>
</member>
<member name="T:GBase.Interfaces.DataHandling.Cache.IDataHandlerCacheEntry">
@ -756,50 +748,57 @@
Interface for data handlers to implement
</summary>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.Init(System.Boolean,System.Threading.CancellationToken)">
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.Init(System.Boolean)">
<summary>
Initialize the <see cref="T:GBase.Interfaces.DataHandling.IDataHandler"/>
</summary>
<param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the async operation</param>
<returns>Returns true if successful, false if not</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.SetValue``2(System.String,``1)">
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.SetValue``2(System.IO.FileStream,System.String,``1,System.Threading.CancellationToken)">
<summary>
Set the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="entryFile"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.RemoveValue``2(System.String,``1)">
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.RemoveValue``2(System.IO.FileStream,System.String,``1,System.Threading.CancellationToken)">
<summary>
Remove the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="entryFile"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.GetValue``2(System.String)">
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.GetValue``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Get the value for the given property, if multiple values are set the first is returned
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="cancellationToken"></param>
<returns>The value for the given property</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.GetValues``2(System.String)">
<member name="M:GBase.Interfaces.DataHandling.IDataHandler.GetValues``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Get all the values that are set for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="cancellationToken"></param>
<returns>An <see cref="T:System.Collections.Generic.IEnumerable`1"/> with all the values for the property</returns>
</member>
<member name="T:GBase.Interfaces.DataHandling.IDataReader">
@ -807,20 +806,15 @@
Interface for data readers to implement
</summary>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataReader.Init(System.Threading.CancellationToken)">
<summary>
Initialize the <see cref="T:GBase.Interfaces.DataHandling.IDataReader"/>
</summary>
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the async operation</param>
<returns>Returns true if successful, false if not</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataReader.Read``2(System.String)">
<member name="M:GBase.Interfaces.DataHandling.IDataReader.Read``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Read the data of a property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/></typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="cancellationToken"></param>
<returns>The data of the given property, null if no data found</returns>
</member>
<member name="T:GBase.Interfaces.DataHandling.IDataWriter">
@ -828,32 +822,51 @@
Interface for data writers to implement
</summary>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataWriter.Init(System.Threading.CancellationToken)">
<member name="M:GBase.Interfaces.DataHandling.IDataWriter.InitFile(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary>
Initialize the <see cref="T:GBase.Interfaces.DataHandling.IDataWriter"/>
</summary>
<param name="file"></param>
<param name="rootElementName"></param>
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the async operation</param>
<returns>Returns true if successful, false if not</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataWriter.Write``2(System.String,System.String,System.Boolean)">
<member name="M:GBase.Interfaces.DataHandling.IDataWriter.Write``2(System.IO.FileStream,System.String,System.String,System.Boolean,System.Threading.CancellationToken)">
<summary>
Write the data of a property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/></typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value of the property</param>
<param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataWriter.Remove``2(System.String,System.String)">
<member name="M:GBase.Interfaces.DataHandling.IDataWriter.Write``1(System.IO.FileStream,System.String,System.String,System.Type,System.Boolean,System.Threading.CancellationToken)">
<summary>
Write the data of a property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/></typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value of the property</param>
<param name="propertyType"></param>
<param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.Interfaces.DataHandling.IDataWriter.Remove``2(System.IO.FileStream,System.String,System.String,System.Threading.CancellationToken)">
<summary>
Remove the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="file"></param>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<param name="cancellationToken"></param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="T:GBase.Interfaces.DataHandling.Xml.Cache.IXmlDataHandlerCache">
@ -899,44 +912,6 @@
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the asynchronous operation</param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.Interfaces.FileHandling.IFileHandler.SetValue``2(System.String,``1)">
<summary>
Set the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.Interfaces.FileHandling.IFileHandler.RemoveValue``2(System.String,``1)">
<summary>
Remove the value for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="propertyName">The name of the property</param>
<param name="value">The value to set</param>
<returns>A <see cref="T:System.Threading.Tasks.Task"/> to await</returns>
</member>
<member name="M:GBase.Interfaces.FileHandling.IFileHandler.GetValue``2(System.String)">
<summary>
Get the value for the given property, if multiple values are set the first is returned
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="propertyName">The name of the property</param>
<returns>The value for the given property</returns>
</member>
<member name="M:GBase.Interfaces.FileHandling.IFileHandler.GetValues``2(System.String)">
<summary>
Get all the values that are set for the given property
</summary>
<typeparam name="T">The <see cref="T:System.Type"/> of the property</typeparam>
<typeparam name="TProperty">The <see cref="T:System.Type"/> of the property</typeparam>
<param name="propertyName">The name of the property</param>
<returns>An <see cref="T:System.Collections.Generic.IEnumerable`1"/> with all the values for the property</returns>
</member>
<member name="T:GBase.Interfaces.IGBase">
<summary>
The base class of the GBase database
@ -985,6 +960,26 @@
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="P:GBase.Interfaces.IGBaseTable`1.Entries">
<summary>
The entries of this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="M:GBase.Interfaces.IGBaseTable`1.AddEntry(`0,System.Threading.CancellationToken)">
<summary>
Add an entry that implements <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/> to this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/></param>
<param name="cancellationToken"></param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.Interfaces.IGBaseTable`1.RemoveEntry(`0)">
<summary>
Remove an entry that implements <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/> from this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/></param>
<returns>True if successful, false if not</returns>
</member>
<member name="T:GBase.Interfaces.IGBaseTable">
<summary>
A <see cref="T:GBase.Interfaces.IGBase"/> table
@ -995,7 +990,7 @@
The <see cref="T:System.Type"/> of the class that this <see cref="T:GBase.Interfaces.IGBaseTable"/> represents
</summary>
</member>
<member name="P:GBase.Interfaces.IGBaseTable.Name">
<member name="P:GBase.Interfaces.IGBaseTable.FolderName">
<summary>
The name of this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
@ -1005,19 +1000,15 @@
The <see cref="T:GBase.Interfaces.IGBaseColumn"/>s of this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="P:GBase.Interfaces.IGBaseTable.Entries">
<summary>
The entries of this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="M:GBase.Interfaces.IGBaseTable.Init(System.Type,System.String,System.String,System.Threading.CancellationToken)">
<summary>
Initialize this <see cref="T:GBase.Interfaces.IGBase"/>
</summary>
<param name="type">The <see cref="T:System.Type"/> of the class that this <see cref="T:GBase.Interfaces.IGBaseTable"/> represents</param>
<param name="name">The name of this <see cref="T:GBase.Interfaces.IGBaseTable"/></param>
/// <param name="databasePath">The path to the database files</param>
<param name="databasePath">The path to the database files</param>
<param name="folderName"></param>
<param name="cancellationToken">A <see cref="T:System.Threading.CancellationToken"/> to cancel the asynchronous operation</param>
///
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.Interfaces.IGBaseTable.AddColumn(GBase.Interfaces.IGBaseColumn)">
@ -1034,20 +1025,6 @@
<param name="column">The given <see cref="T:GBase.Interfaces.IGBaseColumn"/></param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.Interfaces.IGBaseTable.AddEntry(GBase.Api.INotifyGBaseEntryChanged)">
<summary>
Add an entry that implements <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/> to this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/></param>
<returns>True if successful, false if not</returns>
</member>
<member name="M:GBase.Interfaces.IGBaseTable.RemoveEntry(GBase.Api.INotifyGBaseEntryChanged)">
<summary>
Remove an entry that implements <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/> from this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/></param>
<returns>True if successful, false if not</returns>
</member>
<member name="T:GBase.Interfaces.Settings.IGBaseSettings">
<summary>
Settings of a <see cref="T:GBase.Interfaces.IGBase"/> instance

@ -16,10 +16,12 @@ namespace GBase
/// <summary>
/// A column of a <see cref="IGBaseTable"/>
/// </summary>
public GBaseColumn()
public GBaseColumn(string name)
{
Name = name;
}
public string Name { get; }
/// <summary>
/// The <see cref="IAsyncDisposable.DisposeAsync"/> method

@ -0,0 +1,47 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using GBase.Api;
using GBase.Exceptions;
using GBase.Interfaces;
namespace GBase
{
/// <summary>
/// GBase object that supplies inheriting classes with methods to get data from a <see cref="IGBase"/>
/// </summary>
public abstract class GBaseObject<T> : IGBaseObject
{
private readonly IGBaseTable<T> _gBaseTable;
/// <summary>
/// GBase object that allows conversion from <see cref="string"/>
/// </summary>
/// <exception cref="MissingTableException{T}">No table for <typeparamref name="T"/> is existing</exception>
protected GBaseObject(IGBase gBase)
{
_gBaseTable = gBase.GetTable<T>();
if (_gBaseTable == null)
throw new MissingTableException<T>();
}
protected async Task SetValue<TProperty>(T @this, string propertyName, TProperty value, CancellationToken cancellationToken) =>
await _gBaseTable.SetValue(@this, propertyName, value, cancellationToken);
protected async Task<TProperty> GetValue<TProperty>(T @this, string propertyName, CancellationToken cancellationToken) =>
await _gBaseTable.GetValue<TProperty>(@this, propertyName, cancellationToken);
protected async Task<IEnumerable<TProperty>> GetValues<TProperty>(T @this, string propertyName, CancellationToken cancellationToken) =>
await _gBaseTable.GetValues<TProperty>(@this, propertyName, cancellationToken);
/// <summary>
/// Initialize this <see cref="GBaseObject{T}"/> from a given <see cref="string"/>
/// </summary>
/// <param name="string">The given <see cref="string"/></param>
public abstract void InitializeFromString(string @string);
}
}

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
@ -14,6 +13,8 @@ using GBase.Attributes;
using GBase.Factories;
using GBase.FileHandling.Factories;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Pool;
using GBase.Interfaces.FileHandling;
namespace GBase
@ -21,21 +22,26 @@ namespace GBase
/// <summary>
/// A <see cref="IGBase"/> table
/// </summary>
public class GBaseTable : IGBaseTable
public class GBaseTable<T> : IGBaseTable<T>
{
private readonly IFileHandler _fileHandler;
private readonly IDataHandlerPool _dataHandlerPool;
private readonly IGBaseColumnFactory _gBaseColumnFactory;
/// <summary>
/// A <see cref="IGBase"/> table
/// </summary>
public GBaseTable(IFileHandlerFactory fileHandlerFactory, IGBaseColumnFactory gBaseColumnFactory)
/// <param name="fileHandlerFactory"></param>
/// <param name="dataHandlerPool">The <see cref="IDataHandlerPool"/></param>
/// <param name="gBaseColumnFactory"></param>
public GBaseTable(IFileHandlerFactory fileHandlerFactory, IDataHandlerPool dataHandlerPool, IGBaseColumnFactory gBaseColumnFactory)
{
_fileHandler = fileHandlerFactory.Create();
_dataHandlerPool = dataHandlerPool;
_gBaseColumnFactory = gBaseColumnFactory;
Columns = new List<IGBaseColumn>();
Entries = new List<object>();
Entries = new List<T>();
}
@ -47,7 +53,7 @@ namespace GBase
/// <summary>
/// The name of this <see cref="IGBaseTable"/>
/// </summary>
public string Name { get; private set; }
public string FolderName { get; private set; }
/// <summary>
/// The <see cref="IGBaseColumn"/>s of this <see cref="IGBaseTable"/>
@ -57,25 +63,22 @@ namespace GBase
/// <summary>
/// The entries of this <see cref="IGBaseTable"/>
/// </summary>
public List<object> Entries { get; }
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="name">The name of this <see cref="IGBaseTable"/></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 name, string databasePath, CancellationToken cancellationToken)
public async Task<bool> Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken)
{
Type = type;
Name = name;
string fileName = $"{name}.{GBase.GBASE_TABLE_FILE_EXTENSION}";
string path = Path.Combine(databasePath, fileName);
await _fileHandler.Init(path, cancellationToken);
FolderName = folderName;
await _fileHandler.Init(databasePath, cancellationToken);
//TODO: Init columns list depending on GBaseColumnAttributes set for this GBaseTable
foreach (var property in type.GetProperties())
@ -84,7 +87,7 @@ namespace GBase
if (gBaseColumnAttribute == null)
continue;
IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create();
IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create(property.Name);
AddColumn(gBaseColumn);
}
@ -96,7 +99,7 @@ namespace GBase
/// </summary>
/// <param name="column">The given <see cref="IGBaseColumn"/></param>
/// <returns>True if successful, false if not</returns>
public bool AddColumn(IGBaseColumn column)
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;
@ -110,7 +113,7 @@ namespace GBase
/// </summary>
/// <param name="column">The given <see cref="IGBaseColumn"/></param>
/// <returns>True if successful, false if not</returns>
public bool RemoveColumn(IGBaseColumn column)
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;
@ -122,11 +125,15 @@ namespace GBase
/// 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 bool AddEntry(INotifyGBaseEntryChanged entry) //TODO: Write to file
public async Task<bool> AddEntry(T entry, CancellationToken cancellationToken)
{
Entries.Add(entry);
entry.GBaseEntryChanged += OnGBaseEntryChanged;
using IGBaseFile file = _fileHandler.CreateEntryFile(entry, this);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
await dataHandler.AddEntry(entry, this, file.File, cancellationToken);
return true;
}
@ -136,41 +143,35 @@ namespace GBase
/// </summary>
/// <param name="entry">The entry implementing <see cref="INotifyGBaseEntryChanged"/></param>
/// <returns>True if successful, false if not</returns>
public bool RemoveEntry(INotifyGBaseEntryChanged entry) //TODO: remove from file
public async Task<bool> RemoveEntry(T entry)
{
if (!Entries.Contains(entry))
return false;
entry.GBaseEntryChanged -= OnGBaseEntryChanged;
await _fileHandler.DeleteEntryFile(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
public async Task SetValue<TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken)
{
//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;
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, CancellationToken.None);
await dataHandler.SetValue<T, TProperty>(file.File, propertyName, value, cancellationToken);
}
/// <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)
public async Task<TProperty> GetValue<TProperty>(T entry, string propertyName, CancellationToken cancellationToken)
{
//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
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, CancellationToken.None);
return await dataHandler.GetValue<T, TProperty>(file.File, propertyName, cancellationToken);
}
public async Task<IEnumerable<TProperty>> GetValues<TProperty>(T entry, string propertyName, CancellationToken cancellationToken)
{
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, CancellationToken.None);
return await dataHandler.GetValues<T, TProperty>(file.File, propertyName, cancellationToken);
}
/// <summary>
@ -180,6 +181,7 @@ namespace GBase
public async ValueTask DisposeAsync()
{
await _fileHandler.DisposeAsync();
await _dataHandlerPool.DisposeAsync();
foreach (var column in Columns)
{
@ -188,9 +190,9 @@ namespace GBase
Columns.Clear();
foreach (var entry in Entries.OfType<INotifyGBaseEntryChanged>().ToList())
foreach (var entry in Entries.ToList())
{
RemoveEntry(entry);
await RemoveEntry(entry);
}
Entries.Clear();

@ -7,8 +7,13 @@ using GBase.DataHandling;
using GBase.DataHandling.Cache;
using GBase.DataHandling.Cache.Factories;
using GBase.DataHandling.Factories;
using GBase.DataHandling.Factories.Pool;
using GBase.DataHandling.Pool;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Pool;
using GBase.Interfaces.DataHandling.Xml;
using GBase.Interfaces.DataHandling.Xml.Cache;
using LightweightIocContainer;
using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Installers;
@ -22,16 +27,22 @@ namespace GBase.Installers
/// <inheritdoc />
public void Install(IIocContainer container)
{
container.Register<IXmlDataHandler, XmlDataHandler>();
container.Register<IXmlDataReader, XmlDataReader>();
container.Register<IXmlDataWriter, XmlDataWriter>();
container.Register<IDataHandler, IXmlDataHandler, XmlDataHandler>();
container.Register<IDataReader, IXmlDataReader, XmlDataReader>();
container.Register<IDataWriter, IXmlDataWriter, XmlDataWriter>();
//cache
container.Register<IXmlDataHandlerCache, XmlDataHandlerCache>();
container.Register<IXmlDataHandlerCacheEntry, XmlDataHandlerCacheEntry>();
container.Register<IXmlDataHandlerCachePropertyEntry, XmlDataHandlerCachePropertyEntry>();
//pool
container.Register<IDataHandlerPool, DataHandlerPool>(Lifestyle.Singleton).WithParameters(10);
container.Register<IPoolItemFactory, PoolItemFactory>();
container.RegisterFactory<IPoolRequestFactory>();
//factories
container.RegisterFactory<IDataHandlerFactory>();
container.RegisterFactory<IXmlDataHandlerFactory>();
container.RegisterFactory<IXmlDataReaderFactory>();
container.RegisterFactory<IXmlDataWriterFactory>();

@ -19,12 +19,11 @@ namespace GBase.Installers
public void Install(IIocContainer container)
{
container.Register<IGBase, GBase>();
container.Register<IGBaseTable, GBaseTable>();
container.Register<IGBaseColumn, GBaseColumn>();
//factories
container.RegisterFactory<IGBaseFactory>();
container.RegisterFactory<IGBaseTableFactory>();
container.Register<IGBaseTableFactory, GBaseTableFactory>(); //TODO: Once LightweightIocContainer can handle open generic registrations this can be changed back again
container.RegisterFactory<IGBaseColumnFactory>();
}
}

@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace GBase.Interfaces.DataHandling.Cache
@ -39,8 +41,10 @@ namespace GBase.Interfaces.DataHandling.Cache
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
Task<IEnumerable<TProperty>> TryGetValues<T, TProperty>(string propertyName);
Task<IEnumerable<TProperty>> TryGetValues<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken);
}
}

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@ -12,52 +13,63 @@ namespace GBase.Interfaces.DataHandling
/// <summary>
/// Interface for data handlers to implement
/// </summary>
public interface IDataHandler : IAsyncDisposable
public interface IDataHandler
{
/// <summary>
/// Initialize the <see cref="IDataHandler"/>
/// </summary>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
Task<bool> Init(bool overwrite, CancellationToken cancellationToken);
bool Init(bool overwrite);
Task<bool> AddEntry<T>(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken);
Task<bool> RemoveEntry<T>(T entry);
/// <summary>
/// Set the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="entryFile"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
Task SetValue<T, TProperty>(string propertyName, TProperty value);
Task SetValue<T, TProperty>(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken);
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="entryFile"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
Task RemoveValue<T, TProperty>(string propertyName, TProperty value);
Task RemoveValue<T, TProperty>(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken);
/// <summary>
/// Get the value for the given property, if multiple values are set the first is returned
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></param>
/// <returns>The value for the given property</returns>
Task<TProperty> GetValue<T, TProperty>(string propertyName);
Task<TProperty> GetValue<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken);
/// <summary>
/// Get all the values that are set for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
Task<IEnumerable<TProperty>> GetValues<T, TProperty>(string propertyName);
Task<IEnumerable<TProperty>> GetValues<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken);
}
}

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@ -12,22 +13,17 @@ namespace GBase.Interfaces.DataHandling
/// <summary>
/// Interface for data readers to implement
/// </summary>
public interface IDataReader : IAsyncDisposable
public interface IDataReader
{
/// <summary>
/// Initialize the <see cref="IDataReader"/>
/// </summary>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
Task<bool> Init(CancellationToken cancellationToken);
/// <summary>
/// Read the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="cancellationToken"></param>
/// <returns>The data of the given property, null if no data found</returns>
Task<IEnumerable<TProperty>> Read<T, TProperty>(string propertyName);
Task<IEnumerable<TProperty>> Read<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken);
}
}

@ -3,6 +3,7 @@
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
@ -11,34 +12,53 @@ namespace GBase.Interfaces.DataHandling
/// <summary>
/// Interface for data writers to implement
/// </summary>
public interface IDataWriter : IAsyncDisposable
public interface IDataWriter
{
/// <summary>
/// Initialize the <see cref="IDataWriter"/>
/// </summary>
/// <param name="file"></param>
/// <param name="rootElementName"></param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
Task<bool> Init(CancellationToken cancellationToken);
Task<bool> InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken);
/// <summary>
/// Write the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value of the property</param>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
Task Write<T, TProperty>(string propertyName, string value, bool overwrite);
Task Write<T, TProperty>(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken);
/// <summary>
/// Write the data of a property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/></typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value of the property</param>
/// <param name="propertyType"></param>
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
Task Write<T>(FileStream file, string propertyName, string value, Type propertyType, bool overwrite, CancellationToken cancellationToken);
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="file"></param>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <param name="cancellationToken"></param>
/// <returns>A <see cref="Task"/> to await</returns>
Task Remove<T, TProperty>(string propertyName, string value);
Task Remove<T, TProperty>(FileStream file, string propertyName, string value, CancellationToken cancellationToken);
}
}

@ -0,0 +1,15 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace GBase.Interfaces.DataHandling.Pool
{
public interface IDataHandlerPool : IAsyncDisposable
{
Task<IDataHandler> RequestDataHandler(object requester, bool overwrite, CancellationToken cancellationToken);
}
}

@ -0,0 +1,12 @@
// Author: Simon Gockner
// Created: 2020-09-19
// Copyright(c) 2020 SimonG. All Rights Reserved.
namespace GBase.Interfaces.DataHandling.Pool
{
public interface IPoolItem<T>
{
T Item { get; }
bool InUse { get; set; }
}
}

@ -0,0 +1,14 @@
// Author: Simon Gockner
// Created: 2020-09-19
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Threading.Tasks;
namespace GBase.Interfaces.DataHandling.Pool
{
public interface IPoolRequest
{
object Requester { get; }
}
}

@ -3,7 +3,6 @@
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@ -22,42 +21,10 @@ namespace GBase.Interfaces.FileHandling
/// <returns>True if successful, false if not</returns>
Task<bool> Init(string path, CancellationToken cancellationToken);
/// <summary>
/// Set the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
Task SetValue<T, TProperty>(string propertyName, TProperty value);
IGBaseFile CreateEntryFile<T>(T entry, IGBaseTable table);
/// <summary>
/// Remove the value for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
Task RemoveValue<T, TProperty>(string propertyName, TProperty value);
Task<bool> DeleteEntryFile<T>(T entry);
/// <summary>
/// Get the value for the given property, if multiple values are set the first is returned
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>The value for the given property</returns>
Task<TProperty> GetValue<T, TProperty>(string propertyName);
/// <summary>
/// Get all the values that are set for the given property
/// </summary>
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
/// <param name="propertyName">The name of the property</param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
Task<IEnumerable<TProperty>> GetValues<T, TProperty>(string propertyName);
Task<IGBaseFile> RequestEntryFile<T>(T entry);
}
}

@ -0,0 +1,19 @@
// Author: Gockner, Simon
// Created: 2020-11-10
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.IO;
namespace GBase.Interfaces.FileHandling
{
public interface IGBaseFile : IDisposable
{
object Entry { get; }
FileStream File { get; }
string FilePath { get; }
bool InUse { get; }
IGBaseFile UseFile();
}
}

@ -48,11 +48,19 @@ namespace GBase.Interfaces
/// <returns>True if successful, false if not</returns>
bool AddTable(IGBaseTable table);
IGBaseTable<T> GetTable<T>();
/// <summary>
/// Removes a given <see cref="IGBaseTable"/> from this <see cref="IGBase"/>
/// </summary>
/// <param name="table">The given <see cref="IGBaseTable"/></param>
/// <returns>True if successful, false if not</returns>
bool RemoveTable(IGBaseTable table);
Task<bool> AddEntry<T>(T entry, CancellationToken cancellationToken);
Task SetValue<T, TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken);
Task<TProperty> GetValue<T, TProperty>(T entry, string propertyName, CancellationToken cancellationToken);
Task<IEnumerable<TProperty>> GetValues<T, TProperty>(T entry, string propertyName, CancellationToken cancellationToken);
}
}

@ -11,6 +11,6 @@ namespace GBase.Interfaces
/// </summary>
public interface IGBaseColumn : IAsyncDisposable //TODO: Make column generic (generic type is type of the value of the column?)?
{
string Name { get; }
}
}

@ -10,6 +10,38 @@ using GBase.Api;
namespace GBase.Interfaces
{
public interface IGBaseTable<T> : IGBaseTable
{
/// <summary>
/// The entries of this <see cref="IGBaseTable"/>
/// </summary>
List<T> Entries { get; }
/// <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>
Task<bool> AddEntry(T entry, CancellationToken cancellationToken);
//T GetEntry(T entry); //TODO: This doesn't make sense... (passing instance of T to get the same instance back...)
/// <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>
Task<bool> RemoveEntry(T entry);
Task SetValue<TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken);
Task<TProperty> GetValue<TProperty>(T entry, string propertyName, CancellationToken cancellationToken);
Task<IEnumerable<TProperty>> GetValues<TProperty>(T entry, string propertyName, CancellationToken cancellationToken);
}
/// <summary>
/// A <see cref="IGBase"/> table
/// </summary>
@ -23,27 +55,23 @@ namespace GBase.Interfaces
/// <summary>
/// The name of this <see cref="IGBaseTable"/>
/// </summary>
string Name { get; }
string FolderName { get; }
/// <summary>
/// The <see cref="IGBaseColumn"/>s of this <see cref="IGBaseTable"/>
/// </summary>
List<IGBaseColumn> Columns { get; }
/// <summary>
/// The entries of this <see cref="IGBaseTable"/>
/// </summary>
List<object> 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="name">The name of this <see cref="IGBaseTable"/></param>
/// /// <param name="databasePath">The path to the database files</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>
Task<bool> Init(Type type, string name, string databasePath, CancellationToken cancellationToken);
Task<bool> Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken);
/// <summary>
/// Add a given <see cref="IGBaseColumn"/> to this <see cref="IGBaseTable"/>
@ -58,19 +86,5 @@ namespace GBase.Interfaces
/// <param name="column">The given <see cref="IGBaseColumn"/></param>
/// <returns>True if successful, false if not</returns>
bool RemoveColumn(IGBaseColumn 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>
/// <returns>True if successful, false if not</returns>
bool AddEntry(INotifyGBaseEntryChanged entry);
/// <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>
bool RemoveEntry(INotifyGBaseEntryChanged entry);
}
}

@ -0,0 +1,41 @@
# GBase Structure
```md
- GBase
|
+-GBaseTable
|
|
+-GBaseTable
|
+-GBaseColumn--GBaseColumn--GBaseColumn
+-GBaseEntry
+-GBaseEntry
```
## Terminology
| GBase Terminology | C# equivalent |
|-------------------|---------------|
| GBaseTable | Type |
| GBaseColumn | Property |
| GBaseEntry | Instance |
## File Structure
```c#
public class Model
{
private readonly IGBase _gBase;
public
}
```
## Process
### StartUp
### GetValue
### SetValue

@ -3,6 +3,7 @@
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using GBase.DataHandling;
@ -27,12 +28,12 @@ namespace Test.GBase.DataHandling
Assert.Pass(); //Remove this assert.pass() if you want to run this test locally
Mock<IXmlDataWriterFactory> dataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
dataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>()))
.Returns((string path, string rootElementName) => new XmlDataWriter(path, rootElementName));
dataWriterFactoryMock.Setup(w => w.Create())
.Returns(new XmlDataWriter());
Mock<IXmlDataReaderFactory> dataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
dataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>()))
.Returns((string path) => new XmlDataReader(path));
dataReaderFactoryMock.Setup(r => r.Create())
.Returns(new XmlDataReader());
Mock<IXmlDataHandlerCachePropertyEntryFactory> dataHandlerCachePropertyEntryFactoryMock = new Mock<IXmlDataHandlerCachePropertyEntryFactory>();
dataHandlerCachePropertyEntryFactoryMock.Setup(p => p.Create(It.IsAny<string>(), It.IsAny<object>()))
@ -48,21 +49,22 @@ namespace Test.GBase.DataHandling
.Returns((IXmlDataReader xmlDataReader) =>
new XmlDataHandlerCache(xmlDataReader, dataHandlerCacheEntryFactoryMock.Object, dataHandlerCachePropertyEntryFactoryMock.Object));
IXmlDataHandler xmlDataHandler = new XmlDataHandler("TestXml.xml", "Properties", dataReaderFactoryMock.Object, dataWriterFactoryMock.Object,
dataHandlerCacheFactoryMock.Object);
IXmlDataHandler xmlDataHandler = new XmlDataHandler(dataReaderFactoryMock.Object, dataWriterFactoryMock.Object, dataHandlerCacheFactoryMock.Object);
await xmlDataHandler.Init(false, new CancellationToken());
//
xmlDataHandler.Init(false);
FileStream file = null; //FixMe: init this correctly if you want to run this test
//await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, string>(nameof(TestProperty), TestProperty);
//await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, string>(nameof(TestProperty), "empty");
await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, string>(nameof(TestProperty), "test");
await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, string>(file, nameof(TestProperty), "test", new CancellationToken());
//await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, string>(nameof(TestProperty), "OverwrittenString");
//
await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, int>(nameof(TestInt), 1);
await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, int>(file, nameof(TestInt), 1, new CancellationToken());
//await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, int>(nameof(TestInt), 2);
//await xmlDataHandler.SetValue<XmlDataHandlerLocalIntegrationTest, int>(nameof(TestInt), 3);
TestProperty = await xmlDataHandler.GetValue<XmlDataHandlerLocalIntegrationTest, string>(nameof(TestProperty));
TestInt = await xmlDataHandler.GetValue<XmlDataHandlerLocalIntegrationTest, int>(nameof(TestInt));
TestProperty = await xmlDataHandler.GetValue<XmlDataHandlerLocalIntegrationTest, string>(file, nameof(TestProperty), new CancellationToken());
TestInt = await xmlDataHandler.GetValue<XmlDataHandlerLocalIntegrationTest, int>(file, nameof(TestInt), new CancellationToken());
}
}
}

@ -19,104 +19,45 @@ namespace Test.GBase.DataHandling
public class XmlDataHandlerTest
{
[Test]
public async Task TestInit()
public void TestInit()
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
xmlDataReaderMock.Setup(r => r.Init(It.IsAny<CancellationToken>())).ReturnsAsync(true);
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
xmlDataWriterMock.Setup(w => w.Init(It.IsAny<CancellationToken>())).ReturnsAsync(true);
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
Assert.True(await xmlDataHandler.Init(false, CancellationToken.None));
}
[Test]
public async Task TestInitFailedTriedTwice()
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
xmlDataReaderMock.Setup(r => r.Init(It.IsAny<CancellationToken>())).ReturnsAsync(true);
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
xmlDataWriterMock.Setup(w => w.Init(It.IsAny<CancellationToken>())).ReturnsAsync(true);
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
Assert.True(await xmlDataHandler.Init(false, CancellationToken.None));
Assert.False(await xmlDataHandler.Init(false, CancellationToken.None));
Assert.True(xmlDataHandler.Init(false));
}
[Test]
public async Task TestInitFailedInitReaderFailed()
public void TestInitFailedTriedTwice()
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
xmlDataReaderMock.Setup(r => r.Init(It.IsAny<CancellationToken>())).ReturnsAsync(false);
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
xmlDataWriterMock.Setup(w => w.Init(It.IsAny<CancellationToken>())).ReturnsAsync(true);
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
Assert.False(await xmlDataHandler.Init(false, CancellationToken.None));
}
[Test]
public async Task TestInitFailedInitWriterFailed()
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
xmlDataReaderMock.Setup(r => r.Init(It.IsAny<CancellationToken>())).ReturnsAsync(true);
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
xmlDataWriterMock.Setup(w => w.Init(It.IsAny<CancellationToken>())).ReturnsAsync(false);
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
Assert.False(await xmlDataHandler.Init(false, CancellationToken.None));
Assert.True(xmlDataHandler.Init(false));
Assert.False(xmlDataHandler.Init(false));
}
[Test]
@ -124,23 +65,22 @@ namespace Test.GBase.DataHandling
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
await xmlDataHandler.SetValue<XmlDataHandlerTest, string>("property", "SomeString");
await xmlDataHandler.SetValue<XmlDataHandlerTest, string>(null, "property", "SomeString", new CancellationToken());
xmlDataHandlerCacheMock.Verify(c => c.SetValue<XmlDataHandlerTest, string>("property", "SomeString", false), Times.Once);
xmlDataWriterMock.Verify(w => w.Write<XmlDataHandlerTest, string>("property", "SomeString", false), Times.Once);
xmlDataWriterMock.Verify(w => w.Write<XmlDataHandlerTest, string>(null, "property", "SomeString", false, It.IsAny<CancellationToken>()), Times.Once);
}
[Test]
@ -148,24 +88,23 @@ namespace Test.GBase.DataHandling
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
List<string> stringList = new List<string>() {"string", "secondString", "thirdString"};
await xmlDataHandler.SetValue<XmlDataHandlerTest, List<string>>("property", stringList);
await xmlDataHandler.SetValue<XmlDataHandlerTest, List<string>>(null, "property", stringList, new CancellationToken());
xmlDataHandlerCacheMock.Verify(c => c.SetValue<XmlDataHandlerTest, List<string>>("property", stringList, false), Times.Once);
xmlDataWriterMock.Verify(w => w.Write<XmlDataHandlerTest, List<string>>("property", $"{stringList[0]},{stringList[1]},{stringList[2]}", false), Times.Once);
xmlDataWriterMock.Verify(w => w.Write<XmlDataHandlerTest, List<string>>(null, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}",false, It.IsAny<CancellationToken>()), Times.Once);
}
[Test]
@ -173,23 +112,22 @@ namespace Test.GBase.DataHandling
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
await xmlDataHandler.SetValue<XmlDataHandlerTest, string>("property", null);
await xmlDataHandler.SetValue<XmlDataHandlerTest, string>(null, "property", null, new CancellationToken());
xmlDataHandlerCacheMock.Verify(c => c.SetValue<It.IsValueType, It.IsValueType>(It.IsAny<string>(), It.IsAny<It.IsValueType>(), It.IsAny<bool>()), Times.Never);
xmlDataWriterMock.Verify(w => w.Write<It.IsValueType, It.IsValueType>(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()), Times.Never);
xmlDataWriterMock.Verify(w => w.Write<It.IsValueType, It.IsValueType>(null, It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<CancellationToken>()), Times.Never);
}
[Test]
@ -197,23 +135,22 @@ namespace Test.GBase.DataHandling
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
await xmlDataHandler.RemoveValue<XmlDataHandlerTest, string>("property", "SomeString");
await xmlDataHandler.RemoveValue<XmlDataHandlerTest, string>(null, "property", "SomeString", new CancellationToken());
xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue<XmlDataHandlerTest, string>("property", "SomeString"), Times.Once);
xmlDataWriterMock.Verify(w => w.Remove<XmlDataHandlerTest, string>("property", "SomeString"), Times.Once);
xmlDataWriterMock.Verify(w => w.Remove<XmlDataHandlerTest, string>(null, "property", "SomeString", It.IsAny<CancellationToken>()), Times.Once);
}
[Test]
@ -221,24 +158,23 @@ namespace Test.GBase.DataHandling
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
List<string> stringList = new List<string>() { "string", "secondString", "thirdString" };
await xmlDataHandler.RemoveValue<XmlDataHandlerTest, List<string>>("property", stringList);
await xmlDataHandler.RemoveValue<XmlDataHandlerTest, List<string>>(null, "property", stringList, new CancellationToken());
xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue<XmlDataHandlerTest, List<string>>("property", stringList), Times.Once);
xmlDataWriterMock.Verify(w => w.Remove<XmlDataHandlerTest, List<string>>("property", $"{stringList[0]},{stringList[1]},{stringList[2]}"), Times.Once);
xmlDataWriterMock.Verify(w => w.Remove<XmlDataHandlerTest, List<string>>(null, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", It.IsAny<CancellationToken>()), Times.Once);
}
[Test]
@ -246,23 +182,22 @@ namespace Test.GBase.DataHandling
{
Mock<IXmlDataReader> xmlDataReaderMock = new Mock<IXmlDataReader>();
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
await xmlDataHandler.RemoveValue<XmlDataHandlerTest, string>("property", null);
await xmlDataHandler.RemoveValue<XmlDataHandlerTest, string>(null, "property", null, new CancellationToken());
xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue<It.IsValueType, It.IsValueType>(It.IsAny<string>(), It.IsAny<It.IsValueType>()), Times.Never);
xmlDataWriterMock.Verify(w => w.Remove<It.IsValueType, It.IsValueType>(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
xmlDataWriterMock.Verify(w => w.Remove<It.IsValueType, It.IsValueType>(null, It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
}
[Test]
@ -274,18 +209,17 @@ namespace Test.GBase.DataHandling
//xmlDataReaderMock.Setup(r => r.Read<XmlDataHandlerTest, string>("property")).ReturnsAsync<List<string>>(values);
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
}
[Test]
@ -297,20 +231,19 @@ namespace Test.GBase.DataHandling
//xmlDataReaderMock.Setup(r => r.Read<XmlDataHandlerTest, string>("property")).ReturnsAsync<List<string>>(values);
Mock<IXmlDataReaderFactory> xmlDataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny<string>())).Returns(xmlDataReaderMock.Object);
xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object);
Mock<IXmlDataWriter> xmlDataWriterMock = new Mock<IXmlDataWriter>();
Mock<IXmlDataWriterFactory> xmlDataWriterFactoryMock = new Mock<IXmlDataWriterFactory>();
xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny<string>(), It.IsAny<string>())).Returns(xmlDataWriterMock.Object);
xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object);
Mock<IXmlDataHandlerCache> xmlDataHandlerCacheMock = new Mock<IXmlDataHandlerCache>();
Mock<IXmlDataHandlerCacheFactory> xmlDataHandlerCacheFactoryMock = new Mock<IXmlDataHandlerCacheFactory>();
xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny<IXmlDataReader>())).Returns(xmlDataHandlerCacheMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object,
xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object);
IEnumerable<List<string>> readValues = await xmlDataHandler.GetValues<XmlDataHandlerTest, List<string>>("property");
IEnumerable<List<string>> readValues = await xmlDataHandler.GetValues<XmlDataHandlerTest, List<string>>(null, "property", new CancellationToken());
}
}
}

@ -0,0 +1,56 @@
// Author: Gockner, Simon
// Created: 2020-11-11
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Threading;
using System.Threading.Tasks;
using GBase.Factories;
using GBase.Installers;
using LightweightIocContainer;
using LightweightIocContainer.Interfaces;
using NUnit.Framework;
namespace Test.GBase.GBaseIntegrationTest
{
[TestFixture]
public class GBaseIntegrationTest
{
private CancellationTokenSource _cancellationTokenSource;
private IIocContainer _iocContainer;
[SetUp]
public void SetUp()
{
_cancellationTokenSource = new CancellationTokenSource();
_iocContainer = new IocContainer();
_iocContainer.Install(new GBaseInstaller(),
new DataHandlingInstaller(),
new FileHandlingInstaller());
}
[TearDown]
public void TearDown()
{
_cancellationTokenSource.Dispose();
_iocContainer.Dispose();
}
[Test]
public async Task TestGBase()
{
IGBaseFactory gBaseFactory = _iocContainer.Resolve<IGBaseFactory>();
Model model = new Model(gBaseFactory);
await model.Initialize(_cancellationTokenSource.Token);
await model.AddItem(new Item("Item 1", 1), _cancellationTokenSource.Token);
await model.AddItem(new Item("Item 2", 2), _cancellationTokenSource.Token);
await model.AddItem(new Item("Item 3", 3), _cancellationTokenSource.Token);
await model.AddGroup(new Group(1), _cancellationTokenSource.Token);
await model.AddGroup(new Group(2), _cancellationTokenSource.Token);
await model.AddGroup(new Group(3), _cancellationTokenSource.Token);
}
}
}

@ -0,0 +1,26 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic;
using GBase.Attributes;
namespace Test.GBase.GBaseIntegrationTest
{
[GBaseTable("Groups")]
public class Group : IGroup
{
public Group(int key)
{
Key = key;
Items = new List<IItem>();
}
[GBaseColumn]
public int Key { get; private set; }
public List<IItem> Items { get; }
public override string ToString() => $"{Key}";
public void InitializeFromString(string @string) => Key = int.Parse(@string);
}
}

@ -0,0 +1,15 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic;
using GBase.Api;
namespace Test.GBase.GBaseIntegrationTest
{
public interface IGroup : IGBaseObject //: INotifyGBaseEntryChanged
{
int Key { get; }
List<IItem> Items { get; }
}
}

@ -0,0 +1,14 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Api;
namespace Test.GBase.GBaseIntegrationTest
{
public interface IItem : IGBaseObject //: INotifyGBaseEntryChanged
{
string Name { get; }
int Key { get; }
}
}

@ -0,0 +1,34 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Attributes;
namespace Test.GBase.GBaseIntegrationTest
{
[GBaseTable("Items")]
public class Item : IItem
{
public Item(string name, int key)
{
Name = name;
Key = key;
}
[GBaseColumn]
public string Name { get; private set; }
[GBaseColumn]
public int Key { get; private set; }
public override string ToString() => $"{Name}";
public void InitializeFromString(string @string)
{
string[] properties = @string.Split('/');
Key = int.Parse(properties[0]);
Name = properties[1];
}
}
}

@ -0,0 +1,54 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using GBase.Factories;
using GBase.Interfaces;
namespace Test.GBase.GBaseIntegrationTest
{
public class Model
{
private readonly IGBase _gBase;
public Model(IGBaseFactory gBaseFactory)
{
_gBase = gBaseFactory.Create(new Settings());
Items = new List<IItem>();
Groups = new List<IGroup>();
}
public List<IItem> Items { get; private set; }
public List<IGroup> Groups { get; private set; }
public async Task Initialize(CancellationToken cancellationToken)
{
await _gBase.Init("DB", Assembly.GetExecutingAssembly(), cancellationToken);
// IGBaseTable<Item> itemsTable = _gBase.GetTable<Item>();
// Items = itemsTable.Entries.Cast<IItem>().ToList();
Items = (await _gBase.GetValues<Model, Item>(this, nameof(Items), cancellationToken)).Cast<IItem>().ToList();
// IGBaseTable<Group> groupsTable = _gBase.GetTable<Group>();
// Groups = groupsTable.Entries.Cast<IGroup>().ToList();
Groups = (await _gBase.GetValues<Model, Group>(this, nameof(Groups), cancellationToken)).Cast<IGroup>().ToList();
}
public async Task AddItem(Item item, CancellationToken cancellationToken)
{
Items.Add(item);
await _gBase.AddEntry(item, cancellationToken);
}
public async Task AddGroup(Group group, CancellationToken cancellationToken)
{
Groups.Add(group);
await _gBase.AddEntry(group, cancellationToken);
}
}
}

@ -0,0 +1,15 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.IO;
using GBase.Interfaces.Settings;
namespace Test.GBase.GBaseIntegrationTest
{
public class Settings : IGBaseSettings
{
public string DatabasePath => Path.Combine(Environment.CurrentDirectory, "DB");
}
}

@ -7,6 +7,7 @@ using GBase;
using GBase.Factories;
using GBase.FileHandling.Factories;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling.Pool;
using GBase.Interfaces.FileHandling;
using Moq;
using NUnit.Framework;
@ -22,18 +23,25 @@ namespace Test.GBase
{
Mock<IFileHandlerFactory> fileHandlerFactoryMock = new Mock<IFileHandlerFactory>();
fileHandlerFactoryMock.Setup(f => f.Create()).Returns(new Mock<IFileHandler>().Object);
IGBaseColumn gBaseColumn = null;
Mock<IGBaseColumnFactory> gBaseColumnFactoryMock = new Mock<IGBaseColumnFactory>();
gBaseColumnFactoryMock.Setup(c => c.Create()).Returns(new GBaseColumn());
gBaseColumnFactoryMock.Setup(c => c.Create(It.IsAny<string>()))
.Callback<string>(name => { gBaseColumn = new GBaseColumn(name); })
.Returns(gBaseColumn);
IGBaseTable table = new GBaseTable(fileHandlerFactoryMock.Object, gBaseColumnFactoryMock.Object);
table.Init(typeof(Foo), nameof(Foo), "", CancellationToken.None);
Mock<IDataHandlerPool> dataHandlerPoolMock = new Mock<IDataHandlerPool>();
IGBaseTable<Foo> table = new GBaseTable<Foo>(fileHandlerFactoryMock.Object, dataHandlerPoolMock.Object, gBaseColumnFactoryMock.Object);
table.Init(typeof(Foo), "", "", CancellationToken.None);
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Foo foo = new Foo("Test");
table.AddEntry(foo);
table.AddEntry(foo, cancellationTokenSource.Token);
Foo foo2 = new Foo("Test2");
table.AddEntry(foo2);
table.AddEntry(foo2, cancellationTokenSource.Token);
foo.Name = "Foo - ex Test";
foo2.Name = "Some Name";

@ -7,7 +7,7 @@ using GBase.Attributes;
namespace Test.GBase.TestClasses
{
[GBaseTable]
[GBaseTable("Foo")]
public class Foo : NotifyGBaseEntryChanged
{
private string _name;

Loading…
Cancel
Save