(*--------------------------------------------------------------------------- Copyright (c) 2026 Anil Madhavapeddy . All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) (** Daily changes with per-day-per-repo structure. This module provides an immutable data structure for loading and querying daily changes from per-day-per-repo JSON files. Files are named [-.json] and contain timestamped entries for real-time tracking. *) (** {1 Types} *) type commit_range = { from_hash : string; to_hash : string; count : int } (** Commit range information. *) type entry = { repository : string; hour : int; timestamp : Ptime.t; summary : string; changes : string list; commit_range : commit_range; contributors : string list; repo_url : string option; } (** A single timestamped changelog entry. *) type day = { repository : string; date : string; entries : entry list; (** Sorted by timestamp ascending. *) } (** All entries for a single repository on a single day. *) module String_map : Map.S with type key = string (** String-keyed map type. *) type t = { by_repo : day list String_map.t; (** Map from repository name to list of days. *) by_date : day list String_map.t; (** Map from date (YYYY-MM-DD) to list of days across repos. *) all_entries : entry list; (** All entries sorted by timestamp ascending. *) } (** Immutable collection of all loaded daily changes. *) (** {1 Construction} *) val empty : t (** Empty daily changes structure. *) val load_all : fs:_ Eio.Path.t -> changes_dir:Fpath.t -> t (** [load_all ~fs ~changes_dir] loads all [-.json] files from the changes directory and returns an immutable structure for querying. *) (** {1 Querying} *) val since : t -> Ptime.t -> entry list (** [since t timestamp] returns all entries with timestamp after [timestamp], sorted by timestamp ascending. *) val for_repo : t -> string -> day list (** [for_repo t repo] returns all days for the given repository, sorted by date descending. *) val for_date : t -> string -> day list (** [for_date t date] returns all days (across repos) for the given date. *) val repos : t -> string list (** [repos t] returns list of all repository names with changes. *) val dates : t -> string list (** [dates t] returns list of all dates with changes, sorted descending. *) (** {1 File Discovery} *) val list_repos : fs:_ Eio.Path.t -> changes_dir:Fpath.t -> string list (** [list_repos ~fs ~changes_dir] returns all repository names that have daily change files. *) val list_dates : fs:_ Eio.Path.t -> changes_dir:Fpath.t -> repo:string -> string list (** [list_dates ~fs ~changes_dir ~repo] returns all dates for which the given repository has change files. *) (** {1 Loading Individual Files} *) val load_repo_day : fs:_ Eio.Path.t -> changes_dir:Fpath.t -> repo:string -> date:string -> entry list (** [load_repo_day ~fs ~changes_dir ~repo ~date] loads entries for a specific repo and date. Returns empty list if file doesn't exist. *) val load_repo_all : fs:_ Eio.Path.t -> changes_dir:Fpath.t -> repo:string -> entry list (** [load_repo_all ~fs ~changes_dir ~repo] loads all entries for a repository across all dates. *) val entries_since : fs:_ Eio.Path.t -> changes_dir:Fpath.t -> since:Ptime.t -> entry list (** [entries_since ~fs ~changes_dir ~since] returns all entries created after the given timestamp, useful for real-time updates. *)