Created
August 7, 2017 22:27
-
-
Save gdyrrahitis/d8cc02dd37693043fa7b305cd49ac2e3 to your computer and use it in GitHub Desktop.
Drapper new features. Getting rid of the Drapper.Settings.json and introducing a simple container to register types and methods
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Training.Misc | |
{ | |
using System; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
public abstract class AbstractLinker | |
{ | |
protected MethodInfo GetMethodInfo<T>(Expression<Func<T, Delegate>> expression) | |
{ | |
var unaryExpression = (UnaryExpression)expression.Body; | |
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand; | |
var methodInfoExpression = (ConstantExpression)methodCallExpression.Object; | |
var methodInfo = (MethodInfo)methodInfoExpression.Value; | |
return methodInfo; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Training.Misc | |
{ | |
using System; | |
using System.Linq.Expressions; | |
public interface ILinker | |
{ | |
MethodLinker<T> Register<T>(); | |
string Resolve<T>(Expression<Func<T, Delegate>> expression); | |
string Root { get; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Training.Misc | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
public class Linker : AbstractLinker, ILinker | |
{ | |
private const string DefaultPath = "sql"; | |
private readonly IDictionary<Type, IDictionary<MethodInfo, string>> _store; | |
public Linker() : this(DefaultPath) { } | |
public Linker(string path) | |
{ | |
Root = path; | |
_store = new Dictionary<Type, IDictionary<MethodInfo, string>>(); | |
} | |
public MethodLinker<T> Register<T>() | |
{ | |
var type = typeof(T); | |
_store.Add(type, new Dictionary<MethodInfo, string>()); | |
return new MethodLinker<T>(_store[type], this); | |
} | |
public string Resolve<T>(Expression<Func<T, Delegate>> expression) | |
{ | |
var type = typeof(T); | |
var @class = _store[type]; | |
var path = @class[GetMethodInfo(expression)]; | |
return File.ReadAllText(path); | |
} | |
public string Root { get; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Training.Tests.Misc | |
{ | |
using System; | |
using NUnit.Framework; | |
using Training.Misc; | |
using static NUnit.Framework.Assert; | |
[TestFixture] | |
public class LinkerTests | |
{ | |
[Test] | |
public void ReturnsTheOnlyPathRegistered() | |
{ | |
// Arrange | |
var container = new Linker(); | |
container.Register<Repository>() | |
.Correlate(m => new Func<string[]>(m.RetrieveAllUserNames), @"Repository\RetrieveAllUserNames.sql") | |
.End(); | |
// Act | |
var result = container.Resolve<Repository>(m => new Func<string[]>(m.RetrieveAllUserNames)); | |
// Assert | |
AreEqual("select * from tbl_users", result); | |
} | |
[Test] | |
public void ReturnsTheOnlyPathRegisteredWithImplicitSqlExtension() | |
{ | |
// Arrange | |
var container = new Linker(); | |
container.Register<Repository>() | |
.Correlate(m => new Func<string[]>(m.RetrieveAllUserNames), @"Repository\RetrieveAllUserNames") | |
.End(); | |
// Act | |
var result = container.Resolve<Repository>(m => new Func<string[]>(m.RetrieveAllUserNames)); | |
// Assert | |
AreEqual("select * from tbl_users", result); | |
} | |
[Test] | |
public void ReturnsTheOnlyPathRegisteredWithEvenIfThePathBeginsWithForwardSlash() | |
{ | |
// Arrange | |
var container = new Linker(); | |
container.Register<Repository>() | |
.Correlate(m => new Func<string[]>(m.RetrieveAllUserNames), @"\Repository\RetrieveAllUserNames.sql") | |
.End(); | |
// Act | |
var result = container.Resolve<Repository>(m => new Func<string[]>(m.RetrieveAllUserNames)); | |
// Assert | |
AreEqual("select * from tbl_users", result); | |
} | |
[Test] | |
public void ReturnsTheOnlyPathRegisteredWithEvenIfThePathBeginsWithForwardSlashAndExtensionIsOmitted() | |
{ | |
// Arrange | |
var container = new Linker(); | |
container.Register<Repository>() | |
.Correlate(m => new Func<string[]>(m.RetrieveAllUserNames), @"\Repository\RetrieveAllUserNames") | |
.End(); | |
// Act | |
var result = container.Resolve<Repository>(m => new Func<string[]>(m.RetrieveAllUserNames)); | |
// Assert | |
AreEqual("select * from tbl_users", result); | |
} | |
[Test] | |
public void RegistersSingleTypeAndResolvesAllMethods() | |
{ | |
// Arrange | |
var container = new Linker(); | |
container.Register<Repository>() | |
.Correlate(m => new Func<string[]>(m.RetrieveAllUserNames), @"Repository\RetrieveAllUserNames.sql") | |
.Correlate(m => new Func<int, int, int>(m.Add), @"Repository\Add.sql") | |
.End(); | |
// Act | |
var retrieveAllUserNames = container.Resolve<Repository>(m => new Func<string[]>(m.RetrieveAllUserNames)); | |
var add = container.Resolve<Repository>(m => new Func<int, int, int>(m.Add)); | |
// Assert | |
AreEqual("select * from tbl_users", retrieveAllUserNames); | |
AreEqual("select * from tbl_add", add); | |
} | |
[Test] | |
public void ReturnsTheOnlyPathRegisteredWithConfigurableRoot() | |
{ | |
// Arrange | |
var container = new Linker("custom"); | |
container.Register<Repository>() | |
.Correlate(m => new Func<string[]>(m.RetrieveAllUserNames), @"Repository\RetrieveAllUserNames.sql") | |
.End(); | |
// Act | |
var result = container.Resolve<Repository>(m => new Func<string[]>(m.RetrieveAllUserNames)); | |
// Assert | |
AreEqual("select * from tbl_users", result); | |
} | |
[Test] | |
public void RegistersMultipleTypesAndResolvesTheirMethods() | |
{ | |
// Arrange | |
var container = new Linker(); | |
container.Register<Repository>() | |
.Correlate(m => new Func<string[]>(m.RetrieveAllUserNames), @"Repository\RetrieveAllUserNames.sql") | |
.Correlate(m => new Func<int, int, int>(m.Add), @"Repository\Add.sql") | |
.End(); | |
container.Register<OtherRepository>() | |
.Correlate(m => new Func<User>(m.GetUser), @"OtherRepository\GetUser.sql") | |
.End(); | |
// Act | |
var retrieveAllUserNames = container.Resolve<Repository>(m => new Func<string[]>(m.RetrieveAllUserNames)); | |
var add = container.Resolve<Repository>(m => new Func<int, int, int>(m.Add)); | |
var getUser = container.Resolve<OtherRepository>(m => new Func<User>(m.GetUser)); | |
// Assert | |
AreEqual("select * from tbl_users", retrieveAllUserNames); | |
AreEqual("select * from tbl_add", add); | |
AreEqual("select * from tbl_user", getUser); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Training.Misc | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
public class MethodLinker<T> : AbstractLinker | |
{ | |
private readonly IList<KeyValuePair<MethodInfo, string>> _methods; | |
private readonly IDictionary<MethodInfo, string> _methodBucket; | |
private readonly ILinker _linker; | |
public MethodLinker(IDictionary<MethodInfo, string> methodBucket, ILinker linker) | |
{ | |
_methods = new List<KeyValuePair<MethodInfo, string>>(); | |
_methodBucket = methodBucket; | |
_linker = linker; | |
} | |
public string ApplicationPath => string.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath) ? | |
AppDomain.CurrentDomain.BaseDirectory : AppDomain.CurrentDomain.RelativeSearchPath; | |
public MethodLinker<T> Correlate(Expression<Func<T, Delegate>> expression, string relativePath) | |
{ | |
var cleanRelativePath = Path.IsPathRooted(relativePath) ? relativePath.Remove(0, 1) : relativePath; | |
var pathWithExtension = Path.HasExtension(cleanRelativePath) | |
? cleanRelativePath | |
: Path.ChangeExtension(cleanRelativePath, "sql"); | |
var path = Path.Combine(ApplicationPath, _linker.Root, pathWithExtension); | |
var method = GetMethodInfo(expression); | |
return Correlate(path, method); | |
} | |
private MethodLinker<T> Correlate(string path, MethodInfo method) | |
{ | |
_methods.Add(new KeyValuePair<MethodInfo, string>(method, path)); | |
return this; | |
} | |
public ILinker End() | |
{ | |
foreach (var kv in _methods) | |
{ | |
_methodBucket.Add(new KeyValuePair<MethodInfo, string>(kv.Key, kv.Value)); | |
} | |
return _linker; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment