feat: wip server folder structure (#4573)
* feat: wip server folder structure * fix: merge * fix: wrong merge * fix: remove unused file * fix: comment * fix: lint * fix: merge * fix: remove console.log * fix: metadata graphql arguments broken
This commit is contained in:
@ -0,0 +1,27 @@
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { generateNullable } from 'src/engine/metadata-modules/field-metadata/utils/generate-nullable';
|
||||
|
||||
describe('generateNullable', () => {
|
||||
it('should generate a nullable value false for TEXT, EMAIL, PHONE no matter what the input is', () => {
|
||||
expect(generateNullable(FieldMetadataType.TEXT, false)).toEqual(false);
|
||||
expect(generateNullable(FieldMetadataType.PHONE, false)).toEqual(false);
|
||||
expect(generateNullable(FieldMetadataType.EMAIL, false)).toEqual(false);
|
||||
|
||||
expect(generateNullable(FieldMetadataType.TEXT, true)).toEqual(false);
|
||||
expect(generateNullable(FieldMetadataType.PHONE, true)).toEqual(false);
|
||||
expect(generateNullable(FieldMetadataType.EMAIL, true)).toEqual(false);
|
||||
|
||||
expect(generateNullable(FieldMetadataType.TEXT)).toEqual(false);
|
||||
expect(generateNullable(FieldMetadataType.PHONE)).toEqual(false);
|
||||
expect(generateNullable(FieldMetadataType.EMAIL)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should should return true if no input is given', () => {
|
||||
expect(generateNullable(FieldMetadataType.DATE_TIME)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should should return the input value if the input value is given', () => {
|
||||
expect(generateNullable(FieldMetadataType.DATE_TIME, true)).toEqual(true);
|
||||
expect(generateNullable(FieldMetadataType.DATE_TIME, false)).toEqual(false);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,41 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { generateTargetColumnMap } from 'src/engine/metadata-modules/field-metadata/utils/generate-target-column-map.util';
|
||||
|
||||
describe('generateTargetColumnMap', () => {
|
||||
it('should generate a target column map for a given type', () => {
|
||||
const textMap = generateTargetColumnMap(
|
||||
FieldMetadataType.TEXT,
|
||||
false,
|
||||
'name',
|
||||
);
|
||||
|
||||
expect(textMap).toEqual({ value: 'name' });
|
||||
|
||||
const linkMap = generateTargetColumnMap(
|
||||
FieldMetadataType.LINK,
|
||||
false,
|
||||
'website',
|
||||
);
|
||||
|
||||
expect(linkMap).toEqual({ label: 'websiteLabel', url: 'websiteUrl' });
|
||||
|
||||
const currencyMap = generateTargetColumnMap(
|
||||
FieldMetadataType.CURRENCY,
|
||||
true,
|
||||
'price',
|
||||
);
|
||||
|
||||
expect(currencyMap).toEqual({
|
||||
amountMicros: '_priceAmountMicros',
|
||||
currencyCode: '_priceCurrencyCode',
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error for an unknown type', () => {
|
||||
expect(() =>
|
||||
generateTargetColumnMap('invalid' as FieldMetadataType, false, 'name'),
|
||||
).toThrow(BadRequestException);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,46 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
import { serializeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/serialize-default-value';
|
||||
|
||||
describe('serializeDefaultValue', () => {
|
||||
it('should return null for undefined defaultValue', () => {
|
||||
expect(serializeDefaultValue()).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle uuid dynamic default value', () => {
|
||||
expect(serializeDefaultValue({ type: 'uuid' })).toBe(
|
||||
'public.uuid_generate_v4()',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle now dynamic default value', () => {
|
||||
expect(serializeDefaultValue({ type: 'now' })).toBe('now()');
|
||||
});
|
||||
|
||||
it('should throw BadRequestException for invalid dynamic default value type', () => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error Just for testing purposes
|
||||
expect(() => serializeDefaultValue({ type: 'invalid' })).toThrow(
|
||||
BadRequestException,
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle string static default value', () => {
|
||||
expect(serializeDefaultValue('test')).toBe("'test'");
|
||||
});
|
||||
|
||||
it('should handle number static default value', () => {
|
||||
expect(serializeDefaultValue(123)).toBe(123);
|
||||
});
|
||||
|
||||
it('should handle boolean static default value', () => {
|
||||
expect(serializeDefaultValue(true)).toBe(true);
|
||||
expect(serializeDefaultValue(false)).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle Date static default value', () => {
|
||||
const date = new Date('2023-01-01');
|
||||
|
||||
expect(serializeDefaultValue(date)).toBe(`'${date.toISOString()}'`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,161 @@
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { validateDefaultValueForType } from 'src/engine/metadata-modules/field-metadata/utils/validate-default-value-for-type.util';
|
||||
|
||||
describe('validateDefaultValueForType', () => {
|
||||
it('should return true for null defaultValue', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.TEXT, null)).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
// Dynamic default values
|
||||
it('should validate uuid dynamic default value for UUID type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.UUID, { type: 'uuid' }),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should validate now dynamic default value for DATE_TIME type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.DATE_TIME, { type: 'now' }),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for mismatched dynamic default value', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.UUID, { type: 'now' }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// Static default values
|
||||
it('should validate string default value for TEXT type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.TEXT, { value: 'test' }),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid string default value for TEXT type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.TEXT, { value: 123 }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate string default value for PHONE type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.PHONE, {
|
||||
value: '+123456789',
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid string default value for PHONE type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.PHONE, { value: 123 }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate string default value for EMAIL type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.EMAIL, {
|
||||
value: 'test@example.com',
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid string default value for EMAIL type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.EMAIL, { value: 123 }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate number default value for NUMBER type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.NUMBER, { value: 100 }),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid number default value for NUMBER type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.NUMBER, { value: '100' }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate number default value for PROBABILITY type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.PROBABILITY, {
|
||||
value: 0.5,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid number default value for PROBABILITY type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.PROBABILITY, {
|
||||
value: '50%',
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate boolean default value for BOOLEAN type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.BOOLEAN, { value: true }),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid boolean default value for BOOLEAN type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.BOOLEAN, { value: 'true' }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// LINK type
|
||||
it('should validate LINK default value', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.LINK, {
|
||||
label: 'http://example.com',
|
||||
url: 'Example',
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid LINK default value', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error Just for testing purposes
|
||||
{ label: 123, url: {} },
|
||||
FieldMetadataType.LINK,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// CURRENCY type
|
||||
it('should validate CURRENCY default value', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.CURRENCY, {
|
||||
amountMicros: '100',
|
||||
currencyCode: 'USD',
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid CURRENCY default value', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error Just for testing purposes
|
||||
{ amountMicros: 100, currencyCode: 'USD' },
|
||||
FieldMetadataType.CURRENCY,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// Unknown type
|
||||
it('should return false for unknown type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType('unknown' as FieldMetadataType, {
|
||||
value: 'test',
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,33 @@
|
||||
import { FieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
export function generateDefaultValue(
|
||||
type: FieldMetadataType,
|
||||
): FieldMetadataDefaultValue {
|
||||
switch (type) {
|
||||
case FieldMetadataType.TEXT:
|
||||
case FieldMetadataType.PHONE:
|
||||
case FieldMetadataType.EMAIL:
|
||||
return {
|
||||
value: '',
|
||||
};
|
||||
case FieldMetadataType.FULL_NAME:
|
||||
return {
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
};
|
||||
case FieldMetadataType.LINK:
|
||||
return {
|
||||
url: '',
|
||||
label: '',
|
||||
};
|
||||
case FieldMetadataType.CURRENCY:
|
||||
return {
|
||||
amountMicros: null,
|
||||
currencyCode: '',
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
export function generateNullable(
|
||||
type: FieldMetadataType,
|
||||
inputNullableValue?: boolean,
|
||||
): boolean {
|
||||
switch (type) {
|
||||
case FieldMetadataType.TEXT:
|
||||
case FieldMetadataType.PHONE:
|
||||
case FieldMetadataType.EMAIL:
|
||||
return false;
|
||||
default:
|
||||
return inputNullableValue ?? true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
import { v4 as uuidV4 } from 'uuid';
|
||||
|
||||
import { FieldMetadataDefaultOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
|
||||
|
||||
const range = {
|
||||
start: 1,
|
||||
end: 5,
|
||||
};
|
||||
|
||||
export function generateRatingOptions(): FieldMetadataDefaultOption[] {
|
||||
const options: FieldMetadataDefaultOption[] = [];
|
||||
|
||||
for (let i = range.start; i <= range.end; i++) {
|
||||
options.push({
|
||||
id: uuidV4(),
|
||||
label: i.toString(),
|
||||
value: `RATING_${i}`,
|
||||
position: i - 1,
|
||||
});
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
import { FieldMetadataTargetColumnMap } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-target-column-map.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { createCustomColumnName } from 'src/engine/utils/create-custom-column-name.util';
|
||||
|
||||
/**
|
||||
* Generate a target column map for a given type, this is used to map the field to the correct column(s) in the database.
|
||||
* This is used to support fields that map to multiple columns in the database.
|
||||
*
|
||||
* @param type string
|
||||
* @returns FieldMetadataTargetColumnMap
|
||||
*/
|
||||
export function generateTargetColumnMap(
|
||||
type: FieldMetadataType,
|
||||
isCustomField: boolean,
|
||||
fieldName: string,
|
||||
): FieldMetadataTargetColumnMap {
|
||||
const columnName = isCustomField
|
||||
? createCustomColumnName(fieldName)
|
||||
: fieldName;
|
||||
|
||||
switch (type) {
|
||||
case FieldMetadataType.UUID:
|
||||
case FieldMetadataType.TEXT:
|
||||
case FieldMetadataType.PHONE:
|
||||
case FieldMetadataType.EMAIL:
|
||||
case FieldMetadataType.NUMBER:
|
||||
case FieldMetadataType.NUMERIC:
|
||||
case FieldMetadataType.PROBABILITY:
|
||||
case FieldMetadataType.BOOLEAN:
|
||||
case FieldMetadataType.DATE_TIME:
|
||||
case FieldMetadataType.RATING:
|
||||
case FieldMetadataType.SELECT:
|
||||
case FieldMetadataType.MULTI_SELECT:
|
||||
case FieldMetadataType.POSITION:
|
||||
case FieldMetadataType.JSON:
|
||||
return {
|
||||
value: columnName,
|
||||
};
|
||||
case FieldMetadataType.LINK:
|
||||
return {
|
||||
label: `${columnName}Label`,
|
||||
url: `${columnName}Url`,
|
||||
};
|
||||
case FieldMetadataType.CURRENCY:
|
||||
return {
|
||||
amountMicros: `${columnName}AmountMicros`,
|
||||
currencyCode: `${columnName}CurrencyCode`,
|
||||
};
|
||||
case FieldMetadataType.FULL_NAME:
|
||||
return {
|
||||
firstName: `${columnName}FirstName`,
|
||||
lastName: `${columnName}LastName`,
|
||||
};
|
||||
case FieldMetadataType.RELATION:
|
||||
return {};
|
||||
default:
|
||||
throw new BadRequestException(`Unknown type ${type}`);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
export const isCompositeFieldMetadataType = (
|
||||
type: FieldMetadataType,
|
||||
): type is
|
||||
| FieldMetadataType.LINK
|
||||
| FieldMetadataType.CURRENCY
|
||||
| FieldMetadataType.FULL_NAME => {
|
||||
return (
|
||||
type === FieldMetadataType.LINK ||
|
||||
type === FieldMetadataType.CURRENCY ||
|
||||
type === FieldMetadataType.FULL_NAME
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,16 @@
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
export type EnumFieldMetadataUnionType =
|
||||
| FieldMetadataType.RATING
|
||||
| FieldMetadataType.SELECT
|
||||
| FieldMetadataType.MULTI_SELECT;
|
||||
|
||||
export const isEnumFieldMetadataType = (
|
||||
type: FieldMetadataType,
|
||||
): type is EnumFieldMetadataUnionType => {
|
||||
return (
|
||||
type === FieldMetadataType.RATING ||
|
||||
type === FieldMetadataType.SELECT ||
|
||||
type === FieldMetadataType.MULTI_SELECT
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,55 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
|
||||
import { FieldMetadataDefaultSerializableValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
|
||||
import { serializeTypeDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/serialize-type-default-value.util';
|
||||
|
||||
export const serializeDefaultValue = (
|
||||
defaultValue?: FieldMetadataDefaultSerializableValue,
|
||||
) => {
|
||||
if (defaultValue === undefined || defaultValue === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Dynamic default values
|
||||
if (
|
||||
!Array.isArray(defaultValue) &&
|
||||
typeof defaultValue === 'object' &&
|
||||
'type' in defaultValue
|
||||
) {
|
||||
const serializedTypeDefaultValue = serializeTypeDefaultValue(defaultValue);
|
||||
|
||||
if (!serializedTypeDefaultValue) {
|
||||
throw new BadRequestException('Invalid default value');
|
||||
}
|
||||
|
||||
return serializedTypeDefaultValue;
|
||||
}
|
||||
|
||||
// Static default values
|
||||
if (typeof defaultValue === 'string') {
|
||||
return `'${defaultValue}'`;
|
||||
}
|
||||
|
||||
if (typeof defaultValue === 'number') {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (typeof defaultValue === 'boolean') {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (defaultValue instanceof Date) {
|
||||
return `'${defaultValue.toISOString()}'`;
|
||||
}
|
||||
|
||||
if (Array.isArray(defaultValue)) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (typeof defaultValue === 'object') {
|
||||
return `'${JSON.stringify(defaultValue)}'`;
|
||||
}
|
||||
|
||||
throw new BadRequestException('Invalid default value');
|
||||
};
|
||||
@ -0,0 +1,18 @@
|
||||
import { FieldMetadataDynamicDefaultValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
|
||||
export const serializeTypeDefaultValue = (
|
||||
defaultValue?: FieldMetadataDynamicDefaultValue,
|
||||
) => {
|
||||
if (!defaultValue?.type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (defaultValue.type) {
|
||||
case 'uuid':
|
||||
return 'public.uuid_generate_v4()';
|
||||
case 'now':
|
||||
return 'now()';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,72 @@
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { validateSync } from 'class-validator';
|
||||
|
||||
import { FieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-default-value.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import {
|
||||
FieldMetadataDefaultValueBoolean,
|
||||
FieldMetadataDefaultValueCurrency,
|
||||
FieldMetadataDefaultValueDateTime,
|
||||
FieldMetadataDefaultValueFullName,
|
||||
FieldMetadataDefaultValueJson,
|
||||
FieldMetadataDefaultValueLink,
|
||||
FieldMetadataDefaultValueNumber,
|
||||
FieldMetadataDefaultValueString,
|
||||
FieldMetadataDefaultValueStringArray,
|
||||
FieldMetadataDynamicDefaultValueNow,
|
||||
FieldMetadataDynamicDefaultValueUuid,
|
||||
} from 'src/engine/metadata-modules/field-metadata/dtos/default-value.input';
|
||||
|
||||
export const defaultValueValidatorsMap = {
|
||||
[FieldMetadataType.UUID]: [
|
||||
FieldMetadataDefaultValueString,
|
||||
FieldMetadataDynamicDefaultValueUuid,
|
||||
],
|
||||
[FieldMetadataType.TEXT]: [FieldMetadataDefaultValueString],
|
||||
[FieldMetadataType.PHONE]: [FieldMetadataDefaultValueString],
|
||||
[FieldMetadataType.EMAIL]: [FieldMetadataDefaultValueString],
|
||||
[FieldMetadataType.DATE_TIME]: [
|
||||
FieldMetadataDefaultValueDateTime,
|
||||
FieldMetadataDynamicDefaultValueNow,
|
||||
],
|
||||
[FieldMetadataType.BOOLEAN]: [FieldMetadataDefaultValueBoolean],
|
||||
[FieldMetadataType.NUMBER]: [FieldMetadataDefaultValueNumber],
|
||||
[FieldMetadataType.NUMERIC]: [FieldMetadataDefaultValueString],
|
||||
[FieldMetadataType.PROBABILITY]: [FieldMetadataDefaultValueNumber],
|
||||
[FieldMetadataType.LINK]: [FieldMetadataDefaultValueLink],
|
||||
[FieldMetadataType.CURRENCY]: [FieldMetadataDefaultValueCurrency],
|
||||
[FieldMetadataType.FULL_NAME]: [FieldMetadataDefaultValueFullName],
|
||||
[FieldMetadataType.RATING]: [FieldMetadataDefaultValueString],
|
||||
[FieldMetadataType.SELECT]: [FieldMetadataDefaultValueString],
|
||||
[FieldMetadataType.MULTI_SELECT]: [FieldMetadataDefaultValueStringArray],
|
||||
[FieldMetadataType.JSON]: [FieldMetadataDefaultValueJson],
|
||||
};
|
||||
|
||||
export const validateDefaultValueForType = (
|
||||
type: FieldMetadataType,
|
||||
defaultValue: FieldMetadataDefaultValue,
|
||||
): boolean => {
|
||||
if (defaultValue === null) return true;
|
||||
|
||||
const validators = defaultValueValidatorsMap[type];
|
||||
|
||||
if (!validators) return false;
|
||||
|
||||
const isValid = validators.some((validator) => {
|
||||
const defaultValueInstance = plainToInstance<
|
||||
any,
|
||||
FieldMetadataDefaultValue
|
||||
>(validator, defaultValue);
|
||||
|
||||
return (
|
||||
validateSync(defaultValueInstance, {
|
||||
whitelist: true,
|
||||
forbidNonWhitelisted: true,
|
||||
forbidUnknownValues: true,
|
||||
}).length === 0
|
||||
);
|
||||
});
|
||||
|
||||
return isValid;
|
||||
};
|
||||
@ -0,0 +1,60 @@
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { validateSync } from 'class-validator';
|
||||
|
||||
import { FieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-options.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import {
|
||||
FieldMetadataComplexOption,
|
||||
FieldMetadataDefaultOption,
|
||||
} from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
|
||||
|
||||
import { isEnumFieldMetadataType } from './is-enum-field-metadata-type.util';
|
||||
|
||||
export const optionsValidatorsMap = {
|
||||
// RATING doesn't need to be provided as it's the backend that will generate the options
|
||||
[FieldMetadataType.SELECT]: [FieldMetadataComplexOption],
|
||||
[FieldMetadataType.MULTI_SELECT]: [FieldMetadataComplexOption],
|
||||
};
|
||||
|
||||
export const validateOptionsForType = (
|
||||
type: FieldMetadataType,
|
||||
options: FieldMetadataOptions,
|
||||
): boolean => {
|
||||
if (options === null) return true;
|
||||
|
||||
if (!Array.isArray(options)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isEnumFieldMetadataType(type)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type === FieldMetadataType.RATING) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const validators = optionsValidatorsMap[type];
|
||||
|
||||
if (!validators) return false;
|
||||
|
||||
const isValid = options.every((option) => {
|
||||
return validators.some((validator) => {
|
||||
const optionsInstance = plainToInstance<
|
||||
any,
|
||||
FieldMetadataDefaultOption | FieldMetadataComplexOption
|
||||
>(validator, option);
|
||||
|
||||
return (
|
||||
validateSync(optionsInstance, {
|
||||
whitelist: true,
|
||||
forbidNonWhitelisted: true,
|
||||
forbidUnknownValues: true,
|
||||
}).length === 0
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
return isValid;
|
||||
};
|
||||
Reference in New Issue
Block a user