Fix function retry (#2) / Add asOption (#1)

- Add signature file for function module
This commit is contained in:
Daniel J. Summers 2022-05-25 14:34:37 -04:00
parent 7be81e3e4b
commit 8030d81f96
7 changed files with 885 additions and 364 deletions

View File

@ -1,25 +1,28 @@
# RethinkDb.Driver.FSharp # RethinkDb.Driver.FSharp
Idiomatic F# extensions for the C# RethinkDB driver Idiomatic F# extensions for the C# RethinkDB driver
[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/RethinkDb.Driver.FSharp)](https://www.nuget.org/packages/RethinkDb.Driver.FSharp/) [![Nuget (with prereleases)][pkg-img]][pkg-url]
## Using ## Using
Install the [NuGet](https://www.nuget.org/packages/RethinkDb.Driver.FSharp/) package `RethinkDb.Driver.FSharp`. You will need to specify pre-release, as the package currently has a beta designation. Install the [NuGet][pkg-url] package `RethinkDb.Driver.FSharp`. You will need to specify pre-release, as the package currently has a beta designation.
## What It Provides ## What It Provides
The full documentation is on [the project site][project]; TL;DR below.
### A composable pipeline for creating ReQL statements ### A composable pipeline for creating ReQL statements
```fsharp ```fsharp
open RethinkDb.Driver.FSharp.Functions open RethinkDb.Driver.FSharp.Functions
/// string -> (IConnection -> Task<Post>) /// string -> (IConnection -> Task<Post option>)
let fetchPost (postId : string) = let fetchPost (postId : string) =
fromDb "Blog" db "Blog"
|> table "Post" |> table "Post"
|> get postId |> get postId
|> runResult<Post> |> runResult<Post>
|> asOption
|> withRetryDefault |> withRetryDefault
``` ```
@ -86,4 +89,7 @@ license on this project's dependencies. Please see [the heading on the C# driver
If you are using the project, feel free to file issues about your pain points; there is no substitute for real-world feedback! If you are using the project, feel free to file issues about your pain points; there is no substitute for real-world feedback!
[pkg-img]: https://img.shields.io/nuget/vpre/RethinkDb.Driver.FSharp
[pkg-url]: https://www.nuget.org/packages/RethinkDb.Driver.FSharp/
[project]: https://bitbadger.solutions/open-source/rethinkdb-driver-fsharp/
[license]: https://github.com/bchavez/RethinkDb.Driver#open-source-and-commercial-licensing [license]: https://github.com/bchavez/RethinkDb.Driver#open-source-and-commercial-licensing

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@ module private ConnectionBuilder =
| Database x -> builder.Db x | Database x -> builder.Db x
/// RethinDB configuration /// RethinkDB configuration
type DataConfig = type DataConfig =
{ Parameters : DataConfigParameter list } { Parameters : DataConfigParameter list }

View File

@ -4,6 +4,7 @@ module RethinkDb.Driver.FSharp.Functions
open System.Threading open System.Threading
open RethinkDb.Driver open RethinkDb.Driver
open RethinkDb.Driver.Ast open RethinkDb.Driver.Ast
open RethinkDb.Driver.Net
[<AutoOpen>] [<AutoOpen>]
module private Helpers = module private Helpers =
@ -16,122 +17,167 @@ module private Helpers =
// ~~ EXECUTION ~~ // ~~ EXECUTION ~~
/// Get a cursor with the results of an expression /// Get a cursor with the results of an expression
let asyncCursor<'T> conn (expr : ReqlExpr) = let asyncCursor<'T> (expr : ReqlExpr) conn =
expr.RunCursorAsync<'T> conn expr.RunCursorAsync<'T> conn
|> Async.AwaitTask |> Async.AwaitTask
// ~~ WRITES ~~
/// Write a ReQL command with a cancellation token, always returning a result
let runWriteResultWithCancel cancelToken (expr : ReqlExpr) = fun conn ->
expr.RunWriteAsync (conn, cancelToken)
/// Write a ReQL command, always returning a result
let runWriteResult expr = runWriteResultWithCancel CancellationToken.None expr
/// Write a ReQL command with optional arguments and a cancellation token, always returning a result
let runWriteResultWithOptArgsAndCancel args cancelToken (expr : ReqlExpr) = fun conn ->
expr.RunWriteAsync (conn, RunOptArg.create args, cancelToken)
/// Write a ReQL command with optional arguments, always returning a result
let runWriteResultWithOptArgs args expr = runWriteResultWithOptArgsAndCancel args CancellationToken.None expr
/// Write a ReQL command, always returning a result
let asyncWriteResult expr = fun conn ->
runWriteResult expr conn |> Async.AwaitTask
/// Write a ReQL command with optional arguments, always returning a result
let asyncWriteResultWithOptArgs args expr = fun conn ->
runWriteResultWithOptArgs args expr conn |> Async.AwaitTask
/// Write a ReQL command with a cancellation token, always returning a result
let asyncWriteResultWithCancel cancelToken expr = fun conn ->
runWriteResultWithCancel cancelToken expr conn |> Async.AwaitTask
/// Write a ReQL command with optional arguments and a cancellation token, always returning a result
let asyncWriteResultWithOptArgsAndCancel args cancelToken expr = fun conn ->
runWriteResultWithOptArgsAndCancel args cancelToken expr conn |> Async.AwaitTask
/// Write a ReQL command synchronously, always returning a result
let syncWriteResult expr = fun conn ->
asyncWriteResult expr conn |> Async.RunSynchronously
/// Write a ReQL command synchronously with optional arguments, always returning a result
let syncWriteResultWithOptArgs args expr = fun conn ->
asyncWriteResultWithOptArgs args expr conn |> Async.RunSynchronously
/// Raise an exception if a write command encountered an error /// Raise an exception if a write command encountered an error
let private raiseIfWriteError (result : Model.Result) = let raiseIfWriteError (result : Model.Result) =
match result.Errors with match result.Errors with
| 0UL -> result | 0UL -> result
| _ -> raise <| ReqlRuntimeError result.FirstError | _ -> raise <| ReqlRuntimeError result.FirstError
/// Write a ReQL command, raising an exception if an error occurs /// Write a ReQL command, raising an exception if an error occurs
let runWriteWithCancel cancelToken conn (expr : ReqlExpr) = backgroundTask { let runWriteWithCancel cancelToken expr = fun conn -> backgroundTask {
let! result = expr.RunWriteAsync (conn, cancelToken) let! result = runWriteResultWithCancel cancelToken expr conn
return raiseIfWriteError result 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 conn expr = runWriteWithCancel CancellationToken.None conn expr let runWrite expr = runWriteWithCancel CancellationToken.None expr
/// Write a ReQL command with optional arguments, raising an exception if an error occurs /// Write a ReQL command with optional arguments, raising an exception if an error occurs
let runWriteWithOptArgsAndCancel args cancelToken conn (expr : ReqlExpr) = backgroundTask { let runWriteWithOptArgsAndCancel args cancelToken expr = fun conn -> backgroundTask {
let! result = expr.RunWriteAsync (conn, RunOptArg.create args, cancelToken) let! result = runWriteResultWithOptArgsAndCancel args cancelToken expr conn
return raiseIfWriteError result return raiseIfWriteError result
} }
/// Write a ReQL command with optional arguments, raising an exception if an error occurs /// Write a ReQL command with optional arguments, raising an exception if an error occurs
let runWriteWithOptArgs args conn expr = runWriteWithOptArgsAndCancel args CancellationToken.None conn expr let runWriteWithOptArgs args expr = runWriteWithOptArgsAndCancel args CancellationToken.None expr
/// Write a ReQL command, raising an exception if an error occurs /// Write a ReQL command, raising an exception if an error occurs
let asyncWrite conn expr = runWrite conn expr |> Async.AwaitTask let asyncWrite expr = fun conn ->
runWrite expr conn |> Async.AwaitTask
/// Write a ReQL command with optional arguments, raising an exception if an error occurs /// 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 let asyncWriteWithOptArgs args expr = fun conn ->
runWriteWithOptArgs args expr conn |> Async.AwaitTask
/// Write a ReQL command, raising an exception if an error occurs /// Write a ReQL command, raising an exception if an error occurs
let asyncWriteWithCancel cancelToken conn expr = runWriteWithCancel cancelToken conn expr |> Async.AwaitTask let asyncWriteWithCancel cancelToken expr = fun conn ->
runWriteWithCancel cancelToken expr conn |> Async.AwaitTask
/// Write a ReQL command with optional arguments, raising an exception if an error occurs /// Write a ReQL command with optional arguments, raising an exception if an error occurs
let asyncWriteWithOptArgsAndCancel args cancelToken conn expr = let asyncWriteWithOptArgsAndCancel args cancelToken expr = fun conn ->
runWriteWithOptArgsAndCancel args cancelToken conn expr |> Async.AwaitTask runWriteWithOptArgsAndCancel args cancelToken expr conn |> Async.AwaitTask
/// Write a ReQL command synchronously, raising an exception if an error occurs /// Write a ReQL command synchronously, raising an exception if an error occurs
let syncWrite conn expr = asyncWrite conn expr |> Async.RunSynchronously let syncWrite expr = fun conn ->
asyncWrite expr conn |> Async.RunSynchronously
/// Write a ReQL command synchronously with optional arguments, raising an exception if an error occurs /// 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 let syncWriteWithOptArgs args expr = fun conn ->
asyncWriteWithOptArgs args expr conn |> 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
// ~~ QUERY RESULTS AND MANIPULATION ~~
/// Run the ReQL command using a cancellation token, returning the result as the type specified /// 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) let runResultWithCancel<'T> cancelToken (expr : ReqlExpr) = fun conn ->
expr.RunResultAsync<'T> (conn, cancelToken)
/// Run the ReQL command using optional arguments and a cancellation token, returning the result as the type specified /// Run the ReQL command using optional arguments and a cancellation token, returning the result as the type
let runResultWithOptArgsAndCancel<'T> args cancelToken conn (expr : ReqlExpr) = /// specified
let runResultWithOptArgsAndCancel<'T> args cancelToken (expr : ReqlExpr) = fun conn ->
expr.RunResultAsync<'T> (conn, RunOptArg.create args, cancelToken) 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> = runResultWithCancel<'T> CancellationToken.None let runResult<'T> expr = runResultWithCancel<'T> CancellationToken.None expr
/// Run the ReQL command using optional arguments, returning the result as the type specified /// Run the ReQL command using optional arguments, returning the result as the type specified
let runResultWithOptArgs<'T> args = runResultWithOptArgsAndCancel<'T> args CancellationToken.None let runResultWithOptArgs<'T> args expr = runResultWithOptArgsAndCancel<'T> args CancellationToken.None expr
/// Run the ReQL command, returning the result as the type specified /// Run the ReQL command, returning the result as the type specified
let asyncResult<'T> conn expr = let asyncResult<'T> expr = fun conn ->
runResult<'T> expr conn |> Async.AwaitTask runResult<'T> expr conn |> Async.AwaitTask
/// Run the ReQL command using optional arguments, returning the result as the type specified /// Run the ReQL command using optional arguments, returning the result as the type specified
let asyncResultWithOptArgs<'T> args conn expr = let asyncResultWithOptArgs<'T> args expr = fun conn ->
runResultWithOptArgs<'T> args conn expr |> Async.AwaitTask runResultWithOptArgs<'T> args expr conn |> Async.AwaitTask
/// Run the ReQL command using a cancellation token, returning the result as the type specified /// Run the ReQL command using a cancellation token, returning the result as the type specified
let asyncResultWithCancel<'T> cancelToken conn (expr : ReqlExpr) = let asyncResultWithCancel<'T> cancelToken expr = fun conn ->
runResultWithCancel<'T> cancelToken conn expr |> Async.AwaitTask runResultWithCancel<'T> cancelToken expr conn |> Async.AwaitTask
/// Run the ReQL command using optional arguments and a cancellation token, returning the result as the type specified /// Run the ReQL command using optional arguments and a cancellation token, returning the result as the type
let asyncResultWithOptArgsAndCancel<'T> args cancelToken conn expr = /// specified
runResultWithOptArgsAndCancel<'T> args cancelToken conn expr |> Async.AwaitTask let asyncResultWithOptArgsAndCancel<'T> args cancelToken expr = fun conn ->
runResultWithOptArgsAndCancel<'T> args cancelToken expr conn |> Async.AwaitTask
/// Run the ReQL command, returning the result as the type specified /// Run the ReQL command, returning the result as the type specified
let syncResult<'T> conn expr = let syncResult<'T> expr = fun conn ->
asyncResult<'T> expr conn |> Async.RunSynchronously asyncResult<'T> expr conn |> Async.RunSynchronously
/// Run the ReQL command using optional arguments, returning the result as the type specified /// Run the ReQL command using optional arguments, returning the result as the type specified
let syncResultWithOptArgs<'T> args conn expr = let syncResultWithOptArgs<'T> args expr = fun conn ->
asyncResultWithOptArgs<'T> args conn expr |> Async.RunSynchronously asyncResultWithOptArgs<'T> args expr conn |> Async.RunSynchronously
/// Convert a null item to an option (works for value types as well as reference types)
let nullToOption<'T> (it : 'T) =
if isNull (box it) then None else Some it
/// Convert a possibly-null result to an option
let asOption (f : IConnection -> Tasks.Task<'T>) conn = backgroundTask {
let! result = f conn
return nullToOption result
}
/// Convert a possibly-null result to an option
let asAsyncOption (f : IConnection -> Async<'T>) conn = async {
let! result = f conn
return nullToOption result
}
/// Convert a possibly-null result to an option
let asSyncOption (f : IConnection -> 'T) conn = nullToOption (f conn)
/// Ignore the result of a task-based query
let ignoreResult<'T> (f : IConnection -> Tasks.Task<'T>) conn = task {
let! _ = (f conn).ConfigureAwait false
()
}
/// Apply a connection to the query pipeline (typically the final step)
let withConn<'T> conn (f : IConnection -> 'T) = f conn
// ~~ QUERY DEFINITION ~~ // ~~ QUERY DEFINITION ~~
@ -192,7 +238,7 @@ let distinct (expr : ReqlExpr) =
expr.Distinct () expr.Distinct ()
/// Only retrieve distinct entries from a selection, based on an index /// Only retrieve distinct entries from a selection, based on an index
let distinctWithIndex expr (index : string) = let distinctWithIndex (index : string) expr =
(distinct expr).OptArg ("index", index) (distinct expr).OptArg ("index", index)
/// EqJoin the left field on the right-hand table using its primary key /// EqJoin the left field on the right-hand table using its primary key
@ -224,7 +270,7 @@ let filter (filterSpec : obj) (expr : ReqlExpr) =
expr.Filter filterSpec expr.Filter filterSpec
/// Filter documents, providing optional arguments /// Filter documents, providing optional arguments
let filterWithOptArgs (filterSpec : obj) arg expr = let filterWithOptArg (filterSpec : obj) arg expr =
filter filterSpec expr |> FilterOptArg.apply arg filter filterSpec expr |> FilterOptArg.apply arg
/// Filter documents using a function /// Filter documents using a function
@ -232,7 +278,7 @@ let filterFunc f (expr : ReqlExpr) =
expr.Filter (ReqlFunction1 f) expr.Filter (ReqlFunction1 f)
/// Filter documents using a function, providing optional arguments /// Filter documents using a function, providing optional arguments
let filterFuncWithOptArgs f arg expr = let filterFuncWithOptArg f arg expr =
filterFunc f expr |> FilterOptArg.apply arg filterFunc f expr |> FilterOptArg.apply arg
/// Filter documents using multiple functions (has the effect of ANDing them) /// Filter documents using multiple functions (has the effect of ANDing them)
@ -240,7 +286,7 @@ let filterFuncAll fs expr =
(fs |> List.fold (fun (e : ReqlExpr) f -> filterFunc f e) expr) :?> Filter (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 /// Filter documents using multiple functions (has the effect of ANDing them), providing optional arguments
let filterFuncAllWithOptArgs fs arg expr = let filterFuncAllWithOptArg fs arg expr =
filterFuncAll fs expr |> FilterOptArg.apply arg filterFuncAll fs expr |> FilterOptArg.apply arg
/// Filter documents using JavaScript /// Filter documents using JavaScript
@ -248,7 +294,7 @@ let filterJS js (expr : ReqlExpr) =
expr.Filter (toJS js) expr.Filter (toJS js)
/// Filter documents using JavaScript, providing optional arguments /// Filter documents using JavaScript, providing optional arguments
let filterJSWithOptArgs js arg expr = let filterJSWithOptArg js arg expr =
filterJS js expr |> FilterOptArg.apply arg filterJS js expr |> FilterOptArg.apply arg
/// Get a document by its primary key /// Get a document by its primary key
@ -328,19 +374,19 @@ let innerJoinJS (otherSeq : obj) js (expr : ReqlExpr) =
expr.InnerJoin (otherSeq, toJS js) expr.InnerJoin (otherSeq, toJS js)
/// Insert a single document (use insertMany for multiple) /// Insert a single document (use insertMany for multiple)
let insert (doc : obj) (table : Table) = let insert<'T> (doc : 'T) (table : Table) =
table.Insert doc table.Insert doc
/// Insert multiple documents /// Insert multiple documents
let insertMany (docs : obj seq) (table : Table) = let insertMany<'T> (docs : 'T seq) (table : Table) =
table.Insert (Array.ofSeq docs) table.Insert (Array.ofSeq docs)
/// Insert a single document, providing optional arguments (use insertManyWithOptArgs for multiple) /// Insert a single document, providing optional arguments (use insertManyWithOptArgs for multiple)
let insertWithOptArgs (doc : obj) args table = let insertWithOptArgs<'T> (doc : 'T) args table =
insert doc table |> InsertOptArg.apply args insert doc table |> InsertOptArg.apply args
/// Insert multiple documents, providing optional arguments /// Insert multiple documents, providing optional arguments
let insertManyWithOptArgs (docs : obj seq) args table = let insertManyWithOptArgs<'T> (docs : 'T seq) args table =
insertMany docs table |> InsertOptArg.apply args insertMany docs table |> InsertOptArg.apply args
/// Test whether a sequence is empty /// Test whether a sequence is empty
@ -372,7 +418,7 @@ let mergeJS js (expr : ReqlExpr) =
expr.Merge (toJS js) 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 : int) (expr : ReqlExpr) =
expr.Nth n expr.Nth n
/// Order a sequence by a given field /// Order a sequence by a given field
@ -452,27 +498,27 @@ let sync (table : Table) =
table.Sync () table.Sync ()
/// Return all documents in a table (may be further refined) /// Return all documents in a table (may be further refined)
let table tableName (db : Db) = let table (tableName : string) (db : Db) =
db.Table tableName db.Table tableName
/// Return all documents in a table from the default database (may be further refined) /// Return all documents in a table from the default database (may be further refined)
let fromTable tableName = let fromTable (tableName : string) =
r.Table tableName r.Table tableName
/// Create a table in the given database /// Create a table in the given database
let tableCreate tableName (db : Db) = let tableCreate (tableName : string) (db : Db) =
db.TableCreate tableName db.TableCreate tableName
/// Create a table in the connection-default database /// Create a table in the connection-default database
let tableCreateInDefault tableName = let tableCreateInDefault (tableName : string) =
r.TableCreate tableName r.TableCreate tableName
/// Drop a table in the given database /// Drop a table in the given database
let tableDrop tableName (db : Db) = let tableDrop (tableName : string) (db : Db) =
db.TableDrop tableName db.TableDrop tableName
/// Drop a table from the connection-default database /// Drop a table from the connection-default database
let tableDropFromDefault tableName = let tableDropFromDefault (tableName : string) =
r.TableDrop tableName r.TableDrop tableName
/// Get a list of tables for the given database /// Get a list of tables for the given database
@ -515,10 +561,8 @@ let without (columns : string seq) (expr : ReqlExpr) =
let zip (expr : ReqlExpr) = let zip (expr : ReqlExpr) =
expr.Zip () expr.Zip ()
// ~~ RETRY ~~ // ~~ RETRY FUNCTIONS ~~
open RethinkDb.Driver.Net
/// Retry, delaying for each the seconds provided (if required) /// Retry, delaying for each the seconds provided (if required)
let withRetry<'T> intervals f = let withRetry<'T> intervals f =
Retry.withRetry<'T> f intervals Retry.withRetry<'T> f intervals
@ -539,11 +583,11 @@ let withSyncRetry<'T> intervals f =
let withRetryDefault<'T> f = let withRetryDefault<'T> f =
Retry.withRetryDefault<'T> f Retry.withRetryDefault<'T> f
/// Retry, delaying for each the seconds provided (if required) /// Retry failed commands with 200ms, 500ms, and 1 second delays
let withAsyncRetryDefault<'T> f = fun conn -> let withAsyncRetryDefault<'T> f = fun conn ->
withRetryDefault<'T> (asyncFuncToTask f) conn |> Async.AwaitTask withRetryDefault<'T> (asyncFuncToTask f) conn |> Async.AwaitTask
/// Retry, delaying for each the seconds provided (if required) /// Retry failed commands with 200ms, 500ms, and 1 second delays
let withSyncRetryDefault<'T> f = let withSyncRetryDefault<'T> f =
Retry.withRetrySyncDefault<'T> f Retry.withRetrySyncDefault<'T> f
@ -551,10 +595,10 @@ let withSyncRetryDefault<'T> f =
let withRetryOnce<'T> f = let withRetryOnce<'T> f =
Retry.withRetryOnce<'T> f Retry.withRetryOnce<'T> f
/// Retry, delaying for each the seconds provided (if required) /// Retry failed commands one time with no delay
let withAsyncRetryOnce<'T> f = fun conn -> let withAsyncRetryOnce<'T> f = fun conn ->
withRetryOnce<'T> (asyncFuncToTask f) conn |> Async.AwaitTask withRetryOnce<'T> (asyncFuncToTask f) conn |> Async.AwaitTask
/// Retry, delaying for each the seconds provided (if required) /// Retry failed commands one time with no delay
let withSyncRetryOnce<'T> f = let withSyncRetryOnce<'T> f =
Retry.withRetrySyncOnce<'T> f Retry.withRetrySyncOnce<'T> f

View File

@ -0,0 +1,442 @@
/// The function-based Domain-Specific Language (DSL) for RethinkDB
module RethinkDb.Driver.FSharp.Functions
open System.Threading
open System.Threading.Tasks
open RethinkDb.Driver
open RethinkDb.Driver.Ast
open RethinkDb.Driver.Net
/// Get a cursor with the results of an expression
val asyncCursor<'T> : ReqlExpr -> IConnection -> Async<Cursor<'T>>
// ~~ WRITE, ALWAYS RETURNING A RESULT ~~
/// Write a ReQL command with a cancellation token, always returning a result
val runWriteResultWithCancel : CancellationToken -> ReqlExpr -> (IConnection -> Task<Model.Result>)
/// Write a ReQL command, always returning a result
val runWriteResult : ReqlExpr -> (IConnection -> Task<Model.Result>)
/// Write a ReQL command with optional arguments and a cancellation token, always returning a result
val runWriteResultWithOptArgsAndCancel :
RunOptArg list -> CancellationToken -> ReqlExpr -> (IConnection -> Task<Model.Result>)
/// Write a ReQL command with optional arguments, always returning a result
val runWriteResultWithOptArgs : RunOptArg list -> ReqlExpr -> (IConnection -> Task<Model.Result>)
/// Write a ReQL command, always returning a result
val asyncWriteResult : ReqlExpr -> (IConnection -> Async<Model.Result>)
/// Write a ReQL command with optional arguments, always returning a result
val asyncWriteResultWithOptArgs : RunOptArg list -> ReqlExpr -> (IConnection -> Async<Model.Result>)
/// Write a ReQL command with a cancellation token, always returning a result
val asyncWriteResultWithCancel : CancellationToken -> ReqlExpr -> (IConnection -> Async<Model.Result>)
/// Write a ReQL command with optional arguments and a cancellation token, always returning a result
val asyncWriteResultWithOptArgsAndCancel :
RunOptArg list -> CancellationToken -> ReqlExpr -> (IConnection -> Async<Model.Result>)
/// Write a ReQL command synchronously, always returning a result
val syncWriteResult : ReqlExpr -> (IConnection -> Model.Result)
/// Write a ReQL command synchronously with optional arguments, always returning a result
val syncWriteResultWithOptArgs : RunOptArg list -> ReqlExpr -> (IConnection -> Model.Result)
// ~~ WRITE, RAISING AN EXCEPTION ON ERRORS ~~
/// Write a ReQL command, raising an exception if an error occurs
val runWriteWithCancel : CancellationToken -> ReqlExpr -> (IConnection -> Task<Model.Result>)
/// Write a ReQL command, raising an exception if an error occurs
val runWrite : ReqlExpr -> (IConnection -> Task<Model.Result>)
/// Write a ReQL command with optional arguments, raising an exception if an error occurs
val runWriteWithOptArgsAndCancel :
RunOptArg list -> CancellationToken -> ReqlExpr -> (IConnection -> Task<Model.Result>)
/// Write a ReQL command with optional arguments, raising an exception if an error occurs
val runWriteWithOptArgs : RunOptArg list -> ReqlExpr -> (IConnection -> Task<Model.Result>)
/// Write a ReQL command, raising an exception if an error occurs
val asyncWrite : ReqlExpr -> (IConnection -> Async<Model.Result>)
/// Write a ReQL command with optional arguments, raising an exception if an error occurs
val asyncWriteWithOptArgs : RunOptArg list -> ReqlExpr -> (IConnection -> Async<Model.Result>)
/// Write a ReQL command, raising an exception if an error occurs
val asyncWriteWithCancel : CancellationToken -> ReqlExpr -> (IConnection -> Async<Model.Result>)
/// Write a ReQL command with optional arguments, raising an exception if an error occurs
val asyncWriteWithOptArgsAndCancel :
RunOptArg list -> CancellationToken -> ReqlExpr -> (IConnection -> Async<Model.Result>)
/// Write a ReQL command synchronously, raising an exception if an error occurs
val syncWrite : ReqlExpr -> (IConnection -> Model.Result)
/// Write a ReQL command synchronously with optional arguments, raising an exception if an error occurs
val syncWriteWithOptArgs : RunOptArg list -> ReqlExpr -> (IConnection -> Model.Result)
// ~~ RUNNING QUERIES AND MANIPULATING RESULTS ~~
/// Run the ReQL command using a cancellation token, returning the result as the type specified
val runResultWithCancel<'T> : CancellationToken -> ReqlExpr -> (IConnection -> Task<'T>)
/// Run the ReQL command using optional arguments and a cancellation token, returning the result as the type specified
val runResultWithOptArgsAndCancel<'T> : RunOptArg list -> CancellationToken -> ReqlExpr -> (IConnection -> Task<'T>)
/// Run the ReQL command, returning the result as the type specified
val runResult<'T> : ReqlExpr -> (IConnection -> Task<'T>)
/// Run the ReQL command using optional arguments, returning the result as the type specified
val runResultWithOptArgs<'T> : RunOptArg list -> ReqlExpr -> (IConnection -> Task<'T>)
/// Run the ReQL command, returning the result as the type specified
val asyncResult<'T> : ReqlExpr -> (IConnection -> Async<'T>)
/// Run the ReQL command using optional arguments, returning the result as the type specified
val asyncResultWithOptArgs<'T> : RunOptArg list -> ReqlExpr -> (IConnection -> Async<'T>)
/// Run the ReQL command using a cancellation token, returning the result as the type specified
val asyncResultWithCancel<'T> : CancellationToken -> ReqlExpr -> (IConnection -> Async<'T>)
/// Run the ReQL command using optional arguments and a cancellation token, returning the result as the type specified
val asyncResultWithOptArgsAndCancel<'T> : RunOptArg list -> CancellationToken -> ReqlExpr -> (IConnection -> Async<'T>)
/// Run the ReQL command, returning the result as the type specified
val syncResult<'T> : ReqlExpr -> (IConnection -> 'T)
/// Run the ReQL command using optional arguments, returning the result as the type specified
val syncResultWithOptArgs<'T> : RunOptArg list -> ReqlExpr -> (IConnection -> 'T)
/// Convert a possibly-null result to an option
val asOption : (IConnection -> Task<'T>) -> IConnection -> Task<'T option>
/// Convert a possibly-null result to an option
val asAsyncOption : (IConnection -> Async<'T>) -> IConnection -> Async<'T option>
/// Convert a possibly-null result to an option
val asSyncOption : (IConnection -> 'T) -> IConnection -> 'T option
/// Ignore the result of a task-based execution
val ignoreResult<'T> : (IConnection -> Task<'T>) -> IConnection -> Task<unit>
/// Apply a connection to the query pipeline (typically the final step)
val withConn<'T> : IConnection -> (IConnection -> 'T) -> 'T
// ~~ REQL QUERY DEFINITION ~~
/// Get documents between a lower bound and an upper bound based on a primary key
val between : obj -> obj -> ReqlExpr -> Between
/// Get document between a lower bound and an upper bound, specifying one or more optional arguments
val betweenWithOptArgs : obj -> obj -> BetweenOptArg list -> ReqlExpr -> Between
/// Get documents between a lower bound and an upper bound based on an index
val betweenIndex : obj -> obj -> string -> ReqlExpr -> Between
/// Get a connection builder that can be used to create one RethinkDB connection
val connection : unit -> Connection.Builder
/// Count the documents in this query
val count : ReqlExpr -> Count
/// Count the documents in this query where the function returns true
val countFunc : (ReqlExpr -> bool) -> ReqlExpr -> Count
/// Count the documents in this query where the function returns true
val countJS : string -> ReqlExpr -> Count
/// Reference a database
val db : string -> Db
/// Create a database
val dbCreate : string -> DbCreate
/// Drop a database
val dbDrop : string -> DbDrop
/// Get a list of databases
val dbList : unit -> DbList
/// Delete documents
val delete : ReqlExpr -> Delete
/// Delete documents, providing optional arguments
val deleteWithOptArgs : DeleteOptArg list -> ReqlExpr -> Delete
/// Only retrieve distinct entries from a selection
val distinct : ReqlExpr -> Distinct
/// Only retrieve distinct entries from a selection, based on an index
val distinctWithIndex : string -> ReqlExpr -> Distinct
/// EqJoin the left field on the right-hand table using its primary key
val eqJoin : string -> Table -> ReqlExpr -> EqJoin
/// EqJoin the left function on the right-hand table using its primary key
val eqJoinFunc<'T> : (ReqlExpr -> 'T) -> Table -> ReqlExpr -> EqJoin
/// EqJoin the left function on the right-hand table using the specified index
val eqJoinFuncIndex<'T> : (ReqlExpr -> 'T) -> Table -> string -> ReqlExpr -> EqJoin
/// EqJoin the left field on the right-hand table using the specified index
val eqJoinIndex : string -> Table -> string -> ReqlExpr -> EqJoin
/// EqJoin the left JavaScript on the right-hand table using its primary key
val eqJoinJS : string -> Table -> ReqlExpr -> EqJoin
/// EqJoin the left JavaScript on the right-hand table using the specified index
val eqJoinJSIndex : string -> Table -> string -> ReqlExpr -> EqJoin
/// Filter documents
val filter : obj -> ReqlExpr -> Filter
/// Filter documents, providing an optional argument
val filterWithOptArg : obj -> FilterOptArg -> ReqlExpr -> Filter
/// Filter documents using a function
val filterFunc : (ReqlExpr -> obj) -> ReqlExpr -> Filter
/// Filter documents using a function, providing an optional argument
val filterFuncWithOptArg : (ReqlExpr -> obj) -> FilterOptArg -> ReqlExpr -> Filter
/// Filter documents using multiple functions (has the effect of ANDing them)
val filterFuncAll : (ReqlExpr -> obj) list -> ReqlExpr -> Filter
/// Filter documents using multiple functions (has the effect of ANDing them), providing an optional argument
val filterFuncAllWithOptArg : (ReqlExpr -> obj) list -> FilterOptArg -> ReqlExpr -> Filter
/// Filter documents using JavaScript
val filterJS : string -> ReqlExpr -> Filter
/// Filter documents using JavaScript, providing an optional argument
val filterJSWithOptArg : string -> FilterOptArg -> ReqlExpr -> Filter
/// Get a document by its primary key
val get : obj -> Table -> Get
/// Get all documents matching primary keys
val getAll : obj seq -> Table -> GetAll
/// Get all documents matching keys in the given index
val getAllWithIndex : obj seq -> string -> Table -> GetAll
/// Create an index on the given table
val indexCreate : string -> Table -> IndexCreate
/// Create an index on the given table, including optional arguments
val indexCreateWithOptArgs : string -> IndexCreateOptArg list -> Table -> IndexCreate
/// Create an index on the given table using a function
val indexCreateFunc : string -> (ReqlExpr -> obj) -> Table -> IndexCreate
/// Create an index on the given table using a function, including optional arguments
val indexCreateFuncWithOptArgs : string -> (ReqlExpr -> obj) -> IndexCreateOptArg list -> Table -> IndexCreate
/// Create an index on the given table using JavaScript
val indexCreateJS : string -> string -> Table -> IndexCreate
/// Create an index on the given table using JavaScript, including optional arguments
val indexCreateJSWithOptArgs : string -> string -> IndexCreateOptArg list -> Table -> IndexCreate
/// Drop an index
val indexDrop : string -> Table -> IndexDrop
/// Get a list of indexes for the given table
val indexList : Table -> IndexList
/// Rename an index (will fail if new name already exists)
val indexRename : string -> string -> Table -> IndexRename
/// Rename an index (specifying overwrite action)
val indexRenameWithOptArg : string -> string -> IndexRenameOptArg -> Table -> IndexRename
/// Get the status of specific indexes for the given table
val indexStatus : string list -> Table -> IndexStatus
/// Get the status of all indexes for the given table
val indexStatusAll : Table -> IndexStatus
/// Wait for specific indexes on the given table to become ready
val indexWait : string list -> Table -> IndexWait
/// Wait for all indexes on the given table to become ready
val indexWaitAll : Table -> IndexWait
/// Create an inner join between two sequences, specifying the join condition with a function
val innerJoinFunc<'T> : obj -> (ReqlExpr -> ReqlExpr -> 'T) -> ReqlExpr -> InnerJoin
/// Create an inner join between two sequences, specifying the join condition with JavaScript
val innerJoinJS : obj -> string -> ReqlExpr -> InnerJoin
/// Insert a single document (use insertMany for multiple)
val insert<'T> : 'T -> Table -> Insert
/// Insert multiple documents
val insertMany<'T> : 'T seq -> Table -> Insert
/// Insert a single document, providing optional arguments (use insertManyWithOptArgs for multiple)
val insertWithOptArgs<'T> : 'T -> InsertOptArg list -> Table -> Insert
/// Insert multiple documents, providing optional arguments
val insertManyWithOptArgs<'T> : 'T seq -> InsertOptArg list -> Table -> Insert
/// Test whether a sequence is empty
val isEmpty : ReqlExpr -> IsEmpty
/// End a sequence after a given number of elements
val limit : int -> ReqlExpr -> Limit
/// Map the results using a function
val mapFunc : (ReqlExpr -> obj) -> ReqlExpr -> Map
/// Map the results using a JavaScript function
val mapJS : string -> ReqlExpr -> Map
/// Merge the current query with given document
val merge : obj -> ReqlExpr -> Merge
/// Merge the current query with the results of a function
val mergeFunc : (ReqlExpr -> obj) -> ReqlExpr -> Merge
/// Merge the current query with the results of a JavaScript function
val mergeJS : string -> ReqlExpr -> Merge
/// Retrieve the nth element in a sequence
val nth : int -> ReqlExpr -> Nth
/// Order a sequence by a given field
val orderBy : string -> ReqlExpr -> OrderBy
/// Order a sequence in descending order by a given field
val orderByDescending : string -> ReqlExpr -> OrderBy
/// Order a sequence by a given function
val orderByFunc : (ReqlExpr -> obj) -> ReqlExpr -> OrderBy
/// Order a sequence in descending order by a given function
val orderByFuncDescending : (ReqlExpr -> obj) -> ReqlExpr -> OrderBy
/// Order a sequence by a given index
val orderByIndex : string -> ReqlExpr -> OrderBy
/// Order a sequence in descending order by a given index
val orderByIndexDescending : string -> ReqlExpr -> OrderBy
/// Order a sequence by a given JavaScript function
val orderByJS : string -> ReqlExpr -> OrderBy
/// Order a sequence in descending order by a given JavaScript function
val orderByJSDescending : string -> ReqlExpr -> OrderBy
/// Create an outer join between two sequences, specifying the join condition with a function
val outerJoinFunc<'T> : obj -> (ReqlExpr -> ReqlExpr -> 'T) -> ReqlExpr -> OuterJoin
/// Create an outer join between two sequences, specifying the join condition with JavaScript
val outerJoinJS : obj -> string -> ReqlExpr -> OuterJoin
/// Select one or more attributes from an object or sequence
val pluck : string seq -> ReqlExpr -> Pluck
/// Replace documents
val replace : obj -> ReqlExpr -> Replace
/// Replace documents, providing optional arguments
val replaceWithOptArgs : obj -> ReplaceOptArg list -> ReqlExpr -> Replace
/// Replace documents using a function
val replaceFunc : (ReqlExpr -> obj) -> ReqlExpr -> Replace
/// Replace documents using a function, providing optional arguments
val replaceFuncWithOptArgs : (ReqlExpr -> obj) -> ReplaceOptArg list -> ReqlExpr -> Replace
/// Replace documents using JavaScript
val replaceJS : string -> ReqlExpr -> Replace
/// Replace documents using JavaScript, providing optional arguments
val replaceJSWithOptArgs : string -> ReplaceOptArg list -> ReqlExpr -> Replace
/// Skip a number of elements from the head of a sequence
val skip : int -> ReqlExpr -> Skip
/// Ensure changes to a table are written to permanent storage
val sync : Table -> Sync
/// Return all documents in a table (may be further refined)
val table : string -> Db -> Table
/// Return all documents in a table from the default database (may be further refined)
val fromTable : string -> Table
/// Create a table in the given database
val tableCreate : string -> Db -> TableCreate
/// Create a table in the connection-default database
val tableCreateInDefault : string -> TableCreate
/// Drop a table in the given database
val tableDrop : string -> Db -> TableDrop
/// Drop a table from the connection-default database
val tableDropFromDefault : string -> TableDrop
/// Get a list of tables for the given database
val tableList : Db -> TableList
/// Get a list of tables from the connection-default database
val tableListFromDefault : unit -> TableList
/// Update documents
val update : obj -> ReqlExpr -> Update
/// Update documents, providing optional arguments
val updateWithOptArgs : obj -> UpdateOptArg list -> ReqlExpr -> Update
/// Update documents using a function
val updateFunc : (ReqlExpr -> obj) -> ReqlExpr -> Update
/// Update documents using a function, providing optional arguments
val updateFuncWithOptArgs : (ReqlExpr -> obj) -> UpdateOptArg list -> ReqlExpr -> Update
/// Update documents using JavaScript
val updateJS : string -> ReqlExpr -> Update
/// Update documents using JavaScript, providing optional arguments
val updateJSWithOptArgs : string -> UpdateOptArg list -> ReqlExpr -> Update
/// Exclude fields from the result
val without : string seq -> ReqlExpr -> Without
/// Merge the right-hand fields into the left-hand document of a sequence
val zip : ReqlExpr -> Zip
// ~~ RETRY FUNCTIONS ~~
/// Retry, delaying for each the seconds provided (if required)
val withRetry<'T> : float seq -> (IConnection -> Task<'T>) -> (IConnection -> Task<'T>)
/// Retry, delaying for each the seconds provided (if required)
val withAsyncRetry<'T> : float seq -> (IConnection -> Async<'T>) -> (IConnection -> Async<'T>)
/// Retry, delaying for each the seconds provided (if required)
val withSyncRetry<'T> : float seq -> (IConnection -> 'T) -> (IConnection -> 'T)
/// Retry failed commands with 200ms, 500ms, and 1 second delays
val withRetryDefault<'T> : (IConnection -> Task<'T>) -> (IConnection -> Task<'T>)
/// Retry failed commands with 200ms, 500ms, and 1 second delays
val withAsyncRetryDefault<'T> : (IConnection -> Async<'T>) -> (IConnection -> Async<'T>)
/// Retry failed commands with 200ms, 500ms, and 1 second delays
val withSyncRetryDefault<'T> : (IConnection -> 'T) -> (IConnection -> 'T)
/// Retry failed commands one time with no delay
val withRetryOnce<'T> : (IConnection -> Task<'T>) -> (IConnection -> Task<'T>)
/// Retry failed commands one time with no delay
val withAsyncRetryOnce<'T> : (IConnection -> Async<'T>) -> (IConnection -> Async<'T>)
/// Retry failed commands one time with no delay
val withSyncRetryOnce<'T> : (IConnection -> 'T) -> (IConnection -> 'T)

View File

@ -23,7 +23,7 @@ open RethinkDb.Driver.FSharp
let getPost postId conn = let getPost postId conn =
rethink<Post> { rethink<Post> {
fromTable "Post" withTable "Post"
get postId get postId
resultOption resultOption
withRetryOptionDefault conn withRetryOptionDefault conn
@ -31,7 +31,7 @@ let getPost postId conn =
let updatePost post conn = let updatePost post conn =
rethink { rethink {
fromTable "Post" withTable "Post"
get post.id get post.id
update post update post
write write
@ -45,22 +45,24 @@ let updatePost post conn =
```fsharp ```fsharp
open RethinkDb.Driver.FSharp.Functions open RethinkDb.Driver.FSharp.Functions
// NOTE: this returns Task<Post>; checking for null/option is not handled // Remove the conn parameter and usage for point-free style
// as it is with the CE version
let getPost postId conn = let getPost postId conn =
fromTable "Post" fromTable "Post"
|> get postId |> get postId
|> runResult<Post> |> runResult<Post>
|> withRetryDefault conn |> asOption
|> withRetryDefault
|> withConn conn
// NOTE: this returns Task<Result>; ignoring inline is not available as
// it is with the CE version
let updatePost post conn = let updatePost post conn =
fromTable "Post" fromTable "Post"
|> get post.id |> get post.id
|> update post |> update post
|> runWrite |> runWrite
|> withRetryDefault conn |> ignoreResult
|> withRetryDefault
|> withConn conn
``` ```
### Retry Logic ### Retry Logic
@ -76,5 +78,10 @@ Many RethinkDB commands support optional arguments to tweak the behavior of that
between 1 100 [ LowerBound Open; UpperBound Closed ] between 1 100 [ LowerBound Open; UpperBound Closed ]
// ... // ...
``` ```
---
[csharp-pkg]: https://www.nuget.org/packages/RethinkDb.Driver/ More information is available on the [project site][].
[csharp-pkg]: https://www.nuget.org/packages/RethinkDb.Driver/
[project site]: https://bitbadger.solutions/open-source/rethinkdb-driver-fsharp/

View File

@ -3,22 +3,28 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks> <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
<Description>Idiomatic F# extensions on the official RethinkDB C# driver</Description> <Description>Idiomatic F# extensions on the official RethinkDB C# driver</Description>
<Authors>Daniel J. Summers</Authors> <Authors>Daniel J. Summers,Bit Badger Solutions</Authors>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression> <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/danieljsummers/RethinkDb.Driver.FSharp</PackageProjectUrl> <RepositoryUrl>https://github.com/bit-badger/RethinkDb.Driver.FSharp</RepositoryUrl>
<PackageIconUrl>https://github.com/danieljsummers/RethinkDb.Driver.FSharp/raw/main/pkg/icon.png</PackageIconUrl> <RepositoryType>git</RepositoryType>
<PackageProjectUrl>https://bitbadger.solutions/open-source/rethinkdb-driver-fsharp/</PackageProjectUrl>
<PackageIcon>icon.png</PackageIcon> <PackageIcon>icon.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<Copyright>See LICENSE</Copyright> <Copyright>See LICENSE</Copyright>
<PackageTags>RethinkDB document F#</PackageTags> <PackageTags>RethinkDB document F#</PackageTags>
<VersionPrefix>0.9.0</VersionPrefix> <VersionPrefix>0.9.0</VersionPrefix>
<VersionSuffix>beta-01</VersionSuffix> <VersionSuffix>beta-03</VersionSuffix>
<PackageReleaseNotes>
Retry logic now works with functions; added signature for function moduel and explicit type annotations to the
DSL builder
</PackageReleaseNotes>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Retry.fs" /> <Compile Include="Retry.fs" />
<Compile Include="OptArgs.fs" /> <Compile Include="OptArgs.fs" />
<Compile Include="Functions.fsi" />
<Compile Include="Functions.fs" /> <Compile Include="Functions.fs" />
<Compile Include="Builder.fs" /> <Compile Include="Builder.fs" />
<Compile Include="Config.fs" /> <Compile Include="Config.fs" />