Skip to content

Instantly share code, notes, and snippets.

@gdyrrahitis
Created August 7, 2017 22:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gdyrrahitis/d8cc02dd37693043fa7b305cd49ac2e3 to your computer and use it in GitHub Desktop.
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
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;
}
}
}
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; }
}
}
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; }
}
}
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);
}
}
}
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