This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
|
|
@ -0,0 +1,256 @@
|
|||
(* Copyright (C) 2017--2025 Petter A. Urkedal <paurkedal@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version, with the LGPL-3.0 Linking Exception.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* and the LGPL-3.0 Linking Exception along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/> and <https://spdx.org>, respectively.
|
||||
*)
|
||||
|
||||
(** Signature of connection handles.
|
||||
|
||||
The main signature {!S} of this module represents a database connection
|
||||
handle. This is obtained by {{!Caqti_connect_sig} connection functions}
|
||||
implemented in the subpackages [caqti-async], [caqti-eio], [caqti-lwt], and
|
||||
[caqti-mirage].
|
||||
|
||||
While values of {!Caqti_request.t} hold SQL code to be sent to the database,
|
||||
connection handles defined here provide the means to execute them with
|
||||
actual parameters on an RDBMS. So, there is a separation between
|
||||
preparation and execution. This is motivated by the common support for
|
||||
prepared queries in database client libraries, and by the desire to keep the
|
||||
possibly deeply nested data-processing code uncluttered by strings of SQL
|
||||
code. For this separation to be reasonably safe, the request declares the
|
||||
types of parameters and result, and these type declarations are placed right
|
||||
next to the SQL code, so that we can rely on OCaml's powers of refactoring
|
||||
large code bases safely.
|
||||
|
||||
The result type of {!Caqti_request.t} only describes how to decode {e
|
||||
individual rows}, leaving the decision of how to process multiple rows to
|
||||
the execution interface. Therefore, for each request constructor from
|
||||
{!Caqti_request.Infix}, there are one or more matching retrieval functions
|
||||
in the present signature. *)
|
||||
|
||||
type driver_connection = ..
|
||||
(** This type is only to be extended by drivers. *)
|
||||
|
||||
(** Essential connection signature implemented by drivers. *)
|
||||
module type Base = sig
|
||||
type +'a fiber
|
||||
type (+'a, +'err) stream
|
||||
|
||||
(** {2 Query} *)
|
||||
|
||||
module Response : Caqti_response_sig.S
|
||||
with type 'a fiber := 'a fiber
|
||||
and type ('a, 'err) stream := ('a, 'err) stream
|
||||
|
||||
val call :
|
||||
f: (('b, 'm) Response.t -> ('c, 'e) result fiber) ->
|
||||
('a, 'b, 'm) Caqti_request.t -> 'a ->
|
||||
('c, [> Caqti_error.call] as 'e) result fiber
|
||||
(** [call ~f request params] executes [request] with parameters [params]
|
||||
invoking [f] to process the result; except the driver may postpone the
|
||||
request until [f] attempts to retrieve the result.
|
||||
|
||||
One of the {{!Response.result_retrieval} result retrieval}
|
||||
functions must be called exactly once before [f] returns a non-error
|
||||
result. If a result retrieval function is not called, it is unspecified
|
||||
whether the database query has been issued.
|
||||
|
||||
The argument of [f] is only valid during the call to [f], and must not be
|
||||
returned or operated on by other threads. *)
|
||||
|
||||
val set_statement_timeout :
|
||||
float option -> (unit, [> Caqti_error.call]) result fiber
|
||||
(** Set or clear the timeout after which a running SQL statement will be
|
||||
terminated if supported by the driver.
|
||||
This is currently supported for MariaDB (using [max_statement_time]) and
|
||||
PostgreSQL (using [statement_timeout]) and has no effect for SQLite3. *)
|
||||
|
||||
|
||||
(** {2 Transactions} *)
|
||||
|
||||
val start : unit -> (unit, [> Caqti_error.transact]) result fiber
|
||||
(** Starts a transaction if supported by the underlying database, otherwise
|
||||
does nothing. *)
|
||||
|
||||
val commit : unit -> (unit, [> Caqti_error.transact]) result fiber
|
||||
(** Commits the current transaction if supported by the underlying database,
|
||||
otherwise does nothing. *)
|
||||
|
||||
val rollback : unit -> (unit, [> Caqti_error.transact]) result fiber
|
||||
(** Rolls back a transaction if supported by the underlying database,
|
||||
otherwise does nothing. *)
|
||||
|
||||
|
||||
(** {2 Disconnection and Reuse} *)
|
||||
|
||||
val deallocate :
|
||||
('a, 'b, 'm) Caqti_request.t -> (unit, [> Caqti_error.call]) result fiber
|
||||
(** [deallocate req] deallocates the prepared query for [req] if it was
|
||||
allocated. The request must not be oneshot. *)
|
||||
|
||||
val disconnect : unit -> unit fiber
|
||||
(** Calling [disconnect ()] closes the connection to the database and frees
|
||||
up related resources. *)
|
||||
|
||||
val validate : unit -> bool fiber
|
||||
(** For internal use by pool implementations. Tries to ensure the validity of
|
||||
the connection and must return [false] if unsuccessful. *)
|
||||
|
||||
val check : (bool -> unit) -> unit
|
||||
(** For internal use by pool implementations. Called after a connection has
|
||||
been used. [check f] must call [f ()] exactly once with an argument
|
||||
indicating whether to keep the connection in the pool or discard it. *)
|
||||
|
||||
end
|
||||
|
||||
module type Convenience = sig
|
||||
type +'a fiber
|
||||
|
||||
(** {2 Retrieval Convenience}
|
||||
|
||||
Each of these shortcuts combine [call] with the correspondingly named
|
||||
retrieval function from {!Caqti_response_sig.S}. *)
|
||||
|
||||
val exec :
|
||||
('a, unit, [< `Zero]) Caqti_request.t -> 'a ->
|
||||
(unit, [> Caqti_error.call_or_retrieve]) result fiber
|
||||
(** [exec req x] performs [req] with parameters [x] and checks that no rows
|
||||
are returned.
|
||||
See also {!Caqti_response_sig.S.exec}. *)
|
||||
|
||||
val exec_with_affected_count :
|
||||
('a, unit, [< `Zero]) Caqti_request.t -> 'a ->
|
||||
(int, [> Caqti_error.call_or_retrieve | `Unsupported]) result fiber
|
||||
(** [exec_with_affected_count req x] performs [req] with parameters [x],
|
||||
checks that no rows are returned, and returns the number of affected rows.
|
||||
|
||||
See also {!Caqti_response_sig.S.exec} and
|
||||
{!Caqti_response_sig.S.affected_count}. *)
|
||||
|
||||
val find :
|
||||
('a, 'b, [< `One]) Caqti_request.t -> 'a ->
|
||||
('b, [> Caqti_error.call_or_retrieve]) result fiber
|
||||
(** [find req x] performs [req] with parameters [x], checks that a single row
|
||||
is retured, and returns it.
|
||||
|
||||
See also {!Caqti_response_sig.S.find}. *)
|
||||
|
||||
val find_opt :
|
||||
('a, 'b, [< `Zero | `One]) Caqti_request.t -> 'a ->
|
||||
('b option, [> Caqti_error.call_or_retrieve]) result fiber
|
||||
(** [find_opt req x] performs [req] with parameters [x] and returns either
|
||||
[None] if no rows are returned or [Some y] if a single now [y] is returned
|
||||
and fails otherwise.
|
||||
|
||||
See also {!Caqti_response_sig.S.find_opt}. *)
|
||||
|
||||
val fold :
|
||||
('a, 'b, [< `Zero | `One | `Many]) Caqti_request.t ->
|
||||
('b -> 'c -> 'c) ->
|
||||
'a -> 'c -> ('c, [> Caqti_error.call_or_retrieve]) result fiber
|
||||
(** [fold req f x acc] performs [req] with parameters [x] and passes [acc]
|
||||
through the composition of [f y] across the result rows [y] in the order
|
||||
of retrieval.
|
||||
|
||||
See also {!Caqti_response_sig.S.fold}. *)
|
||||
|
||||
val fold_s :
|
||||
('a, 'b, [< `Zero | `One | `Many]) Caqti_request.t ->
|
||||
('b -> 'c -> ('c, 'e) result fiber) ->
|
||||
'a -> 'c -> ('c, [> Caqti_error.call_or_retrieve] as 'e) result fiber
|
||||
(** [fold_s req f x acc] performs [req] with parameters [x] and passes [acc]
|
||||
through the monadic composition of [f y] across the returned rows [y] in
|
||||
the order of retrieval.
|
||||
|
||||
Please be aware of possible deadlocks when using resources from the
|
||||
callback. In particular, if the same connection pool is invoked as the
|
||||
one used to obtain the current connection, it will deadlock if the pool
|
||||
has just run out of connections. An alternative is to collect the rows
|
||||
first e.g. with {!fold} and do the nested queries after exiting.
|
||||
|
||||
See also {!Caqti_response_sig.S.fold_s}. *)
|
||||
|
||||
val iter_s :
|
||||
('a, 'b, [< `Zero | `One | `Many]) Caqti_request.t ->
|
||||
('b -> (unit, 'e) result fiber) ->
|
||||
'a -> (unit, [> Caqti_error.call_or_retrieve] as 'e) result fiber
|
||||
(** [iter_s req f x] performs [req] with parameters [x] and sequences calls to
|
||||
[f y] for each result row [y] in the order of retrieval.
|
||||
|
||||
Please see the warning in {!fold_s} about resource usage in the callback.
|
||||
|
||||
See also {!Caqti_response_sig.S.iter_s}. *)
|
||||
|
||||
val collect_list :
|
||||
('a, 'b, [< `Zero | `One | `Many]) Caqti_request.t -> 'a ->
|
||||
('b list, [> Caqti_error.call_or_retrieve]) result fiber
|
||||
(** [collect_list request x] performs a [req] with parameters [x] and returns
|
||||
a list of rows in order of retrieval. The accumulation is tail recursive
|
||||
but slightly less efficient than {!rev_collect_list}. *)
|
||||
|
||||
val rev_collect_list :
|
||||
('a, 'b, [< `Zero | `One | `Many]) Caqti_request.t -> 'a ->
|
||||
('b list, [> Caqti_error.call_or_retrieve]) result fiber
|
||||
(** [rev_collect_list request x] performs [request] with parameters [x] and
|
||||
returns a list of rows in the reverse order of retrieval. The
|
||||
accumulation is tail recursive and slighly more efficient than
|
||||
{!collect_list}. *)
|
||||
|
||||
|
||||
(** {2 Transactions} *)
|
||||
|
||||
val with_transaction :
|
||||
(unit -> ('a, 'e) result fiber) ->
|
||||
('a, [> Caqti_error.transact] as 'e) result fiber
|
||||
(** [with_transaction f] wraps [f] in a transaction which is committed iff [f]
|
||||
returns [Ok _]. *)
|
||||
end
|
||||
|
||||
module type Populate = sig
|
||||
type +'a fiber
|
||||
type (+'a, +'err) stream
|
||||
|
||||
(** {2 Insertion} *)
|
||||
|
||||
val populate :
|
||||
table: string ->
|
||||
columns: string list ->
|
||||
'a Caqti_type.t -> ('a, 'err) stream ->
|
||||
(unit, [> Caqti_error.call_or_retrieve | `Congested of 'err]) result fiber
|
||||
(** [populate table columns row_type seq] inputs the contents of [seq] into
|
||||
the database in whatever manner is most efficient as decided by the
|
||||
driver. *)
|
||||
end
|
||||
|
||||
(** Full connection signature available to users. *)
|
||||
module type S = sig
|
||||
|
||||
val driver_info : Caqti_driver_info.t
|
||||
(** Information about the driver providing this connection module. *)
|
||||
|
||||
val dialect : Caqti_template.Dialect.t
|
||||
(** Information about the SQL dialect and other properties of the server. *)
|
||||
|
||||
val driver_connection : driver_connection option
|
||||
(** The underlying connection object of the driver if available. The open
|
||||
variant constructor is defined in the driver library. This is currently
|
||||
only implemented for caqti-driver-sqlite3 for the purpose of defining
|
||||
custom functions. *)
|
||||
|
||||
include Base
|
||||
include Convenience with type 'a fiber := 'a fiber
|
||||
include Populate
|
||||
with type 'a fiber := 'a fiber
|
||||
and type ('a, 'err) stream := ('a, 'err) stream
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue