diff options
author | Sébastien Dailly <sebastien@dailly.me> | 2024-03-14 08:26:58 +0100 |
---|---|---|
committer | Sébastien Dailly <sebastien@dailly.me> | 2024-03-14 08:26:58 +0100 |
commit | 6b377719c10d5ab3343fd5221f99a4a21008e25a (patch) | |
tree | a7c1e9a820d339a2f161af3e09cf9e3161286796 /lib/sql/hashs.ml |
Initial commitmain
Diffstat (limited to 'lib/sql/hashs.ml')
-rw-r--r-- | lib/sql/hashs.ml | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/lib/sql/hashs.ml b/lib/sql/hashs.ml new file mode 100644 index 0000000..af1f092 --- /dev/null +++ b/lib/sql/hashs.ml @@ -0,0 +1,79 @@ +(** + This module store the hash of the indexes ([extern_key]) for each table in + order to update the file if the configuration changed. + + The hashes are stored in a table named [hashes] and are evaluated just + before inserting the values. +*) + +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 'hashes' ('table' TEXT, 'hash' INTEGER, \ + PRIMARY KEY ('table'))" + |> T.to_result + +let evaluate : ImportAnalyser.Dependency.t -> int = + fun table -> + (* Extract all the references to this table *) + let keys = + List.map (ImportAnalyser.Dependency.keys table) + ~f:(fun ImportAnalyser.Dependency.{ name; columns; expression } -> + ignore columns; + (name, expression)) + in + Hashtbl.hash keys + +let insert : 'a T.t -> ImportAnalyser.Dependency.t -> unit T.result = + fun db table -> + let source = ImportAnalyser.Dependency.table table in + let table_name = Table.name source in + + let hash = evaluate table in + + let query = + String.concat ~sep:"" + [ + "INSERT INTO 'hashes' ('table', 'hash') VALUES ('"; + table_name; + "', :hash) ON CONFLICT(hashes.'table') DO UPDATE SET 'hash' = :hash"; + ] + in + let* statement = + try Ok (Sqlite3.prepare db query) with + | e -> Error e + in + + let* _ = T.begin_transaction db in + let sql_data = Sqlite3.Data.INT (Int64.of_int hash) in + + let* _ = Sqlite3.bind_name statement ":hash" sql_data |> T.to_result in + let* _ = T.to_result (Sqlite3.step statement) in + T.commit db + +let query : 'a T.t -> ImportDataTypes.Table.t -> int option T.result = + fun db table -> + let table_name = Table.name table in + let query = + String.concat ~sep:"" + [ "SELECT hash FROM 'hashes' WHERE hashes.'table' = '"; table_name; "'" ] + in + + let* stmt = + try Ok (Sqlite3.prepare db query) with + | e -> Error e + in + let state, res = + Sqlite3.fold stmt ~init:None ~f:(fun _ d -> + Some (T.to_datatype (Array.get d 0))) + in + + let* _ = T.to_result state in + match res with + | Some (ImportCSV.DataType.Integer i) -> Ok (Some i) + | _ -> Ok None |