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)