Compare commits

...

107 Commits

Author SHA1 Message Date
SimonG a972ed5464 - add drone build badge 5 years ago
SimonG d70d51421b - add empty line 5 years ago
SimonG b2dd4debca - add drone config 5 years ago
Simon G b629c628b5 - remove all implementations of InitializeFromString() 5 years ago
Simon G 4b2a361ff7 - update xml 5 years ago
Simon G cc6a0bd01c - add test for enumerables 5 years ago
Simon G b20c240b59 - adapt unit tests 5 years ago
Simon G b14099fb25 - use keys to convert a gBase string back to an enumerable 5 years ago
Simon G 9a058caade - inject GBase, prepare for new Enumerables 5 years ago
Simon G 700d71cc9d - remove old parameter comment 5 years ago
Simon G b6a4876bd6 - add GetEntryForKey() to GBase as well 5 years ago
Simon G 85dc6b0652 - add getEntryForKey 5 years ago
Simon G f186503536 - remove InitializeFromString() 5 years ago
Simon G 278ccce013 - add GetEntryForKey() method 5 years ago
Simon G 6cb926d6ef - set lifestyle singleton for GBase 5 years ago
Simon G 5f0dae02d9 - fix method comment 5 years ago
Simon G beed882e91 - refactoring 5 years ago
Simon G 7e929919ac - update xml 5 years ago
Simon G 6233491abd - reset stream to position 0 before loading 5 years ago
Simon G 11885d6345 - fix comment 5 years ago
Simon G 7d2b91701b - adapt to init and remove todo 5 years ago
Simon G 52aedb99a9 - remove todos 5 years ago
Simon G a29700e38b - remove bool return value and todo 5 years ago
Simon G 6b34b5ec06 - remove bool return value and todo 5 years ago
Simon G 9c160ef871 - remove todo and line that doesn't work 5 years ago
Simon G 6040e31891 - check if type inherits from IGBaseObject 5 years ago
Simon G 71b8840df6 - remove wrong comments about INotifyGBaseEntryChanged 5 years ago
Simon G 848733ce5b - remove todo and unused using 5 years ago
Simon G 39974b97ba - update resharper files 5 years ago
Simon G 9a495d0af3 - update xmls 5 years ago
Simon G fb3a515ba0 - fix factory call 5 years ago
Simon G 81309b9839 - adapt to changed IGBaseObject 5 years ago
Simon G 5929e13dca - handle Keys 5 years ago
Simon G f3be965879 - add Key 5 years ago
Simon G e29b7cbafd - add GBaseKey class that is only settable once 5 years ago
Simon G 168823cfde - add isKey Property 5 years ago
Simon G f1c89018ed - add invalid and missing key exception 5 years ago
Simon G 69c4b573a5 - add isKey property 5 years ago
Simon G 4b44358af6 - add method to get inherited attributes for properties 5 years ago
Simon G af2a5768e7 - introduce FileName property to IGBaseObject that returns the file name of an entry 5 years ago
Simon G 1b0610c514 - requestDataHandler now returns IPoolItem<IDataHandler> so that InUse can be set to false again 5 years ago
Simon G 1ea6d259bc - make IPoolItem disposable and add use method, can be used with using now 5 years ago
Simon G 7aa637deb3 - install IPoolRequest 5 years ago
Simon G af42ee3297
Merge pull request #29 from SimonG96/ImproveDataHandling_#25 5 years ago
Simon G eb9d714a12 Merge remote-tracking branch 'origin/ImproveDataHandling_#25' into ImproveDataHandling_#25 5 years ago
Simon G e7bd2206b4 - adapt test classes 5 years ago
Simon G 6b9c827717 - update xml 5 years ago
Simon G be4ccf97e5 - initialize entries from existing files 5 years ago
Simon G d4ab37de84 - initialize existing files 5 years ago
Simon G a949f786f8 - add initialize() method to IGBaseObject 5 years ago
Simon G f52ab833c1 - add setter of entry to interface 5 years ago
Simon G fababa96d7 - add type to interface as well 5 years ago
Simon G baa8acae60 - add type to factory as well 5 years ago
Simon G 8ac13bf6ec - add microsoft.csharp package 5 years ago
Simon G b693b100e8 - add type of property 5 years ago
Simon G 4ce5e0914e - add setter for entry 5 years ago
Simon G 614ad24b5c - add GenericMethodCaller and matching exception 5 years ago
Simon G 01132a3784
Merge pull request #28 from SimonG96/ImproveDataHandling_#25 5 years ago
Simon G 9cdbc9d46b - update xml file structure 5 years ago
Simon G 23317c098e
Merge pull request #27 from SimonG96/ImproveDataHandling_#25 5 years ago
Simon G 2897acbea0 #25: update xml 5 years ago
Simon G 90242543c7 #25: adapt integration test 5 years ago
Simon G 225f10d1a0 #25: return true if file isn't empty, think if bool return value makes sense here 5 years ago
Simon G 1df5d49287 #25: throw missingTableException when getTable() doesn't find a matching table 5 years ago
Simon G b671d30d1d #25: add TODO: need to init existing files 5 years ago
Simon G c4ed254aac #25: add dataHandlerPool to factory 5 years ago
Simon G 62f18c0038 #25: remove need to inherit INotifyGBaseEntryChanged 5 years ago
Simon G 0c334463ee remove unused code 5 years ago
Simon G 7b97b75fb6 #25: update xml 5 years ago
Simon G 3f891b45c9 #25: fix tests 5 years ago
Simon G bfda73950a #25: fix factories and ctors 5 years ago
Simon G 5d0e766a76 #25: remove unused using 5 years ago
Simon G 0a8c1aa549 #25: use new methods from IGBaseTable 5 years ago
Simon G 92c278319e #25: use MissingTableException instead of default exception 5 years ago
Simon G 7ab02d7d3a #25: GBase can now get and set values 5 years ago
Simon G 2d4b9c820d #25: adapt DataHandlerPool 5 years ago
Simon G 93e2a1fd8c #25: adapt cache 5 years ago
Simon G ca6c75be23 #25: file handler now only handles files 5 years ago
Simon G c433add6f0 #25: make test methods async 5 years ago
Simon G 6c5df6818e #25: adapt dataReader 5 years ago
Simon G c446babb05 #25: start adapting FileHandler, add todo for possibly a better usage 5 years ago
Simon G 1cfa80c199 #25: adapt XmlDataHandler 5 years ago
Simon G 84d98a5dee #25: adapt XmlDataWriter to one file per entry strategy 5 years ago
Simon G f0783df9c2 #25: start changing data writer 5 years ago
Simon G 11a1b9c828 - pass cancellationToken where needed 5 years ago
Simon G 688ae81330 - fix usage of GBaseTable attribute 5 years ago
Simon G 8d1b24c5a1 - add const naming rule 5 years ago
Simon G 1498a914df #25: start implementing addEntry 5 years ago
Simon G b10ce3d195 #25: use dataHandler pool 5 years ago
Simon G 641dbf5a52 #25: implement IAsyncDisposable, call DataHandler.Init() 5 years ago
Simon G d873ce20c9 #25: add DataHandlerPool 5 years ago
Simon G a5b6e31690 #25: add todo 5 years ago
Simon G 06f6a4381e #25: add IDataHandlerFactory 5 years ago
Simon G a854354e85 #25: implement workaround for missing open generic registration possibility 5 years ago
Simon G 781c6b3c03 - make methods async 5 years ago
Simon G 92cca71166 - add addEntry and removeEntry methods 5 years ago
Simon G 2e2c0f74c2 - start adding complete GBase integration 5 years ago
Simon G 488fad44a1 - add MissingTableException 5 years ago
Simon G 8299f48eb3 - adapt test to generic table 5 years ago
Simon G b69830fb41 - first try add base GBaseObject implementation 5 years ago
Simon G 7c2f52a265 - try adding generic GBaseTable 5 years ago
Simon G 893fdf33d3 - create structure of gBase, to understand it 5 years ago
Simon G 7c5aa03498 - add todos 5 years ago
Simon G dc5d57e48b - idea folder 5 years ago
Simon G aed5d84383 - add fix me 5 years ago
Simon G f29039c7ab - idea changes 5 years ago
Simon G fd367b6a38
Merge pull request #26 from SimonG96/master 5 years ago
  1. 14
      .drone.yml
  2. 4
      .idea/.idea.GBase/.idea/encodings.xml
  3. 2
      .idea/.idea.GBase/.idea/modules.xml
  4. 14
      .idea/.idea.GBase/.idea/riderModule.iml
  5. 11
      GBase.Api/GBase.Api.xml
  6. 18
      GBase.Api/IGBaseObject.cs
  7. 1
      GBase.sln.DotSettings
  8. 5
      GBase/Attributes/GBaseColumnAttribute.cs
  9. 5
      GBase/Attributes/GBaseTableAttribute.cs
  10. 8
      GBase/DataHandling/Cache/XmlDataHandlerCache.cs
  11. 17
      GBase/DataHandling/Exceptions/InvalidXmlFileException.cs
  12. 13
      GBase/DataHandling/Factories/IDataHandlerFactory.cs
  13. 3
      GBase/DataHandling/Factories/IXmlDataReaderFactory.cs
  14. 4
      GBase/DataHandling/Factories/IXmlDataWriterFactory.cs
  15. 13
      GBase/DataHandling/Factories/Pool/IPoolItemFactory.cs
  16. 13
      GBase/DataHandling/Factories/Pool/IPoolRequestFactory.cs
  17. 14
      GBase/DataHandling/Factories/Pool/PoolItemFactory.cs
  18. 94
      GBase/DataHandling/Pool/DataHandlerPool.cs
  19. 27
      GBase/DataHandling/Pool/PoolItem.cs
  20. 18
      GBase/DataHandling/Pool/PoolRequest.cs
  21. 83
      GBase/DataHandling/XmlDataHandler.cs
  22. 71
      GBase/DataHandling/XmlDataReader.cs
  23. 126
      GBase/DataHandling/XmlDataWriter.cs
  24. 24
      GBase/Exceptions/GenericMethodNotFoundException.cs
  25. 17
      GBase/Exceptions/InvalidKeyException.cs
  26. 27
      GBase/Exceptions/InvalidTableTypeException.cs
  27. 17
      GBase/Exceptions/MissingKeyColumnException.cs
  28. 23
      GBase/Exceptions/MissingTableException.cs
  29. 49
      GBase/Factories/GBaseTableFactory.cs
  30. 3
      GBase/Factories/IGBaseColumnFactory.cs
  31. 3
      GBase/Factories/IGBaseTableFactory.cs
  32. 17
      GBase/FileHandling/Exceptions/FileNotExistingException.cs
  33. 129
      GBase/FileHandling/FileHandler.cs
  34. 32
      GBase/FileHandling/GBaseFile.cs
  35. 66
      GBase/GBase.cs
  36. 1
      GBase/GBase.csproj
  37. 512
      GBase/GBase.xml
  38. 10
      GBase/GBaseColumn.cs
  39. 30
      GBase/GBaseKey.cs
  40. 45
      GBase/GBaseObject.cs
  41. 160
      GBase/GBaseTable.cs
  42. 19
      GBase/Helpers/Attributes.cs
  43. 24
      GBase/Helpers/Enumerables.cs
  44. 108
      GBase/Helpers/GenericMethodCaller.cs
  45. 18
      GBase/Installers/DataHandlingInstaller.cs
  46. 6
      GBase/Installers/GBaseInstaller.cs
  47. 6
      GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs
  48. 26
      GBase/Interfaces/DataHandling/IDataHandler.cs
  49. 14
      GBase/Interfaces/DataHandling/IDataReader.cs
  50. 28
      GBase/Interfaces/DataHandling/IDataWriter.cs
  51. 15
      GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs
  52. 16
      GBase/Interfaces/DataHandling/Pool/IPoolItem.cs
  53. 14
      GBase/Interfaces/DataHandling/Pool/IPoolRequest.cs
  54. 42
      GBase/Interfaces/FileHandling/IFileHandler.cs
  55. 19
      GBase/Interfaces/FileHandling/IGBaseFile.cs
  56. 9
      GBase/Interfaces/IGBase.cs
  57. 6
      GBase/Interfaces/IGBaseColumn.cs
  58. 29
      GBase/Interfaces/IGBaseObject.cs
  59. 62
      GBase/Interfaces/IGBaseTable.cs
  60. 41
      GBaseStructure.md
  61. 2
      README.md
  62. 27
      Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs
  63. 163
      Test.GBase/DataHandling/XmlDataHandlerTest.cs
  64. 56
      Test.GBase/GBaseIntegrationTest/GBaseIntegrationTest.cs
  65. 41
      Test.GBase/GBaseIntegrationTest/Group.cs
  66. 16
      Test.GBase/GBaseIntegrationTest/IGroup.cs
  67. 14
      Test.GBase/GBaseIntegrationTest/IItem.cs
  68. 43
      Test.GBase/GBaseIntegrationTest/Item.cs
  69. 54
      Test.GBase/GBaseIntegrationTest/Model.cs
  70. 15
      Test.GBase/GBaseIntegrationTest/Settings.cs
  71. 19
      Test.GBase/GBaseTableIntegrationTest.cs
  72. 10
      Test.GBase/Helpers/EnumerablesTest.cs
  73. 21
      Test.GBase/TestClasses/Foo.cs
  74. 1
      Test.GBase/TestClasses/IUserType.cs
  75. 10
      Test.GBase/TestClasses/UserType.cs

@ -0,0 +1,14 @@
kind: pipeline
type: docker
name: CI
steps:
- name: Build
image: mcr.microsoft.com/dotnet/sdk:5.0
commands:
- dotnet build
- name: Test
image: mcr.microsoft.com/dotnet/sdk:5.0
commands:
- dotnet test

@ -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,7 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.GBase/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.GBase/riderModule.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.GBase/.idea/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.GBase/.idea/riderModule.iml" />
</modules>
</component>
</project>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RIDER_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$USER_HOME$/.nuget/packages/microsoft.net.test.sdk/16.5.0/build/netcoreapp2.1" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.5.0/build/netcoreapp2.1/x64/testhost.dll" />
<content url="file://$USER_HOME$/.nuget/packages/microsoft.testplatform.testhost/16.5.0/build/netcoreapp2.1/x64/testhost.exe" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.16.1/build/netcoreapp2.1/NUnit3.TestAdapter.dll" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.16.1/build/netcoreapp2.1/NUnit3.TestAdapter.pdb" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.16.1/build/netcoreapp2.1/nunit.engine.api.dll" />
<content url="file://$USER_HOME$/.nuget/packages/nunit3testadapter/3.16.1/build/netcoreapp2.1/nunit.engine.dll" />
<content url="file://$MODULE_DIR$/../.." />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -102,17 +102,6 @@
The new value
</summary>
</member>
<member name="T:GBase.Api.IGBaseObject">
<summary>
GBase object that allows conversion from <see cref="T:System.String"/>
</summary>
</member>
<member name="M:GBase.Api.IGBaseObject.InitializeFromString(System.String)">
<summary>
Initialize this <see cref="T:GBase.Api.IGBaseObject"/> 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.Api.INotifyGBaseEntryChanged">
<summary>
Notify the GBase that an entry has changed

@ -1,18 +0,0 @@
// Author: Gockner, Simon
// Created: 2020-02-14
// Copyright(c) 2020 SimonG. All Rights Reserved.
namespace GBase.Api
{
/// <summary>
/// GBase object that allows conversion from <see cref="string"/>
/// </summary>
public interface IGBaseObject
{
/// <summary>
/// Initialize this <see cref="IGBaseObject"/> from a given <see cref="string"/>
/// </summary>
/// <param name="string">The given <see cref="string"/></param>
void InitializeFromString(string @string);
}
}

@ -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.Property)]
public class GBaseColumnAttribute : Attribute
{
public GBaseColumnAttribute(bool isKey = false)
{
IsKey = isKey;
}
public bool IsKey { get; }
}
}

@ -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,94 @@
// 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<IPoolItem<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<IPoolItem<IDataHandler>> WaitForDataHandler(object requester, CancellationToken cancellationToken)
{
IPoolItem<IDataHandler> dataHandlerItem = null;
IPoolRequest request = _poolRequestFactory.Create(requester);
while (dataHandlerItem == null)
{
if (_waitingRequesters.Contains(request) && _waitingRequesters.IndexOf(request) == 0) //request is in list and is first
{
if (_pool.Any(i => !i.InUse))
dataHandlerItem = 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 dataHandlerItem;
}
private IPoolItem<IDataHandler> CreateDataHandler(bool overwrite)
{
IPoolItem<IDataHandler> item = _poolItemFactory.Create(_dataHandlerFactory.Create());
item.Item.Init(overwrite);
_pool.Add(item);
return item;
}
private IPoolItem<IDataHandler> GetDataHandler() => _pool.First(i => !i.InUse);
public async ValueTask DisposeAsync()
{
while (_waitingRequesters.Any())
{
await Task.Delay(1000);
}
}
}
}

@ -0,0 +1,27 @@
// 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; private set; }
public T Use()
{
InUse = true;
return Item;
}
public void Dispose() => InUse = false;
}
}

@ -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;
@ -45,19 +48,15 @@ namespace GBase.DataHandling
/// <summary>
/// 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 +65,57 @@ 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))
return false;
public async Task<bool> AddEntry<T>(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken)
{
await _xmlDataWriter.InitFile(entryFile, table.Type.Name, cancellationToken);
_isInitialized = true;
foreach (var column in table.Columns)
{
//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 +127,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 +135,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 +152,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 +160,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 +175,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,76 +10,56 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using GBase.DataHandling.Exceptions;
using GBase.Helpers;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Xml;
namespace GBase.DataHandling
{
/// <summary>
/// A <see cref="IDataReader"/> that reads from a xml file
/// An <see cref="IDataReader"/> that reads from a xml file
/// </summary>
public class XmlDataReader : IXmlDataReader
{
private readonly FileStream _file;
private XDocument _xmlDocument;
private XElement _rootElement;
private bool _isInitialized;
private CancellationToken _cancellationToken;
private readonly IGBase _gBase;
/// <summary>
/// A <see cref="IDataReader"/> that reads from a xml file
/// An <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;
}
/// <param name="gBase">The <see cref="IGBase"/></param>
public XmlDataReader(IGBase gBase) => _gBase = gBase;
/// <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));
file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to load 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
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;
@ -95,19 +75,10 @@ namespace GBase.DataHandling
IEnumerable<string> values = valueElements.Select(v => v.Value);
if (typeof(TProperty) != typeof(string) && typeof(TProperty).GetInterfaces().Contains(typeof(IEnumerable))) //read property is an IEnumerable
return values.Select(Enumerables.ConvertToGBaseEnumerable<TProperty>).ToList();
return values.Select(s => Enumerables.ConvertToGBaseEnumerable<TProperty>(s, _gBase)).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,81 +19,68 @@ 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 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;
_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);
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);
}
_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"/></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>
/// <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="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
file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to load 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);
if (typeElement != null) //type element already exists
{
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);
if (propertyElement != null) //property element already exists
{
XElement valueElement = propertyElement.Element(XmlDataHandler.VALUE_ELEMENT_NAME);
@ -112,21 +100,13 @@ namespace GBase.DataHandling
else //property element doesn't exist
{
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.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, propertyType.FullName); //add the property type attribute
typeElement.Add(propertyElement); //create new property element with the value element
}
}
else //type 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
_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 +114,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 +143,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,24 @@
// Author: Gockner, Simon
// Created: 2020-11-13
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase.Exceptions
{
/// <summary>
/// Could not find generic method
/// </summary>
internal class GenericMethodNotFoundException : Exception
{
/// <summary>
/// Could not find generic method
/// </summary>
/// <param name="functionName">The name of the generic method</param>
public GenericMethodNotFoundException(string functionName)
: base($"Could not find function {functionName}")
{
}
}
}

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

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

@ -0,0 +1,17 @@
// Author: Gockner, Simon
// Created: 2020-11-13
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase.Exceptions
{
public class MissingKeyColumnException<T> : Exception
{
public MissingKeyColumnException()
: base($"Type {typeof(T)} is missing a key column.")
{
}
}
}

@ -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,49 @@
// Author: Simon Gockner
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using GBase.Exceptions;
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)
{
if (!typeof(IGBaseObject).IsAssignableFrom(type))
throw new InvalidTableTypeException(type);
Type gBaseTableType = typeof(GBaseTable<>).MakeGenericType(type);
return (IGBaseTable) Activator.CreateInstance(gBaseTableType, _fileHandlerFactory, _dataHandlerPool, _gBaseColumnFactory);
}
}
}

@ -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="IGBaseColumn"/>
/// </summary>
/// <returns>A newly created instance of the implementation for <see cref="IGBaseColumn"/></returns>
IGBaseColumn Create();
IGBaseColumn Create(string name, Type type, bool isKey);
}
}

@ -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,84 +18,91 @@ 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>
/// <param name="path">The path of the database</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(string path, CancellationToken cancellationToken)
public List<IGBaseFile> Init(string path, string folderName, CancellationToken cancellationToken)
{
DataHandler = _dataHandlerFactory.Create();
_path = path;
bool success = await DataHandler.Init(false, cancellationToken);
return success;
}
string directoryPath = Path.Combine(_path, folderName);
if (!Directory.Exists(directoryPath))
return null;
/// <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)
string[] files = Directory.GetFiles(directoryPath, $"*.{GBASE_TABLE_FILE_EXTENSION}");
foreach (var file in files)
{
await DataHandler.SetValue<T, TProperty>(propertyName, value);
FileStream entryFile = File.Open(file, FileMode.OpenOrCreate, FileAccess.ReadWrite);
_files.Add(new GBaseFile(null, entryFile, 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)
return _files;
}
public IGBaseFile CreateEntryFile<T>(T entry, IGBaseTable table) where T : IGBaseObject
{
await DataHandler.RemoveValue<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.FileName)}.{GBASE_TABLE_FILE_EXTENSION}";
//check if file is already opened
IGBaseFile file = _files.FirstOrDefault(f => f.FilePath.Equals(filePath));
if (file != null)
return file.UseFile();
FileStream entryFile = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
file = new GBaseFile(entry, entryFile, filePath);
_files.Add(file);
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 +111,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; set; }
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,21 @@ 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>() where T : IGBaseObject, new()
{
if (Tables.OfType<IGBaseTable<T>>().Any())
return Tables.OfType<IGBaseTable<T>>().First();
throw new MissingTableException<T>();
}
/// <summary>
/// Removes a given <see cref="IGBaseTable"/> from this <see cref="GBase"/>
/// </summary>
@ -113,6 +117,52 @@ namespace GBase
return Tables.Remove(table);
}
public async Task<bool> AddEntry<T>(T entry, CancellationToken cancellationToken) where T : IGBaseObject, new()
{
IGBaseTable<T> table = GetTable<T>();
if (table == null)
throw new MissingTableException<T>();
return await table.AddEntry(entry, cancellationToken);
}
public T GetEntryForKey<T>(int key) where T : IGBaseObject, new()
{
IGBaseTable<T> table = GetTable<T>();
if (table == null)
throw new MissingTableException<T>();
return table.GetEntryForKey(key);
}
public async Task SetValue<T, TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken) where T : IGBaseObject, new()
{
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) where T : IGBaseObject, new()
{
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) where T : IGBaseObject, new()
{
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>

@ -24,6 +24,7 @@
<ItemGroup>
<PackageReference Include="LightweightIocContainer" Version="2.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.5.0-beta2-final" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>
<ItemGroup>

@ -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,158 @@
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
An <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)">
<member name="M:GBase.DataHandling.XmlDataReader.#ctor(GBase.Interfaces.IGBase)">
<summary>
Initialize the <see cref="T:GBase.DataHandling.XmlDataReader"/>
An <see cref="T:GBase.Interfaces.DataHandling.IDataReader"/> that reads from a xml file
</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>
<param name="gBase">The <see cref="T:GBase.Interfaces.IGBase"/></param>
</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>
<exception cref="T:GBase.DataHandling.Exceptions.InvalidXmlFileException">No root element is set</exception>
</member>
<member name="M:GBase.DataHandling.XmlDataWriter.DisposeAsync">
<member name="T:GBase.Exceptions.GenericMethodNotFoundException">
<summary>
Dispose used resources asynchronously
Could not find generic method
</summary>
<returns>A <see cref="T:System.Threading.Tasks.ValueTask"/> to await</returns>
</member>
<member name="M:GBase.Exceptions.GenericMethodNotFoundException.#ctor(System.String)">
<summary>
Could not find generic method
</summary>
<param name="functionName">The name of the generic method</param>
</member>
<member name="T:GBase.Exceptions.InterfaceEnumerablePassedException">
<summary>
@ -361,12 +366,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.Interfaces.IGBaseObject"/>"/>
</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.Interfaces.IGBaseObject"/>"/>
</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,System.Type,System.Boolean)">
<summary>
Creates an <see cref="T:GBase.Interfaces.IGBaseColumn"/>
</summary>
@ -389,7 +434,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,63 +456,25 @@
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)">
<member name="M:GBase.FileHandling.FileHandler.Init(System.String,System.String,System.Threading.CancellationToken)">
<summary>
Initialize this <see cref="T:GBase.Interfaces.FileHandling.IFileHandler"/>
</summary>
<param name="path">The path of the database</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.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 +486,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 +542,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,System.Type,System.Boolean)">
<summary>
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
@ -551,91 +553,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"/>
Add an entry that implements <see cref="T:GBase.Interfaces.IGBaseObject"/> to this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/></param>
<param name="entry">The entry implementing <see cref="T:GBase.Interfaces.IGBaseObject"/></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"/>
Remove an entry that implements <see cref="T:GBase.Interfaces.IGBaseObject"/> 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>
<param name="entry">The entry implementing <see cref="T:GBase.Interfaces.IGBaseObject"/></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>
@ -646,17 +653,73 @@
Convert an <see cref="T:System.Collections.IEnumerable"/> to a GBase <see cref="T:System.String"/>
</summary>
<param name="enumerable">The <see cref="T:System.Collections.IEnumerable"/></param>
<returns></returns>
<returns>The converted <see cref="T:System.Collections.IEnumerable"/> as a GBase <see cref="T:System.String"/></returns>
</member>
<member name="M:GBase.Helpers.Enumerables.ConvertToGBaseEnumerable``1(System.String)">
<member name="M:GBase.Helpers.Enumerables.ConvertToGBaseEnumerable``1(System.String,GBase.Interfaces.IGBase)">
<summary>
Convert a given <see cref="T:System.String"/> to an <see cref="T:System.Collections.Generic.IEnumerable`1"/> of <see cref="T:System.Type"/> <typeparamref name="TEnumerable"/>
</summary>
<typeparam name="TEnumerable">The <see cref="T:System.Collections.Generic.IEnumerable`1"/> <see cref="T:System.Type"/></typeparam>
<typeparam name="T"></typeparam>
<param name="string">The given <see cref="T:System.String"/></param>
<param name="gBase"></param>
<returns>An <see cref="T:System.Collections.Generic.IEnumerable`1"/> of <see cref="T:System.Type"/> <typeparamref name="TEnumerable"/></returns>
<exception cref="T:GBase.Exceptions.InterfaceEnumerablePassedException">Interface was passed to an <see cref="T:System.Collections.Generic.IEnumerable`1"/></exception>
</member>
<member name="M:GBase.Helpers.GenericMethodCaller.Call(System.Object,System.String,System.Reflection.BindingFlags,System.Type,System.Object[])">
<summary>
Call a generic method without generic type parameters
</summary>
<param name="caller">The caller of the method</param>
<param name="functionName">The name of the method to call</param>
<param name="bindingFlags">The <see cref="T:System.Reflection.BindingFlags"/> to find the method</param>
<param name="genericParameter">The generic parameter as <see cref="T:System.Type"/> parameter</param>
<param name="parameters">The parameters of the method</param>
<returns>The result of invoking the method</returns>
<exception cref="T:GBase.Exceptions.GenericMethodNotFoundException">Could not find the generic method</exception>
<exception cref="T:System.Exception">Any <see cref="T:System.Exception"/> thrown after invoking the generic method</exception>
</member>
<member name="M:GBase.Helpers.GenericMethodCaller.Call(System.Object,System.String,System.Reflection.BindingFlags,System.Type,System.Type,System.Object[])">
<summary>
Call a generic method without generic type parameters
</summary>
<param name="caller">The caller of the method</param>
<param name="functionName">The name of the method to call</param>
<param name="bindingFlags">The <see cref="T:System.Reflection.BindingFlags"/> to find the method</param>
<param name="genericParameter">The generic parameter as <see cref="T:System.Type"/> parameter</param>
<param name="secondGenericParameter"></param>
<param name="parameters">The parameters of the method</param>
<returns>The result of invoking the method</returns>
<exception cref="T:GBase.Exceptions.GenericMethodNotFoundException">Could not find the generic method</exception>
<exception cref="T:System.Exception">Any <see cref="T:System.Exception"/> thrown after invoking the generic method</exception>
</member>
<member name="M:GBase.Helpers.GenericMethodCaller.CallAsync(System.Object,System.String,System.Reflection.BindingFlags,System.Type,System.Object[])">
<summary>
Call a generic method asynchronously without generic type parameters
</summary>
<param name="caller">The caller of the method</param>
<param name="functionName">The name of the method to call</param>
<param name="bindingFlags">The <see cref="T:System.Reflection.BindingFlags"/> to find the method</param>
<param name="genericParameter">The generic parameter as <see cref="T:System.Type"/> parameter</param>
<param name="parameters">The parameters of the method</param>
<returns>The result of invoking the method</returns>
<exception cref="T:GBase.Exceptions.GenericMethodNotFoundException">Could not find the generic method</exception>
<exception cref="T:System.Exception">Any <see cref="T:System.Exception"/> thrown after invoking the generic method</exception>
</member>
<member name="M:GBase.Helpers.GenericMethodCaller.CallAsync(System.Object,System.String,System.Reflection.BindingFlags,System.Type,System.Type,System.Object[])">
<summary>
Call a generic method asynchronously without generic type parameters
</summary>
<param name="caller">The caller of the method</param>
<param name="functionName">The name of the method to call</param>
<param name="bindingFlags">The <see cref="T:System.Reflection.BindingFlags"/> to find the method</param>
<param name="genericParameter">The generic parameter as <see cref="T:System.Type"/> parameter</param>
<param name="secondGenericParameter"></param>
<param name="parameters">The parameters of the method</param>
<returns>The result of invoking the method</returns>
<exception cref="T:GBase.Exceptions.GenericMethodNotFoundException">Could not find the generic method</exception>
<exception cref="T:System.Exception">Any <see cref="T:System.Exception"/> thrown after invoking the generic method</exception>
</member>
<member name="T:GBase.Installers.DataHandlingInstaller">
<summary>
<see cref="T:LightweightIocContainer.Interfaces.Installers.IIocInstaller"/> for the data handling
@ -707,13 +770,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 +821,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 +879,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 +895,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">
@ -891,52 +977,15 @@
Internal file handler
</summary>
</member>
<member name="M:GBase.Interfaces.FileHandling.IFileHandler.Init(System.String,System.Threading.CancellationToken)">
<member name="M:GBase.Interfaces.FileHandling.IFileHandler.Init(System.String,System.String,System.Threading.CancellationToken)">
<summary>
Initialize this <see cref="T:GBase.Interfaces.FileHandling.IFileHandler"/>
</summary>
<param name="path">The path of the database</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.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 +1034,47 @@
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="T:GBase.Interfaces.IGBaseObject">
<summary>
GBase object that allows conversion from <see cref="T:System.String"/>
</summary>
</member>
<member name="P:GBase.Interfaces.IGBaseObject.Key">
<summary>
<see cref="T:GBase.Interfaces.IGBase"/> Key
</summary>
</member>
<member name="P:GBase.Interfaces.IGBaseObject.FileName">
<summary>
The FileName of the GBase file for an entry of this object
</summary>
</member>
<member name="M:GBase.Interfaces.IGBaseObject.InitializeFromString(System.String)">
<summary>
Initialize this <see cref="T:GBase.Interfaces.IGBaseObject"/> from a given <see cref="T:System.String"/>
</summary>
<param name="string">The given <see cref="T:System.String"/></param>
</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.Interfaces.IGBaseObject"/> to this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Interfaces.IGBaseObject"/></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.Interfaces.IGBaseObject"/> from this <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
<param name="entry">The entry implementing <see cref="T:GBase.Interfaces.IGBaseObject"/></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 +1085,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 +1095,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 +1120,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,11 +16,17 @@ namespace GBase
/// <summary>
/// A column of a <see cref="IGBaseTable"/>
/// </summary>
public GBaseColumn()
public GBaseColumn(string name, Type type, bool isKey)
{
Name = name;
Type = type;
IsKey = isKey;
}
public string Name { get; }
public Type Type { get; }
public bool IsKey { get; }
/// <summary>
/// The <see cref="IAsyncDisposable.DisposeAsync"/> method
/// </summary>

@ -0,0 +1,30 @@
// Author: Gockner, Simon
// Created: 2020-11-13
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase
{
public class GBaseKey
{
private int _key = -1;
private bool _isSet;
public int Key
{
get => _key;
internal set
{
if (_isSet)
throw new InvalidOperationException("Key is already set.");
_key = value;
_isSet = true;
}
}
public override string ToString() => $"{Key}";
public static implicit operator int(GBaseKey key) => key.Key;
}
}

@ -0,0 +1,45 @@
// 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.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 where T : IGBaseObject, new()
{
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>();
}
public GBaseKey Key { get; set; }
public abstract string FileName { get; }
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);
public abstract void Initialize(GBaseKey key, List<object> parameters);
}
}

@ -4,16 +4,18 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using GBase.Api;
using GBase.Attributes;
using GBase.Exceptions;
using GBase.Factories;
using GBase.FileHandling.Factories;
using GBase.Helpers;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Pool;
using GBase.Interfaces.FileHandling;
namespace GBase
@ -21,21 +23,26 @@ namespace GBase
/// <summary>
/// A <see cref="IGBase"/> table
/// </summary>
public class GBaseTable : IGBaseTable
public class GBaseTable<T> : IGBaseTable<T> where T : IGBaseObject, new()
{
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 +54,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,38 +64,85 @@ namespace GBase
/// <summary>
/// The entries of this <see cref="IGBaseTable"/>
/// </summary>
public List<object> Entries { get; }
public List<T> Entries { get; }
private int CurrentLastKey
{
get
{
T lastEntry = Entries.LastOrDefault();
if (lastEntry == null)
return -1;
return lastEntry.Key;
}
}
/// <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 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;
//TODO: Init columns list depending on GBaseColumnAttributes set for this GBaseTable
foreach (var property in type.GetProperties())
{
GBaseColumnAttribute gBaseColumnAttribute = property.GetCustomAttribute<GBaseColumnAttribute>();
GBaseColumnAttribute gBaseColumnAttribute = property.GetCustomAttribute<GBaseColumnAttribute>() ??
property.GetAttributeFromInheritedInterfaces<GBaseColumnAttribute>();
if (gBaseColumnAttribute == null)
continue;
IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create();
IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create(property.Name, property.PropertyType, gBaseColumnAttribute.IsKey);
AddColumn(gBaseColumn);
}
return true;
List<IGBaseFile> files = _fileHandler.Init(databasePath, FolderName, cancellationToken);
if (files == null)
return;
foreach (var file in files) //create entries for existing files
{
using (file.UseFile())
{
T entry = new T();
List<object> parameters = new List<object>();
foreach (var column in Columns.Where(c => !c.IsKey))
{
using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
parameters.Add(await GenericMethodCaller.CallAsync(dataHandlerItem.Use(),
nameof(IDataHandler.GetValue),
BindingFlags.Public | BindingFlags.Instance,
typeof(T), column.Type,
file.File, column.Name, cancellationToken));
}
IGBaseColumn keyColumn = Columns.FirstOrDefault(c => c.IsKey);
if (keyColumn == null)
throw new MissingKeyColumnException<T>();
GBaseKey key = new GBaseKey();
using (IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken))
{
key.Key = await dataHandlerItem.Use().GetValue<T, int>(file.File, keyColumn.Name, cancellationToken);
}
entry.Initialize(key, parameters);
file.Entry = entry;
Entries.Add(entry);
}
}
}
/// <summary>
@ -96,7 +150,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 +164,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;
@ -119,58 +173,65 @@ namespace GBase
}
/// <summary>
/// Add an entry that implements <see cref="INotifyGBaseEntryChanged"/> to this <see cref="IGBaseTable"/>
/// Add an entry that implements <see cref="IGBaseObject"/> to this <see cref="IGBaseTable"/>
/// </summary>
/// <param name="entry">The entry implementing <see cref="INotifyGBaseEntryChanged"/></param>
/// <param name="entry">The entry implementing <see cref="IGBaseObject"/></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)
{
entry.Key ??= new GBaseKey();
if (entry.Key != -1)
throw new InvalidKeyException("Key of entry is already set. Make sure it is -1 when initializing.");
entry.Key.Key = CurrentLastKey + 1; //set next possible key
Entries.Add(entry);
entry.GBaseEntryChanged += OnGBaseEntryChanged;
using IGBaseFile file = _fileHandler.CreateEntryFile(entry, this);
using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
await dataHandlerItem.Use().AddEntry(entry, this, file.File, cancellationToken);
return true;
}
public T GetEntryForKey(int key) => Entries.FirstOrDefault(e => e.Key == key);
/// <summary>
/// Remove an entry that implements <see cref="INotifyGBaseEntryChanged"/> from this <see cref="IGBaseTable"/>
/// Remove an entry that implements <see cref="IGBaseObject"/> from this <see cref="IGBaseTable"/>
/// </summary>
/// <param name="entry">The entry implementing <see cref="INotifyGBaseEntryChanged"/></param>
/// <param name="entry">The entry implementing <see cref="IGBaseObject"/></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);
using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
await dataHandlerItem.Use().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);
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
return await dataHandlerItem.Use().GetValue<T, TProperty>(file.File, propertyName, cancellationToken);
}
if (!success)
throw new Exception("Failed to handle EntryChanged"); //TODO: Decide what to do here
public async Task<IEnumerable<TProperty>> GetValues<TProperty>(T entry, string propertyName, CancellationToken cancellationToken)
{
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
return await dataHandlerItem.Use().GetValues<T, TProperty>(file.File, propertyName, cancellationToken);
}
/// <summary>
@ -180,6 +241,7 @@ namespace GBase
public async ValueTask DisposeAsync()
{
await _fileHandler.DisposeAsync();
await _dataHandlerPool.DisposeAsync();
foreach (var column in Columns)
{
@ -188,9 +250,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();

@ -0,0 +1,19 @@
// Author: Gockner, Simon
// Created: 2020-11-13
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Linq;
using System.Reflection;
namespace GBase.Helpers
{
internal static class Attributes
{
public static T GetAttributeFromInheritedInterfaces<T>(this PropertyInfo propertyInfo) where T : Attribute =>
propertyInfo.DeclaringType?.GetInterfaces()
.SelectMany(i => i.GetProperties().Where(p => p.Name.Equals(propertyInfo.Name)))
.Select(p => p.GetCustomAttribute<T>())
.FirstOrDefault();
}
}

@ -6,9 +6,10 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using GBase.Api;
using GBase.Exceptions;
using GBase.Interfaces;
namespace GBase.Helpers
{
@ -20,12 +21,15 @@ namespace GBase.Helpers
/// Convert an <see cref="IEnumerable"/> to a GBase <see cref="string"/>
/// </summary>
/// <param name="enumerable">The <see cref="IEnumerable"/></param>
/// <returns></returns>
/// <returns>The converted <see cref="IEnumerable"/> as a GBase <see cref="string"/></returns>
public static string ToGBaseString(this IEnumerable enumerable)
{
StringBuilder @string = new StringBuilder();
foreach (var item in enumerable)
{
if (item is IGBaseObject gBaseObject)
@string.Append($"{gBaseObject.Key}{ENUMERABLE_STRING_DIVIDER}");
else
@string.Append($"{item}{ENUMERABLE_STRING_DIVIDER}");
}
@ -41,9 +45,10 @@ namespace GBase.Helpers
/// </summary>
/// <typeparam name="TEnumerable">The <see cref="IEnumerable{T}"/> <see cref="Type"/></typeparam>
/// <param name="string">The given <see cref="string"/></param>
/// <param name="gBase"></param>
/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="Type"/> <typeparamref name="TEnumerable"/></returns>
/// <exception cref="InterfaceEnumerablePassedException">Interface was passed to an <see cref="IEnumerable{T}"/></exception>
public static TEnumerable ConvertToGBaseEnumerable<TEnumerable>(string @string)
public static TEnumerable ConvertToGBaseEnumerable<TEnumerable>(string @string, IGBase gBase)
{
//get generic type parameter of TEnumerable
Type genericType = typeof(TEnumerable).GetGenericArguments()[0];
@ -61,9 +66,16 @@ namespace GBase.Helpers
if (genericType.IsInterface)
throw new InterfaceEnumerablePassedException(genericType);
IGBaseObject gBaseObject = (IGBaseObject) Activator.CreateInstance(genericType);
gBaseObject.InitializeFromString(value);
item = gBaseObject;
if (!int.TryParse(value, out int key))
throw new InvalidKeyException("Key is not an integer.");
//TODO: What to do when this table isn't initialized yet?
item = GenericMethodCaller.Call(gBase, nameof(IGBase.GetEntryForKey),
BindingFlags.Public | BindingFlags.Instance, genericType, key);
// IGBaseObject gBaseObject = (IGBaseObject) Activator.CreateInstance(genericType);
// gBaseObject.InitializeFromString(value);
// item = gBaseObject;
}
else
item = Convert.ChangeType(value, genericType);

@ -0,0 +1,108 @@
// Author: Gockner, Simon
// Created: 2020-11-13
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Reflection;
using System.Threading.Tasks;
using GBase.Exceptions;
namespace GBase.Helpers
{
internal static class GenericMethodCaller
{
/// <summary>
/// Call a generic method without generic type parameters
/// </summary>
/// <param name="caller">The caller of the method</param>
/// <param name="functionName">The name of the method to call</param>
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param>
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param>
/// <param name="parameters">The parameters of the method</param>
/// <returns>The result of invoking the method</returns>
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception>
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception>
public static object Call(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, params object[] parameters) =>
GetGenericMethod(caller, functionName, bindingFlags, genericParameter).InvokeGenericMethod(caller, parameters);
/// <summary>
/// Call a generic method without generic type parameters
/// </summary>
/// <param name="caller">The caller of the method</param>
/// <param name="functionName">The name of the method to call</param>
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param>
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param>
/// <param name="secondGenericParameter"></param>
/// <param name="parameters">The parameters of the method</param>
/// <returns>The result of invoking the method</returns>
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception>
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception>
public static object Call(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, Type secondGenericParameter,params object[] parameters) =>
GetGenericMethod(caller, functionName, bindingFlags, genericParameter, secondGenericParameter).InvokeGenericMethod(caller, parameters);
/// <summary>
/// Call a generic method asynchronously without generic type parameters
/// </summary>
/// <param name="caller">The caller of the method</param>
/// <param name="functionName">The name of the method to call</param>
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param>
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param>
/// <param name="parameters">The parameters of the method</param>
/// <returns>The result of invoking the method</returns>
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception>
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception>
public static async Task<object> CallAsync(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, params object[] parameters) =>
await GetGenericMethod(caller, functionName, bindingFlags, genericParameter).InvokeGenericMethodAsync(caller, parameters);
/// <summary>
/// Call a generic method asynchronously without generic type parameters
/// </summary>
/// <param name="caller">The caller of the method</param>
/// <param name="functionName">The name of the method to call</param>
/// <param name="bindingFlags">The <see cref="BindingFlags"/> to find the method</param>
/// <param name="genericParameter">The generic parameter as <see cref="Type"/> parameter</param>
/// <param name="secondGenericParameter"></param>
/// <param name="parameters">The parameters of the method</param>
/// <returns>The result of invoking the method</returns>
/// <exception cref="GenericMethodNotFoundException">Could not find the generic method</exception>
/// <exception cref="Exception">Any <see cref="Exception"/> thrown after invoking the generic method</exception>
public static async Task<object> CallAsync(object caller, string functionName, BindingFlags bindingFlags, Type genericParameter, Type secondGenericParameter, params object[] parameters) =>
await GetGenericMethod(caller, functionName, bindingFlags, genericParameter, secondGenericParameter).InvokeGenericMethodAsync(caller, parameters);
private static MethodInfo GetGenericMethod(object caller, string functionName, BindingFlags bindingFlags, params Type[] genericParameters)
{
MethodInfo genericMethod = caller.GetType().GetMethod(functionName, bindingFlags)?.MakeGenericMethod(genericParameters);
if (genericMethod == null)
throw new GenericMethodNotFoundException(functionName);
return genericMethod;
}
private static object InvokeGenericMethod(this MethodInfo genericMethod, object caller, params object[] parameters)
{
try //exceptions thrown by methods called with invoke are wrapped into another exception, the exception thrown by the invoked method can be returned by `Exception.GetBaseException()`
{
return genericMethod.Invoke(caller, parameters);
}
catch (Exception ex)
{
throw ex.GetBaseException();
}
}
private static async Task<object> InvokeGenericMethodAsync(this MethodInfo genericMethod, object caller, params object[] parameters)
{
try //exceptions thrown by methods called with invoke are wrapped into another exception, the exception thrown by the invoked method can be returned by `Exception.GetBaseException()`
{
dynamic awaitable = genericMethod.Invoke(caller, parameters);
await awaitable;
return awaitable.GetAwaiter().GetResult();
}
catch (Exception ex)
{
throw ex.GetBaseException();
}
}
}
}

@ -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,23 @@ 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<IPoolRequest, PoolRequest>();
container.Register<IPoolItemFactory, PoolItemFactory>();
container.RegisterFactory<IPoolRequestFactory>();
//factories
container.RegisterFactory<IDataHandlerFactory>();
container.RegisterFactory<IXmlDataHandlerFactory>();
container.RegisterFactory<IXmlDataReaderFactory>();
container.RegisterFactory<IXmlDataWriterFactory>();

@ -5,6 +5,7 @@
using GBase.Factories;
using GBase.Interfaces;
using LightweightIocContainer;
using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Installers;
@ -18,13 +19,12 @@ namespace GBase.Installers
/// <inheritdoc />
public void Install(IIocContainer container)
{
container.Register<IGBase, GBase>();
container.Register<IGBaseTable, GBaseTable>();
container.Register<IGBase, GBase>(Lifestyle.Singleton);
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 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<IPoolItem<IDataHandler>> RequestDataHandler(object requester, bool overwrite, CancellationToken cancellationToken);
}
}

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

@ -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; }
}
}

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using GBase.Api;
namespace GBase.Interfaces.FileHandling
{
@ -18,46 +19,15 @@ namespace GBase.Interfaces.FileHandling
/// Initialize this <see cref="IFileHandler"/>
/// </summary>
/// <param name="path">The path of the database</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(string path, CancellationToken cancellationToken);
List<IGBaseFile> Init(string path, string folderName, 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) where T : IGBaseObject;
/// <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; set; }
FileStream File { get; }
string FilePath { get; }
bool InUse { get; }
IGBaseFile UseFile();
}
}

@ -48,11 +48,20 @@ namespace GBase.Interfaces
/// <returns>True if successful, false if not</returns>
bool AddTable(IGBaseTable table);
IGBaseTable<T> GetTable<T>() where T : IGBaseObject, new();
/// <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) where T : IGBaseObject, new();
T GetEntryForKey<T>(int key) where T : IGBaseObject, new();
Task SetValue<T, TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken) where T : IGBaseObject, new();
Task<TProperty> GetValue<T, TProperty>(T entry, string propertyName, CancellationToken cancellationToken) where T : IGBaseObject, new();
Task<IEnumerable<TProperty>> GetValues<T, TProperty>(T entry, string propertyName, CancellationToken cancellationToken) where T : IGBaseObject, new();
}
}

@ -9,8 +9,10 @@ namespace GBase.Interfaces
/// <summary>
/// A column of a <see cref="IGBaseTable"/>
/// </summary>
public interface IGBaseColumn : IAsyncDisposable //TODO: Make column generic (generic type is type of the value of the column?)?
public interface IGBaseColumn : IAsyncDisposable
{
string Name { get; }
Type Type { get; }
bool IsKey { get; }
}
}

@ -0,0 +1,29 @@
// Author: Gockner, Simon
// Created: 2020-02-14
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Collections.Generic;
using GBase.Attributes;
namespace GBase.Interfaces
{
/// <summary>
/// GBase object that allows conversion from <see cref="string"/>
/// </summary>
public interface IGBaseObject
{
/// <summary>
/// <see cref="IGBase"/> Key
/// </summary>
[GBaseColumn(true)]
GBaseKey Key { get; set; }
/// <summary>
/// The FileName of the GBase file for an entry of this object
/// </summary>
string FileName { get; }
void Initialize(GBaseKey key, List<object> parameters);
}
}

@ -6,14 +6,44 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using GBase.Api;
namespace GBase.Interfaces
{
public interface IGBaseTable<T> : IGBaseTable where T : IGBaseObject, new()
{
/// <summary>
/// The entries of this <see cref="IGBaseTable"/>
/// </summary>
List<T> Entries { get; }
/// <summary>
/// Add an entry that implements <see cref="IGBaseObject"/> to this <see cref="IGBaseTable"/>
/// </summary>
/// <param name="entry">The entry implementing <see cref="IGBaseObject"/></param>
/// <param name="cancellationToken"></param>
/// <returns>True if successful, false if not</returns>
Task<bool> AddEntry(T entry, CancellationToken cancellationToken);
T GetEntryForKey(int key);
/// <summary>
/// Remove an entry that implements <see cref="IGBaseObject"/> from this <see cref="IGBaseTable"/>
/// </summary>
/// <param name="entry">The entry implementing <see cref="IGBaseObject"/></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>
public interface IGBaseTable : IAsyncDisposable //TODO: make generic?
public interface IGBaseTable : IAsyncDisposable
{
/// <summary>
/// The <see cref="System.Type"/> of the class that this <see cref="IGBaseTable"/> represents
@ -23,27 +53,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 Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken);
/// <summary>
/// Add a given <see cref="IGBaseColumn"/> to this <see cref="IGBaseTable"/>
@ -58,19 +84,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 |
## Xml File Structure
```xml
<Table>
<Column>
<Value >
<Value >
</Column>
</Table>
```
## Process
### StartUp
### GetValue
### SetValue

@ -1,3 +1,5 @@
# GBase
A database based on .net
[![Build Status](https://drone.gockn3r.com/api/badges/SimonG/GBase/status.svg)](https://drone.gockn3r.com/SimonG/GBase)

@ -3,12 +3,14 @@
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using GBase.DataHandling;
using GBase.DataHandling.Cache;
using GBase.DataHandling.Cache.Factories;
using GBase.DataHandling.Factories;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling.Xml;
using Moq;
using NUnit.Framework;
@ -27,12 +29,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.Of<IGBase>()));
Mock<IXmlDataHandlerCachePropertyEntryFactory> dataHandlerCachePropertyEntryFactoryMock = new Mock<IXmlDataHandlerCachePropertyEntryFactory>();
dataHandlerCachePropertyEntryFactoryMock.Setup(p => p.Create(It.IsAny<string>(), It.IsAny<object>()))
@ -48,21 +50,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);
xmlDataHandler.Init(false);
FileStream file = null; //FixMe: init this correctly if you want to run this test
await xmlDataHandler.Init(false, new CancellationToken());
//
//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) {Items = { model.Items[0], model.Items[1] }}, _cancellationTokenSource.Token);
await model.AddGroup(new Group(2) {Items = { model.Items[1], model.Items[2] }}, _cancellationTokenSource.Token);
await model.AddGroup(new Group(3) {Items = { model.Items[0], model.Items[2] }}, _cancellationTokenSource.Token);
}
}
}

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

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

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

@ -0,0 +1,43 @@
// Author: Gockner, Simon
// Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic;
using GBase;
using GBase.Attributes;
namespace Test.GBase.GBaseIntegrationTest
{
[GBaseTable("Items")]
public class Item : IItem
{
public Item()
{
}
public Item(string name, int number)
{
Name = name;
Number = number;
}
[GBaseColumn]
public string Name { get; private set; }
[GBaseColumn]
public int Number { get; private set; }
public GBaseKey Key { get; set; }
public string FileName => Name;
public override string ToString() => $"{Number}/{Name}";
public void Initialize(GBaseKey key, List<object> parameters)
{
Key = key;
Name = (string) parameters[0];
Number = (int) parameters[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<Item>();
Groups = new List<Group>();
}
public List<Item> Items { get; private set; }
public List<Group> 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.ToList();
//Items = (await _gBase.GetValues<Model, Item>(this, nameof(Items), cancellationToken)).Cast<IItem>().ToList();
IGBaseTable<Group> groupsTable = _gBase.GetTable<Group>();
Groups = groupsTable.Entries.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");
}
}

@ -2,11 +2,13 @@
// Created: 2020-03-09
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Threading;
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;
@ -23,17 +25,24 @@ 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>(), It.IsAny<Type>(), It.IsAny<bool>()))
.Callback<string, Type, bool>((name, type, isKey) => { gBaseColumn = new GBaseColumn(name, type, isKey); })
.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";

@ -5,6 +5,8 @@
using System.Collections.Generic;
using GBase.Exceptions;
using GBase.Helpers;
using GBase.Interfaces;
using Moq;
using NUnit.Framework;
using Test.GBase.TestClasses;
@ -85,7 +87,7 @@ namespace Test.GBase.Helpers
string @string = $"{list[0]},{list[1]},{list[2]}";
Assert.AreEqual(list, Enumerables.ConvertToGBaseEnumerable<List<string>>(@string));
Assert.AreEqual(list, Enumerables.ConvertToGBaseEnumerable<List<string>>(@string, Mock.Of<IGBase>()));
}
[Test]
@ -100,7 +102,7 @@ namespace Test.GBase.Helpers
string @string = $"{list[0]},{list[1]},{list[2]}";
Assert.AreEqual(list, Enumerables.ConvertToGBaseEnumerable<List<int>>(@string));
Assert.AreEqual(list, Enumerables.ConvertToGBaseEnumerable<List<int>>(@string, Mock.Of<IGBase>()));
}
[Test]
@ -115,7 +117,7 @@ namespace Test.GBase.Helpers
string @string = $"{list[0]},{list[1]},{list[2]}";
Assert.AreEqual(list, Enumerables.ConvertToGBaseEnumerable<List<UserType>>(@string));
Assert.AreEqual(list, Enumerables.ConvertToGBaseEnumerable<List<UserType>>(@string, Mock.Of<IGBase>()));
}
[Test]
@ -130,7 +132,7 @@ namespace Test.GBase.Helpers
string @string = $"{list[0]},{list[1]},{list[2]}";
InterfaceEnumerablePassedException exception = Assert.Throws<InterfaceEnumerablePassedException>(() => Enumerables.ConvertToGBaseEnumerable<List<IUserType>>(@string));
InterfaceEnumerablePassedException exception = Assert.Throws<InterfaceEnumerablePassedException>(() => Enumerables.ConvertToGBaseEnumerable<List<IUserType>>(@string, Mock.Of<IGBase>()));
Assert.AreEqual(typeof(IUserType), exception.InterfaceType);
}
}

@ -2,16 +2,25 @@
// Created: 2020-01-27
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Collections.Generic;
using GBase;
using GBase.Api;
using GBase.Attributes;
using GBase.Interfaces;
namespace Test.GBase.TestClasses
{
[GBaseTable]
public class Foo : NotifyGBaseEntryChanged
[GBaseTable("Foo")]
public class Foo : NotifyGBaseEntryChanged, IGBaseObject
{
private string _name;
public Foo()
{
}
public Foo(string name)
{
Name = name;
@ -27,5 +36,13 @@ namespace Test.GBase.TestClasses
RaiseGBaseEntryChanged(this, nameof(Name), _name);
}
}
public GBaseKey Key { get; set; }
public string FileName => Name;
public void Initialize(GBaseKey key, List<object> parameters)
{
throw new NotImplementedException();
}
}
}

@ -3,6 +3,7 @@
// Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Api;
using GBase.Interfaces;
namespace Test.GBase.TestClasses
{

@ -3,7 +3,9 @@
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using GBase;
namespace Test.GBase.TestClasses
{
@ -21,10 +23,12 @@ namespace Test.GBase.TestClasses
private int Number { get; set; }
public void InitializeFromString(string @string)
public GBaseKey Key { get; set; }
public string FileName { get; }
public void Initialize(GBaseKey key, List<object> parameters)
{
string numberString = @string.Split('_').Last();
Number = Convert.ToInt32(numberString);
throw new NotImplementedException();
}
public override string ToString() => $"{nameof(UserType)}_{nameof(Number)}_{Number}";

Loading…
Cancel
Save