diff --git a/README.md b/README.md index 50ca87e..d0b8146 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,15 @@ let fetchPost (postId : string) = } ``` -### A standard way to translate JSON into a strongly-typed configuration +### A standard way to translate JSON or a URI into a strongly-typed configuration ```fsharp /// type: DataConfig let config = DataConfig.fromJsonFile "data-config.json" // OR let config = DataConfig.fromConfiguration (config.GetSection "RethinkDB") +// OR +let config = DataConfig.fromUri (config.GetConnectionString "RethinkDB") /// type: IConnection let conn = config.Connect () diff --git a/src/RethinkDb.Driver.FSharp/Config.fs b/src/RethinkDb.Driver.FSharp/Config.fs index 8a1c620..b071cce 100644 --- a/src/RethinkDb.Driver.FSharp/Config.fs +++ b/src/RethinkDb.Driver.FSharp/Config.fs @@ -1,5 +1,6 @@ namespace RethinkDb.Driver.FSharp +open System open Microsoft.Extensions.Configuration open Newtonsoft.Json.Linq open RethinkDb.Driver @@ -72,6 +73,20 @@ type DataConfig = | Some (Database x) -> x | _ -> RethinkDBConstants.DefaultDbName + /// The effective configuration URI (excludes password / auth key) + member this.EffectiveUri = + seq { + "rethinkdb://" + match this.Parameters |> List.tryPick (fun x -> match x with User _ -> Some x | _ -> None) with + | Some (User (username, _)) -> $"{username}:***pw***@" + | _ -> + match this.Parameters |> List.tryPick (fun x -> match x with AuthKey _ -> Some x | _ -> None) with + | Some (AuthKey _) -> "****key****@" + | _ -> () + $"{this.Hostname}:{this.Port}/{this.Database}/{this.Timeout}" + } + |> String.concat "" + /// Parse settings from JSON /// /// A sample JSON object with all the possible properties filled in: @@ -89,14 +104,14 @@ type DataConfig = static member FromJson json = let parsed = JObject.Parse json { Parameters = - [ match parsed["hostname"] with null -> () | x -> Hostname <| x.Value () - match parsed["port"] with null -> () | x -> Port <| x.Value () - match parsed["auth-key"] with null -> () | x -> AuthKey <| x.Value () - match parsed["timeout"] with null -> () | x -> Timeout <| x.Value () - match parsed["database"] with null -> () | x -> Database <| x.Value () - match parsed["username"], parsed["password"] with - | null, _ | _, null -> () - | userName, password -> User (userName.Value (), password.Value ()) + [ match parsed["hostname"] with null -> () | x -> Hostname <| x.Value () + match parsed["port"] with null -> () | x -> Port <| x.Value () + match parsed["auth-key"] with null -> () | x -> AuthKey <| x.Value () + match parsed["timeout"] with null -> () | x -> Timeout <| x.Value () + match parsed["database"] with null -> () | x -> Database <| x.Value () + match parsed["username"], parsed["password"] with + | null, _ | _, null -> () + | userName, password -> User (userName.Value (), password.Value ()) ] } @@ -108,11 +123,34 @@ type DataConfig = /// Parse settings from application configuration static member FromConfiguration (cfg : IConfigurationSection) = { Parameters = - [ match cfg["hostname"] with null -> () | host -> Hostname host - match cfg["port"] with null -> () | port -> Port (int port) - match cfg["auth-key"] with null -> () | key -> AuthKey key - match cfg["timeout"] with null -> () | time -> Timeout (int time) - match cfg["database"] with null -> () | db -> Database db - match cfg["username"], cfg["password"] with null, _ | _, null -> () | user -> User user + [ match cfg["hostname"] with null -> () | host -> Hostname host + match cfg["port"] with null -> () | port -> Port (int port) + match cfg["auth-key"] with null -> () | key -> AuthKey key + match cfg["timeout"] with null -> () | time -> Timeout (int time) + match cfg["database"] with null -> () | db -> Database db + match cfg["username"], cfg["password"] with null, _ | _, null -> () | user -> User user ] } + + /// Parse settings from a URI + /// + /// rethinkdb://user:password@host:port/database/timeout + /// OR + /// rethinkdb://authkey@host:port/database/timeout + /// + /// host is required, database is required if timeout is specified + static member FromUri (uri : string) = + let it = Uri uri + if it.Scheme <> "rethinkdb" then invalidArg "scheme" $"""URI scheme must be "rethinkdb" (was {it.Scheme})""" + { Parameters = + [ Hostname it.Host + if it.Port <> -1 then Port it.Port + if it.UserInfo <> "" then + if it.UserInfo.Contains ':' then + let parts = it.UserInfo.Split ':' |> Array.truncate 2 + User (parts[0], parts[1]) + else AuthKey it.UserInfo + if it.Segments.Length > 1 then Database it.Segments[1] + if it.Segments.Length > 2 then Timeout (int it.Segments[2]) + ] + } \ No newline at end of file diff --git a/src/RethinkDb.Driver.FSharp/README.md b/src/RethinkDb.Driver.FSharp/README.md index bcdcdfd..8b3a97b 100644 --- a/src/RethinkDb.Driver.FSharp/README.md +++ b/src/RethinkDb.Driver.FSharp/README.md @@ -10,6 +10,8 @@ open RethinkDb.Driver.FSharp let dataCfg = DataConfig.fromJson "rethink-config.json" // - or - let dataCfg = DataConfig.fromConfiguration [config-section] +// - or - +let dataCfg = DataConfig.fromUri [connection-string] let conn = dataCfg.CreateConnection () // IConnection ```