I’m trying to get connected to a Postgres database and have been trying to get darioteixeira/pgocaml (opam install pgocaml pgocaml_ppx
) to work but I continue to have issues with it. Based on this post I pinned the dev version (opam pin --dev pgocaml_ppx
) with OCaml version 4.12.
Is there another Postgres library that is maybe a bit more maintained?
Any thoughts on how to get this working easily would be much appreciated.
When I execute a simple query it fails:
open PGOCaml
let get_db_schema =
let dbh = PGOCaml.connect () in
let res =
[%pgsql.object
dbh
"select
table_schema,
table_name
from information_schema.columns
where table_schema not in ('information_schema', 'pg_catalog')
order by table_schema,
table_name"]
in
let a =
List.iter
(fun row ->
Printf.printf "%s makes $%f\n" row#table_schema row#table_name)
res
in
PGOCaml.close dbh;
Error:
File "lib/db.ml", line 24, characters 31--660:
Error: Unbound value name_of_string
Hint: Did you mean date_of_string or time_of_string?
And if I follow the docs and try let%lwt res =
by adding %lwt
, the compiler doesn’t know anything about the extension:
15 | let%lwt res =
^^^
Error: Uninterpreted extension 'lwt'.
PGOcaml makes a best effort to decode Postgres types, but those information_schema tables define their own types (information_schema.sql_identifier
is the offender here I think) which PGOcaml doesn’t have built-in converter functions for. It’s actually possible to add extra type conversions, but there’s a much easier solution.
let res =
[%pgsql.object
dbh
"select
table_schema::text,
table_name::text
from information_schema.columns
where table_schema not in ('information_schema', 'pg_catalog')
order by table_schema,
table_name"]
Note the coercion to text
- PGOcaml then just sees them as strings and can decode them without any trouble.
It’s the price you pay for being able to write typed SQL.
1 Like
That was it @lepoetemaudit, thanks for the help!
@gregberns no problem at all. PGOcaml sorely lacks some simple ‘how to’ guides that would make it much smoother to use in my opinion. It took me two days to figure out how to get it working with Lwt! If you run into any trouble there, let me know as I have working examples. I use PGOcaml with Lwt in production and it is actually great - the reception I’ve had from other devs has been very positive in a project where I’d already set it up… With a bit of care you can have fairly dynamic queries with optional filters etc.,
I slightly prefer not using the object
version of the PPX and instead mapping the tuple straight into a record, but that’s mostly a matter of taste (I kind of wish the PPX could do that for me but it’s minimal and mapping makes it easier to tweak any types or values before you store them in a record for consumption elsewhere)
1 Like
@lepoetemaudit Any examples you have would be excellent. Is there information about Lwt somewhere, like what is it and what does it provide?
Thats an interesting note about the tuples, I did use the object last night but maybe I’ll try with the tuples tonight.
@lepoetemaudit RE: examples. In the name of generating more public content, I’ve been trying to ask StackOverflow questions, even if I’m answering them - if possible we could take your examples and get them into SO as Q&As…
Lwt provides JavaScript-like promises for concurrent programming. More details here Lwt manual
I’d say in terms of Lwt, if you don’t think you need it, it’s much easier to do without it. I use Lwt with PGOcaml as everything is in an asynchronous context with what I’m doing, and Lwt also has some nice modules for things like connection pooling. But using promises definitely complicates matters!
SO answers are better than nothing, but I think a PR back to PGOcaml improving the docs is the best solution overall. I am guilty of not doing this enough. There’s an outstanding issue already for this at least: PGOCaml discovery - Documentation and sample code · Issue #96 · darioteixeira/pgocaml · GitHub
For some context, PGOcaml uses a common pattern in OCaml libraries of functors to abstract its functionality, so the same library code can be adapted to different “backends” - so PGOCaml can work with Lwt, Async (another concurrency library) or potentially any future threading or concurrency library as long as you can provide an adapter). The main PGOcaml module itself is actually just that generic functor instantiated with a basic backend assuming very direct usage: pgocaml/PGOCaml.ml at master · darioteixeira/pgocaml · GitHub
2 Likes