I’m trying to wrap my head around how to use the Caqti infix module (it seems the regular one was deprecated.
So I created the following query
let get_user id =
let query =
let open Caqti_request.Infix in
(T.string ->! T.tup4 T.string T.string T.string (T.tup2 T.string T.bool))
"SELECT id, username, password, privkey, is_admin FROM users WHERE id = ?"
in
fun (module Db : DB) ->
Db.find_opt query id
It works and returns a (LWT result option) type.
I have a few questions:
What does each infix operator mean in caqti? We have ->., ->! and then there is -->! -->. etc.
I have gathered so far that ->. is for unit operations, ->! for when it must return one result and ->? for then the result is optional. However I do not understand the extended arrows.
From what I gather, first parameter for the infix parameter is basically “the input” and then the second parameter is the output. I found that there is Tup4 which I could use. However in this can I have 5 parameter and 4 seems to be the maximum, is there a more ergonomic way (like an infix operator) to handle many columns?
Sorry for not answering the asked question, but have you tried ppx_rapper? It automates away all this boilerplate and expresses queries using something very much like string interpolation–of course, using prepared statement and binding values.
From the docs, the extra - infix operators take a function as a third argument for creating a query (as opposed to a string). I believe the intention is for building up database agnostic queries.
I think Caqti_type ships up to t8 for 8-tuples. But you can compose many together (see caqti 2.0.1 · OCaml Package).
I did try it, but I couldn’t figure out how to make it work with the Dream web server, it expected
( (module Rapper_helper.CONNECTION),
([> Caqti_error.call_or_retrieve ] as 'e) )
Caqti_lwt.Pool.t
for a query I wrote
let many_arg_get_opt pool ~username =
let query =
[%rapper
get_opt
{sql|
SELECT @string{username}
FROM users
WHERE username = %string{username}
|sql}]
in
Caqti_lwt.Pool.use (query ~username) pool
and what you get from Dream is a Caqti_lwt.connection. I couldn’t quite work out the types in order to use query with a caqti connection, only with a pool.
So I can’t find the Caqti method that takes query (module Rapper_helper.CONNECTION) -> (string option, [> Caqti_error.call_or_retrieve ]) result Lwt.t
EDIT: Argh just had a second look at the types, and it seems that Rapper_helper.CONNECTION Is equivalent to the Caqti_lwt.connection. That solves the issue.
Dream.sql request (fun db ->
let query = [%rapper get_opt {sql| MY SQL REQUEST |sql}] in
match%lwt query db with
OK (Some (...)) -> ...
| OK (None) -> ...
| Error err -> ...
)
Ad 1, the API documentation was update in the latest release. I think it should be much more clear than in the release you’re using. I would very much like to know if something is still unclear in that version.
Ad 2, the latest release has tuples up to 8 components, and the next release will have up to 12 components. Since the introduction of product types in the API, it is also fairly simple for the end-user to add higher tuples if needed.