How to get a Caqti_eio.stdenv from a Eio_unix.Stdenv.base

Caqti_eio has a function which needs a parameter of type

type stdenv = <
  net : [`Generic] Eio.Net.ty Eio.Std.r;
  clock : float Eio.Time.clock_ty Eio.Std.r;
  mono_clock : Eio.Time.Mono.ty Eio.Std.r;
>

If I feed it with a Caqti_eio.stdenv given by Eio_main.run, I have the error:

File "main.ml", line 9, characters 47-53:
9 |                     Caqti_eio.with_connection ~stdenv
                                                   ^^^^^^
Error: This expression has type Eio_unix.Stdenv.base
       but an expression was expected of type Caqti_eio.stdenv
       The second object type has no method backend_id

I do understand that the object I give implements to many methods (backend_id is one of them). On most languages, there is an issue when there is not enough methods.

Is there a simple way to have a an object which match the type (just the 3 needed methods) based on stdenv:Eio_unix.Stdenv.base.

I have tried to patch caqtiand add a .. to tolerate other methods, but this doesn’t compile anymore:

65 | type stdenv = <
66 |   net : [`Generic] Eio.Net.ty Eio.Std.r;
67 |   clock : float Eio.Time.clock_ty Eio.Std.r;
68 |   mono_clock : Eio.Time.Mono.ty Eio.Std.r;
69 |   ..
70 | >
Error: A type variable is unbound in this type declaration.
       In type
         < clock : float Eio.Time.clock_ty Eio.Std.r;
           mono_clock : Eio.Time.Mono.ty Eio.Std.r;
           net : [ `Generic ] Eio.Net.ty Eio.Std.r; .. >
         as 'a the variable 'a is unbound

(The error doesn’t print without the ..).

Could you give a slightly more complete but still minimalistic code sample which we can use to try to debug the issue?

I end up to (with a patched ppx_rapper to support Caqti.2.x):

let create_query = [%rapper execute "CREATE TABLE t (a INTEGER, b INTEGER)" ]

class caqti_env (stdenv:Eio_unix.Stdenv.base) = object
  val s = stdenv
  method net = s#net
  method clock = s#clock
  method mono_clock = s#mono_clock
end

let () =
  match
    Eio_main.run @@ fun stdenv ->
                    Caqti_eio.with_connection ~stdenv:(new caqti_env stdenv)
                      (Uri.of_string "sqlite3:essai.sqlite")
                      (function cnx ->
                         let* () = create_query () cnx in
                         Result.Ok ()
                      )
  with
    | Result.Ok () ->
       output_string "OK\n"
    | Result.Error err ->
       output_string (Caqti_error.show err)

converting stdenv to new caqti_env stdenv did solved the method issue, but I find the method a little heavy. I guess I should work on a better way.

However, I get a new issue: the stdenv#net returns something of type

[ `Generic | `Unix ] Eio.Net.ty Eio.Resource.t

And the `Unix is not accepted by Caqti_eio.

EDIT: I had an simple answer here… Eio: stdenv type not compatiable with Eio_unix.Stdenv · Issue #114 · paurkedal/ocaml-caqti · GitHub just type stdenv :> Caqti_eio.stdenv

But now, I have the error at the execution:

Failed to load driver for <sqlite3:essai.sqlite>: Neither caqti-driver-sqlite3 nor the dynamic linker is linked into the application.

Curious. The Lwt version works fine, and there is the following stanza in my dune file:

  (libraries
      ppx_rapper_eio
      eio eio_main
      caqti-eio
      caqti-driver-sqlite3)

It’s because Caqti_eio.with_connection’s signature requires something of type Caqti_eio.stdenv rather than <Caqti_eio.stdenv; .. >. You could work around it by putting this at the start:

module Caqti_eio = struct
  include Caqti_eio

  let with_connection ~stdenv uri fn =
    with_connection ~stdenv:(stdenv :> stdenv) uri fn
end

See the Passing env section of the README for more on this.