V2 centralize relation optimistic logic (#15552)
# Introduction
This PR aims to deprecate having to manually handle optimistic side
effect foreign key addition in the whole v2 experience.
This PR implements the strong basis + builder refactor of the optimistic
computation of a given flat entity maps with its related flat entity
maps ( runner needs a small refactor on actions type definition first )
Flat entity maps updates through mutations are now only scoped to the
generic entity builder ( very isolated )
## What's next
- Refactor actions v2 type definition to gain grain over `metadataName`
and action operation ( `create` `delete` `update` ).
from `{type: 'create_view_field'}` to `{metadataName: 'view_field',
type: 'create' }`
- Use new optimistic tool computation tools
- Only invalidate impacted flat maps cache
## New tools
Strictly dynamically typed new flat entity maps tools
- `addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow`
-
`deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrow`
## Unit test
Adding basic unit testing coverage to introduced tools
## `FlatEntityValidationArgs`
From
```ts
export type FlatEntityValidationArgs<T extends AllMetadataName> = {
flatEntityToValidate: MetadataFlatEntity<T>;
optimisticFlatEntityMaps: MetadataFlatEntityMaps<T>;
mutableDependencyOptimisticFlatEntityMaps: MetadataValidationRelatedFlatEntityMaps<T>;
workspaceId: string;
remainingFlatEntityMapsToValidate: MetadataFlatEntityMaps<T>;
buildOptions: WorkspaceMigrationBuilderOptions;
};
```
To
```ts
export type FlatEntityValidationArgs<T extends AllMetadataName> = {
flatEntityToValidate: MetadataFlatEntity<T>;
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: MetadataFlatEntityAndRelatedFlatEntityMapsForValidation<T>;
workspaceId: string;
remainingFlatEntityMapsToValidate: MetadataFlatEntityMaps<T>;
buildOptions: WorkspaceMigrationBuilderOptions;
};
```
This commit is contained in:
+64
-16
@@ -2,6 +2,7 @@ import { type AllMetadataName } from 'twenty-shared/metadata';
|
||||
import { type ExtractPropertiesThatEndsWithId } from 'twenty-shared/types';
|
||||
|
||||
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
|
||||
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
|
||||
|
||||
type ExtractEntityRelations<TEntity extends MetadataEntity<AllMetadataName>> = {
|
||||
[K in ExtractPropertiesThatEndsWithId<TEntity, 'id' | 'workspaceId'>]: K;
|
||||
@@ -11,46 +12,93 @@ type MetadataRelatedMetadataNames<T extends AllMetadataName> =
|
||||
keyof ExtractEntityRelations<MetadataEntity<T>>;
|
||||
|
||||
type MetadataNameAndRelations = {
|
||||
[T in AllMetadataName]: MetadataRelatedMetadataNames<T> extends never
|
||||
[TSourceMetadataName in AllMetadataName]: MetadataRelatedMetadataNames<TSourceMetadataName> extends never
|
||||
? Record<string, never>
|
||||
: {
|
||||
[P in MetadataRelatedMetadataNames<T>]?: AllMetadataName;
|
||||
[K in MetadataRelatedMetadataNames<TSourceMetadataName>]?: {
|
||||
[TTargetMetadataName in AllMetadataName]?: {
|
||||
metadataName: TTargetMetadataName;
|
||||
flatEntityForeignKeyAggregator: keyof MetadataFlatEntity<TTargetMetadataName>;
|
||||
};
|
||||
}[AllMetadataName];
|
||||
};
|
||||
};
|
||||
|
||||
export const ALL_METADATA_RELATED_METADATA_BY_FOREIGN_KEY = {
|
||||
fieldMetadata: {
|
||||
objectMetadataId: 'objectMetadata',
|
||||
objectMetadataId: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'fieldMetadataIds',
|
||||
},
|
||||
},
|
||||
objectMetadata: {},
|
||||
view: {
|
||||
kanbanAggregateOperationFieldMetadataId: 'fieldMetadata',
|
||||
calendarFieldMetadataId: 'fieldMetadata',
|
||||
objectMetadataId: 'objectMetadata',
|
||||
kanbanAggregateOperationFieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'kanbanAggregateOperationViewIds',
|
||||
},
|
||||
calendarFieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'calendarViewIds',
|
||||
},
|
||||
objectMetadataId: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewIds',
|
||||
},
|
||||
},
|
||||
viewField: {
|
||||
viewId: 'view',
|
||||
fieldMetadataId: 'fieldMetadata',
|
||||
viewId: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFieldIds',
|
||||
},
|
||||
fieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewFieldIds',
|
||||
},
|
||||
},
|
||||
viewGroup: {
|
||||
viewId: 'view',
|
||||
fieldMetadataId: 'fieldMetadata',
|
||||
viewId: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewGroupIds',
|
||||
},
|
||||
fieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewGroupIds',
|
||||
},
|
||||
},
|
||||
index: {
|
||||
objectMetadataId: 'objectMetadata',
|
||||
objectMetadataId: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'indexMetadataIds',
|
||||
},
|
||||
},
|
||||
serverlessFunction: {},
|
||||
cronTrigger: {
|
||||
serverlessFunctionId: 'serverlessFunction',
|
||||
serverlessFunctionId: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'cronTriggerIds',
|
||||
},
|
||||
},
|
||||
databaseEventTrigger: {
|
||||
serverlessFunctionId: 'serverlessFunction',
|
||||
serverlessFunctionId: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'databaseEventTriggerIds',
|
||||
},
|
||||
},
|
||||
routeTrigger: {
|
||||
serverlessFunctionId: 'serverlessFunction',
|
||||
serverlessFunctionId: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'routeTriggerIds',
|
||||
},
|
||||
},
|
||||
viewFilter: {
|
||||
viewId: 'view',
|
||||
fieldMetadataId: 'fieldMetadata',
|
||||
viewId: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterIds',
|
||||
},
|
||||
fieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterIds',
|
||||
},
|
||||
},
|
||||
} as const satisfies MetadataNameAndRelations;
|
||||
|
||||
Reference in New Issue
Block a user