diff options
Diffstat (limited to 'lib/sql-providers')
12 files changed, 646 insertions, 0 deletions
diff --git a/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/README.md b/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/README.md new file mode 100644 index 0000000..2823281 --- /dev/null +++ b/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/README.md @@ -0,0 +1,17 @@ +# VNLib.Plugins.Extensions.Sql.MySql +*A runtime asset library that provides access to MySql database features for plugins that are configured to load the provider* + +**This library contains 3rd-party dependencies** + +## Builds +Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my website (link below). + +## Docs and Guides +Documentation, specifications, and setup guides are available on my website. + +[Docs and Articles](https://www.vaughnnugent.com/resources/software/articles?tags=docs,_vnlib.plugins.Extensions.Sql.MySql) +[Builds and Source](https://www.vaughnnugent.com/resources/software/modules/VNLib.Plugins.Extensions) +[Nuget Feeds](https://www.vaughnnugent.com/resources/software/modules) + +## License +Source files in for this project are licensed to you under the GNU Affero General Public License (or any later version). See the LICENSE files for more information.
\ No newline at end of file diff --git a/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/build.readme.md b/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/build.readme.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/build.readme.md diff --git a/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/src/MYSqlExport.cs b/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/src/MYSqlExport.cs new file mode 100644 index 0000000..26fd3a3 --- /dev/null +++ b/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/src/MYSqlExport.cs @@ -0,0 +1,138 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Extensions.Loading.Sql.Mysql +* File: MySqlExport.cs +* +* MySqlExport.cs is part of VNLib.Plugins.Extensions.Loading.Sql which +* is part of the larger VNLib collection of libraries and utilities. +* +* VNLib.Plugins.Extensions.Loading.Sql is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* VNLib.Plugins.Extensions.Loading.Sql is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +using System; +using System.Text.Json; +using System.Data.Common; +using System.Threading.Tasks; + +using Microsoft.EntityFrameworkCore; + +using MySql.Data.MySqlClient; + +using VNLib.Utils.Logging; +using VNLib.Plugins.Extensions.Loading; + +namespace VNLib.Plugins.Extensions.Sql +{ + + [ServiceExport] + [ConfigurationName("sql", Required = true)] + public sealed class MySqlExport(PluginBase plugin, IConfigScope config) + { + private async Task<string> BuildConnStringAsync() + { + //See if the user suggested a raw connection string + if (config.TryGetProperty("connection_string", ps => ps.GetString(), out string? conString)) + { + return conString!; + } + else if (config.TryGetValue("json", out JsonElement value)) + { + JsonSerializerOptions opt = new(JsonSerializerDefaults.General) + { + AllowTrailingCommas = true, + IgnoreReadOnlyFields = true, + DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower, + }; + + MySqlConnectionStringBuilder b = value.Deserialize<MySqlConnectionStringBuilder>(opt)!; + + //Get the password from the secret manager + using ISecretResult? secret = await plugin.TryGetSecretAsync("db_password"); + + b.Password = secret?.Result.ToString(); + return b.ConnectionString; + } + else + { + //Get the password from the secret manager + using ISecretResult? secret = await plugin.TryGetSecretAsync("db_password"); + + // Build connection strin + return new MySqlConnectionStringBuilder() + { + Server = config["hostname"].GetString(), + Database = config["catalog"].GetString(), + UserID = config["username"].GetString(), + Pooling = true, + MinimumPoolSize = config.GetValueOrDefault("min_pool_size", p => p.GetUInt32(), 10u), + MaximumPoolSize = config.GetValueOrDefault("max_pool_size", p => p.GetUInt32(), 50u), + AllowBatch = config.GetValueOrDefault("allow_batch", p => p.GetBoolean(), true), + ConnectionLifeTime = config.GetValueOrDefault("connection_lifetime", p => p.GetUInt32(), 0u), + ConnectionTimeout = config.GetValueOrDefault("connection_timeout", p => p.GetUInt32(), 15u), + Port = config.GetValueOrDefault("port", p => p.GetUInt32(), 3306u), + PipeName = config.GetValueOrDefault("pipe_name", p => p.GetString(), null), + AllowLoadLocalInfile = config.GetValueOrDefault("allow_load_local_infile", p => p.GetBoolean(), false), + AllowLoadLocalInfileInPath = config.GetValueOrDefault("allow_load_local_infile_in_path", p => p.GetString(), null), + + Password = secret?.Result.ToString(), + } + .ConnectionString; + } + } + + /* + * NOTICE: + * Function names must be public and must match the SqlConnectionLoader delegate names. + * + * GetDbConnection - A sync or async function that takes a configuration scope and + * returns a DbConnection factory + * + * GetDbOptions - A sync or async function that takes a configuration scope and + * returns a DbConnectionOptions instance + * + * GetProviderName - Returns a string that is the provider name for the connection + */ + + public string GetProviderName() => "mysql"; + + public async Task<Func<DbConnection>> GetDbConnectionAsync(IConfigScope sqlConfig) + { + //Store local copy of the connection string, probably not the best idea because of the password, but best for now + string connString = await BuildConnStringAsync(); + + return () => new MySqlConnection(connString); + } + + public async Task<DbContextOptions> GetDbOptionsAsync(IConfigScope sqlConfig) + { + //Get the connection string from the configuration + string connString = await BuildConnStringAsync(); + + //Build the options using the mysql extension method + DbContextOptionsBuilder b = new(); + b.UseMySQL(connString); + + //Write debug loggin to the debug log if the user has it enabled or the plugin is in debug mode + if (sqlConfig.GetValueOrDefault("debug", p => p.GetBoolean(), false) || plugin.IsDebug()) + { + //Write the SQL to the debug log + b.LogTo((v) => plugin.Log.Debug("MySql: {v}", v)); + } + + return b.Options; + } + } +} diff --git a/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/src/VNLib.Plugins.Extensions.Loading.Sql.MYSql.csproj b/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/src/VNLib.Plugins.Extensions.Loading.Sql.MYSql.csproj new file mode 100644 index 0000000..dcb4a5c --- /dev/null +++ b/lib/sql-providers/mysql/VNLib.Plugins.Extensions.Loading.Sql.MySql/src/VNLib.Plugins.Extensions.Loading.Sql.MYSql.csproj @@ -0,0 +1,59 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net8.0</TargetFramework> + <AssemblyName>VNLib.Plugins.Extensions.Sql.MySql</AssemblyName> + <RootNamespace>VNLib.Plugins.Extensions.Sql</RootNamespace> + <Nullable>enable</Nullable> + <ImplicitUsings>disable</ImplicitUsings> + <GenerateDocumentationFile>True</GenerateDocumentationFile> + <!--Enable dynamic loading--> + <EnableDynamicLoading>true</EnableDynamicLoading> + </PropertyGroup> + + <PropertyGroup> + <PackageId>VNLib.Plugins.Extensions.Sql.MySql</PackageId> + <Authors>Vaughn Nugent</Authors> + <Company>Vaughn Nugent</Company> + <Product>VNLib.Plugins.Extensions.Sql.MySql</Product> + <Copyright>Copyright © 2024 Vaughn Nugent</Copyright> + <PackageProjectUrl>https://www.vaughnnugent.com/resources/software/modules/VNLib.Plugins.Extensions</PackageProjectUrl> + <RepositoryUrl>https://github.com/VnUgE/VNLib.Plugins.Extensions/tree/master/lib/sql-providers/VNLib.Plugins.Extensions.Sql.MySql</RepositoryUrl> + <Description>A runtime asset library that provides MySql interfaces for ADO and EFCore SQL server clients</Description> + <PackageReadmeFile>README.md</PackageReadmeFile> + <PackageLicenseFile>LICENSE</PackageLicenseFile> + </PropertyGroup> + + <ItemGroup> + <None Include="../../../../../LICENSE"> + <Pack>True</Pack> + <PackagePath>\</PackagePath> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + <None Include="..\README.md"> + <Pack>True</Pack> + <PackagePath>\</PackagePath> + </None> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="ErrorProne.NET.Structs" Version="0.1.2"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.0" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\..\..\VNLib.Plugins.Extensions.Loading\src\VNLib.Plugins.Extensions.Loading.csproj" /> + </ItemGroup> + + <Target Condition="'$(BuildingInsideVisualStudio)' == true" Name="PostBuild" AfterTargets="PostBuildEvent"> + <Exec Command="start xcopy "$(TargetDir)" "$(SolutionDir)devplugins\RuntimeAssets\$(TargetName)" /E /Y /R" /> + </Target> + +</Project> diff --git a/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/README.md b/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/README.md new file mode 100644 index 0000000..abf236f --- /dev/null +++ b/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/README.md @@ -0,0 +1,17 @@ +# VNLib.Plugins.Extensions.Sql.SQLite +*A runtime asset library that provides access to SQLite database features for plugins that are configured to load the provider* + +**This library contains 3rd-party dependencies** + +## Builds +Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my website (link below). + +## Docs and Guides +Documentation, specifications, and setup guides are available on my website. + +[Docs and Articles](https://www.vaughnnugent.com/resources/software/articles?tags=docs,_vnlib.plugins.Extensions.Sql.SQLite) +[Builds and Source](https://www.vaughnnugent.com/resources/software/modules/VNLib.Plugins.Extensions) +[Nuget Feeds](https://www.vaughnnugent.com/resources/software/modules) + +## License +Source files in for this project are licensed to you under the GNU Affero General Public License (or any later version). See the LICENSE files for more information.
\ No newline at end of file diff --git a/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/build.readme.md b/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/build.readme.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/build.readme.md diff --git a/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/src/SQLiteExport.cs b/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/src/SQLiteExport.cs new file mode 100644 index 0000000..6f9455a --- /dev/null +++ b/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/src/SQLiteExport.cs @@ -0,0 +1,131 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Extensions.Loading.Sql.SQLite +* File: SQLiteExport.cs +* +* SQLiteExport.cs is part of VNLib.Plugins.Extensions.Loading.Sql.SQLite which +* is part of the larger VNLib collection of libraries and utilities. +* +* VNLib.Plugins.Extensions.Loading.Sql is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* VNLib.Plugins.Extensions.Loading.Sql is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +using System; +using System.Text.Json; +using System.Data.Common; +using System.Threading.Tasks; + +using Microsoft.EntityFrameworkCore; + +using Microsoft.Data.Sqlite; + +using VNLib.Utils.Logging; +using VNLib.Plugins.Extensions.Loading; + +namespace VNLib.Plugins.Extensions.Sql +{ + + [ServiceExport] + [ConfigurationName("sql", Required = true)] + public sealed class SQLiteExport(PluginBase plugin, IConfigScope config) + { + + private async Task<string> BuildConnStringAsync() + { + //See if the user suggested a raw connection string + if (config.TryGetProperty("connection_string", ps => ps.GetString(), out string? conString)) + { + return conString!; + } + else if (config.TryGetValue("json", out JsonElement value)) + { + JsonSerializerOptions opt = new(JsonSerializerDefaults.General) + { + AllowTrailingCommas = true, + IgnoreReadOnlyFields = true, + DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower, + }; + + SqliteConnectionStringBuilder b = value.Deserialize<SqliteConnectionStringBuilder>(opt)!; + + //Get the password from the secret manager + using ISecretResult? secret = await plugin.TryGetSecretAsync("db_password"); + + b.Password = secret?.Result.ToString(); + return b.ConnectionString; + } + else + { + //Get the password from the secret manager + using ISecretResult? secret = await plugin.TryGetSecretAsync("db_password"); + + // Build connection strin + return new SqliteConnectionStringBuilder() + { + DataSource = config["source"].GetString(), + Pooling = true, + Cache = SqliteCacheMode.Default, + RecursiveTriggers = config.GetValueOrDefault("recursive_triggers", p => p.GetBoolean(), false), + DefaultTimeout = config.GetValueOrDefault("timeout", p => p.GetInt32(), 30), + Mode = config.GetValueOrDefault("mode", p => (SqliteOpenMode)p.GetInt32(), SqliteOpenMode.ReadWriteCreate), + + Password = secret?.Result.ToString(), + } + .ConnectionString; + } + } + + /* + * NOTICE: + * Function names must be public and must match the SqlConnectionLoader delegate names. + * + * GetDbConnection - A sync or async function that takes a configuration scope and + * returns a DbConnection factory + * + * GetDbOptions - A sync or async function that takes a configuration scope and + * returns a DbConnectionOptions instance + * + * GetProviderName - Returns a string that is the provider name for the connection + */ + + public string GetProviderName() => "sqlite"; //Use default handler for sqlite db creation + + public async Task<Func<DbConnection>> GetDbConnectionAsync(IConfigScope sqlConfig) + { + //Store local copy of the connection string, probably not the best idea because of the password, but best for now + string connString = await BuildConnStringAsync(); + + return () => new SqliteConnection(connString); + } + + public async Task<DbContextOptions> GetDbOptionsAsync(IConfigScope sqlConfig) + { + //Get the connection string from the configuration + string connString = await BuildConnStringAsync(); + + DbContextOptionsBuilder b = new(); + b.UseSqlite(connString); + + //Write debug loggin to the debug log if the user has it enabled or the plugin is in debug mode + if (sqlConfig.GetValueOrDefault("debug", p => p.GetBoolean(), false) || plugin.IsDebug()) + { + //Write the SQL to the debug log + b.LogTo((v) => plugin.Log.Debug("SQLite: {v}", v)); + } + + return b.Options; + } + } +} diff --git a/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/src/VNLib.Plugins.Extensions.Loading.Sql.SQLite.csproj b/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/src/VNLib.Plugins.Extensions.Loading.Sql.SQLite.csproj new file mode 100644 index 0000000..b61f523 --- /dev/null +++ b/lib/sql-providers/sqlite/VNLib.Plugins.Extensions.Loading.Sql.SQLite/src/VNLib.Plugins.Extensions.Loading.Sql.SQLite.csproj @@ -0,0 +1,59 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net8.0</TargetFramework> + <AssemblyName>VNLib.Plugins.Extensions.Sql.SQLite</AssemblyName> + <RootNamespace>VNLib.Plugins.Extensions.Sql</RootNamespace> + <Nullable>enable</Nullable> + <ImplicitUsings>disable</ImplicitUsings> + <GenerateDocumentationFile>True</GenerateDocumentationFile> + <!--Enable dynamic loading--> + <EnableDynamicLoading>true</EnableDynamicLoading> + </PropertyGroup> + + <PropertyGroup> + <PackageId>VNLib.Plugins.Extensions.Sql.SQLite</PackageId> + <Authors>Vaughn Nugent</Authors> + <Company>Vaughn Nugent</Company> + <Product>VNLib.Plugins.Extensions.Sql.SQLite</Product> + <Copyright>Copyright © 2024 Vaughn Nugent</Copyright> + <PackageProjectUrl>https://www.vaughnnugent.com/resources/software/modules/VNLib.Plugins.Extensions</PackageProjectUrl> + <RepositoryUrl>https://github.com/VnUgE/VNLib.Plugins.Extensions/tree/master/lib/sql-providers/VNLib.Plugins.Extensions.Sql.SQLite</RepositoryUrl> + <Description>A runtime asset library that provides SQLite interfaces for ADO and EFCore SQL server clients</Description> + <PackageReadmeFile>README.md</PackageReadmeFile> + <PackageLicenseFile>LICENSE</PackageLicenseFile> + </PropertyGroup> + + <ItemGroup> + <None Include="../../../../../LICENSE"> + <Pack>True</Pack> + <PackagePath>\</PackagePath> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + <None Include="..\README.md"> + <Pack>True</Pack> + <PackagePath>\</PackagePath> + </None> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="ErrorProne.NET.Structs" Version="0.1.2"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.1" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\..\..\VNLib.Plugins.Extensions.Loading\src\VNLib.Plugins.Extensions.Loading.csproj" /> + </ItemGroup> + + <Target Condition="'$(BuildingInsideVisualStudio)' == true" Name="PostBuild" AfterTargets="PostBuildEvent"> + <Exec Command="start xcopy "$(TargetDir)" "$(SolutionDir)devplugins\RuntimeAssets\$(TargetName)" /E /Y /R" /> + </Target> + +</Project> diff --git a/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/README.md b/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/README.md new file mode 100644 index 0000000..89662e7 --- /dev/null +++ b/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/README.md @@ -0,0 +1,17 @@ +# VNLib.Plugins.Extensions.Sql.SqlServer +*A runtime asset library that provides access to SqlServer database features for plugins that are configured to load the provider* + +**This library contains 3rd-party dependencies** + +## Builds +Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my website (link below). + +## Docs and Guides +Documentation, specifications, and setup guides are available on my website. + +[Docs and Articles](https://www.vaughnnugent.com/resources/software/articles?tags=docs,_vnlib.plugins.Extensions.Sql.SqlServer) +[Builds and Source](https://www.vaughnnugent.com/resources/software/modules/VNLib.Plugins.Extensions) +[Nuget Feeds](https://www.vaughnnugent.com/resources/software/modules) + +## License +Source files in for this project are licensed to you under the GNU Affero General Public License (or any later version). See the LICENSE files for more information.
\ No newline at end of file diff --git a/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/build.readme.md b/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/build.readme.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/build.readme.md diff --git a/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/src/SqlServerExport.cs b/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/src/SqlServerExport.cs new file mode 100644 index 0000000..71f16bf --- /dev/null +++ b/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/src/SqlServerExport.cs @@ -0,0 +1,149 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Library: VNLib +* Package: VNLib.Plugins.Extensions.Loading.Sql.SQLServer +* File: SQLServerExport.cs +* +* SQLServerExport.cs is part of VNLib.Plugins.Extensions.Loading.Sql.SQLServer which +* is part of the larger VNLib collection of libraries and utilities. +* +* VNLib.Plugins.Extensions.Loading.Sql is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* VNLib.Plugins.Extensions.Loading.Sql is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +using System; +using System.Text.Json; +using System.Data.Common; +using System.Threading.Tasks; + +using Microsoft.Data.SqlClient; + +using Microsoft.EntityFrameworkCore; + +using VNLib.Utils.Logging; +using VNLib.Plugins.Extensions.Loading; + +namespace VNLib.Plugins.Extensions.Sql +{ + + [ServiceExport] + [ConfigurationName("sql", Required = true)] + public sealed class SqlServerExport(PluginBase plugin, IConfigScope config) + { + private async Task<string> BuildConnStringAsync() + { + //See if the user suggested a raw connection string + if (config.TryGetProperty("connection_string", ps => ps.GetString(), out string? conString)) + { + return conString!; + } + else if (config.TryGetValue("json", out JsonElement value)) + { + JsonSerializerOptions opt = new(JsonSerializerDefaults.General) + { + AllowTrailingCommas = true, + IgnoreReadOnlyFields = true, + DictionaryKeyPolicy = JsonNamingPolicy.SnakeCaseLower, + }; + + SqlConnectionStringBuilder b = value.Deserialize<SqlConnectionStringBuilder>(opt)!; + + //Get the password from the secret manager + using ISecretResult? secret = await plugin.TryGetSecretAsync("db_password"); + + b.Password = secret?.Result.ToString(); + return b.ConnectionString; + } + else + { + //Get the password from the secret manager + using ISecretResult? secret = await plugin.TryGetSecretAsync("db_password"); + + // Build connection string + return new SqlConnectionStringBuilder() + { + DataSource = config["hostname"].GetString(), + InitialCatalog = config["catalog"].GetString(), + UserID = config["username"].GetString(), + Pooling = true, + + + ApplicationName = config.GetValueOrDefault("application_name", p => p.GetString(), string.Empty), + HostNameInCertificate = config.GetValueOrDefault("hostname_in_certificate", p => p.GetString(), string.Empty), + PacketSize = config.GetValueOrDefault("packet_size", p => p.GetInt32(), 8000), + Encrypt = config.GetValueOrDefault("encrypted", p => p.GetBoolean(), false), + IntegratedSecurity = config.GetValueOrDefault("integrated_security", p => p.GetBoolean(), false), + MultipleActiveResultSets = config.GetValueOrDefault("multiple_active_result_sets", p => p.GetBoolean(), false), + ConnectTimeout = config.GetValueOrDefault("connect_timeout", p => p.GetInt32(), 15), + LoadBalanceTimeout = config.GetValueOrDefault("load_balance_timeout", p => p.GetInt32(), 0), + MaxPoolSize = config.GetValueOrDefault("max_pool_size", p => p.GetInt32(), 100), + MinPoolSize = config.GetValueOrDefault("min_pool_size", p => p.GetInt32(), 0), + TransactionBinding = config.GetValueOrDefault("transaction_binding", p => p.GetString(), "Implicit Unbind"), + TypeSystemVersion = config.GetValueOrDefault("type_system_version", p => p.GetString(), "Latest"), + WorkstationID = config.GetValueOrDefault("workstation_id", p => p.GetString(), string.Empty), + CurrentLanguage = config.GetValueOrDefault("current_language", p => p.GetString(), "us_english"), + PersistSecurityInfo = config.GetValueOrDefault("persist_security_info", p => p.GetBoolean(), false), + Replication = config.GetValueOrDefault("replication", p => p.GetBoolean(), false), + TrustServerCertificate = config.GetValueOrDefault("trust_server_certificate", p => p.GetBoolean(), false), + UserInstance = config.GetValueOrDefault("user_instance", p => p.GetBoolean(), false), + + Password = secret?.Result.ToString(), + } + .ConnectionString; + } + } + + /* + * NOTICE: + * Function names must be public and must match the SqlConnectionLoader delegate names. + * + * GetDbConnection - A sync or async function that takes a configuration scope and + * returns a DbConnection factory + * + * GetDbOptions - A sync or async function that takes a configuration scope and + * returns a DbConnectionOptions instance + * + * GetProviderName - Returns a string that is the provider name for the connection + */ + + public string GetProviderName() => "sqlserver"; + + public async Task<Func<DbConnection>> GetDbConnectionAsync(IConfigScope sqlConfig) + { + //Store local copy of the connection string, probably not the best idea because of the password, but best for now + string connString = await BuildConnStringAsync(); + + return () => new SqlConnection(connString); + } + + public async Task<DbContextOptions> GetDbOptionsAsync(IConfigScope sqlConfig) + { + //Get the connection string from the configuration + string connString = await BuildConnStringAsync(); + + //Build the options using the mysql extension method + DbContextOptionsBuilder b = new(); + b.UseSqlServer(connString); + + //Write debug loggin to the debug log if the user has it enabled or the plugin is in debug mode + if (sqlConfig.GetValueOrDefault("debug", p => p.GetBoolean(), false) || plugin.IsDebug()) + { + //Write the SQL to the debug log + b.LogTo((v) => plugin.Log.Debug("SqlServer: {v}", v)); + } + + return b.Options; + } + } +} diff --git a/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/src/VNLib.Plugins.Extensions.Loading.Sql.SQLServer.csproj b/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/src/VNLib.Plugins.Extensions.Loading.Sql.SQLServer.csproj new file mode 100644 index 0000000..fea8eee --- /dev/null +++ b/lib/sql-providers/sqlserver/VNLib.Plugins.Extensions.Loading.Sql.SQLServer/src/VNLib.Plugins.Extensions.Loading.Sql.SQLServer.csproj @@ -0,0 +1,59 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net8.0</TargetFramework> + <AssemblyName>VNLib.Plugins.Extensions.Sql.SqlServer</AssemblyName> + <RootNamespace>VNLib.Plugins.Extensions.Sql</RootNamespace> + <Nullable>enable</Nullable> + <ImplicitUsings>disable</ImplicitUsings> + <GenerateDocumentationFile>True</GenerateDocumentationFile> + <!--Enable dynamic loading--> + <EnableDynamicLoading>true</EnableDynamicLoading> + </PropertyGroup> + + <PropertyGroup> + <PackageId>VNLib.Plugins.Extensions.Sql.SqlServer</PackageId> + <Authors>Vaughn Nugent</Authors> + <Company>Vaughn Nugent</Company> + <Product>VNLib.Plugins.Extensions.Sql.SqlServer</Product> + <Copyright>Copyright © 2024 Vaughn Nugent</Copyright> + <PackageProjectUrl>https://www.vaughnnugent.com/resources/software/modules/VNLib.Plugins.Extensions</PackageProjectUrl> + <RepositoryUrl>https://github.com/VnUgE/VNLib.Plugins.Extensions/tree/master/lib/sql-providers/VNLib.Plugins.Extensions.Sql.SqlServer</RepositoryUrl> + <Description>A runtime asset library that provides SqlServer interfaces for ADO and EFCore SQL server clients</Description> + <PackageReadmeFile>README.md</PackageReadmeFile> + <PackageLicenseFile>LICENSE</PackageLicenseFile> + </PropertyGroup> + + <ItemGroup> + <None Include="../../../../../LICENSE"> + <Pack>True</Pack> + <PackagePath>\</PackagePath> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + <None Include="..\README.md"> + <Pack>True</Pack> + <PackagePath>\</PackagePath> + </None> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="ErrorProne.NET.Structs" Version="0.1.2"> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.1" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\..\..\VNLib.Plugins.Extensions.Loading\src\VNLib.Plugins.Extensions.Loading.csproj" /> + </ItemGroup> + + <Target Condition="'$(BuildingInsideVisualStudio)' == true" Name="PostBuild" AfterTargets="PostBuildEvent"> + <Exec Command="start xcopy "$(TargetDir)" "$(SolutionDir)devplugins\RuntimeAssets\$(TargetName)" /E /Y /R" /> + </Target> + +</Project> |