Dependency Injection Strategies

Folks, I have been toying around with SqlFun and have some questions regarding its design choices. Considering the README, this is how you are supposed to write code on it:

module Database =
    // ...
    let createConnection () = new SqliteConnection("Data Source=:memory:")
    let config = createDefaultConfig createConnection
    let runAsync f = createConnection f

module Repository =
    open Database
	// ...

    module Account =
        let create: Account -> AsyncDb<Account.Username> =
            sql config "INSERT INTO account (username, password) VALUES (@username, @password) RETURNING username;"

In this case, you can see that the module Repository depends on the variable config from the module Database. In this sense, if I were to configure my string connection, I would have something like this:

module Configuration =
    // imagine some private logic happening here
	let sqlConnection =
		sprintfn "Data Source=%s" config.Database.Host

module Database =
   open Configuration
   // ...
   let createConnection () = new SqliteConnection(sqlConnection)

It seems weird to me that this depends exclusively on runtime checks and not compile time checks, although I like how it works as you just evaluate things at the module execution. Anyway, my questions are:

  • Is there a name for this kind of dependency injection strategy?
  • Is this considered good?

Here’s my solution:

module Database =
    let createConnection str () = new SqliteConnection(str)
    let run connection f = connection f

    let sql connection command =
        let config = createDefaultConfig connection
        sql config command

module Workflow =
    module Account =
        type Find = string -> string

module Repository =
    module Account =
        let find connection =
            let query: string -> DbAction<string> = 
                Database.sql connection "select username from account where username = @username"

            fun username -> 
                query username |> connection