Skip to content

A class's instance list keeps only the members that lack a relation - #1270

Merged
WaylandYang merged 2 commits into
deeplethe:devfrom
gedaiu:feat/instances-lacking-a-predicate
Oct 16, 2026
Merged

WaylandYang merged 2 commits into
deeplethe:devfrom
gedaiu:feat/instances-lacking-a-predicate

Conversation

@gedaiu

@gedaiu gedaiu commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Closes #1269.

What happened

"Which members of this class have no link of this kind" had no read. The instance list (GET /kbs/{id}/ontology/entity-types/{type_id}/entities) lists a class's members but cannot filter by what they lack, so a client asked once per member or exported the base.

What changed

Two optional query parameters: missing_predicate (a relation key or an open phrase) and missing_direction (out, the default, in or either). With them, a member stays only when no live fact links it by that predicate, and the response adds missing: {relation_type_id, phrases} so a typo shows up as "matched nothing" rather than as every member. Without them the route answers as before.

  • ontology::link_predicate resolves the predicate in one query: the relation by key, its inverses (both ways of inverse_of, and the relation itself when symmetric), and the phrases bound to either in phrase_bindings, filed by which end of the relation the member is on. The normalized predicate also counts as an open phrase.
  • entity_instances takes Option<Lacking> and adds one condition, shared by the page and the count: per end, a NOT EXISTS on live facts (typed predicate, or layer = 'open' with a matching normalized phrase) and one on live derived_facts. Both use the existing live subject/object indexes. in swaps the ends, either checks both.
  • Membership is unchanged (e.type_id). A bound phrase counts whatever the binding's signature, since a filter for what is missing should lean towards counting a link.
  • A blank predicate or unknown direction is a 422 (bad_missing_predicate, bad_missing_direction), checked in a pure missing_link before the access check.
  • phrase_bindings::phrase_sql becomes pub(crate) so both sides normalize the same way. One paragraph in docs/design/ontology.md.

No migration.

Tests

an_instance_list_names_what_a_type_lacks (utopia-store): six members of one class, linked by a typed relation, an open phrase with odd spacing and case, the inverse relation, a bound phrase, a derived fact, and nothing. missing_predicate=works_for returns only the last, and the echo names the relation and its phrases; an open phrase on the in end returns the members that are not its object. Each arm was checked by removing it: the test fails for the filter, the typed, open, derived, inverse and bound-phrase arms, and normalization. Two unit tests cover the 422s.

Run in rust:1-slim-bookworm against Postgres with UTOPIA_TEST_REQUIRE_DB=1: cargo fmt --all --check and cargo clippy --workspace --all-targets -- -D warnings clean; cargo test -p utopia-store --test store 312 passed; cargo test -p utopia-server ontology 18 passed.

…elation, so a client finds the statements without a test without asking once per entity or exporting the base

Signed-off-by: Bogdan Szabo <bogdan@re-cinq.com>

@WaylandYang WaylandYang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, this is a clean, contained addition. The anti-join handles inverses both ways, symmetric relations, reverse bindings, derived rows, invalidated facts and merged entities; the page and the total share one condition; and the response is unchanged without the parameters. The two clarifications from #1269 (key-only link_predicate, ended facts still counting) can follow. This and #1265 touch list_entity_instances in the same lines, so #1265 will need a rebase. Merging.

@WaylandYang
WaylandYang merged commit 05e6f5a into deeplethe:dev Oct 16, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants