Null equivalence - remove feature flag (#16222)

This commit is contained in:
Etienne
2025-12-01 19:06:24 +01:00
committed by GitHub
parent da7536124e
commit 68c429a54a
23 changed files with 61 additions and 249 deletions
@@ -44,7 +44,6 @@ import {
CommonQueryRunnerExceptionCode,
} from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
import { transformEmailsValue } from 'src/engine/core-modules/record-transformer/utils/transform-emails-value.util';
@@ -85,12 +84,6 @@ export class DataArgProcessor {
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
const isNullEquivalenceEnabled =
await this.featureFlagService.isFeatureEnabled(
FeatureFlagKey.IS_NULL_EQUIVALENCE_ENABLED,
workspace.id,
);
const { fieldIdByName, fieldIdByJoinColumnName } =
buildFieldMapsFromFlatObjectMetadata(
flatFieldMetadataMaps,
@@ -141,7 +134,6 @@ export class DataArgProcessor {
fieldMetadata,
key,
value,
isNullEquivalenceEnabled,
);
}
processedRecords.push(processedRecord);
@@ -166,7 +158,6 @@ export class DataArgProcessor {
fieldMetadata: FlatFieldMetadata,
key: string,
value: unknown,
isNullEquivalenceEnabled: boolean,
): Promise<unknown> {
switch (fieldMetadata.type) {
case FieldMetadataType.POSITION:
@@ -182,7 +173,7 @@ export class DataArgProcessor {
case FieldMetadataType.TEXT: {
const validatedValue = validateTextFieldOrThrow(value, key);
return transformTextField(validatedValue, isNullEquivalenceEnabled);
return transformTextField(validatedValue);
}
case FieldMetadataType.DATE_TIME:
case FieldMetadataType.DATE:
@@ -207,19 +198,19 @@ export class DataArgProcessor {
fieldMetadata.options?.map((option) => option.value),
);
return transformArrayField(validatedValue, isNullEquivalenceEnabled);
return transformArrayField(validatedValue);
}
case FieldMetadataType.UUID:
return validateUUIDFieldOrThrow(value, key);
case FieldMetadataType.ARRAY: {
const validatedValue = validateArrayFieldOrThrow(value, key);
return transformArrayField(validatedValue, isNullEquivalenceEnabled);
return transformArrayField(validatedValue);
}
case FieldMetadataType.RAW_JSON: {
const validatedValue = validateRawJsonFieldOrThrow(value, key);
return transformRawJsonField(validatedValue, isNullEquivalenceEnabled);
return transformRawJsonField(validatedValue);
}
case FieldMetadataType.RELATION:
case FieldMetadataType.MORPH_RELATION: {
@@ -250,18 +241,18 @@ export class DataArgProcessor {
case FieldMetadataType.EMAILS: {
const validatedValue = validateEmailsFieldOrThrow(value, key);
return transformEmailsValue(validatedValue, isNullEquivalenceEnabled);
return transformEmailsValue(validatedValue);
}
case FieldMetadataType.FULL_NAME: {
const validatedValue = validateFullNameFieldOrThrow(value, key);
return transformFullNameField(validatedValue, isNullEquivalenceEnabled);
return transformFullNameField(validatedValue);
}
case FieldMetadataType.ADDRESS: {
const validatedValue = validateAddressFieldOrThrow(value, key);
return transformAddressField(validatedValue, isNullEquivalenceEnabled);
return transformAddressField(validatedValue);
}
case FieldMetadataType.CURRENCY: {
const validatedValue = validateCurrencyFieldOrThrow(value, key);
@@ -271,7 +262,7 @@ export class DataArgProcessor {
case FieldMetadataType.ACTOR: {
const validatedValue = validateActorFieldOrThrow(value, key);
return transformActorField(validatedValue, isNullEquivalenceEnabled);
return transformActorField(validatedValue);
}
case FieldMetadataType.RICH_TEXT_V2: {
const validatedValue = validateRichTextV2FieldOrThrow(value, key);
@@ -4,18 +4,15 @@ import { transformActorField } from 'src/engine/api/common/common-args-processor
describe('transformActorField', () => {
it('should return null when value is null', () => {
const result = transformActorField(null, true);
const result = transformActorField(null);
expect(result).toBeNull();
});
it('should transform actor with source only', () => {
const result = transformActorField(
{
source: FieldActorSource.EMAIL,
},
true,
);
const result = transformActorField({
source: FieldActorSource.EMAIL,
});
expect(result).toEqual({
source: FieldActorSource.EMAIL,
@@ -23,13 +20,10 @@ describe('transformActorField', () => {
});
it('should transform actor with source and context', () => {
const result = transformActorField(
{
source: FieldActorSource.WORKFLOW,
context: { workflowId: '123', stepId: 'step-1' },
},
true,
);
const result = transformActorField({
source: FieldActorSource.WORKFLOW,
context: { workflowId: '123', stepId: 'step-1' },
});
expect(result).toEqual({
source: FieldActorSource.WORKFLOW,
@@ -38,13 +32,10 @@ describe('transformActorField', () => {
});
it('should transform actor with null source', () => {
const result = transformActorField(
{
source: null,
context: { userId: '456' },
},
true,
);
const result = transformActorField({
source: null,
context: { userId: '456' },
});
expect(result).toEqual({
source: null,
@@ -53,13 +44,10 @@ describe('transformActorField', () => {
});
it('should transform actor with null context', () => {
const result = transformActorField(
{
source: FieldActorSource.API,
context: null,
},
true,
);
const result = transformActorField({
source: FieldActorSource.API,
context: null,
});
expect(result).toEqual({
source: FieldActorSource.API,
@@ -68,13 +56,10 @@ describe('transformActorField', () => {
});
it('should transform empty context object to null', () => {
const result = transformActorField(
{
source: FieldActorSource.EMAIL,
context: {},
},
true,
);
const result = transformActorField({
source: FieldActorSource.EMAIL,
context: {},
});
expect(result).toEqual({
source: FieldActorSource.EMAIL,
@@ -2,25 +2,25 @@ import { transformArrayField } from 'src/engine/api/common/common-args-processor
describe('transformArrayField', () => {
it('should return null when value is null', () => {
const result = transformArrayField(null, true);
const result = transformArrayField(null);
expect(result).toBeNull();
});
it('should return null when value is an empty array', () => {
const result = transformArrayField([], true);
const result = transformArrayField([]);
expect(result).toBeNull();
});
it('should return an array when value is a string', () => {
const result = transformArrayField('singleString', true);
const result = transformArrayField('singleString');
expect(result).toEqual(['singleString']);
});
it('should return an array when value is an array of strings', () => {
const result = transformArrayField(['string1', 'string2', 'string3'], true);
const result = transformArrayField(['string1', 'string2', 'string3']);
expect(result).toEqual(['string1', 'string2', 'string3']);
});
@@ -2,7 +2,7 @@ import { transformFullNameField } from 'src/engine/api/common/common-args-proces
describe('transformFullNameField', () => {
it('should return null when value is null', () => {
const result = transformFullNameField(null, true);
const result = transformFullNameField(null);
expect(result).toBeNull();
});
@@ -12,7 +12,7 @@ describe('transformFullNameField', () => {
firstName: 'John',
lastName: 'Doe',
};
const result = transformFullNameField(value, true);
const result = transformFullNameField(value);
expect(result).toEqual({
firstName: 'John',
@@ -24,7 +24,7 @@ describe('transformFullNameField', () => {
const value = {
lastName: '',
};
const result = transformFullNameField(value, true);
const result = transformFullNameField(value);
expect(result).toEqual({
lastName: null,
@@ -2,19 +2,19 @@ import { transformRawJsonField } from 'src/engine/api/common/common-args-process
describe('transformRawJsonField', () => {
it('should return null when value is null', () => {
const result = transformRawJsonField(null, true);
const result = transformRawJsonField(null);
expect(result).toBeNull();
});
it('should return null when value is empty object', () => {
const result = transformRawJsonField({}, true);
const result = transformRawJsonField({});
expect(result).toBeNull();
});
it('should return the string when value is empty array', () => {
const result = transformRawJsonField([], true);
const result = transformRawJsonField([]);
expect(result).toBeNull();
});
@@ -2,19 +2,19 @@ import { transformTextField } from 'src/engine/api/common/common-args-processors
describe('transformTextField', () => {
it('should return null when value is null', () => {
const result = transformTextField(null, true);
const result = transformTextField(null);
expect(result).toBeNull();
});
it('should return null when value is empty string', () => {
const result = transformTextField('', true);
const result = transformTextField('');
expect(result).toBeNull();
});
it('should return the string when value is a non-empty string', () => {
const result = transformTextField('hello world', true);
const result = transformTextField('hello world');
expect(result).toBe('hello world');
});
@@ -11,7 +11,6 @@ export const transformActorField = (
name?: string | null;
workspaceMemberId?: string | null;
} | null,
isNullEquivalenceEnabled: boolean = false,
): {
source?: FieldActorSource | null;
context?: object | string | null;
@@ -24,10 +23,8 @@ export const transformActorField = (
source: value.source,
context: isUndefined(value.context)
? undefined
: transformRawJsonField(value.context, isNullEquivalenceEnabled),
name: isUndefined(value.name)
? undefined
: transformTextField(value.name, isNullEquivalenceEnabled),
: transformRawJsonField(value.context),
name: isUndefined(value.name) ? undefined : transformTextField(value.name),
workspaceMemberId: isUndefined(value.workspaceMemberId)
? undefined
: value.workspaceMemberId,
@@ -14,7 +14,6 @@ export const transformAddressField = (
addressLat?: number | null;
addressLng?: number | null;
} | null,
isNullEquivalenceEnabled: boolean = false,
): {
addressStreet1?: string | null;
addressStreet2?: string | null;
@@ -30,22 +29,22 @@ export const transformAddressField = (
return {
addressStreet1: isUndefined(value.addressStreet1)
? undefined
: transformTextField(value.addressStreet1, isNullEquivalenceEnabled),
: transformTextField(value.addressStreet1),
addressStreet2: isUndefined(value.addressStreet2)
? undefined
: transformTextField(value.addressStreet2, isNullEquivalenceEnabled),
: transformTextField(value.addressStreet2),
addressCity: isUndefined(value.addressCity)
? undefined
: transformTextField(value.addressCity, isNullEquivalenceEnabled),
: transformTextField(value.addressCity),
addressState: isUndefined(value.addressState)
? undefined
: transformTextField(value.addressState, isNullEquivalenceEnabled),
: transformTextField(value.addressState),
addressPostcode: isUndefined(value.addressPostcode)
? undefined
: transformTextField(value.addressPostcode, isNullEquivalenceEnabled),
: transformTextField(value.addressPostcode),
addressCountry: isUndefined(value.addressCountry)
? undefined
: transformTextField(value.addressCountry, isNullEquivalenceEnabled),
: transformTextField(value.addressCountry),
addressLat: isUndefined(value.addressLat)
? undefined
: transformNumericField(value.addressLat),
@@ -2,11 +2,8 @@ import { isNullEquivalentArrayFieldValue } from 'src/engine/api/common/common-ar
export const transformArrayField = (
value: string | string[] | null,
isNullEquivalenceEnabled: boolean = false,
): string[] | null => {
if (typeof value === 'string') return [value];
return isNullEquivalenceEnabled && isNullEquivalentArrayFieldValue(value)
? null
: value;
return isNullEquivalentArrayFieldValue(value) ? null : value;
};
@@ -8,7 +8,6 @@ export const transformCurrencyField = (
amountMicros?: number | string | null;
currencyCode?: string | null;
} | null,
isNullEquivalenceEnabled: boolean = false,
): {
amountMicros?: number | null;
currencyCode?: string | null;
@@ -21,6 +20,6 @@ export const transformCurrencyField = (
: transformNumericField(value.amountMicros),
currencyCode: isUndefined(value.currencyCode)
? undefined
: transformTextField(value.currencyCode, isNullEquivalenceEnabled),
: transformTextField(value.currencyCode),
};
};
@@ -7,7 +7,6 @@ export const transformFullNameField = (
firstName?: string | null;
lastName?: string | null;
} | null,
isNullEquivalenceEnabled: boolean = false,
): {
firstName?: string | null;
lastName?: string | null;
@@ -17,9 +16,9 @@ export const transformFullNameField = (
return {
firstName: isUndefined(value.firstName)
? undefined
: transformTextField(value.firstName, isNullEquivalenceEnabled),
: transformTextField(value.firstName),
lastName: isUndefined(value.lastName)
? undefined
: transformTextField(value.lastName, isNullEquivalenceEnabled),
: transformTextField(value.lastName),
};
};
@@ -3,9 +3,6 @@ import { isNullEquivalentRawJsonFieldValue } from 'src/engine/api/common/common-
export const transformRawJsonField = (
value: object | string | null,
isNullEquivalenceEnabled: boolean = false,
): object | string | null => {
return isNullEquivalenceEnabled && isNullEquivalentRawJsonFieldValue(value)
? null
: value;
return isNullEquivalentRawJsonFieldValue(value) ? null : value;
};
@@ -1,10 +1,5 @@
import { isNullEquivalentTextFieldValue } from 'src/engine/api/common/common-args-processors/data-arg-processor/utils/is-null-equivalent-text-field-value.util';
export const transformTextField = (
value: string | null,
isNullEquivalenceEnabled: boolean = false,
): string | null => {
return isNullEquivalenceEnabled && isNullEquivalentTextFieldValue(value)
? null
: value;
export const transformTextField = (value: string | null): string | null => {
return isNullEquivalentTextFieldValue(value) ? null : value;
};