8000 bug(query): or/or-join deduplication silently missed identical bindings (fixed in 4c8270d, needs test) · Issue #82 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

bug(query): or/or-join deduplication silently missed identical bindings (fixed in 4c8270d, needs test) #82

Closed

Description

@adityamukho

Summary

Commit 4c8270d (merged without a PR or issue) fixed a silent correctness bug in apply_or_clauses in src/query/datalog/executor.rs.

The bug

or and or-join deduplication used BTreeSet<Vec<(String, Value)>> to track seen bindings. The key was constructed as:

let key: Vec<_> = b.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
seen.insert(key);

b is a HashMap<String, Value>. HashMap::iter() returns entries in non-deterministic order. Two bindings that are logically identical (same key-value pairs) can produce different Vec orderings on different iterations, causing BTreeSet::insert to treat them as distinct and failing to deduplicate. The result: duplicate result rows in queries using or or or-join.

The fix (already applied)

4c8270d added key.sort_unstable() before seen.insert(key), normalising the key order so identical bindings always produce the same vector and deduplicate correctly.

What's still missing

A regression test. The fix was applied without a test that would catch a regression. A future refactor could accidentally revert the sort.

Suggested test

Add an integration test in tests/disjunction_test.rs (or a new tests/or_dedup_test.rs):

#[test]
fn or_does_not_return_duplicate_bindings() {
    // Setup: entity has both :tag-a true and :tag-b true.
    // Query: (query [:find ?e :where (or [?e :tag-a true] [?e :tag-b true])])
    // Expected: exactly one result row for ?e, not two.
    let db = Minigraf::open_in_memory().unwrap();
    db.execute(r#"(transact [[:db/add "e1" :tag-a true]
                              [:db/add "e1" :tag-b true]])"#).unwrap();
    let results = db.execute(
        r#"(query [:find ?e :where (or [?e :tag-a true] [?e :tag-b true])])"#
    ).unwrap();
    assert_eq!(results.len(), 1, "entity matching both branches must appear exactly once");
}

Do NOT use {:?} format on Result or any type containing Uuid in assert messages (CLAUDE.md testing conventions).

Files

  • src/query/datalog/executor.rs — apply_or_clauses (lines ~1190–1255)
  • tests/disjunction_test.rs — add the regression test

Activity

  1. added 2 commits that reference this issue on Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstabilityStability/panic issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0