queryer: don't emit a parent type-bound for reified-relationship properties
A SINGLE reified-relationship property (e.g. invoice.counterparty, person.primary_contact — a property whose type is a relationship subtype) is hydrated by a correlated subquery that joins the relationship table and correlates source_id/target_id = parent.id; its discriminators (the relationship subtype and the target's type CASE) are constrained INSIDE that subquery. For such a property the resolved edge is a REVERSE traversal (forward = false) over a generic relationship FK (fk_relationship_source_entity, destination = entity). compile_ polymorphic_bounds then took the `!edge.forward` branch with poly_col = destination_columns[1] = "type" and table_to_alias = "entity", which resolves to the PARENT's entity alias — emitting a bound like `entity_1.type = 'counterparty'` into the parent WHERE. No parent row has that type, so EVERY parent was dropped (e.g. get_invoice returned null for an existing invoice whose counterparty edge was absent). Array reified traversals (contacts, occupancies) never hit this: an array property has no bound_type_name. Only the single form did, and it was previously unexercised. Fix: in compile_polymorphic_bounds, skip the bound when the property's resolved type is itself a relationship (type_def.relationship) — there is no parent-row discriminator column to bound. Test: new queryer case (person.primary_contact, type=contact) asserts the parent WHERE has no spurious entity.type bound while the subquery keeps its discriminator + source_id correlation. Full suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -604,6 +604,17 @@ impl<'a> Compiler<'a> {
|
||||
if let Some(type_name) = bound_type_name {
|
||||
// Ensure this type actually exists
|
||||
if let Some(type_def) = self.db.types.get(&type_name) {
|
||||
// A reified-relationship property (e.g. invoice.counterparty, person.primary_contact)
|
||||
// is hydrated by a correlated subquery that joins the relationship table and correlates
|
||||
// source_id/target_id = parent.id; its discriminators (the relationship subtype and the
|
||||
// target's type CASE) are constrained INSIDE that subquery. There is no parent-row column
|
||||
// to bound here — emitting one wrongly constrains the PARENT entity's own `type` column
|
||||
// (e.g. `entity_1.type = 'counterparty'`), which no parent row satisfies, dropping every
|
||||
// parent. (Array reified traversals never reach this code: an array prop has no
|
||||
// bound_type_name.) So skip the bound entirely for relationship-typed properties.
|
||||
if type_def.relationship {
|
||||
continue;
|
||||
}
|
||||
if let Some(relation) = self.db.relations.get(&edge.constraint) {
|
||||
let mut poly_col = None;
|
||||
let mut table_to_alias = "";
|
||||
|
||||
Reference in New Issue
Block a user