blob: b09f31119cf65c4a53220625566ff529e1ac5c11 (
plain)
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
|
(** The module allow to create fragment in the query which keep together the
binderd parameters and the text of the query.contents.
This is used a lot in order to create the CTE, where you need the create
fragment used both in the main request and partially in the CTE itself.
The content is mutable and all the functions are returning [unit]. *)
type t = {
b : Buffer.t;
parameters : ImportDataTypes.Value.t Queue.t;
}
let create : unit -> t =
fun () -> { b = Buffer.create 16; parameters = Queue.create () }
let create' : Buffer.t -> ImportDataTypes.Value.t Queue.t -> t =
fun b parameters -> { b; parameters }
(* Append the element from [tail] at the end of [head]
Tail is destroyed during the operation.
*)
let append : head:t -> tail:t -> unit =
fun ~head ~tail ->
match Buffer.length tail.b with
| 0 -> ()
| _ ->
Buffer.add_buffer head.b tail.b;
Queue.transfer tail.parameters head.parameters;
()
(** Add a litteral string in the sequence *)
let add_string : t -> string -> unit = fun t v -> Buffer.add_string t.b v
let copy : t -> t =
fun t ->
let b = Buffer.create 16 and parameters = Queue.copy t.parameters in
Buffer.add_buffer b t.b;
{ b; parameters }
let add_parameters : t -> ImportDataTypes.Value.t Seq.t -> unit =
fun t p -> Queue.add_seq t.parameters p
module Table = ImportDataTypes.Table
open StdLabels
let add_expression :
repr:(Format.formatter -> 'a -> unit) ->
t ->
'a ImportExpression.T.t ->
unit =
fun ~repr group expression ->
let formatter = Format.formatter_of_buffer group.b in
Format.pp_print_char formatter '(';
let queue =
ImportExpression.Query.query_of_expression ImportExpression.Query.BindParam
formatter repr expression
in
Format.pp_print_char formatter ')';
Format.pp_print_flush formatter ();
add_parameters group (Queue.to_seq queue)
(** Extract the informations from the dependancies. We get two informations here
:
- the join query in order to load the data from the external column
- the column corresponding to the key in order to identify the missing links
later. *)
let join_external :
conf:ImporterSyntax.t -> join_buffer:t -> ImporterSyntax.Extern.t -> unit =
fun ~conf ~join_buffer external_ ->
let extern_table = Table.name external_.target in
add_string join_buffer "\nLEFT JOIN '";
add_string join_buffer extern_table;
add_string join_buffer "' AS '";
add_string join_buffer external_.target.name;
add_string join_buffer "' ON ";
add_string join_buffer
(Format.asprintf "%t = %s"
(Printers.prepare_key ~f:(fun f ->
let q =
ImportExpression.Query.query_of_expression
ImportExpression.Query.BindParam f (Printers.path ~conf)
external_.intern_key
in
add_parameters join_buffer (Queue.to_seq q)))
(Table.print_column external_.ImporterSyntax.Extern.target
("key_" ^ external_.ImporterSyntax.Extern.target.name)));
(* Add the filters given for this external in the query *)
let table = external_.ImporterSyntax.Extern.target
and filters = external_.ImporterSyntax.Extern.filters in
List.iter filters ~f:(fun f ->
add_string join_buffer " AND ";
add_expression
~repr:(fun formatter column ->
Format.fprintf formatter "%s"
(Table.print_column table ("col_" ^ string_of_int column)))
join_buffer f)
(** Create the from part of the query, adding all the required externals (even
when not required)
SQLite is able to optimize the query and do not load the table not used in
the select clause. *)
let create_from_statement_of_chunck :
?externals:ImporterSyntax.Extern.t list -> ImporterSyntax.t -> t -> unit =
fun ?externals conf c ->
let externals = Option.value externals ~default:conf.externals in
add_string c "\nFROM '";
add_string c (Table.name conf.source);
add_string c "' AS '";
add_string c conf.source.name;
add_string c "'";
(* Add the externals in the query *)
List.iter externals ~f:(join_external ~conf ~join_buffer:c)
(** Add a list of expressions into the group *)
let add_expressions :
repr:(Format.formatter -> 'a -> unit) ->
sep:string ->
t ->
'a ImportExpression.T.t list ->
unit =
fun ~repr ~sep group exppressions ->
let formatter = Format.formatter_of_buffer group.b in
let () =
Format.pp_print_list
~pp_sep:(fun f () -> Format.pp_print_string f sep)
(fun formatter column ->
Format.pp_print_char formatter '(';
let seq =
ImportExpression.Query.query_of_expression
ImportExpression.Query.BindParam formatter repr column
in
Format.pp_print_char formatter ')';
Queue.transfer seq group.parameters)
formatter exppressions
in
Format.pp_print_flush formatter ()
|