Skip to content

feat(database): Add FEATURE_SKIP_CYCLE_CHECK for cyclic FK schemas - #917

Merged
jeffjensen merged 1 commit into
mainfrom
501-skip-cyclic-dependency-check
Aug 8, 2026
Merged

jeffjensen merged 1 commit into
mainfrom
501-skip-cyclic-dependency-check

Conversation

@jeffjensen

@jeffjensen jeffjensen commented Aug 8, 2026

Copy link
Copy Markdown
Member

Summary

  • Add DatabaseConfig.FEATURE_SKIP_CYCLE_CHECK (default false), an opt-in escape hatch letting DatabaseSequenceFilter proceed on a schema with a foreign-key dependency cycle instead of unconditionally rejecting it with CyclicTablesDependencyException.
  • Tables inside a cycle (or only reachable through one) are appended to the sort result in their original input order once the topological sort can no longer place them, so every requested table is still returned exactly once and non-cyclic tables are still ordered correctly around the cycle. The caller becomes responsible for making the cycle insertable another way (e.g. nullable FK columns populated in a later operation, or database-side deferred constraint checking).
  • Documented in filters.adoc and properties.adoc; changes.xml updated.

Fixes #501
Fixes #517
Fixes #411

Test plan

  • Unit tests: DatabaseSequenceFilterTest (default still throws on a cyclic pair; skip-enabled two-table cycle does not throw and returns both tables; skip-enabled three-table case proves a non-cyclic parent still sorts before the appended cycle) and DatabaseConfigTest (default value is false)
  • Integration test: new DatabaseSequenceFilterIT case reusing the existing 5-table hypersonic_cyclic.sql fixture, green against the h2-1-4 and hsqldb-2-7 profiles
  • Full unit suite (2029 tests) green
  • mvnw clean install site green (Javadoc/Checkstyle/AsciiDoc site build, no new warnings)

🤖 Generated with Claude Code

https://claude.ai/code/session_012gmZhDioasFdPtnqxs1ZuP

Summary by Sourcery

Introduce a configurable escape hatch to allow DatabaseSequenceFilter to operate on schemas with circular foreign-key dependencies without failing fast.

New Features:

  • Add DatabaseConfig.FEATURE_SKIP_CYCLE_CHECK to optionally bypass foreign-key dependency cycle detection in DatabaseSequenceFilter and append cyclic tables in input order so all requested tables are returned once.

Enhancements:

  • Update DatabaseSequenceFilter behavior and Javadoc to describe cycle handling when FEATURE_SKIP_CYCLE_CHECK is enabled, including best-effort ordering of cyclic tables.
  • Log a warning when foreign-key dependency cycles are detected but ignored due to FEATURE_SKIP_CYCLE_CHECK.

Documentation:

  • Document FEATURE_SKIP_CYCLE_CHECK in filters and properties documentation and update the release notes to describe the new opt-in cycle-check bypass.

Tests:

  • Add unit and integration tests covering default cycle rejection and skip-enabled behavior for DatabaseSequenceFilter, including ordering with mixed cyclic and non-cyclic tables and default config value for FEATURE_SKIP_CYCLE_CHECK.

Summary by CodeRabbit

  • New Features

    • Added an opt-in setting to bypass cyclic foreign-key dependency checks.
    • When enabled, cyclic tables are processed in input order with warnings instead of failing.
    • Default behavior remains fail-fast, preserving existing validation.
  • Documentation

    • Documented the new setting, ordering behavior, and caller responsibilities when inserting cyclic data.
  • Tests

    • Added coverage for default rejection, bypass behavior, dependency ordering, and warning handling.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sourcery-ai

sourcery-ai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a new DatabaseConfig feature flag, FEATURE_SKIP_CYCLE_CHECK, that allows DatabaseSequenceFilter to bypass foreign-key cycle rejection and instead append cyclic tables in input order so all requested tables are returned once, with accompanying unit/integration tests and documentation/changelog updates.

Sequence diagram for DatabaseSequenceFilter cycle handling with FEATURE_SKIP_CYCLE_CHECK

sequenceDiagram
    participant Caller
    participant IDatabaseConnection as IDatabaseConnection
    participant DatabaseSequenceFilter as DatabaseSequenceFilter
    participant DatabaseConfig as DatabaseConfig
    participant DependencyInfo as DependencyInfo

    Caller->>DatabaseSequenceFilter: sortTableNames(connection, tableNames)
    DatabaseSequenceFilter->>IDatabaseConnection: getConfig()
    IDatabaseConnection-->>DatabaseSequenceFilter: DatabaseConfig
    DatabaseSequenceFilter->>DatabaseConfig: getFeature(FEATURE_SKIP_CYCLE_CHECK)
    DatabaseConfig-->>DatabaseSequenceFilter: skipCycleCheck

    loop for each DependencyInfo in dependencies.values()
        DatabaseSequenceFilter->>DependencyInfo: checkCycles()
        alt CyclicTablesDependencyException thrown
            opt skipCycleCheck is false
                DependencyInfo-->>DatabaseSequenceFilter: CyclicTablesDependencyException
                DatabaseSequenceFilter-->>Caller: throw CyclicTablesDependencyException
            end
            opt skipCycleCheck is true
                DependencyInfo-->>DatabaseSequenceFilter: CyclicTablesDependencyException
                DatabaseSequenceFilter->>DatabaseSequenceFilter: logger.warn(...)
                Note right of DatabaseSequenceFilter: cycle detected but ignored
            end
        end
    end

    DatabaseSequenceFilter->>DatabaseSequenceFilter: sort(connection, tableNames, dependencies)
    alt some tables never reach in-degree 0
        DatabaseSequenceFilter->>DatabaseSequenceFilter: append remaining tables in input order
    end
    DatabaseSequenceFilter-->>Caller: sortedTableNames
Loading

File-Level Changes

Change Details Files
Make DatabaseSequenceFilter optionally skip foreign-key cycle detection and append remaining cyclic tables in input order.
  • Document the new opt-out behavior in DatabaseSequenceFilter Javadoc, including interaction with CyclicTablesDependencyException and DatabaseConfig.FEATURE_SKIP_CYCLE_CHECK.
  • Gate DependencyInfo.checkCycles() with a FEATURE_SKIP_CYCLE_CHECK feature check, converting CyclicTablesDependencyException to a logged warning when the feature is enabled instead of rethrowing.
  • Extend the topological sort to append any tables that never reach in-degree zero (i.e., involved in cycles) in their original tableNames order so every requested table appears exactly once.
src/main/java/org/dbunit/database/DatabaseSequenceFilter.java
Introduce FEATURE_SKIP_CYCLE_CHECK configuration flag in DatabaseConfig with default false.
  • Define the FEATURE_SKIP_CYCLE_CHECK constant and add it to the feature/property registry arrays in DatabaseConfig.
  • Initialize FEATURE_SKIP_CYCLE_CHECK to false in the DatabaseConfig constructor to preserve existing fail-fast behavior by default.
src/main/java/org/dbunit/database/DatabaseConfig.java
Add unit and integration tests validating default cyclic behavior and skip-cycle behavior, including ordering guarantees.
  • Add DatabaseSequenceFilterTest cases for: default cyclic FK pair throwing, skip-enabled cyclic pair returning both tables, and skip-enabled three-table scenario where the non-cyclic parent still precedes the cyclic pair which is appended in original order.
  • Add DatabaseConfigTest case asserting FEATURE_SKIP_CYCLE_CHECK defaults to false.
  • Extend DatabaseSequenceFilterIT with a new case using the existing hypersonic_cyclic.sql fixture to assert that enabling FEATURE_SKIP_CYCLE_CHECK allows cyclic schemas without exceptions and returns all requested tables.
src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java
src/test/java/org/dbunit/database/DatabaseSequenceFilterIT.java
src/test/java/org/dbunit/database/DatabaseConfigTest.java
Update documentation and release notes to describe the new cycle-check bypass feature.
  • Update changes.xml release description and add an action entry documenting FEATURE_SKIP_CYCLE_CHECK as an opt-in escape hatch for cyclic foreign-key schemas.
  • Extend filters.adoc and properties.adoc (not shown in diff body) to describe the new feature flag and its behavior.
src/changes/changes.xml
src/site/asciidoc/filters.adoc
src/site/asciidoc/properties.adoc

Assessment against linked issues

Issue Objective Addressed Explanation
#411 Add a configurable feature to skip cyclic foreign-key/dependency checks so that schemas with cyclic references are not rejected.
#411 Ensure that database operations using DatabaseSequenceFilter can still process all requested tables when cyclic dependencies are present, leaving responsibility for constraint handling to the database (e.g., deferred constraints).
#411 Document the new option to skip cyclic reference checks in the project’s documentation and changelog.
#501 Enable DBUnit to perform CLEAN_INSERT/DELETE_ALL on schemas with circular foreign key references instead of failing due to cycle detection.
#501 Provide a database-agnostic, configurable mechanism to bypass or cope with circular foreign key references in table ordering.
#517 Provide a configurable mechanism to avoid CyclicTablesDependencyException for cyclic foreign-key schemas, allowing dbUnit to proceed on such datasets instead of unconditionally failing.

Possibly linked issues

  • Documentation (wrong code) #130: PR implements the requested opt-in skip of cyclic FK checks via FEATURE_SKIP_CYCLE_CHECK, matching the issue’s feature request.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jeffjensen, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 17 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d2e427d3-b21d-4f8d-b5aa-0bf3e595da91

📥 Commits

Reviewing files that changed from the base of the PR and between 4c63e4c and 8f670b0.

📒 Files selected for processing (3)
  • src/changes/changes.xml
  • src/main/java/org/dbunit/database/DatabaseSequenceFilter.java
  • src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java
📝 Walkthrough

Walkthrough

The change adds the opt-in FEATURE_SKIP_CYCLE_CHECK feature. DatabaseSequenceFilter now detects cyclic components, preserves default rejection, and supports warning-based ordering when enabled. Tests, documentation, and release notes cover the new behavior.

Changes

Cyclic dependency handling

Layer / File(s) Summary
Feature configuration
src/main/java/org/dbunit/database/DatabaseConfig.java
Adds FEATURE_SKIP_CYCLE_CHECK, registers it in configuration properties and compatibility features, and defaults it to false.
Component-based cycle sorting
src/main/java/org/dbunit/database/DatabaseSequenceFilter.java
Detects strongly connected components, orders components by dependencies, preserves input order within cyclic components, and logs skipped cycles.
Behavior validation and release documentation
src/test/java/org/dbunit/database/DatabaseConfigTest.java, src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java, src/test/java/org/dbunit/database/DatabaseSequenceFilterIT.java, src/site/asciidoc/*.adoc, src/changes/changes.xml
Tests cover default rejection, bypass behavior, dependency ordering, table uniqueness, and warning counts. Documentation and release notes describe the feature.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DatabaseSequenceFilter
  participant DatabaseConfig
  participant Logger
  participant CyclicTablesDependencyException
  DatabaseSequenceFilter->>DatabaseConfig: read FEATURE_SKIP_CYCLE_CHECK
  alt cycle checking enabled
    DatabaseSequenceFilter->>CyclicTablesDependencyException: throw for cyclic dependencies
  else cycle checking skipped
    DatabaseSequenceFilter->>Logger: log one warning per cycle
    DatabaseSequenceFilter-->>DatabaseSequenceFilter: order components and restore input order
  end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the new opt-in feature for skipping cyclic foreign-key checks.
Linked Issues check ✅ Passed The implementation provides configurable cycle bypass, preserves default rejection, orders cyclic components, and adds tests and documentation [#501] [#517] [#411].
Out of Scope Changes check ✅ Passed The code, tests, documentation, and changelog changes directly support cyclic foreign-key handling and the new configuration feature.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 501-skip-cyclic-dependency-check

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • When FEATURE_SKIP_CYCLE_CHECK is enabled you still invoke DependencyInfo.checkCycles() for every table and then catch/ignore CyclicTablesDependencyException, which keeps the full cycle-detection cost; consider short-circuiting or providing a cheaper ‘presence-only’ check so opt-in callers don’t pay for work they explicitly chose to skip.
  • The cycle-handling branch in sort() appends all remaining tables purely in their original input order; if there are multiple disjoint cycles or chains reachable through cycles, you might want to document or enforce a more predictable ordering (e.g., per-cycle grouping) to make behavior easier to reason about for callers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- When FEATURE_SKIP_CYCLE_CHECK is enabled you still invoke DependencyInfo.checkCycles() for every table and then catch/ignore CyclicTablesDependencyException, which keeps the full cycle-detection cost; consider short-circuiting or providing a cheaper ‘presence-only’ check so opt-in callers don’t pay for work they explicitly chose to skip.
- The cycle-handling branch in sort() appends all remaining tables purely in their original input order; if there are multiple disjoint cycles or chains reachable through cycles, you might want to document or enforce a more predictable ordering (e.g., per-cycle grouping) to make behavior easier to reason about for callers.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/org/dbunit/database/DatabaseSequenceFilter.java`:
- Around line 254-274: The fallback in DatabaseSequenceFilter must not append
all unresolved tables in raw input order; replace it with strongly connected
component collapse and topological ordering so cyclic component members retain
input order while acyclic descendants remain after their dependencies. In
src/main/java/org/dbunit/database/DatabaseSequenceFilter.java#L254-L274,
implement this ordering change. In
src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java#L230-L260, add
C -> A with A <-> B and assert A precedes C. In
src/changes/changes.xml#L245-L247, remove the claim that tables reachable
through a cycle are appended in input order.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 168ee5d1-bc90-4b59-871d-bd261c34efff

📥 Commits

Reviewing files that changed from the base of the PR and between 560b7ac and 69ea4b9.

📒 Files selected for processing (8)
  • src/changes/changes.xml
  • src/main/java/org/dbunit/database/DatabaseConfig.java
  • src/main/java/org/dbunit/database/DatabaseSequenceFilter.java
  • src/site/asciidoc/filters.adoc
  • src/site/asciidoc/properties.adoc
  • src/test/java/org/dbunit/database/DatabaseConfigTest.java
  • src/test/java/org/dbunit/database/DatabaseSequenceFilterIT.java
  • src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java

Comment thread src/main/java/org/dbunit/database/DatabaseSequenceFilter.java Outdated
@jeffjensen

Copy link
Copy Markdown
Member Author

Addressing @sourcery-ai's two review points:

  • checkCycles() cost when the feature is enabled: left as-is. The expensive part — the transitive DFS/JDBC metadata searches building allTableDependsOn/allTableDependent in getDependencyInfo() — happens earlier regardless of this flag, and sort() now needs those same transitive sets itself for strongly-connected-component grouping (see below), so there's nothing left to meaningfully short-circuit. checkCycles()'s own cost is just a HashSet copy + retainAll per table, which already ran unconditionally on every DatabaseSequenceFilter call before this PR — this PR doesn't add cost to it. The warning it lets us log when a cycle is bypassed has real diagnostic value I'd rather keep than trade away for a negligible saving on an already-cheap check.
  • Per-cycle grouping for predictable ordering: good catch, and it turned out to be connected to a real correctness bug CodeRabbit flagged in the same fallback (a table merely depending on a cyclic table, not itself part of the cycle, could be misordered). Fixed both together: sort() now collapses each cycle into a strongly connected component and topologically sorts the condensed component graph, so multiple disjoint cycles — and any acyclic tables depending on them — are always ordered correctly relative to each other. Only the relative order of tables within the same cyclic component remains input-order, now documented precisely instead of the previous overclaim.

@jeffjensen
jeffjensen force-pushed the 501-skip-cyclic-dependency-check branch 2 times, most recently from b500959 to 4c63e4c Compare August 8, 2026 03:01

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java (2)

208-211: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use AssertJ for the exception assertion.

The rest of this file asserts with AssertJ. The coding guidelines prefer AssertJ and .as() failure messages. Replace assertThrows with assertThatThrownBy.

♻️ Proposed refactor
-        assertThrows(CyclicTablesDependencyException.class,
-                () -> DatabaseSequenceFilter.sortTableNames(connection,
-                        new String[] {"A", "B"}),
-                "A foreign key dependency cycle between A and B must be rejected by default.");
+        assertThatThrownBy(() -> DatabaseSequenceFilter.sortTableNames(connection,
+                new String[] {"A", "B"}))
+                .as("A foreign key dependency cycle between A and B must be rejected by default.")
+                .isInstanceOf(CyclicTablesDependencyException.class);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java` around
lines 208 - 211, In DatabaseSequenceFilterTest, replace the assertThrows
assertion around DatabaseSequenceFilter.sortTableNames with AssertJ’s
assertThatThrownBy, assert the CyclicTablesDependencyException type, and
preserve the existing failure description using AssertJ’s .as() message.

Source: Coding guidelines


315-335: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Set the logger level explicitly so the test does not depend on the ambient logging configuration.

Logback applies the effective level before it calls appenders. If a logback configuration on the test classpath sets the level for org.dbunit or the root logger above WARN, the warning never reaches appender, and hasSize(1) receives 0. Set the level to WARN for the duration of the test and restore the previous value. Stop the appender in the same finally block.

🛠️ Proposed change
         final Logger filterLogger =
                 (Logger) LoggerFactory.getLogger(DatabaseSequenceFilter.class);
+        final Level previousLevel = filterLogger.getLevel();
         final ListAppender<ILoggingEvent> appender = new ListAppender<>();
         appender.start();
+        filterLogger.setLevel(Level.WARN);
         filterLogger.addAppender(appender);
         try
         {
@@
         finally
         {
             filterLogger.detachAppender(appender);
+            appender.stop();
+            filterLogger.setLevel(previousLevel);
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java` around
lines 315 - 335, Update the logger setup in the cycle-warning test around
DatabaseSequenceFilter.sortTableNames to save the filterLogger’s existing level,
set it explicitly to WARN before invoking the code under test, and restore the
saved level in finally. Also stop the ListAppender in that same cleanup block
after detaching it.
src/main/java/org/dbunit/database/DatabaseSequenceFilter.java (2)

334-336: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse getCyclicDependencies() here.

Lines 335-336 repeat the intersection that DependencyInfo.getCyclicDependencies() already performs. Call the accessor to keep one definition of "mutually reachable".

♻️ Proposed refactor
             DependencyInfo info = (DependencyInfo) dependencies.get(tableNames[i]);
-            Set mutuallyReachable = new HashSet(info.getAllTableDependsOn());
-            mutuallyReachable.retainAll(info.getAllTableDependent());
+            Set mutuallyReachable = info.getCyclicDependencies();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/dbunit/database/DatabaseSequenceFilter.java` around lines
334 - 336, In the table dependency processing around DependencyInfo, replace the
manual HashSet intersection of getAllTableDependsOn() and getAllTableDependent()
with a call to info.getCyclicDependencies(). Preserve the existing
mutuallyReachable usage and behavior while relying on the accessor as the single
definition of mutually reachable dependencies.

494-524: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Complete the JavaDoc for the changed constructor and the new accessor.

The constructor signature now takes directDependsOnTablesSet as the second parameter. The JavaDoc does not document it, and the listed parameter order does not match the signature. @param tableName has no description. The existing descriptions do not end with a period. getDirectDependsOnTablesSet() has no JavaDoc.

The coding guidelines require complete sentences that start with a capital letter and end with a period for topic text, parameters, and return descriptions.

📝 Proposed documentation
         /**
-         * `@param` tableName
-         * `@param` allTableDependsOn Tables that are required as prerequisite so that this one can exist
-         * `@param` allTableDependent Tables that need this one in order to be able to exist
+         * Creates the dependency information for one table.
+         *
+         * `@param` tableName The name of the table this information describes.
+         * `@param` directDependsOnTablesSet The tables this one references directly through a
+         * foreign key.
+         * `@param` allTableDependsOn The tables that are required as a prerequisite so that this
+         * one can exist.
+         * `@param` allTableDependent The tables that need this one in order to be able to exist.
          */
+        /**
+         * Returns the tables this one references directly through a foreign key.
+         *
+         * `@return` The direct prerequisite tables.
+         */
         public Set getDirectDependsOnTablesSet() {
             return directDependsOnTablesSet;
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/dbunit/database/DatabaseSequenceFilter.java` around lines
494 - 524, Complete the JavaDoc for DependencyInfo’s constructor by documenting
parameters in signature order, including directDependsOnTablesSet, and give
tableName a capitalized, period-terminated description; update all existing
parameter descriptions to complete sentences ending with periods. Add JavaDoc to
getDirectDependsOnTablesSet() with a complete return description following the
same sentence style.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/org/dbunit/database/DatabaseSequenceFilter.java`:
- Around line 268-299: In the topological-sort expansion surrounding
sortedComponentCount and sortedTableNames, detect when Kahn’s algorithm emits
fewer components than componentCount and fail immediately with an appropriate
exception instead of returning trailing null entries. Keep the existing
expansion behavior unchanged for complete sorts, and ensure the guard runs
before the incomplete sortedTableNames array can propagate.

In `@src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java`:
- Line 237: Update the test method name and failure message in
testSort_cyclicPairWithNonCyclicParentAndSkipCycleCheckEnabled to remove the
stale “appended” wording and describe the cycle as following its parent in input
order. Preserve the existing assertions and expected behavior; change only the
naming and message text.

---

Nitpick comments:
In `@src/main/java/org/dbunit/database/DatabaseSequenceFilter.java`:
- Around line 334-336: In the table dependency processing around DependencyInfo,
replace the manual HashSet intersection of getAllTableDependsOn() and
getAllTableDependent() with a call to info.getCyclicDependencies(). Preserve the
existing mutuallyReachable usage and behavior while relying on the accessor as
the single definition of mutually reachable dependencies.
- Around line 494-524: Complete the JavaDoc for DependencyInfo’s constructor by
documenting parameters in signature order, including directDependsOnTablesSet,
and give tableName a capitalized, period-terminated description; update all
existing parameter descriptions to complete sentences ending with periods. Add
JavaDoc to getDirectDependsOnTablesSet() with a complete return description
following the same sentence style.

In `@src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java`:
- Around line 208-211: In DatabaseSequenceFilterTest, replace the assertThrows
assertion around DatabaseSequenceFilter.sortTableNames with AssertJ’s
assertThatThrownBy, assert the CyclicTablesDependencyException type, and
preserve the existing failure description using AssertJ’s .as() message.
- Around line 315-335: Update the logger setup in the cycle-warning test around
DatabaseSequenceFilter.sortTableNames to save the filterLogger’s existing level,
set it explicitly to WARN before invoking the code under test, and restore the
saved level in finally. Also stop the ListAppender in that same cleanup block
after detaching it.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 02592dcf-3709-4bfe-87fe-e99dc3df0f93

📥 Commits

Reviewing files that changed from the base of the PR and between 69ea4b9 and 4c63e4c.

📒 Files selected for processing (6)
  • src/changes/changes.xml
  • src/main/java/org/dbunit/database/DatabaseSequenceFilter.java
  • src/site/asciidoc/filters.adoc
  • src/site/asciidoc/properties.adoc
  • src/test/java/org/dbunit/database/DatabaseSequenceFilterIT.java
  • src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/changes/changes.xml
  • src/site/asciidoc/filters.adoc
  • src/test/java/org/dbunit/database/DatabaseSequenceFilterIT.java
  • src/site/asciidoc/properties.adoc

Comment thread src/main/java/org/dbunit/database/DatabaseSequenceFilter.java
Comment thread src/test/java/org/dbunit/database/DatabaseSequenceFilterTest.java Outdated
DatabaseSequenceFilter unconditionally rejected any schema with a
foreign-key dependency cycle via CyclicTablesDependencyException, with
no way to opt out even when the cycle is handled another way (nullable
FK columns backfilled later, or database-side deferred constraint
checking).

* Add DatabaseConfig.FEATURE_SKIP_CYCLE_CHECK (default false,
  preserving prior behavior). When enabled,
  DatabaseSequenceFilter.DependencyInfo.checkCycles() logs a warning
  instead of throwing for each detected cycle.
* Make DatabaseSequenceFilter.sort() handle a cycle correctly instead
  of just avoiding the exception: tables are first grouped into
  strongly connected components (reusing the same mutual-reachability
  check checkCycles() already performs), each cycle is condensed into
  a single component, and the condensed component graph - always
  acyclic by construction - is topologically sorted before expanding
  each component back into its member tables in their original input
  order. A table that merely depends on a cyclic table, without itself
  being part of the cycle, is therefore still ordered correctly after
  the whole component it depends on; only the relative order of the
  tables making up the cycle itself falls back to input order.
* Add unit coverage in DatabaseSequenceFilterTest (default still
  throws; a two-table cycle with the feature enabled; a non-cyclic
  parent still sorting before an appended cycle; and a table that
  depends on, but is not part of, a cyclic component still sorting
  after the whole component) and DatabaseConfigTest (default value),
  plus a DatabaseSequenceFilterIT case reusing the existing 5-table
  hypersonic_cyclic.sql fixture, verified against the h2-1-4 and
  hsqldb-2-7 profiles.
* Document the feature in filters.adoc (new "Cyclic foreign-key
  dependencies" subsection) and properties.adoc's Feature Flags table.

Refs: 501
Refs: 517
Refs: 411

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012gmZhDioasFdPtnqxs1ZuP
@jeffjensen
jeffjensen force-pushed the 501-skip-cyclic-dependency-check branch from 4c63e4c to 8f670b0 Compare August 8, 2026 03:41
@jeffjensen

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@jeffjensen
jeffjensen merged commit 1f0d883 into main Aug 8, 2026
29 checks passed
@jeffjensen
jeffjensen deleted the 501-skip-cyclic-dependency-check branch August 8, 2026 03:44
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.

Avoid CyclicTablesDependencyException DBUnit doesn't support circular references Option to Skip Cyclic Reference Checks

1 participant