diff options
Diffstat (limited to 'bs5/universal/native/DB.ml')
-rw-r--r-- | bs5/universal/native/DB.ml | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/bs5/universal/native/DB.ml b/bs5/universal/native/DB.ml new file mode 100644 index 0000000..53ffa1b --- /dev/null +++ b/bs5/universal/native/DB.ml @@ -0,0 +1,120 @@ +open Lwt.Syntax + +let read_file file = + let ( / ) = Filename.concat in + let path = Sys.getcwd () / "server" / "db" / file in + try%lwt + let%lwt v = Lwt_io.with_file ~mode:Lwt_io.Input path Lwt_io.read in + Lwt_result.return v + with e -> + Dream.log "Error reading file %s: %s" path (Printexc.to_string e); + Lwt.return_error (Printexc.to_string e) + +let parse_note (note : Yojson.Safe.t) : Note.t option = + match note with + | `Assoc fields -> + let id = + fields |> List.assoc "id" |> Yojson.Safe.to_string |> int_of_string + in + let title = fields |> List.assoc "title" |> Yojson.Safe.Util.to_string in + let content = + fields |> List.assoc "content" |> Yojson.Safe.Util.to_string + in + let updated_at = + fields |> List.assoc "updated_at" |> Yojson.Safe.to_string + |> float_of_string + in + Some { Note.id; title; content; updated_at } + | _ -> None + +let parse_notes json = + try + match Yojson.Safe.from_string json with + | `List notes -> notes |> List.filter_map parse_note |> Result.ok + | _ -> Result.error "Invalid notes file format" + with _ -> Result.error "Invalid JSON format format" + +module Cache = struct + let db_cache = ref None + let set value = db_cache := Some value + let read () = !db_cache + let delete () = db_cache := None +end + +let read_notes () = + match Cache.read () with + | Some (Ok notes) -> Lwt_result.return notes + | Some (Error e) -> Lwt_result.fail e + | None -> ( + try%lwt + match%lwt read_file "./notes.json" with + | Ok json -> + Cache.set (parse_notes json); + Lwt_result.lift (parse_notes json) + | Error _ -> Lwt.return_error "Error reading notes file" + with _error -> + (* When something fails, treat it as an empty note db *) + Lwt.return_ok []) + +let find_one notes id = + match notes |> List.find_opt (fun (note : Note.t) -> note.id = id) with + | Some note -> Lwt_result.return note + | None -> Lwt_result.fail ("Note with id " ^ Int.to_string id ^ " not found") + +let add_note ~title ~content = + let%lwt notes = read_notes () in + let notes = + Result.map + (fun notes -> + let length = List.length notes in + let note : Note.t = + { id = length; title; content; updated_at = Unix.time () } + in + note :: notes) + notes + in + Cache.set notes; + Lwt_result.lift (notes |> Result.map (fun notes -> notes |> List.hd)) + +let edit_note ~id ~title ~content = + let%lwt notes = read_notes () in + let notes = + Result.map + (fun notes -> + let notes = + notes + |> List.map (fun (current_note : Note.t) -> + if current_note.id = id then + { + current_note with + title; + content; + updated_at = Unix.time (); + } + else current_note) + in + notes) + notes + in + Cache.set notes; + Lwt_result.lift (notes |> Result.map (fun notes -> notes |> List.hd)) + +let delete_note id = + let%lwt notes = read_notes () in + let notes = + Result.map + (fun notes -> notes |> List.filter (fun (note : Note.t) -> note.id <> id)) + notes + in + Cache.set notes; + Lwt_result.lift notes + +let fetch_note id = + match Cache.read () with + | Some (Ok notes) -> find_one notes id + | Some (Error e) -> Lwt_result.fail e + | None -> ( + let* notes = read_notes () in + match notes with + | Ok notes -> find_one notes id + | Error e -> Lwt_result.fail e) |