8000 fix: import with meta without creating new keys (#3000) by bdshadow · Pull Request #3113 · tolgee/tolgee-platform · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

fix: import with meta without creating new keys (#3000) #3113

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

Merged
merged 1 commit into from
Jun 16, 2025

Conversation

bdshadow
Copy link
Contributor
@bdshadow bdshadow commented Jun 9, 2025

When shouldImportKey is called in the FileProcessorContext.processTranslations() method, Hibernate does the flush before executing a select query. At this flush, it discovers that ImportKey has KeyMeta, which is newly created and needs to be flushed, however, there is no cascading.

So cadacding would be a good solution. It is also the first one which is recommended in many articles, e.g. https://www.baeldung.com/hibernate-unsaved-transient-instance-error, as well as cascading is usually (sure, not always) applied in OneToOne relations: https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/. But when I started applying cascading, I ended up modifying too many entities, which led to many unpredictable problems

So I think this solution of saving a KeyMeta alongside the ImportKey is a good compromise here.

Probably the test can be moved to a more suitable place. (I'm just getting acquainted with the code base). It can easily be replicated also with the strings.xml file mentioned in the comment

Summary by CodeRabbit

  • Tests
    • Added a new test case to verify import behavior when creating new keys is disabled.
    • Updated existing tests to include the new "createNewKeys" setting during import.
  • New Features
    • Improved handling of key metadata during import, ensuring author information is set correctly for comments and code references.
    • Enhanced import process to prepare and save key metadata individually for each key.
  • Bug Fixes
    • Fixed import of PO files with single key metadata when creating new keys is disabled.

Copy link
coderabbitai bot commented Jun 9, 2025

Walkthrough

A new boolean parameter, createNewKeys, was added to the import settings application logic and corresponding tests. Key metadata preparation and saving were shifted to a per-key basis during key creation, with a new method introduced for preparing individual key metadata. A new test and resource file were added for coverage.

Changes

File(s) Change Summary
.../ImportSettingsControllerApplicationTest.kt Added createNewKeys parameter to applySettings and all invocations; added a new test case using new resource.
.../simplePoWithSingleKeyMeta.po Added a new PO file resource with a single key and meta for testing.
.../CoreImportFilesProcessor.kt Injected KeyMetaService; moved key meta preparation and saving to per-key logic in getOrCreateKey.
.../ImportDataManager.kt Removed bulk key meta methods; added prepareKeyMeta(keyMeta) for individual key meta preparation.

Sequence Diagram(s)

sequenceDiagram
    participant Test as ImportSettingsControllerApplicationTest
    participant Processor as CoreImportFilesProcessor
    participant Manager as ImportDataManager
    participant KeyMetaService

    Test->>Processor: applySettings(..., createNewKeys)
    Processor->>Processor: getOrCreateKey()
    alt key has keyMeta
        Processor->>Manager: prepareKeyMeta(keyMeta)
        alt saving enabled
            Processor->>KeyMetaService: save(keyMeta)
        end
    end
    Processor->>Processor: save key
Loading

Poem

In the warren of code, a new path appears,
With createNewKeys toggled to calm import fears.
Each key’s little meta now gets special care,
Saved and prepared with a rabbit’s own flair.
New tests and new files, the coverage expands—
Hopping forward, improvements in gentle hands!
🐇✨


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9aa4bed and 8fee44e.

📒 Files selected for processing (4)
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImportController/importSettings/ImportSettingsControllerApplicationTest.kt (7 hunks)
  • backend/app/src/test/resources/import/po/simplePoWithSingleKeyMeta.po (1 hunks)
  • backend/data/src/main/kotlin/io/tolgee/service/dataImport/CoreImportFilesProcessor.kt (3 hunks)
  • backend/data/src/main/kotlin/io/tolgee/service/dataImport/ImportDataManager.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImportController/importSettings/ImportSettingsControllerApplicationTest.kt
  • backend/app/src/test/resources/import/po/simplePoWithSingleKeyMeta.po
  • backend/data/src/main/kotlin/io/tolgee/service/dataImport/CoreImportFilesProcessor.kt
  • backend/data/src/main/kotlin/io/tolgee/service/dataImport/ImportDataManager.kt
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @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.

Copy link
@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
backend/data/src/main/kotlin/io/tolgee/service/dataImport/ImportDataManager.kt (1)

217-220: Consider refactoring to eliminate code duplication.

The new prepareKeyMeta method duplicates the logic from prepareKeyMetas (lines 211-215). While this supports the per-key processing approach needed to fix the Hibernate flush issues, consider refactoring to eliminate duplication.

For example, you could refactor prepareKeyMetas to use the new method:

  fun prepareKeyMetas() {
-    this.storedKeys.mapNotNull { it.value.keyMeta }.forEach { meta ->
-      meta.comments.onEach { comment -> comment.author = comment.author ?: import.author }
-      meta.codeReferences.onEach { ref -> ref.author = ref.author ?: import.author }
-    }
+    this.storedKeys.mapNotNull { it.value.keyMeta }.forEach { meta ->
+      prepareKeyMeta(meta)
+    }
  }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c47e2b2 and ef4f2ac.

📒 Files selected for processing (4)
  • backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImportController/importSettings/ImportSettingsControllerApplicationTest.kt (7 hunks)
  • backend/app/src/test/resources/import/po/simplePoWithSingleKeyMeta.po (1 hunks)
  • backend/data/src/main/kotlin/io/tolgee/service/dataImport/CoreImportFilesProcessor.kt (3 hunks)
  • backend/data/src/main/kotlin/io/tolgee/service/dataImport/ImportDataManager.kt (1 hunks)
🔇 Additional comments (6)
backend/app/src/test/resources/import/po/simplePoWithSingleKeyMeta.po (1)

1-3: LGTM! Well-formatted PO test resource.

The PO file follows correct gettext format with a reference comment, message ID, and German translation. This appropriately supports the test case for importing keys with metadata.

backend/data/src/main/kotlin/io/tolgee/service/dataImport/CoreImportFilesProcessor.kt (2)

48-50: LGTM! Proper service injection.

The KeyMetaService injection is correctly implemented to support per-key metadata handling.


304-309: Good solution for Hibernate flush issues.

The per-key metadata preparation and saving correctly addresses the Hibernate flush problems mentioned in the PR objectives. While this approach may have performance implications compared to bulk operations, it's a justified trade-off to avoid the cascading complexity and "unsaved transient instance" errors.

The conditional saving based on saveData flag is properly handled.

backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ImportController/importSettings/ImportSettingsControllerApplicationTest.kt (3)

21-22: LGTM! Appropriate test resource addition.

The new test resource correctly supports the specific test case for importing with key metadata when createNewKeys=false.


129-139: Excellent test coverage for the GitHub issue.

The new test case specifically targets the scenario described in GitHub issue #3000, verifying that import works correctly when createNewKeys=false and the first key has metadata. This provides good coverage for the Hibernate flush fix.


195-208: Consistent parameter addition across test methods.

The createNewKeys parameter has been properly added to the applySettings method signature and all existing test calls have been updated consistently. The default true values maintain backward compatibility for existing tests.

@bdshadow bdshadow force-pushed the gh-3000 branch 3 times, most recently from d7dffc0 to c91768e Compare June 9, 2025 13:52
@@ -297,7 +301,9 @@ class CoreImportFilesProcessor(
this.keys.computeIfAbsent(name) {
ImportKey(name = name, this.fileEntity)
}.also {
it.keyMeta?.also { keyMeta -> importDataManager.prepareKeyMeta(keyMeta) }
Copy link
Contributor

Choose a reason for hiding this comment

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

I am afraid that these changes might affect performance. In the case of imports the performance is crucial because we are handling huge amount of saves. Are you sure this is fine?

It looks to me like we are saving key metas even if they are already exist, which might cost us some resources...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

repository.save method doesn't execute an updatequery if entity is not marked dirty. For example the following snippet doesn't issue "update" to db:

Optional<Entity> entity = reposRepository.findById(id);
entity.ifPresent(existingEntity -> {
            existingEntity.setUrl(existingEntity.getUrl());
            reposRepository.save(existingEntity);
            });

When saving keys, isn't it correct to save KeyMeta? What's done in the fix is actually just applying the cascading manually.

Regarding the performance, of course, it needs to be tested, but I suppose that it should not be affected since the number of requests to db must not change. Is there an example of a such huge files for imports?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i've added another change. Now it works correctly. I've tested it on the "example.po". This fix generates two additional "update" queries for key_meta. I will try to get rid of it. Meanwhile will move this pr do drafts

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks a lot! I believe I have separated all the saves to groups, so hibernate can execute the updates in single statement... However, I am not hibernate expert so if you are sure it's not harming the performance, we can merge it. However, it's a good idea to test it with some larger dataset like 10000 keys and see how fast it is.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, as stated in this article, it's not always that straightforward with the save() method. Read more in the "The redundant save anti-pattern" section. https://vladmihalcea.com/jpa-persist-and-merge/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@JanCizmar it's ready for review. Now, the number of queries to the database is the same as it was before, plus it fixes the issue.

It was not only about the save method, but more about the order of saving entities.

My opinion is that current mapping can lead to unexpected bugs like this. However, as they say, if you criticize, offer a solution :) I'm sure there is a reason behind such relations between entities, that I don't see at the moment. I will get more familiar with it and with the code in general. Then I'll be able to offer a solution... or will admit that it's ok :)

Copy link
Contributor

Choose a reason for hiding this comment

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

10000

OK, thanks a lot for the PR. I will merge it and let's see what happens.

@@ -312,10 +318,8 @@ class CoreImportFilesProcessor(
}
keyEntity.shouldBeImported = shouldImportKey(keyEntity.name)
}
importDataManager.prepareKeyMetas()
Copy link
Contributor

Choose a reason for hiding this comment

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

this methods are unused now, right? So they should be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

if (saveData) {
importDataManager.saveAllStoredKeys()
importDataManager.saveAllKeyMetas()
Copy link
Contributor

Choose a reason for hiding this comment

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

this methods are unused now, right? So they should be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@bdshadow bdshadow force-pushed the gh-3000 branch 2 times, most recently from 150d6d7 to 9aa4bed Compare June 9, 2025 21:48
@bdshadow bdshadow marked this pull request as draft June 9, 2025 21:54
Signed-off-by: dmitrii.bocharov <bdshadow@gmail.com>
@bdshadow bdshadow marked this pull request as ready for review June 12, 2025 11:13
@JanCizmar JanCizmar enabled auto-merge (squash) June 16, 2025 15:26
@JanCizmar JanCizmar disabled auto-merge June 16, 2025 17:23
@JanCizmar JanCizmar merged commit d266ce3 into tolgee:main Jun 16, 2025
31 checks passed
TolgeeMachine added a commit that referenced this pull request Jun 16, 2025
## [3.123.2](v3.123.1...v3.123.2) (2025-06-16)

### Bug Fixes

* import with meta without creating new keys  ([#3000](#3000)) ([#3113](#3113)) ([d266ce3](d266ce3)), closes [/github.com//issues/3000#issuecomment-2865753203](https://github.com//github.com/tolgee/tolgee-platform/issues/3000/issues/issuecomment-2865753203)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0