fsharp-dapper icon indicating copy to clipboard operation
fsharp-dapper copied to clipboard

How to use this library in a testable way?

Open dedale opened this issue 4 years ago • 1 comments

Hello,

I want to extract the connection part from the code to make it testable. I have introduced a class like the following:

module Queries =
    type Schema (connectionF: unit -> Connection) =

        member __.CreateTables () = querySingleAsync<int> connectionF {
            script """
                DROP TABLE IF EXISTS Bird;
                CREATE TABLE Bird (
                    Id INTEGER NOT NULL PRIMARY KEY,
                    Name VARCHAR(255) NOT NULL,
                    Alias VARCHAR(255) NULL
                );
            """
    }

Unfortunately, when I try to create the schema, I get the following exception:

System.InvalidOperationException: Sequence contains no elements at System.Linq.ThrowHelper.ThrowNoElementsException() at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source) at Dapper.SqlMapper.ThrowZeroRows(Row row) in C:\projects\dapper\Dapper\SqlMapper.cs:line 1160 at Dapper.SqlMapper.QueryRowAsync[T](IDbConnection cnn, Row row, Type effectiveType, CommandDefinition command) in C:\projects\dapper\Dapper\SqlMapper.Async.cs:line 485

If I add the following to Queries module, it works as expected:

let private mkOnDiskConnectionString (dataSource: string) = sprintf "Data Source = %s;" dataSource
let mkOnDisk () = new SqliteConnection (mkOnDiskConnectionString "./example.db")
let private connectionF2 () = Connection.SqliteConnection (mkOnDisk())
let querySeqAsync2<'R> = querySeqAsync<'R> (connectionF2)
let querySingleAsync2<'R> = querySingleOptionAsync<'R> (connectionF2)
member __.CreateTables () = querySingleAsync2<int> {
    script """ ... """
}

What should I do to extract the connection part ? I cannot move QueryBuilders to Schema type because of generic parameters...

Thanks for your help!

dedale avatar Jan 04 '21 10:01 dedale

Well it seems, I can by pass the problem removing the generic parameter:

        let querySingleAsync = querySingleOptionAsync<int> connectionF

        member __.CreateTables () = querySingleAsync {
            script """ ... """
        }

But I do not understand why I need to create intermediary querySingleAsync variable?

dedale avatar Jan 04 '21 10:01 dedale