Compare commits

...

46 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 01132a3784
Merge pull request #28 from SimonG96/ImproveDataHandling_#25 5 years ago
Simon G 23317c098e
Merge pull request #27 from SimonG96/ImproveDataHandling_#25 5 years ago
  1. 14
      .drone.yml
  2. 2
      .idea/.idea.GBase/.idea/modules.xml
  3. 14
      .idea/.idea.GBase/.idea/riderModule.iml
  4. 11
      GBase.Api/GBase.Api.xml
  5. 22
      GBase.Api/IGBaseObject.cs
  6. 7
      GBase/Attributes/GBaseColumnAttribute.cs
  7. 25
      GBase/DataHandling/Pool/DataHandlerPool.cs
  8. 10
      GBase/DataHandling/Pool/PoolItem.cs
  9. 8
      GBase/DataHandling/XmlDataHandler.cs
  10. 16
      GBase/DataHandling/XmlDataReader.cs
  11. 8
      GBase/DataHandling/XmlDataWriter.cs
  12. 17
      GBase/Exceptions/InvalidKeyException.cs
  13. 8
      GBase/Exceptions/InvalidTableTypeException.cs
  14. 17
      GBase/Exceptions/MissingKeyColumnException.cs
  15. 4
      GBase/Factories/GBaseTableFactory.cs
  16. 2
      GBase/Factories/IGBaseColumnFactory.cs
  17. 4
      GBase/FileHandling/FileHandler.cs
  18. 12
      GBase/GBase.cs
  19. 60
      GBase/GBase.xml
  20. 4
      GBase/GBaseColumn.cs
  21. 30
      GBase/GBaseKey.cs
  22. 12
      GBase/GBaseObject.cs
  23. 77
      GBase/GBaseTable.cs
  24. 19
      GBase/Helpers/Attributes.cs
  25. 26
      GBase/Helpers/Enumerables.cs
  26. 1
      GBase/Installers/DataHandlingInstaller.cs
  27. 3
      GBase/Installers/GBaseInstaller.cs
  28. 2
      GBase/Interfaces/DataHandling/IDataWriter.cs
  29. 2
      GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs
  30. 8
      GBase/Interfaces/DataHandling/Pool/IPoolItem.cs
  31. 3
      GBase/Interfaces/FileHandling/IFileHandler.cs
  32. 2
      GBase/Interfaces/IGBase.cs
  33. 3
      GBase/Interfaces/IGBaseColumn.cs
  34. 29
      GBase/Interfaces/IGBaseObject.cs
  35. 16
      GBase/Interfaces/IGBaseTable.cs
  36. 8
      README.md
  37. 3
      Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs
  38. 6
      Test.GBase/GBaseIntegrationTest/GBaseIntegrationTest.cs
  39. 26
      Test.GBase/GBaseIntegrationTest/Group.cs
  40. 5
      Test.GBase/GBaseIntegrationTest/IGroup.cs
  41. 4
      Test.GBase/GBaseIntegrationTest/IItem.cs
  42. 23
      Test.GBase/GBaseIntegrationTest/Item.cs
  43. 12
      Test.GBase/GBaseIntegrationTest/Model.cs
  44. 4
      Test.GBase/GBaseTableIntegrationTest.cs
  45. 10
      Test.GBase/Helpers/EnumerablesTest.cs
  46. 10
      Test.GBase/TestClasses/Foo.cs
  47. 1
      Test.GBase/TestClasses/IUserType.cs
  48. 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

@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <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> </modules>
</component> </component>
</project> </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 The new value
</summary> </summary>
</member> </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"> <member name="T:GBase.Api.INotifyGBaseEntryChanged">
<summary> <summary>
Notify the GBase that an entry has changed Notify the GBase that an entry has changed

@ -1,22 +0,0 @@
// Author: Gockner, Simon
// Created: 2020-02-14
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic;
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);
void Initialize(List<object> parameters);
}
}

@ -13,6 +13,11 @@ namespace GBase.Attributes
[AttributeUsage(AttributeTargets.Property)] [AttributeUsage(AttributeTargets.Property)]
public class GBaseColumnAttribute : Attribute public class GBaseColumnAttribute : Attribute
{ {
public GBaseColumnAttribute(bool isKey = false)
{
IsKey = isKey;
}
public bool IsKey { get; }
} }
} }

@ -37,7 +37,7 @@ namespace GBase.DataHandling.Pool
_waitingRequesters = new List<IPoolRequest>(); _waitingRequesters = new List<IPoolRequest>();
} }
public async Task<IDataHandler> RequestDataHandler(object requester, bool overwrite, CancellationToken cancellationToken) 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 if (_pool.All(i => i.InUse) && _pool.Count == _availableDataHandlers) //no free dataHandlers available
return await WaitForDataHandler(requester, cancellationToken); return await WaitForDataHandler(requester, cancellationToken);
@ -47,17 +47,17 @@ namespace GBase.DataHandling.Pool
return GetDataHandler(); return GetDataHandler();
} }
private async Task<IDataHandler> WaitForDataHandler(object requester, CancellationToken cancellationToken) private async Task<IPoolItem<IDataHandler>> WaitForDataHandler(object requester, CancellationToken cancellationToken)
{ {
IDataHandler dataHandler = null; IPoolItem<IDataHandler> dataHandlerItem = null;
IPoolRequest request = _poolRequestFactory.Create(requester); IPoolRequest request = _poolRequestFactory.Create(requester);
while (dataHandler == null) while (dataHandlerItem == null)
{ {
if (_waitingRequesters.Contains(request) && _waitingRequesters.IndexOf(request) == 0) //request is in list and is first if (_waitingRequesters.Contains(request) && _waitingRequesters.IndexOf(request) == 0) //request is in list and is first
{ {
if (_pool.Any(i => !i.InUse)) if (_pool.Any(i => !i.InUse))
dataHandler = GetDataHandler(); dataHandlerItem = GetDataHandler();
else else
await Task.Delay(1000, cancellationToken); await Task.Delay(1000, cancellationToken);
} }
@ -69,26 +69,19 @@ namespace GBase.DataHandling.Pool
_waitingRequesters.Remove(request); _waitingRequesters.Remove(request);
return dataHandler; return dataHandlerItem;
} }
private IDataHandler CreateDataHandler(bool overwrite) private IPoolItem<IDataHandler> CreateDataHandler(bool overwrite)
{ {
IPoolItem<IDataHandler> item = _poolItemFactory.Create(_dataHandlerFactory.Create()); IPoolItem<IDataHandler> item = _poolItemFactory.Create(_dataHandlerFactory.Create());
item.Item.Init(overwrite); item.Item.Init(overwrite);
_pool.Add(item); _pool.Add(item);
item.InUse = true; return item;
return item.Item;
} }
private IDataHandler GetDataHandler() private IPoolItem<IDataHandler> GetDataHandler() => _pool.First(i => !i.InUse);
{
IPoolItem<IDataHandler> item = _pool.First(i => !i.InUse);
item.InUse = true;
return item.Item;
}
public async ValueTask DisposeAsync() public async ValueTask DisposeAsync()
{ {

@ -14,6 +14,14 @@ namespace GBase.DataHandling.Pool
} }
public T Item { get; } public T Item { get; }
public bool InUse { get; set; } public bool InUse { get; private set; }
public T Use()
{
InUse = true;
return Item;
}
public void Dispose() => InUse = false;
} }
} }

@ -48,7 +48,6 @@ namespace GBase.DataHandling
/// <summary> /// <summary>
/// A <see cref="IDataHandler"/> that handles its data in an xml file /// A <see cref="IDataHandler"/> that handles its data in an xml file
/// </summary> /// </summary>
/// <param name="path">The path to the xml file</param>
/// <param name="xmlDataReaderFactory">The <see cref="IXmlDataReader"/> factory</param> /// <param name="xmlDataReaderFactory">The <see cref="IXmlDataReader"/> factory</param>
/// <param name="xmlDataWriterFactory">The <see cref="IXmlDataWriter"/> factory</param> /// <param name="xmlDataWriterFactory">The <see cref="IXmlDataWriter"/> factory</param>
/// <param name="xmlDataHandlerCacheFactory">The <see cref="IXmlDataHandlerCache"/> factory</param> /// <param name="xmlDataHandlerCacheFactory">The <see cref="IXmlDataHandlerCache"/> factory</param>
@ -80,12 +79,11 @@ namespace GBase.DataHandling
public async Task<bool> AddEntry<T>(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken) public async Task<bool> AddEntry<T>(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken)
{ {
if (!await _xmlDataWriter.InitFile(entryFile, table.Type.Name, cancellationToken)) await _xmlDataWriter.InitFile(entryFile, table.Type.Name, cancellationToken);
return false;
foreach (var column in table.Columns) foreach (var column in table.Columns)
{ {
//TODO: Set value for each column //set value for each column
PropertyInfo property = entry.GetType().GetProperty(column.Name); PropertyInfo property = entry.GetType().GetProperty(column.Name);
if (property == null) if (property == null)
continue; //TODO: What to do in this case? (Shouldn't really happen...) continue; //TODO: What to do in this case? (Shouldn't really happen...)

@ -12,16 +12,25 @@ using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
using GBase.DataHandling.Exceptions; using GBase.DataHandling.Exceptions;
using GBase.Helpers; using GBase.Helpers;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling; using GBase.Interfaces.DataHandling;
using GBase.Interfaces.DataHandling.Xml; using GBase.Interfaces.DataHandling.Xml;
namespace GBase.DataHandling namespace GBase.DataHandling
{ {
/// <summary> /// <summary>
/// A <see cref="IDataReader"/> that reads from a xml file /// An <see cref="IDataReader"/> that reads from a xml file
/// </summary> /// </summary>
public class XmlDataReader : IXmlDataReader public class XmlDataReader : IXmlDataReader
{ {
private readonly IGBase _gBase;
/// <summary>
/// An <see cref="IDataReader"/> that reads from a xml file
/// </summary>
/// <param name="gBase">The <see cref="IGBase"/></param>
public XmlDataReader(IGBase gBase) => _gBase = gBase;
/// <summary> /// <summary>
/// Read the data of a property /// Read the data of a property
/// </summary> /// </summary>
@ -40,6 +49,7 @@ namespace GBase.DataHandling
if (typeName == null) if (typeName == null)
throw new ArgumentNullException(nameof(typeName)); 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); 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 file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it
@ -65,9 +75,9 @@ namespace GBase.DataHandling
IEnumerable<string> values = valueElements.Select(v => v.Value); IEnumerable<string> values = valueElements.Select(v => v.Value);
if (typeof(TProperty) != typeof(string) && typeof(TProperty).GetInterfaces().Contains(typeof(IEnumerable))) //read property is an IEnumerable 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(); return values.Select(value => (TProperty) Convert.ChangeType(value, typeof(TProperty))).ToList();
}, cancellationToken); }, cancellationToken);
} }
} }

@ -27,18 +27,16 @@ namespace GBase.DataHandling
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns> /// <returns>Returns true if successful, false if not</returns>
/// <exception cref="Exception">No root element found</exception> /// <exception cref="Exception">No root element found</exception>
public async Task<bool> InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken) public async Task InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken)
{ {
//if the xml file isn't empty, return //if the xml file isn't empty, return
if (file.Length > 3) //> 3 because of BOM if (file.Length > 3) //> 3 because of BOM
return true; //TODO: Don't return bool? return;
XDocument xmlDocument = new XDocument(); XDocument xmlDocument = new XDocument();
xmlDocument.Add(new XElement(rootElementName)); xmlDocument.Add(new XElement(rootElementName));
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 save it
await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken);
return true;
} }
/// <summary> /// <summary>
@ -74,7 +72,7 @@ namespace GBase.DataHandling
if (typeName == null) if (typeName == null)
throw new ArgumentNullException(nameof(typeName)); 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); 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 file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it

@ -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)
{
}
}
}

@ -3,21 +3,21 @@
// Copyright(c) 2020 SimonG. All Rights Reserved. // Copyright(c) 2020 SimonG. All Rights Reserved.
using System; using System;
using GBase.Api; using GBase.Interfaces;
namespace GBase.Exceptions namespace GBase.Exceptions
{ {
/// <summary> /// <summary>
/// <see cref="Exception"/> that the passed table type doesn't implement <see cref="INotifyGBaseEntryChanged"/>"/> /// <see cref="Exception"/> that the passed table type doesn't implement <see cref="IGBaseObject"/>"/>
/// </summary> /// </summary>
public class InvalidTableTypeException : Exception public class InvalidTableTypeException : Exception
{ {
/// <summary> /// <summary>
/// <see cref="Exception"/> that the passed table type doesn't implement <see cref="INotifyGBaseEntryChanged"/>"/> /// <see cref="Exception"/> that the passed table type doesn't implement <see cref="IGBaseObject"/>"/>
/// </summary> /// </summary>
/// <param name="type">The table type</param> /// <param name="type">The table type</param>
public InvalidTableTypeException(Type type) public InvalidTableTypeException(Type type)
: base($"Table type ({type}) doesn't implement {nameof(INotifyGBaseEntryChanged)}.") : base($"Table type ({type}) doesn't implement {nameof(IGBaseObject)}.")
{ {
Type = type; Type = type;
} }

@ -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.")
{
}
}
}

@ -3,6 +3,7 @@
// Copyright(c) 2020 SimonG. All Rights Reserved. // Copyright(c) 2020 SimonG. All Rights Reserved.
using System; using System;
using GBase.Exceptions;
using GBase.FileHandling.Factories; using GBase.FileHandling.Factories;
using GBase.Interfaces; using GBase.Interfaces;
using GBase.Interfaces.DataHandling.Pool; using GBase.Interfaces.DataHandling.Pool;
@ -38,6 +39,9 @@ namespace GBase.Factories
/// <returns>A newly created instance of the implementation for <see cref="IGBaseTable"/></returns> /// <returns>A newly created instance of the implementation for <see cref="IGBaseTable"/></returns>
public IGBaseTable Create(Type type) public IGBaseTable Create(Type type)
{ {
if (!typeof(IGBaseObject).IsAssignableFrom(type))
throw new InvalidTableTypeException(type);
Type gBaseTableType = typeof(GBaseTable<>).MakeGenericType(type); Type gBaseTableType = typeof(GBaseTable<>).MakeGenericType(type);
return (IGBaseTable) Activator.CreateInstance(gBaseTableType, _fileHandlerFactory, _dataHandlerPool, _gBaseColumnFactory); return (IGBaseTable) Activator.CreateInstance(gBaseTableType, _fileHandlerFactory, _dataHandlerPool, _gBaseColumnFactory);
} }

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

@ -60,7 +60,7 @@ namespace GBase.FileHandling
return _files; return _files;
} }
public IGBaseFile CreateEntryFile<T>(T entry, IGBaseTable table) public IGBaseFile CreateEntryFile<T>(T entry, IGBaseTable table) where T : IGBaseObject
{ {
string directoryPath = Path.Combine(_path, table.FolderName); string directoryPath = Path.Combine(_path, table.FolderName);
@ -68,7 +68,7 @@ namespace GBase.FileHandling
Directory.CreateDirectory(directoryPath); Directory.CreateDirectory(directoryPath);
//create new entry file //create new entry file
string filePath = $"{Path.Combine(directoryPath, entry.ToString())}.{GBASE_TABLE_FILE_EXTENSION}"; string filePath = $"{Path.Combine(directoryPath, entry.FileName)}.{GBASE_TABLE_FILE_EXTENSION}";
//check if file is already opened //check if file is already opened
IGBaseFile file = _files.FirstOrDefault(f => f.FilePath.Equals(filePath)); IGBaseFile file = _files.FirstOrDefault(f => f.FilePath.Equals(filePath));

@ -8,7 +8,6 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using GBase.Api;
using GBase.Attributes; using GBase.Attributes;
using GBase.Exceptions; using GBase.Exceptions;
using GBase.Factories; using GBase.Factories;
@ -103,8 +102,6 @@ namespace GBase
return Tables.OfType<IGBaseTable<T>>().First(); return Tables.OfType<IGBaseTable<T>>().First();
throw new MissingTableException<T>(); throw new MissingTableException<T>();
// //TODO: This probably doesn't work, because even though t.Type : T, IGBaseTable<t.Type> !: IGBaseTable<T>
// return (IGBaseTable<T>) Convert.ChangeType(Tables.FirstOrDefault(t => typeof(T).IsAssignableFrom(t.Type)), typeof(IGBaseTable<T>)); //TestMe
} }
/// <summary> /// <summary>
@ -129,6 +126,15 @@ namespace GBase
return await table.AddEntry(entry, cancellationToken); 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() public async Task SetValue<T, TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken) where T : IGBaseObject, new()
{ {
IGBaseTable<T> table = GetTable<T>(); IGBaseTable<T> table = GetTable<T>();

@ -201,7 +201,6 @@
<summary> <summary>
A <see cref="T:GBase.Interfaces.DataHandling.IDataHandler"/> that handles its data in an xml file A <see cref="T:GBase.Interfaces.DataHandling.IDataHandler"/> that handles its data in an xml file
</summary> </summary>
<param name="path">The path to the xml file</param>
<param name="xmlDataReaderFactory">The <see cref="T:GBase.Interfaces.DataHandling.Xml.IXmlDataReader"/> factory</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="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> <param name="xmlDataHandlerCacheFactory">The <see cref="T:GBase.Interfaces.DataHandling.Xml.Cache.IXmlDataHandlerCache"/> factory</param>
@ -261,9 +260,15 @@
</member> </member>
<member name="T:GBase.DataHandling.XmlDataReader"> <member name="T:GBase.DataHandling.XmlDataReader">
<summary> <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> </summary>
</member> </member>
<member name="M:GBase.DataHandling.XmlDataReader.#ctor(GBase.Interfaces.IGBase)">
<summary>
An <see cref="T:GBase.Interfaces.DataHandling.IDataReader"/> that reads from a xml file
</summary>
<param name="gBase">The <see cref="T:GBase.Interfaces.IGBase"/></param>
</member>
<member name="M:GBase.DataHandling.XmlDataReader.Read``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)"> <member name="M:GBase.DataHandling.XmlDataReader.Read``2(System.IO.FileStream,System.String,System.Threading.CancellationToken)">
<summary> <summary>
Read the data of a property Read the data of a property
@ -363,12 +368,12 @@
</member> </member>
<member name="T:GBase.Exceptions.InvalidTableTypeException"> <member name="T:GBase.Exceptions.InvalidTableTypeException">
<summary> <summary>
<see cref="T:System.Exception"/> that the passed table type doesn't implement <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/>"/> <see cref="T:System.Exception"/> that the passed table type doesn't implement <see cref="T:GBase.Interfaces.IGBaseObject"/>"/>
</summary> </summary>
</member> </member>
<member name="M:GBase.Exceptions.InvalidTableTypeException.#ctor(System.Type)"> <member name="M:GBase.Exceptions.InvalidTableTypeException.#ctor(System.Type)">
<summary> <summary>
<see cref="T:System.Exception"/> that the passed table type doesn't implement <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/>"/> <see cref="T:System.Exception"/> that the passed table type doesn't implement <see cref="T:GBase.Interfaces.IGBaseObject"/>"/>
</summary> </summary>
<param name="type">The table type</param> <param name="type">The table type</param>
</member> </member>
@ -406,7 +411,7 @@
Factory for the <see cref="T:GBase.Interfaces.IGBaseColumn"/> Factory for the <see cref="T:GBase.Interfaces.IGBaseColumn"/>
</summary> </summary>
</member> </member>
<member name="M:GBase.Factories.IGBaseColumnFactory.Create(System.String,System.Type)"> <member name="M:GBase.Factories.IGBaseColumnFactory.Create(System.String,System.Type,System.Boolean)">
<summary> <summary>
Creates an <see cref="T:GBase.Interfaces.IGBaseColumn"/> Creates an <see cref="T:GBase.Interfaces.IGBaseColumn"/>
</summary> </summary>
@ -537,7 +542,7 @@
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/> A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary> </summary>
</member> </member>
<member name="M:GBase.GBaseColumn.#ctor(System.String,System.Type)"> <member name="M:GBase.GBaseColumn.#ctor(System.String,System.Type,System.Boolean)">
<summary> <summary>
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/> A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary> </summary>
@ -624,17 +629,17 @@
</member> </member>
<member name="M:GBase.GBaseTable`1.AddEntry(`0,System.Threading.CancellationToken)"> <member name="M:GBase.GBaseTable`1.AddEntry(`0,System.Threading.CancellationToken)">
<summary> <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> </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> <param name="cancellationToken"></param>
<returns>True if successful, false if not</returns> <returns>True if successful, false if not</returns>
</member> </member>
<member name="M:GBase.GBaseTable`1.RemoveEntry(`0)"> <member name="M:GBase.GBaseTable`1.RemoveEntry(`0)">
<summary> <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> </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>
<returns>True if successful, false if not</returns> <returns>True if successful, false if not</returns>
</member> </member>
<member name="M:GBase.GBaseTable`1.DisposeAsync"> <member name="M:GBase.GBaseTable`1.DisposeAsync">
@ -648,14 +653,16 @@
Convert an <see cref="T:System.Collections.IEnumerable"/> to a GBase <see cref="T:System.String"/> Convert an <see cref="T:System.Collections.IEnumerable"/> to a GBase <see cref="T:System.String"/>
</summary> </summary>
<param name="enumerable">The <see cref="T:System.Collections.IEnumerable"/></param> <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>
<member name="M:GBase.Helpers.Enumerables.ConvertToGBaseEnumerable``1(System.String)"> <member name="M:GBase.Helpers.Enumerables.ConvertToGBaseEnumerable``1(System.String,GBase.Interfaces.IGBase)">
<summary> <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"/> 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> </summary>
<typeparam name="TEnumerable">The <see cref="T:System.Collections.Generic.IEnumerable`1"/> <see cref="T:System.Type"/></typeparam> <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="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> <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> <exception cref="T:GBase.Exceptions.InterfaceEnumerablePassedException">Interface was passed to an <see cref="T:System.Collections.Generic.IEnumerable`1"/></exception>
</member> </member>
@ -1027,6 +1034,27 @@
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/> A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary> </summary>
</member> </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"> <member name="P:GBase.Interfaces.IGBaseTable`1.Entries">
<summary> <summary>
The entries of this <see cref="T:GBase.Interfaces.IGBaseTable"/> The entries of this <see cref="T:GBase.Interfaces.IGBaseTable"/>
@ -1034,17 +1062,17 @@
</member> </member>
<member name="M:GBase.Interfaces.IGBaseTable`1.AddEntry(`0,System.Threading.CancellationToken)"> <member name="M:GBase.Interfaces.IGBaseTable`1.AddEntry(`0,System.Threading.CancellationToken)">
<summary> <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> </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> <param name="cancellationToken"></param>
<returns>True if successful, false if not</returns> <returns>True if successful, false if not</returns>
</member> </member>
<member name="M:GBase.Interfaces.IGBaseTable`1.RemoveEntry(`0)"> <member name="M:GBase.Interfaces.IGBaseTable`1.RemoveEntry(`0)">
<summary> <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> </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>
<returns>True if successful, false if not</returns> <returns>True if successful, false if not</returns>
</member> </member>
<member name="T:GBase.Interfaces.IGBaseTable"> <member name="T:GBase.Interfaces.IGBaseTable">

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

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

@ -5,7 +5,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using GBase.Api;
using GBase.Exceptions; using GBase.Exceptions;
using GBase.Interfaces; using GBase.Interfaces;
@ -29,6 +28,9 @@ namespace GBase
throw new MissingTableException<T>(); 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) => protected async Task SetValue<TProperty>(T @this, string propertyName, TProperty value, CancellationToken cancellationToken) =>
await _gBaseTable.SetValue(@this, propertyName, value, cancellationToken); await _gBaseTable.SetValue(@this, propertyName, value, cancellationToken);
@ -37,13 +39,7 @@ namespace GBase
protected async Task<IEnumerable<TProperty>> GetValues<TProperty>(T @this, string propertyName, CancellationToken cancellationToken) => protected async Task<IEnumerable<TProperty>> GetValues<TProperty>(T @this, string propertyName, CancellationToken cancellationToken) =>
await _gBaseTable.GetValues<TProperty>(@this, propertyName, cancellationToken); await _gBaseTable.GetValues<TProperty>(@this, propertyName, cancellationToken);
/// <summary>
/// Initialize this <see cref="GBaseObject{T}"/> from a given <see cref="string"/>
/// </summary>
/// <param name="string">The given <see cref="string"/></param>
public abstract void InitializeFromString(string @string);
public abstract void Initialize(List<object> parameters); public abstract void Initialize(GBaseKey key, List<object> parameters);
} }
} }

@ -8,8 +8,8 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using GBase.Api;
using GBase.Attributes; using GBase.Attributes;
using GBase.Exceptions;
using GBase.Factories; using GBase.Factories;
using GBase.FileHandling.Factories; using GBase.FileHandling.Factories;
using GBase.Helpers; using GBase.Helpers;
@ -66,6 +66,18 @@ namespace GBase
/// </summary> /// </summary>
public List<T> Entries { get; } public List<T> Entries { get; }
private int CurrentLastKey
{
get
{
T lastEntry = Entries.LastOrDefault();
if (lastEntry == null)
return -1;
return lastEntry.Key;
}
}
/// <summary> /// <summary>
/// Initialize this <see cref="IGBase"/> /// Initialize this <see cref="IGBase"/>
@ -75,7 +87,7 @@ namespace GBase
/// <param name="folderName"></param> /// <param name="folderName"></param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the asynchronous operation</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the asynchronous operation</param>
/// <returns>True if successful, false if not</returns> /// <returns>True if successful, false if not</returns>
public async Task<bool> Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken) //TODO: Remove bool return value? public async Task Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken)
{ {
Type = type; Type = type;
FolderName = folderName; FolderName = folderName;
@ -83,17 +95,19 @@ namespace GBase
//TODO: Init columns list depending on GBaseColumnAttributes set for this GBaseTable //TODO: Init columns list depending on GBaseColumnAttributes set for this GBaseTable
foreach (var property in type.GetProperties()) foreach (var property in type.GetProperties())
{ {
GBaseColumnAttribute gBaseColumnAttribute = property.GetCustomAttribute<GBaseColumnAttribute>(); GBaseColumnAttribute gBaseColumnAttribute = property.GetCustomAttribute<GBaseColumnAttribute>() ??
property.GetAttributeFromInheritedInterfaces<GBaseColumnAttribute>();
if (gBaseColumnAttribute == null) if (gBaseColumnAttribute == null)
continue; continue;
IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create(property.Name, property.PropertyType); IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create(property.Name, property.PropertyType, gBaseColumnAttribute.IsKey);
AddColumn(gBaseColumn); AddColumn(gBaseColumn);
} }
List<IGBaseFile> files = _fileHandler.Init(databasePath, FolderName, cancellationToken); List<IGBaseFile> files = _fileHandler.Init(databasePath, FolderName, cancellationToken);
if (files == null) if (files == null)
return true; return;
foreach (var file in files) //create entries for existing files foreach (var file in files) //create entries for existing files
{ {
@ -102,25 +116,33 @@ namespace GBase
T entry = new T(); T entry = new T();
List<object> parameters = new List<object>(); List<object> parameters = new List<object>();
foreach (var column in Columns) foreach (var column in Columns.Where(c => !c.IsKey))
{ {
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
parameters.Add(await GenericMethodCaller.CallAsync(dataHandler, parameters.Add(await GenericMethodCaller.CallAsync(dataHandlerItem.Use(),
nameof(IDataHandler.GetValue), nameof(IDataHandler.GetValue),
BindingFlags.Public | BindingFlags.Instance, BindingFlags.Public | BindingFlags.Instance,
typeof(T), column.Type, typeof(T), column.Type,
file.File, column.Name, cancellationToken)); 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(parameters); entry.Initialize(key, parameters);
file.Entry = entry; file.Entry = entry;
Entries.Add(entry); Entries.Add(entry);
} }
} }
return true;
} }
/// <summary> /// <summary>
@ -151,26 +173,35 @@ namespace GBase
} }
/// <summary> /// <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> /// </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> /// <param name="cancellationToken"></param>
/// <returns>True if successful, false if not</returns> /// <returns>True if successful, false if not</returns>
public async Task<bool> AddEntry(T entry, CancellationToken cancellationToken) 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); Entries.Add(entry);
using IGBaseFile file = _fileHandler.CreateEntryFile(entry, this); using IGBaseFile file = _fileHandler.CreateEntryFile(entry, this);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
await dataHandler.AddEntry(entry, this, file.File, cancellationToken); await dataHandlerItem.Use().AddEntry(entry, this, file.File, cancellationToken);
return true; return true;
} }
public T GetEntryForKey(int key) => Entries.FirstOrDefault(e => e.Key == key);
/// <summary> /// <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> /// </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> /// <returns>True if successful, false if not</returns>
public async Task<bool> RemoveEntry(T entry) public async Task<bool> RemoveEntry(T entry)
{ {
@ -185,22 +216,22 @@ namespace GBase
public async Task SetValue<TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken) public async Task SetValue<TProperty>(T entry, string propertyName, TProperty value, CancellationToken cancellationToken)
{ {
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry); using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
await dataHandler.SetValue<T, TProperty>(file.File, propertyName, value, cancellationToken); await dataHandlerItem.Use().SetValue<T, TProperty>(file.File, propertyName, value, cancellationToken);
} }
public async Task<TProperty> GetValue<TProperty>(T entry, string propertyName, CancellationToken cancellationToken) public async Task<TProperty> GetValue<TProperty>(T entry, string propertyName, CancellationToken cancellationToken)
{ {
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry); using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
return await dataHandler.GetValue<T, TProperty>(file.File, propertyName, cancellationToken); return await dataHandlerItem.Use().GetValue<T, TProperty>(file.File, propertyName, cancellationToken);
} }
public async Task<IEnumerable<TProperty>> GetValues<TProperty>(T entry, string propertyName, CancellationToken cancellationToken) public async Task<IEnumerable<TProperty>> GetValues<TProperty>(T entry, string propertyName, CancellationToken cancellationToken)
{ {
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry); using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
return await dataHandler.GetValues<T, TProperty>(file.File, propertyName, cancellationToken); return await dataHandlerItem.Use().GetValues<T, TProperty>(file.File, propertyName, cancellationToken);
} }
/// <summary> /// <summary>

@ -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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Text; using System.Text;
using GBase.Api;
using GBase.Exceptions; using GBase.Exceptions;
using GBase.Interfaces;
namespace GBase.Helpers namespace GBase.Helpers
{ {
@ -20,13 +21,16 @@ namespace GBase.Helpers
/// Convert an <see cref="IEnumerable"/> to a GBase <see cref="string"/> /// Convert an <see cref="IEnumerable"/> to a GBase <see cref="string"/>
/// </summary> /// </summary>
/// <param name="enumerable">The <see cref="IEnumerable"/></param> /// <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) public static string ToGBaseString(this IEnumerable enumerable)
{ {
StringBuilder @string = new StringBuilder(); StringBuilder @string = new StringBuilder();
foreach (var item in enumerable) foreach (var item in enumerable)
{ {
@string.Append($"{item}{ENUMERABLE_STRING_DIVIDER}"); if (item is IGBaseObject gBaseObject)
@string.Append($"{gBaseObject.Key}{ENUMERABLE_STRING_DIVIDER}");
else
@string.Append($"{item}{ENUMERABLE_STRING_DIVIDER}");
} }
char lastChar = @string[^1]; char lastChar = @string[^1];
@ -41,9 +45,10 @@ namespace GBase.Helpers
/// </summary> /// </summary>
/// <typeparam name="TEnumerable">The <see cref="IEnumerable{T}"/> <see cref="Type"/></typeparam> /// <typeparam name="TEnumerable">The <see cref="IEnumerable{T}"/> <see cref="Type"/></typeparam>
/// <param name="string">The given <see cref="string"/></param> /// <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> /// <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> /// <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 //get generic type parameter of TEnumerable
Type genericType = typeof(TEnumerable).GetGenericArguments()[0]; Type genericType = typeof(TEnumerable).GetGenericArguments()[0];
@ -61,9 +66,16 @@ namespace GBase.Helpers
if (genericType.IsInterface) if (genericType.IsInterface)
throw new InterfaceEnumerablePassedException(genericType); throw new InterfaceEnumerablePassedException(genericType);
IGBaseObject gBaseObject = (IGBaseObject) Activator.CreateInstance(genericType); if (!int.TryParse(value, out int key))
gBaseObject.InitializeFromString(value); throw new InvalidKeyException("Key is not an integer.");
item = gBaseObject;
//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 else
item = Convert.ChangeType(value, genericType); item = Convert.ChangeType(value, genericType);

@ -38,6 +38,7 @@ namespace GBase.Installers
//pool //pool
container.Register<IDataHandlerPool, DataHandlerPool>(Lifestyle.Singleton).WithParameters(10); container.Register<IDataHandlerPool, DataHandlerPool>(Lifestyle.Singleton).WithParameters(10);
container.Register<IPoolRequest, PoolRequest>();
container.Register<IPoolItemFactory, PoolItemFactory>(); container.Register<IPoolItemFactory, PoolItemFactory>();
container.RegisterFactory<IPoolRequestFactory>(); container.RegisterFactory<IPoolRequestFactory>();

@ -5,6 +5,7 @@
using GBase.Factories; using GBase.Factories;
using GBase.Interfaces; using GBase.Interfaces;
using LightweightIocContainer;
using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces;
using LightweightIocContainer.Interfaces.Installers; using LightweightIocContainer.Interfaces.Installers;
@ -18,7 +19,7 @@ namespace GBase.Installers
/// <inheritdoc /> /// <inheritdoc />
public void Install(IIocContainer container) public void Install(IIocContainer container)
{ {
container.Register<IGBase, GBase>(); container.Register<IGBase, GBase>(Lifestyle.Singleton);
container.Register<IGBaseColumn, GBaseColumn>(); container.Register<IGBaseColumn, GBaseColumn>();
//factories //factories

@ -21,7 +21,7 @@ namespace GBase.Interfaces.DataHandling
/// <param name="rootElementName"></param> /// <param name="rootElementName"></param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns> /// <returns>Returns true if successful, false if not</returns>
Task<bool> InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken); Task InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Write the data of a property /// Write the data of a property

@ -10,6 +10,6 @@ namespace GBase.Interfaces.DataHandling.Pool
{ {
public interface IDataHandlerPool : IAsyncDisposable public interface IDataHandlerPool : IAsyncDisposable
{ {
Task<IDataHandler> RequestDataHandler(object requester, bool overwrite, CancellationToken cancellationToken); Task<IPoolItem<IDataHandler>> RequestDataHandler(object requester, bool overwrite, CancellationToken cancellationToken);
} }
} }

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

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using GBase.Api;
namespace GBase.Interfaces.FileHandling namespace GBase.Interfaces.FileHandling
{ {
@ -23,7 +24,7 @@ namespace GBase.Interfaces.FileHandling
/// <returns>True if successful, false if not</returns> /// <returns>True if successful, false if not</returns>
List<IGBaseFile> Init(string path, string folderName, CancellationToken cancellationToken); List<IGBaseFile> Init(string path, string folderName, CancellationToken cancellationToken);
IGBaseFile CreateEntryFile<T>(T entry, IGBaseTable table); IGBaseFile CreateEntryFile<T>(T entry, IGBaseTable table) where T : IGBaseObject;
Task<bool> DeleteEntryFile<T>(T entry); Task<bool> DeleteEntryFile<T>(T entry);

@ -7,7 +7,6 @@ using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using GBase.Api;
using GBase.Interfaces.Settings; using GBase.Interfaces.Settings;
namespace GBase.Interfaces namespace GBase.Interfaces
@ -59,6 +58,7 @@ namespace GBase.Interfaces
bool RemoveTable(IGBaseTable table); bool RemoveTable(IGBaseTable table);
Task<bool> AddEntry<T>(T entry, CancellationToken cancellationToken) where T : IGBaseObject, new(); 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 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<TProperty> GetValue<T, TProperty>(T entry, string propertyName, CancellationToken cancellationToken) where T : IGBaseObject, new();

@ -9,9 +9,10 @@ namespace GBase.Interfaces
/// <summary> /// <summary>
/// A column of a <see cref="IGBaseTable"/> /// A column of a <see cref="IGBaseTable"/>
/// </summary> /// </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; } string Name { get; }
Type Type { 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,7 +6,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using GBase.Api;
namespace GBase.Interfaces namespace GBase.Interfaces
{ {
@ -18,20 +17,19 @@ namespace GBase.Interfaces
List<T> Entries { get; } List<T> Entries { get; }
/// <summary> /// <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> /// </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> /// <param name="cancellationToken"></param>
/// <returns>True if successful, false if not</returns> /// <returns>True if successful, false if not</returns>
Task<bool> AddEntry(T entry, CancellationToken cancellationToken); Task<bool> AddEntry(T entry, CancellationToken cancellationToken);
T GetEntryForKey(int key);
//T GetEntry(T entry); //TODO: This doesn't make sense... (passing instance of T to get the same instance back...)
/// <summary> /// <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> /// </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> /// <returns>True if successful, false if not</returns>
Task<bool> RemoveEntry(T entry); Task<bool> RemoveEntry(T entry);
@ -45,7 +43,7 @@ namespace GBase.Interfaces
/// <summary> /// <summary>
/// A <see cref="IGBase"/> table /// A <see cref="IGBase"/> table
/// </summary> /// </summary>
public interface IGBaseTable : IAsyncDisposable //TODO: make generic? public interface IGBaseTable : IAsyncDisposable
{ {
/// <summary> /// <summary>
/// The <see cref="System.Type"/> of the class that this <see cref="IGBaseTable"/> represents /// The <see cref="System.Type"/> of the class that this <see cref="IGBaseTable"/> represents
@ -71,7 +69,7 @@ namespace GBase.Interfaces
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the asynchronous operation</param> /// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the asynchronous operation</param>
/// /// /// ///
/// <returns>True if successful, false if not</returns> /// <returns>True if successful, false if not</returns>
Task<bool> Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken); Task Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Add a given <see cref="IGBaseColumn"/> to this <see cref="IGBaseTable"/> /// Add a given <see cref="IGBaseColumn"/> to this <see cref="IGBaseTable"/>

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

@ -10,6 +10,7 @@ using GBase.DataHandling;
using GBase.DataHandling.Cache; using GBase.DataHandling.Cache;
using GBase.DataHandling.Cache.Factories; using GBase.DataHandling.Cache.Factories;
using GBase.DataHandling.Factories; using GBase.DataHandling.Factories;
using GBase.Interfaces;
using GBase.Interfaces.DataHandling.Xml; using GBase.Interfaces.DataHandling.Xml;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@ -33,7 +34,7 @@ namespace Test.GBase.DataHandling
Mock<IXmlDataReaderFactory> dataReaderFactoryMock = new Mock<IXmlDataReaderFactory>(); Mock<IXmlDataReaderFactory> dataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
dataReaderFactoryMock.Setup(r => r.Create()) dataReaderFactoryMock.Setup(r => r.Create())
.Returns(new XmlDataReader()); .Returns(new XmlDataReader(Mock.Of<IGBase>()));
Mock<IXmlDataHandlerCachePropertyEntryFactory> dataHandlerCachePropertyEntryFactoryMock = new Mock<IXmlDataHandlerCachePropertyEntryFactory>(); Mock<IXmlDataHandlerCachePropertyEntryFactory> dataHandlerCachePropertyEntryFactoryMock = new Mock<IXmlDataHandlerCachePropertyEntryFactory>();
dataHandlerCachePropertyEntryFactoryMock.Setup(p => p.Create(It.IsAny<string>(), It.IsAny<object>())) dataHandlerCachePropertyEntryFactoryMock.Setup(p => p.Create(It.IsAny<string>(), It.IsAny<object>()))

@ -48,9 +48,9 @@ namespace Test.GBase.GBaseIntegrationTest
await model.AddItem(new Item("Item 2", 2), _cancellationTokenSource.Token); await model.AddItem(new Item("Item 2", 2), _cancellationTokenSource.Token);
await model.AddItem(new Item("Item 3", 3), _cancellationTokenSource.Token); await model.AddItem(new Item("Item 3", 3), _cancellationTokenSource.Token);
await model.AddGroup(new Group(1), _cancellationTokenSource.Token); await model.AddGroup(new Group(1) {Items = { model.Items[0], model.Items[1] }}, _cancellationTokenSource.Token);
await model.AddGroup(new Group(2), _cancellationTokenSource.Token); await model.AddGroup(new Group(2) {Items = { model.Items[1], model.Items[2] }}, _cancellationTokenSource.Token);
await model.AddGroup(new Group(3), _cancellationTokenSource.Token); await model.AddGroup(new Group(3) {Items = { model.Items[0], model.Items[2] }}, _cancellationTokenSource.Token);
} }
} }
} }

@ -3,6 +3,7 @@
// Copyright(c) 2020 SimonG. All Rights Reserved. // Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic; using System.Collections.Generic;
using GBase;
using GBase.Attributes; using GBase.Attributes;
namespace Test.GBase.GBaseIntegrationTest namespace Test.GBase.GBaseIntegrationTest
@ -12,24 +13,29 @@ namespace Test.GBase.GBaseIntegrationTest
{ {
public Group() public Group()
{ {
Items = new List<IItem>(); Items = new List<Item>();
} }
public Group(int key) public Group(int number)
{ {
Key = key; Number = number;
Items = new List<IItem>(); Items = new List<Item>();
} }
[GBaseColumn] [GBaseColumn]
public int Key { get; private set; } public int Number { get; private set; }
public List<IItem> Items { get; }
[GBaseColumn]
public List<Item> Items { get; }
public GBaseKey Key { get; set; }
public string FileName => $"Group{Number}";
public override string ToString() => $"{Key}"; public override string ToString() => $"{Number}";
public void InitializeFromString(string @string) => Key = int.Parse(@string); public void Initialize(GBaseKey key, List<object> parameters)
public void Initialize(List<object> parameters)
{ {
Key = (int) parameters[0]; Key = key;
Number = (int) parameters[0];
} }
} }
} }

@ -4,12 +4,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using GBase.Api; using GBase.Api;
using GBase.Interfaces;
namespace Test.GBase.GBaseIntegrationTest namespace Test.GBase.GBaseIntegrationTest
{ {
public interface IGroup : IGBaseObject //: INotifyGBaseEntryChanged public interface IGroup : IGBaseObject //: INotifyGBaseEntryChanged
{ {
int Key { get; } int Number { get; }
List<IItem> Items { get; } List<Item> Items { get; }
} }
} }

@ -2,13 +2,13 @@
// Created: 2020-09-18 // Created: 2020-09-18
// Copyright(c) 2020 SimonG. All Rights Reserved. // Copyright(c) 2020 SimonG. All Rights Reserved.
using GBase.Api; using GBase.Interfaces;
namespace Test.GBase.GBaseIntegrationTest namespace Test.GBase.GBaseIntegrationTest
{ {
public interface IItem : IGBaseObject //: INotifyGBaseEntryChanged public interface IItem : IGBaseObject //: INotifyGBaseEntryChanged
{ {
string Name { get; } string Name { get; }
int Key { get; } int Number { get; }
} }
} }

@ -3,6 +3,7 @@
// Copyright(c) 2020 SimonG. All Rights Reserved. // Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic; using System.Collections.Generic;
using GBase;
using GBase.Attributes; using GBase.Attributes;
namespace Test.GBase.GBaseIntegrationTest namespace Test.GBase.GBaseIntegrationTest
@ -15,32 +16,28 @@ namespace Test.GBase.GBaseIntegrationTest
} }
public Item(string name, int key) public Item(string name, int number)
{ {
Name = name; Name = name;
Key = key; Number = number;
} }
[GBaseColumn] [GBaseColumn]
public string Name { get; private set; } public string Name { get; private set; }
[GBaseColumn] [GBaseColumn]
public int Key { get; private set; } public int Number { get; private set; }
public override string ToString() => $"{Name}"; public GBaseKey Key { get; set; }
public string FileName => Name;
public void InitializeFromString(string @string) public override string ToString() => $"{Number}/{Name}";
{
string[] properties = @string.Split('/');
Key = int.Parse(properties[0]);
Name = properties[1];
}
public void Initialize(List<object> parameters) public void Initialize(GBaseKey key, List<object> parameters)
{ {
Key = key;
Name = (string) parameters[0]; Name = (string) parameters[0];
Key = (int) parameters[1]; Number = (int) parameters[1];
} }
} }
} }

@ -19,23 +19,23 @@ namespace Test.GBase.GBaseIntegrationTest
public Model(IGBaseFactory gBaseFactory) public Model(IGBaseFactory gBaseFactory)
{ {
_gBase = gBaseFactory.Create(new Settings()); _gBase = gBaseFactory.Create(new Settings());
Items = new List<IItem>(); Items = new List<Item>();
Groups = new List<IGroup>(); Groups = new List<Group>();
} }
public List<IItem> Items { get; private set; } public List<Item> Items { get; private set; }
public List<IGroup> Groups { get; private set; } public List<Group> Groups { get; private set; }
public async Task Initialize(CancellationToken cancellationToken) public async Task Initialize(CancellationToken cancellationToken)
{ {
await _gBase.Init("DB", Assembly.GetExecutingAssembly(), cancellationToken); await _gBase.Init("DB", Assembly.GetExecutingAssembly(), cancellationToken);
IGBaseTable<Item> itemsTable = _gBase.GetTable<Item>(); IGBaseTable<Item> itemsTable = _gBase.GetTable<Item>();
Items = itemsTable.Entries.Cast<IItem>().ToList(); Items = itemsTable.Entries.ToList();
//Items = (await _gBase.GetValues<Model, Item>(this, nameof(Items), cancellationToken)).Cast<IItem>().ToList(); //Items = (await _gBase.GetValues<Model, Item>(this, nameof(Items), cancellationToken)).Cast<IItem>().ToList();
IGBaseTable<Group> groupsTable = _gBase.GetTable<Group>(); IGBaseTable<Group> groupsTable = _gBase.GetTable<Group>();
Groups = groupsTable.Entries.Cast<IGroup>().ToList(); Groups = groupsTable.Entries.ToList();
//Groups = (await _gBase.GetValues<Model, Group>(this, nameof(Groups), cancellationToken)).Cast<IGroup>().ToList(); //Groups = (await _gBase.GetValues<Model, Group>(this, nameof(Groups), cancellationToken)).Cast<IGroup>().ToList();
} }

@ -27,8 +27,8 @@ namespace Test.GBase
IGBaseColumn gBaseColumn = null; IGBaseColumn gBaseColumn = null;
Mock<IGBaseColumnFactory> gBaseColumnFactoryMock = new Mock<IGBaseColumnFactory>(); Mock<IGBaseColumnFactory> gBaseColumnFactoryMock = new Mock<IGBaseColumnFactory>();
gBaseColumnFactoryMock.Setup(c => c.Create(It.IsAny<string>(), It.IsAny<Type>())) gBaseColumnFactoryMock.Setup(c => c.Create(It.IsAny<string>(), It.IsAny<Type>(), It.IsAny<bool>()))
.Callback<string, Type>((name, type) => { gBaseColumn = new GBaseColumn(name, type); }) .Callback<string, Type, bool>((name, type, isKey) => { gBaseColumn = new GBaseColumn(name, type, isKey); })
.Returns(gBaseColumn); .Returns(gBaseColumn);
Mock<IDataHandlerPool> dataHandlerPoolMock = new Mock<IDataHandlerPool>(); Mock<IDataHandlerPool> dataHandlerPoolMock = new Mock<IDataHandlerPool>();

@ -5,6 +5,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using GBase.Exceptions; using GBase.Exceptions;
using GBase.Helpers; using GBase.Helpers;
using GBase.Interfaces;
using Moq;
using NUnit.Framework; using NUnit.Framework;
using Test.GBase.TestClasses; using Test.GBase.TestClasses;
@ -85,7 +87,7 @@ namespace Test.GBase.Helpers
string @string = $"{list[0]},{list[1]},{list[2]}"; 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] [Test]
@ -100,7 +102,7 @@ namespace Test.GBase.Helpers
string @string = $"{list[0]},{list[1]},{list[2]}"; 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] [Test]
@ -115,7 +117,7 @@ namespace Test.GBase.Helpers
string @string = $"{list[0]},{list[1]},{list[2]}"; 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] [Test]
@ -130,7 +132,7 @@ namespace Test.GBase.Helpers
string @string = $"{list[0]},{list[1]},{list[2]}"; 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); Assert.AreEqual(typeof(IUserType), exception.InterfaceType);
} }
} }

@ -4,8 +4,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using GBase;
using GBase.Api; using GBase.Api;
using GBase.Attributes; using GBase.Attributes;
using GBase.Interfaces;
namespace Test.GBase.TestClasses namespace Test.GBase.TestClasses
{ {
@ -35,12 +37,10 @@ namespace Test.GBase.TestClasses
} }
} }
public void InitializeFromString(string @string) public GBaseKey Key { get; set; }
{ public string FileName => Name;
throw new NotImplementedException();
}
public void Initialize(List<object> parameters) public void Initialize(GBaseKey key, List<object> parameters)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

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

@ -5,6 +5,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using GBase;
namespace Test.GBase.TestClasses namespace Test.GBase.TestClasses
{ {
@ -22,13 +23,10 @@ namespace Test.GBase.TestClasses
private int Number { get; set; } private int Number { get; set; }
public void InitializeFromString(string @string) public GBaseKey Key { get; set; }
{ public string FileName { get; }
string numberString = @string.Split('_').Last();
Number = Convert.ToInt32(numberString);
}
public void Initialize(List<object> parameters) public void Initialize(GBaseKey key, List<object> parameters)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

Loading…
Cancel
Save