common api - null equivalence (#15926)

closes https://github.com/twentyhq/core-team-issues/issues/1629

To do before requesting review : 
- filter update

Migration to come in an other PR


Strat : 
1/  Null transformation

- [x] Transform NULL equivalent value to NULL in field validation in
common api - pre-query - with feature flag
- [ ] Same logic in ORM (Not done, complex to handle feature flag here)
- [x] Transform NULL value to equivalent in data formatting in ORM -
post-query

2/ Migration (in other PR) for fieldMetadata not nullable with default
defaultValue (empty string, ...)

- [ ] Remove NOT NULL db constraint
- [ ] Update record value to NULL
- [ ] Update field metadata : isNullable:true
- [ ] Update uniqueIndex whereClause (also for standard uniqueIndex) 
- [ ] Activate feature flag

3/ Update metadata creation

- [x] No more default default value
- [x] Update standard field nullability
- [x] Remove index default whereClause for standard field

4/ Update filter

- [x] When filtering on NULL or empty string, be sure all records are
returned (the one with NULL + the one with "")

5/ Test

- [ ] Strat. to do
This commit is contained in:
Etienne
2025-11-24 18:57:47 +01:00
committed by GitHub
parent 3ed6d2a16b
commit 208c0857ee
59 changed files with 884 additions and 300 deletions
@@ -1,8 +1,8 @@
import { msg } from '@lingui/core/macro';
import {
ActorMetadata,
FieldMetadataType,
RelationOnDeleteAction,
ActorMetadata,
} from 'twenty-shared/types';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
@@ -68,6 +68,7 @@ export class AttachmentWorkspaceEntity extends BaseWorkspaceEntity {
description: msg`Attachment type (deprecated - use fileCategory)`,
icon: 'IconList',
})
@WorkspaceIsNullable()
type: string;
@WorkspaceField({
@@ -1,10 +1,10 @@
import { msg } from '@lingui/core/macro';
import {
FieldMetadataType,
RelationOnDeleteAction,
ActorMetadata,
AddressMetadata,
FieldMetadataType,
LinksMetadata,
RelationOnDeleteAction,
type CurrencyMetadata,
} from 'twenty-shared/types';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
@@ -30,8 +30,8 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re
import { COMPANY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
import {
type FieldTypeAndNameMetadata,
getTsVectorColumnExpressionFromFields,
type FieldTypeAndNameMetadata,
} from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity';
import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity';
@@ -71,6 +71,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
description: msg`The company name`,
icon: 'IconBuildingSkyscraper',
})
@WorkspaceIsNullable()
name: string;
@WorkspaceField({
@@ -84,6 +85,7 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
},
})
@WorkspaceIsUnique()
@WorkspaceIsNullable()
domainName: LinksMetadata;
@WorkspaceField({
@@ -1,8 +1,8 @@
import { msg } from '@lingui/core/macro';
import {
ActorMetadata,
FieldMetadataType,
RelationOnDeleteAction,
ActorMetadata,
type RichTextV2Metadata,
} from 'twenty-shared/types';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
@@ -71,6 +71,7 @@ export class NoteWorkspaceEntity extends BaseWorkspaceEntity {
description: msg`Note title`,
icon: 'IconNotes',
})
@WorkspaceIsNullable()
title: string;
@WorkspaceField({
@@ -1,9 +1,9 @@
import { msg } from '@lingui/core/macro';
import {
FieldMetadataType,
RelationOnDeleteAction,
ActorMetadata,
type CurrencyMetadata,
FieldMetadataType,
RelationOnDeleteAction,
} from 'twenty-shared/types';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
@@ -63,6 +63,7 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
description: msg`The opportunity name`,
icon: 'IconTargetArrow',
})
@WorkspaceIsNullable()
name: string;
@WorkspaceField({
@@ -1,10 +1,10 @@
import { msg } from '@lingui/core/macro';
import {
FieldMetadataType,
RelationOnDeleteAction,
ActorMetadata,
EmailsMetadata,
FieldMetadataType,
PhonesMetadata,
RelationOnDeleteAction,
type FullNameMetadata,
type LinksMetadata,
} from 'twenty-shared/types';
@@ -31,8 +31,8 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re
import { PERSON_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
import { STANDARD_OBJECT_ICONS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-icons';
import {
type FieldTypeAndNameMetadata,
getTsVectorColumnExpressionFromFields,
type FieldTypeAndNameMetadata,
} from 'src/engine/workspace-manager/workspace-sync-metadata/utils/get-ts-vector-column-expression.util';
import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity';
import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
@@ -96,6 +96,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
},
})
@WorkspaceIsUnique()
@WorkspaceIsNullable()
emails: EmailsMetadata;
@WorkspaceField({
@@ -125,6 +126,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
description: msg`Contacts job title`,
icon: 'IconBriefcase',
})
@WorkspaceIsNullable()
jobTitle: string;
@WorkspaceField({
@@ -147,6 +149,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
maxNumberOfValues: 1,
},
})
@WorkspaceIsNullable()
phones: PhonesMetadata;
@WorkspaceField({
@@ -156,6 +159,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
description: msg`Contacts city`,
icon: 'IconMap',
})
@WorkspaceIsNullable()
city: string;
@WorkspaceField({
@@ -166,6 +170,7 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
icon: 'IconFileUpload',
})
@WorkspaceIsSystem()
@WorkspaceIsNullable()
avatarUrl: string;
@WorkspaceField({
@@ -1,8 +1,8 @@
import { msg } from '@lingui/core/macro';
import {
ActorMetadata,
FieldMetadataType,
RelationOnDeleteAction,
ActorMetadata,
type RichTextV2Metadata,
} from 'twenty-shared/types';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
@@ -74,6 +74,7 @@ export class TaskWorkspaceEntity extends BaseWorkspaceEntity {
description: msg`Task title`,
icon: 'IconNotes',
})
@WorkspaceIsNullable()
title: string;
@WorkspaceField({