Skip to content

Commit

Permalink
Updated Kros.KORM and used new KormConnectionSettings
Browse files Browse the repository at this point in the history
  • Loading branch information
satano committed Jul 26, 2019
1 parent b65889b commit 3441b6b
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 141 deletions.
6 changes: 1 addition & 5 deletions src/DatabaseFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,14 @@ private static Dictionary<string, KormBuilder> AddBuildersDictionary(IServiceCol
/// <param name="name">The name of the database builder.</param>
/// <param name="builder">Database builder.</param>
/// <returns><see langword="true"/>, if this was the first builder added, otherwise <see langword="false"/>.</returns>
internal static bool AddBuilder(IServiceCollection services, string name, KormBuilder builder)
internal static void AddBuilder(IServiceCollection services, string name, KormBuilder builder)
{
Dictionary<string, KormBuilder> builders = AddBuildersDictionary(services);
if (builders.ContainsKey(name))
{
throw new ArgumentException(string.Format(Resources.DuplicateDatabaseName, name), nameof(name));
}
builders.Add(name, builder);

// We need to know if it was the first builder added.
// The first builder is added into the service container also as IDatabase dependency.
return builders.Count == 1;
}

private readonly ConcurrentDictionary<string, IDatabase> _databases = new ConcurrentDictionary<string, IDatabase>();
Expand Down
49 changes: 14 additions & 35 deletions src/KormBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Kros.Data;
using Kros.KORM.Extensions.Asp.Properties;
using Kros.KORM.Migrations;
using Kros.KORM.Migrations.Middleware;
using Kros.KORM.Migrations.Providers;
Expand All @@ -18,63 +19,40 @@ public class KormBuilder
/// </summary>
public const string DefaultConnectionStringName = "DefaultConnection";

internal const string DefaultProviderName = Kros.Data.SqlServer.SqlServerDataHelper.ClientId;
internal const bool DefaultAutoMigrate = false;

private readonly IDatabaseBuilder _builder;

/// <summary>
/// Initializes a new instance of the <see cref="KormBuilder"/> class. Automatic migrations are off and
/// Microsoft SQL Server KORM provider is used.
/// Initializes a new instance of the <see cref="KormBuilder"/> class.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="connectionString">The database connection string.</param>
public KormBuilder(IServiceCollection services, string connectionString)
: this(services, connectionString, DefaultAutoMigrate, DefaultProviderName)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="KormBuilder"/> class. Microsoft SQL Server KORM provider is used.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="connectionString">The database connection string.</param>
/// <param name="autoMigrate">
/// Value for setting if automatic migrations (<see cref="Migrate()"/>) are allowed or not.
/// </param>
public KormBuilder(IServiceCollection services, string connectionString, bool autoMigrate)
: this(services, connectionString, autoMigrate, DefaultProviderName)
: this(services, new KormConnectionSettings(connectionString))
{
}

/// <summary>
/// Initializes a new instance of the <see cref="KormBuilder"/> class.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="connectionString">The database connection string.</param>
/// <param name="autoMigrate">
/// Value for setting if automatic migrations (<see cref="Migrate()"/>) are allowed or not.
/// </param>
/// <param name="kormProvider">KORM provider value.</param>
public KormBuilder(IServiceCollection services, string connectionString, bool autoMigrate, string kormProvider)
/// <param name="connectionSettings">The database connection settings.</param>
public KormBuilder(IServiceCollection services, KormConnectionSettings connectionSettings)
{
Services = Check.NotNull(services, nameof(services));
ConnectionString = Check.NotNullOrWhiteSpace(connectionString, nameof(connectionString));
KormProvider = Check.NotNullOrWhiteSpace(kormProvider, nameof(kormProvider));
AutoMigrate = autoMigrate;
ConnectionSettings = Check.NotNull(connectionSettings, nameof(connectionSettings));
Check.NotNullOrWhiteSpace(
connectionSettings.ConnectionString, nameof(connectionSettings), Resources.EmptyConnectionStringInSettings);

_builder = Database.Builder;
_builder.UseConnection(connectionString, kormProvider);
_builder.UseConnection(connectionSettings);
}

/// <summary>
/// Gets the service collection.
/// </summary>
public IServiceCollection Services { get; }

internal string ConnectionString { get; }
internal string KormProvider { get; }
internal bool AutoMigrate { get; }
internal KormConnectionSettings ConnectionSettings { get; }

/// <summary>
/// Use database configuration.
Expand Down Expand Up @@ -104,7 +82,8 @@ public KormBuilder UseDatabaseConfiguration(DatabaseConfigurationBase databaseCo
/// <returns>This instance.</returns>
public KormBuilder InitDatabaseForIdGenerator()
{
IIdGeneratorFactory factory = IdGeneratorFactories.GetFactory(ConnectionString, KormProvider);
IIdGeneratorFactory factory = IdGeneratorFactories.GetFactory(
ConnectionSettings.ConnectionString, ConnectionSettings.KormProvider);
using (IIdGenerator idGenerator = factory.GetGenerator(string.Empty))
{
idGenerator.InitDatabaseForIdGenerator();
Expand All @@ -123,7 +102,7 @@ public KormBuilder AddKormMigrations(Action<MigrationOptions> setupAction = null
.AddMemoryCache()
.AddTransient((Func<IServiceProvider, IMigrationsRunner>)(s =>
{
var database = new Database(ConnectionString, KormProvider);
var database = new Database(ConnectionSettings);
MigrationOptions options = SetupMigrationOptions(setupAction);
return new MigrationsRunner(database, options);
}));
Expand Down Expand Up @@ -152,7 +131,7 @@ private static MigrationOptions SetupMigrationOptions(Action<MigrationOptions> s
/// </summary>
public void Migrate()
{
if (AutoMigrate)
if (ConnectionSettings.AutoMigrate)
{
Services.BuildServiceProvider()
.GetService<IMigrationsRunner>()
Expand Down
2 changes: 1 addition & 1 deletion src/Kros.KORM.Extensions.Asp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Kros.KORM" Version="4.0.0-alfa5" />
<PackageReference Include="Kros.KORM" Version="4.0.0-alpha.6" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.2.0" />
Expand Down
9 changes: 9 additions & 0 deletions src/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@
<value>Database with name "{0}" was already added.</value>
<comment>0 - name of the database/connection string</comment>
</data>
<data name="EmptyConnectionStringInSettings" xml:space="preserve">
<value>Connection string in connection settings is empty.</value>
</data>
<data name="InvalidConnectionStringName" xml:space="preserve">
<value>Connection strings section does not contain a connection string with name '{0}'.</value>
<comment>0 - connection string name in appsettings</comment>
Expand Down
83 changes: 10 additions & 73 deletions src/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
using Kros.Utils;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Concurrent;
using System.Data.Common;

namespace Kros.KORM.Extensions.Asp
{
Expand All @@ -13,23 +12,6 @@ namespace Kros.KORM.Extensions.Asp
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Key for connection string for setting KORM database provider. If the provider is not set in connection string,
/// Microsoft SQL Server provider is used.
/// </summary>
public const string KormProviderKey = "KormProvider";

/// <summary>
/// Key for connection string for setting if automatic migrations are enabled (<see cref="KormBuilder.Migrate()"/>).
/// If the value is not set in connection string, automatic migrations are disabled.
/// </summary>
public const string KormAutoMigrateKey = "KormAutoMigrate";

// Only one IDatabaseFactory for service collection must be registered.
// This dictionary holds flags for already used service collections.
private static readonly ConcurrentDictionary<IServiceCollection, bool> _databaseFactoryAdded =
new ConcurrentDictionary<IServiceCollection, bool>();

/// <summary>
/// Register KORM into DI container. The connection string with default name
/// (<see cref="KormBuilder.DefaultConnectionStringName"/>) from <paramref name="configuration"/> is used for database.
Expand Down Expand Up @@ -162,74 +144,29 @@ public static KormBuilder AddKorm(this IServiceCollection services, string conne
Check.NotNullOrWhiteSpace(connectionString, nameof(connectionString));
Check.NotNullOrWhiteSpace(name, nameof(name));

var cnstrBuilder = new DbConnectionStringBuilder
{
ConnectionString = connectionString
};
string providerName = GetKormProvider(cnstrBuilder);
bool autoMigrate = GetKormAutoMigrate(cnstrBuilder);
connectionString = cnstrBuilder.ConnectionString; // Previous methods remove keys, so we want clean connection string.

if (string.IsNullOrWhiteSpace(connectionString))
var connectionSettings = new KormConnectionSettings(connectionString);
if (string.IsNullOrWhiteSpace(connectionSettings.ConnectionString))
{
throw new ArgumentException(Resources.ConnectionStringContainsOnlyKormKeys, nameof(connectionString));
}

return AddKormBuilder(services, name, connectionString, autoMigrate, providerName);
return AddKormBuilder(services, name, connectionSettings);
}

private static KormBuilder AddKormBuilder(
IServiceCollection services,
string name,
string connectionString,
bool autoMigrate,
string providerName)
KormConnectionSettings connectionSettings)
{
AddDatabaseFactory(services);
var builder = new KormBuilder(services, connectionString, autoMigrate, providerName);
if (DatabaseFactory.AddBuilder(services, name, builder))
{
// First database is added also as IDatabase mainly for backward compatibility.
services.AddScoped<IDatabase>(
serviceProvider => serviceProvider.GetRequiredService<IDatabaseFactory>().GetDatabase(name));
}
var builder = new KormBuilder(services, connectionSettings);
DatabaseFactory.AddBuilder(services, name, builder);
services.TryAdd(ServiceDescriptor.Scoped<IDatabase>(
serviceProvider => serviceProvider.GetRequiredService<IDatabaseFactory>().GetDatabase(name)));
return builder;
}

private static void AddDatabaseFactory(IServiceCollection services)
{
_ = _databaseFactoryAdded.GetOrAdd(services, svcs =>
{
svcs.AddScoped<IDatabaseFactory>(provider => new DatabaseFactory(services));
return true;
});
}

private static string GetKormProvider(DbConnectionStringBuilder cnstrBuilder)
{
if (cnstrBuilder.TryGetValue(KormProviderKey, out object cnstrProviderName))
{
cnstrBuilder.Remove(KormProviderKey);
string providerName = (string)cnstrProviderName;
if (!string.IsNullOrWhiteSpace(providerName))
{
return providerName;
}
}
return KormBuilder.DefaultProviderName;
}

private static bool GetKormAutoMigrate(DbConnectionStringBuilder cnstrBuilder)
{
if (cnstrBuilder.TryGetValue(KormAutoMigrateKey, out object cnstrAutoMigrate))
{
cnstrBuilder.Remove(KormAutoMigrateKey);
if (bool.TryParse((string)cnstrAutoMigrate, out bool autoMigrate))
{
return autoMigrate;
}
}
return KormBuilder.DefaultAutoMigrate;
}
=> services.TryAdd(ServiceDescriptor.Scoped<IDatabaseFactory>(provider => new DatabaseFactory(services)));
}
}
16 changes: 5 additions & 11 deletions tests/KormBuilderShould.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,17 @@ public void ThrowArgumentExceptionWhenArgumentsAreInvalid()
Action action = () => new KormBuilder(null, connectionString);
action.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("services");

action = () => new KormBuilder(services, null);
action = () => new KormBuilder(services, (string)null);
action.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("connectionString");

action = () => new KormBuilder(services, (KormConnectionSettings)null);
action.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("connectionSettings");

action = () => new KormBuilder(services, string.Empty);
action.Should().Throw<ArgumentException>().And.ParamName.Should().Be("connectionString");

action = () => new KormBuilder(services, " \t ");
action.Should().Throw<ArgumentException>().And.ParamName.Should().Be("connectionString");

action = () => new KormBuilder(services, connectionString, false, null);
action.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be("kormProvider");

action = () => new KormBuilder(services, connectionString, false, string.Empty);
action.Should().Throw<ArgumentException>().And.ParamName.Should().Be("kormProvider");

action = () => new KormBuilder(services, connectionString, false, " \t ");
action.Should().Throw<ArgumentException>().And.ParamName.Should().Be("kormProvider");
}

[Fact]
Expand Down Expand Up @@ -80,6 +74,6 @@ public void UseDatabaseConfiguration()
}

private KormBuilder CreateKormBuilder(bool autoMigrate)
=> new KormBuilder(new ServiceCollection(), "server=localhost", autoMigrate);
=> new KormBuilder(new ServiceCollection(), $"server=localhost;KormAutoMigrate={autoMigrate}");
}
}
5 changes: 1 addition & 4 deletions tests/KormBuilderWithDatabaseShould.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,12 @@ protected override string BaseConnectionString
[Fact]
public void InitDatabaseForIdGenerator()
{
KormBuilder kormBuilder = CreateKormBuilder(false);
var kormBuilder = new KormBuilder(new ServiceCollection(), ServerHelper.Connection.ConnectionString);
kormBuilder.InitDatabaseForIdGenerator();

CheckTableAndProcedure();
}

private KormBuilder CreateKormBuilder(bool autoMigrate)
=> new KormBuilder(new ServiceCollection(), ServerHelper.Connection.ConnectionString, autoMigrate);

private void CheckTableAndProcedure()
{
using (ConnectionHelper.OpenConnection(ServerHelper.Connection))
Expand Down
26 changes: 14 additions & 12 deletions tests/ServiceCollectionExtensionsShould.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace Kros.KORM.Extensions.Api.UnitTests
{
public class ServiceCollectionExtensionsShould
{
private const string DefaultProviderName = Kros.Data.SqlServer.SqlServerDataHelper.ClientId;

[Fact]
public void AddKormToContainer()
{
Expand All @@ -31,7 +33,7 @@ public void UseDefaultConnectionStringIfConfigurationIsProvided()

KormBuilder builder = services.AddKorm(configuration);

builder.ConnectionString.Should().Be(configuration.GetConnectionString("DefaultConnection"));
builder.ConnectionSettings.ConnectionString.Should().Be(configuration.GetConnectionString("DefaultConnection"));
}

[Fact]
Expand Down Expand Up @@ -75,24 +77,24 @@ public void ThrowArgumentExceptionIfConnectionStringContainsOnlyKormValues()
}

[Theory]
[InlineData("server=localhost;", KormBuilder.DefaultProviderName, false)]
[InlineData("server=localhost;KormProvider=", KormBuilder.DefaultProviderName, false)]
[InlineData("server=localhost;KormProvider=' \t '", KormBuilder.DefaultProviderName, false)]
[InlineData("server=localhost;", DefaultProviderName, false)]
[InlineData("server=localhost;KormProvider=", DefaultProviderName, false)]
[InlineData("server=localhost;KormProvider=' \t '", DefaultProviderName, false)]
[InlineData("server=localhost;KormProvider=LoremIpsum", "LoremIpsum", false)]
[InlineData("server=localhost;KormAutoMigrate=true", KormBuilder.DefaultProviderName, true)]
[InlineData("server=localhost;KormAutoMigrate=false", KormBuilder.DefaultProviderName, false)]
[InlineData("server=localhost;KormAutoMigrate=InvalidValue", KormBuilder.DefaultProviderName, false)]
[InlineData("server=localhost;KormAutoMigrate=", KormBuilder.DefaultProviderName, false)]
[InlineData("server=localhost;KormAutoMigrate=' \t '", KormBuilder.DefaultProviderName, false)]
[InlineData("server=localhost;KormAutoMigrate=true", DefaultProviderName, true)]
[InlineData("server=localhost;KormAutoMigrate=false", DefaultProviderName, false)]
[InlineData("server=localhost;KormAutoMigrate=InvalidValue", DefaultProviderName, false)]
[InlineData("server=localhost;KormAutoMigrate=", DefaultProviderName, false)]
[InlineData("server=localhost;KormAutoMigrate=' \t '", DefaultProviderName, false)]
public void ParseKormConnectionStringKeys(string connectionString, string provider, bool autoMigrate)
{
var services = new ServiceCollection();

KormBuilder builder = services.AddKorm(connectionString);

builder.KormProvider.Should().Be(provider);
builder.AutoMigrate.Should().Be(autoMigrate);
builder.ConnectionString.Should().Be("server=localhost");
builder.ConnectionSettings.KormProvider.Should().Be(provider);
builder.ConnectionSettings.AutoMigrate.Should().Be(autoMigrate);
builder.ConnectionSettings.ConnectionString.Should().Be("server=localhost");
}

[Fact]
Expand Down

0 comments on commit 3441b6b

Please sign in to comment.