Skip to content

Conversation

@techouse
Copy link
Owner

@techouse techouse commented Oct 18, 2025

This pull request improves the handling of SQLite index name collisions when migrating from MySQL, ensuring that index names are globally unique in the target SQLite database, especially when index prefixing is disabled. It introduces a helper method for generating unique index names, updates internal tracking attributes, and adds a unit test for the new logic.

Index name uniqueness improvements:

  • Added internal tracking attributes _seen_sqlite_index_names and _sqlite_index_name_counters to both MySQLtoSQLiteAttributes and the main transporter class to record used index names and manage numeric suffixes. [1] [2]
  • Implemented the _get_unique_index_name method in transporter.py to generate globally unique SQLite index names by appending numeric suffixes when needed.
  • Updated the index creation logic in _build_create_table_sql to use the new uniqueness helper, preventing index name collisions when prefixing is disabled.

Testing:

  • Added a unit test test_get_unique_index_name_suffixing_sequence to verify correct suffixing and uniqueness behavior for index names.

Lint configuration:

  • Disabled the C0103 naming style warning in tox.ini to accommodate the new internal attribute naming.

Fixes #108

@techouse techouse self-assigned this Oct 18, 2025
@techouse techouse added the bug Something isn't working label Oct 18, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 18, 2025

Walkthrough

This pull request implements automatic suffixing of duplicate SQLite index names when prefixing is disabled. The solution introduces internal state tracking to detect collisions and append numeric suffixes (_2, _3, etc.) to ensure global index name uniqueness across the database.

Changes

Cohort / File(s) Summary
Index name uniqueness tracking
src/mysql_to_sqlite3/types.py
Added two private attributes (_seen_sqlite_index_names and _sqlite_index_name_counters) to the MySQLtoSQLiteAttributes class for tracking globally unique index names when prefixing is disabled.
Index name resolution logic
src/mysql_to_sqlite3/transporter.py
Implemented new private method _get_unique_index_name() to compute and cache unique index names; modified _build_create_table_sql() to apply uniqueness resolution when prefixing is disabled; initialised state tracking in __init__; added logging for index name collisions.
Unit test coverage
tests/unit/test_transporter.py
Added test test_get_unique_index_name_suffixing_sequence validating the suffix-based naming behaviour for base names and subsequent collisions.
Linting configuration
tox.ini
Added C0103 rule to pylint disable list.

Sequence Diagram(s)

sequenceDiagram
    participant Table Table Processing
    participant _build_create_table_sql
    participant _get_unique_index_name
    participant State Storage

    Table->>_build_create_table_sql: Process indexes
    _build_create_table_sql->>_build_create_table_sql: Compute proposed_index_name
    
    alt Prefixing enabled
        _build_create_table_sql->>_build_create_table_sql: Use proposed_index_name directly
    else Prefixing disabled
        _build_create_table_sql->>_get_unique_index_name: Call with proposed_index_name
        _get_unique_index_name->>State Storage: Check _seen_sqlite_index_names
        
        alt Index name unseen
            State Storage-->>_get_unique_index_name: Not found
            _get_unique_index_name->>State Storage: Record base_name
            _get_unique_index_name-->>_build_create_table_sql: Return base_name
        else Index name collision
            State Storage-->>_get_unique_index_name: Found in seen set
            _get_unique_index_name->>State Storage: Increment counter
            _get_unique_index_name->>_get_unique_index_name: Append suffix (_2, _3, ...)
            _get_unique_index_name->>State Storage: Record unique name
            _get_unique_index_name-->>_build_create_table_sql: Return suffixed_name (log rename)
        end
    end
    
    _build_create_table_sql->>_build_create_table_sql: Use final index name in CREATE INDEX
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

The changes implement a straightforward suffix-based collision resolution pattern. The logic is easy to follow, and the scope is well-contained within the transporter module. However, careful attention is needed to verify the state initialisation order, the correctness of the collision detection logic, and that the test coverage adequately exercises edge cases.

Suggested labels

enhancement

Poem

🐰 A cottontail's ode to index harmony:
When index names clash with a duplicating fray,
We hop through with suffixes—_2, then _3 to play!
No silent omissions shall vex the SQL night,
Each index renamed shines globally bright.
The warren cheers softly: uniqueness takes flight! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title ":bug: prevent non-unique indices from being quietly omitted" directly reflects the core objective of the pull request. It clearly summarises the main change, which is addressing the problem of SQLite index name collisions by ensuring uniqueness through automatic suffix generation when prefixing is disabled. The title is concise, specific, and accurately represents the primary intent of the changeset.
Linked Issues Check ✅ Passed The pull request successfully addresses the requirements specified in linked issue #108. The issue identified that non-unique SQLite index names are quietly omitted when the -K prefixing option is not used, with two suggested solutions: either showing notices of skipped indexes or auto-disambiguating names with numeric suffixes. This PR implements the second solution by introducing the _get_unique_index_name method that automatically appends numeric suffixes (e.g., _2, _3) to duplicate index names, along with tracking attributes and a unit test to verify the behaviour. The implementation directly prevents silent omission of indexes with duplicate names by ensuring all generated index names remain globally unique.
Out of Scope Changes Check ✅ Passed All code changes in this pull request are directly related to addressing issue #108 regarding non-unique SQLite indices. The modifications to transporter.py implement the core uniqueness logic, changes to types.py add the necessary tracking attributes, the unit test validates the new functionality, and the tox.ini modification disables the C0103 pylint rule to accommodate the new internal attribute naming convention. No unrelated refactoring, feature additions, or tangential changes are present in the changeset.
Description Check ✅ Passed The pull request description provides a comprehensive summary of changes, including the problem statement, solution implemented, and testing approach. It clearly states the issue being fixed (issue #108), explains the tracking attributes added, describes the new _get_unique_index_name method, mentions the unit test added, and notes the tox.ini configuration change. However, the description does not follow the structured template format with explicitly marked sections, checkboxes for type of change, or detailed testing instructions, instead presenting the information in narrative form. Despite this format deviation, the core required content is present and complete.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issue-108

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/mysql_to_sqlite3/transporter.py (1)

417-437: Consider logging when index names are modified.

The implementation correctly generates unique index names using numeric suffixes. However, issue #108 suggested providing notice to users when index names are modified. Consider adding a log message (e.g., self._logger.info) when a suffix is appended, informing the user that index base_name was renamed to candidate to avoid conflicts.

Example:

     # Record chosen candidate and bump counter for the base name
     self._seen_sqlite_index_names.add(candidate)
     self._sqlite_index_name_counters[base_name] = next_num + 1
+    self._logger.info(
+        'Index "%s" renamed to "%s" to ensure uniqueness across the SQLite database.',
+        base_name,
+        candidate,
+    )
     return candidate
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a3df4a and 989780b.

📒 Files selected for processing (3)
  • src/mysql_to_sqlite3/transporter.py (3 hunks)
  • src/mysql_to_sqlite3/types.py (1 hunks)
  • tests/unit/mysql_to_sqlite3_test.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/unit/mysql_to_sqlite3_test.py (1)
src/mysql_to_sqlite3/transporter.py (1)
  • _get_unique_index_name (417-437)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (4)
src/mysql_to_sqlite3/types.py (1)

84-86: LGTM! Clear documentation of the new tracking attributes.

The comment clearly explains the purpose of these fields, and the type annotations are correct.

tests/unit/mysql_to_sqlite3_test.py (1)

584-605: LGTM! Comprehensive test of the suffixing sequence.

The test correctly validates the uniqueness logic: first occurrence returns the base name, subsequent occurrences append numeric suffixes starting from 2, and different base names are tracked independently.

src/mysql_to_sqlite3/transporter.py (2)

149-152: LGTM! Proper initialisation of tracking state.

The tracking attributes are correctly initialised as empty collections, and the comments clearly document their purpose.


553-569: LGTM! Integration correctly applies uniqueness logic when prefixing is disabled.

The logic appropriately handles both table name collisions and the prefix option, then ensures global uniqueness by calling _get_unique_index_name when prefixing is disabled. The implementation matches the PR objectives.

@codecov
Copy link

codecov bot commented Oct 18, 2025

Codecov Report

❌ Patch coverage is 90.47619% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.11%. Comparing base (2a3df4a) to head (1c45dd6).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
src/mysql_to_sqlite3/transporter.py 89.47% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #109      +/-   ##
==========================================
- Coverage   94.23%   94.11%   -0.12%     
==========================================
  Files           8        8              
  Lines         659      680      +21     
==========================================
+ Hits          621      640      +19     
- Misses         38       40       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
tox.ini (1)

115-115: Consider inline pylint disables for more targeted suppression.

Whilst adding C0103 to the global disable list works, it affects the entire codebase rather than just the specific attributes that need it (_seen_sqlite_index_names, _sqlite_index_name_counters). For more granular control, you could use inline # pylint: disable=invalid-name comments next to those specific attribute definitions instead.

tests/unit/test_transporter.py (1)

47-66: Excellent test coverage for the suffixing logic.

The test correctly verifies that:

  • First occurrence returns the base name without suffix
  • Subsequent occurrences append numeric suffixes (_2, _3, ...)
  • Different base names are tracked independently

Optionally, you could enhance the test by asserting that instance._logger.info was called with the expected rename messages for the suffixed cases (lines 59, 61, 66), which would verify the logging behaviour as well.

src/mysql_to_sqlite3/transporter.py (1)

558-574: Correct implementation of index name uniqueness when prefixing is disabled.

The logic correctly:

  • Computes the proposed index name based on table name collisions and the prefix option
  • Applies global uniqueness checking via _get_unique_index_name only when prefixing is disabled
  • Uses the resulting unique name in the CREATE INDEX statement

This directly addresses the stated issue of indexes being silently omitted due to name collisions when the -K option is not used.

Note: When prefix_indices=True, no uniqueness check is applied. Whilst table prefixing typically ensures uniqueness, edge cases could theoretically still produce collisions (e.g., table users with index idx_name and table users_idx with index name both become users_idx_name). However, this is the existing behaviour and outside the scope of this PR, which specifically addresses the non-prefixed case.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 989780b and 1c45dd6.

📒 Files selected for processing (3)
  • src/mysql_to_sqlite3/transporter.py (3 hunks)
  • tests/unit/test_transporter.py (1 hunks)
  • tox.ini (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/unit/test_transporter.py (1)
src/mysql_to_sqlite3/transporter.py (2)
  • MySQLtoSQLite (42-820)
  • _get_unique_index_name (417-442)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Test (python3.12, mariadb:5.5, 1, true, 3.12)
  • GitHub Check: Test (python3.11, mariadb:10.0, 1, true, 3.11)
  • GitHub Check: Test (python3.13, mariadb:5.5, 1, true, 3.13)
  • GitHub Check: Test (python3.9, mariadb:10.0, 1, true, 3.9)
  • GitHub Check: Test (python3.10, mariadb:10.0, 1, true, 3.10)
  • GitHub Check: Test (python3.11, mariadb:5.5, 1, true, 3.11)
  • GitHub Check: Test (python3.9, mariadb:5.5, 1, true, 3.9)
  • GitHub Check: Test (python3.10, mariadb:5.5, 1, true, 3.10)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (2)
src/mysql_to_sqlite3/transporter.py (2)

149-152: LGTM! Proper initialization of tracking state.

The tracking attributes are correctly initialised early in the constructor, ensuring they're ready before index generation occurs. The type hints clearly indicate their purpose.


417-442: Well-implemented uniqueness helper.

The method correctly:

  • Returns the base name on first use and records it
  • Generates sequential suffixes (_2, _3, ...) for subsequent collisions
  • Uses the counter dictionary to efficiently find the next available suffix
  • Logs renames to inform users when disambiguation occurs

The while loop guards against potential gaps in the sequence, ensuring robustness.

@techouse techouse merged commit 5ac7b4d into master Oct 18, 2025
61 of 63 checks passed
@techouse techouse deleted the fix/issue-108 branch October 18, 2025 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Non-unique indexes are quietly omitted

2 participants