diff --git a/Docs/SweetLib.Storage b/Docs/SweetLib.Storage
new file mode 100644
index 0000000..9256e24
--- /dev/null
+++ b/Docs/SweetLib.Storage
@@ -0,0 +1,112 @@
+
+
+
+ SweetLib.Storage
+
+
+
+
+ Provider for database connection.
+
+ Specific type of the database connection. Must inherit .
+
+
+
+ Gets an instance of a database connection.
+
+
+
+
+
+ Object to store in database.
+
+ Type of the used identifier.
+
+
+
+ Assigns field names of the database columns.
+
+
+
+
+
+ Assigns values to the query parameters.
+
+
+
+
+
+
+ Assigns values to the object.
+
+
+
+
+
+
+ Table name of the object.
+
+
+
+
+
+ Interface for identified objects.
+
+ Type of the identifier.
+
+
+
+ Identifier of the object.
+
+
+
+
+ Gets a dummy Id for unidentified instances;
+
+
+
+
+
+ Generates a new object id.
+
+ Type of the used identifier.
+
+
+
+ Generates a new id of the specified type.
+
+
+
+
+
+ Generates a new id of the specified type. Runs asynchronous.
+
+
+
+
+
+ Interface for objects which can be stored and restored.
+
+ Type of the used identifier.
+
+
+
+ Stores the object.
+
+
+
+
+
+ Restores an object.
+
+ Identifier of the object to restore.
+
+
+
+
+ Determines whether the current object instance is new or already exists.
+
+ Boolean indicating if the current object instance is new or already exists.
+
+
+
diff --git a/Docs/SweetLib.Storage.MySql b/Docs/SweetLib.Storage.MySql
new file mode 100644
index 0000000..1a3079d
--- /dev/null
+++ b/Docs/SweetLib.Storage.MySql
@@ -0,0 +1,8 @@
+
+
+
+ SweetLib.Storage.MySql
+
+
+
+
diff --git a/Docs/SweetLib.Storage.md b/Docs/SweetLib.Storage.md
new file mode 100644
index 0000000..5401267
--- /dev/null
+++ b/Docs/SweetLib.Storage.md
@@ -0,0 +1,7 @@
+
+# Contents [#](#contents 'Go To Here')
+
+
+
+
+# SweetLib.Storage.MySql [#](#assembly 'Go To Here') [=](#contents 'Back To Contents')
diff --git a/SweetLib.Storage.MySql/CustomMySqlObject.cs b/SweetLib.Storage.MySql/CustomMySqlObject.cs
new file mode 100644
index 0000000..2db43a2
--- /dev/null
+++ b/SweetLib.Storage.MySql/CustomMySqlObject.cs
@@ -0,0 +1,121 @@
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Linq;
+using System.Threading.Tasks;
+using MySql.Data.MySqlClient;
+using SweetLib.Storage.Database;
+using SweetLib.Storage.MySql.Helper;
+
+namespace SweetLib.Storage.MySql;
+
+public abstract class CustomMySqlObject : IDatabaseObject
+{
+ protected CustomMySqlObject(IConnectionProvider connectionProvider,
+ IIdGenerator idGenerator)
+ {
+ ConnectionProvider = connectionProvider;
+ IdGenerator = idGenerator;
+ Id = UnidentifiedId();
+ }
+
+ protected IConnectionProvider ConnectionProvider { get; }
+ protected IIdGenerator IdGenerator { get; }
+
+ public T Id { get; set; }
+ public abstract T UnidentifiedId();
+
+ public async Task Store()
+ {
+ var wasNew = IsNew();
+
+ var connection = ConnectionProvider!.GetConnection();
+ await connection.OpenAsync();
+ try
+ {
+ var command = connection.CreateCommand();
+ try
+ {
+ command.CommandText = wasNew ? InsertCommand() : UpdateCommand();
+ await AssignToAsync(command.Parameters);
+ await command.ExecuteNonQueryAsync();
+ }
+ catch
+ {
+ // Avoid invalid ID if new object could not be stored
+ if (wasNew)
+ Id = UnidentifiedId();
+
+ throw;
+ }
+ }
+ finally
+ {
+ await connection.CloseAsync();
+ }
+ }
+
+ public bool IsNew()
+ {
+ return Id.Equals(UnidentifiedId());
+ }
+
+ public IEnumerable AssignFieldNames()
+ {
+ var result = new List();
+ result.Add(IdFieldName());
+
+ return result;
+ }
+
+ public async Task AssignToAsync(DbParameterCollection parameters)
+ {
+ if (IsNew()) Id = await IdGenerator.GenerateNewIdAsync();
+
+ parameters.AddMySqlParameterWithValue("@Id", Id);
+ }
+
+ public async Task AssignFromAsync(DbDataReader reader)
+ {
+ Id = (T)reader["Id"];
+ }
+
+ public abstract string TableName();
+
+ public async Task Restore(T identifier)
+ {
+ var connection = ConnectionProvider!.GetConnection();
+ await connection.OpenAsync();
+ try
+ {
+ var command = connection.CreateCommand();
+ command.CommandText = $"SELECT * FROM {TableName()} WHERE Id=@id";
+ command.Parameters.AddWithValue("@id", identifier);
+
+ var reader = await command.ExecuteReaderAsync();
+ if (!reader.HasRows)
+ return false;
+
+ await AssignFromAsync(reader);
+ return true;
+ }
+ finally
+ {
+ await connection.CloseAsync();
+ }
+ }
+
+ internal string InsertCommand()
+ {
+ var fields = AssignFieldNames();
+ return
+ $"INSERT INTO {TableName()} ({string.Join(",", fields)}) VALUES ({string.Join(",", fields.Select(f => $"@{f}"))})";
+ }
+
+ internal string UpdateCommand()
+ {
+ var fields = AssignFieldNames();
+ return $"UPDATE {TableName()} SET {string.Join(",", fields.Select(f => $"{f}=@{f}"))}";
+ }
+
+ public abstract string IdFieldName();
+}
\ No newline at end of file
diff --git a/SweetLib.Storage.MySql/Helper/DbParameterExtensions.cs b/SweetLib.Storage.MySql/Helper/DbParameterExtensions.cs
new file mode 100644
index 0000000..6bbc2f0
--- /dev/null
+++ b/SweetLib.Storage.MySql/Helper/DbParameterExtensions.cs
@@ -0,0 +1,17 @@
+using System.Data.Common;
+using MySql.Data.MySqlClient;
+
+namespace SweetLib.Storage.MySql.Helper
+{
+ public static class MySqlDbParameterExtensions
+ {
+ public static MySqlParameter AddMySqlParameterWithValue(this DbParameterCollection parameterCollection,
+ string name, object value)
+ {
+ var param = new MySqlParameter(name, value);
+ parameterCollection.Add(param);
+
+ return param;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SweetLib.Storage.MySql/SweetLib.Storage.MySql.csproj b/SweetLib.Storage.MySql/SweetLib.Storage.MySql.csproj
new file mode 100644
index 0000000..74d7e51
--- /dev/null
+++ b/SweetLib.Storage.MySql/SweetLib.Storage.MySql.csproj
@@ -0,0 +1,47 @@
+
+
+
+ netstandard2.0
+ 0.1.0-alpha.1
+ SweetLib MySql Storage package
+ Serraniel
+
+ Copyright © 2017-2022 by Serraniel
+
+ https://github.com/Serraniel/SweetLib
+ https://github.com/Serraniel/SweetLib
+ true
+ https://github.com/Serraniel/SweetLib/blob/develop/nuget_icon.png?raw=true
+ true
+ LICENSE
+ 0.1.0.3
+ 0.1.0.3
+ latest
+
+
+
+ bin\Release\netstandard1.3\SweetLib.IO.xml
+
+
+
+ ..\Docs\SweetLib.Storage.MySql
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+
+
+
+
+
+
+
diff --git a/SweetLib.Storage.MySql/SweetLib.Storage.MySql.nuspec b/SweetLib.Storage.MySql/SweetLib.Storage.MySql.nuspec
new file mode 100644
index 0000000..60041e9
--- /dev/null
+++ b/SweetLib.Storage.MySql/SweetLib.Storage.MySql.nuspec
@@ -0,0 +1,18 @@
+
+
+
+ $id$
+ $version$-alpha
+ $title$
+ Serraniel
+ $author$
+ https://opensource.org/licenses/GPL-3.0
+ https://github.com/Serraniel/SweetLib
+ https://github.com/Serraniel/SweetLib/blob/develop/nuget_icon.png?raw=true
+ true
+ $description$
+ First pre version just to try that nuget package thing :)
+ Copyright © 2017 Serraniel
+ Utility
+
+
\ No newline at end of file
diff --git a/SweetLib.Storage.MySql/build-nuget.bat b/SweetLib.Storage.MySql/build-nuget.bat
new file mode 100644
index 0000000..f341b7c
--- /dev/null
+++ b/SweetLib.Storage.MySql/build-nuget.bat
@@ -0,0 +1,2 @@
+nuget pack SweetLib.Storage.MySql.csproj -properties Configuration=Release -symbols
+pause
\ No newline at end of file
diff --git a/SweetLib.Storage/Database/IConnectionProvider.cs b/SweetLib.Storage/Database/IConnectionProvider.cs
new file mode 100644
index 0000000..c5caa30
--- /dev/null
+++ b/SweetLib.Storage/Database/IConnectionProvider.cs
@@ -0,0 +1,17 @@
+using System.Data.Common;
+
+namespace SweetLib.Storage.Database
+{
+ ///
+ /// Provider for database connection.
+ ///
+ /// Specific type of the database connection. Must inherit .
+ public interface IConnectionProvider where T : DbConnection
+ {
+ ///
+ /// Gets an instance of a database connection.
+ ///
+ ///
+ T GetConnection();
+ }
+}
\ No newline at end of file
diff --git a/SweetLib.Storage/Database/IDatabaseObject.cs b/SweetLib.Storage/Database/IDatabaseObject.cs
new file mode 100644
index 0000000..b579fa8
--- /dev/null
+++ b/SweetLib.Storage/Database/IDatabaseObject.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using System.Data.Common;
+using System.Threading.Tasks;
+
+namespace SweetLib.Storage.Database
+{
+ ///
+ /// Object to store in database.
+ ///
+ /// Type of the used identifier.
+ public interface IDatabaseObject : IStorable
+ {
+ ///
+ /// Assigns field names of the database columns.
+ ///
+ ///
+ IEnumerable AssignFieldNames();
+
+ ///
+ /// Assigns values to the query parameters.
+ ///
+ ///
+ ///
+ Task AssignToAsync(DbParameterCollection parameters);
+
+ ///
+ /// Assigns values to the object.
+ ///
+ ///
+ ///
+ Task AssignFromAsync(DbDataReader reader);
+
+ ///
+ /// Table name of the object.
+ ///
+ ///
+ string TableName();
+ }
+}
\ No newline at end of file
diff --git a/SweetLib.Storage/IIdGenerator.cs b/SweetLib.Storage/IIdGenerator.cs
new file mode 100644
index 0000000..ab5a885
--- /dev/null
+++ b/SweetLib.Storage/IIdGenerator.cs
@@ -0,0 +1,23 @@
+using System.Threading.Tasks;
+
+namespace SweetLib.Storage
+{
+ ///
+ /// Generates a new object id.
+ ///
+ /// Type of the used identifier.
+ public interface IIdGenerator
+ {
+ ///
+ /// Generates a new id of the specified type.
+ ///
+ ///
+ T GenerateNewId();
+
+ ///
+ /// Generates a new id of the specified type. Runs asynchronous.
+ ///
+ ///
+ Task GenerateNewIdAsync();
+ }
+}
\ No newline at end of file
diff --git a/SweetLib.Storage/IIdentified.cs b/SweetLib.Storage/IIdentified.cs
new file mode 100644
index 0000000..5185b44
--- /dev/null
+++ b/SweetLib.Storage/IIdentified.cs
@@ -0,0 +1,20 @@
+namespace SweetLib.Storage
+{
+ ///
+ /// Interface for identified objects.
+ ///
+ /// Type of the identifier.
+ public interface IIdentified
+ {
+ ///
+ /// Identifier of the object.
+ ///
+ T Id { get; set; }
+
+ ///
+ /// Gets a dummy Id for unidentified instances;
+ ///
+ ///
+ T UnidentifiedId();
+ }
+}
\ No newline at end of file
diff --git a/SweetLib.Storage/IStorable.cs b/SweetLib.Storage/IStorable.cs
new file mode 100644
index 0000000..101ff3e
--- /dev/null
+++ b/SweetLib.Storage/IStorable.cs
@@ -0,0 +1,30 @@
+using System.Threading.Tasks;
+
+namespace SweetLib.Storage
+{
+ ///
+ /// Interface for objects which can be stored and restored.
+ ///
+ /// Type of the used identifier.
+ public interface IStorable : IIdentified
+ {
+ ///
+ /// Stores the object.
+ ///
+ ///
+ Task Store();
+
+ ///
+ /// Restores an object.
+ ///
+ /// Identifier of the object to restore.
+ ///
+ Task Restore(T identifier);
+
+ ///
+ /// Determines whether the current object instance is new or already exists.
+ ///
+ /// Boolean indicating if the current object instance is new or already exists.
+ bool IsNew();
+ }
+}
\ No newline at end of file
diff --git a/SweetLib.Storage/SweetLib.Storage.csproj b/SweetLib.Storage/SweetLib.Storage.csproj
index cdd0238..a60a9ce 100644
--- a/SweetLib.Storage/SweetLib.Storage.csproj
+++ b/SweetLib.Storage/SweetLib.Storage.csproj
@@ -28,7 +28,6 @@
-
diff --git a/SweetLib.sln b/SweetLib.sln
index c774c87..accdee1 100644
--- a/SweetLib.sln
+++ b/SweetLib.sln
@@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SweetLib.IO", "SweetLib.IO\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SweetLib.Storage", "SweetLib.Storage\SweetLib.Storage.csproj", "{E08BDA4B-BA1E-44F8-9D97-D11F80F8F9F0}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SweetLib.Storage.MySql", "SweetLib.Storage.MySql\SweetLib.Storage.MySql.csproj", "{EEDC1D23-1CA9-4A1D-85CB-C71E73E10B12}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -43,6 +45,10 @@ Global
{E08BDA4B-BA1E-44F8-9D97-D11F80F8F9F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E08BDA4B-BA1E-44F8-9D97-D11F80F8F9F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E08BDA4B-BA1E-44F8-9D97-D11F80F8F9F0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EEDC1D23-1CA9-4A1D-85CB-C71E73E10B12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EEDC1D23-1CA9-4A1D-85CB-C71E73E10B12}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EEDC1D23-1CA9-4A1D-85CB-C71E73E10B12}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EEDC1D23-1CA9-4A1D-85CB-C71E73E10B12}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE