aboutsummaryrefslogtreecommitdiffstats
path: root/src/letsqlite.mli
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2021-10-09 21:45:43 -0400
committerGravatar Peter McGoron 2021-10-09 21:45:43 -0400
commit8c8496da46660f3d0e45171a3cc3d8d3159dfa2f (patch)
treea5f37277cfa9b0a72b2d1632b20ae781716b6a5e /src/letsqlite.mli
move over stuff from old project
Diffstat (limited to '')
-rw-r--r--src/letsqlite.mli141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/letsqlite.mli b/src/letsqlite.mli
new file mode 100644
index 0000000..001b228
--- /dev/null
+++ b/src/letsqlite.mli
@@ -0,0 +1,141 @@
+(** {1 Type definitions}
+
+Types used for monad composition.
+*)
+type 'a stmt_m =
+| Failed of Sqlite3.Rc.t
+| Norm of ('a * Sqlite3.stmt)
+(** The ['a] value in the [stmt_m] is referred to as the bundled value.
+ A function may "fail with [e]", in which it returns [Failed e],
+ or it may "return a value", in which it returns [Norm v s].
+ They are collectively refered to as the monad's values.
+
+ The bundled {Sqlite.stmt} value is refered to as [S], and the
+ value bundled is refered to as [V].
+
+ {i Never directly use [Failed].} You run the likelihood of leaking
+ memory.
+*)
+
+type ('a,'b) monad_fun = ('a * Sqlite3.stmt) -> 'b stmt_m
+
+type rowdata = (string, Sqlite3.Data.t) Hashtbl.t
+
+(** {1 Primary Functions} *)
+
+val (>>$) : 'a stmt_m -> ('a,'b) monad_fun -> 'b stmt_m
+(** [>>$] is the monadic composition function.
+
+ [s >>$ f] return [s] if [s] is [Failed] and [f V S] otherwise.
+*)
+
+val (let$) : 'a stmt_m -> ('a,'b) monad_fun -> 'b stmt_m
+(** [let$ (v,s) = f (V,S) in ...] is equivalent to
+ [f (V,S) >>$ (fun (v,s) -> ...)]. *)
+
+val (>-$) : 'a stmt_m -> ('a,'b) monad_fun -> 'a stmt_m
+(** [>-$] is the passthrough function.
+
+ [s >-$ f] is equivalent to [s >>$ f] except that the bundled
+ value from [f (V,S)] is discarded and replaced with [V]. This function
+ passes the original [V] through.
+*)
+
+(** {1 Non-Execution Functions}
+
+These functions do not execute any SQL queries. They exist to make dealing
+with the monad easier.
+*)
+
+val inject : 'a -> ('b,'a) monad_fun
+(** [inject x] returns [Norm x S], discarding [V]. *)
+
+val fail : Sqlite3.Rc.t -> ('a,'b) monad_fun
+(** [fail e] finalizes [S] and returns [Failure], where the error
+ code is [e] if [e] is not a success error code, and the return code
+ of {finalize} otherwise.
+*)
+
+val stmtfail : Sqlite3.Rc.t -> Sqlite3.stmt -> unit stmt_m
+(** [stmtfail e s] is equivalent to [fail] except it assembles a statement
+ with unit type. *)
+
+val lift_err : Sqlite3.Rc.t -> ('a,'a) monad_fun
+(** [lift_err e] is equivalent to [fail e] when [e] is not a success
+ value, and otherwise returns the monad's values unchanged.
+
+ {b NOTE}: You may be tempted to define a function like
+ [lift : (Sqlite3.stmt -> Sqlite3.Rc.t) -> ('a,'a) monad_fun]
+ which would take a function and apply [lift_err (f S) V S]
+ to the function. However, the partial application [lift f]
+ would leave you with a {i weak type}, which will force your
+ type to have a fixed type. *)
+
+(** {1 Execution functions}
+
+All of these functions will (effectively) exceute {fail} and return
+[Failed] on failure. All functions will omit error behavior unless
+there is something different across any of them. *)
+
+val prepare : Sqlite3.db -> string -> 'a -> 'a stmt_m
+(** [prepare db stmt v] returns a monad with bundled value [v] and
+ the statement in [s].
+*)
+
+val reprepare : Sqlite3.db -> string -> ('a,'a) monad_fun
+(** [reprepare db stmt] finalizes [S] and prepares [stmt] in
+ its place. *)
+
+val reset : ('a,'a) monad_fun
+(** [reset] resets [S] so that it may be executed again. *)
+
+val step : ('a,'a) monad_fun
+(** [step] is equivalent to the Sqlite3 function {step}.
+
+ {b NOTE}: [step] will fail when the statement returns a row.
+*)
+
+val fold : ('a -> ('b,'b) monad_fun) -> 'a list -> ('b,'b) monad_fun
+(** [fold f l] applies each element of [l] to make a monadic function [f]. *)
+
+val getrow : ('a,(unit * rowdata)) monad_fun
+(** [getrow] steps [S] and stores the returned row. The value in [S] is
+ discarded.
+
+ The function returns a tuple with the unit type to interact with
+ {extract}.
+*)
+
+val exec_extract : ('a -> 'b option) -> ('b -> 'c option)
+ -> (('d * 'a),('c * 'a)) monad_fun
+(** [exec_extract extr conv] extracts a value from the second element in
+ [V], and then applies [conv] to it. If both were successful, the
+ function replaces the first element of [V] with the converted
+ value. *)
+
+val extract : string -> (Sqlite3.Data.t -> 'b option)
+ -> (('a * rowdata),('b * rowdata)) monad_fun
+(** [extract name f] finds the value in the row with header name [name]
+ and applies [f] to it. If [f] succeeds then its return value is
+ stored in [V]. The rowdata is preserved.
+*)
+
+val finalize : 'a stmt_m -> 'a
+(** [finalize] raises an exception if the execution failed, and [V]
+ otherwise. *)
+
+val bind_values : Sqlite3.Data.t list -> ('a,'a) monad_fun
+(** [bind_values l] binds each index of [l] to a positional parameter
+ in [S]. *)
+
+val clear_bindings : ('a,'a) monad_fun
+(** [clear_bindings] clears any values bound to [S]. *)
+
+val exec : Sqlite3.db -> string -> unit stmt_m
+(** [exec db s] is equivalent to a call to {prepare} followed by {step}. *)
+
+val reexec : Sqlite3.db -> string -> ('a,'a) monad_fun
+(** [reexec db s] is equivalent to [reprepare >>$ step]. *)
+
+val bsrc : Sqlite3.Data.t list -> ('a,'a) monad_fun
+(** [bsrc l] is equivalent to [bind_values >>$ step >>$ reset >>$ clear_bindings]. *)