This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
296
unikernel/duniverse/ocaml-caqti/caqti/lib/caqti_error.mli
Normal file
296
unikernel/duniverse/ocaml-caqti/caqti/lib/caqti_error.mli
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
(* Copyright (C) 2017--2023 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.
|
||||
*)
|
||||
|
||||
(** Error descriptors. *)
|
||||
|
||||
|
||||
(** {2 Error Causes}
|
||||
|
||||
The {!type:cause} type is an incomplete enumeration of consolidated causes
|
||||
of errors between different database systems. The selection includes the
|
||||
causes which are believed to be useful to handle and excludes causes which
|
||||
are specific to the implementation of a certain database system.
|
||||
|
||||
The causes are classified into subtypes to help matching them collectively.
|
||||
Each subtype has a fall-back case which is used if the database system does
|
||||
not clearly report one of the specific cases. An condition which is
|
||||
reported as the fall-back case may in a future version be reported as a
|
||||
specific case, possibly adding a new case to the subtype. Therefore, for
|
||||
backwards compatibility you should match the full subtype rather than the
|
||||
fall-back, e.g.
|
||||
{[
|
||||
(match Caqti_error.cause error with
|
||||
| `Unique_violation -> handle_unique_violation ()
|
||||
| #integrity_constraint_violation -> handle_other_constraint_violation ()
|
||||
| _ -> handle_other_error ())
|
||||
]}
|
||||
This ensures that your code stil compiles when a new case is added to
|
||||
{!integrity_constraint_violation}, and that the error condition receiving
|
||||
mapped to the new case is still handled by the subtype pattern when you link
|
||||
to the new version of Caqti.
|
||||
|
||||
Currently we do not have access to the extended error codes from SQLite3,
|
||||
meaning that all integrity constraint violation conditions will be reported
|
||||
as [`Integrity_constraint_violation__don't_match].
|
||||
|
||||
Since the consolitation of each error condition requires some investitation
|
||||
and testing, the selection made is very conservative. If you need to handle
|
||||
an error which is currently unlisted, please open an issue or create a pull
|
||||
request. A pull request should, if possible, include a extension of
|
||||
[test_error_cause.ml] to demonstrate how the error is triggered by the
|
||||
database systems. *)
|
||||
|
||||
type integrity_constraint_violation = [
|
||||
| `Restrict_violation
|
||||
(** This is meant to indicate that a deletion or update would cause a
|
||||
foreign key violation, although this may be reported as a
|
||||
[`Foreign_key_violation]. *)
|
||||
| `Not_null_violation
|
||||
(** An insertion or update attempts to assign a [NULL] value to column
|
||||
having a [NOT NULL] constraint. *)
|
||||
| `Foreign_key_violation
|
||||
(** An modification would cause a column to reference a non-existing key.
|
||||
This cause may also be reported for cases which should have been
|
||||
covered by [`Restrict_violation]. *)
|
||||
| `Unique_violation
|
||||
(** An insertion or update would duplicate a key as declared by a [UNIQUE]
|
||||
or [PRIMARY KEY] constraint. *)
|
||||
| `Check_violation
|
||||
(** A requested change would violate a [CHECK] constraint. *)
|
||||
| `Exclusion_violation
|
||||
(** A requested insertion or update would cause an overlap of rows
|
||||
according to an [EXCLUDE] constraint. *)
|
||||
| `Integrity_constraint_violation__don't_match
|
||||
(** An yet unclassified cause; match the full subtype instead. *)
|
||||
]
|
||||
(** A subtype of {!type:cause} informing about violation of SQL constraints. *)
|
||||
|
||||
type insufficient_resources = [
|
||||
| `Disk_full
|
||||
(** The server is out of disk space. *)
|
||||
| `Out_of_memory
|
||||
(** The server is out of memory *)
|
||||
| `Too_many_connections
|
||||
(** The server does not accept establishing more connections. *)
|
||||
| `Configuration_limit_exceeded
|
||||
(** Some unspecific server limit is exceeded. *)
|
||||
| `Insufficient_resources__don't_match
|
||||
(** An yet unclassified cause; match the full subtype instead. *)
|
||||
]
|
||||
(** A subtype of {!type:cause} informing about insufficient resources on the
|
||||
server side. *)
|
||||
|
||||
type cause = [
|
||||
| integrity_constraint_violation
|
||||
| insufficient_resources
|
||||
| `Unspecified__don't_match
|
||||
]
|
||||
(** The selection of causes of errors which have been mapped. *)
|
||||
|
||||
val show_cause : [< cause] -> string
|
||||
|
||||
|
||||
(** {2 Messages} *)
|
||||
|
||||
type msg = ..
|
||||
(** In this type, drivers can stash information about any errors in their own
|
||||
format, which can later be used for pretty-printing and or future
|
||||
operations. Drivers must call {!define_msg} on each constructor added to
|
||||
this type. *)
|
||||
|
||||
val define_msg :
|
||||
pp: (Format.formatter -> msg -> unit) ->
|
||||
?cause: (msg -> cause) ->
|
||||
extension_constructor -> unit
|
||||
(** Mandatory registration of pretty-printer for a driver-supplied error
|
||||
descriptor. *)
|
||||
|
||||
val pp_msg : Format.formatter -> msg -> unit
|
||||
(** [pp_msg ppf msg] formats [msg] on [ppf]. *)
|
||||
|
||||
type msg += Msg : string -> msg
|
||||
(** The shape of locally generated messages and messages from drivers without
|
||||
dedicated error type. *)
|
||||
|
||||
(**/**)
|
||||
val pp_uri : Format.formatter -> Uri.t -> unit
|
||||
(** Pretty printer of URIs which omits the password, used by drivers when
|
||||
logging. *)
|
||||
(**/**)
|
||||
|
||||
(** {2 Messages with Metadata}
|
||||
|
||||
{b Note.} Please consider the fields internal for now, they may still be
|
||||
revised or hidden. *)
|
||||
|
||||
type load_error = private {
|
||||
uri: Uri.t;
|
||||
msg: msg;
|
||||
}
|
||||
type connection_error = private {
|
||||
uri: Uri.t;
|
||||
msg: msg;
|
||||
}
|
||||
type query_error = private {
|
||||
uri: Uri.t;
|
||||
query: string;
|
||||
msg: msg;
|
||||
}
|
||||
type coding_error = private {
|
||||
uri: Uri.t;
|
||||
typ: Caqti_type.any;
|
||||
msg: msg;
|
||||
}
|
||||
|
||||
|
||||
(** {2 Documented Constructors} *)
|
||||
|
||||
|
||||
(** {3 Errors during Driver Loading} *)
|
||||
|
||||
val load_rejected : uri: Uri.t -> msg -> [> `Load_rejected of load_error]
|
||||
(** [load_rejected ~uri msg] indicates that a driver could not be identified
|
||||
from [uri]. *)
|
||||
|
||||
val load_failed : uri: Uri.t -> msg -> [> `Load_failed of load_error]
|
||||
(** [load_failed ~uri msg] indicates that a driver for [uri] could not be
|
||||
loaded. *)
|
||||
|
||||
|
||||
(** {3 Errors during Connect} *)
|
||||
|
||||
val connect_rejected : uri: Uri.t -> msg ->
|
||||
[> `Connect_rejected of connection_error]
|
||||
(** [connect_rejected ~uri msg] indicates that the driver rejected the URI. *)
|
||||
|
||||
val connect_failed : uri: Uri.t -> msg ->
|
||||
[> `Connect_failed of connection_error]
|
||||
(** [connect_failed ~uri msg] indicates that the driver failed to establish a
|
||||
connection to the database. *)
|
||||
|
||||
|
||||
(** {3 Errors during Call} *)
|
||||
|
||||
val encode_missing : uri: Uri.t -> field_type: 'a Caqti_type.Field.t -> unit ->
|
||||
[> `Encode_rejected of coding_error]
|
||||
(** [encode_missing ~uri ~field_type ()] indicates that the driver does not
|
||||
support [field_type] and no fallback encoding is available for the type. *)
|
||||
|
||||
val encode_rejected : uri: Uri.t -> typ: 'a Caqti_type.t -> msg ->
|
||||
[> `Encode_rejected of coding_error]
|
||||
(** [encode_rejected ~uri ~typ msg] indicates that encoding a value to [typ]
|
||||
failed, e.g. due to being out of range. *)
|
||||
|
||||
val encode_failed : uri: Uri.t -> typ: 'a Caqti_type.t -> msg ->
|
||||
[> `Encode_failed of coding_error]
|
||||
(** [encode_failed ~uri ~typ msg] indicates that a parameter of type [typ] was
|
||||
not accepted by the database client library. *)
|
||||
|
||||
val request_failed : uri: Uri.t -> query: string -> msg ->
|
||||
[> `Request_failed of query_error]
|
||||
(** [request_failed ~uri ~query msg] indicates that the request could not be
|
||||
transmitted to the database, that the database was not ready to process the
|
||||
request, or that something went wrong while processing the request. *)
|
||||
|
||||
|
||||
(** {3 Errors during Result Retrieval} *)
|
||||
|
||||
val decode_missing : uri: Uri.t -> field_type: 'a Caqti_type.Field.t -> unit ->
|
||||
[> `Decode_rejected of coding_error]
|
||||
(** [decode_missing ~uri ~field_type ()] indicates that the driver does not
|
||||
support [field_type] for decoding result rows. *)
|
||||
|
||||
val decode_rejected : uri: Uri.t -> typ: 'a Caqti_type.t -> msg ->
|
||||
[> `Decode_rejected of coding_error]
|
||||
(** [decode_rejected ~uri ~typ msg] indicates that the driver could not decode a
|
||||
field of type [typ] from the returned row, e.g. due to an invalid value or
|
||||
limited range of the target type. *)
|
||||
|
||||
val response_failed : uri: Uri.t -> query: string -> msg ->
|
||||
[> `Response_failed of query_error]
|
||||
(** [response_failed ~uri ~query msg] indicates that something when wrong while
|
||||
fetching a delayed part of the response. *)
|
||||
|
||||
val response_rejected : uri: Uri.t -> query: string -> msg ->
|
||||
[> `Response_rejected of query_error]
|
||||
(** [response_rejected ~uri ~query msg] indicates that the response from the
|
||||
database was rejected due to requirements posed by client code. *)
|
||||
|
||||
|
||||
(** {2 Specific Error Types} *)
|
||||
|
||||
type call =
|
||||
[ `Encode_rejected of coding_error
|
||||
| `Encode_failed of coding_error
|
||||
| `Request_failed of query_error
|
||||
| `Response_rejected of query_error ]
|
||||
|
||||
type retrieve =
|
||||
[ `Decode_rejected of coding_error
|
||||
| `Request_failed of query_error
|
||||
| `Response_failed of query_error
|
||||
| `Response_rejected of query_error ]
|
||||
(** Errors which may occur during retrival of result rows. This includes
|
||||
[`Request_failed] since the request is fused with retrieval for the pgx
|
||||
driver. *)
|
||||
|
||||
type call_or_retrieve = [call | retrieve]
|
||||
|
||||
type transact = [call | retrieve] (* TODO: Should be a subset. *)
|
||||
|
||||
type load =
|
||||
[ `Load_rejected of load_error
|
||||
| `Load_failed of load_error ]
|
||||
|
||||
type connect =
|
||||
[ `Connect_rejected of connection_error
|
||||
| `Connect_failed of connection_error
|
||||
| `Post_connect of call_or_retrieve ]
|
||||
|
||||
type load_or_connect = [load | connect]
|
||||
|
||||
|
||||
(** {2 Generic Error Type and Functions} *)
|
||||
|
||||
type t = [load | connect | call | retrieve]
|
||||
(** The full union of errors used by Caqti. *)
|
||||
|
||||
val uri : [< t] -> Uri.t
|
||||
(** [uri error] is the URI of the connection used where [error] occurred. *)
|
||||
|
||||
val pp : Format.formatter -> [< t] -> unit
|
||||
(** [pp ppf error] prints an explanation of [error] on [ppf]. *)
|
||||
|
||||
val show : [< t] -> string
|
||||
(** [show error] is an explanation of [error]. *)
|
||||
|
||||
val cause :
|
||||
[< `Request_failed of query_error | `Response_failed of query_error] -> cause
|
||||
(** A matchable representation of the cause of the error, if available. *)
|
||||
|
||||
type counit = |
|
||||
(** An uninhabited type used by {!uncongested}. *)
|
||||
|
||||
val uncongested :
|
||||
('a, [< t | `Congested of counit]) result ->
|
||||
('a, [> t]) result
|
||||
(** [uncongested r] eliminates an unused [`Congested] case from the error. *)
|
||||
|
||||
exception Exn of t
|
||||
(** [Exn error] can be used when an exception is preferred over explicit error
|
||||
handling. The core Caqti API never raises exceptions which originate from
|
||||
runtime errors. *)
|
||||
Loading…
Add table
Add a link
Reference in a new issue