Establishes version control for the personal Logseq DB fork before starting the server-client architecture migration and domain features described in docs/agent-guide and the approved implementation plan. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
130 lines
4.0 KiB
OCaml
130 lines
4.0 KiB
OCaml
type status = { ident : Cli_primitive.keyword; value : string }
|
|
|
|
let kw value = Edn_util.keyword value
|
|
let sym value = Edn_util.symbol value
|
|
let vector_vec values = Edn_util.vector_vec values
|
|
let vector_t_vec values = Edn_util.vector_t_vec values
|
|
|
|
let status_closed_values_query =
|
|
Cli_primitive.(
|
|
make_datascript_query
|
|
~find:
|
|
(Vec.singleton
|
|
(vector_vec (Vec.of_array [| sym "?status-ident"; sym "..." |])))
|
|
~where:
|
|
(Vec.of_array
|
|
[|
|
|
V
|
|
(vector_t_vec
|
|
(Vec.of_array
|
|
[|
|
|
sym "?property";
|
|
kw "db/ident";
|
|
kw "logseq.property/status";
|
|
|]));
|
|
V
|
|
(vector_t_vec
|
|
(Vec.of_array
|
|
[|
|
|
sym "?value";
|
|
kw "block/closed-value-property";
|
|
sym "?property";
|
|
|]));
|
|
V
|
|
(vector_t_vec
|
|
(Vec.of_array
|
|
[| sym "?value"; kw "db/ident"; sym "?status-ident" |]));
|
|
|])
|
|
()
|
|
|> datascript_query_to_edn)
|
|
|
|
let starts_with ~prefix value =
|
|
let prefix_len = String.length prefix in
|
|
String.length value >= prefix_len && String.sub value 0 prefix_len = prefix
|
|
|
|
let drop_prefix prefix value =
|
|
if starts_with ~prefix value then
|
|
String.sub value (String.length prefix)
|
|
(String.length value - String.length prefix)
|
|
else value
|
|
|
|
let normalize_token value =
|
|
value |> String.trim |> String.lowercase_ascii |> drop_prefix ":"
|
|
|> drop_prefix "logseq.property/status."
|
|
|> drop_prefix "status."
|
|
|> String.map (function ' ' | '_' -> '-' | c -> c)
|
|
|
|
let status_value_of_ident ident =
|
|
ident |> drop_prefix ":"
|
|
|> drop_prefix "logseq.property/status."
|
|
|> drop_prefix "status." |> normalize_token
|
|
|
|
let keyword_of_string value = Edn_util.keyword_t value
|
|
|
|
let status_of_value value =
|
|
match Edn_util.as_string_like value with
|
|
| Some ident ->
|
|
let value = status_value_of_ident ident in
|
|
if value = "" || value = ident then None
|
|
else Some { ident = keyword_of_string ident; value }
|
|
| None -> (
|
|
match Edn_util.as_map value with
|
|
| None -> None
|
|
| Some fields -> (
|
|
let value_of_key key =
|
|
Vec.find_map
|
|
(fun (k, v) ->
|
|
match Edn_util.as_string_like k with
|
|
| Some k when k = key -> Some v
|
|
| _ -> None)
|
|
fields
|
|
in
|
|
let ident =
|
|
match
|
|
Option.bind (value_of_key "ident") Edn_util.as_string_like
|
|
with
|
|
| Some ident -> Some (keyword_of_string ident)
|
|
| None -> None
|
|
in
|
|
let value =
|
|
match
|
|
Option.bind (value_of_key "value") Edn_util.as_string_like
|
|
with
|
|
| Some value -> Some (normalize_token value)
|
|
| _ ->
|
|
Option.map
|
|
(fun ident ->
|
|
status_value_of_ident (Edn_util.keyword_to_string ident))
|
|
ident
|
|
in
|
|
match (ident, value) with
|
|
| Some ident, Some value when value <> "" -> Some { ident; value }
|
|
| _ -> None))
|
|
|
|
let normalize_available_statuses values =
|
|
values
|
|
|> Vec.filter_map status_of_value
|
|
|> Vec.sort (fun a b -> compare (a.value, a.ident) (b.value, b.ident))
|
|
|
|
let resolve_status_ident value statuses =
|
|
let token = normalize_token value in
|
|
let ident_from_token =
|
|
keyword_of_string ("logseq.property/status." ^ token)
|
|
in
|
|
statuses
|
|
|> Vec.find_map (fun s ->
|
|
if
|
|
s.value = token
|
|
|| s.ident = keyword_of_string value
|
|
|| s.ident = ident_from_token
|
|
then Some s.ident
|
|
else None)
|
|
|
|
let invalid_status_message value statuses =
|
|
let available =
|
|
statuses |> Vec.map (fun s -> s.value) |> Vec.string_concat ", "
|
|
in
|
|
let available = if available = "" then "(none)" else available in
|
|
"Invalid value for option :status: " ^ value ^ ". Available values: "
|
|
^ available
|