Null equivalence - Fix (#16050)

@charlesBochet 
In workflow codebase, NULL (instead of empty object) is expected on
workflow version object step field, when a new workflow is created for
example.
(packages/twenty-front/src/modules/workflow/workflow-diagram/utils/generateWorkflowDiagram.ts
- 42)
This case is not isolated and it creates many issues.

We decided to format NULL value to equivalent (empty string for text
field, empty object for raw_json) but it seems it complicates the dev x.

To unlock @Devessier I prefer revert the logic, the time we discuss how
to solve this cases.
This commit is contained in:
Etienne
2025-11-25 14:07:32 +01:00
committed by GitHub
parent ab3d48383b
commit 2028a8f9be
5 changed files with 10 additions and 19 deletions
@@ -10,7 +10,6 @@ import { isDefined } from 'twenty-shared/utils';
import {
DEFAULT_ARRAY_FIELD_NULL_EQUIVALENT_VALUE,
DEFAULT_COMPOSITE_FIELDS_NULL_EQUIVALENT_VALUE,
DEFAULT_RAW_JSON_FIELD_NULL_EQUIVALENT_VALUE,
DEFAULT_TEXT_FIELD_NULL_EQUIVALENT_VALUE,
} from 'src/engine/api/common/common-args-processors/data-arg-processor/constants/null-equivalent-values.constant';
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
@@ -199,10 +198,6 @@ function formatFieldMetadataValue(
return DEFAULT_ARRAY_FIELD_NULL_EQUIVALENT_VALUE;
}
if (fieldMetadataType === FieldMetadataType.RAW_JSON) {
return DEFAULT_RAW_JSON_FIELD_NULL_EQUIVALENT_VALUE;
}
if (fieldMetadataType === FieldMetadataType.TEXT) {
return DEFAULT_TEXT_FIELD_NULL_EQUIVALENT_VALUE;
}
@@ -1,10 +1,10 @@
import { msg } from '@lingui/core/macro';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import {
ActorMetadata,
FieldMetadataType,
RelationOnDeleteAction,
ActorMetadata,
} from 'twenty-shared/types';
import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
@@ -85,7 +85,8 @@ export class WorkflowWorkspaceEntity extends BaseWorkspaceEntity {
description: msg`The workflow name`,
icon: 'IconSettingsAutomation',
})
name: string;
@WorkspaceIsNullable()
name: string | null;
@WorkspaceField({
standardId: WORKFLOW_STANDARD_FIELD_IDS.lastPublishedVersionId,
@@ -1,8 +1,8 @@
import { Scope } from '@nestjs/common';
import { isDefined } from 'class-validator';
import isEmpty from 'lodash.isempty';
import { FieldActorSource } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
@@ -1,6 +1,7 @@
import { type FieldMetadataTypesToTestForCreateInputValidation } from 'test/integration/graphql/suites/inputs-validation/types/field-metadata-type-to-test';
import { TEST_TARGET_OBJECT_RECORD_ID_FIELD_VALUE } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
import { isEmptyObject } from 'twenty-shared/utils';
export const successfulCreateInputByFieldMetadataType: {
[K in Exclude<
@@ -134,10 +135,7 @@ export const successfulCreateInputByFieldMetadataType: {
rawJsonField: {},
},
validateInput: (record: Record<string, any>) => {
return (
typeof record.rawJsonField === 'object' &&
Object.keys(record.rawJsonField).length === 0
);
return isEmptyObject(record.rawJsonField);
},
},
{
@@ -145,10 +143,7 @@ export const successfulCreateInputByFieldMetadataType: {
rawJsonField: null,
},
validateInput: (record: Record<string, any>) => {
return (
typeof record.rawJsonField === 'object' &&
Object.keys(record.rawJsonField).length === 0
);
return record.rawJsonField === null;
},
},
{
@@ -4,7 +4,7 @@ import {
TEST_UUID_FIELD_VALUE,
} from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined, isEmptyObject } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
export const successfulFilterInputByFieldMetadataType: {
[K in FieldMetadataTypesToTestForFilterInputValidation]: {
@@ -895,7 +895,7 @@ export const successfulFilterInputByFieldMetadataType: {
gqlFilterInput: { rawJsonField: { is: 'NULL' } },
restFilterInput: 'rawJsonField[is]:NULL',
validateFilter: (record: Record<string, any>) => {
return isEmptyObject(record.rawJsonField);
return record.rawJsonField === null;
},
},
{