-
-
Notifications
You must be signed in to change notification settings - Fork 134
Run Helpers
The official RethinkDB drivers expect developers to know the type of response returned from a given query. The C# driver and official Java driver follow the same paradigm.
In order for the C# driver to maintain API compatibility with the official drivers, the .Run()
method return a dynamic
type. The underlying dynamic
type is determined by Newtonsoft
and represents a best effort guess as to what the underlying type is. The Dynamic Language Runtime (DLR) Integration goes into further detail.
There are two consequences to using the .Run()
method:
- The execution context of
.Run()
goes through the DLR. The DLR incurs a slight performance tax. - An extra syntax burden is placed on the developer to get a strongly-typed result from
.Run()
.
The use of run helpers solve both issues above. To illustrate, consider the following example:
Cursor<Change<Hero>> changeFeed = R.Db("marvel").Table("heros")
.Changes().Run<Cursor<Change<Foo>>();
The syntax is a bit verbose and it invokes the DLR via .Run<T>()
. The above query can be written more simply (and gain a slight edge in performance) by using the .RunChanges
helper as shown below:
var changeFeed = R.Db("marvel").Table("heroes")
.Changes().RunChanges<Hero>();
The full list of Run Helpers are outlined here:
When the response type for a query is a SUCCESS_ATOM
the driver is expected to return an object of T
. Typically, queries that return singleRowSelection
are atom responses.
Hero result = R.Db("marvel").Table("heros")
.Get("iron_man")
.Run<Hero>(conn);
var result = R.Db("marvel").Table("heros")
.Get("iron_man")
.RunAtom<Hero>(conn);
.RunWrite()
helps with DML (data manipulation language) type of result queries. .RunWrite()
should be used to perform inserts, updates and deletes as shown below:
var result = R.Db("marvel").Table("heros")
.Insert({"name":"Iron Man"})
.RunWrite(conn);
/*
{
"deleted": 0,
"errors": 0,
"inserted": 1,
"replaced": 0,
"skipped": 0,
"unchanged": 0
}
*/
In the example above, .RunWrite
returns a result
that is a strongly typed Result
helper object with strongly typed properties.
With Result
types, assertions can be made about the result. For example:
var result = R.Db("marvel").Table("heros")
.Insert({"name":"Iron Man"})
.RunWrite(conn)
.AssertNoErrors()
.AssertInserted(1);
The example above ensures that there are 0 errors and 1 document inserted. Otherwise an exception is thrown.
When the response type for a query is a SUCCESS_SEQUENCE
or SUCCESS_PARTIAL
the driver is expected to return a cursor.
Cursor<Hero> all = R.Db("marvel")
.Table("heros")
.GetAll("iron_man", "hulk", "thor")
.Run<Hero>(conn);
var all = R.Db("marvel")
.Table("heros")
.GetAll("iron_man", "hulk", "thor")
.RunCursor<Hero>(conn);
.RunResult<T>()
helps deserialize T
object atom (SUCCESS_ATOM
) or finished sequences List<T>
(SUCCESS_SEQUENCE
) List<T>
server responses.
The main purpose of RunResult<T>
is to handle both SUCCESS_ATOM
and SUCCESS_SEQUENCE
response types which are both fully completed query responses. Both response types can be directly built into T
.
Fundamentally, SUCCESS_SEQUENCE
is actually a fully completed Cursor
response. This means the driver has all the response data necessary to fully satisfy the query in its totality. Instead of going through the headache of creating a formal Cursor<T>
object (when a Cursor<T>
is not really needed), RunResult<T>
simply builds T
off the completed Cursor
response. RunResult
will work anywhere between small to medium response sizes (up to about 100K items). When the server decides the initial response is "too large" to send down the wire, the server will switch the response type from SUCCESS_SEQUENCE
to SUCCESS_PARTIAL
; in which case, RunResult<T>
will no longer work. RunCursor<T>
is recommended if query responses are expected to be larger than 100K items.
Change feed declarations can be cumbersome with a dynamic
.Run()
. For example,
Cursor<Change<Hero>> changeFeed = R.Db("marvel").Table("heros")
.Changes().Run<Cursor<Change<Foo>>();
Using the RunChanges<T>
helper reduces verbosity while type safety for changeFeed
is preserved as Cursor<Change<Hero>>
:
var changeFeed = R.Db("marvel").Table("heros")
.Changes().RunChanges<Hero>();
Change<T>
is a helper type that contains two properties, NewValue
and OldValue
of type T
. When subscribing to .Changes()
the changeFeed
cursor will fill with Change<T>
items when the changeFeed
cursor is enumerated over and as changes happen.
JObject, JArray, JToken
types should not be used with this run helper. Since .RunChanges<T>
is a wrapper for .RunCursor<Change<T>>
developers may experience this GOTCHA. It is recommended that if T
is any JToken
type such as JObject
, you should replace .RunChanges<JObject>
with .RunCursor<JObject>
.
Consider the following query:
IEnumerable<GroupedResult<string,Game>> result =
R.Expr(games).Group("player")
.Run<GroupedResult<string, Game>>(conn);
foreach( var group in result )
{
Console.WriteLine($">>>> KEY:{group.Key}");
group.Dump();
}
The same query can be simplified with the RunGrouping
helper:
var result =
R.Expr(games).Group("player")
.RunGrouping<string, Game>(conn);
foreach( var group in result )
{
Console.WriteLine($">>>> KEY:{group.Key}");
group.Dump();
}
result
is still typed as IEnumerable<GroupedResult<string,Game>>
.
- Home
- Query Examples
- Logging
- Connections & Pooling
- Extra C# Features
- GOTCHA Goblins!
- LINQ to ReQL Provider
- Differences
- Java ReQL API Documentation