Source file contract_database.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
type database =
  | MariaDb
  | PostgreSql

(* Signature *)
let name = "database"

exception Exception of string

module type Sig = sig
  (** ['a prepared_search_request] is a prepared SQL statement that can be used
      to sort, filter and paginate (= search) a collection. *)
  type 'a prepared_search_request

  val prepare_requests : string -> string -> string -> string
    (* Deprecated in 0.6.0 *)
    [@@deprecated "Use prepare_search_request instead"]

  (** [prepare_search_request ~search_query ~count_query ~filter_fragment
      ?sort_by_field type]
      returns a prepared SQL statement ['a prepared_search_request] by
      assembling the SQL query from the provided fragments.

      [search_query] is the [SELECT ... FROM table] part of the query.

      [count_query] is a query that is executed by Sihl after the search in
      order to obtain the total number of items in the table. For example
      [SELECT COUNT(\*\) FROM table].

      [filter_fragment] is the fragment that is appended to [search_query] for
      filtering. Usually you want ot [OR] fields that are often searched for.
      For example
      [WHERE table.field1 LIKE $1 OR table.field2 $1 OR table.field3 LIKE $1].

      [sort_by_field] is an optional field name that is used for sorting. By
      default, the field "id" is used. Note that in order to prepare the
      requests, the sort field has to be known beforehand. If you want to
      dynamically set the field, you need to write your own query at runtime.

      [format_filter] is a function applied to the filter keyword before it is
      passed to the database. By default, a keyword "keyword" is formatted to
      "%skeyword%s". This might not be what you want performance-wise. If you
      need full control, pass in the identity function and format the keyword
      yourself.

      [type] is the caqti type of an item of the collection. *)
  val prepare_search_request
    :  search_query:string
    -> filter_fragment:string
    -> ?sort_by_field:string
    -> ?format_filter:(string -> string)
    -> 'a Caqti_type.t
    -> 'a prepared_search_request

  val run_request
    :  (module Caqti_lwt.CONNECTION)
    -> 'a prepared_search_request
    -> [< `Asc | `Desc ]
    -> 'c option
    -> 'a
    -> ('b list * int) Lwt.t
    (* Deprecated in 0.6.0 *)
    [@@deprecated "Use run_search_request instead"]

  (** [run_search_request prepared_request sort filter ~limit ~offset] runs the
      [prepared_request] and returns a partial result of the whole stored
      collection. The second element of the result tuple is the total amount of
      items in the whole collection.

      [prepared_request] is the returned prepared request by
      {!prepare_search_request}.

      [sort] is the sort order. The field that is sorted by was set by
      {!prepare_search_request}.

      [filter] is an optional keyword that is used to filter the collection. If
      no filter is provided, the collection is not filtered.

      [offset] is the number of items that the returned partial result is offset
      by.

      [limit] is the number of items of the returned partial result.

      [offset] and [limit] can be used together to implement pagination. *)
  val run_search_request
    :  'a prepared_search_request
    -> [ `Asc | `Desc ]
    -> string option
    -> limit:int
    -> offset:int
    -> ('a list * int) Lwt.t

  (** [raise_error err] raises a printable caqti error [err] .*)
  val raise_error : ('a, Caqti_error.t) Result.t -> 'a

  (** [fetch_pool ()] returns the connection pool that was set up. If there was
      no connection pool set up, setting it up now. *)
  val fetch_pool
    :  unit
    -> (Caqti_lwt.connection, Caqti_error.t) Caqti_lwt.Pool.t

  (** [find_opt request input] runs a caqti [request] in the connection pool
      where [input] is the input of the caqti request and returns one row or
      [None]. Returns [None] if no rows are found.

      Note that the caqti request is only allowed to return one or zero rows,
      not many. *)
  val find_opt
    :  ('a, 'b, [< `One | `Zero ]) Caqti_request.t
    -> 'a
    -> 'b option Lwt.t

  (** [find request input] runs a caqti [request] on the connection pool where
      [input] is the input of the caqti request and returns one row. Raises an
      exception if no row was found.

      Note that the caqti request is only allowed to return one or zero rows,
      not many. *)
  val find : ('a, 'b, [< `One ]) Caqti_request.t -> 'a -> 'b Lwt.t

  (** [collect request input] runs a caqti [request] on the connection pool
      where [input] is the input of the caqti request and retuns a list of rows.

      Note that the caqti request is allowed to return one, zero or many rows. *)
  val collect
    :  ('a, 'b, [< `One | `Zero | `Many ]) Caqti_request.t
    -> 'a
    -> 'b list Lwt.t

  (** [exec request input] runs a caqti [request] on the connection pool.

      Note that the caqti request is not allowed to return any rows.

      Use {!exec} to run mutations. *)
  val exec : ('b, unit, [< `Zero ]) Caqti_request.t -> 'b -> unit Lwt.t

  (** [query f] runs the query [f] on the connection pool and returns the
      result. If the query fails the Lwt.t fails as well. *)
  val query : (Caqti_lwt.connection -> 'a Lwt.t) -> 'a Lwt.t

  (** [query' f] runs the query [f] on the connection pool and returns the
      result. Use [query'] instead of {!query} as a shorthand when you have a
      single caqti request to execute. *)
  val query'
    :  (Caqti_lwt.connection -> ('a, Caqti_error.t) Result.t Lwt.t)
    -> 'a Lwt.t

  (** [transaction f] runs the query [f] on the connection pool in a transaction
      and returns the result. If the query fails the Lwt.t fails as well and the
      transaction gets rolled back. If the database driver doesn't support
      transactions, [transaction] gracefully becomes {!query}. *)
  val transaction : (Caqti_lwt.connection -> 'a Lwt.t) -> 'a Lwt.t

  (** [transaction' f] runs the query [f] on the connection pool in a
      transaction and returns the result. If the query fails the Lwt.t fails as
      well and the transaction gets rolled back. If the database driver doesn't
      support transactions, [transaction'] gracefully becomes {!query'}. *)
  val transaction'
    :  (Caqti_lwt.connection -> ('a, Caqti_error.t) Result.t Lwt.t)
    -> 'a Lwt.t

  val register : unit -> Core_container.Service.t

  include Core_container.Service.Sig
end