Skip to content

fix(database): order foreign key target commands - #9

Closed
binaryfire wants to merge 22 commits into
0.4from
fix/schema-foreign-key-ordering
Closed

fix(database): order foreign key target commands#9
binaryfire wants to merge 22 commits into
0.4from
fix/schema-foreign-key-ordering

Conversation

@binaryfire

@binaryfire binaryfire commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Goal

Make schema blueprints reliable when a foreign key and its target primary, unique, or ordinary index are declared in the same migration callback.

Background

Blueprint::addFluentIndexes() materializes column-level indexes after the migration callback has finished. The schema builder then compiles and executes commands in list order.

This creates two failure modes:

  • A CREATE blueprint can emit a foreign key before an explicit or generated target key.
  • An ALTER blueprint can emit a generated fluent target at the end of the callback, after a foreign key that depends on it.

PostgreSQL, MySQL, and MariaDB reject the affected forms according to their foreign-key requirements. SQLite does not have the same command model: CREATE constraints are compiled into the table definition, while ALTER commands feed an ordered table-rebuild state machine.

Implementation

CREATE blueprints now use one stable pass to move primary, unique, and ordinary index commands ahead of the first foreign key. The implementation moves only target commands. Other commands keep their authored relative order, including custom commands placed after a foreign key.

For non-SQLite ALTER blueprints, generated fluent targets are associated with their exact owning ColumnDefinition before columns become add or change commands. The same command objects are moved immediately after their owners, preserving subclass and macro metadata. Explicit ALTER commands remain in callback order.

SQLite ALTER is deliberately excluded from target placement so its ordered rebuild grouping remains unchanged.

The change also:

  • makes the internal column and command list invariants explicit for static analysis;
  • uses strict identifier and schema-command comparisons;
  • corrects the PostgreSQL online-index documentation so online() is applied to an index definition.

No public API, configuration, migration workaround, or compatibility layer is added. The extra work is bounded linear processing during schema compilation and does not affect application query paths.

Testing

Coverage includes:

  • stable CREATE promotion with interleaved foreign keys, target keys, and custom commands;
  • generated ALTER placement for primary, unique, named unique, and ordinary indexes;
  • exact command identity and metadata preservation;
  • explicit ALTER order and non-target index behavior;
  • strict handling of numeric-looking column identifiers;
  • real CREATE and ALTER execution on MySQL, MariaDB, PostgreSQL, and SQLite;
  • MariaDB ordinary-index foreign-key targets;
  • exact SQLite SQL proving combined primary and unique changes use one rebuild.

The complete database-driver suites and the repository composer fix workflow pass.

Summary by CodeRabbit

  • New Features

    • Improved database schema execution safety across PostgreSQL, SQLite, MySQL, and MariaDB.
    • Added safer nested foreign-key constraint handling and connection-state recovery.
    • Enhanced SQLite schema changes to preserve indexes, constraints, collations, ordering, and table options.
    • Added atomic schema execution and clearer failure handling.
    • Improved SQLite database-file refresh and cleanup safeguards.
  • Documentation

    • Updated migration guidance for indexes, foreign keys, transactions, and deferred constraints.
    • Added implementation plans for schema execution safety and foreign-key ordering.

Route Blueprint execution through the connection-owned schema builder, compile statements once, and fail loudly when a schema statement reports failure.

Make foreign-key suppression connection-owned and nest-safe, preserve the incoming MySQL and MariaDB state, bypass application callbacks for physical-session restoration, and invalidate leaked or failed session state before pooled reuse.

Reject pooled reconnects that remain unsafe, including shared in-memory SQLite sessions that cannot be replaced without losing their database, and cover execution order, failure handling, nesting, restoration, pool reset, and real database behavior.
Wrap supported multi-statement Blueprint operations in a database transaction while preserving caller-owned transactions, runtime grammar opt-outs, and framework command ordering.

Keep online index operations unwrapped because PostgreSQL forbids concurrent index creation inside a transaction, and leave extension-defined compilers on the existing ordered execution path.

Cover rollback, nested transaction ownership, every online index form, grammar extensions and overrides, raw compilation, and real PostgreSQL constraint-suppression nesting.
Execute framework-owned multi-statement Blueprints inside guarded SQLite transactions while preserving foreign-key state, caller transactions, pretend mode, command order, and extension compiler behavior.

Round-trip index identity and semantics through authoritative SQLite metadata, including expression and partial indexes, collations, descending order, constraint-backed indexes, comma-bearing identifiers, column renames, table options, and supported constraint clauses. Fail before mutation when SQLite metadata cannot reconstruct the original behavior safely.

Replace live database-file truncation with guarded catalog cleanup, preserve views during table wipes, reload schema state safely across SQLite versions, and make explicit database-file refresh reject active transactions, in-memory databases, and WAL mode.

Add focused unit and real-engine regressions for rollback, rebuild ordering, exact index and constraint behavior, stored definitions, foreign-key safety, writable-schema restoration, WAL and file handling, and every discovered data-integrity failure.
Teach the test database resolver to discard pooled wrappers whose physical session state became unknown, clear both cached connection entries, and complete all resets before rethrowing the first cleanup failure.

Add resolver regressions for discard and failure ordering, plus integration coverage proving DatabaseTruncation preserves an initially disabled SQLite foreign-key state.
Correct the stale claim about Hypervel SQLite defaults and document the transaction boundaries that govern SQLite constraint toggles and PostgreSQL constraint deferral.
Record the verified failure modes and final architecture for Blueprint execution, driver-specific transaction boundaries, exact SQLite index reconstruction, connection-owned foreign-key suppression, pooled-session invalidation, and safe SQLite catalog cleanup.

Capture the required integration coverage, compatibility guarantees, performance boundaries, public behavior disclosures, and completed review status so the implementation and future maintenance share one concise source of truth.
Read foreign-key constraint state from the write PDO so nested suppression restores the physical session that schema mutations use. MariaDB inherits the same correction through its MySQL builder base.\n\nRoute drop-all table and view statements through the guarded schema executor. Exact false statement results now surface as failures, while native exceptions, SQL ordering, and foreign-key restoration behavior remain unchanged.\n\nAdd regression coverage for write-session reads, failed cleanup statements, and restoration before error propagation.
Route Schema::hasTable(), SQLite pragma and rebuild probes, stored table definitions, and populated-table guards through the write PDO. This keeps mutation decisions consistent with the physical session and schema they govern when read/write connections differ.\n\nKeep SQLite compile-option discovery on the reader because it is process-wide library metadata, and document that deliberate exception.\n\nGuard PostgreSQL drop-all table, view, type, and domain statements against exact false results without changing their SQL or execution order. Add real split-PDO SQLite regressions and strict call-shape coverage across every supported builder.
Verify WITHOUT ROWID preservation through sqlite_master so the assertion works on the same SQLite versions as the schema introspection path. Keep the reachable STRICT version guard and remove the redundant older-version guard.\n\nReplace compile-option assumptions about double-quoted string fallback with a behavioral DDL probe that covers both indexed-column and partial-predicate positions. Unsupported builds skip only on SQLite's missing-column diagnostic, while all other failures remain visible.
Separate the SQLite and PostgreSQL transaction rules so the guidance cannot be read as applying the same way to both drivers.\n\nDocument that PostgreSQL defers only foreign keys created with deferrable(), only inside a transaction, while other constraints remain enforced.
Record that mutation-governing schema and session state belongs to the write connection, including Schema::hasTable() and SQLite rebuild state.\n\nAdd failed drop-all results and reader/writer divergence to the PR behavior and upstream-defect lists. Refresh the remaining-work wording without turning the plan into durable commit or push authority.
Replace the mock-only SQLite restoration test with a real transaction that commits DDL before a controlled foreign-key restoration failure.

Assert that the schema change remains committed, foreign keys remain disabled, the restoration error propagates, and the physical session is marked unknown. Narrow the plan's atomicity guarantee to failures that occur before commit.
…afety

Harden database schema execution and SQLite rebuilds
Require native class-constant types in newly written Hypervel code wherever PHP permits them.\n\nMake the same modernization explicit for Laravel package ports so upstream untyped constants are upgraded consistently alongside parameters, return values, and properties.
Promote primary, unique, and ordinary index commands ahead of foreign keys when compiling CREATE blueprints. For ALTER blueprints, move generated fluent targets beside their exact owning columns while preserving authored command order.

Keep SQLite ALTER ordering intact because its grammar builds ordered rebuild groups. Preserve generated command identity and metadata, use linear command-list rebuilds, and compare removed column identifiers strictly.

Add focused coverage for stable CREATE promotion, explicit ALTER ordering, owner placement, named fluent indexes, command identity, non-target commands, SQLite exclusion, and numeric-looking identifiers.
Use strict comparison when selecting schema commands by name.

Command names are strings throughout the schema pipeline, so this preserves existing behavior while removing the final loose comparison from schema command lookup.
Exercise self-referencing primary and unique targets through the real Schema builder on every supported database for both CREATE and ALTER callbacks.

Add MariaDB coverage for its supported ordinary-index target behavior. Verify the resulting indexes and foreign keys, accept valid references, reject invalid rows, and confirm rejected inserts leave no data behind.

Use strict comparison in the adjacent schema macro assertion while updating the file.
Pin the exact SQL emitted when an SQLite ALTER callback adds fluent primary and unique targets while changing an existing column.

The regression proves generated target placement remains disabled for SQLite ALTER, avoiding duplicate rebuild groups and preserving unique-index creation after the single rebuild.
Apply online() to the index definition returned by Blueprint::unique() instead of to the column definition.

This matches the documented index-modifier API and ensures PostgreSQL emits CREATE INDEX CONCURRENTLY with the expected transaction behavior.
Document the cross-driver failure, the CREATE and ALTER normalization rules, SQLite's ordered rebuild constraint, command-identity guarantees, and schema-only performance cost.

Capture the implementation shape, database and unit verification plan, completion criteria, and rejected alternatives so future maintenance preserves the intended ordering boundary without adding public machinery.
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6026fa15-36cc-42f5-a2a3-af707d684e4c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR centralizes schema execution, adds nested foreign-key suppression and session-state recovery, preserves detailed SQLite schema metadata during rebuilds, orders foreign-key target indexes, and adds cross-driver unit and integration coverage.

Changes

Database schema safety

Layer / File(s) Summary
Execution and session-state control
src/database/src/Connection.php, src/database/src/Pool/*, src/database/src/Schema/Builder.php, src/database/src/Schema/*Builder.php, src/foundation/src/Testing/*, src/support/src/Facades/Schema.php, tests/Database/*, tests/Foundation/*, tests/Integration/Database/*, tests/Integration/Foundation/*
Schema statements now execute through guarded builder methods. Foreign-key suppression tracks nested scopes. Unknown sessions are invalidated and pooled connections are discarded or rejected when recovery is unsafe.
SQLite schema metadata and rebuilds
src/database/src/Query/Processors/SQLiteProcessor.php, src/database/src/Schema/BlueprintState.php, src/database/src/Schema/Grammars/SQLiteGrammar.php, src/database/src/Schema/SQLiteBuilder.php, tests/Database/DatabaseSQLite*, tests/Integration/Database/Sqlite/*
SQLite schema introspection preserves physical index names, stored SQL, collations, sort order, constraints, and table options. Rebuild, rename, drop, cleanup, and refresh paths validate definitions and preserve connection state.
Blueprint command ordering
src/database/src/Schema/Blueprint.php, src/database/src/Schema/Grammars/Grammar.php, tests/Database/DatabaseSchemaBlueprintTest.php, tests/Integration/Database/SchemaBuilderTest.php
Generated index commands are ordered before foreign keys during creation and after owning columns during alteration. Strict command and column-name comparisons are used.
Documentation and implementation plans
AGENTS.md, docs/plans/*, src/boost/docs/migrations.md
PHP typing guidance, schema safety plans, foreign-key ordering plans, and migration examples describe the updated behavior.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Blueprint
  participant SchemaBuilder
  participant SQLiteBuilder
  participant SQLiteGrammar
  participant Connection
  Blueprint->>SchemaBuilder: executeBlueprint(Blueprint)
  SchemaBuilder->>SQLiteBuilder: select SQLite execution path
  SQLiteBuilder->>Connection: inspect and suppress foreign keys
  SQLiteBuilder->>SQLiteGrammar: compile validated rebuild statements
  SQLiteGrammar-->>SQLiteBuilder: return ordered SQL
  SQLiteBuilder->>Connection: execute statements and restore session state
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.80% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: ordering foreign-key target commands before dependent foreign keys.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/schema-foreign-key-ordering

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.

@greptile-apps

greptile-apps Bot commented Aug 9, 2026

Copy link
Copy Markdown

Greptile Summary

The PR strengthens schema-operation ordering and execution safety across supported database drivers.

  • Orders foreign-key target commands while preserving explicit ALTER and SQLite rebuild semantics.
  • Adds guarded and transactional blueprint execution where supported.
  • Preserves foreign-key suppression and physical-session state across nested scopes, failures, pooling, and test cleanup.
  • Expands SQLite schema reconstruction, catalog cleanup, and database-file refresh safeguards.
  • Adds extensive unit and integration coverage for the affected database paths.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains within the eligible follow-up-review scope.

No blocking failure remains.

Important Files Changed

Filename Overview
src/database/src/Schema/Blueprint.php Stably promotes CREATE target indexes and places generated non-SQLite ALTER indexes beside their owning columns while preserving command identity.
src/database/src/Schema/Builder.php Centralizes guarded blueprint execution and nested foreign-key suppression with restoration of the incoming state.
src/database/src/Schema/SQLiteBuilder.php Adds transaction-aware SQLite blueprint execution, guarded catalog cleanup, and safer database-file refresh behavior.
src/database/src/Schema/Grammars/SQLiteGrammar.php Extends SQLite rebuild compilation to preserve richer index metadata, table options, and command-order semantics.
src/database/src/Schema/BlueprintState.php Tracks exact SQLite schema and index metadata through rename, drop, and rebuild operations.
src/database/src/Connection.php Moves foreign-key suppression ownership onto the connection and strengthens physical-session invalidation and synchronization.
src/database/src/Pool/PooledConnection.php Prevents pooled reuse of physical sessions whose state became untrustworthy during cleanup.
src/database/src/Schema/PostgresBuilder.php Makes eligible multi-statement PostgreSQL blueprint execution transactional while retaining online-index exclusions.
src/foundation/src/Testing/DatabaseConnectionResolver.php Discards cached pooled connections whose session state cannot be trusted after test cleanup.

Reviews (2): Last reviewed commit: "test(database): preserve promoted comman..." | Re-trigger Greptile

@binaryfire

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

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.

@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 (1)
tests/Database/DatabaseSchemaBlueprintTest.php (1)

254-282: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert identity for the moved CREATE unique command.

The test moves the command returned by unique('code'), but it only checks command names. Assert that generatedUniqueCommand is at index 1 and retains testMetadata. This prevents a future command reconstruction from passing the CREATE-ordering test.

Proposed test addition
         $this->assertSame(
             [
                 'create', 'unique', 'index', 'primary', 'foreign', 'foreign', 'custom',
                 'AutoIncrementStartingValues', 'Comment', 'AutoIncrementStartingValues', 'Comment',
                 'AutoIncrementStartingValues', 'Comment',
             ],
             array_column($blueprint->getCommands(), 'name'),
         );
+        $this->assertSame($blueprint->generatedUniqueCommand, $blueprint->getCommands()[1]);
+        $this->assertSame('preserved', $blueprint->getCommands()[1]->testMetadata);
🤖 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 `@tests/Database/DatabaseSchemaBlueprintTest.php` around lines 254 - 282,
Update testCreatePromotesForeignKeyTargetsWithoutMovingOtherCommands to capture
the command returned by unique('code') as generatedUniqueCommand, then assert it
is at index 1 in the blueprint commands and retains its testMetadata, in
addition to the existing command-name assertions.
🤖 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/boost/docs/migrations.md`:
- Around line 1660-1664: Remove the blank line separating the NOTE and WARNING
blockquotes in the migration documentation, keeping both blockquote sections
directly adjacent.

In `@src/database/src/Schema/SQLiteBuilder.php`:
- Around line 44-56: Update the in-transaction guard around SQLiteBuilder’s
table rebuild flow to also detect populated child tables whose foreign keys
reference the rebuild target, not just rows in the target itself. Reuse the
existing schema/foreign-key inspection helpers where available, and throw the
same RuntimeException before executeStatements runs when either the target or
any referencing child table is populated while suppression is required.

---

Nitpick comments:
In `@tests/Database/DatabaseSchemaBlueprintTest.php`:
- Around line 254-282: Update
testCreatePromotesForeignKeyTargetsWithoutMovingOtherCommands to capture the
command returned by unique('code') as generatedUniqueCommand, then assert it is
at index 1 in the blueprint commands and retains its testMetadata, in addition
to the existing command-name assertions.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d9e17e76-223e-49d2-bccc-1116e4653fa9

📥 Commits

Reviewing files that changed from the base of the PR and between 5c41e9d and ae332ba.

📒 Files selected for processing (37)
  • AGENTS.md
  • docs/plans/2026-08-09-0555-database-schema-execution-safety.md
  • docs/plans/2026-08-09-2010-database-foreign-key-target-command-ordering.md
  • src/boost/docs/migrations.md
  • src/database/src/Connection.php
  • src/database/src/Pool/PooledConnection.php
  • src/database/src/Query/Processors/SQLiteProcessor.php
  • src/database/src/Schema/Blueprint.php
  • src/database/src/Schema/BlueprintState.php
  • src/database/src/Schema/Builder.php
  • src/database/src/Schema/Grammars/Grammar.php
  • src/database/src/Schema/Grammars/SQLiteGrammar.php
  • src/database/src/Schema/MySqlBuilder.php
  • src/database/src/Schema/PostgresBuilder.php
  • src/database/src/Schema/SQLiteBuilder.php
  • src/foundation/src/Testing/DatabaseConnectionResolver.php
  • src/support/src/Facades/Schema.php
  • tests/Database/DatabaseConnectionTest.php
  • tests/Database/DatabaseMariaDbSchemaBuilderTest.php
  • tests/Database/DatabaseMySQLSchemaBuilderTest.php
  • tests/Database/DatabaseMySqlBuilderTest.php
  • tests/Database/DatabasePostgresBuilderTest.php
  • tests/Database/DatabasePostgresSchemaBuilderTest.php
  • tests/Database/DatabaseSQLiteBuilderTest.php
  • tests/Database/DatabaseSQLiteProcessorTest.php
  • tests/Database/DatabaseSQLiteSchemaGrammarTest.php
  • tests/Database/DatabaseSchemaBlueprintTest.php
  • tests/Database/DatabaseSchemaBuilderTest.php
  • tests/Foundation/Testing/DatabaseConnectionResolverTest.php
  • tests/Integration/Database/MariaDb/DatabaseMariaDbSchemaBuilderTest.php
  • tests/Integration/Database/MySql/DatabaseMySqlSchemaBuilderTest.php
  • tests/Integration/Database/PooledConnectionTest.php
  • tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php
  • tests/Integration/Database/SchemaBuilderTest.php
  • tests/Integration/Database/Sqlite/DatabaseSchemaBlueprintTest.php
  • tests/Integration/Database/Sqlite/DatabaseSqliteSchemaBuilderTest.php
  • tests/Integration/Foundation/Testing/DatabaseTruncationTest.php

Comment thread src/boost/docs/migrations.md
Comment thread src/database/src/Schema/SQLiteBuilder.php
Assert that CREATE target promotion keeps the exact unique-command object at its new position.

Also pin the command's custom metadata so a future in-place normalization cannot retain identity while discarding extension attributes.
@binaryfire

Copy link
Copy Markdown
Collaborator Author

@coderabbitai Thanks for the review. I checked each finding against the implementation.

Addressed

  • Added CREATE-path assertions for exact promoted command identity and custom metadata preservation in e7598e537. These separately pin that normalization moves the original command and preserves extension attributes.

No change

  • Kept the blank line between the NOTE and WARNING alerts. GitHub renders the current form as two alerts; removing the blank line produces one NOTE containing a literal [!WARNING] marker. The same pattern exists elsewhere in the documentation, and MD028 is not enforced by this repository.
  • Kept the SQLite in-transaction guard scoped to rows in the rebuild target. DROP TABLE foreign-key work is driven by deleted parent rows. SQLite probes show that empty targets rebuild safely with populated nullable children and with a deferred reference repaired before commit; populated referenced targets are already rejected by tableHasRows(). A child-table scan would add schema queries and reject safe cases.
  • Did not add docblocks to test methods and closures for the generic documentation-coverage metric. The new production methods already have useful docblocks, while boilerplate on tests would not improve the code.

The focused Blueprint test and repository diff checks pass.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@binaryfire Thanks for the detailed review of the findings.

The new assertions in e7598e537 cover both command identity and custom metadata preservation for CREATE-path promotion.

Your rationale for the unchanged items is clear. The current SQLite guard rejects rebuilds only when the rebuild target has rows. This preserves safe empty-target rebuilds and avoids unnecessary child-table queries.

🐇 ✅


✏️ Learnings added
Learnt from: binaryfire
URL: https://github.com/hypervel/components-backup/pull/9

Timestamp: 2026-08-09T23:46:02.867Z
Learning: For SQLite schema rebuilds in `src/database/src/Schema/SQLiteBuilder.php`, the in-transaction foreign-key safety guard is intentionally scoped to whether the rebuild target table has rows. Do not require a scan of referencing child tables: empty target tables can rebuild safely even when nullable child rows exist or a deferred reference is repaired before commit, while populated target tables are rejected by `tableHasRows()`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

@binaryfire binaryfire closed this Aug 9, 2026
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.

1 participant