///|
/// Typed queries select KV3 files only. Explicit selections reject KV1 files.
pub fn Workspace::select_kv3(
self : Workspace,
expression : String,
files~ : Array[String] = [],
) -> Json raise {
let query = compile_kv3_query(expression)
let rows : Array[Json] = []
let mut total = 0
for name in self.selected_names(files) {
guard self.kv3_documents.get(name) is Some(document) else {
if !files.is_empty() {
raise InvalidQuery("Selected file is not KV3")
}
continue
}
let matches = query.select(document.document())
total += matches.length()
if total > 10000 {
raise InvalidQuery("Workspace exceeds 10000 query matches")
}
if !matches.is_empty() {
rows.push(
Json::object({
"file": Json::string(name),
"matches": kv3_located_values_to_json(matches),
}),
)
}
}
Json::array(rows)
}
///|
/// All targets use original file snapshots. Failure returns no partial workspace.
pub fn Workspace::edit_query_kv3(
self : Workspace,
expression : String,
operation : KV3QueryEdit,
files~ : Array[String] = [],
) -> Workspace raise {
self.select_kv3(expression, files~) |> ignore
let output = self.files()
for name in self.selected_names(files) {
if self.kv3_documents.get(name) is Some(document) {
output[name] = document.edit_query(expression, operation).text()
}
}
new_workspace(output, options=self.options)
}
///|
pub fn query_workspace_kv3_snapshot(
snapshot : Json,
expression : String,
files~ : Array[String] = [],
options~ : ParseOptions = ParseOptions::default(),
) -> Json raise {
guard snapshot is Object(fields) &&
fields.get("format") == Some(Json::string("moonvalve-project-v1")) &&
fields.get("source") is Some(String(source)) &&
fields.get("files") is Some(contents) else {
raise InvalidReference("Expected MoonValve project snapshot")
}
let workspace = workspace_from_json(contents, options~)
if !workspace.has_file(source) {
raise InvalidReference("Snapshot entry is missing")
}
workspace.select_kv3(expression, files~)
}