[28] 20.11.2021 17:37
Code-Beispiel: PostgreSQL-OCaml und die Result-Monade

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.


[->/]