Last active
September 26, 2015 06:12
-
-
Save danielwertheim/074a7a9f22b3cb977319 to your computer and use it in GitHub Desktop.
Some MongoDB and Proxies
This file contains hidden or 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
using System; | |
using System.Collections.Concurrent; | |
using Castle.DynamicProxy; | |
using MongoDB.Bson; | |
namespace FunnyBunny | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var interceptor = new EntityInterceptor(); | |
var generator = new ProxyGenerator(); | |
var p = (Person)generator.CreateClassProxy(typeof(Person), new[] { typeof(IMongoDynamicEntityProxy) }, interceptor); | |
p.Name = "Daniel"; | |
p.Age = 35; | |
p.MakeAdmin(); | |
var pp = (IMongoDynamicEntityProxy) p; | |
DumpChanges(pp); | |
pp.ClearChanges(); | |
p.Age += 1; | |
DumpChanges(pp); | |
} | |
private static void DumpChanges(IMongoDynamicEntityProxy pp) | |
{ | |
Console.WriteLine(); | |
Console.WriteLine("==============="); | |
Console.WriteLine("BSON Document with changes"); | |
Console.WriteLine("==============="); | |
var changes = pp.GetChangesAsDocument(); | |
foreach (var entry in changes) | |
Console.WriteLine($"{entry.Name}:{entry.Value}"); | |
} | |
} | |
public class Person | |
{ | |
private int _age; | |
public virtual string Name { get; set; } | |
public virtual int Age | |
{ | |
get | |
{ | |
Console.WriteLine("Getting Age"); | |
return _age; | |
} | |
set | |
{ | |
Console.WriteLine("Setting Age"); | |
_age = value; | |
} | |
} | |
public virtual bool IsAdmin { get; protected set; } | |
public virtual void MakeAdmin() | |
{ | |
IsAdmin = true; | |
} | |
} | |
public interface IMongoDynamicEntityProxy | |
{ | |
BsonDocument GetChangesAsDocument(); | |
void ClearChanges(); | |
} | |
public class State | |
{ | |
public object Value { get; } | |
public bool IsDirty { get; private set; } | |
public State(object value, bool isDirty) | |
{ | |
Value = value; | |
IsDirty = isDirty; | |
} | |
public State Mutate(object newValue) | |
{ | |
return new State(newValue, true); | |
} | |
public void Commit() | |
{ | |
IsDirty = false; | |
} | |
} | |
public class EntityInterceptor : IInterceptor | |
{ | |
private readonly ConcurrentDictionary<string, object> _updatedStateBag = new ConcurrentDictionary<string, object>(); | |
public void Intercept(IInvocation invocation) | |
{ | |
var name = invocation.MethodInvocationTarget?.Name ?? invocation.Method.Name; | |
if (IsSetter(name)) | |
{ | |
var key = name.Remove(0, 4); | |
SetValue(key, invocation.Arguments[0]); | |
invocation.Proceed(); | |
return; | |
} | |
if (invocation.Method.DeclaringType == typeof(IMongoDynamicEntityProxy)) | |
{ | |
switch (name) | |
{ | |
case "ClearChanges": | |
ClearChanges(); | |
break; | |
case "GetChangesAsDocument": | |
GetChangesAsDocument(invocation); | |
break; | |
} | |
return; | |
} | |
invocation.Proceed(); | |
} | |
private void ClearChanges() | |
{ | |
_updatedStateBag.Clear(); | |
} | |
private void GetChangesAsDocument(IInvocation invocation) | |
{ | |
var document = new BsonDocument(); | |
foreach (var keyValue in _updatedStateBag) | |
document.Set(keyValue.Key, BsonTypeMapper.MapToBsonValue(keyValue.Value)); | |
invocation.ReturnValue = document; | |
} | |
private void SetValue(string key, object value) | |
{ | |
_updatedStateBag.AddOrUpdate(key, value, (k, v) => value); | |
} | |
private bool IsSetter(string name) | |
{ | |
return name.StartsWith("set_"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment