diff --git a/fixtures/merger.json b/fixtures/merger.json index 3608978..3688345 100644 --- a/fixtures/merger.json +++ b/fixtures/merger.json @@ -1461,17 +1461,7 @@ "success": true, "sql": [ [ - "(SELECT to_jsonb(t1.*) || to_jsonb(t2.*) || to_jsonb(t3.*) || to_jsonb(t4.*)", - "FROM agreego.\"entity\" t1", - "JOIN agreego.\"organization\" t2 ON ", - "JOIN agreego.\"user\" t3 ON ", - "JOIN agreego.\"person\" t4 ON ", - "WHERE", - " t1.id = '{{uuid:data.id}}'", - " OR (\"first_name\" = 'LookupFirst'", - " AND \"last_name\" = 'LookupLast'", - " AND \"date_of_birth\" = '{{timestamp}}'", - " AND \"pronouns\" = 'they/them'))" + "(SELECT to_jsonb(t1.*) || to_jsonb(t2.*) || to_jsonb(t3.*) || to_jsonb(t4.*) FROM agreego.\"entity\" t1 LEFT JOIN agreego.\"organization\" t2 ON t2.id = t1.id LEFT JOIN agreego.\"user\" t3 ON t3.id = t1.id LEFT JOIN agreego.\"person\" t4 ON t4.id = t1.id WHERE t1.id = '{{uuid:data.id}}' UNION SELECT to_jsonb(t1.*) || to_jsonb(t2.*) || to_jsonb(t3.*) || to_jsonb(t4.*) FROM agreego.\"entity\" t1 LEFT JOIN agreego.\"organization\" t2 ON t2.id = t1.id LEFT JOIN agreego.\"user\" t3 ON t3.id = t1.id LEFT JOIN agreego.\"person\" t4 ON t4.id = t1.id WHERE (\"first_name\" = 'LookupFirst' AND \"last_name\" = 'LookupLast' AND \"date_of_birth\" = '{{timestamp}}' AND \"pronouns\" = 'they/them'))" ], [ "INSERT INTO agreego.\"entity\" (", @@ -1614,17 +1604,7 @@ "success": true, "sql": [ [ - "(SELECT to_jsonb(t1.*) || to_jsonb(t2.*) || to_jsonb(t3.*) || to_jsonb(t4.*)", - "FROM agreego.\"entity\" t1", - "JOIN agreego.\"organization\" t2 ON ", - "JOIN agreego.\"user\" t3 ON ", - "JOIN agreego.\"person\" t4 ON ", - "WHERE", - " t1.id = '{{uuid:data.id}}'", - " OR (\"first_name\" = 'LookupFirst'", - " AND \"last_name\" = 'LookupLast'", - " AND \"date_of_birth\" = '{{timestamp}}'", - " AND \"pronouns\" = 'they/them'))" + "(SELECT to_jsonb(t1.*) || to_jsonb(t2.*) || to_jsonb(t3.*) || to_jsonb(t4.*) FROM agreego.\"entity\" t1 LEFT JOIN agreego.\"organization\" t2 ON t2.id = t1.id LEFT JOIN agreego.\"user\" t3 ON t3.id = t1.id LEFT JOIN agreego.\"person\" t4 ON t4.id = t1.id WHERE t1.id = '{{uuid:data.id}}' UNION SELECT to_jsonb(t1.*) || to_jsonb(t2.*) || to_jsonb(t3.*) || to_jsonb(t4.*) FROM agreego.\"entity\" t1 LEFT JOIN agreego.\"organization\" t2 ON t2.id = t1.id LEFT JOIN agreego.\"user\" t3 ON t3.id = t1.id LEFT JOIN agreego.\"person\" t4 ON t4.id = t1.id WHERE (\"first_name\" = 'LookupFirst' AND \"last_name\" = 'LookupLast' AND \"date_of_birth\" = '{{timestamp}}' AND \"pronouns\" = 'they/them'))" ], [ "INSERT INTO agreego.\"entity\" (", @@ -2219,12 +2199,7 @@ "success": true, "sql": [ [ - "(SELECT to_jsonb(t1.*) || to_jsonb(t2.*)", - "FROM agreego.\"entity\" t1", - "JOIN agreego.\"order\" t2 ON ", - "WHERE", - " t1.id = 'abc'", - " OR (\"id\" = 'abc'))" + "(SELECT to_jsonb(t1.*) || to_jsonb(t2.*) FROM agreego.\"entity\" t1 LEFT JOIN agreego.\"order\" t2 ON t2.id = t1.id WHERE t1.id = 'abc' UNION SELECT to_jsonb(t1.*) || to_jsonb(t2.*) FROM agreego.\"entity\" t1 LEFT JOIN agreego.\"order\" t2 ON t2.id = t1.id WHERE (\"id\" = 'abc'))" ], [ "INSERT INTO agreego.\"entity\" (", @@ -3499,12 +3474,7 @@ "success": true, "sql": [ [ - "(SELECT to_jsonb(t1.*) || to_jsonb(t2.*)", - "FROM agreego.\"entity\" t1", - "JOIN agreego.\"invoice\" t2 ON ", - "WHERE", - " t1.id = '{{uuid:data.id}}'", - " OR (\"id\" = '{{uuid:data.id}}'))" + "(SELECT to_jsonb(t1.*) || to_jsonb(t2.*) FROM agreego.\"entity\" t1 LEFT JOIN agreego.\"invoice\" t2 ON t2.id = t1.id WHERE t1.id = '{{uuid:data.id}}' UNION SELECT to_jsonb(t1.*) || to_jsonb(t2.*) FROM agreego.\"entity\" t1 LEFT JOIN agreego.\"invoice\" t2 ON t2.id = t1.id WHERE (\"id\" = '{{uuid:data.id}}'))" ], [ "INSERT INTO agreego.\"entity\" (", diff --git a/src/merger/mod.rs b/src/merger/mod.rs index ce5fcb2..0159fea 100644 --- a/src/merger/mod.rs +++ b/src/merger/mod.rs @@ -744,9 +744,19 @@ impl Merger { return Ok(None); } - let where_clause = format!("WHERE {}", where_parts.join(" OR ")); - - let final_sql = format!("{} {}", fetch_sql_template, where_clause); + // An OR across the hierarchy join is un-indexable — it forces a full scan + // of the subtype table on every child merge. UNION lets each arm use its + // own index (pk for the id arm, the lk_ unique index for the lookup arm) + // and still dedups, so TOO_MANY_LOOKUP_ROWS semantics are preserved. + let final_sql = if where_parts.len() == 1 { + format!("{} WHERE {}", fetch_sql_template, where_parts[0]) + } else { + where_parts + .iter() + .map(|p| format!("{} WHERE {}", fetch_sql_template, p)) + .collect::>() + .join(" UNION ") + }; let fetched = match self.db.query(&final_sql, None) { Ok(Value::Array(table)) => {