Skip to content

Instantly share code, notes, and snippets.

@adept
Created December 15, 2024 13:16
Show Gist options
  • Save adept/9088e2a80e7066b1af6388c021488892 to your computer and use it in GitHub Desktop.
Save adept/9088e2a80e7066b1af6388c021488892 to your computer and use it in GitHub Desktop.
module Jdbc : sig
type 'a connection
val connect : config:string -> [`regular] connection
(* execute sql statement, like "CREATE TABLE ..." *)
val execute : _ connection -> string -> unit
val query : _ connection -> string -> string list
(* wraps [f] in BEGIN ... END, does error handling/cleanup *)
val in_transaction : [`regular] connection -> f:([`in_transaction] connection -> 'a) -> 'a
end = struct
type 'a connection = Connection
type row = string list
let connect ~config = Connection
let execute connection sql_statement = print_endline sql_statement
let query connection sql = print_endline sql; ["fake";"results"]
let in_transaction connection ~f =
execute connection "BEGIN";
let result = f (connection :> [`in_transaction] connection) in
execute connection "COMMIT";
result
end
module Account_management : sig
(* IMPORTANT: always do these in transaction! *)
val process1 : [`in_transaction] Jdbc.connection -> unit
val process2 : [`in_transaction] Jdbc.connection -> unit
(* IMPORTANT: This will fail to run in transaction! *)
val update_report1 : [`regular] Jdbc.connection -> unit
(* Ok to run either in transaction, or outside of one *)
val report2 : _ Jdbc.connection -> string list
end = struct
let process1 conn =
Jdbc.execute conn "update accounts set ...";
Jdbc.execute conn "update orders set ...";
Jdbc.execute conn "update balances set ..."
let process2 conn =
Jdbc.execute conn "update accounts set ...";
Jdbc.execute conn "update orders set ..."
let update_report1 conn =
Jdbc.execute conn "refresh materialized view concurrently report1"
let report2 conn =
Jdbc.query conn "select sum(amount) from balances"
end
let () =
let open Jdbc in
let open Account_management in
let conn = connect ~config:"jdbc://dbhost/dbname" in
(* FIXED: User forgot to run the [process1] in transaction :( *)
in_transaction conn ~f:(fun conn ->
process1 conn);
(* This is actually fine *)
update_report1 conn;
in_transaction conn ~f:(fun conn ->
process2 conn;
List.iter print_endline (report2 conn));
(* FIXED: user does nested transactions, but our database does not support them. *)
in_transaction conn ~f:(fun conn ->
process1 conn;
process2 conn);
(* FIXED: Report1 cannot be ran in transaction! *)
update_report1 conn
;;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment