Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-78 Rewrite database to ORMLite JDBC #116

Merged
merged 46 commits into from
Jan 15, 2025
Merged

GH-78 Rewrite database to ORMLite JDBC #116

merged 46 commits into from
Jan 15, 2025

Conversation

Jakubk15
Copy link
Member

@Jakubk15 Jakubk15 commented Dec 31, 2024

Resolves #78

Adds support for more database types as well as rewrites general database logic to use the j256/ormlite-jdbc library.

@Jakubk15 Jakubk15 added 🆕 feature New feature or request 🛠️ maintainers task This task will be handled by EternalCodeTeam Maintainers, please do not PR. labels Dec 31, 2024
Copy link
Contributor

coderabbitai bot commented Dec 31, 2024

Warning

Rate limit exceeded

@Jakubk15 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 13 minutes and 42 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between defdc12 and 7e978f0.

📒 Files selected for processing (2)
  • src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (8 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepositoryOrmLite.java (1 hunks)

Walkthrough

The pull request introduces a comprehensive refactoring of the database layer in the ParcelLockers plugin, transitioning from a custom database implementation to an ORM Lite (Object-Relational Mapping Lite) approach. This change involves replacing existing repository implementations with ORM Lite versions, introducing new wrapper classes for database entities, and updating the database management strategy. The modifications support multiple database types, including H2, PostgreSQL, and MySQL, with improved configuration and connection handling.

Assessment against linked issues

Objective Addressed Explanation
Rewrite database to ORMLite JDBC [#78]

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Jakubk15
Copy link
Member Author

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Dec 31, 2024

✅ Actions performed

Review triggered.

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.

Copy link
Contributor

@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: 6

🔭 Outside diff range comments (1)
src/main/java/com/eternalcode/parcellockers/user/UserManager.java (1)

Line range hint 51-63: Potential Concurrency Issues in create(UUID uuid, String name)

While the create method works for a single-threaded approach, concurrent calls can pose these risks:

  1. Race Conditions: Two threads creating the same user simultaneously might slip past the containsKey checks.
  2. Repository Consistency: A user might fail to be saved if an exception occurs in the repository, potentially leaving the in-memory map out of sync.

To address these concerns, consider atomic checks or synchronization around map updates, or rely on your repository if it can guarantee uniqueness at the database level.

🧹 Nitpick comments (33)
src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepository.java (1)

22-22: Document the return value meaning
Changing the return type from CompletableFuture<Void> to CompletableFuture<Integer> is beneficial, as it allows for tracking how many records were removed. However, please add or update documentation to clarify what the returned integer represents (e.g., the count of removed rows or an indicator of success/failure).

src/main/java/com/eternalcode/parcellockers/user/repository/UserWrapper.java (4)

9-10: Consider class visibility for broader usage.
By default, this class is package-private. If future features or modules outside this package will need direct access to UserWrapper, consider using the public modifier.


15-16: Specify additional column constraints for robustness.
If there is a maximum length or uniqueness requirement for username, consider leveraging ORMLite’s @DatabaseField attributes (e.g., width, unique) to ensure better data consistency and constraints.


26-28: Validate non-null argument to avoid potential NullPointerException.
If user is ever null, user.uuid() and user.name() would raise an exception. Consider adding a null check or clarifying in the method contract that user must not be null.


30-32: Check consistency of exposure vs. encapsulation.
setUsername(...) is declared public while the class itself is package-private. If external consumers need to update username, ensure that the class is likewise accessible; otherwise, consider limiting the visibility of this setter.

src/main/java/com/eternalcode/parcellockers/user/repository/UserRepositoryOrmLite.java (2)

22-28: Consider avoiding double-logging exceptions.

Here, the code captures exceptions with Sentry and also prints the stack trace. This can lead to duplicate logs. Typically, either logging to Sentry with supplemental log statements or printing stack traces individually should suffice.

 try {
     TableUtils.createTableIfNotExists(databaseManager.connectionSource(), UserWrapper.class);
 } catch (SQLException exception) {
     Sentry.captureException(exception);
-    exception.printStackTrace();
 }

58-74: Revisit the pagination logic when checking hasNext.

Currently, the query limits results to page.getLimit(), so you do not fetch an extra record to determine if more data exists. If you'd like to confirm there is more data, you might need to query for limit + 1 rows and then remove the last row if it exists.

List<User> users = dao.queryBuilder()
-    .offset((long) page.getOffset())
-    .limit((long) page.getLimit())
+    .offset((long) page.getOffset())
+    .limit((long) (page.getLimit() + 1))
     .query()
     .stream()
     .map(UserWrapper::toUser)
     .collect(Collectors.toList());

boolean hasNext = users.size() > page.getLimit();
if (hasNext) {
    users.remove(users.size() - 1);
}
src/main/java/com/eternalcode/parcellockers/database/wrapper/AbstractRepositoryOrmLite.java (3)

17-19: Use more descriptive parameter names for clarity
In methods like save(Class<T> type, T warp), the parameter name warp can be confusing. Consider renaming this parameter to something more descriptive, such as entity.


53-55: Provide a custom Executor or clarify concurrency requirements
CompletableFuture.runAsync(...) uses the common ForkJoinPool by default, which may be undesirable in some scenarios (e.g., heavy I/O operations or concurrency constraints). Consider providing a custom Executor if you need stricter control over threading or concurrency.


62-66: Avoid printing stack traces after sending them to Sentry
You are already capturing exceptions with Sentry. Printing stack traces manually might create redundant logs. Instead, consider using a logger at a suitable log level if needed for local debugging.

src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepositoryOrmLite.java (2)

30-36: Consider removing raw exception printing
You capture exceptions with Sentry but also call ex.printStackTrace(). You may want to switch to a standard logger to ensure consistent logging across the application.


38-42: Check for cache and database consistency
When save(Parcel parcel) completes asynchronously, the parcel is added to the cache immediately but the database operation is still pending. In highly concurrent scenarios, this might momentarily create inconsistencies. Consider documenting or synchronizing the cache update if consistency is critical.

src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryOrmLite.java (1)

118-124: Handle potential concurrency race conditions in updateCaches()
The method clears and repopulates caches asynchronously. If other threads are reading or writing at the same time, keys may vanish or reappear in unexpected ways. Add explicit synchronization or use thread-safe structures to ensure data consistency.

src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (5)

112-113: ORMLite log set to NullLogBackend.
Double-check if you want all logs suppressed. Debugging database operations may be harder without logs.


114-123: Instantiation and connection of DatabaseManager.
While this works, consider instantiating directly into the field and connecting within the try block to avoid potential scoping confusion. Also consider adding more descriptive error handling or fallback logic in case of failures.


134-135: ItemStorageRepositoryOrmLite creation.
Implementation looks straightforward. The blank line may be removed for cleanliness.


186-189: Gracefully disconnecting from the database.
Consider wrapping disconnect() in a try-catch block to handle potential close errors or log them.


208-208: MC version support warning updated.
You might want to mention your newly supported range in documentation for clarity.

src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageWrapper.java (1)

29-35: Enforce immutability of domain objects if permissible.
Currently, List<ItemStack> items is mutable and returned directly via toItemStorage(). If the data should be immutable after loading from DB, consider returning an unmodifiable list.

src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentWrapper.java (3)

12-13: Check table naming consistency.
Ensure that "parcel_content" aligns with naming conventions used across the project. In some teams, table names are all plural or all singular. This keeps your schema consistent if you have multiple domain objects.


15-19: Consider data growth strategy.
Similar to ItemStorageWrapper, this class stores a list of ItemStack objects in a single column. Evaluate your expected row sizes—if you need advanced queries on these items, normalizing or splitting them across multiple records may be more scalable.


29-35: Avoid passing mutable data.
When converting to ParcelContent, consider returning an unmodifiable or defensive copy of the items list to prevent in-place modifications that might drift from the state saved in the database.

src/main/java/com/eternalcode/parcellockers/locker/repository/LockerWrapper.java (1)

11-12: Use consistent naming for table columns.
@DatabaseTable(tableName = "lockers") is clear, but verify that other similar domain objects use either “plural” or “singular” naming for table names.

src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageRepositoryOrmLite.java (1)

19-25: Improve exception logging.
In addition to capturing the exception in Sentry, consider using a logger instead of ex.printStackTrace() for consistent log formatting and better integration with logging tools.

} catch (SQLException ex) {
    Sentry.captureException(ex);
-   ex.printStackTrace();
+   Logger logger = LoggerFactory.getLogger(ItemStorageRepositoryOrmLite.class);
+   logger.error("Failed to create table", ex);
}
src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryOrmLite.java (1)

28-31: Clarify asynchronous return value
When returning a CompletableFuture<Void>, it might be useful to capture and handle possible exceptions. Consider chaining a .exceptionally(...) to log or manage failures, particularly for critical database write operations.

src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (2)

56-58: Validate null arguments in static factory method
When mapping from Parcel to ParcelWrapper, consider whether any fields can be null and handle them gracefully to prevent potential NullPointerException.


60-62: Review single-element Set usage
The toParcel() method creates a Set with only the sender. If multi-sender support is planned, consider adjusting or adding an appropriate collection. Otherwise, document this design choice for clarity.

src/test/java/com/eternalcode/parcellockers/database/ParcelLockerDatabaseServiceIntegrationTest.java (3)

17-17: Importing File for local data storage
Using java.io.File is standard, but ensure the hard-coded paths in this test file do not conflict with other test environments or CI servers.


20-20: Java Logger usage
Utilizing java.util.logging.Logger is acceptable. However, if your project uses SLF4J or another logging framework in production, consider aligning the test with the same logger approach for consistency.


33-33: Hard-coded data folder path
Storing data under "run/plugins/ParcelLockers" works locally but could be less flexible in CI or other environments. Consider using a parameterized or temporary folder for improved test portability.

- File dataFolder = new File("run/plugins/ParcelLockers");
+ File dataFolder = Files.createTempDirectory("ParcelLockersTest").toFile();
src/main/java/com/eternalcode/parcellockers/database/DatabaseManager.java (3)

47-49: Expose pool size and timeouts to config
Hardcoding HikariCP parameters can limit flexibility. Consider making these properties configurable in PluginConfiguration.

 this.dataSource.setMaximumPoolSize(5);
 this.dataSource.setConnectionTimeout(5000);
 this.dataSource.setLeakDetectionThreshold(5000);
+ // e.g., this.dataSource.setMaximumPoolSize(config.settings.poolSize);
+ //       this.dataSource.setConnectionTimeout(config.settings.connectionTimeout);
+ //       this.dataSource.setLeakDetectionThreshold(config.settings.leakDetectionThreshold);

65-68: Potential cross-platform path issue
For H2, jdbc:h2:./ plus File might cause path separators issues on some systems. Consider using dataFolder.getAbsolutePath() or a platform-agnostic approach.


99-114: Concurrent access to cached DAO
Using a ConcurrentHashMap is good, but creating a DAO in a race could produce redundant entries. Prevent this with computeIfAbsent or similar.

Dao<?, ?> dao = this.cachedDao.computeIfAbsent(type, key -> {
    try {
        return DaoManager.createDao(this.connectionSource, key);
    }
    catch (SQLException exception) {
        throw new RuntimeException(exception);
    }
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5743cb4 and f433141.

📒 Files selected for processing (41)
  • TODO.md (1 hunks)
  • build.gradle.kts (3 hunks)
  • src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (7 hunks)
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryImpl.java (0 hunks)
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentWrapper.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/AbstractDatabaseService.java (0 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/DataSourceFactory.java (0 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/DatabaseManager.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/DatabaseType.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/persister/ItemStackPersister.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/persister/PositionPersister.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/wrapper/AbstractRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/gui/implementation/locker/LockerMainGUI.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/gui/implementation/locker/ParcelItemStorageGUI.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/gui/implementation/locker/ParcelSendingGUI.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/gui/implementation/locker/ReceiverSelectionGui.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageRepositoryImpl.java (0 hunks)
  • src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageWrapper.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryImpl.java (0 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerWrapper.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepositoryImpl.java (0 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/shared/Position.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/UserManager.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/UserPageResult.java (0 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/UserRepositoryImpl.java (0 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/repository/UserPageResult.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/repository/UserRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/repository/UserRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/repository/UserWrapper.java (1 hunks)
  • src/test/java/com/eternalcode/parcellockers/database/ParcelDatabaseServiceIntegrationTest.java (2 hunks)
  • src/test/java/com/eternalcode/parcellockers/database/ParcelLockerDatabaseServiceIntegrationTest.java (2 hunks)
  • src/test/java/com/eternalcode/parcellockers/database/ParcelLockerIntegrationSpec.java (0 hunks)
💤 Files with no reviewable changes (9)
  • src/main/java/com/eternalcode/parcellockers/user/UserPageResult.java
  • src/test/java/com/eternalcode/parcellockers/database/ParcelLockerIntegrationSpec.java
  • src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageRepositoryImpl.java
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryImpl.java
  • src/main/java/com/eternalcode/parcellockers/database/AbstractDatabaseService.java
  • src/main/java/com/eternalcode/parcellockers/database/DataSourceFactory.java
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryImpl.java
  • src/main/java/com/eternalcode/parcellockers/user/UserRepositoryImpl.java
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepositoryImpl.java
✅ Files skipped from review due to trivial changes (7)
  • TODO.md
  • src/main/java/com/eternalcode/parcellockers/user/repository/UserPageResult.java
  • src/main/java/com/eternalcode/parcellockers/gui/implementation/locker/ReceiverSelectionGui.java
  • src/main/java/com/eternalcode/parcellockers/gui/implementation/locker/LockerMainGUI.java
  • src/main/java/com/eternalcode/parcellockers/gui/implementation/locker/ParcelItemStorageGUI.java
  • src/main/java/com/eternalcode/parcellockers/gui/implementation/locker/ParcelSendingGUI.java
  • src/main/java/com/eternalcode/parcellockers/user/repository/UserRepository.java
🔇 Additional comments (50)
src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepository.java (1)

24-24: Consistent handling of remove by UUID
Likewise, returning an integer here adds consistency. Verify that any consumer code handling partial or missing records is updated to interpret the integer's value correctly.

src/main/java/com/eternalcode/parcellockers/user/repository/UserWrapper.java (1)

12-13: Verify database column type compatibility.
Storing a Java UUID in the database typically requires either a VARCHAR(36) or similar column type. Confirm that ORMLite is configured to handle the UUID field correctly.

src/main/java/com/eternalcode/parcellockers/user/UserManager.java (3)

3-4: Importing UserRepository Looks Good

Bringing in the UserRepository from com.eternalcode.parcellockers.user.repository fits well with the new ORMLite-based design. This import is necessary for integrating the database interactions within the UserManager.


Line range hint 16-26: Asynchronous getUser(UUID uuid) Implementation

Returning a CompletableFuture<Optional<User>> is a solid choice for non-blocking I/O. This allows calls to the repository to be processed asynchronously, which can yield better performance. However, please verify:

  1. Thread-safety: Ensure that the usersByUUID map is only modified by safe operations or from a single thread, otherwise consider using concurrent structures or external synchronization.
  2. Consistent Cache Usage: Confirm whether the cache (i.e., usersByUUID) remains up-to-date whenever remote changes (e.g., name updates) occur in the repository.

Line range hint 28-38: Asynchronous getUser(String name) Method

Following a similar pattern to getUser(UUID), this asynchronous retrieval from the repository is clear. Keep an eye out for:

  1. Case Sensitivity: If user names ever vary in casing, consider normalizing or clarifying that names are case-sensitive.
  2. Performance: Double-check whether name-to-user lookups are frequent. If so, ensure that the usersByName map remains current to avoid stale or missing entries.
src/main/java/com/eternalcode/parcellockers/database/persister/ItemStackPersister.java (2)

38-40: Gracefully handle null inputs
Returning null from javaToSqlArg() is correct, but be mindful of any further processing in the call chain where a null might cause NullPointerException. Verify that all callers handle null results properly.


72-77: Consistent exception handling
Capturing exceptions with Sentry and throwing ParcelLockersException is a good approach. Ensure that any upstream callers handle or log the exception in a user-friendly manner.

src/test/java/com/eternalcode/parcellockers/database/ParcelDatabaseServiceIntegrationTest.java (1)

36-39: Confirm test container initialization and resource cleanup
The new approach loads configuration from disk and connects to the MySQL test container. Ensure that resource cleanup is properly handled and that leftover files in run/plugins/ParcelLockers do not interfere with subsequent tests.

src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (17)

5-6: Imports for scheduler functionality look good.
The newly introduced scheduler imports should help streamline asynchronous tasks. Ensure you properly handle concurrency and shutdown worker threads when the plugin is disabled.


12-12: Import for ParcelContentRepositoryOrmLite.
This aligns with the migration to the new ORMLite-based repository. Looks consistent with the PR objectives.


13-13: Import for DatabaseManager.
Matches the new refactored approach for database handling. No issues here.


18-18: Import for ItemStorageRepositoryOrmLite.
Consistent with the switch to ORMLite. Good to have a unified repository approach.


23-23: Import for LockerRepositoryOrmLite.
Migrating to ORM-based repository helps with cleaner database interactions.


31-31: Import for ParcelRepositoryOrmLite.
Complements the other repository migrations. No concerns here.


36-37: Imports for UserRepository and UserRepositoryOrmLite.
Indicates a shift to an ORM-based user repository. Looks good.


39-40: Imports for ORMLite logger classes.
Setting a null log backend might suppress important ORMLite logs. Consider using a minimal logger instead, unless silence is your intent.


60-60: Import for SQLException.
Necessary for robust error handling with the new database logic.


78-79: Field databaseManager introduced.
The field name clearly expresses its role. This refactor centralizes DB management.


96-96: Initializing the Scheduler implementation.
Please confirm that this scheduler instance is utilized later in the code. If unused, consider removing or storing it for task scheduling.


107-107: Disabling Sentry (options.setEnabled(false)).
Revisit whether disabling Sentry here conflicts with config.settings.enableSentry. This might override user configuration.


131-131: LockerRepositoryOrmLite usage.
Immediately updating caches is good for performance, but verify that it does not introduce heavy load on large datasets. Lazy-loading strategies or partial caching might be beneficial if the dataset grows large.


136-136: ParcelRepositoryOrmLite creation.
Consistent with the ORMLite approach. No issues.


140-140: UserRepositoryOrmLite assignment.
Smooth integration with UserManager. Looks well-structured.


143-143: ParcelContentRepositoryOrmLite usage.
Good alignment with the new ORM architecture.


212-212: Conditional check for version 17 or 21.
The OR condition might exclude versions between 18–20. If you intend multi-version support, verify that your condition is correct.

src/main/java/com/eternalcode/parcellockers/database/DatabaseType.java (1)

5-8: Newly added database types.
Supporting H2, POSTGRESQL, and MARIADB expands compatibility. Note that MariaDB can often be treated similarly to MySQL, so ensure your code handles their small differences if any.

src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageRepository.java (1)

15-15: Changed remove method return type to CompletableFuture<Integer>.
Returning the number of removed items (instead of void) makes the API more expressive. Great improvement.

src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepository.java (1)

13-13: Updated remove to return an integer.
This adds clarity about how many records were removed, aligning with other repositories.

src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepository.java (3)

23-23: remove(UUID) now returns CompletableFuture<Integer>.
Returning the count is good for validation or logging.


25-25: remove(Locker) similarly updated.
Consistent approach for remove. This helps unify repository expectations.


29-29: Renamed findLocker(uuid) to getFromCache(uuid).
The name emphasizes cache usage, which is more descriptive. Ensure there's a fallback if the cache is stale or empty.

src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageWrapper.java (2)

18-19: Verify the persister for a list of ItemStacks.
Storing a collection of complex objects such as ItemStack in a single table column can be fragile—especially when item data can be large or frequently updated. Ensure that ItemStackPersister thoroughly handles edge cases (e.g., corrupted data, partial updates).


12-13: Consider explicit access modifier.
Currently, the class is package-private. If other packages need to utilize ItemStorageWrapper, consider marking the class public, or providing factory methods/services within the same package to manage visibility.

Would you like me to search for references to ItemStorageWrapper outside this package to confirm whether it should be public?

src/main/java/com/eternalcode/parcellockers/locker/repository/LockerWrapper.java (2)

14-21: Check data constraints for fields.
The description field currently has no length or nullability constraints. If it can be very large or null, ensure the schema and code handle that properly.


32-38: Ensure domain-object integrity.
Locker is reconstructed directly from LockerWrapper. Confirm that no additional data validations are needed (e.g., checking for null uuid or invalid position).
[approve]

src/main/java/com/eternalcode/parcellockers/itemstorage/repository/ItemStorageRepositoryOrmLite.java (2)

28-30: Clarify the handling of DAO in save method.
The completion stage discards the DAO reference (thenApply(dao -> null)). Confirm that ignoring the DAO is intended, or if an additional operation should be performed with the DAO result.


38-39: Confirm correct row count for remove operation.
Returning an Integer row count is valuable, but ensure in tests or at call sites that removing a nonexistent entry returning 0 does not cause confusion.

src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryOrmLite.java (2)

19-25: Consider handling table creation exceptions more gracefully
Catching and printing stack traces is helpful for debugging, but for production systems, consider more robust exception handling (e.g., re-throwing a custom runtime exception, or ensuring logs are stored with proper context).


44-45: Check for potential null in parcelContentWrapper
When mapping via Optional.ofNullable(...), ensure parcelContentWrapper itself is not null. Though the code is currently safe, consider a null check or a default value to avoid subtle runtime errors if select(...) returns null unexpectedly.

src/main/java/com/eternalcode/parcellockers/database/persister/PositionPersister.java (1)

59-67: Validate format when splitting the deserialized string
Splitting on '/' without robust validation can lead to ArrayIndexOutOfBoundsException if the stored string is malformed. Consider verifying that params.length == 4 before parsing.

src/main/java/com/eternalcode/parcellockers/shared/Position.java (1)

58-58: Ensure world is not null before checking
The updated logic checks if this.world is empty, but does not handle null. If world might be null, consider a null-safe check or fallback to an empty string before comparison.

src/test/java/com/eternalcode/parcellockers/database/ParcelLockerDatabaseServiceIntegrationTest.java (5)

3-4: New imports for Configuration Manager and Plugin Configuration
These imports appear correct and are used consistently below. Good job ensuring the configuration and manager are introduced properly in this test.


8-8: Switching to ORM Lite repository
Importing the LockerRepositoryOrmLite is in line with the PR’s migration to ORM Lite. This is well-aligned with the new database approach.


34-34: Configuration loading
It’s good that the configuration is loaded in a straightforward manner. Ensure that you have test coverage to validate behavior when the config file is missing or malformed.


35-35: DatabaseManager instantiation
This follows the new design nicely. Make sure to verify the database manager is properly closed or disconnected at the end of the test to avoid resource leaks.


37-37: Repository assignment
Assigning the repository to the new ORM Lite class is consistent with the PR’s objectives. The usage in subsequent lines appears cohesive with the new database logic.

build.gradle.kts (4)

30-30: Updated API version
Switching to 1.21.4-R0.1-SNAPSHOT aligns with the new Minecraft version target. Ensure you’ve tested compatibility thoroughly.


60-62: Adding ORM Lite, H2, and PostgreSQL dependencies
Great job adding essential dependencies for the new database architecture. Verify that the correct versions are shaded or included in the plugin jar if your production environment needs them packaged.


133-133: Bumping the run server version
Ensure the updated test environment (1.21.4) is stable in your CI or local environment.


141-141: New jar naming convention
Renaming your output for broader version compatibility is clear and helpful for end users.

@Jakubk15 Jakubk15 requested a review from Rollczi December 31, 2024 16:32
Copy link
Contributor

@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: 5

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1137be0 and 93ef8e4.

📒 Files selected for processing (3)
  • src/main/java/com/eternalcode/parcellockers/database/wrapper/AbstractRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerWrapper.java (1 hunks)
  • src/test/java/com/eternalcode/parcellockers/TestScheduler.java (1 hunks)
🔇 Additional comments (7)
src/main/java/com/eternalcode/parcellockers/locker/repository/LockerWrapper.java (3)

11-12: Nice work on the class design!

The package-private visibility and table naming are well thought out.


20-21: Check the unique position constraint.

The unique position makes sense, but please verify:

  • What happens when a locker is deleted and a new one is created at the same spot?
  • Is there any cleanup needed?

23-30: Good job with the constructors!

Both the default constructor (needed for ORMLite) and the full constructor are properly implemented.

src/test/java/com/eternalcode/parcellockers/TestScheduler.java (4)

18-22: Implementation looks good!

The synchronous task execution is implemented correctly.


24-28: Implementation looks good!

The asynchronous execution using CompletableFuture is well implemented.


54-62: Review identical implementations

The complete and completeAsync methods have the same implementation. Consider if they should behave differently.


64-85: Implementation looks good!

The Task implementation has been improved to correctly handle both CompletableFuture and ScheduledFuture.

Jakubk15 and others added 2 commits January 14, 2025 19:05
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@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: 17

♻️ Duplicate comments (4)
src/main/java/com/eternalcode/parcellockers/database/persister/PositionPersister.java (1)

24-33: 🛠️ Refactor suggestion

Consider using JSON for robust serialization.

The current string concatenation approach might have issues with special characters in world names.

Note: This is a duplicate of a previous comment where JSON serialization was suggested as a more robust solution.

src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (1)

35-39: 🧹 Nitpick (assertive)

Consider adding indexes for locker fields

Since entryLocker and destinationLocker are likely to be frequently queried, adding indexes could improve performance.

-    @DatabaseField(columnName = "entryLocker")
+    @DatabaseField(columnName = "entryLocker", index = true)
     private UUID entryLocker;

-    @DatabaseField(columnName = "destinationLocker")
+    @DatabaseField(columnName = "destinationLocker", index = true)
     private UUID destinationLocker;
src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryOrmLite.java (1)

33-35: 🧹 Nitpick (assertive)

Consider removing redundant error logging

The ex.printStackTrace(); line might be unnecessary since the exception is already captured by Sentry and rethrown. Removing it can clean up the console output.

Apply this change:

             } catch (SQLException ex) {
                 Sentry.captureException(ex);
-                ex.printStackTrace();
                 throw new RuntimeException("Failed to initialize locker table", ex);
             }
src/main/java/com/eternalcode/parcellockers/locker/repository/LockerWrapper.java (1)

32-34: 🧹 Nitpick (assertive)

Add null check for safety

Adding a null check for the locker parameter can prevent potential issues if a null value is passed.

Consider updating the method:

 static LockerWrapper from(Locker locker) {
+    if (locker == null) {
+        throw new IllegalArgumentException("Locker cannot be null");
+    }
     return new LockerWrapper(locker.uuid(), locker.description(), locker.position());
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 93ef8e4 and 441acd6.

📒 Files selected for processing (13)
  • build.gradle.kts (3 hunks)
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentWrapper.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/persister/ItemStackPersister.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/persister/PositionPersister.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerWrapper.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/repository/UserWrapper.java (1 hunks)
  • src/test/java/com/eternalcode/parcellockers/TestScheduler.java (1 hunks)
🔇 Additional comments (14)
src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepository.java (2)

22-22: Changes look good

The updates to the remove methods' return types make sense.

Also applies to: 24-24


30-30: The method rename is clear

Renaming to findParcelFromCache accurately reflects its purpose.

src/test/java/com/eternalcode/parcellockers/TestScheduler.java (3)

18-20: Great job adding the shutdown method!


35-38: Please handle negative durations

It's a good idea to check if the duration is negative to prevent unexpected behavior.


47-50: Please handle negative durations

Make sure to validate that initialDelay and period are not negative.

src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (2)

1-12: Nice work on the class setup!

The class is well-organized with appropriate visibility and annotations.


41-54: Well-structured constructors!

Both the default constructor (required by ORMLite) and the all-args constructor are properly implemented.

src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryOrmLite.java (3)

40-45: Cache update after successful save looks good

Updating the cache after the locker is saved ensures consistency between the database and the cache. Nice work!


24-25: Great choice using ConcurrentHashMap

Using ConcurrentHashMap for cache and positionCache helps handle concurrent access safely. Good job!


62-64: ⚠️ Potential issue

Fix method usage when accessing list elements

Instead of lockers.getFirst(), which isn't a standard method for List, use lockers.get(0) to get the first element.

Here's the fix:

     return lockers.isEmpty() ? Optional.empty() : Optional.of(lockers.getFirst().toLocker());
+    return lockers.isEmpty() ? Optional.empty() : Optional.of(lockers.get(0).toLocker());

Likely invalid or redundant comment.

src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepository.java (1)

13-13: Ensure that the return type change for remove method is handled properly

Just wanted to mention that changing the return type from CompletableFuture<Void> to CompletableFuture<Integer> might affect existing code that uses this method. Please make sure to update any implementations or calls to handle the new return type.

You can run the following script to find all usages of the remove method and ensure they are updated accordingly:

✅ Verification successful

Return type change is safe to proceed

The code currently ignores the return value in all places where remove() is called, so changing from Void to Integer won't cause any issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all usages of 'remove' method in 'ParcelContentRepository' and check for handling of the return value.

rg 'ParcelContentRepository.*\.remove\(' -g '*.java' -t java

Length of output: 62


Script:

#!/bin/bash
# Find implementations and usages with broader patterns
echo "=== Finding interface implementations ==="
ast-grep --pattern 'class $_ implements $$$ParcelContentRepository$$$'

echo -e "\n=== Finding all remove method calls with UUID parameter ==="
rg '\.remove\(\s*[a-zA-Z0-9_]+\.getUniqueId\(\)\s*\)' -t java

echo -e "\n=== Finding imports of ParcelContentRepository ==="
rg "import.*ParcelContentRepository" -t java

Length of output: 1876

src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryOrmLite.java (1)

29-31: Consider returning the saved entity

The save operation could return the saved entity for further use, as suggested in previous reviews.

-public CompletableFuture<Void> save(ParcelContent parcelContent) {
-    return this.saveIfNotExist(ParcelContentWrapper.class, ParcelContentWrapper.from(parcelContent)).thenApply(dao -> null);
+public CompletableFuture<ParcelContent> save(ParcelContent parcelContent) {
+    return this.saveIfNotExist(ParcelContentWrapper.class, ParcelContentWrapper.from(parcelContent))
+        .thenApply(wrapper -> wrapper.toParcelContent());
build.gradle.kts (2)

141-141: Verify version compatibility

The version range has been narrowed from 1.8.8-1.21.x to 1.21.3-1.21.4. Make sure this change is intentional and all features are compatible with this range.


128-128: Document Java 21 requirement

The upgrade to Java 21 is significant. Consider adding a note in the README about this requirement.

Copy link
Contributor

@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: 12

🔭 Outside diff range comments (2)
src/main/java/com/eternalcode/parcellockers/locker/controller/LockerBreakController.java (2)

Line range hint 56-76: Simplify the break operation

Since we already have the locker in cache, we can simplify this:

-   this.lockerRepository.findByPosition(position).thenAccept((locker) -> {
-       if (locker.isEmpty()) {
-           return;
-       }
-
-       UUID toRemove = this.cache.get(position).get().uuid();
+   this.cache.get(position).ifPresent(locker -> {
+       UUID toRemove = locker.uuid();
        this.lockerRepository.remove(toRemove);

        this.announcer.sendMessage(player, this.messages.parcelLockerSuccessfullyDeleted);

        Formatter formatter = new Formatter()
            .register("{X}", position.x())
            .register("{Y}", position.y())
            .register("{Z}", position.z())
            .register("{WORLD}", position.world())
            .register("{PLAYER}", player.getName());

        this.announcer.broadcast(formatter.format(this.messages.broadcastParcelLockerRemoved));
-   });
+   });

Line range hint 82-127: Reduce repeated code

All these event handlers do the same check. Let's create a helper method:

+ private boolean isLockerPosition(Position position) {
+     return this.cache.get(position).isPresent();
+ }

  @EventHandler
  public void onBlockBurn(BlockBurnEvent event) {
      Position position = PositionAdapter.convert(event.getBlock().getLocation());
-     if (this.cache.get(position).isPresent()) {
+     if (isLockerPosition(position)) {
          event.setCancelled(true);
      }
  }
♻️ Duplicate comments (2)
src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryOrmLite.java (1)

104-108: 🛠️ Refactor suggestion

Update cache atomically in updateCaches()

Clearing and repopulating the cache asynchronously can lead to inconsistent reads. Consider updating the cache atomically.

src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (1)

121-123: 🧹 Nitpick (assertive)

Handle database connection failures without stopping the plugin

Throwing a RuntimeException stops the plugin if the database connection fails. Maybe catch the exception and allow the plugin to keep running, even if some features won't work.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 441acd6 and 0507635.

📒 Files selected for processing (11)
  • src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (8 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/argument/ParcelLockerArgument.java (2 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/controller/LockerBreakController.java (8 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/controller/LockerInteractionController.java (3 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerCache.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/command/argument/ParcelArgument.java (2 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelCache.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepository.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepositoryOrmLite.java (1 hunks)
🔇 Additional comments (15)
src/main/java/com/eternalcode/parcellockers/locker/controller/LockerInteractionController.java (4)

4-4: Import updated to LockerCache


18-18: Nice switch to use LockerCache


21-22: Constructor adjusted appropriately


39-39: Cache check updated nicely

src/main/java/com/eternalcode/parcellockers/locker/repository/LockerCache.java (1)

14-15: Good choice using ConcurrentHashMap!

Using thread-safe maps is perfect for handling multiple requests at once.

src/main/java/com/eternalcode/parcellockers/locker/argument/ParcelLockerArgument.java (3)

13-15: Looking good!

The switch to LockerCache makes sense and follows the PR's goal of improving data access.


17-19: Nice and clean!

The constructor is simple and does its job well.


Line range hint 1-12: Check for consistent cache usage across the project

Let's make sure other classes are also using LockerCache consistently.

✅ Verification successful

All good! The cache and repository are working together as intended

The code shows a proper setup where LockerCache complements LockerRepository instead of replacing it. This is exactly how it should work! 🎯

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining LockerRepository usage
rg "LockerRepository" -l

# Search for LockerCache usage
rg "LockerCache" -l

Length of output: 1863


Script:

#!/bin/bash
# Check content of files containing both
echo "=== ParcelLockers.java ==="
rg "LockerRepository|LockerCache" src/main/java/com/eternalcode/parcellockers/ParcelLockers.java -B 1 -A 1

echo -e "\n=== LockerBreakController.java ==="
rg "LockerRepository|LockerCache" src/main/java/com/eternalcode/parcellockers/locker/controller/LockerBreakController.java -B 1 -A 1

echo -e "\n=== LockerRepositoryOrmLite.java ==="
rg "LockerRepository|LockerCache" src/main/java/com/eternalcode/parcellockers/locker/repository/LockerRepositoryOrmLite.java -B 1 -A 1

Length of output: 2144

src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (1)

213-213: Check the version support logic

You're warning about supported versions from 1.17.x to 1.21.x, but the code only checks for version 17. Consider updating the check to cover the entire range.

src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepository.java (2)

15-15: The addition of findAll() looks good!

Adding findAll() enhances parcel retrieval options.


23-25: Changing return types of remove methods seems appropriate.

Switching to return CompletableFuture<Integer> allows for tracking the number of parcels removed.

src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelRepositoryOrmLite.java (1)

34-35: Consider replacing ex.printStackTrace() with proper logging.

Using ex.printStackTrace() may clutter the console.

src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelCache.java (1)

1-38: The ParcelCache implementation looks good!

This class provides efficient caching of parcels.

src/main/java/com/eternalcode/parcellockers/parcel/command/argument/ParcelArgument.java (2)

4-4: LGTM! Clean import additions.

The new imports support the cache-based implementation nicely.

Also applies to: 14-14


19-22: Nice and clean dependency injection!

The switch to ParcelCache is implemented well with proper constructor injection.

Copy link
Contributor

@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: 1

♻️ Duplicate comments (1)
src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (1)

60-62: ⚠️ Potential issue

Fix data loss in toParcel() method.

The toParcel() method is losing data by only using the sender as the allowed sender. We need to store and restore all allowed senders.

Add a field to store all allowed senders:

+    @DatabaseField(columnName = "allowed_senders")
+    private String allowedSenders;  // Store as comma-separated UUIDs

     Parcel toParcel() {
-        return new Parcel(this.uuid, this.sender, this.name, this.description, this.priority, Set.of(this.sender), this.receiver, this.size, this.entryLocker, this.destinationLocker);
+        Set<UUID> allowedSenderSet = Arrays.stream(this.allowedSenders.split(","))
+            .map(UUID::fromString)
+            .collect(Collectors.toSet());
+        return new Parcel(this.uuid, this.sender, this.name, this.description, this.priority, allowedSenderSet, this.receiver, this.size, this.entryLocker, this.destinationLocker);
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0507635 and d62297e.

📒 Files selected for processing (1)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (1 hunks)
🔇 Additional comments (2)
src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (2)

1-12: Looking good! Clean class setup.

The class structure and annotations are well-organized.


41-54: Perfect constructor setup!

Both the no-args constructor (required by ORMLite) and the full constructor are properly implemented.

Jakubk15 and others added 8 commits January 15, 2025 20:48
…ParcelWrapper.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…/PositionPersister.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…/PositionPersister.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…/ParcelContentRepositoryOrmLite.java

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@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: 7

♻️ Duplicate comments (3)
src/main/java/com/eternalcode/parcellockers/locker/argument/ParcelLockerArgument.java (1)

32-37: 🧹 Nitpick (assertive)

Consider caching the suggestions for better performance.

Since locker descriptions don't change often, we could avoid creating new streams each time.

src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryOrmLite.java (2)

29-31: 🧹 Nitpick (assertive)

Consider returning the saved ParcelContent

Returning the saved ParcelContent might be useful for future operations.


39-41: ⚠️ Potential issue

Watch out for a null pointer exception

If parcelContentWrapper is null, calling toParcelContent() could cause an exception. Let's handle this safely.

Here's a suggestion to fix it:

 return this.select(ParcelContentWrapper.class, uniqueId)
-    .thenApply(parcelContentWrapper -> Optional.ofNullable(parcelContentWrapper.toParcelContent()));
+    .thenApply(parcelContentWrapper -> {
+        if (parcelContentWrapper == null) {
+            return Optional.empty();
+        } else {
+            return Optional.of(parcelContentWrapper.toParcelContent());
+        }
+    });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d62297e and defdc12.

📒 Files selected for processing (9)
  • src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (8 hunks)
  • src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryOrmLite.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/database/persister/PositionPersister.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/locker/argument/ParcelLockerArgument.java (2 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/command/argument/ParcelArgument.java (2 hunks)
  • src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (1 hunks)
  • src/main/java/com/eternalcode/parcellockers/user/repository/UserWrapper.java (1 hunks)
  • src/test/java/com/eternalcode/parcellockers/database/ParcelDatabaseServiceIntegrationTest.java (2 hunks)
  • src/test/java/com/eternalcode/parcellockers/database/ParcelLockerDatabaseServiceIntegrationTest.java (3 hunks)
🧰 Additional context used
📓 Learnings (1)
src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (1)
Learnt from: Jakubk15
PR: EternalCodeTeam/ParcelLockers#116
File: src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java:59-61
Timestamp: 2025-01-15T20:13:38.696Z
Learning: The ParcelWrapper class currently only stores a single sender, while the Parcel class supports multiple allowed senders. This limitation will be addressed in a future PR.
🔇 Additional comments (17)
src/main/java/com/eternalcode/parcellockers/locker/argument/ParcelLockerArgument.java (4)

Line range hint 1-11: Nice package restructuring!

The move to locker.argument package makes more sense with the new database design.


13-15: Good field update!

The switch to LockerCache aligns well with the new caching strategy.


17-19: Clean constructor update!

The constructor properly initializes the cache field.


22-28: Great job implementing the suggested improvements!

The parse method looks cleaner with the map(ParseResult::success) approach.

src/main/java/com/eternalcode/parcellockers/user/repository/UserWrapper.java (4)

9-10: Consider making the class public and the table name configurable.

The class might need to be accessed from other packages, and the table name could be made configurable for different environments.


18-24: Add constructor validation and documentation.

The default constructor needs documentation explaining it's for ORMLite, and the parameterized constructor should validate its inputs.


26-36: Add validation to conversion methods.

The conversion methods need null checks and validation.


15-16: 🧹 Nitpick (assertive)

Add length validation for username.

Consider adding a maximum length limit to prevent overly long usernames.

-    @DatabaseField(index = true, unique = true, canBeNull = false)
+    @DatabaseField(index = true, unique = true, canBeNull = false, width = 32)
     private String username;

Likely invalid or redundant comment.

src/main/java/com/eternalcode/parcellockers/parcel/command/argument/ParcelArgument.java (2)

27-34: Good job handling invalid UUID inputs.


39-41: Consider renaming cache.cache() to improve clarity.

src/main/java/com/eternalcode/parcellockers/content/repository/ParcelContentRepositoryOrmLite.java (1)

20-25: Nice exception handling

Good job capturing exceptions with Sentry and throwing a RuntimeException to handle critical errors.

src/main/java/com/eternalcode/parcellockers/ParcelLockers.java (1)

190-192: Ensure databaseManager is properly initialized before disconnecting

Since databaseManager might not have been assigned to the class variable, calling this.databaseManager.disconnect(); could lead to a NullPointerException. After assigning it correctly in the onEnable method, this issue will be resolved.

src/main/java/com/eternalcode/parcellockers/database/persister/PositionPersister.java (2)

24-26: Add a null check for javaObject in javaToSqlArg

Adding a null check here can prevent potential NullPointerException if javaObject is null.


25-32: Handle special characters in worldName during serialization

If worldName contains '/', it could cause issues when deserializing. Consider escaping special characters or using a different serialization format like JSON.

src/test/java/com/eternalcode/parcellockers/database/ParcelLockerDatabaseServiceIntegrationTest.java (1)

75-78: 🧹 Nitpick (assertive)

Let's check if databaseManager is not null before disconnecting to avoid any issues.

Apply this diff:

     @AfterEach
     void tearDown() {
-        databaseManager.disconnect();
+        if (databaseManager != null) {
+            databaseManager.disconnect();
+        }
     }

Likely invalid or redundant comment.

src/main/java/com/eternalcode/parcellockers/parcel/repository/ParcelWrapper.java (2)

14-39: Field declarations look great!

Good job adding indexes on frequently queried fields. The field names and types are clear and appropriate.


59-61: 🧹 Nitpick (assertive)

Add a TODO comment about the multiple senders limitation.

Based on the retrieved learnings, this is a known limitation that will be addressed in a future PR.

+    // TODO: Support multiple senders in a future PR - currently only stores the primary sender
     Parcel toParcel() {

Likely invalid or redundant comment.

coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 15, 2025
@Jakubk15 Jakubk15 merged commit 989315d into master Jan 15, 2025
1 check passed
@Jakubk15 Jakubk15 deleted the ormlite-jdbc branch January 15, 2025 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🆕 feature New feature or request 🛠️ maintainers task This task will be handled by EternalCodeTeam Maintainers, please do not PR.
Projects
Status: ✅ Done
Development

Successfully merging this pull request may close these issues.

Rewrite database to ORMLite JDBC
4 participants