blob: 15e8cda2ec5eada9654719e47dc63abfc23eb4e1 (
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
|
(** Build a fragment of the query match a filter *)
module Path = ImportDataTypes.Path
module Expression = ImportExpression
open StdLabels
type 'a cte_acc = {
n : int;
has_previous : bool;
acc : 'a;
cte_index : int option;
latest_expression : Path.t Expression.T.t list;
}
let add_inner : conf:ImporterSyntax.t -> int -> Buffer.t -> unit =
fun ~conf n b ->
let name = "filter" ^ string_of_int n in
(* We use an INNER JOIN here because we want to be sure to get all the rows
fetched by the CTE *)
Buffer.add_string b "\nINNER JOIN '";
Buffer.add_string b name;
Buffer.add_string b "' ON ";
Buffer.add_string b name;
Buffer.add_string b ".id = ";
Buffer.add_string b conf.source.name;
Buffer.add_string b ".id\n"
let print :
conf:ImporterSyntax.t ->
(Chunk.t * Chunk.t) cte_acc ->
ImporterSyntax.CTE.t ->
(Chunk.t * Chunk.t) cte_acc =
fun ~conf acc cte ->
let predicates, query = acc.acc in
let n = acc.n in
let cte_index =
match cte.ImporterSyntax.CTE.group with
| Some expression ->
begin
if acc.has_previous then Chunk.add_string query ", "
else Chunk.add_string query "WITH "
end;
Chunk.add_string query "filter";
Chunk.add_string query (string_of_int n);
Chunk.add_string query " AS (";
Chunk.add_string query "SELECT ";
Chunk.add_string query conf.source.name;
Chunk.add_string query ".id, ";
Chunk.add_expression ~repr:(Printers.path ~conf) query expression;
Chunk.add_string query " AS group_function";
Chunk.create_from_statement_of_chunck conf query;
if acc.has_previous then begin
let previous_name = "filter" ^ string_of_int (n - 1) in
add_inner ~conf (n - 1) query.Chunk.b;
Chunk.add_string query "WHERE ";
Chunk.add_string query previous_name;
Chunk.add_string query ".group_function"
end;
begin
match cte.ImporterSyntax.CTE.filters with
| [] -> ()
| _ ->
Chunk.add_string query " WHERE ";
Chunk.add_expressions ~sep:"\nAND " ~repr:(Printers.path ~conf)
query cte.ImporterSyntax.CTE.filters
end;
Chunk.add_string query ")\n";
Some acc.n
| None ->
(* Do not add the filters in the CTE (we don’t have any) but in the main
query *)
Chunk.add_string predicates "WHERE ";
Chunk.add_expressions ~sep:"\nAND " ~repr:(Printers.path ~conf)
predicates cte.ImporterSyntax.CTE.filters;
acc.cte_index
in
{
acc with
has_previous = true;
n = acc.n + 1;
cte_index;
latest_expression = cte.ImporterSyntax.CTE.filters;
}
let generate_sql :
conf:ImporterSyntax.t -> ImporterSyntax.CTE.t list -> Chunk.t -> Chunk.t =
fun ~conf filters links' ->
let predicates = Chunk.create () and links = Chunk.create () in
let eval =
List.fold_left filters
~init:
{
n = 0;
has_previous = false;
acc = (links, predicates);
cte_index = None;
latest_expression = [];
}
~f:(print ~conf)
in
match (eval.cte_index, eval.latest_expression) with
| None, [] -> predicates
| None, _ ->
Chunk.add_string links' " ";
Chunk.append ~head:links' ~tail:links;
predicates
| Some n, [] ->
add_inner ~conf n links'.b;
Chunk.append ~head:links' ~tail:links;
Chunk.add_string links' "filter";
Chunk.add_string links' (string_of_int n);
Chunk.add_string links' ".group_function";
predicates
| Some n, _ ->
add_inner ~conf n links'.b;
Chunk.append ~head:links' ~tail:links;
Chunk.add_string links' " AND filter";
Chunk.add_string links' (string_of_int n);
Chunk.add_string links' ".group_function";
predicates
|