feat: address composite field (#4492)

Added new Address field input type.

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
rostaklein
2024-03-28 16:50:38 +01:00
committed by GitHub
parent 22d4af2e0c
commit 3171d0c87b
56 changed files with 1839 additions and 716 deletions

View File

@ -9,6 +9,7 @@ import { fullNameObjectDefinition } from 'src/engine/metadata-modules/field-meta
import { currencyObjectDefinition } from 'src/engine/metadata-modules/field-metadata/composite-types/currency.composite-type';
import { linkObjectDefinition } from 'src/engine/metadata-modules/field-metadata/composite-types/link.composite-type';
import { EnumTypeDefinitionFactory } from 'src/engine/api/graphql/workspace-schema-builder/factories/enum-type-definition.factory';
import { addressObjectDefinition } from 'src/engine/metadata-modules/field-metadata/composite-types/address.composite-type';
import { TypeDefinitionsStorage } from './storages/type-definitions.storage';
import {
@ -68,7 +69,8 @@ export class TypeDefinitionsGenerator {
currencyObjectDefinition,
linkObjectDefinition,
fullNameObjectDefinition,
];
addressObjectDefinition,
] satisfies ObjectMetadataInterface[];
this.logger.log(
`Generating staticObjects: [${staticObjectMetadataCollection

View File

@ -104,5 +104,19 @@ export const mapFieldMetadataToGraphqlQuery = (
lastName
}
`;
} else if (fieldType === FieldMetadataType.ADDRESS) {
return `
${field.name}
{
addressStreet1
addressStreet2
addressCity
addressPostcode
addressState
addressCountry
addressLat
addressLng
}
`;
}
};

View File

@ -57,6 +57,7 @@ const getSchemaComponentsProperties = (
case FieldMetadataType.LINK:
case FieldMetadataType.CURRENCY:
case FieldMetadataType.FULL_NAME:
case FieldMetadataType.ADDRESS:
itemProperty = {
type: 'object',
properties: Object.keys(field.targetColumnMap).reduce(

View File

@ -0,0 +1,195 @@
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
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';
export const addressFields = (
fieldMetadata?: FieldMetadataInterface,
): FieldMetadataInterface[] => {
const inferredFieldMetadata = fieldMetadata as
| FieldMetadataInterface<FieldMetadataType.ADDRESS>
| undefined;
const targetColumnMap = inferredFieldMetadata
? generateTargetColumnMap(
inferredFieldMetadata.type,
inferredFieldMetadata.isCustom ?? false,
inferredFieldMetadata.name,
)
: {
addressStreet1: 'addressStreet1',
addressStreet2: 'addressStreet2',
addressCity: 'addressCity',
addressPostcode: 'addressPostcode',
addressState: 'addressState',
addressCountry: 'addressCountry',
addressLat: 'addressLat',
addressLng: 'addressLng',
};
return [
{
id: 'addressStreet1',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.ADDRESS.toString(),
name: 'addressStreet1',
label: 'Address',
targetColumnMap: {
value: targetColumnMap.addressStreet1,
},
isNullable: true,
...(inferredFieldMetadata
? {
defaultValue:
inferredFieldMetadata.defaultValue?.addressStreet1 ?? undefined,
}
: {}),
} satisfies FieldMetadataInterface<FieldMetadataType.TEXT>,
{
id: 'addressStreet2',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.ADDRESS.toString(),
name: 'addressStreet2',
label: 'Address 2',
targetColumnMap: {
value: targetColumnMap.addressStreet2,
},
isNullable: true,
...(inferredFieldMetadata
? {
defaultValue:
inferredFieldMetadata.defaultValue?.addressStreet2 ?? null,
}
: {}),
} satisfies FieldMetadataInterface<FieldMetadataType.TEXT>,
{
id: 'addressCity',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.ADDRESS.toString(),
name: 'addressCity',
label: 'City',
targetColumnMap: {
value: targetColumnMap.addressCity,
},
isNullable: true,
...(inferredFieldMetadata
? {
defaultValue:
inferredFieldMetadata.defaultValue?.addressCity ?? null,
}
: {}),
} satisfies FieldMetadataInterface<FieldMetadataType.TEXT>,
{
id: 'addressPostcode',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.ADDRESS.toString(),
name: 'addressPostcode',
label: 'Postcode',
targetColumnMap: {
value: targetColumnMap.addressPostcode,
},
isNullable: true,
...(inferredFieldMetadata
? {
defaultValue:
inferredFieldMetadata.defaultValue?.addressPostcode ?? null,
}
: {}),
} satisfies FieldMetadataInterface<FieldMetadataType.TEXT>,
{
id: 'addressState',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.ADDRESS.toString(),
name: 'addressState',
label: 'State',
targetColumnMap: {
value: targetColumnMap.addressState,
},
isNullable: true,
...(inferredFieldMetadata
? {
defaultValue:
inferredFieldMetadata.defaultValue?.addressState ?? null,
}
: {}),
} satisfies FieldMetadataInterface<FieldMetadataType.TEXT>,
{
id: 'addressCountry',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.ADDRESS.toString(),
name: 'addressCountry',
label: 'Country',
targetColumnMap: {
value: targetColumnMap.addressCountry,
},
isNullable: true,
...(inferredFieldMetadata
? {
defaultValue:
inferredFieldMetadata.defaultValue?.addressCountry ?? null,
}
: {}),
} satisfies FieldMetadataInterface<FieldMetadataType.TEXT>,
{
id: 'addressLat',
type: FieldMetadataType.NUMBER,
objectMetadataId: FieldMetadataType.ADDRESS.toString(),
name: 'addressLat',
label: 'Latitude',
targetColumnMap: {
value: targetColumnMap.addressLat,
},
isNullable: true,
...(inferredFieldMetadata
? {
defaultValue:
inferredFieldMetadata.defaultValue?.addressLat ?? null,
}
: {}),
} satisfies FieldMetadataInterface<FieldMetadataType.NUMBER>,
{
id: 'addressLng',
type: FieldMetadataType.NUMBER,
objectMetadataId: FieldMetadataType.ADDRESS.toString(),
name: 'addressLng',
label: 'Longitude',
targetColumnMap: {
value: targetColumnMap.addressLng,
},
isNullable: true,
...(inferredFieldMetadata
? {
defaultValue:
inferredFieldMetadata.defaultValue?.addressLng ?? null,
}
: {}),
} satisfies FieldMetadataInterface<FieldMetadataType.NUMBER>,
];
};
export const addressObjectDefinition = {
id: FieldMetadataType.ADDRESS.toString(),
nameSingular: 'address',
namePlural: 'address',
labelSingular: 'Address',
labelPlural: 'Addresses',
targetTableName: '',
fields: addressFields(),
fromRelations: [],
toRelations: [],
isActive: true,
isSystem: true,
isCustom: false,
isRemote: false,
} satisfies ObjectMetadataInterface;
export type AddressMetadata = {
addressStreet1: string;
addressStreet2: string;
addressCity: string;
addressState: string;
addressZipCode: string;
addressCountry: string;
addressLat: number;
addressLng: number;
};

View File

@ -4,6 +4,7 @@ import { currencyFields } from 'src/engine/metadata-modules/field-metadata/compo
import { fullNameFields } from 'src/engine/metadata-modules/field-metadata/composite-types/full-name.composite-type';
import { linkFields } from 'src/engine/metadata-modules/field-metadata/composite-types/link.composite-type';
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { addressFields } from 'src/engine/metadata-modules/field-metadata/composite-types/address.composite-type';
export type CompositeFieldsDefinitionFunction = (
fieldMetadata?: FieldMetadataInterface,
@ -16,4 +17,5 @@ export const compositeDefinitions = new Map<
[FieldMetadataType.LINK, linkFields],
[FieldMetadataType.CURRENCY, currencyFields],
[FieldMetadataType.FULL_NAME, fullNameFields],
[FieldMetadataType.ADDRESS, addressFields],
]);

View File

@ -6,6 +6,7 @@ import {
IsNotEmpty,
IsNumber,
IsNumberString,
IsString,
Matches,
ValidateIf,
} from 'class-validator';
@ -98,3 +99,36 @@ export class FieldMetadataDefaultValueNowFunction {
@IsNotEmpty()
value: typeof fieldMetadataDefaultValueFunctionName.NOW;
}
export class FieldMetadataDefaultValueAddress {
@ValidateIf((_object, value) => value !== null)
@IsString()
addressStreet1: string | null;
@ValidateIf((_object, value) => value !== null)
@IsString()
addressStreet2: string | null;
@ValidateIf((_object, value) => value !== null)
@IsString()
addressCity: string | null;
@ValidateIf((_object, value) => value !== null)
@IsString()
addressPostcode: string | null;
@ValidateIf((_object, value) => value !== null)
@IsString()
addressState: string | null;
@ValidateIf((_object, value) => value !== null)
@IsString()
addressCountry: string | null;
@ValidateIf((_object, value) => value !== null)
@IsNumber()
addressLat: number | null;
@ValidateIf((_object, value) => value !== null)
@IsNumber()
addressLng: number | null;
}

View File

@ -36,6 +36,8 @@ export enum FieldMetadataType {
MULTI_SELECT = 'MULTI_SELECT',
RELATION = 'RELATION',
POSITION = 'POSITION',
ADDRESS = 'ADDRESS',
JSON = 'JSON',
RAW_JSON = 'RAW_JSON',
}

View File

@ -1,4 +1,5 @@
import {
FieldMetadataDefaultValueAddress,
FieldMetadataDefaultValueBoolean,
FieldMetadataDefaultValueCurrency,
FieldMetadataDefaultValueDateTime,
@ -35,6 +36,7 @@ type FieldMetadataDefaultValueMapping = {
[FieldMetadataType.LINK]: FieldMetadataDefaultValueLink;
[FieldMetadataType.CURRENCY]: FieldMetadataDefaultValueCurrency;
[FieldMetadataType.FULL_NAME]: FieldMetadataDefaultValueFullName;
[FieldMetadataType.ADDRESS]: FieldMetadataDefaultValueAddress;
[FieldMetadataType.RATING]: FieldMetadataDefaultValueString;
[FieldMetadataType.SELECT]: FieldMetadataDefaultValueString;
[FieldMetadataType.MULTI_SELECT]: FieldMetadataDefaultValueStringArray;

View File

@ -19,6 +19,17 @@ export interface FieldMetadataTargetColumnMapFullName {
lastName: string;
}
export type FieldMetadataTargetColumnMapAddress = {
addressStreet1: string;
addressStreet2: string;
addressCity: string;
addressState: string;
addressZipCode: string;
addressCountry: string;
addressLat: number;
addressLng: number;
};
type AllFieldMetadataTypes = {
[key: string]: string;
};
@ -27,6 +38,7 @@ type FieldMetadataTypeMapping = {
[FieldMetadataType.LINK]: FieldMetadataTargetColumnMapLink;
[FieldMetadataType.CURRENCY]: FieldMetadataTargetColumnMapCurrency;
[FieldMetadataType.FULL_NAME]: FieldMetadataTargetColumnMapFullName;
[FieldMetadataType.ADDRESS]: FieldMetadataTargetColumnMapAddress;
};
type TypeByFieldMetadata<T extends FieldMetadataType | 'default'> = [

View File

@ -15,6 +15,17 @@ export function generateDefaultValue(
firstName: "''",
lastName: "''",
};
case FieldMetadataType.ADDRESS:
return {
addressStreet1: "''",
addressStreet2: "''",
addressCity: "''",
addressState: "''",
addressCountry: "''",
addressPostcode: "''",
addressLat: null,
addressLng: null,
};
case FieldMetadataType.LINK:
return {
url: "''",

View File

@ -54,6 +54,17 @@ export function generateTargetColumnMap(
firstName: `${columnName}FirstName`,
lastName: `${columnName}LastName`,
};
case FieldMetadataType.ADDRESS:
return {
addressStreet1: `${columnName}AddressStreet1`,
addressStreet2: `${columnName}AddressStreet2`,
addressCity: `${columnName}AddressCity`,
addressPostcode: `${columnName}AddressPostcode`,
addressState: `${columnName}AddressState`,
addressCountry: `${columnName}AddressCountry`,
addressLat: `${columnName}AddressLat`,
addressLng: `${columnName}AddressLng`,
};
case FieldMetadataType.RELATION:
return {};
default:

View File

@ -9,6 +9,7 @@ export const isCompositeFieldMetadataType = (
return (
type === FieldMetadataType.LINK ||
type === FieldMetadataType.CURRENCY ||
type === FieldMetadataType.FULL_NAME
type === FieldMetadataType.FULL_NAME ||
type === FieldMetadataType.ADDRESS
);
};

View File

@ -8,6 +8,7 @@ import {
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import {
FieldMetadataDefaultValueAddress,
FieldMetadataDefaultValueBoolean,
FieldMetadataDefaultValueCurrency,
FieldMetadataDefaultValueDateTime,
@ -44,6 +45,7 @@ export const defaultValueValidatorsMap = {
[FieldMetadataType.RATING]: [FieldMetadataDefaultValueString],
[FieldMetadataType.SELECT]: [FieldMetadataDefaultValueString],
[FieldMetadataType.MULTI_SELECT]: [FieldMetadataDefaultValueStringArray],
[FieldMetadataType.ADDRESS]: [FieldMetadataDefaultValueAddress],
[FieldMetadataType.RAW_JSON]: [FieldMetadataDefaultValueRawJson],
};

View File

@ -12,7 +12,7 @@ export const companyPrefillDemoData = async (
.into(`${schemaName}.company`, [
'name',
'domainName',
'address',
'addressAddressCity',
'employees',
'linkedinLinkUrl',
'position',