Skip to content

Instantly share code, notes, and snippets.

@phillip-haydon
Created September 28, 2012 06:15
Show Gist options
  • Save phillip-haydon/3798206 to your computer and use it in GitHub Desktop.
Save phillip-haydon/3798206 to your computer and use it in GitHub Desktop.
Dynamic Chained API (playing around to see possibilities)
using System;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using Raven.Client;
using Raven.Client.Document;
using Raven.Json.Linq;
namespace ChainedAPISample
{
class Program
{
static void Main(string[] args)
{
var documentStore = (new DocumentStore()
{
DefaultDatabase = "Testing",
Url = "http://localhost:8080"
}).Initialize();
using (dynamic chainer = documentStore.OpenDynamicSession())
{
chainer.Posts.insert(new
{
Name = "Rabbit"
}, "909");
chainer.Posts.Insert(new
{
Name = "Banana"
}, "123");
chainer.People.insert(new
{
FirstName = "Phillip"
}, "1");
chainer.People.Insert(new
{
FirstName = "Prabir"
}, "2");
chainer.SaveChanges();
}
using (dynamic chainer = documentStore.OpenDynamicSession())
{
dynamic result = chainer.Posts.load(123);
Console.WriteLine(result.Name);
dynamic result2 = chainer.Posts.Load(909);
Console.WriteLine(result2.Name);
dynamic result3 = chainer.People.load(1);
Console.WriteLine(result3.FirstName);
dynamic result4 = chainer.People.Load(2);
Console.WriteLine(result4.FirstName);
}
Console.ReadKey();
}
}
public class Chainer : DynamicObject, IDisposable
{
protected IDocumentSession Session { get; set; }
public Chainer(IDocumentSession session)
{
Session = session;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = new ChainBuilder(this, Session, binder.Name);
return true;
}
private class ChainBuilder : DynamicObject
{
private dynamic OriginalObject { get; set; }
private IDocumentSession Session { get; set; }
private string CollectionName { get; set; }
private static Type documentSessionType = typeof (IDocumentSession);
public ChainBuilder(DynamicObject originalObject, IDocumentSession session, string collection)
{
OriginalObject = originalObject;
Session = session;
CollectionName = collection;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (binder.Name.Equals("load", StringComparison.OrdinalIgnoreCase))
{
var generic = GetLoadMethod();
var id = CollectionName.ToLower() + "/" + args[0];
result = generic.Invoke(Session, new object[] { id });
return true;
}
if (binder.Name.Equals("insert", StringComparison.OrdinalIgnoreCase))
{
MethodInfo method = GetStoreMethod();
var id = CollectionName.ToLower() + "/" + args[1];
var objectToStore = args[0] as object;
method.Invoke(Session, new []{objectToStore, id});
RavenJObject metadata = Session.Advanced.GetMetadataFor(objectToStore);
metadata["Raven-Entity-Name"] = CollectionName;
result = null;
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
private static MethodInfo GetLoadMethod()
{
MethodInfo method = documentSessionType.GetMethods().FirstOrDefault(x => x.Name == "Load");
MethodInfo generic = method.MakeGenericMethod(typeof (object));
return generic;
}
private static MethodInfo GetStoreMethod()
{
return documentSessionType.GetMethods()
.Where(x =>
{
if (x.Name != "Store")
return false;
var methodParams = x.GetParameters();
if (methodParams.Length != 2)
return false;
if (methodParams[1].ParameterType == typeof(string))
return true;
return false;
})
.FirstOrDefault();
}
}
public void SaveChanges()
{
Session.SaveChanges();
}
public void Dispose()
{
Session.Dispose();
}
}
public static class DynamicSessionExtension
{
public static Chainer OpenDynamicSession(this IDocumentStore store)
{
var chainer = new Chainer(store.OpenSession());
return chainer;
}
}
}
@prabirshrestha
Copy link

This could be improved to support named parameters.

var user = _db.Users.Insert(Name: "Steve", Age: 50);    

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment