twenty
twenty copied to clipboard
migration for Custom Objects
Before working on migration of timeline activites, we need to work on this project first.
There are two main feature to develop
- updateOne of a Relation that involves a CustomObject, because the nameSingular needs to be updated in the fieldMetadata
- nameSingular and namePlural must be provided since they are necessary for morph name computation
- label sync should be false
- updateOne on a morph relation: inside a morph relation, we need to be able to add or remove targets objects. using the updateOne from fieldMetadata sounds a great idea but we want to have a dedicated fieldMetadataupdateMorphInput that will take the morphId instead of the id
We will handle 2. in a second PR for better clarity
Interesting files to look at:
-
packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts
-
UPDATE => packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/rename-related-morph-field-on-object-names-update.util.ts ( also update relation indexes ) needs v2 refactor to handle field relation name update
-
CREATE => packages/twenty-server/src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util.ts ( handle morph instead of previous classic relation )
-
DELETE => DONE
🚀 Preview Environment Ready!
Your preview environment is available at: http://bore.pub:15583
This environment will automatically shut down when the PR is closed or after 5 hours.
Closing for now, let's re-open when ready :)
Greptile Overview
Greptile Summary
This PR implements proper handling of field metadata name updates when custom objects are renamed, particularly for morph relations. The changes ensure that when an object's nameSingular or namePlural is updated, all related morph relation field names, join column names, and indexes are correctly recomputed and updated.
Key Changes
- Created new utility
compute-flat-field-to-update-and-related-flat-field-to-update.util.tsto handle propagation of field updates to sibling morph relations and target relation fields - Enhanced
rename-related-morph-field-on-object-names-update.util.tsto properly handle index updates alongside field name changes - Modified
update-field-action-handler.service.tsto handle join column renames during workspace migrations - Added constants defining which properties are editable on sibling fields during morph relation updates
- Significantly expanded test coverage for both field updates and object renames with morph relations
Technical Implementation
The PR introduces a sophisticated system for cascading updates:
- When a morph relation field is updated, changes propagate to all sibling morph fields and their target relation fields
- When an object is renamed, all morph fields pointing to it are recomputed with new names
- Join column names are automatically updated to match new field names
- Related indexes are found and recomputed to reflect name changes
The implementation properly distinguishes between standard and custom fields, applying different property update rules for each.
Confidence Score: 4/5
- This PR is safe to merge with comprehensive test coverage, though the complexity of the changes warrants careful monitoring in production
- Score reflects well-structured implementation with extensive test coverage (245+ lines of new tests), but the high complexity of cascading updates across morph relations, indexes, and views introduces some risk. The refactoring extracts logic into reusable utilities which improves maintainability. Previous style comments have been addressed.
- Pay close attention to
rename-related-morph-field-on-object-names-update.util.tsas it handles critical index recomputation logic
Important Files Changed
File Analysis
| Filename | Score | Overview |
|---|---|---|
| packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/rename-related-morph-field-on-object-names-update.util.ts | 4/5 | Enhanced to handle index updates when morph field names change during object rename, now properly recomputes and updates related indexes |
| packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/compute-flat-field-to-update-and-related-flat-field-to-update.util.ts | 5/5 | New utility that computes field updates for morph relations and standard relations, propagating changes to sibling fields with appropriate property filtering |
| packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-update-field-input-to-flat-field-metadata.util.ts | 5/5 | Refactored to use new compute-flat-field-to-update util, handling field updates with side effects for views, indexes, and related fields |
| packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-runner-v2/action-handlers/field/services/update-field-action-handler.service.ts | 4/5 | Enhanced to handle join column name updates for morph/relation fields during workspace migrations, properly renaming database columns |
Sequence Diagram
sequenceDiagram
participant Client
participant UpdateFieldResolver
participant fromUpdateFieldInput
participant computeFlatField
participant sanitizeInput
participant handleSideEffect
participant UpdateFieldHandler
participant Database
alt Object Name Update
Client->>UpdateFieldResolver: Update Object (nameSingular/namePlural)
UpdateFieldResolver->>handleSideEffect: handleFlatObjectMetadataUpdateSideEffect
handleSideEffect->>handleSideEffect: Check if nameSingular or namePlural changed
handleSideEffect->>renameRelatedMorph: renameRelatedMorphFieldOnObjectNamesUpdate
renameRelatedMorph->>renameRelatedMorph: Get all morph relations targeting this object
renameRelatedMorph->>renameRelatedMorph: For each morph field, compute new name
renameRelatedMorph->>renameRelatedMorph: Recompute join column names
renameRelatedMorph->>renameRelatedMorph: Find and update related indexes
renameRelatedMorph-->>handleSideEffect: morphFlatFieldMetadatasToUpdate, morphRelatedFlatIndexesToUpdate
handleSideEffect-->>UpdateFieldResolver: Updated fields and indexes
end
alt Field Metadata Update
Client->>UpdateFieldResolver: Update Field (label, description, etc.)
UpdateFieldResolver->>fromUpdateFieldInput: fromUpdateFieldInputToFlatFieldMetadata
fromUpdateFieldInput->>sanitizeInput: sanitizeRawUpdateFieldInput
sanitizeInput->>sanitizeInput: Extract editable properties
sanitizeInput->>sanitizeInput: Add UUIDs to options if present
sanitizeInput->>sanitizeInput: Handle standard overrides
sanitizeInput-->>fromUpdateFieldInput: sanitized input
fromUpdateFieldInput->>computeFlatField: computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate
alt RELATION field
computeFlatField->>computeFlatField: Find target relation field
computeFlatField->>computeFlatField: Merge updates using RELATION_EDITABLE_PROPERTIES
computeFlatField-->>fromUpdateFieldInput: field + 1 related field
else MORPH_RELATION field
computeFlatField->>computeFlatField: Find all sibling morph fields
computeFlatField->>computeFlatField: Find all target relation fields
computeFlatField->>computeFlatField: Update morph siblings using MORPH_RELATION_EDITABLE_PROPERTIES
computeFlatField->>computeFlatField: Update relation targets using RELATION_EDITABLE_PROPERTIES
computeFlatField-->>fromUpdateFieldInput: field + multiple related fields
else Other field types
computeFlatField-->>fromUpdateFieldInput: field only
end
fromUpdateFieldInput->>handleSideEffect: For each field, handleFlatFieldMetadataUpdateSideEffect
handleSideEffect->>handleSideEffect: Update indexes if name changed
handleSideEffect->>handleSideEffect: Update view filters/groups/fields
handleSideEffect-->>fromUpdateFieldInput: Side effects (indexes, views, etc.)
fromUpdateFieldInput-->>UpdateFieldResolver: All fields to update + side effects
UpdateFieldResolver->>UpdateFieldHandler: Execute migration
UpdateFieldHandler->>UpdateFieldHandler: optimisticallyApplyActionOnAllFlatEntityMaps
UpdateFieldHandler->>Database: Update metadata tables
UpdateFieldHandler->>Database: Rename columns if joinColumnName changed
UpdateFieldHandler->>Database: Update indexes, views, etc.
UpdateFieldHandler-->>Client: Success
end
I faced a bug while trying to create a morph. I believe it's when you select the object itself as start and end of the morph, looks not related to this PR ==> looks actually legit on BE side (Morph relation creation payloads must not target source object metadata), we should just surface it better on FE
Error when trying to rename an object
seems related to this one!
@greptileai trigger
@charlesBochet it would be great to have a ~second~ third eye on this PR since @prastoin helped me a lot in the work I started on this topic.
cc: @Bonapara @FelixMalfait This PR allows custom relation field name update. We could update the frontend to allow doing so in a separate PR. Would this make sense for the product in advanced mode ? We could also allow label and name synchronization for relations fields too
ps: not join column name yet as unless i' mistaken @guillim is about to implement it ?
Great! Yes renaming relations is a frequent request and would be great to expose in the frontend (not in Advanced mode imo, it should be seamless ideally). @guillim could you please create a follow up issue if you are handling this to make sure we don't lose track of it? Thanks!
Great! Yes renaming relations is a frequent request and would be great to expose in the frontend (not in Advanced mode imo, it should be seamless ideally). @guillim could you please create a follow up issue if you are handling this to make sure we don't lose track of it? Thanks!
I will yes. I will include this "FE relation name edition" in the main issue about morph. Even though it is not directly related to morph, I will keep track of it and we will for sure keep this in the roadmap. Consider it done
Congrats! Reviewed and tested! Let's merge :)