I'm not quite sure where this work will end up. Here's what I've experimented with so far:
Creating a table with an object type "dynamic", rather than a specific type.
This allows the insertion of object types only; other types, like an int, seem to just fail silently.
Insertion of object types ends up at ObjectDatumConverter.ConvertObject. I've modified this method to use the object's Type and find an appropriate datum converter, and then use that to convert the object to a datum.
Reading values back from that table.
From the library's point of view, this ends up at ObjectDatumConverter.ConvertDatum.
Initially this would return a Dictionary<string,object>. But, if you inserted an object with fields, and got back a dictionary, your code would look weird... so I changed this to return a System.Dynamic.DynamicObject subclass that allows accessing the object data as both fields and index accessors.
I think fundamentally this is going to run into problems where the returned objects don't come back as the correct .NET types, and there's no avoiding that. For example...
[DataContract]
public class Thing
{
[DataMember(Name="id")]
public string Id;
[DataMember(Name="full_name")]
public string FullName;
}
var testTable = Query.Db("test").Table<dynamic>("table");
connection.Run(testTable.Insert(new Thing() { Id = "id1", FullName = "Mathieu Fenniak" }));
var readThing = connection.Run(testTable).First();
In this code sample, what type does "readThing" have? All the driver knows is: (a) the library user is asking for a System.Object type (that's what dynamic gets converted to when compiled), and (b) the data is an object with the fields "id" and "full_name".
readThing could be a Dictionary<string,object>, but, then I can't access readThing.Id. It could be a RethinkDbObject (the type I just created in this prototype), and then I can access readThing.id or readThing.full_name, but not readThing.id or readThing.FullName.
Ultimately the best thing to return would be a Thing type, but the driver has no way to identify that as the correct type.
Anyway, aside from that, here are other problems that dynamic support will have:
Not sure how we'll map special operators (like using + to concatate strings)
Not sure how field, property, method accessors will work for dynamic types.
Especially not sure how special behaviours currently built into rethinkdb-net would work; like accessing .Hour on a DateTime type. If it's a dynamic, we'd never know it could be a DateTime and that we'd need to create a special term to access the hour from it.
Upon further investigation, it looks like dynamic operations cannot exist inside an expression tree. This code snippet fails to compile:
var testTable = Query.Db("test").Table<dynamic>("table");
connection.Run(testTable.Insert(new { date = DateTime.UtcNow }));
var retval = connection.Run(testTable.Select(d => d.date.Year));
Because it would be impossible for the compiler to know what type of expression to create for ".date" and ".Year") inside the Select, the C# compiler prevents the usage of dynamic elements inside an expression tree. This is basically a torpedo in the entire idea of using dynamic within rethinkdb-net; if we can't access anything in an expression tree, we'd be severely limited in what we could do.
Experimental work-in-progress!
I'm not quite sure where this work will end up. Here's what I've experimented with so far:
Dictionary<string,object>
. But, if you inserted an object with fields, and got back a dictionary, your code would look weird... so I changed this to return aSystem.Dynamic.DynamicObject
subclass that allows accessing the object data as both fields and index accessors.I think fundamentally this is going to run into problems where the returned objects don't come back as the correct .NET types, and there's no avoiding that. For example...
In this code sample, what type does "readThing" have? All the driver knows is: (a) the library user is asking for a
System.Object
type (that's whatdynamic
gets converted to when compiled), and (b) the data is an object with the fields "id" and "full_name".readThing
could be aDictionary<string,object>
, but, then I can't access readThing.Id. It could be a RethinkDbObject (the type I just created in this prototype), and then I can accessreadThing.id
orreadThing.full_name
, but notreadThing.id
orreadThing.FullName
.Ultimately the best thing to return would be a
Thing
type, but the driver has no way to identify that as the correct type.Anyway, aside from that, here are other problems that dynamic support will have:
.Hour
on a DateTime type. If it's a dynamic, we'd never know it could be a DateTime and that we'd need to create a special term to access the hour from it.Upon further investigation, it looks like
dynamic
operations cannot exist inside an expression tree. This code snippet fails to compile:Because it would be impossible for the compiler to know what type of expression to create for ".date" and ".Year") inside the Select, the C# compiler prevents the usage of dynamic elements inside an expression tree. This is basically a torpedo in the entire idea of using dynamic within rethinkdb-net; if we can't access anything in an expression tree, we'd be severely limited in what we could do.