aboutsummaryrefslogtreecommitdiff
path: root/lib/sql/header.ml
blob: 3cac5fbb9599204f9c8ff7c39093f85a663598d2 (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
open StdLabels
module Table = ImportDataTypes.Table

let ( let* ) = Result.bind

let create_table : 'a T.t -> unit T.result =
 fun db ->
  Sqlite3.exec db
    "CREATE TABLE IF NOT EXISTS 'header' ('table' TEXT, 'column' INTEGER, \
     'label', PRIMARY KEY ('table', 'column'))"
  |> T.to_result

let insert_header :
    'a T.t ->
    ImportDataTypes.Table.t ->
    (int * ImportCSV.DataType.t) array ->
    unit T.result =
 fun db table values ->
  let table_name = Table.name table in

  let query =
    String.concat ~sep:""
      [
        "INSERT INTO 'header' ('table', 'column', 'label') VALUES ('";
        table_name;
        "', :column, :label) ON CONFLICT(header.'table', header.'column') DO \
         UPDATE SET 'label' = :label";
      ]
  in

  let statement = Sqlite3.prepare db query in

  let* _ = T.begin_transaction db in
  let* _ =
    Array.fold_left values ~init:(Ok ()) ~f:(fun acc (column, value) ->
        let* _ = acc in
        let sql_data = T.of_datatype value in
        let* _ = Sqlite3.bind_name statement ":label" sql_data |> T.to_result in

        let* _ =
          Sqlite3.bind_name statement ":column"
            (Sqlite3.Data.INT (Int64.of_int column))
          |> T.to_result
        in
        let* _ = T.to_result (Sqlite3.step statement) in
        T.reset statement)
  in
  T.commit db

let query_headers :
    'a T.t -> ImportDataTypes.Table.t -> ImportCSV.DataType.t array T.result =
 fun db table ->
  let table_name = Table.name table in
  let query =
    String.concat ~sep:""
      [
        "SELECT label FROM 'header' WHERE header.'table' = '";
        table_name;
        "' ORDER BY column DESC";
      ]
  in

  let* stmt =
    try Ok (Sqlite3.prepare db query) with
    | e -> Error e
  in
  let state, res =
    Sqlite3.fold stmt ~init:[] ~f:(fun acc d ->
        let value = T.to_datatype (Array.get d 0) in
        value :: acc)
  in

  let* _ = T.to_result state in
  Ok (Array.of_list res)