Skip to content

Tính năng chuyển đổi dữ liệu H2 <-> MariaDB/MySQL - #80

Closed
minhh2792 wants to merge 1 commit into
masterfrom
database-converter
Closed

Tính năng chuyển đổi dữ liệu H2 <-> MariaDB/MySQL#80
minhh2792 wants to merge 1 commit into
masterfrom
database-converter

Conversation

@minhh2792

@minhh2792 minhh2792 commented Jun 18, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features
    • Added database conversion command to migrate between H2 and SQL databases (MySQL/MariaDB)
    • Includes validation to prevent invalid conversions
    • Progress tracking displayed during conversion
    • Confirmation prompt before starting conversion

@minhh2792 minhh2792 self-assigned this Jun 18, 2026
Copilot AI review requested due to automatic review settings June 18, 2026 19:34
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a new dbconvert subcommand to AdminCmd and two new files: DbConvertEngine (an enum defining H2/MySQL/MariaDB with validation rules) and DbConversionService (a full conversion pipeline that migrates schema, copies batched table data between engines under transaction control, tracks progress via a boss bar, and reports results to the player).

Changes

Database Conversion Feature

Layer / File(s) Summary
DbConvertEngine enum and validation rules
dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConvertEngine.kt
Defines the DbConvertEngine enum (H2, MYSQL, MARIADB) with migration path strings, SQL identifier quoting, isSql(), case-insensitive from() lookup, and a validate() method that returns localized error strings for invalid H2↔SQL conversion configurations.
AdminCmd dbconvert subcommand
dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt
Registers dbconvert in the command tree, implements the command with argument validation, concurrency guard via DbConversionService.isRunning(), engine parsing and validation, an interactive ChatListener-based XACNHAN/huy confirmation flow, and tab completion helpers availableSources/availableTargets.
DbConversionService entry point and connection management
dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt
Provides an AtomicBoolean concurrency guard, isRunning() accessor, start() async entrypoint with success/failure reporting and plugin disable on H2 target success, and openConnection() that draws from the SQL pool or creates a temporary H2 pool.
Core conversion pipeline: migration, schema discovery, table copy
dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt
Implements convert() orchestrating connection open, bidirectional migration via BukkitDBMigrator, JDBC metadata-based dotman_ table/column discovery, copy eligibility validation, row counting, and per-table batched DELETE+INSERT with manual transaction commit/rollback.
Post-copy operations and transaction cleanup
dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt
Reseeds H2 auto-increment columns via ALTER TABLE ... RESTART WITH, persists migration_version using engine-specific SQL (MERGE for H2, INSERT ... ON DUPLICATE KEY UPDATE for MySQL), and provides best-effort rollback and connection-state reset helpers.
ConversionResult, ProgressView boss bar, and supporting types
dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt
Defines ConversionResult with sendTo(player) summary formatting, ProgressView managing a Bukkit boss bar with throttled ETA updates marshalled via runSync, and supporting types ManagedConnection, TablePair, TableInfo, ColumnInfo, and a ResultSet.isAutoIncrementColumn() helper.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • amadeusmz

Poem

🐇 Hoppin' through H2 and MySQL's den,
I copy your tables again and again.
A boss bar of progress, a XACNHAN cheer,
MERGE or INSERT — the bunny is here!
When migration is done, I'll rest in my hutch,
Converting databases — not by much! 🗄️✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main feature: adding database conversion capability between H2 and MariaDB/MySQL engines, which aligns with all three modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch database-converter

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.

Copilot AI 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.

Pull request overview

PR bổ sung tính năng chuyển đổi dữ liệu giữa H2 và MariaDB/MySQL trong plugin DotMan, cho phép admin chạy chuyển đổi trực tiếp trong game và theo dõi tiến độ bằng bossbar.

Changes:

  • Thêm enum DbConvertEngine để chuẩn hoá engine, quoting identifier và validate điều kiện chuyển đổi.
  • Thêm DbConversionService thực hiện pipeline migrate schema, đối chiếu bảng/cột, copy dữ liệu theo batch, và reseed identity cho H2.
  • Thêm subcommand /dotman admin dbconvert (có confirm qua chat + tab-complete) để kích hoạt chuyển đổi.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConvertEngine.kt Khai báo engine (H2/MySQL/MariaDB), quoting và validate rule chuyển đổi.
dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt Implement toàn bộ logic migrate + copy dữ liệu + hiển thị tiến độ.
dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt Thêm command dbconvert, tab completion và luồng xác nhận qua chat.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +411 to +418
tabComplete {
val current = DbConvertEngine.from(DotMan.instance.config.config.getString("database.engine"))
when (args.size) {
1 -> availableSources(current).filter { it.startsWith(args.last().lowercase()) }
2 -> availableTargets(args.firstOrNull(), current).filter { it.startsWith(args.last().lowercase()) }
else -> emptyList()
}
}
Comment on lines +451 to +462
player.send("""
§eBạn sắp chuyển đổi database từ §b§n${source.typeName}§f -> §a§n${target.typeName}
§r
§c§lLƯU Ý:
§e- Hãy nhớ backup dữ liệu trước khi tiếp tục.
§e- Dữ liệu ở database đích §b(${target.typeName})§e sẽ bị ghi đè (nếu có).
§e- Chỉ thực hiện khi server không có người chơi.
§e- Quá trình chuyển đổi có thể mất vài phút, hãy kiên nhẫn chờ đợi và đừng tắt server trong quá trình này.
§e- Sau khi chuyển đổi xong, hãy nhớ cập nhật lại cấu hình database trong file config.yml và restart server để áp dụng.
§r
§eNhập §a§lXACNHAN §eđể bắt đầu, hoặc nhập §c§lHUY §eđể hủy bỏ.
""".trimIndent())
Comment on lines +325 to +327
target.createStatement().use { statement ->
statement.executeUpdate("DELETE FROM $targetTableName")
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt (1)

482-494: Acknowledged TODO: Boss bar removed before completion state is visible.

The complete() method immediately calls removeAll(), which removes the boss bar before the player can see the 100% completion state. To improve UX, the boss bar should remain visible briefly before removal.

Would you like me to generate a workaround using Bukkit's scheduler to delay the removeAll() call until runLater is available in minevn-lib? A simple approach using Bukkit.getScheduler().runTaskLater() with a 40-60 tick delay would provide the same effect.

🤖 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
`@dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt`
around lines 482 - 494, The complete() method removes the boss bar immediately
after setting it to 100% progress and green color, preventing the player from
seeing the completion state. Wrap the bossBar?.removeAll() call with a delayed
execution using Bukkit.getScheduler().runTaskLater() to delay the removal by
40-60 ticks (2-3 seconds), allowing the completion state to remain visible to
the player before the boss bar is removed.
🤖 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 `@dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt`:
- Around line 414-415: The tab completion filter in the adminCmd has a case
mismatch where availableSources() and availableTargets() return uppercase values
but are filtered against args.last().lowercase(). To fix this, apply
.lowercase() to the items returned from availableSources(current) and
availableTargets(args.firstOrNull(), current) before filtering them with
startsWith(args.last().lowercase()), so that "h2".startsWith("h") will correctly
match the available source values.

---

Nitpick comments:
In
`@dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt`:
- Around line 482-494: The complete() method removes the boss bar immediately
after setting it to 100% progress and green color, preventing the player from
seeing the completion state. Wrap the bossBar?.removeAll() call with a delayed
execution using Bukkit.getScheduler().runTaskLater() to delay the removal by
40-60 ticks (2-3 seconds), allowing the completion state to remain visible to
the player before the boss bar is removed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3a6e2f08-44f7-4cb4-811f-7541dd8d63cb

📥 Commits

Reviewing files that changed from the base of the PR and between 6379abf and ce25388.

📒 Files selected for processing (3)
  • dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt
  • dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConversionService.kt
  • dotman-plugin/src/main/java/net/minevn/dotman/database/convert/DbConvertEngine.kt

Comment on lines +414 to +415
1 -> availableSources(current).filter { it.startsWith(args.last().lowercase()) }
2 -> availableTargets(args.firstOrNull(), current).filter { it.startsWith(args.last().lowercase()) }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Tab completion filter has case mismatch.

availableSources() and availableTargets() return uppercase values (e.g., "H2", "MYSQL"), but the filter compares against args.last().lowercase(). This causes "H2".startsWith("h") to return false, so typing h won't suggest H2.

🔧 Proposed fix
 tabComplete {
     val current = DbConvertEngine.from(DotMan.instance.config.config.getString("database.engine"))
     when (args.size) {
-        1 -> availableSources(current).filter { it.startsWith(args.last().lowercase()) }
-        2 -> availableTargets(args.firstOrNull(), current).filter { it.startsWith(args.last().lowercase()) }
+        1 -> availableSources(current).filter { it.lowercase().startsWith(args.last().lowercase()) }
+        2 -> availableTargets(args.firstOrNull(), current).filter { it.lowercase().startsWith(args.last().lowercase()) }
         else -> emptyList()
     }
 }
🤖 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 `@dotman-plugin/src/main/java/net/minevn/dotman/commands/AdminCmd.kt` around
lines 414 - 415, The tab completion filter in the adminCmd has a case mismatch
where availableSources() and availableTargets() return uppercase values but are
filtered against args.last().lowercase(). To fix this, apply .lowercase() to the
items returned from availableSources(current) and
availableTargets(args.firstOrNull(), current) before filtering them with
startsWith(args.last().lowercase()), so that "h2".startsWith("h") will correctly
match the available source values.

@minhh2792
minhh2792 marked this pull request as draft July 13, 2026 17:02
@minhh2792 minhh2792 closed this Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants