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. 5
      GBase/Attributes/GBaseColumnAttribute.cs
  7. 25
      GBase/DataHandling/Pool/DataHandlerPool.cs
  8. 10
      GBase/DataHandling/Pool/PoolItem.cs
  9. 6
      GBase/DataHandling/XmlDataHandler.cs
  10. 14
      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. 24
      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. 2
      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">
<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,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)]
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>();
}
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
return await WaitForDataHandler(requester, cancellationToken);
@ -47,17 +47,17 @@ namespace GBase.DataHandling.Pool
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);
while (dataHandler == null)
while (dataHandlerItem == null)
{
if (_waitingRequesters.Contains(request) && _waitingRequesters.IndexOf(request) == 0) //request is in list and is first
{
if (_pool.Any(i => !i.InUse))
dataHandler = GetDataHandler();
dataHandlerItem = GetDataHandler();
else
await Task.Delay(1000, cancellationToken);
}
@ -69,26 +69,19 @@ namespace GBase.DataHandling.Pool
_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());
item.Item.Init(overwrite);
_pool.Add(item);
item.InUse = true;
return item.Item;
return item;
}
private IDataHandler GetDataHandler()
{
IPoolItem<IDataHandler> item = _pool.First(i => !i.InUse);
item.InUse = true;
return item.Item;
}
private IPoolItem<IDataHandler> GetDataHandler() => _pool.First(i => !i.InUse);
public async ValueTask DisposeAsync()
{

@ -14,6 +14,14 @@ namespace GBase.DataHandling.Pool
}
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>
/// 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="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>
@ -80,12 +79,11 @@ namespace GBase.DataHandling
public async Task<bool> AddEntry<T>(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken)
{
if (!await _xmlDataWriter.InitFile(entryFile, table.Type.Name, cancellationToken))
return false;
await _xmlDataWriter.InitFile(entryFile, table.Type.Name, cancellationToken);
foreach (var column in table.Columns)
{
//TODO: Set value for each column
//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...)

@ -12,16 +12,25 @@ 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 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>
/// Read the data of a property
/// </summary>
@ -40,6 +49,7 @@ namespace GBase.DataHandling
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
@ -65,7 +75,7 @@ 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);

@ -27,18 +27,16 @@ namespace GBase.DataHandling
/// <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> 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 (file.Length > 3) //> 3 because of BOM
return true; //TODO: Don't return bool?
return;
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);
return true;
}
/// <summary>
@ -74,7 +72,7 @@ namespace GBase.DataHandling
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

@ -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.
using System;
using GBase.Api;
using GBase.Interfaces;
namespace GBase.Exceptions
{
/// <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>
public class InvalidTableTypeException : Exception
{
/// <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>
/// <param name="type">The table type</param>
public InvalidTableTypeException(Type type)
: base($"Table type ({type}) doesn't implement {nameof(INotifyGBaseEntryChanged)}.")
: base($"Table type ({type}) doesn't implement {nameof(IGBaseObject)}.")
{
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.
using System;
using GBase.Exceptions;
using GBase.FileHandling.Factories;
using GBase.Interfaces;
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>
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);
}

@ -17,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(string name, Type type);
IGBaseColumn Create(string name, Type type, bool isKey);
}
}

@ -60,7 +60,7 @@ namespace GBase.FileHandling
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);
@ -68,7 +68,7 @@ namespace GBase.FileHandling
Directory.CreateDirectory(directoryPath);
//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
IGBaseFile file = _files.FirstOrDefault(f => f.FilePath.Equals(filePath));

@ -8,7 +8,6 @@ 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;
@ -103,8 +102,6 @@ namespace GBase
return Tables.OfType<IGBaseTable<T>>().First();
throw new MissingTableException<T>();
// //TODO: This probably doesn't work, because even though t.Type : T, IGBaseTable<t.Type> !: IGBaseTable<T>
// return (IGBaseTable<T>) Convert.ChangeType(Tables.FirstOrDefault(t => typeof(T).IsAssignableFrom(t.Type)), typeof(IGBaseTable<T>)); //TestMe
}
/// <summary>
@ -129,6 +126,15 @@ namespace GBase
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>();

@ -201,7 +201,6 @@
<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="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>
@ -261,9 +260,15 @@
</member>
<member name="T:GBase.DataHandling.XmlDataReader">
<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>
</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)">
<summary>
Read the data of a property
@ -363,12 +368,12 @@
</member>
<member name="T:GBase.Exceptions.InvalidTableTypeException">
<summary>
<see cref="T:System.Exception"/> that the passed table type doesn't implement <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/>"/>
<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.Api.INotifyGBaseEntryChanged"/>"/>
<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>
@ -406,7 +411,7 @@
Factory for the <see cref="T:GBase.Interfaces.IGBaseColumn"/>
</summary>
</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>
Creates an <see cref="T:GBase.Interfaces.IGBaseColumn"/>
</summary>
@ -537,7 +542,7 @@
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
</member>
<member name="M:GBase.GBaseColumn.#ctor(System.String,System.Type)">
<member name="M:GBase.GBaseColumn.#ctor(System.String,System.Type,System.Boolean)">
<summary>
A column of a <see cref="T:GBase.Interfaces.IGBaseTable"/>
</summary>
@ -624,17 +629,17 @@
</member>
<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`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>
<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`1.DisposeAsync">
@ -648,14 +653,16 @@
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>
@ -1027,6 +1034,27 @@
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"/>
@ -1034,17 +1062,17 @@
</member>
<member name="M:GBase.Interfaces.IGBaseTable`1.AddEntry(`0,System.Threading.CancellationToken)">
<summary>
Add an entry that implements <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/> to this <see cref="T:GBase.Interfaces.IGBaseTable"/>
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.Interfaces.IGBaseTable`1.RemoveEntry(`0)">
<summary>
Remove an entry that implements <see cref="T:GBase.Api.INotifyGBaseEntryChanged"/> from this <see cref="T:GBase.Interfaces.IGBaseTable"/>
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>
<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">

@ -16,14 +16,16 @@ namespace GBase
/// <summary>
/// A column of a <see cref="IGBaseTable"/>
/// </summary>
public GBaseColumn(string name, Type type)
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

@ -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.Threading;
using System.Threading.Tasks;
using GBase.Api;
using GBase.Exceptions;
using GBase.Interfaces;
@ -29,6 +28,9 @@ namespace GBase
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);
@ -38,12 +40,6 @@ namespace GBase
protected async Task<IEnumerable<TProperty>> GetValues<TProperty>(T @this, string propertyName, CancellationToken cancellationToken) =>
await _gBaseTable.GetValues<TProperty>(@this, propertyName, cancellationToken);
/// <summary>
/// Initialize this <see cref="GBaseObject{T}"/> from a given <see cref="string"/>
/// </summary>
/// <param name="string">The given <see cref="string"/></param>
public abstract void InitializeFromString(string @string);
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.Threading;
using System.Threading.Tasks;
using GBase.Api;
using GBase.Attributes;
using GBase.Exceptions;
using GBase.Factories;
using GBase.FileHandling.Factories;
using GBase.Helpers;
@ -66,6 +66,18 @@ namespace GBase
/// </summary>
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"/>
@ -75,7 +87,7 @@ namespace GBase
/// <param name="folderName"></param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the asynchronous operation</param>
/// <returns>True if successful, false if not</returns>
public async Task<bool> Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken) //TODO: Remove bool return value?
public async Task Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken)
{
Type = type;
FolderName = folderName;
@ -83,17 +95,19 @@ namespace GBase
//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(property.Name, property.PropertyType);
IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create(property.Name, property.PropertyType, gBaseColumnAttribute.IsKey);
AddColumn(gBaseColumn);
}
List<IGBaseFile> files = _fileHandler.Init(databasePath, FolderName, cancellationToken);
if (files == null)
return true;
return;
foreach (var file in files) //create entries for existing files
{
@ -102,25 +116,33 @@ namespace GBase
T entry = new T();
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),
BindingFlags.Public | BindingFlags.Instance,
typeof(T), column.Type,
file.File, column.Name, cancellationToken));
}
entry.Initialize(parameters);
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);
}
}
return true;
}
/// <summary>
@ -151,26 +173,35 @@ 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 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);
using IGBaseFile file = _fileHandler.CreateEntryFile(entry, this);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
await dataHandler.AddEntry(entry, this, file.File, cancellationToken);
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 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)
{
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
await dataHandler.SetValue<T, TProperty>(file.File, propertyName, value, cancellationToken);
using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
await dataHandlerItem.Use().SetValue<T, TProperty>(file.File, propertyName, value, cancellationToken);
}
public async Task<TProperty> GetValue<TProperty>(T entry, string propertyName, CancellationToken cancellationToken)
{
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
return await dataHandler.GetValue<T, TProperty>(file.File, propertyName, cancellationToken);
using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, 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)
{
using IGBaseFile file = await _fileHandler.RequestEntryFile(entry);
IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
return await dataHandler.GetValues<T, TProperty>(file.File, propertyName, cancellationToken);
using IPoolItem<IDataHandler> dataHandlerItem = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken);
return await dataHandlerItem.Use().GetValues<T, TProperty>(file.File, propertyName, cancellationToken);
}
/// <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.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);

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

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

@ -21,7 +21,7 @@ namespace GBase.Interfaces.DataHandling
/// <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> InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken);
Task InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken);
/// <summary>
/// Write the data of a property

@ -10,6 +10,6 @@ namespace GBase.Interfaces.DataHandling.Pool
{
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
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System;
namespace GBase.Interfaces.DataHandling.Pool
{
public interface IPoolItem<T>
public interface IPoolItem<T> : IDisposable
{
T Item { get; }
bool InUse { get; set; }
bool InUse { get; }
T Use();
}
}

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using GBase.Api;
namespace GBase.Interfaces.FileHandling
{
@ -23,7 +24,7 @@ namespace GBase.Interfaces.FileHandling
/// <returns>True if successful, false if not</returns>
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);

@ -7,7 +7,6 @@ using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using GBase.Api;
using GBase.Interfaces.Settings;
namespace GBase.Interfaces
@ -59,6 +58,7 @@ namespace GBase.Interfaces
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();

@ -9,9 +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,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using GBase.Api;
namespace GBase.Interfaces
{
@ -18,20 +17,19 @@ namespace GBase.Interfaces
List<T> Entries { get; }
/// <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>
Task<bool> AddEntry(T entry, CancellationToken cancellationToken);
//T GetEntry(T entry); //TODO: This doesn't make sense... (passing instance of T to get the same instance back...)
T GetEntryForKey(int 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>
Task<bool> RemoveEntry(T entry);
@ -45,7 +43,7 @@ namespace GBase.Interfaces
/// <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
@ -71,7 +69,7 @@ namespace GBase.Interfaces
/// <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 databasePath, string folderName, CancellationToken cancellationToken);
Task Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken);
/// <summary>
/// Add a given <see cref="IGBaseColumn"/> to this <see cref="IGBaseTable"/>

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

@ -10,6 +10,7 @@ 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;
@ -33,7 +34,7 @@ namespace Test.GBase.DataHandling
Mock<IXmlDataReaderFactory> dataReaderFactoryMock = new Mock<IXmlDataReaderFactory>();
dataReaderFactoryMock.Setup(r => r.Create())
.Returns(new XmlDataReader());
.Returns(new XmlDataReader(Mock.Of<IGBase>()));
Mock<IXmlDataHandlerCachePropertyEntryFactory> dataHandlerCachePropertyEntryFactoryMock = new Mock<IXmlDataHandlerCachePropertyEntryFactory>();
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 3", 3), _cancellationTokenSource.Token);
await model.AddGroup(new Group(1), _cancellationTokenSource.Token);
await model.AddGroup(new Group(2), _cancellationTokenSource.Token);
await model.AddGroup(new Group(3), _cancellationTokenSource.Token);
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);
}
}
}

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

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

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

@ -3,6 +3,7 @@
// Copyright(c) 2020 SimonG. All Rights Reserved.
using System.Collections.Generic;
using GBase;
using GBase.Attributes;
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;
Key = key;
Number = number;
}
[GBaseColumn]
public string Name { get; private set; }
[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)
{
string[] properties = @string.Split('/');
public override string ToString() => $"{Number}/{Name}";
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];
Key = (int) parameters[1];
Number = (int) parameters[1];
}
}
}

@ -19,23 +19,23 @@ namespace Test.GBase.GBaseIntegrationTest
public Model(IGBaseFactory gBaseFactory)
{
_gBase = gBaseFactory.Create(new Settings());
Items = new List<IItem>();
Groups = new List<IGroup>();
Items = new List<Item>();
Groups = new List<Group>();
}
public List<IItem> Items { get; private set; }
public List<IGroup> Groups { get; private set; }
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.Cast<IItem>().ToList();
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.Cast<IGroup>().ToList();
Groups = groupsTable.Entries.ToList();
//Groups = (await _gBase.GetValues<Model, Group>(this, nameof(Groups), cancellationToken)).Cast<IGroup>().ToList();
}

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

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

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

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

Loading…
Cancel
Save