PostgreSQL-OCaml und die Result-Monade
Ein kleines Beispiel für ein OCaml-Modul, das eine DB-Tabelle und dazugheörige Abfragen repräsentiert. Für die Kommunikation mit der Datenbank verwenden wir PostgreSQL-Ocaml. Als Standardbibliothek und zum Logging kommt Batteries Included zum Einsatz.
In der Funktion für die Abfrage eines Datensatzes (select
) wird die die
Result-Monade mit der relativ neuen (OCaml 4.08.0) let*
-Syntax für das
monadische bind
verwendet. Siehe dazu auch den Blogbeitrag
OCaml has some new shiny syntax.
(* foo.ml
DB:
create table public.foo (
id serial primary key,
name text not null
);
*)
open! Batteries
open! BatLog.Easy
type t = {
id : int;
name : string;
}
let t_qs_base = "select id, name from public.foo"
let of_row r = {
id = int_of_string r.(0);
name = r.(1);
}
let select_exec (conn:Postgresql.connection) id =
let params = [|string_of_int id|] in
let qs = t_qs_base ^ " where id = $1;" in
let expect = [Postgresql.Tuples_ok] in
try Result.Ok (conn#exec ~params ~expect qs)
with Postgresql.Error e -> begin
log `error (Postgresql.string_of_error e) ;
Result.Error (Postgresql.Error e)
end
let select_result (res:Postgresql.result) =
if res#ntuples <> 1 then Result.Ok None
else Result.Ok (Some (of_row (res#get_tuple 0)))
let (let*) x f = Result.bind x f
let select conn id =
let* res = select_exec conn id in
select_result res
Die Schnittstelle des Moduls sieht so aus:
(* foo.mli *)
open! Batteries
type t = {
id : int;
name : string;
}
val select : Postgresql.connection -> int -> (t option, exn) Result.t
Der Punkt dieses Beispiels ist, dass der Code zur Abfrage der Datenbank dank
der Result-Monade und der let*
-Syntax flach und einfach nachvollziehbar
bleibt.