WIP toward completeness
- Add opt args for the run command - Support Task/Async/sync for all run/write/result cmds - Define builder using funcs from Functions module - Functions module no longer auto-opened - Update README with some of the above
This commit is contained in:
parent
78e5bbf77d
commit
f23f7b90e9
12
README.md
12
README.md
@ -13,6 +13,8 @@ The goal is to provide:
|
|||||||
- A composable pipeline for creating ReQL statements:
|
- A composable pipeline for creating ReQL statements:
|
||||||
|
|
||||||
```fsharp
|
```fsharp
|
||||||
|
open RethinkDb.Driver.FSharp.Functions
|
||||||
|
|
||||||
/// string -> (IConnection -> Task<Post>)
|
/// string -> (IConnection -> Task<Post>)
|
||||||
let fetchPost (postId : string) =
|
let fetchPost (postId : string) =
|
||||||
fromDb "Blog"
|
fromDb "Blog"
|
||||||
@ -25,6 +27,8 @@ let fetchPost (postId : string) =
|
|||||||
- An F# domain-specific language (DSL) using a `rethink` computation expression (CE):
|
- An F# domain-specific language (DSL) using a `rethink` computation expression (CE):
|
||||||
|
|
||||||
```fsharp
|
```fsharp
|
||||||
|
open RethinkDb.Driver.FSharp
|
||||||
|
|
||||||
/// string -> (IConnection -> Task<Post>)
|
/// string -> (IConnection -> Task<Post>)
|
||||||
let fetchPost (postId : string) =
|
let fetchPost (postId : string) =
|
||||||
rethink<Post> {
|
rethink<Post> {
|
||||||
@ -59,19 +63,21 @@ The examples above both use the default retry logic.
|
|||||||
|
|
||||||
- Only rename functions/methods where required
|
- Only rename functions/methods where required
|
||||||
|
|
||||||
Within the CE, there are a few differing names, mostly notably at the start (selecting databases and tables); this is to allow for a more natural language flow. Its names may change in the 0.8.x series; it is the most alpha part of the project at this point.
|
Within the CE, there are a few differing names, mostly notably at the start (selecting databases and tables); this is to allow for a more natural language flow. Its names may change in the 0.8.x series; it is the most alpha part of the project at this point. Also, while CEs now support overloading (thank you F# 6 developers!), they do not detect if the first value in the tupled arguments is different. This is most noticeable once `result*` or `write*` commands have been issued; these support `Task<'T>`, `Async<'T>`, and synchronous `'T` operations, but the follow-on commands will be different (e.x. `withRetryDefault` (tasks) vs. `withAsyncRetryDefault` vs. `withSyncRetryDefault`). There are also versions of these that support optional arguments (for all) and cancellation tokens (for task/async).
|
||||||
|
|
||||||
The functions do have to change a bit, since they do not support overloading; an example for `filter` is below.
|
The functions show this pattern throughout, as functions in a module do not support overloading; an example for `filter` is below.
|
||||||
|
|
||||||
```fsharp
|
```fsharp
|
||||||
// Function names cannot be polymorphic the way object-oriented methods can, so filter's three overloads become
|
// Function names cannot be polymorphic the way object-oriented methods can, so filter's three overloads become
|
||||||
filter (r.HashMap ("age", 30))
|
filter (r.HashMap ("age", 30))
|
||||||
// and
|
// and
|
||||||
filterFunc (fun row -> row.["age"].Eq(30))
|
filterFunc (fun row -> row.G("age").Eq 30)
|
||||||
// and
|
// and
|
||||||
filterJS "function (row) { return 30 == row['age'] }"
|
filterJS "function (row) { return 30 == row['age'] }"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Functions that support optional arguments end with `WithOptArgs`; those that support cancellation tokens end with `WithCancel`; and, those that support both end with `WithOptArgsAndCancel`.
|
||||||
|
|
||||||
## Licensing
|
## Licensing
|
||||||
|
|
||||||
While no specific additional license restrictions exist for this project, there are modifications to the Apache v2
|
While no specific additional license restrictions exist for this project, there are modifications to the Apache v2
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
|||||||
[<AutoOpen>]
|
/// The function-based Domain-Specific Language (DSL) for RethinkDB
|
||||||
module RethinkDb.Driver.FSharp.Functions
|
module RethinkDb.Driver.FSharp.Functions
|
||||||
|
|
||||||
|
open System.Threading
|
||||||
open RethinkDb.Driver
|
open RethinkDb.Driver
|
||||||
open RethinkDb.Driver.Ast
|
open RethinkDb.Driver.Ast
|
||||||
|
|
||||||
@ -18,29 +19,118 @@ let asyncCursor<'T> conn (expr : ReqlExpr) =
|
|||||||
expr.RunCursorAsync<'T> conn
|
expr.RunCursorAsync<'T> conn
|
||||||
|> Async.AwaitTask
|
|> Async.AwaitTask
|
||||||
|
|
||||||
/// Get the result of a non-select ReQL expression
|
/// Raise an exception if a write command encountered an error
|
||||||
let asyncReqlResult conn (expr : ReqlExpr) =
|
let private raiseIfWriteError (result : Model.Result) =
|
||||||
expr.RunWriteAsync conn
|
match result.Errors with
|
||||||
|> Async.AwaitTask
|
| 0UL -> result
|
||||||
|
| _ -> raise <| ReqlRuntimeError result.FirstError
|
||||||
/// Write a ReQL command, always returning a result
|
|
||||||
let runWriteResult (expr : ReqlExpr) =
|
/// Write a ReQL command, raising an exception if an error occurs
|
||||||
expr.RunWriteAsync
|
let runWriteWithCancel cancelToken conn (expr : ReqlExpr) = backgroundTask {
|
||||||
|
let! result = expr.RunWriteAsync (conn, cancelToken)
|
||||||
|
return raiseIfWriteError result
|
||||||
|
}
|
||||||
|
|
||||||
/// Write a ReQL command, raising an exception if an error occurs
|
/// Write a ReQL command, raising an exception if an error occurs
|
||||||
let runWrite (expr : ReqlExpr) = fun conn -> backgroundTask {
|
let runWrite conn expr = runWriteWithCancel CancellationToken.None conn expr
|
||||||
let! result = expr.RunWriteAsync conn
|
|
||||||
if result.Errors > 0UL then raise <| ReqlRuntimeError result.FirstError
|
/// Write a ReQL command with optional arguments, raising an exception if an error occurs
|
||||||
return result
|
let runWriteWithOptArgsAndCancel args cancelToken conn (expr : ReqlExpr) = backgroundTask {
|
||||||
|
let! result = expr.RunWriteAsync (conn, RunOptArg.create args, cancelToken)
|
||||||
|
return raiseIfWriteError result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the results of an expression
|
/// Write a ReQL command with optional arguments, raising an exception if an error occurs
|
||||||
let asyncResult<'T> conn (expr : ReqlExpr) =
|
let runWriteWithOptArgs args conn expr = runWriteWithOptArgsAndCancel args CancellationToken.None conn expr
|
||||||
expr.RunResultAsync<'T> conn
|
|
||||||
|> Async.AwaitTask
|
/// Write a ReQL command, raising an exception if an error occurs
|
||||||
|
let asyncWrite conn expr = runWrite conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Write a ReQL command with optional arguments, raising an exception if an error occurs
|
||||||
|
let asyncWriteWithOptArgs args conn expr = runWriteWithOptArgs args conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Write a ReQL command, raising an exception if an error occurs
|
||||||
|
let asyncWriteWithCancel cancelToken conn expr = runWriteWithCancel cancelToken conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Write a ReQL command with optional arguments, raising an exception if an error occurs
|
||||||
|
let asyncWriteWithOptArgsAndCancel args cancelToken conn expr =
|
||||||
|
runWriteWithOptArgsAndCancel args cancelToken conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Write a ReQL command synchronously, raising an exception if an error occurs
|
||||||
|
let syncWrite conn expr = asyncWrite conn expr |> Async.RunSynchronously
|
||||||
|
|
||||||
|
/// Write a ReQL command synchronously with optional arguments, raising an exception if an error occurs
|
||||||
|
let syncWriteWithOptArgs args conn expr = asyncWriteWithOptArgs args conn expr |> Async.RunSynchronously
|
||||||
|
|
||||||
|
/// Write a ReQL command with a cancellation token, always returning a result
|
||||||
|
let runWriteResultWithCancel cancelToken conn (expr : ReqlExpr) =
|
||||||
|
expr.RunWriteAsync (conn, cancelToken)
|
||||||
|
|
||||||
|
/// Write a ReQL command, always returning a result
|
||||||
|
let runWriteResult conn expr = runWriteResultWithCancel CancellationToken.None conn expr
|
||||||
|
|
||||||
|
/// Write a ReQL command with optional arguments and a cancellation token, always returning a result
|
||||||
|
let runWriteResultWithOptArgsAndCancel args cancelToken conn (expr : ReqlExpr) =
|
||||||
|
expr.RunWriteAsync (conn, RunOptArg.create args, cancelToken)
|
||||||
|
|
||||||
|
/// Write a ReQL command with optional arguments, always returning a result
|
||||||
|
let runWriteResultWithOptArgs args conn expr = runWriteResultWithOptArgsAndCancel args CancellationToken.None conn expr
|
||||||
|
|
||||||
|
/// Write a ReQL command, always returning a result
|
||||||
|
let asyncWriteResult conn expr = runWriteResult conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Write a ReQL command with optional arguments, always returning a result
|
||||||
|
let asyncWriteResultWithOptArgs args conn expr = runWriteResultWithOptArgs args conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Write a ReQL command with a cancellation token, always returning a result
|
||||||
|
let asyncWriteResultWithCancel cancelToken conn expr = runWriteResultWithCancel cancelToken conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Write a ReQL command with optional arguments and a cancellation token, always returning a result
|
||||||
|
let asyncWriteResultWithOptArgsAndCancel args cancelToken conn expr =
|
||||||
|
runWriteResultWithOptArgsAndCancel args cancelToken conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Write a ReQL command synchronously, always returning a result
|
||||||
|
let syncWriteResult conn expr = asyncWriteResult conn expr |> Async.RunSynchronously
|
||||||
|
|
||||||
|
/// Write a ReQL command synchronously with optional arguments, always returning a result
|
||||||
|
let syncWriteResultWithOptArgs args conn expr = asyncWriteResultWithOptArgs args conn expr |> Async.RunSynchronously
|
||||||
|
|
||||||
|
/// Run the ReQL command using a cancellation token, returning the result as the type specified
|
||||||
|
let runResultWithCancel<'T> cancelToken conn (expr : ReqlExpr) = expr.RunResultAsync<'T> (conn, cancelToken)
|
||||||
|
|
||||||
|
/// Run the ReQL command using optional arguments and a cancellation token, returning the result as the type specified
|
||||||
|
let runResultWithOptArgsAndCancel<'T> args cancelToken conn (expr : ReqlExpr) =
|
||||||
|
expr.RunResultAsync<'T> (conn, RunOptArg.create args, cancelToken)
|
||||||
|
|
||||||
/// Run the ReQL command, returning the result as the type specified
|
/// Run the ReQL command, returning the result as the type specified
|
||||||
let runResult<'T> (expr : ReqlExpr) = expr.RunResultAsync<'T>
|
let runResult<'T> = runResultWithCancel<'T> CancellationToken.None
|
||||||
|
|
||||||
|
/// Run the ReQL command using optional arguments, returning the result as the type specified
|
||||||
|
let runResultWithOptArgs<'T> args = runResultWithOptArgsAndCancel<'T> args CancellationToken.None
|
||||||
|
|
||||||
|
/// Run the ReQL command, returning the result as the type specified
|
||||||
|
let asyncResult<'T> conn expr =
|
||||||
|
runResult<'T> expr conn |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Run the ReQL command using optional arguments, returning the result as the type specified
|
||||||
|
let asyncResultWithOptArgs<'T> args conn expr =
|
||||||
|
runResultWithOptArgs<'T> args conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Run the ReQL command using a cancellation token, returning the result as the type specified
|
||||||
|
let asyncResultWithCancel<'T> cancelToken conn (expr : ReqlExpr) =
|
||||||
|
runResultWithCancel<'T> cancelToken conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Run the ReQL command using optional arguments and a cancellation token, returning the result as the type specified
|
||||||
|
let asyncResultWithOptArgsAndCancel<'T> args cancelToken conn expr =
|
||||||
|
runResultWithOptArgsAndCancel<'T> args cancelToken conn expr |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Run the ReQL command, returning the result as the type specified
|
||||||
|
let syncResult<'T> conn expr =
|
||||||
|
asyncResult<'T> expr conn |> Async.RunSynchronously
|
||||||
|
|
||||||
|
/// Run the ReQL command using optional arguments, returning the result as the type specified
|
||||||
|
let syncResultWithOptArgs<'T> args conn expr =
|
||||||
|
asyncResultWithOptArgs<'T> args conn expr |> Async.RunSynchronously
|
||||||
|
|
||||||
/// Get documents between a lower bound and an upper bound based on a primary key
|
/// Get documents between a lower bound and an upper bound based on a primary key
|
||||||
let between (lowerKey : obj) (upperKey : obj) (expr : ReqlExpr) =
|
let between (lowerKey : obj) (upperKey : obj) (expr : ReqlExpr) =
|
||||||
@ -58,6 +148,18 @@ let betweenIndex (lowerKey : obj) (upperKey : obj) index expr =
|
|||||||
let connection () =
|
let connection () =
|
||||||
r.Connection ()
|
r.Connection ()
|
||||||
|
|
||||||
|
/// Count the documents in this query
|
||||||
|
let count (expr : ReqlExpr) =
|
||||||
|
expr.Count ()
|
||||||
|
|
||||||
|
/// Count the documents in this query where the function returns true
|
||||||
|
let countFunc (f : ReqlExpr -> bool) (expr : ReqlExpr) =
|
||||||
|
expr.Count (ReqlFunction1 (fun row -> f row :> obj))
|
||||||
|
|
||||||
|
/// Count the documents in this query where the function returns true
|
||||||
|
let countJS js (expr : ReqlExpr) =
|
||||||
|
expr.Count (toJS js)
|
||||||
|
|
||||||
/// Reference a database
|
/// Reference a database
|
||||||
let db dbName =
|
let db dbName =
|
||||||
match dbName with "" -> r.Db () | _ -> r.Db dbName
|
match dbName with "" -> r.Db () | _ -> r.Db dbName
|
||||||
@ -110,21 +212,25 @@ let eqJoinJSIndex js table (indexName : string) expr =
|
|||||||
let filter (filterSpec : obj) (expr : ReqlExpr) =
|
let filter (filterSpec : obj) (expr : ReqlExpr) =
|
||||||
expr.Filter filterSpec
|
expr.Filter filterSpec
|
||||||
|
|
||||||
/// Apply optional argument to a filter
|
|
||||||
let private optArgFilter arg (filter : Filter) =
|
|
||||||
filter.OptArg (match arg with Default d -> d.reql)
|
|
||||||
|
|
||||||
/// Filter documents, providing optional arguments
|
/// Filter documents, providing optional arguments
|
||||||
let filterWithOptArgs (filterSpec : obj) arg expr =
|
let filterWithOptArgs (filterSpec : obj) arg expr =
|
||||||
filter filterSpec expr |> optArgFilter arg
|
filter filterSpec expr |> FilterOptArg.apply arg
|
||||||
|
|
||||||
/// Filter documents using a function
|
/// Filter documents using a function
|
||||||
let filterFunc<'T> (f : ReqlExpr -> 'T) (expr : ReqlExpr) =
|
let filterFunc (f : ReqlExpr -> bool) (expr : ReqlExpr) =
|
||||||
expr.Filter (ReqlFunction1 (fun row -> f row :> obj))
|
expr.Filter (ReqlFunction1 (fun row -> f row :> obj))
|
||||||
|
|
||||||
/// Filter documents using a function, providing optional arguments
|
/// Filter documents using a function, providing optional arguments
|
||||||
let filterFuncWithOptArgs<'T> (f : ReqlExpr -> 'T) arg expr =
|
let filterFuncWithOptArgs f arg expr =
|
||||||
filterFunc f expr |> optArgFilter arg
|
filterFunc f expr |> FilterOptArg.apply arg
|
||||||
|
|
||||||
|
/// Filter documents using multiple functions (has the effect of ANDing them)
|
||||||
|
let filterFuncAll (fs : (ReqlExpr -> bool) list) (expr : ReqlExpr) =
|
||||||
|
(fs |> List.fold (fun (e : ReqlExpr) f -> filterFunc f e) expr) :?> Filter
|
||||||
|
|
||||||
|
/// Filter documents using multiple functions (has the effect of ANDing them), providing optional arguments
|
||||||
|
let filterFuncAllWithOptArgs fs arg expr =
|
||||||
|
filterFuncAll fs expr |> FilterOptArg.apply arg
|
||||||
|
|
||||||
/// Filter documents using JavaScript
|
/// Filter documents using JavaScript
|
||||||
let filterJS js (expr : ReqlExpr) =
|
let filterJS js (expr : ReqlExpr) =
|
||||||
@ -132,7 +238,7 @@ let filterJS js (expr : ReqlExpr) =
|
|||||||
|
|
||||||
/// Filter documents using JavaScript, providing optional arguments
|
/// Filter documents using JavaScript, providing optional arguments
|
||||||
let filterJSWithOptArgs js arg expr =
|
let filterJSWithOptArgs js arg expr =
|
||||||
filterJS js expr |> optArgFilter arg
|
filterJS js expr |> FilterOptArg.apply arg
|
||||||
|
|
||||||
/// Get a document by its primary key
|
/// Get a document by its primary key
|
||||||
let get (documentId : obj) (table : Table) =
|
let get (documentId : obj) (table : Table) =
|
||||||
@ -182,12 +288,12 @@ let indexList (table : Table) =
|
|||||||
let indexRename (oldName : string) (newName : string) (table : Table) =
|
let indexRename (oldName : string) (newName : string) (table : Table) =
|
||||||
table.IndexRename (oldName, newName)
|
table.IndexRename (oldName, newName)
|
||||||
|
|
||||||
/// Rename an index (overwrite will succeed)
|
/// Rename an index (specifying overwrite action)
|
||||||
let indexRenameWithOverwrite (oldName : string) (newName : string) (table : Table) =
|
let indexRenameWithOptArg oldName newName arg table =
|
||||||
indexRename oldName newName table |> IndexRenameOptArg.apply Overwrite
|
indexRename oldName newName table |> IndexRenameOptArg.apply arg
|
||||||
|
|
||||||
/// Get the status of specific indexes for the given table
|
/// Get the status of specific indexes for the given table
|
||||||
let indexStatus (table : Table) (indexes : string list) =
|
let indexStatus (indexes : string list) (table : Table) =
|
||||||
table.IndexStatus (Array.ofList indexes)
|
table.IndexStatus (Array.ofList indexes)
|
||||||
|
|
||||||
/// Get the status of all indexes for the given table
|
/// Get the status of all indexes for the given table
|
||||||
@ -195,7 +301,7 @@ let indexStatusAll (table : Table) =
|
|||||||
table.IndexStatus ()
|
table.IndexStatus ()
|
||||||
|
|
||||||
/// Wait for specific indexes on the given table to become ready
|
/// Wait for specific indexes on the given table to become ready
|
||||||
let indexWait (table : Table) (indexes : string list) =
|
let indexWait (indexes : string list) (table : Table) =
|
||||||
table.IndexWait (Array.ofList indexes)
|
table.IndexWait (Array.ofList indexes)
|
||||||
|
|
||||||
/// Wait for all indexes on the given table to become ready
|
/// Wait for all indexes on the given table to become ready
|
||||||
@ -231,13 +337,65 @@ let isEmpty (expr : ReqlExpr) =
|
|||||||
expr.IsEmpty ()
|
expr.IsEmpty ()
|
||||||
|
|
||||||
/// End a sequence after a given number of elements
|
/// End a sequence after a given number of elements
|
||||||
let limit n (expr : ReqlExpr) =
|
let limit (n : int) (expr : ReqlExpr) =
|
||||||
expr.Limit n
|
expr.Limit n
|
||||||
|
|
||||||
|
/// Map the results using a function
|
||||||
|
let mapFunc f (expr : ReqlExpr) =
|
||||||
|
expr.Map (ReqlFunction1 f)
|
||||||
|
|
||||||
|
/// Map the results using a JavaScript function
|
||||||
|
let mapJS js (expr : ReqlExpr) =
|
||||||
|
expr.Map (toJS js)
|
||||||
|
|
||||||
|
/// Merge the current query with given document
|
||||||
|
let merge (doc : obj) (expr : ReqlExpr) =
|
||||||
|
expr.Merge doc
|
||||||
|
|
||||||
|
/// Merge the current query with the results of a function
|
||||||
|
let mergeFunc f (expr : ReqlExpr) =
|
||||||
|
expr.Merge (ReqlFunction1 f)
|
||||||
|
|
||||||
|
/// Merge the current query with the results of a JavaScript function
|
||||||
|
let mergeJS js (expr : ReqlExpr) =
|
||||||
|
expr.Merge (toJS js)
|
||||||
|
|
||||||
/// Retrieve the nth element in a sequence
|
/// Retrieve the nth element in a sequence
|
||||||
let nth n (expr : ReqlExpr) =
|
let nth n (expr : ReqlExpr) =
|
||||||
expr.Nth n
|
expr.Nth n
|
||||||
|
|
||||||
|
/// Order a sequence by a given field
|
||||||
|
let orderBy (field : string) (expr : ReqlExpr) =
|
||||||
|
expr.OrderBy field
|
||||||
|
|
||||||
|
/// Order a sequence in descending order by a given field
|
||||||
|
let orderByDescending (field : string) (expr : ReqlExpr) =
|
||||||
|
expr.OrderBy (r.Desc field)
|
||||||
|
|
||||||
|
/// Order a sequence by a given function
|
||||||
|
let orderByFunc f (expr : ReqlExpr) =
|
||||||
|
expr.OrderBy (ReqlFunction1 f)
|
||||||
|
|
||||||
|
/// Order a sequence in descending order by a given function
|
||||||
|
let orderByFuncDescending f (expr : ReqlExpr) =
|
||||||
|
expr.OrderBy (r.Desc (ReqlFunction1 f))
|
||||||
|
|
||||||
|
/// Order a sequence by a given index
|
||||||
|
let orderByIndex (index : string) (expr : ReqlExpr) =
|
||||||
|
expr.OrderBy().OptArg("index", index)
|
||||||
|
|
||||||
|
/// Order a sequence in descending order by a given index
|
||||||
|
let orderByIndexDescending (index : string) (expr : ReqlExpr) =
|
||||||
|
expr.OrderBy().OptArg("index", r.Desc index)
|
||||||
|
|
||||||
|
/// Order a sequence by a given JavaScript function
|
||||||
|
let orderByJS js (expr : ReqlExpr) =
|
||||||
|
expr.OrderBy (toJS js)
|
||||||
|
|
||||||
|
/// Order a sequence in descending order by a given JavaScript function
|
||||||
|
let orderByJSDescending js (expr : ReqlExpr) =
|
||||||
|
expr.OrderBy (r.Desc (toJS js))
|
||||||
|
|
||||||
/// Create an outer join between two sequences, specifying the join condition with a function
|
/// Create an outer join between two sequences, specifying the join condition with a function
|
||||||
let outerJoinFunc<'T> (otherSeq : obj) (f : ReqlExpr -> ReqlExpr -> 'T) (expr : ReqlExpr) =
|
let outerJoinFunc<'T> (otherSeq : obj) (f : ReqlExpr -> ReqlExpr -> 'T) (expr : ReqlExpr) =
|
||||||
expr.OuterJoin (otherSeq, ReqlFunction2 (fun f1 f2 -> f f1 f2 :> obj))
|
expr.OuterJoin (otherSeq, ReqlFunction2 (fun f1 f2 -> f f1 f2 :> obj))
|
||||||
@ -275,7 +433,7 @@ let replaceJSWithOptArgs js args expr =
|
|||||||
replaceJS js expr |> ReplaceOptArg.apply args
|
replaceJS js expr |> ReplaceOptArg.apply args
|
||||||
|
|
||||||
/// Skip a number of elements from the head of a sequence
|
/// Skip a number of elements from the head of a sequence
|
||||||
let skip n (expr : ReqlExpr) =
|
let skip (n : int) (expr : ReqlExpr) =
|
||||||
expr.Skip n
|
expr.Skip n
|
||||||
|
|
||||||
/// Ensure changes to a table are written to permanent storage
|
/// Ensure changes to a table are written to permanent storage
|
||||||
@ -350,16 +508,43 @@ let zip (expr : ReqlExpr) =
|
|||||||
// ~~ RETRY ~~
|
// ~~ RETRY ~~
|
||||||
|
|
||||||
open RethinkDb.Driver.Net
|
open RethinkDb.Driver.Net
|
||||||
open System.Threading.Tasks
|
|
||||||
|
|
||||||
/// Retry, delaying for each the seconds provided (if required)
|
/// Retry, delaying for each the seconds provided (if required)
|
||||||
let withRetry intervals (f : IConnection -> Task<'T>) =
|
let withRetry<'T> intervals f =
|
||||||
Retry.withRetry f intervals
|
Retry.withRetry<'T> f intervals
|
||||||
|
|
||||||
|
/// Convert an async function to a task function (Polly does not understand F# Async)
|
||||||
|
let private asyncFuncToTask<'T> (f : IConnection -> Async<'T>) =
|
||||||
|
fun conn -> f conn |> Async.StartAsTask
|
||||||
|
|
||||||
|
/// Retry, delaying for each the seconds provided (if required)
|
||||||
|
let withAsyncRetry<'T> intervals f = fun conn ->
|
||||||
|
withRetry<'T> intervals (asyncFuncToTask f) conn |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Retry, delaying for each the seconds provided (if required)
|
||||||
|
let withSyncRetry<'T> intervals f =
|
||||||
|
Retry.withRetrySync<'T> f intervals
|
||||||
|
|
||||||
/// Retry failed commands with 200ms, 500ms, and 1 second delays
|
/// Retry failed commands with 200ms, 500ms, and 1 second delays
|
||||||
let withRetryDefault (f : IConnection -> Task<'T>) =
|
let withRetryDefault<'T> f =
|
||||||
Retry.withRetryDefault f
|
Retry.withRetryDefault<'T> f
|
||||||
|
|
||||||
|
/// Retry, delaying for each the seconds provided (if required)
|
||||||
|
let withAsyncRetryDefault<'T> f = fun conn ->
|
||||||
|
withRetryDefault<'T> (asyncFuncToTask f) conn |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Retry, delaying for each the seconds provided (if required)
|
||||||
|
let withSyncRetryDefault<'T> f =
|
||||||
|
Retry.withRetrySyncDefault<'T> f
|
||||||
|
|
||||||
/// Retry failed commands one time with no delay
|
/// Retry failed commands one time with no delay
|
||||||
let withRetryOnce (f : IConnection -> Task<'T>) =
|
let withRetryOnce<'T> f =
|
||||||
Retry.withRetryOnce f
|
Retry.withRetryOnce<'T> f
|
||||||
|
|
||||||
|
/// Retry, delaying for each the seconds provided (if required)
|
||||||
|
let withAsyncRetryOnce<'T> f = fun conn ->
|
||||||
|
withRetryOnce<'T> (asyncFuncToTask f) conn |> Async.AwaitTask
|
||||||
|
|
||||||
|
/// Retry, delaying for each the seconds provided (if required)
|
||||||
|
let withSyncRetryOnce<'T> f =
|
||||||
|
Retry.withRetrySyncOnce<'T> f
|
||||||
|
@ -215,6 +215,90 @@ module ReplaceOptArg =
|
|||||||
r
|
r
|
||||||
|
|
||||||
|
|
||||||
|
/// How RethinkDB should read the data
|
||||||
|
type ReadMode =
|
||||||
|
/// Return values in memory from the primary replica (default)
|
||||||
|
| Single
|
||||||
|
/// Return values committed to a majority of replicas
|
||||||
|
| Majority
|
||||||
|
/// Return values in memory from an arbitrary replica
|
||||||
|
| Outdated
|
||||||
|
|
||||||
|
/// The ReQL representation of the read mode
|
||||||
|
member this.reql = match this with Single -> "single" | Majority -> "majority" | Outdated -> "outdated"
|
||||||
|
|
||||||
|
|
||||||
|
/// How the returned data should be formatted
|
||||||
|
type ReturnFormat =
|
||||||
|
/// The native representation for the calling environment
|
||||||
|
| Native
|
||||||
|
/// The raw representation
|
||||||
|
| Raw
|
||||||
|
|
||||||
|
/// The ReQL representation of the format
|
||||||
|
member this.reql = match this with Native -> "native" | Raw -> "raw"
|
||||||
|
|
||||||
|
|
||||||
|
/// Optional arguments for the `run` command
|
||||||
|
type RunOptArg =
|
||||||
|
/// How data should be read
|
||||||
|
| ReadMode of ReadMode
|
||||||
|
/// The time format (raw is JSON)
|
||||||
|
| TimeFormat of ReturnFormat
|
||||||
|
/// Whether to profile the query
|
||||||
|
| Profile of bool
|
||||||
|
/// The durability of the command
|
||||||
|
| Durability of Durability
|
||||||
|
/// The format of grouped data and streams
|
||||||
|
| GroupFormat of ReturnFormat
|
||||||
|
/// The database against which this run should be executed
|
||||||
|
| Db of string
|
||||||
|
/// The maximum size of a returned array (RethinkDB default is 100,000)
|
||||||
|
| ArrayLimit of int
|
||||||
|
/// The format of binary data
|
||||||
|
| BinaryFormat of ReturnFormat
|
||||||
|
/// Minimum number of rows to wait before batching results (RethinkDB default is 8)
|
||||||
|
| MinBatchRows of int
|
||||||
|
/// Maximum number of rows to wait before batching results (RethinkDB default is no upper bound)
|
||||||
|
| MaxBatchRows of int
|
||||||
|
/// Maximum number of bytes to wait before batching results (RethinkDB default is 1MB)
|
||||||
|
| MaxBatchBytes of int
|
||||||
|
/// Maximum number of seconds to wait before batching results (RethinkDB default is 0.5)
|
||||||
|
| MaxBatchSeconds of float
|
||||||
|
/// Factor to reduce other values for the first batch
|
||||||
|
| FirstBatchScaleDownFactor of int
|
||||||
|
|
||||||
|
/// The ReQL representation of the optional argument
|
||||||
|
member this.reql =
|
||||||
|
let pair =
|
||||||
|
match this with
|
||||||
|
| ReadMode mde -> "read_mode", mde.reql :> obj
|
||||||
|
| TimeFormat fmt -> "time_format", fmt.reql
|
||||||
|
| Profile prf -> "profile", prf
|
||||||
|
| Durability dur -> match dur.reql with k, v -> k, v
|
||||||
|
| GroupFormat fmt -> "group_format", fmt.reql
|
||||||
|
| Db db -> "db", db
|
||||||
|
| ArrayLimit lim -> "array_limit", lim
|
||||||
|
| BinaryFormat fmt -> "binary_format", fmt.reql
|
||||||
|
| MinBatchRows min -> "min_batch_rows", min
|
||||||
|
| MaxBatchRows max -> "max_batch_rows", max
|
||||||
|
| MaxBatchBytes max -> "max_batch_bytes", max
|
||||||
|
| MaxBatchSeconds max -> "max_batch_seconds", max
|
||||||
|
| FirstBatchScaleDownFactor fac -> "first_batch_scaledown_factor", fac
|
||||||
|
fst pair, RethinkDB.R.Expr (snd pair)
|
||||||
|
|
||||||
|
/// Function to support `run` optional arguments
|
||||||
|
module RunOptArg =
|
||||||
|
|
||||||
|
open RethinkDb.Driver.Model
|
||||||
|
|
||||||
|
/// Create optional argument for a run command
|
||||||
|
let create (opts : RunOptArg list) =
|
||||||
|
let args = OptArgs ()
|
||||||
|
opts |> List.iter (fun arg -> args.Add arg.reql)
|
||||||
|
args
|
||||||
|
|
||||||
|
|
||||||
/// Optional arguments for the `update` statement
|
/// Optional arguments for the `update` statement
|
||||||
type UpdateOptArg =
|
type UpdateOptArg =
|
||||||
/// The durability of the command
|
/// The durability of the command
|
||||||
|
@ -8,18 +8,18 @@
|
|||||||
<PackageProjectUrl>https://github.com/danieljsummers/RethinkDb.Driver.FSharp</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/danieljsummers/RethinkDb.Driver.FSharp</PackageProjectUrl>
|
||||||
<!-- PackageIconUrl>https://github.com/danieljsummers/RethinkDb.Driver.FSharp/raw/master/icon/icon.png</PackageIconUrl -->
|
<!-- PackageIconUrl>https://github.com/danieljsummers/RethinkDb.Driver.FSharp/raw/master/icon/icon.png</PackageIconUrl -->
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
<PackageReleaseNotes>Alpha; use at your own risk</PackageReleaseNotes>
|
|
||||||
<Copyright>See LICENSE</Copyright>
|
<Copyright>See LICENSE</Copyright>
|
||||||
<PackageTags>RethinkDB document F#</PackageTags>
|
<PackageTags>RethinkDB document F#</PackageTags>
|
||||||
<VersionPrefix>0.8.0</VersionPrefix>
|
<VersionPrefix>0.8.0</VersionPrefix>
|
||||||
<VersionSuffix>alpha-0005</VersionSuffix>
|
<VersionSuffix>alpha-0006</VersionSuffix>
|
||||||
|
<PackageReleaseNotes>Alpha; use at your own risk</PackageReleaseNotes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Retry.fs" />
|
<Compile Include="Retry.fs" />
|
||||||
<Compile Include="OptArgs.fs" />
|
<Compile Include="OptArgs.fs" />
|
||||||
<Compile Include="Builder.fs" />
|
|
||||||
<Compile Include="Functions.fs" />
|
<Compile Include="Functions.fs" />
|
||||||
|
<Compile Include="Builder.fs" />
|
||||||
<Compile Include="Config.fs" />
|
<Compile Include="Config.fs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -20,16 +20,42 @@ let retryPolicy (intervals : float seq) (conn : IConnection) =
|
|||||||
(conn :?> Connection).Reconnect false
|
(conn :?> Connection).Reconnect false
|
||||||
| false -> ()))
|
| false -> ()))
|
||||||
|
|
||||||
|
/// Create a retry policy that attempts to reconnect to RethinkDB when a synchronous operation encounters an error
|
||||||
|
let retryPolicySync (intervals : float seq) (conn : IConnection) =
|
||||||
|
Policy
|
||||||
|
.Handle<ReqlDriverError>()
|
||||||
|
.WaitAndRetry(
|
||||||
|
intervals |> Seq.map TimeSpan.FromSeconds,
|
||||||
|
System.Action<exn, TimeSpan, int, Context> (fun ex _ _ _ ->
|
||||||
|
printf $"Encountered RethinkDB exception: {ex.Message}"
|
||||||
|
match ex.Message.Contains "socket" with
|
||||||
|
| true ->
|
||||||
|
printf "Reconnecting to RethinkDB"
|
||||||
|
(conn :?> Connection).Reconnect false
|
||||||
|
| false -> ()))
|
||||||
|
|
||||||
/// Perform a query, retrying after each delay specified
|
/// Perform a query, retrying after each delay specified
|
||||||
let withRetry (f : IConnection -> Task<'T>) retries =
|
let withRetry<'T> (f : IConnection -> Task<'T>) retries =
|
||||||
fun conn -> backgroundTask {
|
fun conn -> backgroundTask {
|
||||||
return! (retryPolicy retries conn).ExecuteAsync(fun () -> f conn)
|
return! (retryPolicy retries conn).ExecuteAsync(fun () -> f conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform a synchronous query, retrying after each delay specified
|
||||||
|
let withRetrySync<'T> (f : IConnection -> 'T) retries = fun conn ->
|
||||||
|
(retryPolicySync retries conn).Execute(fun () -> f conn)
|
||||||
|
|
||||||
/// Retry three times, after 200ms, 500ms, and 1 second
|
/// Retry three times, after 200ms, 500ms, and 1 second
|
||||||
let withRetryDefault f =
|
let withRetryDefault<'T> f =
|
||||||
withRetry f [ 0.2; 0.5; 1.0 ]
|
withRetry<'T> f [ 0.2; 0.5; 1.0 ]
|
||||||
|
|
||||||
|
/// Retry three times, after 200ms, 500ms, and 1 second
|
||||||
|
let withRetrySyncDefault<'T> f =
|
||||||
|
withRetrySync<'T> f [ 0.2; 0.5; 1.0 ]
|
||||||
|
|
||||||
/// Retry one time immediately
|
/// Retry one time immediately
|
||||||
let withRetryOnce f =
|
let withRetryOnce<'T> f =
|
||||||
withRetry f [ 0.0 ]
|
withRetry<'T> f [ 0.0 ]
|
||||||
|
|
||||||
|
/// Retry one time immediately
|
||||||
|
let withRetrySyncOnce<'T> f =
|
||||||
|
withRetrySync<'T> f [ 0.0 ]
|
||||||
|
Loading…
Reference in New Issue
Block a user