Handle self-referencing FK filter propagation during subsetting#19
Handle self-referencing FK filter propagation during subsetting#19
Conversation
a5595e0 to
868e3de
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates subsetting filter propagation to correctly handle self-referencing foreign keys by generating recursive CTE-based constraints, and adds unit/integration coverage using new departments/projects/assignments fixtures.
Changes:
- Add recursive-CTE generation for self-referencing FK propagation in
FilterPropagation. - Adjust FK processing order so non-self (cross-table) FK filters are applied before self-ref handling.
- Extend unit + integration tests and add new schema/data fixtures for a 3-table chain with a self-ref FK.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
simple-anonymizer/src/scala/simpleanonymizer/FilterPropagation.scala |
Adds recursive CTE generation for self-referencing FK propagation and processes non-self FKs first. |
tests/src/scala/simpleanonymizer/FilterPropagationTest.scala |
Adds unit tests asserting self-ref recursive CTE behavior (explicit + propagated filter, and no-filter case). |
integration-tests/src/scala/simpleanonymizer/DbCopierIntegrationTest.scala |
Adds an integration test verifying cross-table propagation + self-ref exclusion behavior; updates existing tests to include/skip new tables. |
integration-tests/src/resources/01-schema.sql |
Adds departments, projects (self-ref), and assignments tables for integration coverage. |
integration-tests/src/resources/02-data.sql |
Seeds departments/projects/assignments data including a cross-dept parent edge case. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
simple-anonymizer/src/scala/simpleanonymizer/FilterPropagation.scala
Outdated
Show resolved
Hide resolved
simple-anonymizer/src/scala/simpleanonymizer/FilterPropagation.scala
Outdated
Show resolved
Hide resolved
simple-anonymizer/src/scala/simpleanonymizer/FilterPropagation.scala
Outdated
Show resolved
Hide resolved
868e3de to
ea9e8ac
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ea9e8ac to
b34a7b0
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
simple-anonymizer/src/scala/simpleanonymizer/FilterPropagation.scala
Outdated
Show resolved
Hide resolved
simple-anonymizer/src/scala/simpleanonymizer/FilterPropagation.scala
Outdated
Show resolved
Hide resolved
simple-anonymizer/src/scala/simpleanonymizer/FilterPropagation.scala
Outdated
Show resolved
Hide resolved
When subsetting with FilterPropagation, self-referencing FKs were ignored because the table's own propagated filter hadn't been computed yet (accumulated.get(table) was always None). This caused rows with dangling self-ref FK pointers to be copied, violating FK integrity. Fix: process cross-table FKs first, then for self-ref FKs use the in-progress accumulator (which already has cross-table clauses) and generate a recursive CTE to compute the transitive closure of reachable rows through the self-ref chain. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
b34a7b0 to
6f1c3cc
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Introduce LogicalFK to group multi-column FK constraints and generate correct tuple-based SQL (e.g., (fk1, fk2) IN (SELECT pk1, pk2 ...)). Extract quotedCols/sqlTuple helpers to eliminate double-quoting and repetition. Fix sqlTuple misuse in SELECT column lists where plain comma-separated lists are needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
simple-anonymizer/src/scala/simpleanonymizer/FilterPropagation.scala
Outdated
Show resolved
Hide resolved
Move qualified-name quoting into SlickProfile.quoteQualified (two overloads) and LogicalFK/groupFKs into DbContext, adding a memoized logicalForeignKeys lazy val. All consumers now share these abstractions instead of duplicating the logic. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1143eb0 to
c85c181
Compare
When a table has multiple self-referencing FKs (e.g., manager_id and mentor_id), compute each recursive CTE from the same base filter (explicit + cross-ref) rather than chaining them sequentially, which would nest one CTE inside another's filter. Use unique CTE names (_reachable_<tablename>) and prefix CTE columns with _r_ to avoid ambiguity with base table columns in the WHERE clause. Also refactor tests to construct LogicalFK directly instead of routing through MForeignKey + groupFKs, matching the actual API surface. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
c85c181 to
dcd1209
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
FilterPropagationnow correctly handles self-referencing FKs by generating recursive CTEs that compute the transitive closure of reachable rowsTest plan
🤖 Generated with Claude Code