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
type ('res, !'multiplicity) caqti_request_inner =
MkCaqti:'input Type.ty_list * ('input, 'res, 'multiplicity) Caqti_request.t ->
('res, 'multiplicity) caqti_request_inner
type ('res, !'multiplicity) t =
('res, 'multiplicity) caqti_request_inner * Expr.wrapped_value list
type wrapped_ty_list = MkWrappedTyList : 'a Type.ty_list -> wrapped_ty_list
let rec : Expr.wrapped_value list -> wrapped_ty_list =
function
| [] -> MkWrappedTyList Nil
| Expr.MkWrapped (ty, _) :: rest ->
let (MkWrappedTyList rest) = extract_ty_list rest in
MkWrappedTyList (Cons (ty, rest))
let rec unwrap : 'a . 'a Type.ty_list * Expr.wrapped_value list -> 'a =
fun (type a) ((tyls: a Type.ty_list), (ls: Expr.wrapped_value list)) : a ->
match tyls,ls with
| Nil,[] -> ()
| Cons (BOOL, tyls), Expr.MkWrapped (BOOL, vl) :: ls ->
(vl, unwrap (tyls, ls))
| Cons (INTEGER, tyls), Expr.MkWrapped (INTEGER, vl) :: ls ->
(vl, unwrap (tyls, ls))
| Cons (REAL, tyls), Expr.MkWrapped (REAL, vl) :: ls ->
(vl, unwrap (tyls, ls))
| Cons (TEXT, tyls), Expr.MkWrapped (TEXT, vl) :: ls ->
(vl, unwrap (tyls, ls))
| Cons (BLOB, tyls), Expr.MkWrapped (BLOB, vl) :: ls ->
(vl, unwrap (tyls, ls))
| Cons (ty, _), Expr.MkWrapped (oty, _) :: _ ->
Format.ksprintf failwith "wrapped value list did not conform to specification - expected %s got %s"
(Type.show ty) (Type.show oty)
| Nil, _ | _, [] -> failwith "wrapped value list length mismatch"
module QueryMap = Type.Map (struct type ('a,'b) t = ('a,'b) caqti_request_inner end)
let cache_zero : (string, [ `Zero ] QueryMap.t) Hashtbl.t = Hashtbl.create 10
let cache_one : (string, [ `One ] QueryMap.t) Hashtbl.t = Hashtbl.create 10
let cache_zero_or_one : (string, [ `Zero | `One ] QueryMap.t) Hashtbl.t = Hashtbl.create 10
let cache_many : (string, [ `Many | `Zero | `One ] QueryMap.t) Hashtbl.t = Hashtbl.create 10
let make_zero : 'b . (unit,'b) Query.t -> (unit, [`Zero]) t =
fun (type b) (query: (unit,b) Query.t) : (unit, [`Zero]) t ->
let query_repr = Caqti_query.of_string_exn (Format.asprintf "%a" Query.pp_query query) in
let query_values = Query.query_values query in
let (MkWrappedTyList query_value_ty) = extract_ty_list query_values in
let request = Caqti_request.create (Type.ty_list_to_caqti_ty query_value_ty) Caqti_type.unit Caqti_mult.zero
(fun _ -> query_repr) in
MkCaqti (query_value_ty,request), query_values
let make_zero : 'b . (unit,'b) Query.t -> (unit, [`Zero]) t =
fun (type b) (query: (unit,b) Query.t) : (unit, [`Zero]) t ->
let query_txt = Format.asprintf "%a" Query.pp_query query in
let query_ty = Query.query_ret_ty query in
let query_values = Query.query_values query in
let ty_map = match Hashtbl.find_opt cache_zero query_txt with
| Some ty_map -> ty_map
| None -> QueryMap.empty in
match QueryMap.lookup_opt ty_map ~key:query_ty with
| Some res -> res, query_values
| None ->
let (query_inner, _) as query = make_zero query in
let ty_map = QueryMap.insert ty_map ~key:query_ty ~data:query_inner in
Hashtbl.replace cache_zero query_txt ty_map;
query
let make_one : 'a 'b . ('a,'b) Query.t -> ('a, [`One]) t =
fun (type a b) (query: (a,b) Query.t) : (a, [`One]) t ->
let query_repr = Caqti_query.of_string_exn (Format.asprintf "%a" Query.pp_query query) in
let query_values = Query.query_values query in
let (MkWrappedTyList query_value_ty) = extract_ty_list query_values in
let ret_ty = Query.query_ret_ty query in
let request = Caqti_request.create (Type.ty_list_to_caqti_ty query_value_ty) (Type.ty_list_to_caqti_ty ret_ty)
Caqti_mult.one (fun _ -> query_repr) in
MkCaqti (query_value_ty,request), query_values
let make_one : 'a 'b . ('a,'b) Query.t -> ('a, [`One]) t =
fun (type a b) (query: (a,b) Query.t) : (a, [`One]) t ->
let query_txt = Format.asprintf "%a" Query.pp_query query in
let query_ty = Query.query_ret_ty query in
let query_values = Query.query_values query in
let ty_map = match Hashtbl.find_opt cache_one query_txt with
| Some ty_map -> ty_map
| None -> QueryMap.empty in
match QueryMap.lookup_opt ty_map ~key:query_ty with
| Some res -> res, query_values
| None ->
let (query_values, _) as query = make_one query in
let ty_map = QueryMap.insert ty_map ~key:query_ty ~data:query_values in
Hashtbl.replace cache_one query_txt ty_map;
query
let make_zero_or_one : 'a 'b . ('a,'b) Query.t -> ('a, [`Zero | `One]) t =
fun (type a b) (query: (a,b) Query.t) : (a, [`Zero | `One]) t ->
let query_repr = Caqti_query.of_string_exn (Format.asprintf "%a" Query.pp_query query) in
let query_values = Query.query_values query in
let (MkWrappedTyList query_value_ty) = extract_ty_list query_values in
let ret_ty = Query.query_ret_ty query in
let request = Caqti_request.create (Type.ty_list_to_caqti_ty query_value_ty) (Type.ty_list_to_caqti_ty ret_ty)
Caqti_mult.zero_or_one (fun _ -> query_repr) in
MkCaqti (query_value_ty,request), query_values
let make_zero_or_one : 'a 'b . ('a,'b) Query.t -> ('a, [`Zero | `One]) t =
fun (type a b) (query: (a,b) Query.t) : (a, [`Zero | `One]) t ->
let query_txt = Format.asprintf "%a" Query.pp_query query in
let query_ty = Query.query_ret_ty query in
let query_values = Query.query_values query in
let ty_map = match Hashtbl.find_opt cache_zero_or_one query_txt with
| Some ty_map -> ty_map
| None -> QueryMap.empty in
match QueryMap.lookup_opt ty_map ~key:query_ty with
| Some res -> res, query_values
| None ->
let (query_inner, _) as query = make_zero_or_one query in
let ty_map = QueryMap.insert ty_map ~key:query_ty ~data:query_inner in
Hashtbl.replace cache_zero_or_one query_txt ty_map;
query
let make_many : 'a 'b . ('a,'b) Query.t -> ('a, [`Many | `Zero | `One]) t =
fun (type a b) (query: (a,b) Query.t) : (a, [`Many | `Zero | `One]) t ->
let query_repr = Caqti_query.of_string_exn (Format.asprintf "%a" Query.pp_query query) in
let query_values = Query.query_values query in
let (MkWrappedTyList query_value_ty) = extract_ty_list query_values in
let ret_ty = Query.query_ret_ty query in
let request = Caqti_request.create (Type.ty_list_to_caqti_ty query_value_ty) (Type.ty_list_to_caqti_ty ret_ty)
Caqti_mult.zero_or_more (fun _ -> query_repr) in
MkCaqti (query_value_ty,request), query_values
let make_many : 'a 'b . ('a,'b) Query.t -> ('a, [`Many | `Zero | `One]) t =
fun (type a b) (query: (a,b) Query.t) : (a, [`Many | `Zero | `One]) t ->
let query_txt = Format.asprintf "%a" Query.pp_query query in
let query_ty = Query.query_ret_ty query in
let query_values = Query.query_values query in
let ty_map = match Hashtbl.find_opt cache_many query_txt with
| Some ty_map -> ty_map
| None -> QueryMap.empty in
match QueryMap.lookup_opt ty_map ~key:query_ty with
| Some res -> res, query_values
| None ->
let (query_inner, _) as query = make_many query in
let ty_map = QueryMap.insert ty_map ~key:query_ty ~data:query_inner in
Hashtbl.replace cache_many query_txt ty_map;
query