mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-09-07 02:17:22 +02:00
fix(import): treat a pair's row ID as identity, not content
Headers, URL parameters, and environment variables each carry an `id` that identifies the row to the pair editor. Importers leave it empty and the editor stamps one in the first time it touches a resource, so merely opening an imported request made the next import report it as locally edited. `comparable` now drops `id` at every level rather than only the top, since a row ID says no more about content than the model's own ID. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6796569466
commit
64b9479deb
@@ -1005,17 +1005,33 @@ enum KeyStatus<'a> {
|
||||
/// The deprecated environment `base` flag mirrors `parentModel`, which is compared already.
|
||||
/// Importers number `sortPriority` from source order, so comparing it would turn one insertion
|
||||
/// into an update of everything after it.
|
||||
fn comparable(mut value: Value) -> Value {
|
||||
fn comparable(value: Value) -> Value {
|
||||
let mut value = strip_ids(value);
|
||||
if let Some(object) = value.as_object_mut() {
|
||||
for field in
|
||||
["id", "model", "workspaceId", "createdAt", "updatedAt", "base", "sortPriority"]
|
||||
{
|
||||
for field in ["model", "workspaceId", "createdAt", "updatedAt", "base", "sortPriority"] {
|
||||
object.remove(field);
|
||||
}
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
/// A header, parameter, or variable carries an `id` that identifies its row to the editor rather
|
||||
/// than anything about its content, and the editor fills those in the first time it touches a
|
||||
/// resource. Dropping every `id` keeps that from reading as a local edit.
|
||||
fn strip_ids(value: Value) -> Value {
|
||||
match value {
|
||||
Value::Object(object) => Value::Object(
|
||||
object
|
||||
.into_iter()
|
||||
.filter(|(key, _)| key != "id")
|
||||
.map(|(key, value)| (key, strip_ids(value)))
|
||||
.collect(),
|
||||
),
|
||||
Value::Array(items) => Value::Array(items.into_iter().map(strip_ids).collect()),
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
const CONTENT_HASH_VERSION: &str = "v1:";
|
||||
|
||||
/// Identifies a resource's content well enough to tell "changed since the last import" from
|
||||
@@ -1920,11 +1936,18 @@ mod tests {
|
||||
}
|
||||
|
||||
fn first_import(query_manager: &QueryManager) -> BatchUpsertResult {
|
||||
first_import_with(query_manager, imported_resources())
|
||||
}
|
||||
|
||||
fn first_import_with(
|
||||
query_manager: &QueryManager,
|
||||
resources: ImportResources,
|
||||
) -> BatchUpsertResult {
|
||||
let plan = plan_import_resources(
|
||||
query_manager,
|
||||
"OpenAPI".to_string(),
|
||||
ImportDestination::NewWorkspace,
|
||||
imported_resources(),
|
||||
resources,
|
||||
Some(importer_keys()),
|
||||
Some(linked_origin()),
|
||||
)
|
||||
@@ -2563,6 +2586,49 @@ mod tests {
|
||||
assert_eq!(root.resolution, Some(ImportConflictResolution::KeepMine));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filling_in_editor_row_ids_is_not_an_edit() {
|
||||
let (query_manager, _blob_manager, _rx) =
|
||||
yaak_models::init_in_memory().expect("initialize database");
|
||||
let mut resources = imported_resources();
|
||||
resources.http_requests[0].headers = vec![HttpRequestHeader {
|
||||
enabled: true,
|
||||
name: "Accept".to_string(),
|
||||
value: "application/json".to_string(),
|
||||
id: None,
|
||||
}];
|
||||
let committed = first_import_with(&query_manager, resources.clone());
|
||||
let workspace_id = committed.workspaces[0].id.clone();
|
||||
let root_id = committed
|
||||
.http_requests
|
||||
.iter()
|
||||
.find(|r| r.name == "Root Request")
|
||||
.expect("root request")
|
||||
.id
|
||||
.clone();
|
||||
|
||||
// Opening the request in the editor stamps a row ID onto every header it renders.
|
||||
{
|
||||
let db = query_manager.connect();
|
||||
let root = db.get_http_request(&root_id).expect("get root");
|
||||
let headers = root
|
||||
.headers
|
||||
.iter()
|
||||
.map(|h| HttpRequestHeader { id: Some("hd_generated".to_string()), ..h.clone() })
|
||||
.collect();
|
||||
db.upsert_http_request(&HttpRequest { headers, ..root }, &UpdateSource::Background)
|
||||
.expect("stamp row ids");
|
||||
}
|
||||
|
||||
let plan = replan(&query_manager, &workspace_id, resources);
|
||||
assert_eq!(
|
||||
item_by_name(&plan, "Root Request").action,
|
||||
ImportPlanAction::Unchanged,
|
||||
"a row ID is not content: {:?}",
|
||||
item_by_name(&plan, "Root Request").changed_fields,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reordering_the_source_document_changes_nothing() {
|
||||
let (query_manager, _blob_manager, _rx) =
|
||||
|
||||
Reference in New Issue
Block a user