Skip to content

Error handling

Jacek Hełka edited this page Apr 1, 2024 · 6 revisions

Simple queries

DbFun relies on hand-written SQL and runtime code generation. It's not type-safe in a usual meaning. But there is quite nice equivalent. Since all query functions are generated during their module initialization, we need only one test for each data access module. E.g. to type-check the module:

module Blogging =     
    let getBlog = query.Sql<int, Blog>( ...
    let getNumberOfPosts = query.Sql<int, int>( ... 
    let getPost = query.Sql<int, Post>( ...

the following test is enough:

[<Test>]
member this.``Blogging module passes type checks``() = 
    Blogging.getBlog |> ignore

Accessing one module member triggers initialization of remaining members. During code generation DbFun executes query in SchemaOnly mode and tries to generate all needed type conversions. Typos in SQL and incorrect parameter or return types results in exceptions. The downside is, that NULL checks cannot be performed this way.

Error reports

Another downside of this approach is, that we cannot obtain full error report, since code generation breaks after first error. To improve it, the QueryBuilder.LogCompileTimeErrors() method has been provided. It creates new QueryBuilder, that intercepts code generation exceptions and collects them as CompileTimeErrors property.

To use it, add follwing code to each data access module:

module Blogging = 
    let query = query.LogCompileTimeErrors()
    ...

Then, add one test per module, like this:

[<Fact>]
let ``TestQueries passes compile-time checks``() =
    Assert.True(Blogging.query.CompileTimeErrors.IsEmpty, sprintf "%A" Blogging.query.CompileTimeErrors)
Clone this wiki locally