Skip to content

Conversation

cr0ss
Copy link
Member

@cr0ss cr0ss commented Oct 17, 2025

Summary by CodeRabbit

  • Refactor
    • Enhanced category migration system to support multiple target categories from a single source.
    • Improved preference document handling with better logging and batch processing capabilities.

Copy link

coderabbitai bot commented Oct 17, 2025

Walkthrough

Refactored migration logic to support split category scenarios where one source category maps to multiple target categories. Migration now uses grouped mapping approach, updates the primary category on the original document, and creates new preference documents for additional target categories with batch writing.

Changes

Cohort / File(s) Summary
Migration Service Enhancement
CategoryMigrationLambda/Services/CategoryMigrationService.cs
Introduces grouped migration via MigrateCategoryAndSubcategoriesGrouped to handle multiple target categories per source. Primary group updates original document; additional groups trigger creation of new preference documents via CreateNewPreferenceDocument. Adds batch handling for new document writes, document identifier generation (EntityId/SK/Gsi1SK), timestamp updates, subcategory deduplication and sorting, and enhanced logging for migration details and new document creation. Refactors internal helpers for backward compatibility.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Linked Issues Check ❓ Inconclusive The linked issue RISE-3309 requests definition and documentation of cases for split category migrations (such as Dev -> Dev + Sales). The code changes implement the core functionality to support these split migrations by introducing MigrateCategoryAndSubcategoriesGrouped, CreateNewPreferenceDocument, and batch handling for multiple target categories. However, the raw summary and PR description do not clearly indicate whether the cases have been formally defined or documented (for example, through test cases, design documentation, or requirement specifications that enumerate specific migration scenarios). The implementation appears to support the feature, but verification of complete case coverage is unclear. To conclusively validate this check, confirm whether the issue requirements included documentation or definition of specific migration cases and whether test cases or documentation were added to verify coverage of scenarios like Dev -> Dev + Sales.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Split migrations" directly aligns with the main functionality being added. The raw summary confirms that the changes replace single-mapping migration calls with grouped migrations, enabling multiple target categories from one source, and create additional new preference documents for extra groups. This is a clear, concise title that accurately reflects the primary change without unnecessary noise or vagueness.
Out of Scope Changes Check ✅ Passed The changes are limited to CategoryMigrationLambda/Services/CategoryMigrationService.cs and focus on refactoring the migration logic to support split migrations: introducing MigrateCategoryAndSubcategoriesGrouped, CreateNewPreferenceDocument for handling multiple target groups, batch document writing, timestamp updates, and subcategory deduplication/sorting. All these modifications directly support the objective of enabling split category migrations as described in RISE-3309. No changes to public exported entities were introduced, and all modifications appear directly related to the split migrations feature scope.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/RISE-3309

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
CategoryMigrationLambda/Services/CategoryMigrationService.cs (1)

334-389: LGTM! New document creation logic is well-structured.

The method correctly clones the original document, generates a new unique EntityId, updates the necessary key fields (SK, Gsi1SK), and sets appropriate timestamps. The defensive check for IsPrimary (lines 380-383) is good practice.

Optional: Consider more explicit SK parsing.

Line 355 uses string replacement to update the EntityId in the SK. While this should be safe given the documented format ENTITYID#{EntityId} and GUID-based EntityIds, you could make it more explicit:

// More explicit parsing (optional)
if (originalDocument.ContainsKey("SK"))
{
    newDocument["SK"] = $"ENTITYID#{newEntityId}";
}

This assumes the SK format is always exactly ENTITYID#{EntityId} without additional segments.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 17d883c and 32edb41.

📒 Files selected for processing (1)
  • CategoryMigrationLambda/Services/CategoryMigrationService.cs (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{cs,cshtml}

⚙️ CodeRabbit configuration file

**/*.{cs,cshtml}: For any public or protected asynchronous method name that does not end in "Async", suggest changing the name to end in "Async".
Recommend using "await" instead of "Result" when calling asynchronous methods.

When HttpClient is used, verify that it is injected and not created manually. When HttpRequestMessage or HttpResponseMessage is used, verify that they are disposed correctly.

When DynamoDbClient is used, verify that it is injected or created by IDataClientFactory and not created manually. Also verify that the DynamoDbClient is disposed correctly since it implements IDisposable.

Files:

  • CategoryMigrationLambda/Services/CategoryMigrationService.cs
🧬 Code graph analysis (1)
CategoryMigrationLambda/Services/CategoryMigrationService.cs (1)
CategoryMigrationLambda/Services/CategoryMappings.cs (1)
  • CategoryMappings (6-77)
🔇 Additional comments (5)
CategoryMigrationLambda/Services/CategoryMigrationService.cs (5)

210-218: LGTM! Good defensive check for empty migrations.

The code appropriately handles the case where no valid migration mappings are found by logging a warning and skipping the document.


220-246: LGTM! Primary category migration logic is correct.

The code correctly uses the first grouped migration as the primary category to update the existing preference document, with appropriate logging.


402-404: LGTM! Timestamp update is appropriate.

Adding the UpdatedAt timestamp ensures proper tracking of when the migration was performed on each document.


407-479: LGTM! Grouped migration logic is well-designed.

The method correctly groups mappings by target category, handles null mappings appropriately (lines 438-442), and ensures clean data by deduplicating and sorting subcategories (lines 472-476). The fallback to category-only mapping when no subcategory mappings are found is a good safeguard.


481-490: LGTM! Backward compatibility maintained.

The refactoring correctly delegates to the grouped method while maintaining the original return signature by returning the first (primary) category mapping.

Comment on lines +248 to 282
// Handle additional categories (create new preferences)
if (groupedMigrations.Count > 1)
{
var additionalCategories = groupedMigrations.Skip(1);

foreach (var additionalCategory in additionalCategories)
{
var newCategoryId = additionalCategory.Key;
var newSubcategoryIds = additionalCategory.Value;

if (!result.DryRun)
{
// Create a new document (preference) for this additional category
var newDocument = CreateNewPreferenceDocument(document, newCategoryId, newSubcategoryIds);
batch.Add(newDocument);
}

result.MigratedCount++;

// Log the new preference creation
var newEntityId = !result.DryRun ? document["EntityId"].AsString() + "_split_" + newCategoryId : "(dry-run)";
if (userContext != null)
{
_logger.LogInformation("Created NEW preference {NewEntityId} for user {UserContext} from {OriginalEntityId}: CategoryId -> {NewCategoryId}, SubcategoryIds -> [{NewSubcategoryIds}]",
newEntityId, userContext, preference.EntityId, newCategoryId,
string.Join(",", newSubcategoryIds));
}
else
{
_logger.LogInformation("Created NEW preference {NewEntityId} from {OriginalEntityId}: CategoryId -> {NewCategoryId}, SubcategoryIds -> [{NewSubcategoryIds}]",
newEntityId, preference.EntityId, newCategoryId,
string.Join(",", newSubcategoryIds));
}
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix incorrect EntityId in log messages.

The logged newEntityId on line 268 doesn't match the actual EntityId created in CreateNewPreferenceDocument. Line 268 constructs a descriptive string (originalId_split_categoryId), but CreateNewPreferenceDocument generates a completely new GUID (line 346). This makes the logs misleading and could hinder debugging.

Apply this diff to log the actual EntityId:

                                if (!result.DryRun)
                                {
                                    // Create a new document (preference) for this additional category
                                    var newDocument = CreateNewPreferenceDocument(document, newCategoryId, newSubcategoryIds);
                                    batch.Add(newDocument);
+                                   var newEntityId = newDocument["EntityId"].AsString();
-                                   var newEntityId = !result.DryRun ? document["EntityId"].AsString() + "_split_" + newCategoryId : "(dry-run)";
                                    if (userContext != null)
                                    {
                                        _logger.LogInformation("Created NEW preference {NewEntityId} for user {UserContext} from {OriginalEntityId}: CategoryId -> {NewCategoryId}, SubcategoryIds -> [{NewSubcategoryIds}]",
                                            newEntityId, userContext, preference.EntityId, newCategoryId,
                                            string.Join(",", newSubcategoryIds));
                                    }
                                    else
                                    {
                                        _logger.LogInformation("Created NEW preference {NewEntityId} from {OriginalEntityId}: CategoryId -> {NewCategoryId}, SubcategoryIds -> [{NewSubcategoryIds}]",
                                            newEntityId, preference.EntityId, newCategoryId,
                                            string.Join(",", newSubcategoryIds));
                                    }
+                               }
+                               else
+                               {
+                                   var newEntityId = "(dry-run)";
+                                   if (userContext != null)
+                                   {
+                                       _logger.LogInformation("Would create NEW preference for user {UserContext} from {OriginalEntityId}: CategoryId -> {NewCategoryId}, SubcategoryIds -> [{NewSubcategoryIds}]",
+                                           userContext, preference.EntityId, newCategoryId,
+                                           string.Join(",", newSubcategoryIds));
+                                   }
+                                   else
+                                   {
+                                       _logger.LogInformation("Would create NEW preference from {OriginalEntityId}: CategoryId -> {NewCategoryId}, SubcategoryIds -> [{NewSubcategoryIds}]",
+                                           preference.EntityId, newCategoryId,
+                                           string.Join(",", newSubcategoryIds));
+                                   }
                                }

Committable suggestion skipped: line range outside the PR's diff.

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.

1 participant