I am trying to get execute sql query statement but seems not to be a success. What could I be doing wrong?
I have the following modules and the main is executed via dune exec ...main.exe
(* ./drop_tbl.ml *)
open Caqti_request.Infix
module T = Caqti_type
let drop_table (module Db : Caqti_lwt.CONNECTION) =
let query = (T.unit -->. T.unit) @:- Printf.sprintf "DROP DATABASE mydb" in
let%lwt unit_or_error = Db.exec query () in
Caqti_lwt.or_fail unit_or_error
(*./main.ml *)
(* FIXME: use environment variable. *)
let database_url = "postgresql://localhost:<default port>/postgres"
let db =
(module (val let connect = Caqti_lwt.connect (Uri.of_string database_url) in
Lwt_main.run (Lwt.bind connect Caqti_lwt.or_fail))
: Caqti_lwt.CONNECTION)
let () =
let drop_tbl = Lwt.return_ok (drop_tbl.drop_table db) in
match Lwt_main.run drop_tbl with
| Ok _ -> Printf.printf "Successful set up"
| Error e -> Printf.printf "Error: %s" (Caqti_error.show e)
; dune file
(executable
(name main)
(public_name main)
(libraries
caqti-driver-postgresql
caqti
caqti-lwt)
(preprocess
(pps lwt_ppx)))
Edited: Changed module name and function names (create → drop) to reflect the query statement (which I changed after their creation at the time)
You kinda double wrapped a promise, which looks wrong to me.
I think you can simplify your library code that way:
(* ./drop_tbl.ml *)
open Caqti_request.Infix
module T = Caqti_type
let drop_table (module Db : Caqti_lwt.CONNECTION) =
let query = (T.unit -->. T.unit) @:- Printf.sprintf "DROP DATABASE mydb" in
Db.exec query
And let the binary execute the definitions of your queries (my terminology may be wrong here):
(*./main.ml *)
let get_uri () =
let env_vars =
let ( let* ) = Option.bind in
let* pg_host = Sys.getenv_opt "PGHOST" in
let* pg_port = Sys.getenv_opt "PGPORT" in
let* pg_database = Sys.getenv_opt "PGDATABASE" in
Some (pg_host, pg_port, pg_database)
in
match env_vars with
| Some (pg_host, pg_port, pg_database) ->
Printf.sprintf "postgresql://%s:%s/%s" pg_host pg_port pg_database
| None -> "postgresql://" (* use system defaults *)
let db =
(module (val let connect = Caqti_lwt.connect (Uri.of_string (get_uri ())) in
Lwt_main.run (Lwt.bind connect Caqti_lwt.or_fail))
: Caqti_lwt.CONNECTION)
let () =
let promise = Lib.drop_table db () in
match Lwt_main.run promise with
| Ok () -> Printf.printf "I've dropped the table!"
| Error e -> Printf.printf "Got an error: %s" (Caqti_error.show e)
What helped me studying Caqti is to pay particular attention to the types.
As a way of contributing, I’ve been working on a documentation project here: GitHub - benjamin-thomas/caqti-study at v1
It’ still a WIP, but in the meantime, maybe browsing through it will give you a few ideas on how to get going.
4 Likes
When you match on Ok _
you discard the premise holding the execution of the SQL statement (so, a double promise, as noted). The promise is scheduled anyway, but Lwt_main.run drup_table
exits immediately since drop_table
is a resolved-by-construction promise, which terminates the scheduler before reaching the real task. (At least that’s may understanding of Lwt.)
1 Like
Thank you @benjamin-thomas and @paurkedal.
I was able to follow up closely on project @benjamin-thomas linked, and I got my tiny program running well. I also agree that Caqti and Lwt require some great attention to the types for a fair grasp.