Skip to content

Conversation

@techouse
Copy link
Owner

This pull request adds support for specifying a prefix to prepend to all MySQL table names during SQLite-to-MySQL migrations. It introduces a new CLI option for the table prefix, validates the prefix format, and ensures that all table, index, and foreign key references throughout the migration process consistently use the prefixed names.

Key changes include:

CLI and Validation Enhancements:

  • Added a new CLI option --mysql-table-prefix (or -b) that allows users to specify a prefix for all MySQL table names. The prefix is validated to ensure it starts with a letter, contains only letters, numbers, or underscores, and is at most 32 characters long. [1] [2] [3]

Core Migration Logic Updates:

  • Updated the SQLite3toMySQL class to store and validate the table prefix, and introduced a _mysql_table_name method to generate prefixed table names. All relevant internal methods now use this method to ensure consistent naming. [1] [2] [3] [4]

Table and Index Handling:

  • Modified table creation, truncation, and index/constraint addition logic to use the prefixed table names everywhere, including SQL statements and logging. [1] [2] [3] [4] [5] [6] [7] [8]

Foreign Key and Reference Consistency:

  • Ensured that foreign key constraints and references to other tables also use the prefixed table names, maintaining referential integrity in the migrated schema. [1] [2] [3] [4]

Data Transfer Adjustments:

  • Updated the data transfer logic to use the new prefixed table names in all relevant SQL operations and logging, ensuring that inserts and updates target the correct tables. [1] [2] [3]

Fixes #155

@techouse techouse self-assigned this Nov 16, 2025
@techouse techouse added the enhancement New feature or request label Nov 16, 2025
@techouse techouse added this to the 2.5.5 milestone Nov 16, 2025
@coderabbitai
Copy link

coderabbitai bot commented Nov 16, 2025

Walkthrough

The pull request adds configurable MySQL table prefix support. A new validated CLI option passes a prefix into the transporter; the transporter validates and stores it, and all generated MySQL table identifiers (creation, truncation, indexes, foreign keys, data transfer) are adjusted to use the prefix with length-safe trimming.

Changes

Cohort / File(s) Summary
CLI Option Registration
src/sqlite3_to_mysql/cli.py
Added -b, --mysql-table-prefix CLI option with callback _validate_mysql_table_prefix, imported MYSQL_TABLE_PREFIX_PATTERN, extended cli() signature to accept and propagate mysql_table_prefix.
Core Prefix Implementation
src/sqlite3_to_mysql/transporter.py
Added MYSQL_TABLE_PREFIX_PATTERN constant and TABLE_PREFIX_PATTERN alias, validated and stored mysql_table_prefix in __init__, added internal _mysql_table_name() to compute prefixed names (with trimming), and updated all table-related SQL generation and logging to use prefixed table names.
Type Definitions
src/sqlite3_to_mysql/types.py
Added mysql_table_prefix: t.Optional[str] to SQLite3toMySQLParams and _mysql_table_prefix: str to SQLite3toMySQLAttributes.
Test Coverage
tests/unit/sqlite3_to_mysql_test.py
Added tests validating CLI propagation and validation of the prefix, and unit tests verifying prefixed table names appear in generated INSERT/LOAD and foreign-key DDL statements.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant CLI as CLI handler
    participant Validator as Prefix validator
    participant Transporter as SQLite3toMySQL
    participant SQLGen as SQL generator

    User->>CLI: run with --mysql-table-prefix "pre_"
    CLI->>Validator: validate("pre_")
    alt valid
        Validator-->>CLI: "pre_"
        CLI->>Transporter: init(..., mysql_table_prefix="pre_")
        Transporter->>Transporter: store & validate prefix
        Transporter->>SQLGen: transfer(table="users")
        SQLGen->>SQLGen: use _mysql_table_name("users") -> "pre_users" (trim if needed)
        SQLGen-->>Transporter: CREATE TABLE `pre_users`...
        SQLGen-->>Transporter: INSERT INTO `pre_users`...
    else invalid
        Validator-->>CLI: raise error (click.BadParameter) -> exit non-zero
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review transporter changes ensuring every SQL generation path (CREATE TABLE, TRUNCATE, INDEX, FOREIGN KEY, INSERT/LOAD) consistently uses _mysql_table_name.
  • Verify MYSQL_TABLE_PREFIX_PATTERN enforces allowed characters/length and that error messages surface correctly via CLI callback.
  • Check trimming logic preserves uniqueness and avoids collisions; inspect tests covering edge cases.
  • Confirm foreign-key DDL uses prefixed names for both parent and child references.

Possibly related PRs

Poem

🐇 I hopped through code to add a name,
Prefixed tables now play the game,
From CLI whisper to MySQL's stage,
pre\_users step onto the page,
Validated, trimmed — a tidy new frame.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding a MySQL table prefix option to the CLI. It is concise, specific, and directly related to the primary feature introduced in the changeset.
Description check ✅ Passed The description comprehensively covers the pull request scope, includes a 'Fixes' reference to issue #155, and details key changes across CLI, validation, migration logic, table handling, foreign keys, and data transfer. However, the 'Type of change', 'How Has This Been Tested?', and checklist sections from the template are entirely missing.
Linked Issues check ✅ Passed The pull request successfully implements the core objective from issue #155 by adding a --mysql-table-prefix CLI option and ensuring all table, index, and foreign key references use the prefixed names. However, the implementation only covers prefix functionality; suffix support requested in the issue is not included.
Out of Scope Changes check ✅ Passed All code changes directly support the implementation of the MySQL table prefix feature described in the pull request objectives and linked issue #155. No unrelated or out-of-scope modifications were detected across the CLI, transporter, types, or test files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 feat/table-prefix

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 (3)
src/sqlite3_to_mysql/transporter.py (2)

69-70: Table prefix validation and helper look robust and consistent

The compiled MYSQL_TABLE_PREFIX_PATTERN, class alias, __init__ validation, and _mysql_table_name() helper together give a clean, centralised implementation of prefixing while still respecting MySQL identifier limits via safe_identifier_length(). The getattr fallback for _mysql_table_prefix also keeps tests that bypass __init__ safe.

Only (very) minor thought: the CLI and ValueError messages differ slightly in wording; if you ever touch this again, you might consider reusing a shared constant for the human‑facing text to avoid drift, but it’s not a blocker.

Also applies to: 95-95, 179-185, 352-357


1121-1218: Index DDL and error logging fully switched to prefixed table names

Using _mysql_table_name(table_name) in _add_index() for the ALTER TABLE target and all related log messages keeps index creation aligned with the actual MySQL table name (including prefix) and avoids confusion when troubleshooting. The duplicate‑key retry behaviour is unchanged; the static‑analysis suggestion to use logging.exception in the generic error branch would be a nice‑to‑have if you want richer tracebacks in logs.

tests/unit/sqlite3_to_mysql_test.py (1)

546-565: test_transfer_applies_mysql_table_prefix exercises DML path correctly

This test sets _mysql_table_prefix = "pre_" on the stub and asserts that the generated INSERT SQL targets INTO \pre_tbl`, directly validating that transfer()now uses_mysql_table_name()for data writes. The stubbed execute side‑effect is minimal but sufficient; if you ever touch this again, you could drop the unusedparams` argument to quieten the Ruff ARG001 hint, but that’s purely cosmetic.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a876c7 and 9a2d4ca.

📒 Files selected for processing (4)
  • src/sqlite3_to_mysql/cli.py (4 hunks)
  • src/sqlite3_to_mysql/transporter.py (20 hunks)
  • src/sqlite3_to_mysql/types.py (2 hunks)
  • tests/unit/sqlite3_to_mysql_test.py (4 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
src/sqlite3_to_mysql/types.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Provide typed parameter/attribute structures in types.py for consumption via typing.Unpack in SQLite3toMySQL.init

Files:

  • src/sqlite3_to_mysql/types.py
src/sqlite3_to_mysql/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/sqlite3_to_mysql/**/*.py: Always wrap dynamic table/index/column names with safe_identifier_length(...) before emitting SQL
Use the class _logger for logging; do not print directly; respect the quiet flag for progress/INFO while always emitting errors

Files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
src/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.py: Format with Black (line length 120) and isort (profile=black); adhere to Flake8’s 88-column soft cap to avoid long chained expressions on one line
Preserve and add type hints for new public interfaces

Files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
src/sqlite3_to_mysql/cli.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/sqlite3_to_mysql/cli.py: Define and maintain the Click CLI in cli.py, validating mutual exclusions and implied flags for options
Make --sqlite-tables and --exclude-sqlite-tables mutually exclusive; setting either implies --without-foreign-keys
Disallow simultaneous -K (skip create) and -J (skip transfer) with an early exit and clear error message
Expose insert method choices IGNORE (default), UPDATE, and DEFAULT via CLI with clear help text
Define new CLI flags above cli() with consistent help text and error messages; maintain mutual exclusion patterns

Files:

  • src/sqlite3_to_mysql/cli.py
src/sqlite3_to_mysql/{cli.py,transporter.py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In debug mode (--debug), surface exceptions instead of swallowing them

Files:

  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
src/sqlite3_to_mysql/transporter.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/sqlite3_to_mysql/transporter.py: Keep SQLite3toMySQL.transfer() flow: create DB (if missing) → create tables → optionally truncate → bulk insert (chunked or streamed) → then create indices → then add foreign keys
On table creation failures due to expression DEFAULTs, retry without DEFAULTs (two-pass _create_table with skip_default=True)
Initialize MySQL capability booleans (e.g., _mysql_fulltext_support, _allow_expr_defaults) early in init, and gate conditional behavior on them
Extend column type translation only in _translate_type_from_sqlite_to_mysql instead of scattering conversions
Handle DEFAULT normalization in _translate_default_for_mysql; return empty string to suppress invalid defaults
During index creation, handle duplicate names by appending numeric suffixes, unless _ignore_duplicate_keys is set to skip retries
Implement chunked transfer with cursor.fetchmany when --chunk is set; otherwise use fetchall with tqdm progress
Only add foreign keys when no table include/exclude filters are set and --without-foreign-keys is not in effect
Implement insert methods: IGNORE (default), UPDATE using ON DUPLICATE KEY UPDATE (with optional VALUES alias), and DEFAULT (no modifiers)
Expose new capability booleans from init of SQLite3toMySQL for downstream logic
Use prepared cursors (cursor(prepared=True)) and batch inserts via executemany for performance
For large transfers, prefer --chunk and preserve commit granularity in any new bulk path

Files:

  • src/sqlite3_to_mysql/transporter.py
tests/{unit,func}/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Place unit tests under tests/unit and functional/CLI tests under tests/func

Files:

  • tests/unit/sqlite3_to_mysql_test.py
tests/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Format test code with Black/isort and respect Flake8’s 88-column soft cap

Files:

  • tests/unit/sqlite3_to_mysql_test.py
tests/unit/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Add unit tests for new behavior, isolating pure functions

Files:

  • tests/unit/sqlite3_to_mysql_test.py
🧠 Learnings (20)
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/types.py : Provide typed parameter/attribute structures in types.py for consumption via typing.Unpack in SQLite3toMySQL.__init__

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{mysql_utils.py,sqlite_utils.py} : Add new MySQL/SQLite capability checks in mysql_utils.py/sqlite_utils.py and keep them as dedicated helpers

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Extend column type translation only in _translate_type_from_sqlite_to_mysql instead of scattering conversions

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{mysql_utils.py,sqlite_utils.py} : Centralize dialect/version feature checks, type adaptation, and identifier safety in mysql_utils.py and sqlite_utils.py; add new MySQL capability gates here

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/**/*.py : Always wrap dynamic table/index/column names with safe_identifier_length(...) before emitting SQL

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Expose new capability booleans from __init__ of SQLite3toMySQL for downstream logic

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Make --sqlite-tables and --exclude-sqlite-tables mutually exclusive; setting either implies --without-foreign-keys

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Initialize MySQL capability booleans (e.g., _mysql_fulltext_support, _allow_expr_defaults) early in __init__, and gate conditional behavior on them

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Define new CLI flags above cli() with consistent help text and error messages; maintain mutual exclusion patterns

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Handle DEFAULT normalization in _translate_default_for_mysql; return empty string to suppress invalid defaults

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Implement insert methods: IGNORE (default), UPDATE using ON DUPLICATE KEY UPDATE (with optional VALUES alias), and DEFAULT (no modifiers)

Applied to files:

  • src/sqlite3_to_mysql/types.py
  • src/sqlite3_to_mysql/cli.py
  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Define and maintain the Click CLI in cli.py, validating mutual exclusions and implied flags for options

Applied to files:

  • src/sqlite3_to_mysql/cli.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Expose insert method choices IGNORE (default), UPDATE, and DEFAULT via CLI with clear help text

Applied to files:

  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{cli.py,transporter.py} : In debug mode (--debug), surface exceptions instead of swallowing them

Applied to files:

  • src/sqlite3_to_mysql/cli.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Keep SQLite3toMySQL.transfer() flow: create DB (if missing) → create tables → optionally truncate → bulk insert (chunked or streamed) → then create indices → then add foreign keys

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Use prepared cursors (cursor(prepared=True)) and batch inserts via executemany for performance

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : During index creation, handle duplicate names by appending numeric suffixes, unless _ignore_duplicate_keys is set to skip retries

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : On table creation failures due to expression DEFAULTs, retry without DEFAULTs (two-pass _create_table with skip_default=True)

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Only add foreign keys when no table include/exclude filters are set and --without-foreign-keys is not in effect

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • tests/unit/sqlite3_to_mysql_test.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : For large transfers, prefer --chunk and preserve commit granularity in any new bulk path

Applied to files:

  • tests/unit/sqlite3_to_mysql_test.py
🧬 Code graph analysis (2)
src/sqlite3_to_mysql/transporter.py (1)
src/sqlite3_to_mysql/mysql_utils.py (1)
  • safe_identifier_length (166-168)
tests/unit/sqlite3_to_mysql_test.py (2)
tests/conftest.py (4)
  • cli_runner (333-334)
  • sqlite_database (150-187)
  • mysql_credentials (206-232)
  • MySQLCredentials (195-202)
src/sqlite3_to_mysql/transporter.py (3)
  • transfer (1324-1490)
  • _transfer_table_data (1303-1322)
  • _add_foreign_keys (1220-1301)
🪛 Ruff (0.14.4)
src/sqlite3_to_mysql/cli.py

28-31: Avoid specifying long messages outside the exception class

(TRY003)

src/sqlite3_to_mysql/transporter.py

181-184: Avoid specifying long messages outside the exception class

(TRY003)


997-1001: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1212-1217: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

tests/unit/sqlite3_to_mysql_test.py

95-95: Consider [*common_args, "--mysql-table-prefix", "stage_"] instead of concatenation

Replace with [*common_args, "--mysql-table-prefix", "stage_"]

(RUF005)


123-123: Consider [*common_args, "--mysql-table-prefix", "123bad"] instead of concatenation

Replace with [*common_args, "--mysql-table-prefix", "123bad"]

(RUF005)


553-553: Unused function argument: params

(ARG001)

⏰ 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.9, mariadb:5.5, 1, true, 3.9)
  • GitHub Check: Test (python3.9, mariadb:10.0, 1, true, 3.9)
  • GitHub Check: Test (python3.14, mariadb:5.5, 1, true, 3.14)
  • GitHub Check: Test (python3.10, mariadb:10.0, 1, true, 3.10)
  • GitHub Check: Test (python3.10, mariadb:5.5, 1, true, 3.10)
  • GitHub Check: Test (python3.12, mariadb:5.5, 1, true, 3.12)
  • GitHub Check: Test (python3.13, mariadb:5.5, 1, true, 3.13)
  • GitHub Check: Test (python3.11, mariadb:5.5, 1, true, 3.11)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (9)
src/sqlite3_to_mysql/transporter.py (4)

899-903: Prefixed table name use in _create_table is correct and complete

Using mysql_table_name = self._mysql_table_name(table_name) for the CREATE TABLE statement, the optional rowid constraint name, and both the invalid‑default retry and error logs keeps MySQL‑side identifiers and diagnostics aligned with the actual table names, including any prefix. No functional issues spotted here.

Also applies to: 980-985, 989-1002


1004-1019: Truncate and index setup correctly honour prefixed table names

_truncate_table() now checks and truncates the prefixed MySQL table, and _add_indices() logs missing metadata against the prefixed table name. This matches the new naming semantics and still respects safe_identifier_length() for all dynamic identifiers.

Also applies to: 1021-1031, 1083-1087


1220-1301: Foreign key DDL correctly applies prefix to both child and referenced tables

_add_foreign_keys() now derives mysql_table_name and mysql_ref_table_name via _mysql_table_name(), so both the ALTER TABLE target and REFERENCES clause use the prefixed names. This preserves referential integrity when all migrated tables share a prefix, and the log messages have been updated accordingly. The shorthand‑PK resolution still uses the SQLite table name and only prefixes at the MySQL boundary, which is the right separation of concerns.


1341-1345: Data‑transfer SQL now targets prefixed tables consistently

In transfer(), computing mysql_table_name once per table and using it in all generated INSERT/INSERT ... ON DUPLICATE KEY UPDATE statements and the corresponding error log ensures that data loads always go to the prefixed table, without altering the SQLite‑side selection logic. Behaviour for insert methods (IGNORE/UPDATE/DEFAULT) remains intact.

Also applies to: 1409-1439, 1443-1448

src/sqlite3_to_mysql/types.py (1)

50-50: Types for mysql_table_prefix are aligned with transporter usage

Adding mysql_table_prefix: t.Optional[str] to SQLite3toMySQLParams and _mysql_table_prefix: str to SQLite3toMySQLAttributes matches how SQLite3toMySQL.__init__ normalises the value to a str. This keeps the Unpackable parameter surface and internal state consistent, as per the typed‑params guideline.

Also applies to: 79-79

src/sqlite3_to_mysql/cli.py (1)

17-18: CLI table‑prefix option is well‑integrated and reuses core validation

The _validate_mysql_table_prefix() callback correctly shares MYSQL_TABLE_PREFIX_PATTERN with the transporter, returning an empty string when unset and raising click.BadParameter for invalid values. The new -b/--mysql-table-prefix option is documented clearly, threads a mysql_table_prefix: str parameter into cli(), and is passed through to SQLite3toMySQL(...) using the same keyword name, so type hints and runtime wiring stay in sync.

No behavioural issues spotted; the error handling and debug flag semantics are unchanged.

Also applies to: 23-32, 132-138, 172-203, 230-259

tests/unit/sqlite3_to_mysql_test.py (3)

70-98: CLI tests cover prefix propagation end‑to‑end

test_cli_mysql_table_prefix_passed_to_transporter and test_cli_mysql_table_prefix_validation nicely assert that --mysql-table-prefix both reaches the transporter ctor kwargs and is rejected early when invalid. This gives good confidence that the new option is wired and guarded correctly at the CLI boundary.


432-470: Transfer stub initialises _mysql_table_prefix, keeping tests forward‑compatible

Initialising _mysql_table_prefix = "" in _make_transfer_stub() mirrors the real constructor and ensures new uses of _mysql_table_name() in transfer() behave predictably in tests that use __new__. This avoids brittle AttributeErrors while still defaulting to no prefix.


1801-1827: Foreign‑key prefix test validates child and parent table naming

test_add_foreign_keys_apply_mysql_table_prefix builds a lightweight instance with _mysql_table_prefix = "pre_" and verifies both ALTER TABLE \pre_child`andREFERENCES `pre_parent`appear in the emitted DDL. This directly checks that_add_foreign_keys()` applies the prefix consistently to both sides of the relationship, complementing the existing shorthand‑PK tests.

@codecov
Copy link

codecov bot commented Nov 16, 2025

Codecov Report

❌ Patch coverage is 96.87500% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 98.01%. Comparing base (0a876c7) to head (9a2d4ca).

Files with missing lines Patch % Lines
src/sqlite3_to_mysql/transporter.py 95.45% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #158      +/-   ##
==========================================
- Coverage   98.05%   98.01%   -0.04%     
==========================================
  Files           8        8              
  Lines        1132     1160      +28     
==========================================
+ Hits         1110     1137      +27     
- Misses         22       23       +1     

☔ 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/sqlite3_to_mysql/transporter.py (1)

1338-1476: Table prefixing breaks MySQL views created from SQLite views

In transfer(), you now:

  • Create and populate base tables using mysql_table_name = self._mysql_table_name(table_name).
  • Later, when not self._sqlite_views_as_tables and self._mysql_create_tables, translate SQLite views via _translate_sqlite_view_definition(view_name, sql_definition) and create them with _create_mysql_view(view_name, mysql_view_sql).

However, _translate_sqlite_view_definition does not rewrite table references inside the view SQL to use self._mysql_table_name(...). With a non‑empty mysql_table_prefix, the MySQL view definition will still reference unprefixed base table names (e.g. SELECT * FROM `my_table```), while the actual tables were created as {prefix}my_table ``. That means:

  • Views will fail at runtime with “table does not exist” errors when queried.
  • The failure is silent at migration time because view creation itself does not touch the base table.

This is a functional regression for the combination “table prefix + view replication”.

A minimal mitigation would be to explicitly skip or forbid view creation when a prefix is configured, rather than silently creating broken views. For example:

@@ def transfer(self) -> None:
-        if not self._sqlite_views_as_tables and self._mysql_create_tables:
-            views: t.List[t.Dict[str, t.Any]] = self._fetch_sqlite_master_rows(("view",), include_sql=True)
-        else:
-            views = []
+        if not self._sqlite_views_as_tables and self._mysql_create_tables:
+            views: t.List[t.Dict[str, t.Any]] = self._fetch_sqlite_master_rows(("view",), include_sql=True)
+            if getattr(self, "_mysql_table_prefix", ""):
+                self._logger.warning(
+                    "Skipping creation of MySQL views for SQLite views because mysql_table_prefix %r is set; "
+                    "view definitions currently reference unprefixed table names.",
+                    self._mysql_table_prefix,
+                )
+                views = []
+        else:
+            views = []

Longer term, a more complete fix would be to use sqlglot to rewrite exp.Table nodes in the parsed view expression so that any base table whose SQLite name is t is rendered as self._mysql_table_name(t) in the MySQL view definition.

🧹 Nitpick comments (5)
src/sqlite3_to_mysql/cli.py (1)

17-32: Shared table-prefix validation is correct; consider centralising the message text

Reusing MYSQL_TABLE_PREFIX_PATTERN in _validate_mysql_table_prefix keeps CLI and transporter validation aligned, and returning "" for falsy values matches the default behaviour. The long error message string is duplicated here and in SQLite3toMySQL.__init__, and Ruff flags it (TRY003); you could extract a shared constant (e.g. MYSQL_TABLE_PREFIX_HELP) and reuse it for both the exception text and the CLI help for easier maintenance.

src/sqlite3_to_mysql/transporter.py (4)

179-186: mysql_table_prefix normalisation/validation covers programmatic use; message could be shared

Normalising mysql_table_prefix to a string, validating only when truthy, and raising ValueError if it doesn’t match TABLE_PREFIX_PATTERN gives the same guarantees as the CLI for non‑CLI callers, which is good.

As Ruff notes (TRY003), the long error message string here duplicates the CLI message; consider hoisting a shared constant (e.g. MYSQL_TABLE_PREFIX_ERROR) used by both this ValueError and the Click BadParameter to keep messages in sync.


900-999: Prefixed table names in _create_table are consistent; DEFAULT handling remains correct

Using mysql_table_name = self._mysql_table_name(table_name) for the CREATE TABLE statement and for constraint names/logging keeps the physical MySQL table name consistent with the prefix configuration.

The updated DEFAULT clause condition now relies on self._column_type_supports_default(base_type, self._allow_expr_defaults) and passes self._allow_expr_defaults into _format_textual_default, which aligns with the capability flags initialised in __init__. The control flow around retrying without DEFAULTs still looks correct.

One minor suggestion in light of identifier limits: constraint names like `{mysql_table_name}_rowid` can now grow longer due to the prefix. If you start seeing ER_TOO_LONG_IDENT on constraint creation, you may want to wrap the constraint identifier in safe_identifier_length(...) as well.


1128-1216: Index DDL and logging correctly target the prefixed table name; consider logging.exception on hard failures

Using mysql_table_name = self._mysql_table_name(table_name) in _add_index ensures ALTER TABLE, duplicate-key retries, and warnings/errors all reference the actual MySQL table name, which is important once a prefix is configured.

Ruff’s TRY400 hint about logging.exception applies to the final self._logger.error(...); raise branch: switching that last error log to self._logger.exception(...) would capture the traceback automatically and can aid debugging without changing control flow.


1219-1299: Foreign key definitions and logging now use prefixed table names consistently

In _add_foreign_keys, using mysql_table_name and mysql_ref_table_name for the ALTER TABLE and REFERENCES clauses keeps foreign key constraints aligned with the prefixed tables, and the warnings/errors now log the same names, which should help correlate with MySQL’s own diagnostics.

Just like with the rowid constraint, composite constraint names ({table}_FK_{id}_{seq}) can become quite long when a prefix is used. If you hit identifier-length errors in practice, consider wrapping the generated constraint name with safe_identifier_length(...).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a2d4ca and e1291e5.

📒 Files selected for processing (2)
  • src/sqlite3_to_mysql/cli.py (4 hunks)
  • src/sqlite3_to_mysql/transporter.py (21 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
src/sqlite3_to_mysql/transporter.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/sqlite3_to_mysql/transporter.py: Keep SQLite3toMySQL.transfer() flow: create DB (if missing) → create tables → optionally truncate → bulk insert (chunked or streamed) → then create indices → then add foreign keys
On table creation failures due to expression DEFAULTs, retry without DEFAULTs (two-pass _create_table with skip_default=True)
Initialize MySQL capability booleans (e.g., _mysql_fulltext_support, _allow_expr_defaults) early in init, and gate conditional behavior on them
Extend column type translation only in _translate_type_from_sqlite_to_mysql instead of scattering conversions
Handle DEFAULT normalization in _translate_default_for_mysql; return empty string to suppress invalid defaults
During index creation, handle duplicate names by appending numeric suffixes, unless _ignore_duplicate_keys is set to skip retries
Implement chunked transfer with cursor.fetchmany when --chunk is set; otherwise use fetchall with tqdm progress
Only add foreign keys when no table include/exclude filters are set and --without-foreign-keys is not in effect
Implement insert methods: IGNORE (default), UPDATE using ON DUPLICATE KEY UPDATE (with optional VALUES alias), and DEFAULT (no modifiers)
Expose new capability booleans from init of SQLite3toMySQL for downstream logic
Use prepared cursors (cursor(prepared=True)) and batch inserts via executemany for performance
For large transfers, prefer --chunk and preserve commit granularity in any new bulk path

Files:

  • src/sqlite3_to_mysql/transporter.py
src/sqlite3_to_mysql/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/sqlite3_to_mysql/**/*.py: Always wrap dynamic table/index/column names with safe_identifier_length(...) before emitting SQL
Use the class _logger for logging; do not print directly; respect the quiet flag for progress/INFO while always emitting errors

Files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
src/**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.py: Format with Black (line length 120) and isort (profile=black); adhere to Flake8’s 88-column soft cap to avoid long chained expressions on one line
Preserve and add type hints for new public interfaces

Files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
src/sqlite3_to_mysql/{cli.py,transporter.py}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In debug mode (--debug), surface exceptions instead of swallowing them

Files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
src/sqlite3_to_mysql/cli.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/sqlite3_to_mysql/cli.py: Define and maintain the Click CLI in cli.py, validating mutual exclusions and implied flags for options
Make --sqlite-tables and --exclude-sqlite-tables mutually exclusive; setting either implies --without-foreign-keys
Disallow simultaneous -K (skip create) and -J (skip transfer) with an early exit and clear error message
Expose insert method choices IGNORE (default), UPDATE, and DEFAULT via CLI with clear help text
Define new CLI flags above cli() with consistent help text and error messages; maintain mutual exclusion patterns

Files:

  • src/sqlite3_to_mysql/cli.py
🧠 Learnings (18)
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/**/*.py : Always wrap dynamic table/index/column names with safe_identifier_length(...) before emitting SQL

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Initialize MySQL capability booleans (e.g., _mysql_fulltext_support, _allow_expr_defaults) early in __init__, and gate conditional behavior on them

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{mysql_utils.py,sqlite_utils.py} : Centralize dialect/version feature checks, type adaptation, and identifier safety in mysql_utils.py and sqlite_utils.py; add new MySQL capability gates here

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{mysql_utils.py,sqlite_utils.py} : Add new MySQL/SQLite capability checks in mysql_utils.py/sqlite_utils.py and keep them as dedicated helpers

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Expose new capability booleans from __init__ of SQLite3toMySQL for downstream logic

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Extend column type translation only in _translate_type_from_sqlite_to_mysql instead of scattering conversions

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Keep SQLite3toMySQL.transfer() flow: create DB (if missing) → create tables → optionally truncate → bulk insert (chunked or streamed) → then create indices → then add foreign keys

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Implement insert methods: IGNORE (default), UPDATE using ON DUPLICATE KEY UPDATE (with optional VALUES alias), and DEFAULT (no modifiers)

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Handle DEFAULT normalization in _translate_default_for_mysql; return empty string to suppress invalid defaults

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : On table creation failures due to expression DEFAULTs, retry without DEFAULTs (two-pass _create_table with skip_default=True)

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/types.py : Provide typed parameter/attribute structures in types.py for consumption via typing.Unpack in SQLite3toMySQL.__init__

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : During index creation, handle duplicate names by appending numeric suffixes, unless _ignore_duplicate_keys is set to skip retries

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/transporter.py : Only add foreign keys when no table include/exclude filters are set and --without-foreign-keys is not in effect

Applied to files:

  • src/sqlite3_to_mysql/transporter.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Define new CLI flags above cli() with consistent help text and error messages; maintain mutual exclusion patterns

Applied to files:

  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Define and maintain the Click CLI in cli.py, validating mutual exclusions and implied flags for options

Applied to files:

  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Make --sqlite-tables and --exclude-sqlite-tables mutually exclusive; setting either implies --without-foreign-keys

Applied to files:

  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/cli.py : Expose insert method choices IGNORE (default), UPDATE, and DEFAULT via CLI with clear help text

Applied to files:

  • src/sqlite3_to_mysql/cli.py
📚 Learning: 2025-10-23T18:16:08.709Z
Learnt from: CR
Repo: techouse/sqlite3-to-mysql PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-23T18:16:08.709Z
Learning: Applies to src/sqlite3_to_mysql/{cli.py,transporter.py} : In debug mode (--debug), surface exceptions instead of swallowing them

Applied to files:

  • src/sqlite3_to_mysql/cli.py
🧬 Code graph analysis (1)
src/sqlite3_to_mysql/transporter.py (1)
src/sqlite3_to_mysql/mysql_utils.py (1)
  • safe_identifier_length (166-168)
🪛 Ruff (0.14.4)
src/sqlite3_to_mysql/transporter.py

181-184: Avoid specifying long messages outside the exception class

(TRY003)


995-999: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


1210-1215: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

src/sqlite3_to_mysql/cli.py

28-31: Avoid specifying long messages outside the exception class

(TRY003)

⏰ 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.10, mariadb:10.0, 1, true, 3.10)
  • 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.12, mariadb:5.5, 1, true, 3.12)
  • GitHub Check: Test (python3.14, mariadb:5.5, 1, true, 3.14)
  • 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 (7)
src/sqlite3_to_mysql/cli.py (3)

132-139: New --mysql-table-prefix option is wired cleanly

The -b/--mysql-table-prefix option with a default of "" and the callback is consistent with existing options, and the help text accurately documents the regex constraints and length limit. There are no mutual-exclusion clashes with other flags.


173-204: CLI signature update for mysql_table_prefix keeps type hints consistent

Adding mysql_table_prefix: str to the cli parameters matches the callback’s return type and keeps the signature explicit and typed. No issues from a Click or typing perspective.


231-260: Propagation of mysql_table_prefix into SQLite3toMySQL looks correct, but suffix from issue #155 remains unimplemented

Passing mysql_table_prefix=mysql_table_prefix into SQLite3toMySQL integrates the new option into the transport layer cleanly, and the parameter ordering is consistent with the attributes structure.

One thing to double-check against the linked issue: #155 mentions both a prefix and a suffix for converted table names. This PR implements only the prefix path; if suffix support is still planned, you might want to mirror this CLI wiring for a --mysql-table-suffix flag in a follow‑up.

src/sqlite3_to_mysql/transporter.py (4)

69-96: Centralising the table-prefix regex is a solid choice

Defining MYSQL_TABLE_PREFIX_PATTERN once at module level and exposing it via TABLE_PREFIX_PATTERN on the class avoids divergent rules between CLI and transporter. The regex itself enforces the documented constraints (leading letter, alphanumeric/underscore, ≤32 chars) and is straightforward to follow.


352-357: _mysql_table_name encapsulates prefixing and length limiting cleanly

Encapsulating prefix application and safe_identifier_length in _mysql_table_name is a nice way to keep call sites simple and ensure MySQL’s identifier length limit is respected. Using getattr with a default guards against tests or partial construction using mocks.


1003-1017: Table truncation correctly honours the prefixed table name

_truncate_table now uses self._mysql_table_name(table_name) both in the INFORMATION_SCHEMA.TABLES lookup and the TRUNCATE TABLE statement, and logs against the same name. This keeps truncation in sync with how tables are created.


1019-1085: Index metadata still uses SQLite names, but operations/logging reference the prefixed MySQL table

The added mysql_table_name variable is used only for logging in the warning path, while index creation is delegated to _add_index, which re-computes the prefixed table name internally. That separation is fine: SQLite metadata uses original names, and MySQL DDL/logging use the prefixed ones.

@techouse techouse marked this pull request as draft November 16, 2025 17:58
@techouse techouse mentioned this pull request Nov 16, 2025
@techouse techouse closed this Nov 16, 2025
@techouse techouse deleted the feat/table-prefix branch November 16, 2025 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Convert renaming tables

2 participants