Dream.sql / PostgreSQL / ppx_rapper: incompatible types
El-Profesor opened this issue · comments
Attempt to get Dream working with ppx_rapper but get the following type error:
Error: This expression has type
unit ->
(module Rapper_helper.CONNECTION) ->
((string * string) option, [> Caqti_error.call_or_retrieve ]) result
Lwt.t
but an expression was expected of type
Caqti_lwt.connection -> 'a Lwt.t
Type unit is not compatible with type
Caqti_lwt.connection = (module Caqti_lwt.CONNECTION)
Hint: Did you forget to provide `()' as argument?
I'm relatively new to OCaml, I understand the error, but I couldn't get the following code (commented ppx_rapper version) to work.
Any idea about this ? Thanks in advance.
module type DB = Caqti_lwt.CONNECTION
module T = Caqti_type
(* (1) ----- Does not work (ppx_rapper version)
let list_buyers =
[%rapper
get_many
{sql|
SELECT @string{first_name}, @string{last_name}
FROM buyer
|sql}] *)
(* (2) ----- Works (Caqti version) *)
let list_buyers =
let query =
let open Caqti_request.Infix in
(T.unit ->* T.(tup2 string string))
"SELECT first_name, last_name FROM buyer" in
fun (module Db : DB) ->
let%lwt buyers_or_error = Db.collect_list query () in
Caqti_lwt.or_fail buyers_or_error
let render buyers request =
<html>
<body>
% buyers |> List.iter (fun (_id, buyer) ->
<p><%s buyer %></p><% ); %>
<form method="POST" action="/">
<%s! Dream.csrf_tag request %>
<input name="text" autofocus>
</form>
</body>
</html>
let () =
Dream.run
@@ Dream.logger
@@ Dream.sql_pool "postgresql://mentor:superMentor@localhost/dream_market"
@@ Dream.sql_sessions
@@ Dream.router [
Dream.get "/" (fun request ->
let%lwt buyers = Dream.sql request list_buyers in
Dream.html (render buyers request));
]
I don't currently know ppx_rapper, and you didn't show which error the line is on, but it appears the error says list_buyers
, generated by ppx_rapper, has an extra unit argument (generated by ppx_rapper). Could you do something like
let list_buyers connection =
[%rapper
get_many
{sql|
SELECT @string{first_name}, @string{last_name}
FROM buyer
|sql}]
() connection
Thanks a lot for you reply @aantron.
« you didn't show which error the line is on »
File "bin/main.eml.ml", line 43, characters 41-52
which corresponds to:
let%lwt buyers = Dream.sql request list_buyers in`
Dream.html (render buyers request));
Sorry for missing this detail. Also, I thought ppx_rapper’s Dream integration was planned (Dream Wiki > Roadmap).
There is no integration with ppx_rapper planned. The roadmap says to study ppx_rapper -- I haven't done so yet :) Did my suggestion help?
Your suggestion only partially solved the type error, but it helped me realize that I need to learn OCaml more in depth before I can continue experimenting Dream.
But I hope to contribute to the Dream project in a while!
Thank you for your great work on Dream.
Note: If you're curious about it, here is the error message when applying your suggestion:
Error: This expression has type
((string * string) list, [> Caqti_error.call_or_retrieve ]) result
but an expression was expected of type ('a * string) list
which corresponds to the second line below:
let%lwt buyers = Dream.sql request list_buyers in
Dream.html (render buyers request));
Absolutely I'm curious about it :) At this point, you need to pattern-match on the result of running the SQL query, because it might fail. Something like
let%lwt buyers = Dream.sql request list_buyers in
match buyers with
| Error _ ->
assert false (* But you should figure out how you actually want to handle this, if it is even possible. *)
| Ok buyers ->
Dream.html (render buyers request)
There are other ways of writing it, such as using Result.get_ok
(if the error is impossible) or match%lwt
:
match%lwt Dream.sql request list_buyers with
| Error _ ->
assert false (* But you should figure out how you actually want to handle this, if it is even possible. *)
| Ok buyers ->
Dream.html (render buyers request)
There are also probably various operators that propagate errors around until you actually want to handle them, but they would come from Caqti or ppx_rapper and I'm not familiar with them off the top of my head.
Both solutions work perfectly.
Now I have to understand why they work... So it’s time for me to study OCaml in depth.
I hope to be back here in a while.
Thank you very much for the explanations and for your help.