Permalink
Browse files

Add methods to register and retrieve custom providers (#449)

Looks good ;)
  • Loading branch information...
asherber authored and pleb committed Apr 11, 2018
1 parent d58e2c0 commit ee93e6fc9941d56e16dec57e08faf0c61f0ed006
@@ -79,6 +79,7 @@
<Compile Include="Core\SqlTests.cs" />
<Compile Include="DatabaseConfigurationTests.cs" />
<Compile Include="DatabaseTests.cs" />
<Compile Include="Providers\CustomProviderRegistrationTests.cs" />
<Compile Include="Providers\SqlServerDatabaseProviderTests.cs" />
<Compile Include="DescriptionAttribute.cs" />
<Compile Include="Models\Note.cs" />
@@ -0,0 +1,110 @@
// <copyright company="PetaPoco - CollaboratingPlatypus">
// Apache License, Version 2.0 https://github.com/CollaboratingPlatypus/PetaPoco/blob/master/LICENSE.txt
// </copyright>
// <author>PetaPoco - CollaboratingPlatypus</author>
// <date>2018/04/10</date>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
using Shouldly;
using PetaPoco.Core;
using System.Data.Common;
using PetaPoco.Providers;
using System.Data;
namespace PetaPoco.Tests.Unit.Providers
{
public class CustomProviderRegistrationTests: IDisposable
{
public void Dispose()
{
DatabaseProvider.ClearCustomProviders();
}
private void RegisterProviders()
{
DatabaseProvider.RegisterCustomProvider<MyCustomProvider>("Foo");
DatabaseProvider.RegisterCustomProvider<MyCustomProvider>("Bar");
}
[Theory]
[InlineData("Foo", typeof(MyCustomProvider))]
[InlineData("foo", typeof(MyCustomProvider))]
[InlineData("FOO", typeof(MyCustomProvider))]
[InlineData("Bar", typeof(MyCustomProvider))]
[InlineData("Baz", typeof(SqlServerDatabaseProvider))]
[InlineData("MySql.SomethingOrOther", typeof(MySqlDatabaseProvider))]
public void Resolve_WithName_ShouldHaveExpectedProvider(string name, Type type)
{
RegisterProviders();
var provider = DatabaseProvider.Resolve(name, true, "Data Source=foo");
provider.GetType().ShouldBe(type);
}
[Theory]
[InlineData(typeof(FooType), typeof(MyCustomProvider))]
[InlineData(typeof(BarType), typeof(MyCustomProvider))]
[InlineData(typeof(String), typeof(SqlServerDatabaseProvider))]
[InlineData(typeof(MariaDbType), typeof(MariaDbDatabaseProvider))]
public void Resolve_WithType_ShouldHaveExpectedProvider(Type inputType, Type providerType)
{
RegisterProviders();
var provider = DatabaseProvider.Resolve(inputType, true, "Data Source=foo");
provider.GetType().ShouldBe(providerType);
}
[Fact]
public void ChangingRegistration_ShouldHaveExpectedProvider()
{
RegisterProviders();
DatabaseProvider.RegisterCustomProvider<MyOtherCustomProvider>("Foo");
var provider = DatabaseProvider.Resolve("foo", true, "Data Source=foo");
provider.GetType().ShouldBe(typeof(MyOtherCustomProvider));
}
[Fact]
public void NoCustomRegistrations_ShouldHaveDefaultProvider()
{
var provider = DatabaseProvider.Resolve("foo", true, "Data Source=foo");
provider.GetType().ShouldBe(typeof(SqlServerDatabaseProvider));
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public void InvalidString_ShouldThrow(string input)
{
Should.Throw<ArgumentException>(() => DatabaseProvider.RegisterCustomProvider<MyCustomProvider>(input));
}
private class MyCustomProvider : DatabaseProvider
{
public override DbProviderFactory GetFactory()
{
throw new NotImplementedException();
}
}
private class MyOtherCustomProvider : DatabaseProvider
{
public override DbProviderFactory GetFactory()
{
throw new NotImplementedException();
}
}
private class FooType { }
private class BarType { }
private class MariaDbType { }
}
}
View
@@ -1,4 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
@@ -157,7 +161,12 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DB/@EntryIndexedValue">DB</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MS/@EntryIndexedValue">MS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
@@ -5,6 +5,7 @@
// <date>2016/01/11</date>
using System;
using System.Collections.Concurrent;
using System.Data;
using System.Data.Common;
using System.Linq;
@@ -178,6 +179,42 @@ protected DbProviderFactory GetFactory(params string[] assemblyQualifiedNames)
return (DbProviderFactory)ft.GetField("Instance").GetValue(null);
}
private static readonly ConcurrentDictionary<string, IProvider> _customProviders = new ConcurrentDictionary<string, IProvider>();
/// <summary>
/// Registers a custom IProvider with a string that will the beginning of the name
/// of the provider, DbConnection, or DbProviderFactory.
/// </summary>
/// <typeparam name="T">Type of IProvider to be registered.</typeparam>
/// <param name="initialString">String to be matched against the beginning of the provider name.</param>
public static void RegisterCustomProvider<T>(string initialString) where T: IProvider, new()
{
if (String.IsNullOrWhiteSpace(initialString))
throw new ArgumentException("Initial string must not be null or empty", "initialString");
_customProviders[initialString] = Singleton<T>.Instance;
}
private static IProvider GetCustomProvider(string name)
{
IProvider provider;
foreach (var initialString in _customProviders.Keys)
{
if (name.IndexOf(initialString, StringComparison.InvariantCultureIgnoreCase) == 0
&& _customProviders.TryGetValue(initialString, out provider))
{
return provider;
}
}
return null;
}
internal static void ClearCustomProviders()
{
_customProviders.Clear();
}
/// <summary>
/// Look at the type and provider name being used and instantiate a suitable DatabaseType instance.
/// </summary>
@@ -190,6 +227,10 @@ internal static IProvider Resolve(Type type, bool allowDefault, string connectio
var typeName = type.Name;
// Try using type name first (more reliable)
var custom = GetCustomProvider(typeName);
if (custom != null)
return custom;
if (typeName.StartsWith("MySql"))
return Singleton<MySqlDatabaseProvider>.Instance;
if (typeName.StartsWith("MariaDb"))
@@ -228,6 +269,10 @@ internal static IProvider Resolve(Type type, bool allowDefault, string connectio
internal static IProvider Resolve(string providerName, bool allowDefault, string connectionString)
{
// Try again with provider name
var custom = GetCustomProvider(providerName);
if (custom != null)
return custom;
if (providerName.IndexOf("MySql", StringComparison.InvariantCultureIgnoreCase) >= 0)
return Singleton<MySqlDatabaseProvider>.Instance;
if (providerName.IndexOf("MariaDb", StringComparison.InvariantCultureIgnoreCase) >= 0)

0 comments on commit ee93e6f

Please sign in to comment.