Skip to content

Basic concepts

Jacek edited this page Oct 29, 2017 · 24 revisions

How to represent query in code?

Of course, as a function. Query parameters could be reflected as function parameters, its result as function return type.

E.g. the query:

    select id, name, title, description, owner, createdAt, modifiedAt, modifiedBy 
    from Blog 
    where id = @id

could be implemented as a function of type:

    int -> IDbConnection-> Blog

Actually, instead of IDbConnection, SqlFun uses DataContext type, encapsulating connection and transaction:

    int -> DataContext -> Blog

SqlFun alows to generate such a function:

    let getBlog: int -> DataContext -> Blog = 
        sql "select id, name, title, description, owner, createdAt, modifiedAt, modifiedBy 
             from Blog 
             where id = @id"

where sql is a function responsible for building query functions using runtime code generation. It generates:

  • mappings between function parameters and query parameters
  • mappings between query result and function result
  • all needed type conversions
  • command execution

A side-effect of code generation is a validation of sql commands and all necessary type checking (i.e. whether function parameter types match query parameter types and whether function and query results are compatible).

Couple of functions can be grouped in a module:

    module Blogging =     
        let getBlog: int -> DataContext -> Blog = ...
        let getPosts: int -> DataContext -> Post list = ...
        let getComments: int -> DataContext -> Comment list = ...

We don't need any cache. Assigning generated functions to variables is perfectly enough. And, since all variables are evaluated and assigned during the first access to the module contents, we obtain some level of type safety almost for free (one unit test per module is needed).

Clone this wiki locally