From f29039c7abdd87fc0da629f0da241d6924bc4897 Mon Sep 17 00:00:00 2001 From: Simon G Date: Thu, 17 Sep 2020 10:21:28 +0200 Subject: [PATCH 01/46] - idea changes --- .idea/.idea.GBase/.idea/encodings.xml | 4 ---- .idea/.idea.GBase/.idea/projectSettingsUpdater.xml | 6 ------ 2 files changed, 10 deletions(-) delete mode 100644 .idea/.idea.GBase/.idea/encodings.xml delete mode 100644 .idea/.idea.GBase/.idea/projectSettingsUpdater.xml diff --git a/.idea/.idea.GBase/.idea/encodings.xml b/.idea/.idea.GBase/.idea/encodings.xml deleted file mode 100644 index df87cf9..0000000 --- a/.idea/.idea.GBase/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/.idea.GBase/.idea/projectSettingsUpdater.xml b/.idea/.idea.GBase/.idea/projectSettingsUpdater.xml deleted file mode 100644 index 4bb9f4d..0000000 --- a/.idea/.idea.GBase/.idea/projectSettingsUpdater.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file From aed5d84383f0a26091b15fa1c9513b77c52c9e58 Mon Sep 17 00:00:00 2001 From: Simon G Date: Thu, 17 Sep 2020 10:26:55 +0200 Subject: [PATCH 02/46] - add fix me --- GBase/FileHandling/FileHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index 468fe12..89376b6 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -42,7 +42,7 @@ namespace GBase.FileHandling /// True if successful, false if not public async Task Init(string path, CancellationToken cancellationToken) { - DataHandler = _dataHandlerFactory.Create(); + DataHandler = _dataHandlerFactory.Create(); //FixMe: Factory is missing parameters bool success = await DataHandler.Init(false, cancellationToken); return success; From dc5d57e48bb5b0ddedd33ace93008453dc09114f Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 10:12:25 +0200 Subject: [PATCH 03/46] - idea folder --- .idea/.idea.GBase/.idea/projectSettingsUpdater.xml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .idea/.idea.GBase/.idea/projectSettingsUpdater.xml diff --git a/.idea/.idea.GBase/.idea/projectSettingsUpdater.xml b/.idea/.idea.GBase/.idea/projectSettingsUpdater.xml new file mode 100644 index 0000000..4bb9f4d --- /dev/null +++ b/.idea/.idea.GBase/.idea/projectSettingsUpdater.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file From 7c5aa0349889c122cc0cdd2f17fbcd124bc8cb8b Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 10:18:45 +0200 Subject: [PATCH 04/46] - add todos --- GBase/GBaseTable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GBase/GBaseTable.cs b/GBase/GBaseTable.cs index 887f8d8..92fa996 100644 --- a/GBase/GBaseTable.cs +++ b/GBase/GBaseTable.cs @@ -96,7 +96,7 @@ namespace GBase /// /// The given /// True if successful, false if not - public bool AddColumn(IGBaseColumn column) + public bool AddColumn(IGBaseColumn column) //TODO: if a column is added, it has to be added to every entry file as well { if (Columns.Contains(column)) return false; @@ -110,7 +110,7 @@ namespace GBase /// /// The given /// True if successful, false if not - public bool RemoveColumn(IGBaseColumn column) + public bool RemoveColumn(IGBaseColumn column) //TODO: if a column is removed, it has to be removed from every entry file as well { if (!Columns.Contains(column)) return false; From 893fdf33d30bcd8cd263fd218aba26c0ff0cb02a Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 15:06:25 +0200 Subject: [PATCH 05/46] - create structure of gBase, to understand it --- GBaseStructure.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 GBaseStructure.md diff --git a/GBaseStructure.md b/GBaseStructure.md new file mode 100644 index 0000000..14e8c1b --- /dev/null +++ b/GBaseStructure.md @@ -0,0 +1,41 @@ +# GBase Structure + +```md +- GBase + | + +-GBaseTable + | + | + +-GBaseTable + | + +-GBaseColumn--GBaseColumn--GBaseColumn + +-GBaseEntry + +-GBaseEntry +``` + +## Terminology + +| GBase Terminology | C# equivalent | +|-------------------|---------------| +| GBaseTable | Type | +| GBaseColumn | Property | +| GBaseEntry | Instance | + +## File Structure + +```c# +public class Model +{ + private readonly IGBase _gBase; + + public +} +``` + +## Process + +### StartUp + +### GetValue + +### SetValue From 7c2f52a265390bb4f3acf748766842847a21165b Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 15:08:08 +0200 Subject: [PATCH 06/46] - try adding generic GBaseTable --- GBase/GBase.cs | 19 ++++++++++++++ GBase/GBaseTable.cs | 12 ++++----- GBase/Interfaces/IGBase.cs | 5 ++++ GBase/Interfaces/IGBaseTable.cs | 44 +++++++++++++++++++-------------- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/GBase/GBase.cs b/GBase/GBase.cs index 0bf717e..e87c247 100644 --- a/GBase/GBase.cs +++ b/GBase/GBase.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using GBase.Api; using GBase.Attributes; using GBase.Factories; using GBase.Interfaces; @@ -100,6 +101,15 @@ namespace GBase return true; } + public IGBaseTable GetTable() where T : INotifyGBaseEntryChanged + { + if (Tables.OfType>().Any()) + return Tables.OfType>().First(); + + //TODO: This probably doesn't work, because even though t.Type : T, IGBaseTable !: IGBaseTable + return (IGBaseTable) Tables.FirstOrDefault(t => typeof(T).IsAssignableFrom(t.Type)); //TestMe + } + /// /// Removes a given from this /// @@ -113,6 +123,15 @@ namespace GBase return Tables.Remove(table); } + public bool AddEntry(T entry) where T : INotifyGBaseEntryChanged + { + IGBaseTable table = GetTable(); + if (table == null) + throw new Exception(); //TODO: Create exception + + return table.AddEntry(entry); + } + /// /// Dispose used resources asynchronously /// diff --git a/GBase/GBaseTable.cs b/GBase/GBaseTable.cs index 92fa996..5684bb1 100644 --- a/GBase/GBaseTable.cs +++ b/GBase/GBaseTable.cs @@ -21,7 +21,7 @@ namespace GBase /// /// A table /// - public class GBaseTable : IGBaseTable + public class GBaseTable : IGBaseTable where T : INotifyGBaseEntryChanged { private readonly IFileHandler _fileHandler; private readonly IGBaseColumnFactory _gBaseColumnFactory; @@ -35,7 +35,7 @@ namespace GBase _gBaseColumnFactory = gBaseColumnFactory; Columns = new List(); - Entries = new List(); + Entries = new List(); } @@ -57,7 +57,7 @@ namespace GBase /// /// The entries of this /// - public List Entries { get; } + public List Entries { get; } /// @@ -123,7 +123,7 @@ namespace GBase /// /// The entry implementing /// True if successful, false if not - public bool AddEntry(INotifyGBaseEntryChanged entry) //TODO: Write to file + public bool AddEntry(T entry) //TODO: Write to file { Entries.Add(entry); entry.GBaseEntryChanged += OnGBaseEntryChanged; @@ -136,7 +136,7 @@ namespace GBase /// /// The entry implementing /// True if successful, false if not - public bool RemoveEntry(INotifyGBaseEntryChanged entry) //TODO: remove from file + public bool RemoveEntry(T entry) //TODO: remove from file { if (!Entries.Contains(entry)) return false; @@ -188,7 +188,7 @@ namespace GBase Columns.Clear(); - foreach (var entry in Entries.OfType().ToList()) + foreach (var entry in Entries.ToList()) { RemoveEntry(entry); } diff --git a/GBase/Interfaces/IGBase.cs b/GBase/Interfaces/IGBase.cs index 614211a..955e242 100644 --- a/GBase/Interfaces/IGBase.cs +++ b/GBase/Interfaces/IGBase.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using GBase.Api; using GBase.Interfaces.Settings; namespace GBase.Interfaces @@ -48,11 +49,15 @@ namespace GBase.Interfaces /// True if successful, false if not bool AddTable(IGBaseTable table); + IGBaseTable GetTable() where T : INotifyGBaseEntryChanged; + /// /// Removes a given from this /// /// The given /// True if successful, false if not bool RemoveTable(IGBaseTable table); + + bool AddEntry(T entry) where T : INotifyGBaseEntryChanged; } } \ No newline at end of file diff --git a/GBase/Interfaces/IGBaseTable.cs b/GBase/Interfaces/IGBaseTable.cs index 613c0af..52673bc 100644 --- a/GBase/Interfaces/IGBaseTable.cs +++ b/GBase/Interfaces/IGBaseTable.cs @@ -10,6 +10,31 @@ using GBase.Api; namespace GBase.Interfaces { + public interface IGBaseTable : IGBaseTable where T : INotifyGBaseEntryChanged + { + /// + /// The entries of this + /// + List Entries { get; } + + /// + /// Add an entry that implements to this + /// + /// The entry implementing + /// True if successful, false if not + bool AddEntry(T entry); + + + //T GetEntry(T entry); //TODO: This doesn't make sense... (passing instance of T to get the same instance back...) + + /// + /// Remove an entry that implements from this + /// + /// The entry implementing + /// True if successful, false if not + bool RemoveEntry(T entry); + } + /// /// A table /// @@ -30,11 +55,6 @@ namespace GBase.Interfaces /// List Columns { get; } - /// - /// The entries of this - /// - List Entries { get; } - /// /// Initialize this /// @@ -58,19 +78,5 @@ namespace GBase.Interfaces /// The given /// True if successful, false if not bool RemoveColumn(IGBaseColumn column); - - /// - /// Add an entry that implements to this - /// - /// The entry implementing - /// True if successful, false if not - bool AddEntry(INotifyGBaseEntryChanged entry); - - /// - /// Remove an entry that implements from this - /// - /// The entry implementing - /// True if successful, false if not - bool RemoveEntry(INotifyGBaseEntryChanged entry); } } \ No newline at end of file From b69830fb41cd0d0fa5579c5118a3c6cc706a78a1 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 15:08:28 +0200 Subject: [PATCH 07/46] - first try add base GBaseObject implementation --- GBase/GBaseObject.cs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 GBase/GBaseObject.cs diff --git a/GBase/GBaseObject.cs b/GBase/GBaseObject.cs new file mode 100644 index 0000000..5ff272e --- /dev/null +++ b/GBase/GBaseObject.cs @@ -0,0 +1,44 @@ +// Author: Gockner, Simon +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Linq; +using GBase.Api; +using GBase.Exceptions; +using GBase.Interfaces; + +namespace GBase +{ + /// + /// GBase object that supplies inheriting classes with methods to get data from a + /// + public abstract class GBaseObject : IGBaseObject where T : INotifyGBaseEntryChanged + { + private readonly IGBaseTable _gBaseTable; + + /// + /// GBase object that allows conversion from + /// + /// No table for is existing + protected GBaseObject(IGBase gBase) + { + _gBaseTable = gBase.GetTable(); + if (_gBaseTable == null) + throw new MissingTableException(typeof(T)); + } + + + protected TProperty Get() + { + throw new NotImplementedException(); + //_gBaseTable.GetEntry() + } + + /// + /// Initialize this from a given + /// + /// The given + public abstract void InitializeFromString(string @string); + } +} \ No newline at end of file From 8299f48eb32eb5e64b866c966b213d311ce539c0 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 15:08:42 +0200 Subject: [PATCH 08/46] - adapt test to generic table --- Test.GBase/GBaseTableIntegrationTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test.GBase/GBaseTableIntegrationTest.cs b/Test.GBase/GBaseTableIntegrationTest.cs index 11da737..4e5a753 100644 --- a/Test.GBase/GBaseTableIntegrationTest.cs +++ b/Test.GBase/GBaseTableIntegrationTest.cs @@ -26,7 +26,7 @@ namespace Test.GBase Mock gBaseColumnFactoryMock = new Mock(); gBaseColumnFactoryMock.Setup(c => c.Create()).Returns(new GBaseColumn()); - IGBaseTable table = new GBaseTable(fileHandlerFactoryMock.Object, gBaseColumnFactoryMock.Object); + IGBaseTable table = new GBaseTable(fileHandlerFactoryMock.Object, gBaseColumnFactoryMock.Object); table.Init(typeof(Foo), nameof(Foo), "", CancellationToken.None); Foo foo = new Foo("Test"); From 488fad44a1e134163fabb8c821063cc9f071244e Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 15:08:53 +0200 Subject: [PATCH 09/46] - add MissingTableException --- GBase/Exceptions/MissingTableException.cs | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 GBase/Exceptions/MissingTableException.cs diff --git a/GBase/Exceptions/MissingTableException.cs b/GBase/Exceptions/MissingTableException.cs new file mode 100644 index 0000000..1d6015b --- /dev/null +++ b/GBase/Exceptions/MissingTableException.cs @@ -0,0 +1,28 @@ +// Author: Gockner, Simon +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; + +namespace GBase.Exceptions +{ + /// + /// that the table for the given is missing + /// + public class MissingTableException : Exception + { + /// + /// that the table for the given is missing + /// + public MissingTableException(Type type) + : base($"There is no table for type {type}.") + { + Type = type; + } + + /// + /// The that has no table + /// + public Type Type { get; } + } +} \ No newline at end of file From 2e2c0f74c2aded10796f40e9726b8040eaf8fc8a Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 15:09:24 +0200 Subject: [PATCH 10/46] - start adding complete GBase integration --- Test.GBase/GBaseIntegrationTest/Group.cs | 21 +++++++++ Test.GBase/GBaseIntegrationTest/IGroup.cs | 14 ++++++ Test.GBase/GBaseIntegrationTest/IItem.cs | 13 ++++++ Test.GBase/GBaseIntegrationTest/Item.cs | 15 ++++++ Test.GBase/GBaseIntegrationTest/Model.cs | 51 +++++++++++++++++++++ Test.GBase/GBaseIntegrationTest/Settings.cs | 13 ++++++ 6 files changed, 127 insertions(+) create mode 100644 Test.GBase/GBaseIntegrationTest/Group.cs create mode 100644 Test.GBase/GBaseIntegrationTest/IGroup.cs create mode 100644 Test.GBase/GBaseIntegrationTest/IItem.cs create mode 100644 Test.GBase/GBaseIntegrationTest/Item.cs create mode 100644 Test.GBase/GBaseIntegrationTest/Model.cs create mode 100644 Test.GBase/GBaseIntegrationTest/Settings.cs diff --git a/Test.GBase/GBaseIntegrationTest/Group.cs b/Test.GBase/GBaseIntegrationTest/Group.cs new file mode 100644 index 0000000..d1dc03c --- /dev/null +++ b/Test.GBase/GBaseIntegrationTest/Group.cs @@ -0,0 +1,21 @@ +// Author: Gockner, Simon +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.Collections.Generic; +using GBase.Api; +using GBase.Attributes; + +namespace Test.GBase.GBaseIntegrationTest +{ + [GBaseTable] + public class Group : NotifyGBaseEntryChanged, IGroup + { + public Group() + { + Items = new List(); + } + + public List Items { get; } + } +} \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/IGroup.cs b/Test.GBase/GBaseIntegrationTest/IGroup.cs new file mode 100644 index 0000000..966eac8 --- /dev/null +++ b/Test.GBase/GBaseIntegrationTest/IGroup.cs @@ -0,0 +1,14 @@ +// Author: Gockner, Simon +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.Collections.Generic; +using GBase.Api; + +namespace Test.GBase.GBaseIntegrationTest +{ + public interface IGroup : INotifyGBaseEntryChanged + { + List Items { get; } + } +} \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/IItem.cs b/Test.GBase/GBaseIntegrationTest/IItem.cs new file mode 100644 index 0000000..5d4fe77 --- /dev/null +++ b/Test.GBase/GBaseIntegrationTest/IItem.cs @@ -0,0 +1,13 @@ +// Author: Gockner, Simon +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Api; + +namespace Test.GBase.GBaseIntegrationTest +{ + public interface IItem : INotifyGBaseEntryChanged + { + + } +} \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/Item.cs b/Test.GBase/GBaseIntegrationTest/Item.cs new file mode 100644 index 0000000..e1f32b0 --- /dev/null +++ b/Test.GBase/GBaseIntegrationTest/Item.cs @@ -0,0 +1,15 @@ +// Author: Gockner, Simon +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Api; +using GBase.Attributes; + +namespace Test.GBase.GBaseIntegrationTest +{ + [GBaseTable] + public class Item : NotifyGBaseEntryChanged, IItem + { + + } +} \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/Model.cs b/Test.GBase/GBaseIntegrationTest/Model.cs new file mode 100644 index 0000000..8253bc1 --- /dev/null +++ b/Test.GBase/GBaseIntegrationTest/Model.cs @@ -0,0 +1,51 @@ +// Author: Gockner, Simon +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using GBase.Factories; +using GBase.Interfaces; + +namespace Test.GBase.GBaseIntegrationTest +{ + public class Model + { + private readonly IGBase _gBase; + + public Model(IGBaseFactory gBaseFactory) + { + _gBase = gBaseFactory.Create(new Settings()); + Items = new List(); + Groups = new List(); + } + + public List Items { get; private set; } + public List Groups { get; private set; } + + public async Task Initialize(CancellationToken cancellationToken) + { + await _gBase.Init("DB", Assembly.GetExecutingAssembly(), cancellationToken); + + IGBaseTable itemsTable = _gBase.GetTable(); + Items = itemsTable.Entries; + + IGBaseTable groupsTable = _gBase.GetTable(); + Groups = groupsTable.Entries; + } + + public void AddItem(IItem item) + { + Items.Add(item); + _gBase.AddEntry(item); + } + + public void AddGroup(IGroup group) + { + Groups.Add(group); + _gBase.AddEntry(@group); + } + } +} \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/Settings.cs b/Test.GBase/GBaseIntegrationTest/Settings.cs new file mode 100644 index 0000000..8335033 --- /dev/null +++ b/Test.GBase/GBaseIntegrationTest/Settings.cs @@ -0,0 +1,13 @@ +// Author: Gockner, Simon +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.Settings; + +namespace Test.GBase.GBaseIntegrationTest +{ + public class Settings : IGBaseSettings + { + public string DatabasePath => ""; + } +} \ No newline at end of file From 92cca711668991cb16123ec2b501f5abb182328e Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 15:58:39 +0200 Subject: [PATCH 11/46] - add addEntry and removeEntry methods --- GBase/FileHandling/FileHandler.cs | 13 +++++++++++++ GBase/Interfaces/FileHandling/IFileHandler.cs | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index 89376b6..cbc1952 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using GBase.DataHandling.Factories; +using GBase.Interfaces; using GBase.Interfaces.DataHandling; using GBase.Interfaces.DataHandling.Xml; using GBase.Interfaces.FileHandling; @@ -48,6 +49,18 @@ namespace GBase.FileHandling return success; } + public Task AddEntry(T entry, IGBaseTable table) + { + //create new entry file + throw new NotImplementedException(); + } + + public Task RemoveEntry(T entry) + { + //remove entry file + throw new NotImplementedException(); + } + /// /// Set the value for the given property /// diff --git a/GBase/Interfaces/FileHandling/IFileHandler.cs b/GBase/Interfaces/FileHandling/IFileHandler.cs index 9e33882..ae3eb99 100644 --- a/GBase/Interfaces/FileHandling/IFileHandler.cs +++ b/GBase/Interfaces/FileHandling/IFileHandler.cs @@ -22,6 +22,10 @@ namespace GBase.Interfaces.FileHandling /// True if successful, false if not Task Init(string path, CancellationToken cancellationToken); + Task AddEntry(T entry, IGBaseTable table); + + Task RemoveEntry(T entry); + /// /// Set the value for the given property /// From 781c6b3c03267b45a82a26e3ec81ad9ac8516784 Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 15:58:59 +0200 Subject: [PATCH 12/46] - make methods async --- GBase/GBase.cs | 4 ++-- GBase/GBaseTable.cs | 10 +++++++--- GBase/Interfaces/IGBase.cs | 2 +- GBase/Interfaces/IGBaseTable.cs | 6 +++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/GBase/GBase.cs b/GBase/GBase.cs index e87c247..6008166 100644 --- a/GBase/GBase.cs +++ b/GBase/GBase.cs @@ -123,13 +123,13 @@ namespace GBase return Tables.Remove(table); } - public bool AddEntry(T entry) where T : INotifyGBaseEntryChanged + public async Task AddEntry(T entry) where T : INotifyGBaseEntryChanged { IGBaseTable table = GetTable(); if (table == null) throw new Exception(); //TODO: Create exception - return table.AddEntry(entry); + return await table.AddEntry(entry); } /// diff --git a/GBase/GBaseTable.cs b/GBase/GBaseTable.cs index 5684bb1..5076bac 100644 --- a/GBase/GBaseTable.cs +++ b/GBase/GBaseTable.cs @@ -123,11 +123,13 @@ namespace GBase /// /// The entry implementing /// True if successful, false if not - public bool AddEntry(T entry) //TODO: Write to file + public async Task AddEntry(T entry) //TODO: Write to file { Entries.Add(entry); entry.GBaseEntryChanged += OnGBaseEntryChanged; + await _fileHandler.AddEntry(entry, this); + return true; } @@ -136,13 +138,15 @@ namespace GBase /// /// The entry implementing /// True if successful, false if not - public bool RemoveEntry(T entry) //TODO: remove from file + public async Task RemoveEntry(T entry) //TODO: remove from file { if (!Entries.Contains(entry)) return false; entry.GBaseEntryChanged -= OnGBaseEntryChanged; + await _fileHandler.RemoveEntry(entry); + return Entries.Remove(entry); } @@ -190,7 +194,7 @@ namespace GBase foreach (var entry in Entries.ToList()) { - RemoveEntry(entry); + await RemoveEntry(entry); } Entries.Clear(); diff --git a/GBase/Interfaces/IGBase.cs b/GBase/Interfaces/IGBase.cs index 955e242..380d7cc 100644 --- a/GBase/Interfaces/IGBase.cs +++ b/GBase/Interfaces/IGBase.cs @@ -58,6 +58,6 @@ namespace GBase.Interfaces /// True if successful, false if not bool RemoveTable(IGBaseTable table); - bool AddEntry(T entry) where T : INotifyGBaseEntryChanged; + Task AddEntry(T entry) where T : INotifyGBaseEntryChanged; } } \ No newline at end of file diff --git a/GBase/Interfaces/IGBaseTable.cs b/GBase/Interfaces/IGBaseTable.cs index 52673bc..c240e37 100644 --- a/GBase/Interfaces/IGBaseTable.cs +++ b/GBase/Interfaces/IGBaseTable.cs @@ -16,13 +16,13 @@ namespace GBase.Interfaces /// The entries of this /// List Entries { get; } - + /// /// Add an entry that implements to this /// /// The entry implementing /// True if successful, false if not - bool AddEntry(T entry); + Task AddEntry(T entry); //T GetEntry(T entry); //TODO: This doesn't make sense... (passing instance of T to get the same instance back...) @@ -32,7 +32,7 @@ namespace GBase.Interfaces /// /// The entry implementing /// True if successful, false if not - bool RemoveEntry(T entry); + Task RemoveEntry(T entry); } /// From a854354e8551479a62b5a61ecf0c25ae1256146d Mon Sep 17 00:00:00 2001 From: Simon G Date: Fri, 18 Sep 2020 23:22:10 +0200 Subject: [PATCH 13/46] #25: implement workaround for missing open generic registration possibility --- GBase/Exceptions/InvalidTableTypeException.cs | 27 +++++++++++ GBase/Factories/GBaseTableFactory.cs | 46 +++++++++++++++++++ GBase/Factories/IGBaseTableFactory.cs | 3 +- GBase/GBase.cs | 2 +- GBase/Installers/GBaseInstaller.cs | 3 +- 5 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 GBase/Exceptions/InvalidTableTypeException.cs create mode 100644 GBase/Factories/GBaseTableFactory.cs diff --git a/GBase/Exceptions/InvalidTableTypeException.cs b/GBase/Exceptions/InvalidTableTypeException.cs new file mode 100644 index 0000000..9be6013 --- /dev/null +++ b/GBase/Exceptions/InvalidTableTypeException.cs @@ -0,0 +1,27 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using GBase.Api; + +namespace GBase.Exceptions +{ + /// + /// that the passed table type doesn't implement "/> + /// + public class InvalidTableTypeException : Exception + { + /// + /// that the passed table type doesn't implement "/> + /// + /// The table type + public InvalidTableTypeException(Type type) + : base($"Table type ({type}) doesn't implement {nameof(INotifyGBaseEntryChanged)}.") + { + Type = type; + } + + public Type Type { get; } + } +} \ No newline at end of file diff --git a/GBase/Factories/GBaseTableFactory.cs b/GBase/Factories/GBaseTableFactory.cs new file mode 100644 index 0000000..70d3062 --- /dev/null +++ b/GBase/Factories/GBaseTableFactory.cs @@ -0,0 +1,46 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using GBase.Api; +using GBase.Exceptions; +using GBase.FileHandling.Factories; +using GBase.Interfaces; +using GBase.Interfaces.FileHandling; + +namespace GBase.Factories +{ + /// + /// Factory for the + /// + public class GBaseTableFactory : IGBaseTableFactory + { + private readonly IFileHandlerFactory _fileHandlerFactory; + private readonly IGBaseColumnFactory _gBaseColumnFactory; + + /// + /// Factory for the + /// + /// Factory for the + /// Factory for the + public GBaseTableFactory(IFileHandlerFactory fileHandlerFactory, IGBaseColumnFactory gBaseColumnFactory) + { + _fileHandlerFactory = fileHandlerFactory; + _gBaseColumnFactory = gBaseColumnFactory; + } + + /// + /// Creates an + /// + /// A newly created instance of the implementation for + public IGBaseTable Create(Type type) + { + if (!typeof(INotifyGBaseEntryChanged).IsAssignableFrom(type)) + throw new InvalidTableTypeException(type); + + Type gBaseTableType = typeof(GBaseTable<>).MakeGenericType(type); + return (IGBaseTable) Activator.CreateInstance(gBaseTableType, _fileHandlerFactory, _gBaseColumnFactory); + } + } +} \ No newline at end of file diff --git a/GBase/Factories/IGBaseTableFactory.cs b/GBase/Factories/IGBaseTableFactory.cs index 43792c0..11c8554 100644 --- a/GBase/Factories/IGBaseTableFactory.cs +++ b/GBase/Factories/IGBaseTableFactory.cs @@ -3,6 +3,7 @@ // Copyright(c) 2020 SimonG. All Rights Reserved. +using System; using GBase.Interfaces; namespace GBase.Factories @@ -16,6 +17,6 @@ namespace GBase.Factories /// Creates an /// /// A newly created instance of the implementation for - IGBaseTable Create(); + IGBaseTable Create(Type type); } } \ No newline at end of file diff --git a/GBase/GBase.cs b/GBase/GBase.cs index 6008166..4a789a3 100644 --- a/GBase/GBase.cs +++ b/GBase/GBase.cs @@ -75,7 +75,7 @@ namespace GBase if (gBaseTableAttribute == null) continue; - IGBaseTable gBaseTable = _gBaseTableFactory.Create(); + IGBaseTable gBaseTable = _gBaseTableFactory.Create(type); await gBaseTable.Init(type, type.Name, Settings.DatabasePath, cancellationToken); AddTable(gBaseTable); diff --git a/GBase/Installers/GBaseInstaller.cs b/GBase/Installers/GBaseInstaller.cs index 9ace16d..902e7cd 100644 --- a/GBase/Installers/GBaseInstaller.cs +++ b/GBase/Installers/GBaseInstaller.cs @@ -19,12 +19,11 @@ namespace GBase.Installers public void Install(IIocContainer container) { container.Register(); - container.Register(); container.Register(); //factories container.RegisterFactory(); - container.RegisterFactory(); + container.Register(); //TODO: Once LightweightIocContainer can handle open generic registrations this can be changed back again container.RegisterFactory(); } } From 06f6a4381ee573629a02f20dd5f6bc48e72cecec Mon Sep 17 00:00:00 2001 From: Simon G Date: Sat, 19 Sep 2020 21:21:30 +0200 Subject: [PATCH 14/46] #25: add IDataHandlerFactory --- GBase/DataHandling/Factories/IDataHandlerFactory.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 GBase/DataHandling/Factories/IDataHandlerFactory.cs diff --git a/GBase/DataHandling/Factories/IDataHandlerFactory.cs b/GBase/DataHandling/Factories/IDataHandlerFactory.cs new file mode 100644 index 0000000..d2b8515 --- /dev/null +++ b/GBase/DataHandling/Factories/IDataHandlerFactory.cs @@ -0,0 +1,13 @@ +// Author: Simon Gockner +// Created: 2020-09-19 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.DataHandling; + +namespace GBase.DataHandling.Factories +{ + public interface IDataHandlerFactory + { + IDataHandler Create(); //TODO: Add correct parameters + } +} \ No newline at end of file From a5b6e316900ce768f910b2bedca94448c765b007 Mon Sep 17 00:00:00 2001 From: Simon G Date: Sat, 19 Sep 2020 21:21:48 +0200 Subject: [PATCH 15/46] #25: add todo --- GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs b/GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs index 7b416c9..7d4bac7 100644 --- a/GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs +++ b/GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs @@ -15,6 +15,6 @@ namespace GBase.DataHandling.Factories /// Creates an /// /// A newly created instance of the implementation for - IXmlDataHandler Create(); + IXmlDataHandler Create(); //TODO: Add correct parameters } } \ No newline at end of file From d873ce20c944509ebdbae9edd01ce8ecdf4d6f2a Mon Sep 17 00:00:00 2001 From: Simon G Date: Sat, 19 Sep 2020 21:22:29 +0200 Subject: [PATCH 16/46] #25: add DataHandlerPool --- .../Factories/Pool/IPoolItemFactory.cs | 13 +++ .../Factories/Pool/IPoolRequestFactory.cs | 13 +++ .../Factories/Pool/PoolItemFactory.cs | 14 +++ GBase/DataHandling/Pool/DataHandlerPool.cs | 91 +++++++++++++++++++ GBase/DataHandling/Pool/PoolItem.cs | 19 ++++ GBase/DataHandling/Pool/PoolRequest.cs | 18 ++++ GBase/Installers/DataHandlingInstaller.cs | 17 +++- .../DataHandling/Pool/IDataHandlerPool.cs | 13 +++ .../Interfaces/DataHandling/Pool/IPoolItem.cs | 12 +++ .../DataHandling/Pool/IPoolRequest.cs | 14 +++ 10 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 GBase/DataHandling/Factories/Pool/IPoolItemFactory.cs create mode 100644 GBase/DataHandling/Factories/Pool/IPoolRequestFactory.cs create mode 100644 GBase/DataHandling/Factories/Pool/PoolItemFactory.cs create mode 100644 GBase/DataHandling/Pool/DataHandlerPool.cs create mode 100644 GBase/DataHandling/Pool/PoolItem.cs create mode 100644 GBase/DataHandling/Pool/PoolRequest.cs create mode 100644 GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs create mode 100644 GBase/Interfaces/DataHandling/Pool/IPoolItem.cs create mode 100644 GBase/Interfaces/DataHandling/Pool/IPoolRequest.cs diff --git a/GBase/DataHandling/Factories/Pool/IPoolItemFactory.cs b/GBase/DataHandling/Factories/Pool/IPoolItemFactory.cs new file mode 100644 index 0000000..5fb24c6 --- /dev/null +++ b/GBase/DataHandling/Factories/Pool/IPoolItemFactory.cs @@ -0,0 +1,13 @@ +// Author: Simon Gockner +// Created: 2020-09-19 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.DataHandling.Pool; + +namespace GBase.DataHandling.Factories.Pool +{ + public interface IPoolItemFactory + { + IPoolItem Create(T item); + } +} \ No newline at end of file diff --git a/GBase/DataHandling/Factories/Pool/IPoolRequestFactory.cs b/GBase/DataHandling/Factories/Pool/IPoolRequestFactory.cs new file mode 100644 index 0000000..3f1e51e --- /dev/null +++ b/GBase/DataHandling/Factories/Pool/IPoolRequestFactory.cs @@ -0,0 +1,13 @@ +// Author: Simon Gockner +// Created: 2020-09-19 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.DataHandling.Pool; + +namespace GBase.DataHandling.Factories.Pool +{ + public interface IPoolRequestFactory + { + IPoolRequest Create(object requester); + } +} \ No newline at end of file diff --git a/GBase/DataHandling/Factories/Pool/PoolItemFactory.cs b/GBase/DataHandling/Factories/Pool/PoolItemFactory.cs new file mode 100644 index 0000000..e6bd04e --- /dev/null +++ b/GBase/DataHandling/Factories/Pool/PoolItemFactory.cs @@ -0,0 +1,14 @@ +// Author: Simon Gockner +// Created: 2020-09-19 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.DataHandling.Pool; +using GBase.Interfaces.DataHandling.Pool; + +namespace GBase.DataHandling.Factories.Pool +{ + public class PoolItemFactory : IPoolItemFactory + { + public IPoolItem Create(T item) => new PoolItem(item); + } +} \ No newline at end of file diff --git a/GBase/DataHandling/Pool/DataHandlerPool.cs b/GBase/DataHandling/Pool/DataHandlerPool.cs new file mode 100644 index 0000000..23add72 --- /dev/null +++ b/GBase/DataHandling/Pool/DataHandlerPool.cs @@ -0,0 +1,91 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using GBase.DataHandling.Factories; +using GBase.DataHandling.Factories.Pool; +using GBase.Interfaces.DataHandling; +using GBase.Interfaces.DataHandling.Pool; + +namespace GBase.DataHandling.Pool +{ + public class DataHandlerPool : IDataHandlerPool + { + private readonly int _availableDataHandlers; + private readonly IPoolItemFactory _poolItemFactory; + private readonly IPoolRequestFactory _poolRequestFactory; + private readonly IDataHandlerFactory _dataHandlerFactory; + + private readonly List> _pool; + private readonly List _waitingRequesters; + + public DataHandlerPool(int availableDataHandlers, + IPoolItemFactory poolItemFactory, + IPoolRequestFactory poolRequestFactory, + IDataHandlerFactory dataHandlerFactory) + { + _availableDataHandlers = availableDataHandlers; + _poolItemFactory = poolItemFactory; + _poolRequestFactory = poolRequestFactory; + _dataHandlerFactory = dataHandlerFactory; + + _pool = new List>(); + _waitingRequesters = new List(); + } + + public async Task RequestDataHandler(object requester) //TODO: async? + { + if (_pool.All(i => i.InUse) && _pool.Count == _availableDataHandlers) //no free dataHandlers available + return await WaitForDataHandler(requester); + else if (_pool.All(i => i.InUse)) //every existing dataHandler is used -> create a new one + return CreateDataHandler(); + else //there are unused dataHandlers existing + return GetDataHandler(); + } + + private async Task WaitForDataHandler(object requester) //TODO: Add request to list/stack (FIFO) with all requests that have to be resolved + { + IDataHandler dataHandler = null; + IPoolRequest request = _poolRequestFactory.Create(requester); + + while (dataHandler == null) + { + if (_waitingRequesters.Contains(request) && _waitingRequesters.IndexOf(request) == 0) //request is in list and is first + { + if (_pool.Any(i => !i.InUse)) + dataHandler = GetDataHandler(); + else + await Task.Delay(1000); + } + else if (_waitingRequesters.Contains(request)) //request is in list but not first + await Task.Delay(1000); + else + _waitingRequesters.Add(request); + } + + _waitingRequesters.Remove(request); + + return dataHandler; + } + + private IDataHandler CreateDataHandler() + { + IPoolItem item = _poolItemFactory.Create(_dataHandlerFactory.Create()); + _pool.Add(item); + + item.InUse = true; + return item.Item; + } + + private IDataHandler GetDataHandler() + { + IPoolItem item = _pool.First(i => !i.InUse); + + item.InUse = true; + return item.Item; + } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/Pool/PoolItem.cs b/GBase/DataHandling/Pool/PoolItem.cs new file mode 100644 index 0000000..90fd4e9 --- /dev/null +++ b/GBase/DataHandling/Pool/PoolItem.cs @@ -0,0 +1,19 @@ +// Author: Simon Gockner +// Created: 2020-09-19 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.DataHandling.Pool; + +namespace GBase.DataHandling.Pool +{ + public class PoolItem : IPoolItem + { + public PoolItem(T item) + { + Item = item; + } + + public T Item { get; } + public bool InUse { get; set; } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/Pool/PoolRequest.cs b/GBase/DataHandling/Pool/PoolRequest.cs new file mode 100644 index 0000000..9a565fe --- /dev/null +++ b/GBase/DataHandling/Pool/PoolRequest.cs @@ -0,0 +1,18 @@ +// Author: Simon Gockner +// Created: 2020-09-19 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using GBase.Interfaces.DataHandling.Pool; + +namespace GBase.DataHandling.Pool +{ + public class PoolRequest : IPoolRequest + { + public PoolRequest(object requester) + { + Requester = requester; + } + + public object Requester { get; } + } +} \ No newline at end of file diff --git a/GBase/Installers/DataHandlingInstaller.cs b/GBase/Installers/DataHandlingInstaller.cs index cd523e5..134ccee 100644 --- a/GBase/Installers/DataHandlingInstaller.cs +++ b/GBase/Installers/DataHandlingInstaller.cs @@ -7,8 +7,13 @@ using GBase.DataHandling; using GBase.DataHandling.Cache; using GBase.DataHandling.Cache.Factories; using GBase.DataHandling.Factories; +using GBase.DataHandling.Factories.Pool; +using GBase.DataHandling.Pool; +using GBase.Interfaces.DataHandling; +using GBase.Interfaces.DataHandling.Pool; using GBase.Interfaces.DataHandling.Xml; using GBase.Interfaces.DataHandling.Xml.Cache; +using LightweightIocContainer; using LightweightIocContainer.Interfaces; using LightweightIocContainer.Interfaces.Installers; @@ -22,16 +27,22 @@ namespace GBase.Installers /// public void Install(IIocContainer container) { - container.Register(); - container.Register(); - container.Register(); + container.Register(); + container.Register(); + container.Register(); //cache container.Register(); container.Register(); container.Register(); + //pool + container.Register(Lifestyle.Singleton).WithParameters(10); + container.Register(); + container.RegisterFactory(); + //factories + container.RegisterFactory(); container.RegisterFactory(); container.RegisterFactory(); container.RegisterFactory(); diff --git a/GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs b/GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs new file mode 100644 index 0000000..5410861 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs @@ -0,0 +1,13 @@ +// Author: Simon Gockner +// Created: 2020-09-18 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.Threading.Tasks; + +namespace GBase.Interfaces.DataHandling.Pool +{ + public interface IDataHandlerPool + { + Task RequestDataHandler(object requester); + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Pool/IPoolItem.cs b/GBase/Interfaces/DataHandling/Pool/IPoolItem.cs new file mode 100644 index 0000000..8cdb3d9 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Pool/IPoolItem.cs @@ -0,0 +1,12 @@ +// Author: Simon Gockner +// Created: 2020-09-19 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +namespace GBase.Interfaces.DataHandling.Pool +{ + public interface IPoolItem + { + T Item { get; } + bool InUse { get; set; } + } +} \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Pool/IPoolRequest.cs b/GBase/Interfaces/DataHandling/Pool/IPoolRequest.cs new file mode 100644 index 0000000..6e36e93 --- /dev/null +++ b/GBase/Interfaces/DataHandling/Pool/IPoolRequest.cs @@ -0,0 +1,14 @@ +// Author: Simon Gockner +// Created: 2020-09-19 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.Threading.Tasks; + +namespace GBase.Interfaces.DataHandling.Pool +{ + public interface IPoolRequest + { + object Requester { get; } + } +} \ No newline at end of file From 641dbf5a52639d9405aeb72e6bdd0c947afd9a29 Mon Sep 17 00:00:00 2001 From: Simon G Date: Sun, 20 Sep 2020 23:45:47 +0200 Subject: [PATCH 17/46] #25: implement IAsyncDisposable, call DataHandler.Init() --- GBase/DataHandling/Pool/DataHandlerPool.cs | 29 ++++++++++++++----- .../DataHandling/Pool/IDataHandlerPool.cs | 6 ++-- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/GBase/DataHandling/Pool/DataHandlerPool.cs b/GBase/DataHandling/Pool/DataHandlerPool.cs index 23add72..5013e04 100644 --- a/GBase/DataHandling/Pool/DataHandlerPool.cs +++ b/GBase/DataHandling/Pool/DataHandlerPool.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using GBase.DataHandling.Factories; using GBase.DataHandling.Factories.Pool; @@ -36,17 +37,17 @@ namespace GBase.DataHandling.Pool _waitingRequesters = new List(); } - public async Task RequestDataHandler(object requester) //TODO: async? + public async Task RequestDataHandler(object requester, bool overwrite, CancellationToken cancellationToken) { if (_pool.All(i => i.InUse) && _pool.Count == _availableDataHandlers) //no free dataHandlers available - return await WaitForDataHandler(requester); + return await WaitForDataHandler(requester, cancellationToken); else if (_pool.All(i => i.InUse)) //every existing dataHandler is used -> create a new one - return CreateDataHandler(); + return await CreateDataHandler(overwrite, cancellationToken); else //there are unused dataHandlers existing return GetDataHandler(); } - private async Task WaitForDataHandler(object requester) //TODO: Add request to list/stack (FIFO) with all requests that have to be resolved + private async Task WaitForDataHandler(object requester, CancellationToken cancellationToken) { IDataHandler dataHandler = null; IPoolRequest request = _poolRequestFactory.Create(requester); @@ -58,10 +59,10 @@ namespace GBase.DataHandling.Pool if (_pool.Any(i => !i.InUse)) dataHandler = GetDataHandler(); else - await Task.Delay(1000); + await Task.Delay(1000, cancellationToken); } else if (_waitingRequesters.Contains(request)) //request is in list but not first - await Task.Delay(1000); + await Task.Delay(1000, cancellationToken); else _waitingRequesters.Add(request); } @@ -71,9 +72,10 @@ namespace GBase.DataHandling.Pool return dataHandler; } - private IDataHandler CreateDataHandler() + private async Task CreateDataHandler(bool overwrite, CancellationToken cancellationToken) { IPoolItem item = _poolItemFactory.Create(_dataHandlerFactory.Create()); + await item.Item.Init(overwrite, cancellationToken); _pool.Add(item); item.InUse = true; @@ -87,5 +89,18 @@ namespace GBase.DataHandling.Pool item.InUse = true; return item.Item; } + + public async ValueTask DisposeAsync() + { + while (_waitingRequesters.Any()) + { + await Task.Delay(1000); + } + + foreach (var dataHandler in _pool.Select(i => i.Item)) + { + await dataHandler.DisposeAsync(); + } + } } } \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs b/GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs index 5410861..ccece22 100644 --- a/GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs +++ b/GBase/Interfaces/DataHandling/Pool/IDataHandlerPool.cs @@ -2,12 +2,14 @@ // Created: 2020-09-18 // Copyright(c) 2020 SimonG. All Rights Reserved. +using System; +using System.Threading; using System.Threading.Tasks; namespace GBase.Interfaces.DataHandling.Pool { - public interface IDataHandlerPool + public interface IDataHandlerPool : IAsyncDisposable { - Task RequestDataHandler(object requester); + Task RequestDataHandler(object requester, bool overwrite, CancellationToken cancellationToken); } } \ No newline at end of file From b10ce3d1955caff42d0db6e7c8ecb857402ea83c Mon Sep 17 00:00:00 2001 From: Simon G Date: Sun, 20 Sep 2020 23:46:13 +0200 Subject: [PATCH 18/46] #25: use dataHandler pool --- GBase/FileHandling/FileHandler.cs | 50 +++++++++---------- GBase/Interfaces/FileHandling/IFileHandler.cs | 12 +++-- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index cbc1952..dcc9103 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -6,10 +6,9 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using GBase.DataHandling.Factories; using GBase.Interfaces; using GBase.Interfaces.DataHandling; -using GBase.Interfaces.DataHandling.Xml; +using GBase.Interfaces.DataHandling.Pool; using GBase.Interfaces.FileHandling; namespace GBase.FileHandling @@ -19,22 +18,17 @@ namespace GBase.FileHandling /// public class FileHandler : IFileHandler { - private readonly IXmlDataHandlerFactory _dataHandlerFactory; + private readonly IDataHandlerPool _dataHandlerPool; /// /// Internal file handler /// - /// Factory for the - public FileHandler(IXmlDataHandlerFactory xmlDataHandlerFactory) + /// The + public FileHandler(IDataHandlerPool dataHandlerPool) { - _dataHandlerFactory = xmlDataHandlerFactory; + _dataHandlerPool = dataHandlerPool; } - /// - /// The of this - /// - private IDataHandler DataHandler { get; set; } - /// /// Initialize this /// @@ -43,10 +37,7 @@ namespace GBase.FileHandling /// True if successful, false if not public async Task Init(string path, CancellationToken cancellationToken) { - DataHandler = _dataHandlerFactory.Create(); //FixMe: Factory is missing parameters - - bool success = await DataHandler.Init(false, cancellationToken); - return success; + return true; //TODO: is there anything that needs to be initialized here? } public Task AddEntry(T entry, IGBaseTable table) @@ -68,10 +59,12 @@ namespace GBase.FileHandling /// The of the property /// The name of the property /// The value to set + /// /// A to await - public async Task SetValue(string propertyName, TProperty value) + public async Task SetValue(string propertyName, TProperty value, CancellationToken cancellationToken) { - await DataHandler.SetValue(propertyName, value); + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); + await dataHandler.SetValue(propertyName, value); } /// @@ -81,10 +74,12 @@ namespace GBase.FileHandling /// The of the property /// The name of the property /// The value to set + /// /// A to await - public async Task RemoveValue(string propertyName, TProperty value) + public async Task RemoveValue(string propertyName, TProperty value, CancellationToken cancellationToken) { - await DataHandler.RemoveValue(propertyName, value); + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); + await dataHandler.RemoveValue(propertyName, value); } /// @@ -93,10 +88,12 @@ namespace GBase.FileHandling /// The of the property /// The of the property /// The name of the property + /// /// The value for the given property - public async Task GetValue(string propertyName) + public async Task GetValue(string propertyName, CancellationToken cancellationToken) { - return await DataHandler.GetValue(propertyName); + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); + return await dataHandler.GetValue(propertyName); } /// @@ -105,19 +102,18 @@ namespace GBase.FileHandling /// The of the property /// The of the property /// The name of the property + /// /// An with all the values for the property - public async Task> GetValues(string propertyName) + public async Task> GetValues(string propertyName, CancellationToken cancellationToken) { - return await DataHandler.GetValues(propertyName); + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); + return await dataHandler.GetValues(propertyName); } /// /// Dispose used resources asynchronously /// /// A to await - public async ValueTask DisposeAsync() - { - await DataHandler.DisposeAsync(); - } + public async ValueTask DisposeAsync() => await _dataHandlerPool.DisposeAsync(); } } \ No newline at end of file diff --git a/GBase/Interfaces/FileHandling/IFileHandler.cs b/GBase/Interfaces/FileHandling/IFileHandler.cs index ae3eb99..31a8b86 100644 --- a/GBase/Interfaces/FileHandling/IFileHandler.cs +++ b/GBase/Interfaces/FileHandling/IFileHandler.cs @@ -33,8 +33,9 @@ namespace GBase.Interfaces.FileHandling /// The of the property /// The name of the property /// The value to set + /// /// A to await - Task SetValue(string propertyName, TProperty value); + Task SetValue(string propertyName, TProperty value, CancellationToken cancellationToken); /// /// Remove the value for the given property @@ -43,8 +44,9 @@ namespace GBase.Interfaces.FileHandling /// The of the property /// The name of the property /// The value to set + /// /// A to await - Task RemoveValue(string propertyName, TProperty value); + Task RemoveValue(string propertyName, TProperty value, CancellationToken cancellationToken); /// /// Get the value for the given property, if multiple values are set the first is returned @@ -52,8 +54,9 @@ namespace GBase.Interfaces.FileHandling /// The of the property /// The of the property /// The name of the property + /// /// The value for the given property - Task GetValue(string propertyName); + Task GetValue(string propertyName, CancellationToken cancellationToken); /// /// Get all the values that are set for the given property @@ -61,7 +64,8 @@ namespace GBase.Interfaces.FileHandling /// The of the property /// The of the property /// The name of the property + /// /// An with all the values for the property - Task> GetValues(string propertyName); + Task> GetValues(string propertyName, CancellationToken cancellationToken); } } \ No newline at end of file From 1498a914df7421f3711f6ab947400f9a6c709a59 Mon Sep 17 00:00:00 2001 From: Simon G Date: Mon, 21 Sep 2020 03:46:16 +0200 Subject: [PATCH 19/46] #25: start implementing addEntry --- GBase/Attributes/GBaseTableAttribute.cs | 5 + GBase/FileHandling/FileHandler.cs | 20 ++- GBase/GBase.cs | 9 +- GBase/GBase.xml | 129 +++++++++++++----- GBase/GBaseTable.cs | 20 ++- GBase/Interfaces/FileHandling/IFileHandler.cs | 2 +- GBase/Interfaces/IGBaseTable.cs | 9 +- Test.GBase/GBaseTableIntegrationTest.cs | 2 +- 8 files changed, 135 insertions(+), 61 deletions(-) diff --git a/GBase/Attributes/GBaseTableAttribute.cs b/GBase/Attributes/GBaseTableAttribute.cs index 078e9f6..df332f8 100644 --- a/GBase/Attributes/GBaseTableAttribute.cs +++ b/GBase/Attributes/GBaseTableAttribute.cs @@ -13,6 +13,11 @@ namespace GBase.Attributes [AttributeUsage(AttributeTargets.Class)] public class GBaseTableAttribute : Attribute //TODO: Decide how to handle enums (as table or their own type) { + public GBaseTableAttribute(string folderName) + { + FolderName = folderName; + } + public string FolderName { get; } } } \ No newline at end of file diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index dcc9103..88ce20d 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; using GBase.Interfaces; @@ -18,7 +19,13 @@ namespace GBase.FileHandling /// public class FileHandler : IFileHandler { + /// + /// The file extension for all GBase tables + /// + public const string GBASE_TABLE_FILE_EXTENSION = "gb"; + private readonly IDataHandlerPool _dataHandlerPool; + private string _path; /// /// Internal file handler @@ -37,13 +44,22 @@ namespace GBase.FileHandling /// True if successful, false if not public async Task Init(string path, CancellationToken cancellationToken) { + _path = path; return true; //TODO: is there anything that needs to be initialized here? } - public Task AddEntry(T entry, IGBaseTable table) + public async Task AddEntry(T entry, IGBaseTable table, CancellationToken cancellationToken) { + string directoryPath = Path.Combine(_path, table.FolderName); + + //create directory if it doesn't exist + Directory.CreateDirectory(directoryPath); + //create new entry file - throw new NotImplementedException(); + string filePath = $"{Path.Combine(directoryPath, entry.ToString())}.{GBASE_TABLE_FILE_EXTENSION}"; + FileStream entryFile = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); + + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); } public Task RemoveEntry(T entry) diff --git a/GBase/GBase.cs b/GBase/GBase.cs index 4a789a3..91ff813 100644 --- a/GBase/GBase.cs +++ b/GBase/GBase.cs @@ -21,11 +21,6 @@ namespace GBase /// public class GBase : IGBase { - /// - /// The file extension for all GBase tables - /// - public const string GBASE_TABLE_FILE_EXTENSION = "gb"; //TODO: Find correct place for this const - private readonly IGBaseTableFactory _gBaseTableFactory; /// @@ -76,7 +71,7 @@ namespace GBase continue; IGBaseTable gBaseTable = _gBaseTableFactory.Create(type); - await gBaseTable.Init(type, type.Name, Settings.DatabasePath, cancellationToken); + await gBaseTable.Init(type, Settings.DatabasePath, gBaseTableAttribute.FolderName, cancellationToken); AddTable(gBaseTable); } @@ -94,7 +89,7 @@ namespace GBase if (Tables.Contains(table)) return false; - if (Tables.Any(t => t.Name.Equals(table.Name))) + if (Tables.Any(t => t.FolderName.Equals(table.FolderName))) return false; Tables.Add(table); diff --git a/GBase/GBase.xml b/GBase/GBase.xml index 2945813..cf649c2 100644 --- a/GBase/GBase.xml +++ b/GBase/GBase.xml @@ -361,6 +361,50 @@ The of the passed interface + + + that the passed table type doesn't implement "/> + + + + + that the passed table type doesn't implement "/> + + The table type + + + + that the table for the given is missing + + + + + that the table for the given is missing + + + + + The that has no table + + + + + Factory for the + + + + + Factory for the + + Factory for the + Factory for the + + + + Creates an + + A newly created instance of the implementation for + Factory for the @@ -389,7 +433,7 @@ Factory for the - + Creates an @@ -551,37 +595,54 @@ A to await - + + + GBase object that supplies inheriting classes with methods to get data from a + + + + + GBase object that allows conversion from + + No table for is existing + + + + Initialize this from a given + + The given + + A table - + A table - + The of the class that this represents - + The name of this - + The s of this - + The entries of this - + Initialize this @@ -591,35 +652,35 @@ A to cancel the asynchronous operation True if successful, false if not - + Add a given to this The given True if successful, false if not - + Remove a given from this The given True if successful, false if not - + Add an entry that implements to this The entry implementing True if successful, false if not - + Remove an entry that implements from this The entry implementing True if successful, false if not - + Modify the property of a given entry with the given value @@ -628,14 +689,14 @@ The new value to set True if successful, false if not - + A entry changed The entry (sender) The - + The method @@ -985,6 +1046,25 @@ A column of a + + + The entries of this + + + + + Add an entry that implements to this + + The entry implementing + True if successful, false if not + + + + Remove an entry that implements from this + + The entry implementing + True if successful, false if not + A table @@ -1005,11 +1085,6 @@ The s of this - - - The entries of this - - Initialize this @@ -1034,20 +1109,6 @@ The given True if successful, false if not - - - Add an entry that implements to this - - The entry implementing - True if successful, false if not - - - - Remove an entry that implements from this - - The entry implementing - True if successful, false if not - Settings of a instance diff --git a/GBase/GBaseTable.cs b/GBase/GBaseTable.cs index 5076bac..10bd705 100644 --- a/GBase/GBaseTable.cs +++ b/GBase/GBaseTable.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Reflection; using System.Threading; @@ -47,7 +46,7 @@ namespace GBase /// /// The name of this /// - public string Name { get; private set; } + public string FolderName { get; private set; } /// /// The s of this @@ -64,18 +63,15 @@ namespace GBase /// Initialize this /// /// The of the class that this represents - /// The name of this /// The path to the database files + /// /// A to cancel the asynchronous operation /// True if successful, false if not - public async Task Init(Type type, string name, string databasePath, CancellationToken cancellationToken) + public async Task Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken) { Type = type; - Name = name; - - string fileName = $"{name}.{GBase.GBASE_TABLE_FILE_EXTENSION}"; - string path = Path.Combine(databasePath, fileName); - await _fileHandler.Init(path, cancellationToken); + FolderName = folderName; + await _fileHandler.Init(databasePath, cancellationToken); //TODO: Init columns list depending on GBaseColumnAttributes set for this GBaseTable foreach (var property in type.GetProperties()) @@ -123,12 +119,12 @@ namespace GBase /// /// The entry implementing /// True if successful, false if not - public async Task AddEntry(T entry) //TODO: Write to file + public async Task AddEntry(T entry) { Entries.Add(entry); entry.GBaseEntryChanged += OnGBaseEntryChanged; - await _fileHandler.AddEntry(entry, this); + await _fileHandler.AddEntry(entry, this, TODO); return true; } @@ -138,7 +134,7 @@ namespace GBase /// /// The entry implementing /// True if successful, false if not - public async Task RemoveEntry(T entry) //TODO: remove from file + public async Task RemoveEntry(T entry) { if (!Entries.Contains(entry)) return false; diff --git a/GBase/Interfaces/FileHandling/IFileHandler.cs b/GBase/Interfaces/FileHandling/IFileHandler.cs index 31a8b86..3e3e715 100644 --- a/GBase/Interfaces/FileHandling/IFileHandler.cs +++ b/GBase/Interfaces/FileHandling/IFileHandler.cs @@ -22,7 +22,7 @@ namespace GBase.Interfaces.FileHandling /// True if successful, false if not Task Init(string path, CancellationToken cancellationToken); - Task AddEntry(T entry, IGBaseTable table); + Task AddEntry(T entry, IGBaseTable table, CancellationToken cancellationToken); Task RemoveEntry(T entry); diff --git a/GBase/Interfaces/IGBaseTable.cs b/GBase/Interfaces/IGBaseTable.cs index c240e37..e72bb9e 100644 --- a/GBase/Interfaces/IGBaseTable.cs +++ b/GBase/Interfaces/IGBaseTable.cs @@ -48,7 +48,7 @@ namespace GBase.Interfaces /// /// The name of this /// - string Name { get; } + string FolderName { get; } /// /// The s of this @@ -59,11 +59,12 @@ namespace GBase.Interfaces /// Initialize this /// /// The of the class that this represents - /// The name of this - /// /// The path to the database files + /// The path to the database files + /// /// A to cancel the asynchronous operation + /// /// /// True if successful, false if not - Task Init(Type type, string name, string databasePath, CancellationToken cancellationToken); + Task Init(Type type, string databasePath, string folderName, CancellationToken cancellationToken); /// /// Add a given to this diff --git a/Test.GBase/GBaseTableIntegrationTest.cs b/Test.GBase/GBaseTableIntegrationTest.cs index 4e5a753..8ec77c1 100644 --- a/Test.GBase/GBaseTableIntegrationTest.cs +++ b/Test.GBase/GBaseTableIntegrationTest.cs @@ -27,7 +27,7 @@ namespace Test.GBase gBaseColumnFactoryMock.Setup(c => c.Create()).Returns(new GBaseColumn()); IGBaseTable table = new GBaseTable(fileHandlerFactoryMock.Object, gBaseColumnFactoryMock.Object); - table.Init(typeof(Foo), nameof(Foo), "", CancellationToken.None); + table.Init(typeof(Foo), "", TODO, CancellationToken.None); Foo foo = new Foo("Test"); table.AddEntry(foo); From 8d1b24c5a11b66bd6a4826b4894615797e5159f6 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 22 Sep 2020 14:05:23 +0200 Subject: [PATCH 20/46] - add const naming rule --- GBase.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/GBase.sln.DotSettings b/GBase.sln.DotSettings index 976aca6..cb097b1 100644 --- a/GBase.sln.DotSettings +++ b/GBase.sln.DotSettings @@ -2,5 +2,6 @@ Author: $USER_NAME$ Created: $CREATED_YEAR$-$CREATED_MONTH$-$CREATED_DAY$ Copyright(c) $CREATED_YEAR$ SimonG. All Rights Reserved. + <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> \ No newline at end of file From 688ae81330a8c832d7e64af496faadd29b229d4e Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 22 Sep 2020 14:05:51 +0200 Subject: [PATCH 21/46] - fix usage of GBaseTable attribute --- Test.GBase/GBaseIntegrationTest/Group.cs | 2 +- Test.GBase/GBaseIntegrationTest/Item.cs | 2 +- Test.GBase/TestClasses/Foo.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Test.GBase/GBaseIntegrationTest/Group.cs b/Test.GBase/GBaseIntegrationTest/Group.cs index d1dc03c..24a77de 100644 --- a/Test.GBase/GBaseIntegrationTest/Group.cs +++ b/Test.GBase/GBaseIntegrationTest/Group.cs @@ -8,7 +8,7 @@ using GBase.Attributes; namespace Test.GBase.GBaseIntegrationTest { - [GBaseTable] + [GBaseTable("Groups")] public class Group : NotifyGBaseEntryChanged, IGroup { public Group() diff --git a/Test.GBase/GBaseIntegrationTest/Item.cs b/Test.GBase/GBaseIntegrationTest/Item.cs index e1f32b0..5eaecc7 100644 --- a/Test.GBase/GBaseIntegrationTest/Item.cs +++ b/Test.GBase/GBaseIntegrationTest/Item.cs @@ -7,7 +7,7 @@ using GBase.Attributes; namespace Test.GBase.GBaseIntegrationTest { - [GBaseTable] + [GBaseTable("Items")] public class Item : NotifyGBaseEntryChanged, IItem { diff --git a/Test.GBase/TestClasses/Foo.cs b/Test.GBase/TestClasses/Foo.cs index 0d4f1c2..2cfbb7c 100644 --- a/Test.GBase/TestClasses/Foo.cs +++ b/Test.GBase/TestClasses/Foo.cs @@ -7,7 +7,7 @@ using GBase.Attributes; namespace Test.GBase.TestClasses { - [GBaseTable] + [GBaseTable("Foo")] public class Foo : NotifyGBaseEntryChanged { private string _name; From 11a1b9c8283c2711f4ffa1707dfec628f11a4387 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 22 Sep 2020 14:06:22 +0200 Subject: [PATCH 22/46] - pass cancellationToken where needed --- GBase/GBase.cs | 4 ++-- GBase/GBaseTable.cs | 5 +++-- GBase/Interfaces/IGBase.cs | 2 +- GBase/Interfaces/IGBaseTable.cs | 3 ++- Test.GBase/GBaseIntegrationTest/Model.cs | 8 ++++---- Test.GBase/GBaseTableIntegrationTest.cs | 8 +++++--- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/GBase/GBase.cs b/GBase/GBase.cs index 91ff813..b449665 100644 --- a/GBase/GBase.cs +++ b/GBase/GBase.cs @@ -118,13 +118,13 @@ namespace GBase return Tables.Remove(table); } - public async Task AddEntry(T entry) where T : INotifyGBaseEntryChanged + public async Task AddEntry(T entry, CancellationToken cancellationToken) where T : INotifyGBaseEntryChanged { IGBaseTable table = GetTable(); if (table == null) throw new Exception(); //TODO: Create exception - return await table.AddEntry(entry); + return await table.AddEntry(entry, cancellationToken); } /// diff --git a/GBase/GBaseTable.cs b/GBase/GBaseTable.cs index 10bd705..790c9b5 100644 --- a/GBase/GBaseTable.cs +++ b/GBase/GBaseTable.cs @@ -118,13 +118,14 @@ namespace GBase /// Add an entry that implements to this /// /// The entry implementing + /// /// True if successful, false if not - public async Task AddEntry(T entry) + public async Task AddEntry(T entry, CancellationToken cancellationToken) { Entries.Add(entry); entry.GBaseEntryChanged += OnGBaseEntryChanged; - await _fileHandler.AddEntry(entry, this, TODO); + await _fileHandler.AddEntry(entry, this, cancellationToken); return true; } diff --git a/GBase/Interfaces/IGBase.cs b/GBase/Interfaces/IGBase.cs index 380d7cc..b49e0be 100644 --- a/GBase/Interfaces/IGBase.cs +++ b/GBase/Interfaces/IGBase.cs @@ -58,6 +58,6 @@ namespace GBase.Interfaces /// True if successful, false if not bool RemoveTable(IGBaseTable table); - Task AddEntry(T entry) where T : INotifyGBaseEntryChanged; + Task AddEntry(T entry, CancellationToken cancellationToken) where T : INotifyGBaseEntryChanged; } } \ No newline at end of file diff --git a/GBase/Interfaces/IGBaseTable.cs b/GBase/Interfaces/IGBaseTable.cs index e72bb9e..ca18623 100644 --- a/GBase/Interfaces/IGBaseTable.cs +++ b/GBase/Interfaces/IGBaseTable.cs @@ -21,8 +21,9 @@ namespace GBase.Interfaces /// Add an entry that implements to this /// /// The entry implementing + /// /// True if successful, false if not - Task AddEntry(T entry); + Task 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...) diff --git a/Test.GBase/GBaseIntegrationTest/Model.cs b/Test.GBase/GBaseIntegrationTest/Model.cs index 8253bc1..ca58085 100644 --- a/Test.GBase/GBaseIntegrationTest/Model.cs +++ b/Test.GBase/GBaseIntegrationTest/Model.cs @@ -36,16 +36,16 @@ namespace Test.GBase.GBaseIntegrationTest Groups = groupsTable.Entries; } - public void AddItem(IItem item) + public void AddItem(IItem item, CancellationToken cancellationToken) { Items.Add(item); - _gBase.AddEntry(item); + _gBase.AddEntry(item, cancellationToken); } - public void AddGroup(IGroup group) + public void AddGroup(IGroup group, CancellationToken cancellationToken) { Groups.Add(group); - _gBase.AddEntry(@group); + _gBase.AddEntry(group, cancellationToken); } } } \ No newline at end of file diff --git a/Test.GBase/GBaseTableIntegrationTest.cs b/Test.GBase/GBaseTableIntegrationTest.cs index 8ec77c1..0bb97ff 100644 --- a/Test.GBase/GBaseTableIntegrationTest.cs +++ b/Test.GBase/GBaseTableIntegrationTest.cs @@ -27,13 +27,15 @@ namespace Test.GBase gBaseColumnFactoryMock.Setup(c => c.Create()).Returns(new GBaseColumn()); IGBaseTable table = new GBaseTable(fileHandlerFactoryMock.Object, gBaseColumnFactoryMock.Object); - table.Init(typeof(Foo), "", TODO, CancellationToken.None); + table.Init(typeof(Foo), "", "", CancellationToken.None); + CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); + Foo foo = new Foo("Test"); - table.AddEntry(foo); + table.AddEntry(foo, cancellationTokenSource.Token); Foo foo2 = new Foo("Test2"); - table.AddEntry(foo2); + table.AddEntry(foo2, cancellationTokenSource.Token); foo.Name = "Foo - ex Test"; foo2.Name = "Some Name"; From f0783df9c2b2ca46db13783c9428f29cc1bbb803 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 22 Sep 2020 15:28:02 +0200 Subject: [PATCH 23/46] #25: start changing data writer --- .../Factories/IXmlDataWriterFactory.cs | 4 +- GBase/DataHandling/XmlDataHandler.cs | 29 ++++++-- GBase/DataHandling/XmlDataWriter.cs | 71 +++++-------------- GBase/FileHandling/FileHandler.cs | 3 +- GBase/GBase.xml | 56 ++++++++------- GBase/Interfaces/DataHandling/IDataHandler.cs | 5 ++ GBase/Interfaces/DataHandling/IDataWriter.cs | 11 ++- .../XmlDataHandlerLocalIntegrationTest.cs | 6 +- Test.GBase/DataHandling/XmlDataHandlerTest.cs | 62 ++++++++-------- 9 files changed, 120 insertions(+), 127 deletions(-) diff --git a/GBase/DataHandling/Factories/IXmlDataWriterFactory.cs b/GBase/DataHandling/Factories/IXmlDataWriterFactory.cs index 3c17344..53eb50b 100644 --- a/GBase/DataHandling/Factories/IXmlDataWriterFactory.cs +++ b/GBase/DataHandling/Factories/IXmlDataWriterFactory.cs @@ -14,9 +14,7 @@ namespace GBase.DataHandling.Factories /// /// Creates an /// - /// The path to the xml file - /// The root element name of the xml file /// A newly created instance of the implementation for - IXmlDataWriter Create(string path, string rootElementName); + IXmlDataWriter Create(); } } \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataHandler.cs b/GBase/DataHandling/XmlDataHandler.cs index 6c79de3..f666969 100644 --- a/GBase/DataHandling/XmlDataHandler.cs +++ b/GBase/DataHandling/XmlDataHandler.cs @@ -5,12 +5,14 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using GBase.DataHandling.Cache.Factories; using GBase.DataHandling.Factories; using GBase.Helpers; +using GBase.Interfaces; using GBase.Interfaces.DataHandling; using GBase.Interfaces.DataHandling.Xml; using GBase.Interfaces.DataHandling.Xml.Cache; @@ -46,17 +48,15 @@ namespace GBase.DataHandling /// A that handles its data in an xml file /// /// The path to the xml file - /// The root element name of the xml file /// The factory /// The factory /// The factory public XmlDataHandler(string path, - string rootElementName, IXmlDataReaderFactory xmlDataReaderFactory, IXmlDataWriterFactory xmlDataWriterFactory, IXmlDataHandlerCacheFactory xmlDataHandlerCacheFactory) { - _xmlDataWriter = xmlDataWriterFactory.Create(path, rootElementName); + _xmlDataWriter = xmlDataWriterFactory.Create(); _xmlDataReader = xmlDataReaderFactory.Create(path); _cache = xmlDataHandlerCacheFactory.Create(_xmlDataReader); @@ -75,9 +75,6 @@ namespace GBase.DataHandling _overwrite = overwrite; - if (!await _xmlDataWriter.Init(cancellationToken)) - return false; - if (!await _xmlDataReader.Init(cancellationToken)) return false; @@ -86,6 +83,24 @@ namespace GBase.DataHandling return true; } + public async Task AddEntry(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken) + { + if (!await _xmlDataWriter.InitFile(entryFile, table.Type.Name, cancellationToken)) + return false; + + foreach (var column in table.Columns) + { + //TODO: Set value for each column + } + + return true; + } + + public Task RemoveEntry(T entry) + { + throw new NotImplementedException(); + } + /// /// Set the value for the given property /// @@ -106,7 +121,7 @@ namespace GBase.DataHandling valueString = value.ToString(); await _cache.SetValue(propertyName, value, _overwrite); - await _xmlDataWriter.Write(propertyName, valueString, _overwrite); + await _xmlDataWriter.Write(TODO, propertyName, valueString, _overwrite, TODO); } /// diff --git a/GBase/DataHandling/XmlDataWriter.cs b/GBase/DataHandling/XmlDataWriter.cs index 3799f0b..40cc62a 100644 --- a/GBase/DataHandling/XmlDataWriter.cs +++ b/GBase/DataHandling/XmlDataWriter.cs @@ -18,56 +18,25 @@ namespace GBase.DataHandling /// public class XmlDataWriter : IXmlDataWriter { - private readonly string _rootElementName; - private readonly FileStream _file; - - private XDocument _xmlDocument; - private XElement _rootElement; - - private bool _isInitialized; - private CancellationToken _cancellationToken; - - /// - /// A that writes to an xml file - /// - /// The path to the xml file - /// The root element name of the xml file - public XmlDataWriter(string path, string rootElementName) - { - _rootElementName = rootElementName; - _file = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); - } - /// /// Initialize the /// + /// + /// /// A to cancel the async operation /// Returns true if successful, false if not /// No root element found - public async Task Init(CancellationToken cancellationToken) + public async Task InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken) { - if (_isInitialized) + //if the xml file isn't empty, return + if (file.Length > 3) //> 3 because of BOM return false; + + XDocument xmlDocument = new XDocument(); + xmlDocument.Add(new XElement(rootElementName)); + file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it + await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); - _cancellationToken = cancellationToken; - //if the xml file is empty, write the root element - if (_file.Length <= 3) //<= 3 because of BOM - { - _xmlDocument = new XDocument(); - _xmlDocument.Add(new XElement(_rootElementName)); - _file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it - await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); - } - else - { - _xmlDocument = await XDocument.LoadAsync(_file, LoadOptions.None, _cancellationToken); - } - - _rootElement = _xmlDocument.Root;//?.Element(_rootElementName); - if (_rootElement == null) - throw new Exception("No root element found."); - - _isInitialized = true; return true; } @@ -76,18 +45,22 @@ namespace GBase.DataHandling /// /// The that implements the property /// The of the property + /// /// The name of the property /// The value of the property /// If true an existing value is overwritten, if false an additional value is added + /// /// A to await /// - public async Task Write(string propertyName, string value, bool overwrite) + public async Task Write(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken) { string typeName = typeof(T).FullName; if (typeName == null) throw new ArgumentNullException(nameof(typeName)); + + XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken); - _file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it + file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it XElement typeElement = _rootElement.Element(typeName); if (typeElement != null) //type element already exists @@ -126,7 +99,7 @@ namespace GBase.DataHandling } //TODO: check if whole file is overwritten (probably) -> performance issues for large files? - await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, _cancellationToken); //save the document with the added elements + await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); //save the document with the added elements } /// @@ -157,15 +130,5 @@ namespace GBase.DataHandling //TODO: check if whole file is overwritten (probably) -> performance issues for large files? await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, _cancellationToken); //save the document with the added elements } - - /// - /// Dispose used resources asynchronously - /// - /// A to await - public async ValueTask DisposeAsync() - { - await _xmlDocument.SaveAsync(_file, SaveOptions.None, _cancellationToken); - await _file.DisposeAsync(); - } } } \ No newline at end of file diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index 88ce20d..e4915bc 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -57,9 +57,10 @@ namespace GBase.FileHandling //create new entry file string filePath = $"{Path.Combine(directoryPath, entry.ToString())}.{GBASE_TABLE_FILE_EXTENSION}"; - FileStream entryFile = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); + FileStream entryFile = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); //TODO: Stream has to be disposed IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); + await dataHandler.AddEntry(entry, table, entryFile, cancellationToken); } public Task RemoveEntry(T entry) diff --git a/GBase/GBase.xml b/GBase/GBase.xml index cf649c2..ded0749 100644 --- a/GBase/GBase.xml +++ b/GBase/GBase.xml @@ -455,16 +455,16 @@ Internal file handler - + - Internal file handler + The file extension for all GBase tables - Factory for the - + - The of this + Internal file handler + The @@ -474,7 +474,7 @@ A to cancel the asynchronous operation True if successful, false if not - + Set the value for the given property @@ -482,9 +482,10 @@ The of the property The name of the property The value to set + A to await - + Remove the value for the given property @@ -492,24 +493,27 @@ The of the property The name of the property The value to set + A to await - + Get the value for the given property, if multiple values are set the first is returned The of the property The of the property The name of the property + The value for the given property - + Get all the values that are set for the given property The of the property The of the property The name of the property + An with all the values for the property @@ -523,11 +527,6 @@ The base class of the GBase database - - - The file extension for all GBase tables - - The base class of the GBase database @@ -627,7 +626,7 @@ The of the class that this represents - + The name of this @@ -647,8 +646,8 @@ Initialize this The of the class that this represents - The name of this The path to the database files + A to cancel the asynchronous operation True if successful, false if not @@ -666,11 +665,12 @@ The given True if successful, false if not - + Add an entry that implements to this The entry implementing + True if successful, false if not @@ -960,7 +960,7 @@ A to cancel the asynchronous operation True if successful, false if not - + Set the value for the given property @@ -968,9 +968,10 @@ The of the property The name of the property The value to set + A to await - + Remove the value for the given property @@ -978,24 +979,27 @@ The of the property The name of the property The value to set + A to await - + Get the value for the given property, if multiple values are set the first is returned The of the property The of the property The name of the property + The value for the given property - + Get all the values that are set for the given property The of the property The of the property The name of the property + An with all the values for the property @@ -1051,11 +1055,12 @@ The entries of this - + Add an entry that implements to this The entry implementing + True if successful, false if not @@ -1075,7 +1080,7 @@ The of the class that this represents - + The name of this @@ -1090,9 +1095,10 @@ Initialize this The of the class that this represents - The name of this - /// The path to the database files + The path to the database files + A to cancel the asynchronous operation + /// True if successful, false if not diff --git a/GBase/Interfaces/DataHandling/IDataHandler.cs b/GBase/Interfaces/DataHandling/IDataHandler.cs index cc600be..f42cb82 100644 --- a/GBase/Interfaces/DataHandling/IDataHandler.cs +++ b/GBase/Interfaces/DataHandling/IDataHandler.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; @@ -22,6 +23,10 @@ namespace GBase.Interfaces.DataHandling /// Returns true if successful, false if not Task Init(bool overwrite, CancellationToken cancellationToken); + Task AddEntry(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken); + + Task RemoveEntry(T entry); + /// /// Set the value for the given property /// diff --git a/GBase/Interfaces/DataHandling/IDataWriter.cs b/GBase/Interfaces/DataHandling/IDataWriter.cs index c049b66..cd65a26 100644 --- a/GBase/Interfaces/DataHandling/IDataWriter.cs +++ b/GBase/Interfaces/DataHandling/IDataWriter.cs @@ -3,6 +3,7 @@ // Copyright(c) 2020 SimonG. All Rights Reserved. using System; +using System.IO; using System.Threading; using System.Threading.Tasks; @@ -11,25 +12,29 @@ namespace GBase.Interfaces.DataHandling /// /// Interface for data writers to implement /// - public interface IDataWriter : IAsyncDisposable + public interface IDataWriter { /// /// Initialize the /// + /// + /// /// A to cancel the async operation /// Returns true if successful, false if not - Task Init(CancellationToken cancellationToken); + Task InitFile(FileStream file, string rootElementName, CancellationToken cancellationToken); /// /// Write the data of a property /// /// The /// The of the property + /// /// The name of the property /// The value of the property /// If true an existing value is overwritten, if false an additional value is added + /// /// A to await - Task Write(string propertyName, string value, bool overwrite); + Task Write(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken); /// /// Remove the value for the given property diff --git a/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs b/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs index 72f4459..afc6caf 100644 --- a/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs +++ b/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs @@ -27,8 +27,8 @@ namespace Test.GBase.DataHandling Assert.Pass(); //Remove this assert.pass() if you want to run this test locally Mock dataWriterFactoryMock = new Mock(); - dataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())) - .Returns((string path, string rootElementName) => new XmlDataWriter(path, rootElementName)); + dataWriterFactoryMock.Setup(w => w.Create()) + .Returns(new XmlDataWriter()); Mock dataReaderFactoryMock = new Mock(); dataReaderFactoryMock.Setup(r => r.Create(It.IsAny())) @@ -48,7 +48,7 @@ namespace Test.GBase.DataHandling .Returns((IXmlDataReader xmlDataReader) => new XmlDataHandlerCache(xmlDataReader, dataHandlerCacheEntryFactoryMock.Object, dataHandlerCachePropertyEntryFactoryMock.Object)); - IXmlDataHandler xmlDataHandler = new XmlDataHandler("TestXml.xml", "Properties", dataReaderFactoryMock.Object, dataWriterFactoryMock.Object, + IXmlDataHandler xmlDataHandler = new XmlDataHandler("TestXml.xml", dataReaderFactoryMock.Object, dataWriterFactoryMock.Object, dataHandlerCacheFactoryMock.Object); await xmlDataHandler.Init(false, new CancellationToken()); diff --git a/Test.GBase/DataHandling/XmlDataHandlerTest.cs b/Test.GBase/DataHandling/XmlDataHandlerTest.cs index 699aede..cbf4b4f 100644 --- a/Test.GBase/DataHandling/XmlDataHandlerTest.cs +++ b/Test.GBase/DataHandling/XmlDataHandlerTest.cs @@ -28,16 +28,16 @@ namespace Test.GBase.DataHandling xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); - xmlDataWriterMock.Setup(w => w.Init(It.IsAny())).ReturnsAsync(true); + xmlDataWriterMock.Setup(w => w.InitFile(TODO, TODO, It.IsAny())).ReturnsAsync(true); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); Assert.True(await xmlDataHandler.Init(false, CancellationToken.None)); @@ -53,16 +53,16 @@ namespace Test.GBase.DataHandling xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); - xmlDataWriterMock.Setup(w => w.Init(It.IsAny())).ReturnsAsync(true); + xmlDataWriterMock.Setup(w => w.InitFile(TODO, TODO, It.IsAny())).ReturnsAsync(true); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); Assert.True(await xmlDataHandler.Init(false, CancellationToken.None)); @@ -79,16 +79,16 @@ namespace Test.GBase.DataHandling xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); - xmlDataWriterMock.Setup(w => w.Init(It.IsAny())).ReturnsAsync(true); + xmlDataWriterMock.Setup(w => w.InitFile(TODO, TODO, It.IsAny())).ReturnsAsync(true); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); Assert.False(await xmlDataHandler.Init(false, CancellationToken.None)); @@ -104,16 +104,16 @@ namespace Test.GBase.DataHandling xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); - xmlDataWriterMock.Setup(w => w.Init(It.IsAny())).ReturnsAsync(false); + xmlDataWriterMock.Setup(w => w.InitFile(TODO, TODO, It.IsAny())).ReturnsAsync(false); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); Assert.False(await xmlDataHandler.Init(false, CancellationToken.None)); @@ -128,19 +128,19 @@ namespace Test.GBase.DataHandling Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); await xmlDataHandler.SetValue("property", "SomeString"); xmlDataHandlerCacheMock.Verify(c => c.SetValue("property", "SomeString", false), Times.Once); - xmlDataWriterMock.Verify(w => w.Write("property", "SomeString", false), Times.Once); + xmlDataWriterMock.Verify(w => w.Write(TODO, "property", "SomeString", false, TODO), Times.Once); } [Test] @@ -152,20 +152,20 @@ namespace Test.GBase.DataHandling Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); List stringList = new List() {"string", "secondString", "thirdString"}; await xmlDataHandler.SetValue>("property", stringList); xmlDataHandlerCacheMock.Verify(c => c.SetValue>("property", stringList, false), Times.Once); - xmlDataWriterMock.Verify(w => w.Write>("property", $"{stringList[0]},{stringList[1]},{stringList[2]}", false), Times.Once); + xmlDataWriterMock.Verify(w => w.Write>(TODO, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", false, TODO), Times.Once); } [Test] @@ -177,19 +177,19 @@ namespace Test.GBase.DataHandling Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); await xmlDataHandler.SetValue("property", null); xmlDataHandlerCacheMock.Verify(c => c.SetValue(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - xmlDataWriterMock.Verify(w => w.Write(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + xmlDataWriterMock.Verify(w => w.Write(TODO, It.IsAny(), It.IsAny(), It.IsAny(), TODO), Times.Never); } [Test] @@ -201,13 +201,13 @@ namespace Test.GBase.DataHandling Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); await xmlDataHandler.RemoveValue("property", "SomeString"); @@ -225,13 +225,13 @@ namespace Test.GBase.DataHandling Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); List stringList = new List() { "string", "secondString", "thirdString" }; @@ -250,13 +250,13 @@ namespace Test.GBase.DataHandling Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); await xmlDataHandler.RemoveValue("property", null); @@ -278,13 +278,13 @@ namespace Test.GBase.DataHandling Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); } @@ -301,13 +301,13 @@ namespace Test.GBase.DataHandling Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create(It.IsAny(), It.IsAny())).Returns(xmlDataWriterMock.Object); + xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); Mock xmlDataHandlerCacheMock = new Mock(); Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", "root", xmlDataReaderFactoryMock.Object, + XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); IEnumerable> readValues = await xmlDataHandler.GetValues>("property"); From 84d98a5dee5d5e57ef359a8d7853815f853563d0 Mon Sep 17 00:00:00 2001 From: Simon G Date: Mon, 9 Nov 2020 15:27:23 +0100 Subject: [PATCH 24/46] #25: adapt XmlDataWriter to one file per entry strategy --- .../Exceptions/InvalidXmlFileException.cs | 17 +++++ GBase/DataHandling/XmlDataHandler.cs | 2 +- GBase/DataHandling/XmlDataWriter.cs | 62 ++++++++++--------- GBase/Interfaces/DataHandling/IDataWriter.cs | 4 +- Test.GBase/DataHandling/XmlDataHandlerTest.cs | 6 +- 5 files changed, 56 insertions(+), 35 deletions(-) create mode 100644 GBase/DataHandling/Exceptions/InvalidXmlFileException.cs diff --git a/GBase/DataHandling/Exceptions/InvalidXmlFileException.cs b/GBase/DataHandling/Exceptions/InvalidXmlFileException.cs new file mode 100644 index 0000000..adfc8fc --- /dev/null +++ b/GBase/DataHandling/Exceptions/InvalidXmlFileException.cs @@ -0,0 +1,17 @@ +// Author: Gockner, Simon +// Created: 2020-11-09 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; + +namespace GBase.DataHandling.Exceptions +{ + public class InvalidXmlFileException : Exception + { + public InvalidXmlFileException(string message) + : base(message) + { + + } + } +} \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataHandler.cs b/GBase/DataHandling/XmlDataHandler.cs index f666969..c168908 100644 --- a/GBase/DataHandling/XmlDataHandler.cs +++ b/GBase/DataHandling/XmlDataHandler.cs @@ -144,7 +144,7 @@ namespace GBase.DataHandling valueString = value.ToString(); await _cache.TryRemoveValue(propertyName, value); - await _xmlDataWriter.Remove(propertyName, valueString); + await _xmlDataWriter.Remove(TODO, propertyName, valueString, TODO); } /// diff --git a/GBase/DataHandling/XmlDataWriter.cs b/GBase/DataHandling/XmlDataWriter.cs index 40cc62a..5e3e54f 100644 --- a/GBase/DataHandling/XmlDataWriter.cs +++ b/GBase/DataHandling/XmlDataWriter.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; +using GBase.DataHandling.Exceptions; using GBase.Interfaces.DataHandling; using GBase.Interfaces.DataHandling.Xml; @@ -52,6 +53,7 @@ namespace GBase.DataHandling /// /// A to await /// + /// No root element is set public async Task Write(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken) { string typeName = typeof(T).FullName; @@ -59,43 +61,35 @@ namespace GBase.DataHandling throw new ArgumentNullException(nameof(typeName)); XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken); - file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it - XElement typeElement = _rootElement.Element(typeName); - if (typeElement != null) //type element already exists + XElement rootElement = xmlDocument.Root; + if (rootElement == null) + throw new InvalidXmlFileException("No root element is set."); + + XElement propertyElement = rootElement.Element(propertyName); + if (propertyElement != null) //property element already exists { - XElement propertyElement = typeElement.Element(propertyName); - if (propertyElement != null) //property element already exists + XElement valueElement = propertyElement.Element(XmlDataHandler.VALUE_ELEMENT_NAME); + if (valueElement != null && overwrite) //value element exists and overwrite is true { - XElement valueElement = propertyElement.Element(XmlDataHandler.VALUE_ELEMENT_NAME); - if (valueElement != null && overwrite) //value element exists and overwrite is true - { - valueElement.Value = value; //overwrite existing value - } - else if (!overwrite && propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).Any(v => v.Value.Equals(value))) //no overwrite and same value exists already - { - XElement sameValueElement = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).First(v => v.Value.Equals(value)); - sameValueElement.Remove(); //remove the already existing value from its current position - propertyElement.AddFirst(sameValueElement); //add it as the first element again - } - else //no value element exists or overwrite is false - propertyElement.AddFirst(new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //add a new value element + valueElement.Value = value; //overwrite existing value } - else //property element doesn't exist + else if (!overwrite && propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).Any(v => v.Value.Equals(value))) //no overwrite and same value exists already { - propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element - propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute - - typeElement.Add(propertyElement); //create new property element with the value element + XElement sameValueElement = propertyElement.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).First(v => v.Value.Equals(value)); + sameValueElement.Remove(); //remove the already existing value from its current position + propertyElement.AddFirst(sameValueElement); //add it as the first element again } + else //no value element exists or overwrite is false + propertyElement.AddFirst(new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //add a new value element } - else //type element doesn't exist + else //property element doesn't exist { - XElement propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element + propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute - _rootElement.Add(new XElement(typeName, propertyElement)); //create a new type element with the new property element + rootElement.Add(propertyElement); //create new property element with the value element } //TODO: check if whole file is overwritten (probably) -> performance issues for large files? @@ -107,19 +101,27 @@ namespace GBase.DataHandling /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set + /// /// A to await /// - public async Task Remove(string propertyName, string value) + /// No root element is set + public async Task Remove(FileStream file, string propertyName, string value, CancellationToken cancellationToken) { string typeName = typeof(T).FullName; if (typeName == null) throw new ArgumentNullException(nameof(typeName)); - _file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it + XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken); + file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it - XElement typeElement = _rootElement.Element(typeName); + XElement rootElement = xmlDocument.Root; + if (rootElement == null) + throw new InvalidXmlFileException("No root element is set."); + + XElement typeElement = rootElement.Element(typeName); XElement propertyElement = typeElement?.Element(propertyName); XElement valueElement = propertyElement?.Elements(XmlDataHandler.VALUE_ELEMENT_NAME).FirstOrDefault(e => e.Value.Equals(value)); if (valueElement == null) @@ -128,7 +130,7 @@ namespace GBase.DataHandling valueElement.Remove(); //TODO: check if whole file is overwritten (probably) -> performance issues for large files? - await _xmlDocument.SaveAsync(_file, SaveOptions.OmitDuplicateNamespaces, _cancellationToken); //save the document with the added elements + await xmlDocument.SaveAsync(file, SaveOptions.OmitDuplicateNamespaces, cancellationToken); //save the document with the added elements } } } \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/IDataWriter.cs b/GBase/Interfaces/DataHandling/IDataWriter.cs index cd65a26..c7a67c2 100644 --- a/GBase/Interfaces/DataHandling/IDataWriter.cs +++ b/GBase/Interfaces/DataHandling/IDataWriter.cs @@ -41,9 +41,11 @@ namespace GBase.Interfaces.DataHandling /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set + /// /// A to await - Task Remove(string propertyName, string value); + Task Remove(FileStream file, string propertyName, string value, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/Test.GBase/DataHandling/XmlDataHandlerTest.cs b/Test.GBase/DataHandling/XmlDataHandlerTest.cs index cbf4b4f..548b2fe 100644 --- a/Test.GBase/DataHandling/XmlDataHandlerTest.cs +++ b/Test.GBase/DataHandling/XmlDataHandlerTest.cs @@ -213,7 +213,7 @@ namespace Test.GBase.DataHandling await xmlDataHandler.RemoveValue("property", "SomeString"); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue("property", "SomeString"), Times.Once); - xmlDataWriterMock.Verify(w => w.Remove("property", "SomeString"), Times.Once); + xmlDataWriterMock.Verify(w => w.Remove(TODO, "property", "SomeString", TODO), Times.Once); } [Test] @@ -238,7 +238,7 @@ namespace Test.GBase.DataHandling await xmlDataHandler.RemoveValue>("property", stringList); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue>("property", stringList), Times.Once); - xmlDataWriterMock.Verify(w => w.Remove>("property", $"{stringList[0]},{stringList[1]},{stringList[2]}"), Times.Once); + xmlDataWriterMock.Verify(w => w.Remove>(TODO, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", TODO), Times.Once); } [Test] @@ -262,7 +262,7 @@ namespace Test.GBase.DataHandling await xmlDataHandler.RemoveValue("property", null); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue(It.IsAny(), It.IsAny()), Times.Never); - xmlDataWriterMock.Verify(w => w.Remove(It.IsAny(), It.IsAny()), Times.Never); + xmlDataWriterMock.Verify(w => w.Remove(TODO, It.IsAny(), It.IsAny(), TODO), Times.Never); } [Test] From 1cfa80c19994252fed151bf3f8ecaed621da8f86 Mon Sep 17 00:00:00 2001 From: Simon G Date: Mon, 9 Nov 2020 16:04:50 +0100 Subject: [PATCH 25/46] #25: adapt XmlDataHandler --- GBase/DataHandling/XmlDataHandler.cs | 25 +++++++++++++++---- GBase/DataHandling/XmlDataWriter.cs | 20 ++++++++++++--- GBase/Factories/IGBaseColumnFactory.cs | 2 +- GBase/FileHandling/FileHandler.cs | 4 +-- GBase/GBaseColumn.cs | 6 +++-- GBase/GBaseTable.cs | 2 +- GBase/Interfaces/DataHandling/IDataHandler.cs | 12 ++++++--- GBase/Interfaces/DataHandling/IDataWriter.cs | 13 ++++++++++ GBase/Interfaces/IGBaseColumn.cs | 2 +- .../XmlDataHandlerLocalIntegrationTest.cs | 4 +-- Test.GBase/DataHandling/XmlDataHandlerTest.cs | 18 ++++++------- 11 files changed, 79 insertions(+), 29 deletions(-) diff --git a/GBase/DataHandling/XmlDataHandler.cs b/GBase/DataHandling/XmlDataHandler.cs index c168908..83de8eb 100644 --- a/GBase/DataHandling/XmlDataHandler.cs +++ b/GBase/DataHandling/XmlDataHandler.cs @@ -7,6 +7,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Threading; using System.Threading.Tasks; using GBase.DataHandling.Cache.Factories; @@ -91,6 +92,17 @@ namespace GBase.DataHandling foreach (var column in table.Columns) { //TODO: Set value for each column + PropertyInfo property = entry.GetType().GetProperty(column.Name); + if (property == null) + continue; //TODO: What to do in this case? (Shouldn't really happen...) + + string valueString; + if (property.PropertyType != typeof(string) && property.GetValue(entry) is IEnumerable enumerable) + valueString = enumerable.ToGBaseString(); + else + valueString = property.GetValue(entry).ToString(); + + await _xmlDataWriter.Write(entryFile, property.Name, valueString, property.PropertyType, _overwrite, cancellationToken); } return true; @@ -106,10 +118,12 @@ namespace GBase.DataHandling /// /// The that implements the property /// The of the property + /// /// The name of the property /// The value to set + /// /// A to await - public async Task SetValue(string propertyName, TProperty value) + public async Task SetValue(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken) { if (value == null) return; @@ -121,7 +135,7 @@ namespace GBase.DataHandling valueString = value.ToString(); await _cache.SetValue(propertyName, value, _overwrite); - await _xmlDataWriter.Write(TODO, propertyName, valueString, _overwrite, TODO); + await _xmlDataWriter.Write(entryFile, propertyName, valueString, _overwrite, cancellationToken); } /// @@ -129,10 +143,12 @@ namespace GBase.DataHandling /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set + /// /// A to await - public async Task RemoveValue(string propertyName, TProperty value) + public async Task RemoveValue(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken) { if (value == null) return; @@ -144,7 +160,7 @@ namespace GBase.DataHandling valueString = value.ToString(); await _cache.TryRemoveValue(propertyName, value); - await _xmlDataWriter.Remove(TODO, propertyName, valueString, TODO); + await _xmlDataWriter.Remove(entryFile, propertyName, valueString, cancellationToken); } /// @@ -183,7 +199,6 @@ namespace GBase.DataHandling public async ValueTask DisposeAsync() { await _xmlDataReader.DisposeAsync(); - await _xmlDataWriter.DisposeAsync(); } } } \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataWriter.cs b/GBase/DataHandling/XmlDataWriter.cs index 5e3e54f..4dce15d 100644 --- a/GBase/DataHandling/XmlDataWriter.cs +++ b/GBase/DataHandling/XmlDataWriter.cs @@ -44,7 +44,7 @@ namespace GBase.DataHandling /// /// Write the data of a property /// - /// The that implements the property + /// The /// The of the property /// /// The name of the property @@ -52,9 +52,23 @@ namespace GBase.DataHandling /// If true an existing value is overwritten, if false an additional value is added /// /// A to await + public async Task Write(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken) => + await Write(file, propertyName, value, typeof(TProperty), overwrite, cancellationToken); + + /// + /// Write the data of a property + /// + /// The that implements the property + /// + /// The name of the property + /// The value of the property + /// + /// If true an existing value is overwritten, if false an additional value is added + /// + /// A to await /// /// No root element is set - public async Task Write(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken) + public async Task Write(FileStream file, string propertyName, string value, Type propertyType, bool overwrite, CancellationToken cancellationToken) { string typeName = typeof(T).FullName; if (typeName == null) @@ -87,7 +101,7 @@ namespace GBase.DataHandling else //property element doesn't exist { propertyElement = new XElement(propertyName, new XElement(XmlDataHandler.VALUE_ELEMENT_NAME) { Value = value }); //create the new property element with the value element - propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, typeof(TProperty).FullName); //add the property type attribute + propertyElement.SetAttributeValue(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME, propertyType.FullName); //add the property type attribute rootElement.Add(propertyElement); //create new property element with the value element } diff --git a/GBase/Factories/IGBaseColumnFactory.cs b/GBase/Factories/IGBaseColumnFactory.cs index 46f5b4c..7bd39ed 100644 --- a/GBase/Factories/IGBaseColumnFactory.cs +++ b/GBase/Factories/IGBaseColumnFactory.cs @@ -16,6 +16,6 @@ namespace GBase.Factories /// Creates an /// /// A newly created instance of the implementation for - IGBaseColumn Create(); + IGBaseColumn Create(string name); } } \ No newline at end of file diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index e4915bc..1e997d2 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -81,7 +81,7 @@ namespace GBase.FileHandling public async Task SetValue(string propertyName, TProperty value, CancellationToken cancellationToken) { IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); - await dataHandler.SetValue(propertyName, value); + await dataHandler.SetValue(TODO, propertyName, value, cancellationToken); } /// @@ -96,7 +96,7 @@ namespace GBase.FileHandling public async Task RemoveValue(string propertyName, TProperty value, CancellationToken cancellationToken) { IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); - await dataHandler.RemoveValue(propertyName, value); + await dataHandler.RemoveValue(TODO, propertyName, value, cancellationToken); } /// diff --git a/GBase/GBaseColumn.cs b/GBase/GBaseColumn.cs index ee3f45b..25d2da2 100644 --- a/GBase/GBaseColumn.cs +++ b/GBase/GBaseColumn.cs @@ -16,10 +16,12 @@ namespace GBase /// /// A column of a /// - public GBaseColumn() + public GBaseColumn(string name) { - + Name = name; } + + public string Name { get; } /// /// The method diff --git a/GBase/GBaseTable.cs b/GBase/GBaseTable.cs index 790c9b5..1bddadd 100644 --- a/GBase/GBaseTable.cs +++ b/GBase/GBaseTable.cs @@ -80,7 +80,7 @@ namespace GBase if (gBaseColumnAttribute == null) continue; - IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create(); + IGBaseColumn gBaseColumn = _gBaseColumnFactory.Create(property.Name); AddColumn(gBaseColumn); } diff --git a/GBase/Interfaces/DataHandling/IDataHandler.cs b/GBase/Interfaces/DataHandling/IDataHandler.cs index f42cb82..7ff4d30 100644 --- a/GBase/Interfaces/DataHandling/IDataHandler.cs +++ b/GBase/Interfaces/DataHandling/IDataHandler.cs @@ -26,26 +26,32 @@ namespace GBase.Interfaces.DataHandling Task AddEntry(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken); Task RemoveEntry(T entry); - + /// /// Set the value for the given property /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set + /// /// A to await - Task SetValue(string propertyName, TProperty value); + Task SetValue(FileStream entryFile, string propertyName, TProperty value, + CancellationToken cancellationToken); /// /// Remove the value for the given property /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set + /// /// A to await - Task RemoveValue(string propertyName, TProperty value); + Task RemoveValue(FileStream entryFile, string propertyName, TProperty value, + CancellationToken cancellationToken); /// /// Get the value for the given property, if multiple values are set the first is returned diff --git a/GBase/Interfaces/DataHandling/IDataWriter.cs b/GBase/Interfaces/DataHandling/IDataWriter.cs index c7a67c2..98ffef4 100644 --- a/GBase/Interfaces/DataHandling/IDataWriter.cs +++ b/GBase/Interfaces/DataHandling/IDataWriter.cs @@ -35,6 +35,19 @@ namespace GBase.Interfaces.DataHandling /// /// A to await Task Write(FileStream file, string propertyName, string value, bool overwrite, CancellationToken cancellationToken); + + /// + /// Write the data of a property + /// + /// The + /// + /// The name of the property + /// The value of the property + /// + /// If true an existing value is overwritten, if false an additional value is added + /// + /// A to await + Task Write(FileStream file, string propertyName, string value, Type propertyType, bool overwrite, CancellationToken cancellationToken); /// /// Remove the value for the given property diff --git a/GBase/Interfaces/IGBaseColumn.cs b/GBase/Interfaces/IGBaseColumn.cs index d78a691..59cd728 100644 --- a/GBase/Interfaces/IGBaseColumn.cs +++ b/GBase/Interfaces/IGBaseColumn.cs @@ -11,6 +11,6 @@ namespace GBase.Interfaces /// public interface IGBaseColumn : IAsyncDisposable //TODO: Make column generic (generic type is type of the value of the column?)? { - + string Name { get; } } } \ No newline at end of file diff --git a/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs b/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs index afc6caf..0b56644 100644 --- a/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs +++ b/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs @@ -55,10 +55,10 @@ namespace Test.GBase.DataHandling // //await xmlDataHandler.SetValue(nameof(TestProperty), TestProperty); //await xmlDataHandler.SetValue(nameof(TestProperty), "empty"); - await xmlDataHandler.SetValue(nameof(TestProperty), "test"); + await xmlDataHandler.SetValue(TODO, nameof(TestProperty), "test", TODO); //await xmlDataHandler.SetValue(nameof(TestProperty), "OverwrittenString"); // - await xmlDataHandler.SetValue(nameof(TestInt), 1); + await xmlDataHandler.SetValue(TODO, nameof(TestInt), 1, TODO); //await xmlDataHandler.SetValue(nameof(TestInt), 2); //await xmlDataHandler.SetValue(nameof(TestInt), 3); TestProperty = await xmlDataHandler.GetValue(nameof(TestProperty)); diff --git a/Test.GBase/DataHandling/XmlDataHandlerTest.cs b/Test.GBase/DataHandling/XmlDataHandlerTest.cs index 548b2fe..b8d9384 100644 --- a/Test.GBase/DataHandling/XmlDataHandlerTest.cs +++ b/Test.GBase/DataHandling/XmlDataHandlerTest.cs @@ -137,10 +137,10 @@ namespace Test.GBase.DataHandling XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - await xmlDataHandler.SetValue("property", "SomeString"); + await xmlDataHandler.SetValue(TODO, "property", "SomeString", TODO); xmlDataHandlerCacheMock.Verify(c => c.SetValue("property", "SomeString", false), Times.Once); - xmlDataWriterMock.Verify(w => w.Write(TODO, "property", "SomeString", false, TODO), Times.Once); + xmlDataWriterMock.Verify(w => w.Write(TODO, "property", "SomeString", TODO, false, TODO), Times.Once); } [Test] @@ -162,10 +162,10 @@ namespace Test.GBase.DataHandling xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); List stringList = new List() {"string", "secondString", "thirdString"}; - await xmlDataHandler.SetValue>("property", stringList); + await xmlDataHandler.SetValue>(TODO, "property", stringList, TODO); xmlDataHandlerCacheMock.Verify(c => c.SetValue>("property", stringList, false), Times.Once); - xmlDataWriterMock.Verify(w => w.Write>(TODO, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", false, TODO), Times.Once); + xmlDataWriterMock.Verify(w => w.Write>(TODO, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", TODO, false, TODO), Times.Once); } [Test] @@ -186,10 +186,10 @@ namespace Test.GBase.DataHandling XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - await xmlDataHandler.SetValue("property", null); + await xmlDataHandler.SetValue(TODO, "property", null, TODO); xmlDataHandlerCacheMock.Verify(c => c.SetValue(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - xmlDataWriterMock.Verify(w => w.Write(TODO, It.IsAny(), It.IsAny(), It.IsAny(), TODO), Times.Never); + xmlDataWriterMock.Verify(w => w.Write(TODO, It.IsAny(), It.IsAny(), TODO, It.IsAny(), TODO), Times.Never); } [Test] @@ -210,7 +210,7 @@ namespace Test.GBase.DataHandling XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - await xmlDataHandler.RemoveValue("property", "SomeString"); + await xmlDataHandler.RemoveValue(TODO, "property", "SomeString", TODO); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue("property", "SomeString"), Times.Once); xmlDataWriterMock.Verify(w => w.Remove(TODO, "property", "SomeString", TODO), Times.Once); @@ -235,7 +235,7 @@ namespace Test.GBase.DataHandling xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); List stringList = new List() { "string", "secondString", "thirdString" }; - await xmlDataHandler.RemoveValue>("property", stringList); + await xmlDataHandler.RemoveValue>(TODO, "property", stringList, TODO); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue>("property", stringList), Times.Once); xmlDataWriterMock.Verify(w => w.Remove>(TODO, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", TODO), Times.Once); @@ -259,7 +259,7 @@ namespace Test.GBase.DataHandling XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - await xmlDataHandler.RemoveValue("property", null); + await xmlDataHandler.RemoveValue(TODO, "property", null, TODO); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue(It.IsAny(), It.IsAny()), Times.Never); xmlDataWriterMock.Verify(w => w.Remove(TODO, It.IsAny(), It.IsAny(), TODO), Times.Never); From c446babb05e42d0f6f713a3ca7444166abbf4d59 Mon Sep 17 00:00:00 2001 From: Simon G Date: Mon, 9 Nov 2020 16:31:43 +0100 Subject: [PATCH 26/46] #25: start adapting FileHandler, add todo for possibly a better usage --- GBase/FileHandling/FileHandler.cs | 22 ++++++++++++++----- GBase/Interfaces/FileHandling/IFileHandler.cs | 3 ++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index 1e997d2..e4a708b 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using GBase.Interfaces; @@ -17,7 +18,7 @@ namespace GBase.FileHandling /// /// Internal file handler /// - public class FileHandler : IFileHandler + public class FileHandler : IFileHandler //TODO: Don't let file handler call data handler, have them parallel and have file handler only handle the files. this also makes more sense with the dataHandlerPool { /// /// The file extension for all GBase tables @@ -27,6 +28,8 @@ namespace GBase.FileHandling private readonly IDataHandlerPool _dataHandlerPool; private string _path; + private readonly List<(object entry, FileStream file, string filePath, bool inUse)> _files; + /// /// Internal file handler /// @@ -34,6 +37,7 @@ namespace GBase.FileHandling public FileHandler(IDataHandlerPool dataHandlerPool) { _dataHandlerPool = dataHandlerPool; + _files = new List<(object entry, FileStream file, string filePath, bool inUse)>(); } /// @@ -61,12 +65,19 @@ namespace GBase.FileHandling IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); await dataHandler.AddEntry(entry, table, entryFile, cancellationToken); + + _files.Add((entry, entryFile, filePath, false)); } - public Task RemoveEntry(T entry) + public async Task RemoveEntry(T entry) { - //remove entry file - throw new NotImplementedException(); + var file = _files.FirstOrDefault(f => f.entry.Equals(entry)); + if (file == default) + return false; + + await file.file.DisposeAsync(); + File.Delete(file.filePath); + return true; } /// @@ -74,11 +85,12 @@ namespace GBase.FileHandling /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set /// /// A to await - public async Task SetValue(string propertyName, TProperty value, CancellationToken cancellationToken) + public async Task SetValue(T entry, string propertyName, TProperty value, CancellationToken cancellationToken) { IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); await dataHandler.SetValue(TODO, propertyName, value, cancellationToken); diff --git a/GBase/Interfaces/FileHandling/IFileHandler.cs b/GBase/Interfaces/FileHandling/IFileHandler.cs index 3e3e715..b617c6d 100644 --- a/GBase/Interfaces/FileHandling/IFileHandler.cs +++ b/GBase/Interfaces/FileHandling/IFileHandler.cs @@ -31,11 +31,12 @@ namespace GBase.Interfaces.FileHandling /// /// The of the property /// The of the property + /// /// The name of the property /// The value to set /// /// A to await - Task SetValue(string propertyName, TProperty value, CancellationToken cancellationToken); + Task SetValue(T entry, string propertyName, TProperty value, CancellationToken cancellationToken); /// /// Remove the value for the given property From 6c5df6818e08b0a636cfaf6100d418095b8c1558 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 14:52:08 +0100 Subject: [PATCH 27/46] #25: adapt dataReader --- GBase/DataHandling/XmlDataHandler.cs | 28 +++----- GBase/DataHandling/XmlDataReader.cs | 65 ++++--------------- GBase/Interfaces/DataHandling/IDataHandler.cs | 19 +++--- GBase/Interfaces/DataHandling/IDataReader.cs | 14 ++-- 4 files changed, 37 insertions(+), 89 deletions(-) diff --git a/GBase/DataHandling/XmlDataHandler.cs b/GBase/DataHandling/XmlDataHandler.cs index 83de8eb..b61a2dd 100644 --- a/GBase/DataHandling/XmlDataHandler.cs +++ b/GBase/DataHandling/XmlDataHandler.cs @@ -67,20 +67,15 @@ namespace GBase.DataHandling /// Initialize the /// /// If true an existing value is overwritten, if false an additional value is added - /// A to cancel the async operation /// Returns true if successful, false if not - public async Task Init(bool overwrite, CancellationToken cancellationToken) + public bool Init(bool overwrite) { if (_isInitialized) return false; _overwrite = overwrite; - if (!await _xmlDataReader.Init(cancellationToken)) - return false; - _isInitialized = true; - return true; } @@ -168,11 +163,13 @@ namespace GBase.DataHandling /// /// The that implements the property /// The of the property + /// /// The name of the property + /// /// The value for the given property - public async Task GetValue(string propertyName) + public async Task GetValue(FileStream file, string propertyName, CancellationToken cancellationToken) { - IEnumerable enumerable = await GetValues(propertyName); + IEnumerable enumerable = await GetValues(file, propertyName, cancellationToken); return enumerable == null ? default : enumerable.FirstOrDefault(); } @@ -181,24 +178,17 @@ namespace GBase.DataHandling /// /// The that implements the property /// The of the property + /// /// The name of the property + /// /// An with all the values for the property - public async Task> GetValues(string propertyName) + public async Task> GetValues(FileStream file, string propertyName, CancellationToken cancellationToken) { IEnumerable cachedValues = await _cache.TryGetValues(propertyName); if (cachedValues != null) return cachedValues; - return await _xmlDataReader.Read(propertyName); - } - - /// - /// Dispose used resources asynchronously - /// - /// A to await - public async ValueTask DisposeAsync() - { - await _xmlDataReader.DisposeAsync(); + return await _xmlDataReader.Read(file, propertyName, cancellationToken); } } } \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataReader.cs b/GBase/DataHandling/XmlDataReader.cs index 03b7396..e83ba65 100644 --- a/GBase/DataHandling/XmlDataReader.cs +++ b/GBase/DataHandling/XmlDataReader.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; +using GBase.DataHandling.Exceptions; using GBase.Helpers; using GBase.Interfaces.DataHandling; using GBase.Interfaces.DataHandling.Xml; @@ -21,65 +22,34 @@ namespace GBase.DataHandling /// public class XmlDataReader : IXmlDataReader { - private readonly FileStream _file; - private XDocument _xmlDocument; - private XElement _rootElement; - - private bool _isInitialized; - private CancellationToken _cancellationToken; - - /// - /// A that reads from a xml file - /// - /// The path to the xml file - public XmlDataReader(string path) - { - _file = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - } - - /// - /// Initialize the - /// - /// A to cancel the async operation - /// Returns true if successful, false if not - /// No root element found - public async Task Init(CancellationToken cancellationToken) - { - if (_isInitialized) - return false; - - _cancellationToken = cancellationToken; - _xmlDocument = await XDocument.LoadAsync(_file, LoadOptions.None, _cancellationToken); - - _rootElement = _xmlDocument.Root; - if (_rootElement == null) - throw new Exception("No root element found."); - - _isInitialized = true; - - return true; - } - /// /// Read the data of a property /// /// The /// The of the property + /// /// The name of the property + /// /// The data of the given property, null if no data found /// /// Invalid found for the read object - public async Task> Read(string propertyName) + public async Task> Read(FileStream file, string propertyName, CancellationToken cancellationToken) //TODO: Read currently doesn't work for newly added items -> probably because file was loaded before new items were added; is probably not a problem -> cache { string typeName = typeof(T).FullName; if (typeName == null) throw new ArgumentNullException(nameof(typeName)); + XDocument xmlDocument = await XDocument.LoadAsync(file, LoadOptions.None, cancellationToken); + file.Seek(0, SeekOrigin.Begin); //reset stream to it's beginning to be able to save it + return await Task.Run(() => { - XElement typeElement = _rootElement.Element(typeName); - XElement propertyElement = typeElement?.Element(propertyName); + XElement rootElement = xmlDocument.Root; + if (rootElement == null) + throw new InvalidXmlFileException("No root element is set."); + + XElement propertyElement = rootElement.Element(propertyName); XAttribute propertyTypeAttribute = propertyElement?.Attribute(XmlDataHandler.VALUE_TYPE_ATTRIBUTE_NAME); if (propertyTypeAttribute == null) return null; @@ -98,16 +68,7 @@ namespace GBase.DataHandling return values.Select(Enumerables.ConvertToGBaseEnumerable).ToList(); return values.Select(value => (TProperty)Convert.ChangeType(value, typeof(TProperty))).ToList(); - }, _cancellationToken); - } - - /// - /// Dispose used resources asynchronously - /// - /// A to await - public async ValueTask DisposeAsync() - { - await _file.DisposeAsync(); + }, cancellationToken); } } } \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/IDataHandler.cs b/GBase/Interfaces/DataHandling/IDataHandler.cs index 7ff4d30..afab835 100644 --- a/GBase/Interfaces/DataHandling/IDataHandler.cs +++ b/GBase/Interfaces/DataHandling/IDataHandler.cs @@ -13,15 +13,14 @@ namespace GBase.Interfaces.DataHandling /// /// Interface for data handlers to implement /// - public interface IDataHandler : IAsyncDisposable + public interface IDataHandler { /// /// Initialize the /// /// If true an existing value is overwritten, if false an additional value is added - /// A to cancel the async operation /// Returns true if successful, false if not - Task Init(bool overwrite, CancellationToken cancellationToken); + bool Init(bool overwrite); Task AddEntry(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken); @@ -37,8 +36,7 @@ namespace GBase.Interfaces.DataHandling /// The value to set /// /// A to await - Task SetValue(FileStream entryFile, string propertyName, TProperty value, - CancellationToken cancellationToken); + Task SetValue(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken); /// /// Remove the value for the given property @@ -50,25 +48,28 @@ namespace GBase.Interfaces.DataHandling /// The value to set /// /// A to await - Task RemoveValue(FileStream entryFile, string propertyName, TProperty value, - CancellationToken cancellationToken); + Task RemoveValue(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken); /// /// Get the value for the given property, if multiple values are set the first is returned /// /// The of the property /// The of the property + /// /// The name of the property + /// /// The value for the given property - Task GetValue(string propertyName); + Task GetValue(FileStream file, string propertyName, CancellationToken cancellationToken); /// /// Get all the values that are set for the given property /// /// The of the property /// The of the property + /// /// The name of the property + /// /// An with all the values for the property - Task> GetValues(string propertyName); + Task> GetValues(FileStream file, string propertyName, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/GBase/Interfaces/DataHandling/IDataReader.cs b/GBase/Interfaces/DataHandling/IDataReader.cs index e6d34da..cacdfb5 100644 --- a/GBase/Interfaces/DataHandling/IDataReader.cs +++ b/GBase/Interfaces/DataHandling/IDataReader.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; @@ -12,22 +13,17 @@ namespace GBase.Interfaces.DataHandling /// /// Interface for data readers to implement /// - public interface IDataReader : IAsyncDisposable + public interface IDataReader { - /// - /// Initialize the - /// - /// A to cancel the async operation - /// Returns true if successful, false if not - Task Init(CancellationToken cancellationToken); - /// /// Read the data of a property /// /// The /// The of the property + /// /// The name of the property + /// /// The data of the given property, null if no data found - Task> Read(string propertyName); + Task> Read(FileStream file, string propertyName, CancellationToken cancellationToken); } } \ No newline at end of file From c433add6f02de09db5f9ef6045e45c79d80281d4 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 14:52:21 +0100 Subject: [PATCH 28/46] #25: make test methods async --- Test.GBase/GBaseIntegrationTest/Model.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Test.GBase/GBaseIntegrationTest/Model.cs b/Test.GBase/GBaseIntegrationTest/Model.cs index ca58085..dc8f9de 100644 --- a/Test.GBase/GBaseIntegrationTest/Model.cs +++ b/Test.GBase/GBaseIntegrationTest/Model.cs @@ -36,16 +36,16 @@ namespace Test.GBase.GBaseIntegrationTest Groups = groupsTable.Entries; } - public void AddItem(IItem item, CancellationToken cancellationToken) + public async Task AddItem(IItem item, CancellationToken cancellationToken) { Items.Add(item); - _gBase.AddEntry(item, cancellationToken); + await _gBase.AddEntry(item, cancellationToken); } - public void AddGroup(IGroup group, CancellationToken cancellationToken) + public async Task AddGroup(IGroup group, CancellationToken cancellationToken) { Groups.Add(group); - _gBase.AddEntry(group, cancellationToken); + await _gBase.AddEntry(@group, cancellationToken); } } } \ No newline at end of file From ca6c75be2354c9bc78f20637f21e0a1674d9af38 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 15:25:57 +0100 Subject: [PATCH 29/46] #25: file handler now only handles files --- .../Exceptions/FileNotExistingException.cs | 17 +++ GBase/FileHandling/FileHandler.cs | 108 ++++++------------ GBase/FileHandling/GBaseFile.cs | 32 ++++++ GBase/Interfaces/FileHandling/IFileHandler.cs | 48 +------- GBase/Interfaces/FileHandling/IGBaseFile.cs | 19 +++ 5 files changed, 104 insertions(+), 120 deletions(-) create mode 100644 GBase/FileHandling/Exceptions/FileNotExistingException.cs create mode 100644 GBase/FileHandling/GBaseFile.cs create mode 100644 GBase/Interfaces/FileHandling/IGBaseFile.cs diff --git a/GBase/FileHandling/Exceptions/FileNotExistingException.cs b/GBase/FileHandling/Exceptions/FileNotExistingException.cs new file mode 100644 index 0000000..2981ec1 --- /dev/null +++ b/GBase/FileHandling/Exceptions/FileNotExistingException.cs @@ -0,0 +1,17 @@ +// Author: Gockner, Simon +// Created: 2020-11-10 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; + +namespace GBase.FileHandling.Exceptions +{ + public class FileNotExistingException : Exception + { + public FileNotExistingException() + : base($"File for the given type {typeof(T)} is not existing.") + { + + } + } +} \ No newline at end of file diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index e4a708b..0e330ec 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -2,15 +2,13 @@ // Created: 2020-02-12 // Copyright(c) 2020 SimonG. All Rights Reserved. -using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using GBase.FileHandling.Exceptions; using GBase.Interfaces; -using GBase.Interfaces.DataHandling; -using GBase.Interfaces.DataHandling.Pool; using GBase.Interfaces.FileHandling; namespace GBase.FileHandling @@ -18,26 +16,22 @@ namespace GBase.FileHandling /// /// Internal file handler /// - public class FileHandler : IFileHandler //TODO: Don't let file handler call data handler, have them parallel and have file handler only handle the files. this also makes more sense with the dataHandlerPool + public class FileHandler : IFileHandler { /// /// The file extension for all GBase tables /// public const string GBASE_TABLE_FILE_EXTENSION = "gb"; - private readonly IDataHandlerPool _dataHandlerPool; + private readonly List _files; private string _path; - - private readonly List<(object entry, FileStream file, string filePath, bool inUse)> _files; /// /// Internal file handler /// - /// The - public FileHandler(IDataHandlerPool dataHandlerPool) + public FileHandler() { - _dataHandlerPool = dataHandlerPool; - _files = new List<(object entry, FileStream file, string filePath, bool inUse)>(); + _files = new List(); } /// @@ -52,7 +46,7 @@ namespace GBase.FileHandling return true; //TODO: is there anything that needs to be initialized here? } - public async Task AddEntry(T entry, IGBaseTable table, CancellationToken cancellationToken) + public IGBaseFile CreateEntryFile(T entry, IGBaseTable table) { string directoryPath = Path.Combine(_path, table.FolderName); @@ -63,86 +57,50 @@ namespace GBase.FileHandling string filePath = $"{Path.Combine(directoryPath, entry.ToString())}.{GBASE_TABLE_FILE_EXTENSION}"; FileStream entryFile = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite); //TODO: Stream has to be disposed - IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); - await dataHandler.AddEntry(entry, table, entryFile, cancellationToken); - - _files.Add((entry, entryFile, filePath, false)); + IGBaseFile file = new GBaseFile(entry, entryFile, filePath); + _files.Add(file); + + return file.UseFile(); } - public async Task RemoveEntry(T entry) + public async Task DeleteEntryFile(T entry) { - var file = _files.FirstOrDefault(f => f.entry.Equals(entry)); + IGBaseFile file = _files.FirstOrDefault(f => f.Entry.Equals(entry)); if (file == default) return false; - await file.file.DisposeAsync(); - File.Delete(file.filePath); + await file.File.DisposeAsync(); + File.Delete(file.FilePath); return true; } - /// - /// Set the value for the given property - /// - /// The of the property - /// The of the property - /// - /// The name of the property - /// The value to set - /// - /// A to await - public async Task SetValue(T entry, string propertyName, TProperty value, CancellationToken cancellationToken) + public async Task RequestEntryFile(T entry) { - IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); - await dataHandler.SetValue(TODO, propertyName, value, cancellationToken); - } - - /// - /// Remove the value for the given property - /// - /// The of the property - /// The of the property - /// The name of the property - /// The value to set - /// - /// A to await - public async Task RemoveValue(string propertyName, TProperty value, CancellationToken cancellationToken) - { - IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); - await dataHandler.RemoveValue(TODO, propertyName, value, cancellationToken); - } + IGBaseFile file = _files.FirstOrDefault(f => f.Entry.Equals(entry)); + if (file == default) + throw new FileNotExistingException(); - /// - /// Get the value for the given property, if multiple values are set the first is returned - /// - /// The of the property - /// The of the property - /// The name of the property - /// - /// The value for the given property - public async Task GetValue(string propertyName, CancellationToken cancellationToken) - { - IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); - return await dataHandler.GetValue(propertyName); - } + if (file.InUse) + await Task.Delay(1000); - /// - /// Get all the values that are set for the given property - /// - /// The of the property - /// The of the property - /// The name of the property - /// - /// An with all the values for the property - public async Task> GetValues(string propertyName, CancellationToken cancellationToken) - { - IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); - return await dataHandler.GetValues(propertyName); + return file.UseFile(); } /// /// Dispose used resources asynchronously /// /// A to await - public async ValueTask DisposeAsync() => await _dataHandlerPool.DisposeAsync(); + public async ValueTask DisposeAsync() + { + while (_files.Any(f => f.InUse)) + { + await Task.Delay(1000); + } + + foreach (var file in _files) + { + await file.File.DisposeAsync(); + } + } } } \ No newline at end of file diff --git a/GBase/FileHandling/GBaseFile.cs b/GBase/FileHandling/GBaseFile.cs new file mode 100644 index 0000000..aaf0f56 --- /dev/null +++ b/GBase/FileHandling/GBaseFile.cs @@ -0,0 +1,32 @@ +// Author: Gockner, Simon +// Created: 2020-11-10 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.IO; +using GBase.Interfaces.FileHandling; + +namespace GBase.FileHandling +{ + public class GBaseFile : IGBaseFile + { + public GBaseFile(object entry, FileStream file, string filePath) + { + Entry = entry; + File = file; + FilePath = filePath; + } + + public object Entry { get; } + public FileStream File { get; } + public string FilePath { get; } + public bool InUse { get; private set; } + + public IGBaseFile UseFile() + { + InUse = true; + return this; + } + + public void Dispose() => InUse = false; + } +} \ No newline at end of file diff --git a/GBase/Interfaces/FileHandling/IFileHandler.cs b/GBase/Interfaces/FileHandling/IFileHandler.cs index b617c6d..0e9ca47 100644 --- a/GBase/Interfaces/FileHandling/IFileHandler.cs +++ b/GBase/Interfaces/FileHandling/IFileHandler.cs @@ -3,7 +3,6 @@ // Copyright(c) 2020 SimonG. All Rights Reserved. using System; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -22,51 +21,10 @@ namespace GBase.Interfaces.FileHandling /// True if successful, false if not Task Init(string path, CancellationToken cancellationToken); - Task AddEntry(T entry, IGBaseTable table, CancellationToken cancellationToken); + IGBaseFile CreateEntryFile(T entry, IGBaseTable table); - Task RemoveEntry(T entry); + Task DeleteEntryFile(T entry); - /// - /// Set the value for the given property - /// - /// The of the property - /// The of the property - /// - /// The name of the property - /// The value to set - /// - /// A to await - Task SetValue(T entry, string propertyName, TProperty value, CancellationToken cancellationToken); - - /// - /// Remove the value for the given property - /// - /// The of the property - /// The of the property - /// The name of the property - /// The value to set - /// - /// A to await - Task RemoveValue(string propertyName, TProperty value, CancellationToken cancellationToken); - - /// - /// Get the value for the given property, if multiple values are set the first is returned - /// - /// The of the property - /// The of the property - /// The name of the property - /// - /// The value for the given property - Task GetValue(string propertyName, CancellationToken cancellationToken); - - /// - /// Get all the values that are set for the given property - /// - /// The of the property - /// The of the property - /// The name of the property - /// - /// An with all the values for the property - Task> GetValues(string propertyName, CancellationToken cancellationToken); + Task RequestEntryFile(T entry); } } \ No newline at end of file diff --git a/GBase/Interfaces/FileHandling/IGBaseFile.cs b/GBase/Interfaces/FileHandling/IGBaseFile.cs new file mode 100644 index 0000000..9904130 --- /dev/null +++ b/GBase/Interfaces/FileHandling/IGBaseFile.cs @@ -0,0 +1,19 @@ +// Author: Gockner, Simon +// Created: 2020-11-10 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System; +using System.IO; + +namespace GBase.Interfaces.FileHandling +{ + public interface IGBaseFile : IDisposable + { + object Entry { get; } + FileStream File { get; } + string FilePath { get; } + bool InUse { get; } + + IGBaseFile UseFile(); + } +} \ No newline at end of file From 93e2a1fd8c0c5c7e0249c5ba97f861a442326124 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 15:26:20 +0100 Subject: [PATCH 30/46] #25: adapt cache --- GBase/DataHandling/Cache/XmlDataHandlerCache.cs | 8 ++++++-- GBase/DataHandling/XmlDataHandler.cs | 2 +- GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs | 6 +++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/GBase/DataHandling/Cache/XmlDataHandlerCache.cs b/GBase/DataHandling/Cache/XmlDataHandlerCache.cs index 43d7883..e6db2a2 100644 --- a/GBase/DataHandling/Cache/XmlDataHandlerCache.cs +++ b/GBase/DataHandling/Cache/XmlDataHandlerCache.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using GBase.DataHandling.Cache.Factories; using GBase.Interfaces.DataHandling.Cache; @@ -103,9 +105,11 @@ namespace GBase.DataHandling.Cache /// /// The that implements the property /// The of the property + /// /// The name of the property + /// /// An with all the values for the property - public async Task> TryGetValues(string propertyName) + public async Task> TryGetValues(FileStream file, string propertyName, CancellationToken cancellationToken) { IXmlDataHandlerCacheEntry entry = _cache.FirstOrDefault(e => e.Type == typeof(T)); IDataHandlerCachePropertyEntry property = entry?.Properties.FirstOrDefault(p => p.PropertyName.Equals(propertyName)); @@ -114,7 +118,7 @@ namespace GBase.DataHandling.Cache if (!property.IsInitialized) //initialize property by reading the values from the xml { - List values = (await _xmlDataReader.Read(propertyName))?.ToList(); + List values = (await _xmlDataReader.Read(file, propertyName, cancellationToken))?.ToList(); if (values != null) { foreach (TProperty value in values.Where(value => !property.Values.Any(v => v.Equals(value)))) diff --git a/GBase/DataHandling/XmlDataHandler.cs b/GBase/DataHandling/XmlDataHandler.cs index b61a2dd..64c2901 100644 --- a/GBase/DataHandling/XmlDataHandler.cs +++ b/GBase/DataHandling/XmlDataHandler.cs @@ -184,7 +184,7 @@ namespace GBase.DataHandling /// An with all the values for the property public async Task> GetValues(FileStream file, string propertyName, CancellationToken cancellationToken) { - IEnumerable cachedValues = await _cache.TryGetValues(propertyName); + IEnumerable cachedValues = await _cache.TryGetValues(file, propertyName, cancellationToken); if (cachedValues != null) return cachedValues; diff --git a/GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs b/GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs index e02a452..9bcba60 100644 --- a/GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs +++ b/GBase/Interfaces/DataHandling/Cache/IDataHandlerCache.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Threading; using System.Threading.Tasks; namespace GBase.Interfaces.DataHandling.Cache @@ -39,8 +41,10 @@ namespace GBase.Interfaces.DataHandling.Cache /// /// The that implements the property /// The of the property + /// /// The name of the property + /// /// An with all the values for the property - Task> TryGetValues(string propertyName); + Task> TryGetValues(FileStream file, string propertyName, CancellationToken cancellationToken); } } \ No newline at end of file From 2d4b9c820de57dc89eacf76901190658b1c9e07c Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 15:26:31 +0100 Subject: [PATCH 31/46] #25: adapt DataHandlerPool --- GBase/DataHandling/Pool/DataHandlerPool.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/GBase/DataHandling/Pool/DataHandlerPool.cs b/GBase/DataHandling/Pool/DataHandlerPool.cs index 5013e04..8438d04 100644 --- a/GBase/DataHandling/Pool/DataHandlerPool.cs +++ b/GBase/DataHandling/Pool/DataHandlerPool.cs @@ -42,7 +42,7 @@ namespace GBase.DataHandling.Pool if (_pool.All(i => i.InUse) && _pool.Count == _availableDataHandlers) //no free dataHandlers available return await WaitForDataHandler(requester, cancellationToken); else if (_pool.All(i => i.InUse)) //every existing dataHandler is used -> create a new one - return await CreateDataHandler(overwrite, cancellationToken); + return CreateDataHandler(overwrite); else //there are unused dataHandlers existing return GetDataHandler(); } @@ -72,10 +72,10 @@ namespace GBase.DataHandling.Pool return dataHandler; } - private async Task CreateDataHandler(bool overwrite, CancellationToken cancellationToken) + private IDataHandler CreateDataHandler(bool overwrite) { IPoolItem item = _poolItemFactory.Create(_dataHandlerFactory.Create()); - await item.Item.Init(overwrite, cancellationToken); + item.Item.Init(overwrite); _pool.Add(item); item.InUse = true; @@ -96,11 +96,6 @@ namespace GBase.DataHandling.Pool { await Task.Delay(1000); } - - foreach (var dataHandler in _pool.Select(i => i.Item)) - { - await dataHandler.DisposeAsync(); - } } } } \ No newline at end of file From 7ab02d7d3a8330eda65ad9d70a91a53a70d119fe Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 15:26:49 +0100 Subject: [PATCH 32/46] #25: GBase can now get and set values --- GBase/GBase.cs | 33 +++++++++++++++++-- GBase/GBaseTable.cs | 57 +++++++++++++++++---------------- GBase/Interfaces/IGBase.cs | 9 ++++-- GBase/Interfaces/IGBaseTable.cs | 8 ++++- 4 files changed, 72 insertions(+), 35 deletions(-) diff --git a/GBase/GBase.cs b/GBase/GBase.cs index b449665..56ad1c0 100644 --- a/GBase/GBase.cs +++ b/GBase/GBase.cs @@ -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.Factories; using GBase.Interfaces; @@ -96,7 +95,7 @@ namespace GBase return true; } - public IGBaseTable GetTable() where T : INotifyGBaseEntryChanged + public IGBaseTable GetTable() { if (Tables.OfType>().Any()) return Tables.OfType>().First(); @@ -118,7 +117,7 @@ namespace GBase return Tables.Remove(table); } - public async Task AddEntry(T entry, CancellationToken cancellationToken) where T : INotifyGBaseEntryChanged + public async Task AddEntry(T entry, CancellationToken cancellationToken) { IGBaseTable table = GetTable(); if (table == null) @@ -126,6 +125,34 @@ namespace GBase return await table.AddEntry(entry, cancellationToken); } + + public async Task SetValue(T entry, string propertyName, TProperty value, CancellationToken cancellationToken) + { + IGBaseTable table = GetTable(); + if (table == null) + throw new Exception(); //TODO: Create exception + + await table.SetValue(entry, propertyName, value, cancellationToken); + } + + public async Task GetValue(T entry, string propertyName, CancellationToken cancellationToken) + { + IGBaseTable table = GetTable(); + if (table == null) + throw new Exception(); //TODO: Create exception + + return await table.GetValue(entry, propertyName, cancellationToken); + } + + public async Task> GetValues(T entry, string propertyName, CancellationToken cancellationToken) + { + IGBaseTable table = GetTable(); + if (table == null) + throw new Exception(); //TODO: Create exception + + return await table.GetValues(entry, propertyName, cancellationToken); + } + /// /// Dispose used resources asynchronously diff --git a/GBase/GBaseTable.cs b/GBase/GBaseTable.cs index 1bddadd..644e0fe 100644 --- a/GBase/GBaseTable.cs +++ b/GBase/GBaseTable.cs @@ -13,6 +13,8 @@ using GBase.Attributes; using GBase.Factories; using GBase.FileHandling.Factories; using GBase.Interfaces; +using GBase.Interfaces.DataHandling; +using GBase.Interfaces.DataHandling.Pool; using GBase.Interfaces.FileHandling; namespace GBase @@ -20,17 +22,22 @@ namespace GBase /// /// A table /// - public class GBaseTable : IGBaseTable where T : INotifyGBaseEntryChanged + public class GBaseTable : IGBaseTable { private readonly IFileHandler _fileHandler; + private readonly IDataHandlerPool _dataHandlerPool; private readonly IGBaseColumnFactory _gBaseColumnFactory; /// /// A table /// - public GBaseTable(IFileHandlerFactory fileHandlerFactory, IGBaseColumnFactory gBaseColumnFactory) + /// + /// The + /// + public GBaseTable(IFileHandlerFactory fileHandlerFactory, IDataHandlerPool dataHandlerPool, IGBaseColumnFactory gBaseColumnFactory) { _fileHandler = fileHandlerFactory.Create(); + _dataHandlerPool = dataHandlerPool; _gBaseColumnFactory = gBaseColumnFactory; Columns = new List(); @@ -123,9 +130,10 @@ namespace GBase public async Task AddEntry(T entry, CancellationToken cancellationToken) { Entries.Add(entry); - entry.GBaseEntryChanged += OnGBaseEntryChanged; - await _fileHandler.AddEntry(entry, this, cancellationToken); + using IGBaseFile file = _fileHandler.CreateEntryFile(entry, this); + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, cancellationToken); + await dataHandler.AddEntry(entry, this, file.File, cancellationToken); return true; } @@ -140,38 +148,30 @@ namespace GBase if (!Entries.Contains(entry)) return false; - entry.GBaseEntryChanged -= OnGBaseEntryChanged; - - await _fileHandler.RemoveEntry(entry); + await _fileHandler.DeleteEntryFile(entry); return Entries.Remove(entry); } - /// - /// Modify the property of a given entry with the given value - /// - /// The entry - /// The name of the property - /// The new value to set - /// True if successful, false if not - private bool ModifyEntry(object entry, string propertyName, object value) //TODO: Write to file + public async Task SetValue(T entry, string propertyName, TProperty value, CancellationToken cancellationToken) { - //don't need to change value of property in `Entries` list, the instance is saved there, any property change is already changed there as well - return true; + using IGBaseFile file = await _fileHandler.RequestEntryFile(entry); + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, CancellationToken.None); + await dataHandler.SetValue(file.File, propertyName, value, cancellationToken); } - /// - /// A entry changed - /// - /// The entry (sender) - /// The - private void OnGBaseEntryChanged(object entry, GBaseEntryChangedEventArgs args) + public async Task GetValue(T entry, string propertyName, CancellationToken cancellationToken) { - //TODO: Might change, depending on #23 - bool success = ModifyEntry(entry, args.ColumnName, args.Value); - - if (!success) - throw new Exception("Failed to handle EntryChanged"); //TODO: Decide what to do here + using IGBaseFile file = await _fileHandler.RequestEntryFile(entry); + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, CancellationToken.None); + return await dataHandler.GetValue(file.File, propertyName, cancellationToken); + } + + public async Task> GetValues(T entry, string propertyName, CancellationToken cancellationToken) + { + using IGBaseFile file = await _fileHandler.RequestEntryFile(entry); + IDataHandler dataHandler = await _dataHandlerPool.RequestDataHandler(this, false, CancellationToken.None); + return await dataHandler.GetValues(file.File, propertyName, cancellationToken); } /// @@ -181,6 +181,7 @@ namespace GBase public async ValueTask DisposeAsync() { await _fileHandler.DisposeAsync(); + await _dataHandlerPool.DisposeAsync(); foreach (var column in Columns) { diff --git a/GBase/Interfaces/IGBase.cs b/GBase/Interfaces/IGBase.cs index b49e0be..74b571c 100644 --- a/GBase/Interfaces/IGBase.cs +++ b/GBase/Interfaces/IGBase.cs @@ -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 @@ -49,7 +48,7 @@ namespace GBase.Interfaces /// True if successful, false if not bool AddTable(IGBaseTable table); - IGBaseTable GetTable() where T : INotifyGBaseEntryChanged; + IGBaseTable GetTable(); /// /// Removes a given from this @@ -58,6 +57,10 @@ namespace GBase.Interfaces /// True if successful, false if not bool RemoveTable(IGBaseTable table); - Task AddEntry(T entry, CancellationToken cancellationToken) where T : INotifyGBaseEntryChanged; + Task AddEntry(T entry, CancellationToken cancellationToken); + + Task SetValue(T entry, string propertyName, TProperty value, CancellationToken cancellationToken); + Task GetValue(T entry, string propertyName, CancellationToken cancellationToken); + Task> GetValues(T entry, string propertyName, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/GBase/Interfaces/IGBaseTable.cs b/GBase/Interfaces/IGBaseTable.cs index ca18623..277c1c5 100644 --- a/GBase/Interfaces/IGBaseTable.cs +++ b/GBase/Interfaces/IGBaseTable.cs @@ -10,7 +10,7 @@ using GBase.Api; namespace GBase.Interfaces { - public interface IGBaseTable : IGBaseTable where T : INotifyGBaseEntryChanged + public interface IGBaseTable : IGBaseTable { /// /// The entries of this @@ -34,6 +34,12 @@ namespace GBase.Interfaces /// The entry implementing /// True if successful, false if not Task RemoveEntry(T entry); + + Task SetValue(T entry, string propertyName, TProperty value, CancellationToken cancellationToken); + + Task GetValue(T entry, string propertyName, CancellationToken cancellationToken); + + Task> GetValues(T entry, string propertyName, CancellationToken cancellationToken); } /// From 92c278319e572d0c0c94a073d042ad64a8c3be77 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 15:31:00 +0100 Subject: [PATCH 33/46] #25: use MissingTableException instead of default exception --- GBase/Exceptions/MissingTableException.cs | 13 ++++--------- GBase/GBase.cs | 7 ++++--- GBase/GBaseObject.cs | 4 ++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/GBase/Exceptions/MissingTableException.cs b/GBase/Exceptions/MissingTableException.cs index 1d6015b..78af97c 100644 --- a/GBase/Exceptions/MissingTableException.cs +++ b/GBase/Exceptions/MissingTableException.cs @@ -9,20 +9,15 @@ namespace GBase.Exceptions /// /// that the table for the given is missing /// - public class MissingTableException : Exception + public class MissingTableException : Exception { /// /// that the table for the given is missing /// - public MissingTableException(Type type) - : base($"There is no table for type {type}.") + public MissingTableException() + : base($"There is no table for type {typeof(T)}.") { - Type = type; + } - - /// - /// The that has no table - /// - public Type Type { get; } } } \ No newline at end of file diff --git a/GBase/GBase.cs b/GBase/GBase.cs index 56ad1c0..3e43512 100644 --- a/GBase/GBase.cs +++ b/GBase/GBase.cs @@ -9,6 +9,7 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; using GBase.Attributes; +using GBase.Exceptions; using GBase.Factories; using GBase.Interfaces; using GBase.Interfaces.Settings; @@ -121,7 +122,7 @@ namespace GBase { IGBaseTable table = GetTable(); if (table == null) - throw new Exception(); //TODO: Create exception + throw new MissingTableException(); return await table.AddEntry(entry, cancellationToken); } @@ -130,7 +131,7 @@ namespace GBase { IGBaseTable table = GetTable(); if (table == null) - throw new Exception(); //TODO: Create exception + throw new MissingTableException(); await table.SetValue(entry, propertyName, value, cancellationToken); } @@ -139,7 +140,7 @@ namespace GBase { IGBaseTable table = GetTable(); if (table == null) - throw new Exception(); //TODO: Create exception + throw new MissingTableException(); return await table.GetValue(entry, propertyName, cancellationToken); } diff --git a/GBase/GBaseObject.cs b/GBase/GBaseObject.cs index 5ff272e..44af228 100644 --- a/GBase/GBaseObject.cs +++ b/GBase/GBaseObject.cs @@ -20,12 +20,12 @@ namespace GBase /// /// GBase object that allows conversion from /// - /// No table for is existing + /// No table for is existing protected GBaseObject(IGBase gBase) { _gBaseTable = gBase.GetTable(); if (_gBaseTable == null) - throw new MissingTableException(typeof(T)); + throw new MissingTableException(); } From 0a8c1aa549682555d41be0815406e72d3203412b Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 15:41:18 +0100 Subject: [PATCH 34/46] #25: use new methods from IGBaseTable --- GBase/GBaseObject.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/GBase/GBaseObject.cs b/GBase/GBaseObject.cs index 44af228..99b3c69 100644 --- a/GBase/GBaseObject.cs +++ b/GBase/GBaseObject.cs @@ -3,7 +3,9 @@ // Copyright(c) 2020 SimonG. All Rights Reserved. using System; -using System.Linq; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using GBase.Api; using GBase.Exceptions; using GBase.Interfaces; @@ -13,9 +15,9 @@ namespace GBase /// /// GBase object that supplies inheriting classes with methods to get data from a /// - public abstract class GBaseObject : IGBaseObject where T : INotifyGBaseEntryChanged + public abstract class GBaseObject : IGBaseObject { - private readonly IGBaseTable _gBaseTable; + private readonly IGBaseTable _gBaseTable; /// /// GBase object that allows conversion from @@ -28,12 +30,14 @@ namespace GBase throw new MissingTableException(); } + protected async Task SetValue(T @this, string propertyName, TProperty value, CancellationToken cancellationToken) => + await _gBaseTable.SetValue(@this, propertyName, value, cancellationToken); - protected TProperty Get() - { - throw new NotImplementedException(); - //_gBaseTable.GetEntry() - } + protected async Task GetValue(T @this, string propertyName, CancellationToken cancellationToken) => + await _gBaseTable.GetValue(@this, propertyName, cancellationToken); + + protected async Task> GetValues(T @this, string propertyName, CancellationToken cancellationToken) => + await _gBaseTable.GetValues(@this, propertyName, cancellationToken); /// /// Initialize this from a given From 5d0e766a7697b59b193268c1c391543d2ebe11ba Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 15:43:24 +0100 Subject: [PATCH 35/46] #25: remove unused using --- GBase/GBaseObject.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/GBase/GBaseObject.cs b/GBase/GBaseObject.cs index 99b3c69..2711bed 100644 --- a/GBase/GBaseObject.cs +++ b/GBase/GBaseObject.cs @@ -2,7 +2,6 @@ // Created: 2020-09-18 // Copyright(c) 2020 SimonG. All Rights Reserved. -using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; From bfda73950a8f16c337ab7cc78d7ed1754e777fc9 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 15:45:18 +0100 Subject: [PATCH 36/46] #25: fix factories and ctors --- GBase/DataHandling/Factories/IDataHandlerFactory.cs | 2 +- GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs | 2 +- GBase/DataHandling/Factories/IXmlDataReaderFactory.cs | 3 +-- GBase/DataHandling/XmlDataHandler.cs | 5 ++--- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/GBase/DataHandling/Factories/IDataHandlerFactory.cs b/GBase/DataHandling/Factories/IDataHandlerFactory.cs index d2b8515..2d0413d 100644 --- a/GBase/DataHandling/Factories/IDataHandlerFactory.cs +++ b/GBase/DataHandling/Factories/IDataHandlerFactory.cs @@ -8,6 +8,6 @@ namespace GBase.DataHandling.Factories { public interface IDataHandlerFactory { - IDataHandler Create(); //TODO: Add correct parameters + IDataHandler Create(); } } \ No newline at end of file diff --git a/GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs b/GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs index 7d4bac7..7b416c9 100644 --- a/GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs +++ b/GBase/DataHandling/Factories/IXmlDataHandlerFactory.cs @@ -15,6 +15,6 @@ namespace GBase.DataHandling.Factories /// Creates an /// /// A newly created instance of the implementation for - IXmlDataHandler Create(); //TODO: Add correct parameters + IXmlDataHandler Create(); } } \ No newline at end of file diff --git a/GBase/DataHandling/Factories/IXmlDataReaderFactory.cs b/GBase/DataHandling/Factories/IXmlDataReaderFactory.cs index 3670de9..ad11818 100644 --- a/GBase/DataHandling/Factories/IXmlDataReaderFactory.cs +++ b/GBase/DataHandling/Factories/IXmlDataReaderFactory.cs @@ -14,8 +14,7 @@ namespace GBase.DataHandling.Factories /// /// Creates an /// - /// The path to the xml file /// A newly created instance of the implementation for - IXmlDataReader Create(string path); + IXmlDataReader Create(); } } \ No newline at end of file diff --git a/GBase/DataHandling/XmlDataHandler.cs b/GBase/DataHandling/XmlDataHandler.cs index 64c2901..34948f6 100644 --- a/GBase/DataHandling/XmlDataHandler.cs +++ b/GBase/DataHandling/XmlDataHandler.cs @@ -52,13 +52,12 @@ namespace GBase.DataHandling /// The factory /// The factory /// The factory - public XmlDataHandler(string path, - IXmlDataReaderFactory xmlDataReaderFactory, + public XmlDataHandler(IXmlDataReaderFactory xmlDataReaderFactory, IXmlDataWriterFactory xmlDataWriterFactory, IXmlDataHandlerCacheFactory xmlDataHandlerCacheFactory) { _xmlDataWriter = xmlDataWriterFactory.Create(); - _xmlDataReader = xmlDataReaderFactory.Create(path); + _xmlDataReader = xmlDataReaderFactory.Create(); _cache = xmlDataHandlerCacheFactory.Create(_xmlDataReader); } From 3f891b45c9873bacedfe4ff4b00d6339fd22af55 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 16:08:41 +0100 Subject: [PATCH 37/46] #25: fix tests --- .../XmlDataHandlerLocalIntegrationTest.cs | 22 +-- Test.GBase/DataHandling/XmlDataHandlerTest.cs | 143 +++++------------- Test.GBase/GBaseTableIntegrationTest.cs | 13 +- 3 files changed, 60 insertions(+), 118 deletions(-) diff --git a/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs b/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs index 0b56644..db09cfc 100644 --- a/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs +++ b/Test.GBase/DataHandling/XmlDataHandlerLocalIntegrationTest.cs @@ -3,6 +3,7 @@ // Copyright(c) 2020 SimonG. All Rights Reserved. using System; +using System.IO; using System.Threading; using System.Threading.Tasks; using GBase.DataHandling; @@ -31,8 +32,8 @@ namespace Test.GBase.DataHandling .Returns(new XmlDataWriter()); Mock dataReaderFactoryMock = new Mock(); - dataReaderFactoryMock.Setup(r => r.Create(It.IsAny())) - .Returns((string path) => new XmlDataReader(path)); + dataReaderFactoryMock.Setup(r => r.Create()) + .Returns(new XmlDataReader()); Mock dataHandlerCachePropertyEntryFactoryMock = new Mock(); dataHandlerCachePropertyEntryFactoryMock.Setup(p => p.Create(It.IsAny(), It.IsAny())) @@ -48,21 +49,22 @@ namespace Test.GBase.DataHandling .Returns((IXmlDataReader xmlDataReader) => new XmlDataHandlerCache(xmlDataReader, dataHandlerCacheEntryFactoryMock.Object, dataHandlerCachePropertyEntryFactoryMock.Object)); - IXmlDataHandler xmlDataHandler = new XmlDataHandler("TestXml.xml", dataReaderFactoryMock.Object, dataWriterFactoryMock.Object, - dataHandlerCacheFactoryMock.Object); + IXmlDataHandler xmlDataHandler = new XmlDataHandler(dataReaderFactoryMock.Object, dataWriterFactoryMock.Object, dataHandlerCacheFactoryMock.Object); - await xmlDataHandler.Init(false, new CancellationToken()); - // + xmlDataHandler.Init(false); + + FileStream file = null; //FixMe: init this correctly if you want to run this test + //await xmlDataHandler.SetValue(nameof(TestProperty), TestProperty); //await xmlDataHandler.SetValue(nameof(TestProperty), "empty"); - await xmlDataHandler.SetValue(TODO, nameof(TestProperty), "test", TODO); + await xmlDataHandler.SetValue(file, nameof(TestProperty), "test", new CancellationToken()); //await xmlDataHandler.SetValue(nameof(TestProperty), "OverwrittenString"); // - await xmlDataHandler.SetValue(TODO, nameof(TestInt), 1, TODO); + await xmlDataHandler.SetValue(file, nameof(TestInt), 1, new CancellationToken()); //await xmlDataHandler.SetValue(nameof(TestInt), 2); //await xmlDataHandler.SetValue(nameof(TestInt), 3); - TestProperty = await xmlDataHandler.GetValue(nameof(TestProperty)); - TestInt = await xmlDataHandler.GetValue(nameof(TestInt)); + TestProperty = await xmlDataHandler.GetValue(file, nameof(TestProperty), new CancellationToken()); + TestInt = await xmlDataHandler.GetValue(file, nameof(TestInt), new CancellationToken()); } } } \ No newline at end of file diff --git a/Test.GBase/DataHandling/XmlDataHandlerTest.cs b/Test.GBase/DataHandling/XmlDataHandlerTest.cs index b8d9384..475d5b8 100644 --- a/Test.GBase/DataHandling/XmlDataHandlerTest.cs +++ b/Test.GBase/DataHandling/XmlDataHandlerTest.cs @@ -19,42 +19,13 @@ namespace Test.GBase.DataHandling public class XmlDataHandlerTest { [Test] - public async Task TestInit() + public void TestInit() { Mock xmlDataReaderMock = new Mock(); - xmlDataReaderMock.Setup(r => r.Init(It.IsAny())).ReturnsAsync(true); - - Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); - - Mock xmlDataWriterMock = new Mock(); - xmlDataWriterMock.Setup(w => w.InitFile(TODO, TODO, It.IsAny())).ReturnsAsync(true); - - Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); - - Mock xmlDataHandlerCacheMock = new Mock(); - Mock xmlDataHandlerCacheFactoryMock = new Mock(); - xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - - Assert.True(await xmlDataHandler.Init(false, CancellationToken.None)); - } - - [Test] - public async Task TestInitFailedTriedTwice() - { - Mock xmlDataReaderMock = new Mock(); - xmlDataReaderMock.Setup(r => r.Init(It.IsAny())).ReturnsAsync(true); - Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); - xmlDataWriterMock.Setup(w => w.InitFile(TODO, TODO, It.IsAny())).ReturnsAsync(true); - Mock xmlDataWriterFactoryMock = new Mock(); xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); @@ -62,50 +33,20 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - Assert.True(await xmlDataHandler.Init(false, CancellationToken.None)); - Assert.False(await xmlDataHandler.Init(false, CancellationToken.None)); + Assert.True(xmlDataHandler.Init(false)); } [Test] - public async Task TestInitFailedInitReaderFailed() + public void TestInitFailedTriedTwice() { Mock xmlDataReaderMock = new Mock(); - xmlDataReaderMock.Setup(r => r.Init(It.IsAny())).ReturnsAsync(false); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); - xmlDataWriterMock.Setup(w => w.InitFile(TODO, TODO, It.IsAny())).ReturnsAsync(true); - - Mock xmlDataWriterFactoryMock = new Mock(); - xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); - - Mock xmlDataHandlerCacheMock = new Mock(); - Mock xmlDataHandlerCacheFactoryMock = new Mock(); - xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - - Assert.False(await xmlDataHandler.Init(false, CancellationToken.None)); - } - - [Test] - public async Task TestInitFailedInitWriterFailed() - { - Mock xmlDataReaderMock = new Mock(); - xmlDataReaderMock.Setup(r => r.Init(It.IsAny())).ReturnsAsync(true); - - Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); - - Mock xmlDataWriterMock = new Mock(); - xmlDataWriterMock.Setup(w => w.InitFile(TODO, TODO, It.IsAny())).ReturnsAsync(false); - Mock xmlDataWriterFactoryMock = new Mock(); xmlDataWriterFactoryMock.Setup(w => w.Create()).Returns(xmlDataWriterMock.Object); @@ -113,10 +54,10 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - Assert.False(await xmlDataHandler.Init(false, CancellationToken.None)); + Assert.True(xmlDataHandler.Init(false)); + Assert.False(xmlDataHandler.Init(false)); } [Test] @@ -124,7 +65,7 @@ namespace Test.GBase.DataHandling { Mock xmlDataReaderMock = new Mock(); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); @@ -134,13 +75,12 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - await xmlDataHandler.SetValue(TODO, "property", "SomeString", TODO); + await xmlDataHandler.SetValue(null, "property", "SomeString", new CancellationToken()); xmlDataHandlerCacheMock.Verify(c => c.SetValue("property", "SomeString", false), Times.Once); - xmlDataWriterMock.Verify(w => w.Write(TODO, "property", "SomeString", TODO, false, TODO), Times.Once); + xmlDataWriterMock.Verify(w => w.Write(null, "property", "SomeString", false, It.IsAny()), Times.Once); } [Test] @@ -148,7 +88,7 @@ namespace Test.GBase.DataHandling { Mock xmlDataReaderMock = new Mock(); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); @@ -158,14 +98,13 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); List stringList = new List() {"string", "secondString", "thirdString"}; - await xmlDataHandler.SetValue>(TODO, "property", stringList, TODO); + await xmlDataHandler.SetValue>(null, "property", stringList, new CancellationToken()); xmlDataHandlerCacheMock.Verify(c => c.SetValue>("property", stringList, false), Times.Once); - xmlDataWriterMock.Verify(w => w.Write>(TODO, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", TODO, false, TODO), Times.Once); + xmlDataWriterMock.Verify(w => w.Write>(null, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}",false, It.IsAny()), Times.Once); } [Test] @@ -173,7 +112,7 @@ namespace Test.GBase.DataHandling { Mock xmlDataReaderMock = new Mock(); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); @@ -183,13 +122,12 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - await xmlDataHandler.SetValue(TODO, "property", null, TODO); + await xmlDataHandler.SetValue(null, "property", null, new CancellationToken()); xmlDataHandlerCacheMock.Verify(c => c.SetValue(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - xmlDataWriterMock.Verify(w => w.Write(TODO, It.IsAny(), It.IsAny(), TODO, It.IsAny(), TODO), Times.Never); + xmlDataWriterMock.Verify(w => w.Write(null, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); } [Test] @@ -197,7 +135,7 @@ namespace Test.GBase.DataHandling { Mock xmlDataReaderMock = new Mock(); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); @@ -207,13 +145,12 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - await xmlDataHandler.RemoveValue(TODO, "property", "SomeString", TODO); + await xmlDataHandler.RemoveValue(null, "property", "SomeString", new CancellationToken()); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue("property", "SomeString"), Times.Once); - xmlDataWriterMock.Verify(w => w.Remove(TODO, "property", "SomeString", TODO), Times.Once); + xmlDataWriterMock.Verify(w => w.Remove(null, "property", "SomeString", It.IsAny()), Times.Once); } [Test] @@ -221,7 +158,7 @@ namespace Test.GBase.DataHandling { Mock xmlDataReaderMock = new Mock(); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); @@ -231,14 +168,13 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); List stringList = new List() { "string", "secondString", "thirdString" }; - await xmlDataHandler.RemoveValue>(TODO, "property", stringList, TODO); + await xmlDataHandler.RemoveValue>(null, "property", stringList, new CancellationToken()); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue>("property", stringList), Times.Once); - xmlDataWriterMock.Verify(w => w.Remove>(TODO, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", TODO), Times.Once); + xmlDataWriterMock.Verify(w => w.Remove>(null, "property", $"{stringList[0]},{stringList[1]},{stringList[2]}", It.IsAny()), Times.Once); } [Test] @@ -246,7 +182,7 @@ namespace Test.GBase.DataHandling { Mock xmlDataReaderMock = new Mock(); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); @@ -256,13 +192,12 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - await xmlDataHandler.RemoveValue(TODO, "property", null, TODO); + await xmlDataHandler.RemoveValue(null, "property", null, new CancellationToken()); xmlDataHandlerCacheMock.Verify(c => c.TryRemoveValue(It.IsAny(), It.IsAny()), Times.Never); - xmlDataWriterMock.Verify(w => w.Remove(TODO, It.IsAny(), It.IsAny(), TODO), Times.Never); + xmlDataWriterMock.Verify(w => w.Remove(null, It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); } [Test] @@ -274,7 +209,7 @@ namespace Test.GBase.DataHandling //xmlDataReaderMock.Setup(r => r.Read("property")).ReturnsAsync>(values); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); @@ -284,8 +219,7 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); } [Test] @@ -297,7 +231,7 @@ namespace Test.GBase.DataHandling //xmlDataReaderMock.Setup(r => r.Read("property")).ReturnsAsync>(values); Mock xmlDataReaderFactoryMock = new Mock(); - xmlDataReaderFactoryMock.Setup(r => r.Create(It.IsAny())).Returns(xmlDataReaderMock.Object); + xmlDataReaderFactoryMock.Setup(r => r.Create()).Returns(xmlDataReaderMock.Object); Mock xmlDataWriterMock = new Mock(); Mock xmlDataWriterFactoryMock = new Mock(); @@ -307,10 +241,9 @@ namespace Test.GBase.DataHandling Mock xmlDataHandlerCacheFactoryMock = new Mock(); xmlDataHandlerCacheFactoryMock.Setup(c => c.Create(It.IsAny())).Returns(xmlDataHandlerCacheMock.Object); - XmlDataHandler xmlDataHandler = new XmlDataHandler("path", xmlDataReaderFactoryMock.Object, - xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); + XmlDataHandler xmlDataHandler = new XmlDataHandler(xmlDataReaderFactoryMock.Object, xmlDataWriterFactoryMock.Object, xmlDataHandlerCacheFactoryMock.Object); - IEnumerable> readValues = await xmlDataHandler.GetValues>("property"); + IEnumerable> readValues = await xmlDataHandler.GetValues>(null, "property", new CancellationToken()); } } } \ No newline at end of file diff --git a/Test.GBase/GBaseTableIntegrationTest.cs b/Test.GBase/GBaseTableIntegrationTest.cs index 0bb97ff..692f4d9 100644 --- a/Test.GBase/GBaseTableIntegrationTest.cs +++ b/Test.GBase/GBaseTableIntegrationTest.cs @@ -4,9 +4,11 @@ using System.Threading; using GBase; +using GBase.DataHandling.Pool; using GBase.Factories; using GBase.FileHandling.Factories; using GBase.Interfaces; +using GBase.Interfaces.DataHandling.Pool; using GBase.Interfaces.FileHandling; using Moq; using NUnit.Framework; @@ -22,11 +24,16 @@ namespace Test.GBase { Mock fileHandlerFactoryMock = new Mock(); fileHandlerFactoryMock.Setup(f => f.Create()).Returns(new Mock().Object); - + + IGBaseColumn gBaseColumn = null; Mock gBaseColumnFactoryMock = new Mock(); - gBaseColumnFactoryMock.Setup(c => c.Create()).Returns(new GBaseColumn()); + gBaseColumnFactoryMock.Setup(c => c.Create(It.IsAny())) + .Callback(name => { gBaseColumn = new GBaseColumn(name); }) + .Returns(gBaseColumn); - IGBaseTable table = new GBaseTable(fileHandlerFactoryMock.Object, gBaseColumnFactoryMock.Object); + Mock dataHandlerPoolMock = new Mock(); + + IGBaseTable table = new GBaseTable(fileHandlerFactoryMock.Object, dataHandlerPoolMock.Object, gBaseColumnFactoryMock.Object); table.Init(typeof(Foo), "", "", CancellationToken.None); CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); From 7b97b75fb6778388ba557dec2e7989d7dbb6d656 Mon Sep 17 00:00:00 2001 From: Simon G Date: Tue, 10 Nov 2020 16:08:57 +0100 Subject: [PATCH 38/46] #25: update xml --- GBase/GBase.xml | 291 +++++++++++++++++------------------------------- 1 file changed, 100 insertions(+), 191 deletions(-) diff --git a/GBase/GBase.xml b/GBase/GBase.xml index ded0749..55dd771 100644 --- a/GBase/GBase.xml +++ b/GBase/GBase.xml @@ -87,13 +87,15 @@ The value to set A to await - + Try to get values from the cache for the given property The that implements the property The of the property + The name of the property + An with all the values for the property @@ -163,11 +165,10 @@ Factory for the - + Creates an - The path to the xml file A newly created instance of the implementation for @@ -175,12 +176,10 @@ Factory for the - + Creates an - The path to the xml file - The root element name of the xml file A newly created instance of the implementation for @@ -198,152 +197,142 @@ The attribute name of the value attribute - + A that handles its data in an xml file The path to the xml file - The root element name of the xml file The factory The factory The factory - + Initialize the If true an existing value is overwritten, if false an additional value is added - A to cancel the async operation Returns true if successful, false if not - + Set the value for the given property The that implements the property The of the property + The name of the property The value to set + A to await - + Remove the value for the given property The of the property The of the property + The name of the property The value to set + A to await - + Get the value for the given property, if multiple values are set the first is returned The that implements the property The of the property + The name of the property + The value for the given property - + Get all the values that are set for the given property The that implements the property The of the property + The name of the property + An with all the values for the property - - - Dispose used resources asynchronously - - A to await - A that reads from a xml file - - - A that reads from a xml file - - The path to the xml file - - - - Initialize the - - A to cancel the async operation - Returns true if successful, false if not - No root element found - - + Read the data of a property The The of the property + The name of the property + The data of the given property, null if no data found Invalid found for the read object - - - Dispose used resources asynchronously - - A to await - A that writes to a xml file - - - A that writes to an xml file - - The path to the xml file - The root element name of the xml file - - + Initialize the + + A to cancel the async operation Returns true if successful, false if not No root element found - + Write the data of a property - The that implements the property + The The of the property + The name of the property The value of the property If true an existing value is overwritten, if false an additional value is added + + A to await + + + + Write the data of a property + + The that implements the property + + The name of the property + The value of the property + + If true an existing value is overwritten, if false an additional value is added + A to await + No root element is set - + Remove the value for the given property The of the property The of the property + The name of the property The value to set + A to await - - - - Dispose used resources asynchronously - - A to await + No root element is set @@ -372,19 +361,14 @@ The table type - + - that the table for the given is missing + that the table for the given is missing - + - that the table for the given is missing - - - - - The that has no table + that the table for the given is missing @@ -410,7 +394,7 @@ Factory for the - + Creates an @@ -460,11 +444,10 @@ The file extension for all GBase tables - + Internal file handler - The @@ -474,48 +457,6 @@ A to cancel the asynchronous operation True if successful, false if not - - - Set the value for the given property - - The of the property - The of the property - The name of the property - The value to set - - A to await - - - - Remove the value for the given property - - The of the property - The of the property - The name of the property - The value to set - - A to await - - - - Get the value for the given property, if multiple values are set the first is returned - - The of the property - The of the property - The name of the property - - The value for the given property - - - - Get all the values that are set for the given property - - The of the property - The of the property - The name of the property - - An with all the values for the property - Dispose used resources asynchronously @@ -583,7 +524,7 @@ A column of a - + A column of a @@ -603,7 +544,7 @@ GBase object that allows conversion from - No table for is existing + No table for is existing @@ -616,10 +557,13 @@ A table - + A table + + The + @@ -680,22 +624,6 @@ The entry implementing True if successful, false if not - - - Modify the property of a given entry with the given value - - The entry - The name of the property - The new value to set - True if successful, false if not - - - - A entry changed - - The entry (sender) - The - The method @@ -768,13 +696,15 @@ The value to set A to await - + Try to get values from the cache for the given property The that implements the property The of the property + The name of the property + An with all the values for the property @@ -817,50 +747,57 @@ Interface for data handlers to implement - + Initialize the If true an existing value is overwritten, if false an additional value is added - A to cancel the async operation Returns true if successful, false if not - + Set the value for the given property The of the property The of the property + The name of the property The value to set + A to await - + Remove the value for the given property The of the property The of the property + The name of the property The value to set + A to await - + Get the value for the given property, if multiple values are set the first is returned The of the property The of the property + The name of the property + The value for the given property - + Get all the values that are set for the given property The of the property The of the property + The name of the property + An with all the values for the property @@ -868,20 +805,15 @@ Interface for data readers to implement - - - Initialize the - - A to cancel the async operation - Returns true if successful, false if not - - + Read the data of a property The The of the property + The name of the property + The data of the given property, null if no data found @@ -889,32 +821,51 @@ Interface for data writers to implement - + Initialize the + + A to cancel the async operation Returns true if successful, false if not - + Write the data of a property The The of the property + The name of the property The value of the property If true an existing value is overwritten, if false an additional value is added + A to await - + + + Write the data of a property + + The + + The name of the property + The value of the property + + If true an existing value is overwritten, if false an additional value is added + + A to await + + Remove the value for the given property The of the property The of the property + The name of the property The value to set + A to await @@ -960,48 +911,6 @@ A to cancel the asynchronous operation True if successful, false if not - - - Set the value for the given property - - The of the property - The of the property - The name of the property - The value to set - - A to await - - - - Remove the value for the given property - - The of the property - The of the property - The name of the property - The value to set - - A to await - - - - Get the value for the given property, if multiple values are set the first is returned - - The of the property - The of the property - The name of the property - - The value for the given property - - - - Get all the values that are set for the given property - - The of the property - The of the property - The name of the property - - An with all the values for the property - The base class of the GBase database From 0c334463eecf3ce1f4725960a0c4d39589f94de6 Mon Sep 17 00:00:00 2001 From: Simon G Date: Wed, 11 Nov 2020 13:05:20 +0100 Subject: [PATCH 39/46] remove unused code --- Test.GBase/GBaseIntegrationTest/Model.cs | 2 +- Test.GBase/GBaseTableIntegrationTest.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Test.GBase/GBaseIntegrationTest/Model.cs b/Test.GBase/GBaseIntegrationTest/Model.cs index dc8f9de..31d6e1a 100644 --- a/Test.GBase/GBaseIntegrationTest/Model.cs +++ b/Test.GBase/GBaseIntegrationTest/Model.cs @@ -45,7 +45,7 @@ namespace Test.GBase.GBaseIntegrationTest public async Task AddGroup(IGroup group, CancellationToken cancellationToken) { Groups.Add(group); - await _gBase.AddEntry(@group, cancellationToken); + await _gBase.AddEntry(group, cancellationToken); } } } \ No newline at end of file diff --git a/Test.GBase/GBaseTableIntegrationTest.cs b/Test.GBase/GBaseTableIntegrationTest.cs index 692f4d9..cf69136 100644 --- a/Test.GBase/GBaseTableIntegrationTest.cs +++ b/Test.GBase/GBaseTableIntegrationTest.cs @@ -4,7 +4,6 @@ using System.Threading; using GBase; -using GBase.DataHandling.Pool; using GBase.Factories; using GBase.FileHandling.Factories; using GBase.Interfaces; From 62f18c0038fda527c77fc516552b93968b8f6874 Mon Sep 17 00:00:00 2001 From: Simon G Date: Wed, 11 Nov 2020 13:09:39 +0100 Subject: [PATCH 40/46] #25: remove need to inherit INotifyGBaseEntryChanged --- GBase/Factories/GBaseTableFactory.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/GBase/Factories/GBaseTableFactory.cs b/GBase/Factories/GBaseTableFactory.cs index 70d3062..aa23703 100644 --- a/GBase/Factories/GBaseTableFactory.cs +++ b/GBase/Factories/GBaseTableFactory.cs @@ -36,9 +36,6 @@ namespace GBase.Factories /// A newly created instance of the implementation for public IGBaseTable Create(Type type) { - if (!typeof(INotifyGBaseEntryChanged).IsAssignableFrom(type)) - throw new InvalidTableTypeException(type); - Type gBaseTableType = typeof(GBaseTable<>).MakeGenericType(type); return (IGBaseTable) Activator.CreateInstance(gBaseTableType, _fileHandlerFactory, _gBaseColumnFactory); } From c4ed254aac15df60ce7bbd0d5272858713be43aa Mon Sep 17 00:00:00 2001 From: Simon G Date: Wed, 11 Nov 2020 14:05:20 +0100 Subject: [PATCH 41/46] #25: add dataHandlerPool to factory --- GBase/Factories/GBaseTableFactory.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/GBase/Factories/GBaseTableFactory.cs b/GBase/Factories/GBaseTableFactory.cs index aa23703..d20772d 100644 --- a/GBase/Factories/GBaseTableFactory.cs +++ b/GBase/Factories/GBaseTableFactory.cs @@ -3,10 +3,9 @@ // Copyright(c) 2020 SimonG. All Rights Reserved. using System; -using GBase.Api; -using GBase.Exceptions; using GBase.FileHandling.Factories; using GBase.Interfaces; +using GBase.Interfaces.DataHandling.Pool; using GBase.Interfaces.FileHandling; namespace GBase.Factories @@ -17,16 +16,19 @@ namespace GBase.Factories public class GBaseTableFactory : IGBaseTableFactory { private readonly IFileHandlerFactory _fileHandlerFactory; + private readonly IDataHandlerPool _dataHandlerPool; private readonly IGBaseColumnFactory _gBaseColumnFactory; /// /// Factory for the /// /// Factory for the + /// /// Factory for the - public GBaseTableFactory(IFileHandlerFactory fileHandlerFactory, IGBaseColumnFactory gBaseColumnFactory) + public GBaseTableFactory(IFileHandlerFactory fileHandlerFactory, IDataHandlerPool dataHandlerPool, IGBaseColumnFactory gBaseColumnFactory) { _fileHandlerFactory = fileHandlerFactory; + _dataHandlerPool = dataHandlerPool; _gBaseColumnFactory = gBaseColumnFactory; } @@ -37,7 +39,7 @@ namespace GBase.Factories public IGBaseTable Create(Type type) { Type gBaseTableType = typeof(GBaseTable<>).MakeGenericType(type); - return (IGBaseTable) Activator.CreateInstance(gBaseTableType, _fileHandlerFactory, _gBaseColumnFactory); + return (IGBaseTable) Activator.CreateInstance(gBaseTableType, _fileHandlerFactory, _dataHandlerPool, _gBaseColumnFactory); } } } \ No newline at end of file From b671d30d1d3797e8d2f3adb492bc06ff4a2495de Mon Sep 17 00:00:00 2001 From: Simon G Date: Wed, 11 Nov 2020 16:16:49 +0100 Subject: [PATCH 42/46] #25: add TODO: need to init existing files --- GBase/FileHandling/FileHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GBase/FileHandling/FileHandler.cs b/GBase/FileHandling/FileHandler.cs index 0e330ec..4e1d396 100644 --- a/GBase/FileHandling/FileHandler.cs +++ b/GBase/FileHandling/FileHandler.cs @@ -42,8 +42,8 @@ namespace GBase.FileHandling /// True if successful, false if not public async Task Init(string path, CancellationToken cancellationToken) { - _path = path; - return true; //TODO: is there anything that needs to be initialized here? + _path = path; + return true; //TODO: initialize existing files } public IGBaseFile CreateEntryFile(T entry, IGBaseTable table) From 1df5d492874743ab72583d984734b8cd9c3b5df5 Mon Sep 17 00:00:00 2001 From: Simon G Date: Wed, 11 Nov 2020 16:17:22 +0100 Subject: [PATCH 43/46] #25: throw missingTableException when getTable() doesn't find a matching table --- GBase/GBase.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/GBase/GBase.cs b/GBase/GBase.cs index 3e43512..eba244f 100644 --- a/GBase/GBase.cs +++ b/GBase/GBase.cs @@ -101,8 +101,9 @@ namespace GBase if (Tables.OfType>().Any()) return Tables.OfType>().First(); - //TODO: This probably doesn't work, because even though t.Type : T, IGBaseTable !: IGBaseTable - return (IGBaseTable) Tables.FirstOrDefault(t => typeof(T).IsAssignableFrom(t.Type)); //TestMe + throw new MissingTableException(); + // //TODO: This probably doesn't work, because even though t.Type : T, IGBaseTable !: IGBaseTable + // return (IGBaseTable) Convert.ChangeType(Tables.FirstOrDefault(t => typeof(T).IsAssignableFrom(t.Type)), typeof(IGBaseTable)); //TestMe } /// @@ -149,7 +150,7 @@ namespace GBase { IGBaseTable table = GetTable(); if (table == null) - throw new Exception(); //TODO: Create exception + throw new MissingTableException(); return await table.GetValues(entry, propertyName, cancellationToken); } From 225f10d1a097d48ff83fcc72ce0a493134f2fc66 Mon Sep 17 00:00:00 2001 From: Simon G Date: Wed, 11 Nov 2020 16:18:10 +0100 Subject: [PATCH 44/46] #25: return true if file isn't empty, think if bool return value makes sense here --- GBase/DataHandling/XmlDataWriter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GBase/DataHandling/XmlDataWriter.cs b/GBase/DataHandling/XmlDataWriter.cs index 4dce15d..31cfc74 100644 --- a/GBase/DataHandling/XmlDataWriter.cs +++ b/GBase/DataHandling/XmlDataWriter.cs @@ -31,7 +31,7 @@ namespace GBase.DataHandling { //if the xml file isn't empty, return if (file.Length > 3) //> 3 because of BOM - return false; + return true; //TODO: Don't return bool? XDocument xmlDocument = new XDocument(); xmlDocument.Add(new XElement(rootElementName)); @@ -74,6 +74,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 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 From 90242543c72be2f994df31bababd3fde5f862d4b Mon Sep 17 00:00:00 2001 From: Simon G Date: Wed, 11 Nov 2020 16:18:25 +0100 Subject: [PATCH 45/46] #25: adapt integration test --- .../GBaseIntegrationTest.cs | 56 +++++++++++++++++++ Test.GBase/GBaseIntegrationTest/Group.cs | 13 +++-- Test.GBase/GBaseIntegrationTest/IGroup.cs | 3 +- Test.GBase/GBaseIntegrationTest/IItem.cs | 5 +- Test.GBase/GBaseIntegrationTest/Item.cs | 23 +++++++- Test.GBase/GBaseIntegrationTest/Model.cs | 17 +++--- Test.GBase/GBaseIntegrationTest/Settings.cs | 4 +- 7 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 Test.GBase/GBaseIntegrationTest/GBaseIntegrationTest.cs diff --git a/Test.GBase/GBaseIntegrationTest/GBaseIntegrationTest.cs b/Test.GBase/GBaseIntegrationTest/GBaseIntegrationTest.cs new file mode 100644 index 0000000..50a8541 --- /dev/null +++ b/Test.GBase/GBaseIntegrationTest/GBaseIntegrationTest.cs @@ -0,0 +1,56 @@ +// Author: Gockner, Simon +// Created: 2020-11-11 +// Copyright(c) 2020 SimonG. All Rights Reserved. + +using System.Threading; +using System.Threading.Tasks; +using GBase.Factories; +using GBase.Installers; +using LightweightIocContainer; +using LightweightIocContainer.Interfaces; +using NUnit.Framework; + +namespace Test.GBase.GBaseIntegrationTest +{ + [TestFixture] + public class GBaseIntegrationTest + { + private CancellationTokenSource _cancellationTokenSource; + private IIocContainer _iocContainer; + + [SetUp] + public void SetUp() + { + _cancellationTokenSource = new CancellationTokenSource(); + + _iocContainer = new IocContainer(); + _iocContainer.Install(new GBaseInstaller(), + new DataHandlingInstaller(), + new FileHandlingInstaller()); + } + + [TearDown] + public void TearDown() + { + _cancellationTokenSource.Dispose(); + _iocContainer.Dispose(); + } + + [Test] + public async Task TestGBase() + { + IGBaseFactory gBaseFactory = _iocContainer.Resolve(); + Model model = new Model(gBaseFactory); + + await model.Initialize(_cancellationTokenSource.Token); + + await model.AddItem(new Item("Item 1", 1), _cancellationTokenSource.Token); + await model.AddItem(new Item("Item 2", 2), _cancellationTokenSource.Token); + await model.AddItem(new Item("Item 3", 3), _cancellationTokenSource.Token); + + await model.AddGroup(new Group(1), _cancellationTokenSource.Token); + await model.AddGroup(new Group(2), _cancellationTokenSource.Token); + await model.AddGroup(new Group(3), _cancellationTokenSource.Token); + } + } +} \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/Group.cs b/Test.GBase/GBaseIntegrationTest/Group.cs index 24a77de..b9587af 100644 --- a/Test.GBase/GBaseIntegrationTest/Group.cs +++ b/Test.GBase/GBaseIntegrationTest/Group.cs @@ -3,19 +3,24 @@ // Copyright(c) 2020 SimonG. All Rights Reserved. using System.Collections.Generic; -using GBase.Api; using GBase.Attributes; namespace Test.GBase.GBaseIntegrationTest { [GBaseTable("Groups")] - public class Group : NotifyGBaseEntryChanged, IGroup + public class Group : IGroup { - public Group() + public Group(int key) { + Key = key; Items = new List(); } - + + [GBaseColumn] + public int Key { get; private set; } public List Items { get; } + + public override string ToString() => $"{Key}"; + public void InitializeFromString(string @string) => Key = int.Parse(@string); } } \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/IGroup.cs b/Test.GBase/GBaseIntegrationTest/IGroup.cs index 966eac8..1957f03 100644 --- a/Test.GBase/GBaseIntegrationTest/IGroup.cs +++ b/Test.GBase/GBaseIntegrationTest/IGroup.cs @@ -7,8 +7,9 @@ using GBase.Api; namespace Test.GBase.GBaseIntegrationTest { - public interface IGroup : INotifyGBaseEntryChanged + public interface IGroup : IGBaseObject //: INotifyGBaseEntryChanged { + int Key { get; } List Items { get; } } } \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/IItem.cs b/Test.GBase/GBaseIntegrationTest/IItem.cs index 5d4fe77..8aaea05 100644 --- a/Test.GBase/GBaseIntegrationTest/IItem.cs +++ b/Test.GBase/GBaseIntegrationTest/IItem.cs @@ -6,8 +6,9 @@ using GBase.Api; namespace Test.GBase.GBaseIntegrationTest { - public interface IItem : INotifyGBaseEntryChanged + public interface IItem : IGBaseObject //: INotifyGBaseEntryChanged { - + string Name { get; } + int Key { get; } } } \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/Item.cs b/Test.GBase/GBaseIntegrationTest/Item.cs index 5eaecc7..e49acd8 100644 --- a/Test.GBase/GBaseIntegrationTest/Item.cs +++ b/Test.GBase/GBaseIntegrationTest/Item.cs @@ -2,14 +2,33 @@ // Created: 2020-09-18 // Copyright(c) 2020 SimonG. All Rights Reserved. -using GBase.Api; using GBase.Attributes; namespace Test.GBase.GBaseIntegrationTest { [GBaseTable("Items")] - public class Item : NotifyGBaseEntryChanged, IItem + public class Item : IItem { + public Item(string name, int key) + { + Name = name; + Key = key; + } + + [GBaseColumn] + public string Name { get; private set; } + [GBaseColumn] + public int Key { get; private set; } + + public override string ToString() => $"{Name}"; + + public void InitializeFromString(string @string) + { + string[] properties = @string.Split('/'); + + Key = int.Parse(properties[0]); + Name = properties[1]; + } } } \ No newline at end of file diff --git a/Test.GBase/GBaseIntegrationTest/Model.cs b/Test.GBase/GBaseIntegrationTest/Model.cs index 31d6e1a..0b608a7 100644 --- a/Test.GBase/GBaseIntegrationTest/Model.cs +++ b/Test.GBase/GBaseIntegrationTest/Model.cs @@ -3,6 +3,7 @@ // Copyright(c) 2020 SimonG. All Rights Reserved. using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -29,20 +30,22 @@ namespace Test.GBase.GBaseIntegrationTest { await _gBase.Init("DB", Assembly.GetExecutingAssembly(), cancellationToken); - IGBaseTable itemsTable = _gBase.GetTable(); - Items = itemsTable.Entries; - - IGBaseTable groupsTable = _gBase.GetTable(); - Groups = groupsTable.Entries; + // IGBaseTable itemsTable = _gBase.GetTable(); + // Items = itemsTable.Entries.Cast().ToList(); + Items = (await _gBase.GetValues(this, nameof(Items), cancellationToken)).Cast().ToList(); + + // IGBaseTable groupsTable = _gBase.GetTable(); + // Groups = groupsTable.Entries.Cast().ToList(); + Groups = (await _gBase.GetValues(this, nameof(Groups), cancellationToken)).Cast().ToList(); } - public async Task AddItem(IItem item, CancellationToken cancellationToken) + public async Task AddItem(Item item, CancellationToken cancellationToken) { Items.Add(item); await _gBase.AddEntry(item, cancellationToken); } - public async Task AddGroup(IGroup group, CancellationToken cancellationToken) + public async Task AddGroup(Group group, CancellationToken cancellationToken) { Groups.Add(group); await _gBase.AddEntry(group, cancellationToken); diff --git a/Test.GBase/GBaseIntegrationTest/Settings.cs b/Test.GBase/GBaseIntegrationTest/Settings.cs index 8335033..9040384 100644 --- a/Test.GBase/GBaseIntegrationTest/Settings.cs +++ b/Test.GBase/GBaseIntegrationTest/Settings.cs @@ -2,12 +2,14 @@ // Created: 2020-09-18 // Copyright(c) 2020 SimonG. All Rights Reserved. +using System; +using System.IO; using GBase.Interfaces.Settings; namespace Test.GBase.GBaseIntegrationTest { public class Settings : IGBaseSettings { - public string DatabasePath => ""; + public string DatabasePath => Path.Combine(Environment.CurrentDirectory, "DB"); } } \ No newline at end of file From 2897acbea06a37db517bda4102ba7e84c130b531 Mon Sep 17 00:00:00 2001 From: Simon G Date: Wed, 11 Nov 2020 16:18:35 +0100 Subject: [PATCH 46/46] #25: update xml --- GBase/GBase.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GBase/GBase.xml b/GBase/GBase.xml index 55dd771..d9641b4 100644 --- a/GBase/GBase.xml +++ b/GBase/GBase.xml @@ -376,11 +376,12 @@ Factory for the - + Factory for the Factory for the + Factory for the