Hello!
I’m having issues trying to structure my project better with Caqti.
Firstly, I define a customer_repo.ml
file like this:
(* ./lib/customer_repo.ml *)
module Q = struct
open Caqti_request.Infix
let create_tbl =
Caqti_type.(unit ->. unit)
@@ {|
CREATE TABLE IF NOT EXISTS customers
( id INTEGER PRIMARY KEY AUTOINCREMENT
, first_name VARCHAR(255)
, last_name VARCHAR(255)
)
|}
;;
let insert =
Caqti_type.(tup2 string string ->. unit)
@@ {|
INSERT INTO customers (first_name, last_name)
VALUES (?, ?)
|}
;;
end
let create_tbl (module Db : Caqti_lwt.CONNECTION) = Db.exec Q.create_tbl
let insert (module Db : Caqti_lwt.CONNECTION) first_name last_name =
Db.exec Q.insert (first_name, last_name)
;;
Then I create a binary that will only be concerned about setting up the database:
(* ./bin/setup.ml *)
module Db : Caqti_lwt.CONNECTION =
(val let cwd = Sys.getcwd () in
let path = Printf.sprintf "sqlite3://%s/db.sqlite3" cwd in
let connect = Caqti_lwt.connect (Uri.of_string path) in
Lwt_main.run (Lwt.bind connect Caqti_lwt.or_fail))
let info_log fmt = Printf.printf ("[INFO] " ^^ fmt ^^ "\n%!")
let err_log fmt = Printf.printf ("[ERROR] " ^^ fmt ^^ "\n%!")
let () =
let open Lwt_result.Syntax in
let all_promises : (unit, 'error) result Lwt.t =
let* () = Lib.Customer_repo.create_tbl Db () in
let* () = Lib.Customer_repo.insert Db "John" "Doe" in
Lwt.return_ok ()
in
Lwt_main.run all_promises |> function
| Ok () -> info_log "Setup OK!"
| Error e -> err_log "%s" (Caqti_error.show e)
;;
The issue comes from (module Db : Caqti_lwt.CONNECTION)
, which looks like a function parameter that could be passed around.
However, I get this type error which I don’t understand:
Error: This expression should not be a constructor, the expected type is (module Caqti_lwt.CONNECTION)
It seems to me that I’m passing specifically a module that has the type Caqti_lwt.CONNECTION
.
I fact, I don’t really understand this definition:
module Db : Caqti_lwt.CONNECTION =
(val let cwd = Sys.getcwd () in
let path = Printf.sprintf "sqlite3://%s/db.sqlite3" cwd in
let connect = Caqti_lwt.connect (Uri.of_string path) in
Lwt_main.run (Lwt.bind connect Caqti_lwt.or_fail))
I understand I’m initializing a module correctly (I can see the many functions it provides), but I’m confused about the “val syntax”, what it represents, what this type of module is exactly, and what I can do/not do with it.
If I define this module in customer_repo.ml
directly, and stop trying to pass it around as a function parameter, then it works!
But I can also see that receiving the module as a function parameter is valid syntax too, if I look at the bikereg example. So I’m obviously confused.
I looked at various module docs, but nothing seems to fit. I’ve learnt about modules as a way to namespace things, control the private/public status of its functions via mli
files and have only a very basic understanding of functors (I haven’t learnt them properly yet).
But this module seems to be something else. What am I missing?