Remove relations for remotes (#5455)

For remotes, we will only create the foreign key, without the relation
metadata. Expected behavior will be:
- possible to create an activity. But the remote object will not be
displayed in the relations of the activity
- the remote objects should not be available in the search for relations

Also switched the number settings to an enum, since we now have to
handle `BigInt` case.

---------

Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
Thomas Trompette 2024-05-20 16:37:35 +02:00 committed by GitHub
parent b098027174
commit 4d479ee8ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 461 additions and 486 deletions

View File

@ -95,6 +95,7 @@
"graphql-fields": "^2.0.3", "graphql-fields": "^2.0.3",
"graphql-middleware": "^6.1.35", "graphql-middleware": "^6.1.35",
"graphql-rate-limit": "^3.3.0", "graphql-rate-limit": "^3.3.0",
"graphql-scalars": "^1.23.0",
"graphql-subscriptions": "2.0.0", "graphql-subscriptions": "2.0.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"graphql-type-json": "^0.3.2", "graphql-type-json": "^0.3.2",

View File

@ -29,19 +29,19 @@ export const useMultiObjectSearchMatchesSearchFilterAndToSelectQuery = ({
}) => { }) => {
const objectMetadataItems = useRecoilValue(objectMetadataItemsState); const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
const nonSystemObjectMetadataItems = objectMetadataItems.filter( const selectableObjectMetadataItems = objectMetadataItems.filter(
({ isSystem }) => !isSystem, ({ isSystem, isRemote }) => !isSystem && !isRemote,
); );
const { searchFilterPerMetadataItemNameSingular } = const { searchFilterPerMetadataItemNameSingular } =
useSearchFilterPerMetadataItem({ useSearchFilterPerMetadataItem({
objectMetadataItems: nonSystemObjectMetadataItems, objectMetadataItems: selectableObjectMetadataItems,
searchFilterValue, searchFilterValue,
}); });
const objectRecordsToSelectAndMatchesSearchFilterTextFilterPerMetadataItem = const objectRecordsToSelectAndMatchesSearchFilterTextFilterPerMetadataItem =
Object.fromEntries( Object.fromEntries(
nonSystemObjectMetadataItems selectableObjectMetadataItems
.map(({ nameSingular }) => { .map(({ nameSingular }) => {
const selectedIds = selectedObjectRecordIds const selectedIds = selectedObjectRecordIds
.filter( .filter(
@ -74,16 +74,16 @@ export const useMultiObjectSearchMatchesSearchFilterAndToSelectQuery = ({
); );
const { orderByFieldPerMetadataItem } = useOrderByFieldPerMetadataItem({ const { orderByFieldPerMetadataItem } = useOrderByFieldPerMetadataItem({
objectMetadataItems: nonSystemObjectMetadataItems, objectMetadataItems: selectableObjectMetadataItems,
}); });
const { limitPerMetadataItem } = useLimitPerMetadataItem({ const { limitPerMetadataItem } = useLimitPerMetadataItem({
objectMetadataItems: nonSystemObjectMetadataItems, objectMetadataItems: selectableObjectMetadataItems,
limit, limit,
}); });
const multiSelectQuery = useGenerateCombinedFindManyRecordsQuery({ const multiSelectQuery = useGenerateCombinedFindManyRecordsQuery({
operationSignatures: nonSystemObjectMetadataItems.map( operationSignatures: selectableObjectMetadataItems.map(
(objectMetadataItem) => ({ (objectMetadataItem) => ({
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
variables: {}, variables: {},

View File

@ -1,22 +1,18 @@
import { import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql';
GraphQLInputObjectType, import { GraphQLBigInt } from 'graphql-scalars';
GraphQLList,
GraphQLNonNull,
GraphQLInt,
} from 'graphql';
import { FilterIs } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/input/filter-is.input-type'; import { FilterIs } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/input/filter-is.input-type';
export const BigIntFilterType = new GraphQLInputObjectType({ export const BigIntFilterType = new GraphQLInputObjectType({
name: 'BigIntFilter', name: 'BigIntFilter',
fields: { fields: {
eq: { type: GraphQLInt }, eq: { type: GraphQLBigInt },
gt: { type: GraphQLInt }, gt: { type: GraphQLBigInt },
gte: { type: GraphQLInt }, gte: { type: GraphQLBigInt },
in: { type: new GraphQLList(new GraphQLNonNull(GraphQLInt)) }, in: { type: new GraphQLList(new GraphQLNonNull(GraphQLBigInt)) },
lt: { type: GraphQLInt }, lt: { type: GraphQLBigInt },
lte: { type: GraphQLInt }, lte: { type: GraphQLBigInt },
neq: { type: GraphQLInt }, neq: { type: GraphQLBigInt },
is: { type: FilterIs }, is: { type: FilterIs },
}, },
}); });

View File

@ -8,7 +8,6 @@ import {
GraphQLID, GraphQLID,
GraphQLInputObjectType, GraphQLInputObjectType,
GraphQLInputType, GraphQLInputType,
GraphQLInt,
GraphQLList, GraphQLList,
GraphQLNonNull, GraphQLNonNull,
GraphQLScalarType, GraphQLScalarType,
@ -26,7 +25,6 @@ import {
BooleanFilterType, BooleanFilterType,
BigFloatFilterType, BigFloatFilterType,
RawJsonFilterType, RawJsonFilterType,
IntFilterType,
} from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/input'; } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/input';
import { OrderByDirectionType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/enum'; import { OrderByDirectionType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/enum';
import { import {
@ -36,6 +34,8 @@ import {
import { PositionScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/position.scalar'; import { PositionScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/position.scalar';
import { RawJSONScalar } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/raw-json.scalar'; import { RawJSONScalar } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars/raw-json.scalar';
import { IDFilterType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/input/id-filter.input-type'; import { IDFilterType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/input/id-filter.input-type';
import { getNumberFilterType } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-number-filter-type.util';
import { getNumberScalarType } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-number-scalar-type.util';
export interface TypeOptions<T = any> { export interface TypeOptions<T = any> {
nullable?: boolean; nullable?: boolean;
@ -57,13 +57,6 @@ export class TypeMapperService {
return GraphQLID; return GraphQLID;
} }
const numberScalar =
fieldMetadataType === FieldMetadataType.NUMBER &&
(settings as FieldMetadataSettings<FieldMetadataType.NUMBER>)
?.precision === 0
? GraphQLInt
: GraphQLFloat;
const typeScalarMapping = new Map<FieldMetadataType, GraphQLScalarType>([ const typeScalarMapping = new Map<FieldMetadataType, GraphQLScalarType>([
[FieldMetadataType.UUID, UUIDScalarType], [FieldMetadataType.UUID, UUIDScalarType],
[FieldMetadataType.TEXT, GraphQLString], [FieldMetadataType.TEXT, GraphQLString],
@ -72,7 +65,13 @@ export class TypeMapperService {
[FieldMetadataType.DATE_TIME, GraphQLISODateTime], [FieldMetadataType.DATE_TIME, GraphQLISODateTime],
[FieldMetadataType.DATE, GraphQLISODateTime], [FieldMetadataType.DATE, GraphQLISODateTime],
[FieldMetadataType.BOOLEAN, GraphQLBoolean], [FieldMetadataType.BOOLEAN, GraphQLBoolean],
[FieldMetadataType.NUMBER, numberScalar], [
FieldMetadataType.NUMBER,
getNumberScalarType(
(settings as FieldMetadataSettings<FieldMetadataType.NUMBER>)
?.dataType,
),
],
[FieldMetadataType.NUMERIC, BigFloatScalarType], [FieldMetadataType.NUMERIC, BigFloatScalarType],
[FieldMetadataType.PROBABILITY, GraphQLFloat], [FieldMetadataType.PROBABILITY, GraphQLFloat],
[FieldMetadataType.POSITION, PositionScalarType], [FieldMetadataType.POSITION, PositionScalarType],
@ -91,13 +90,6 @@ export class TypeMapperService {
return IDFilterType; return IDFilterType;
} }
const numberScalar =
fieldMetadataType === FieldMetadataType.NUMBER &&
(settings as FieldMetadataSettings<FieldMetadataType.NUMBER>)
?.precision === 0
? IntFilterType
: FloatFilterType;
const typeFilterMapping = new Map< const typeFilterMapping = new Map<
FieldMetadataType, FieldMetadataType,
GraphQLInputObjectType | GraphQLScalarType GraphQLInputObjectType | GraphQLScalarType
@ -109,7 +101,13 @@ export class TypeMapperService {
[FieldMetadataType.DATE_TIME, DateFilterType], [FieldMetadataType.DATE_TIME, DateFilterType],
[FieldMetadataType.DATE, DateFilterType], [FieldMetadataType.DATE, DateFilterType],
[FieldMetadataType.BOOLEAN, BooleanFilterType], [FieldMetadataType.BOOLEAN, BooleanFilterType],
[FieldMetadataType.NUMBER, numberScalar], [
FieldMetadataType.NUMBER,
getNumberFilterType(
(settings as FieldMetadataSettings<FieldMetadataType.NUMBER>)
?.dataType,
),
],
[FieldMetadataType.NUMERIC, BigFloatFilterType], [FieldMetadataType.NUMERIC, BigFloatFilterType],
[FieldMetadataType.PROBABILITY, FloatFilterType], [FieldMetadataType.PROBABILITY, FloatFilterType],
[FieldMetadataType.POSITION, FloatFilterType], [FieldMetadataType.POSITION, FloatFilterType],

View File

@ -0,0 +1,24 @@
import { GraphQLInputObjectType } from 'graphql';
import { NumberDataType } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import {
BigIntFilterType,
FloatFilterType,
IntFilterType,
} from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/input';
export const getNumberFilterType = (
subType: NumberDataType | undefined,
): GraphQLInputObjectType => {
switch (subType) {
case NumberDataType.FLOAT:
return FloatFilterType;
case NumberDataType.BIGINT:
return BigIntFilterType;
case NumberDataType.INT:
return IntFilterType;
default:
return FloatFilterType;
}
};

View File

@ -0,0 +1,19 @@
import { GraphQLInt, GraphQLFloat, GraphQLScalarType } from 'graphql';
import { GraphQLBigInt } from 'graphql-scalars';
import { NumberDataType } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
export const getNumberScalarType = (
dataType: NumberDataType,
): GraphQLScalarType => {
switch (dataType) {
case NumberDataType.FLOAT:
return GraphQLFloat;
case NumberDataType.BIGINT:
return GraphQLBigInt;
case NumberDataType.INT:
return GraphQLInt;
default:
return GraphQLFloat;
}
};

View File

@ -1,11 +1,17 @@
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
export enum NumberDataType {
FLOAT = 'float',
INT = 'int',
BIGINT = 'bigint',
}
type FieldMetadataDefaultSettings = { type FieldMetadataDefaultSettings = {
isForeignKey?: boolean; isForeignKey?: boolean;
}; };
type FieldMetadataNumberSettings = { type FieldMetadataNumberSettings = {
precision: number; dataType: NumberDataType;
}; };
type FieldMetadataSettingsMapping = { type FieldMetadataSettingsMapping = {

View File

@ -8,12 +8,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import console from 'console'; import console from 'console';
import { import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
DataSource,
FindManyOptions,
FindOneOptions,
Repository,
} from 'typeorm';
import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm';
import { Query, QueryOptions } from '@ptc-org/nestjs-query-core'; import { Query, QueryOptions } from '@ptc-org/nestjs-query-core';
@ -57,7 +52,6 @@ import {
import { createWorkspaceMigrationsForCustomObjectRelations } from 'src/engine/metadata-modules/object-metadata/utils/create-migrations-for-custom-object-relations.util'; import { createWorkspaceMigrationsForCustomObjectRelations } from 'src/engine/metadata-modules/object-metadata/utils/create-migrations-for-custom-object-relations.util';
import { createWorkspaceMigrationsForRemoteObjectRelations } from 'src/engine/metadata-modules/object-metadata/utils/create-workspace-migrations-for-remote-object-relations.util'; import { createWorkspaceMigrationsForRemoteObjectRelations } from 'src/engine/metadata-modules/object-metadata/utils/create-workspace-migrations-for-remote-object-relations.util';
import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { validateObjectMetadataInputOrThrow } from 'src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util'; import { validateObjectMetadataInputOrThrow } from 'src/engine/metadata-modules/object-metadata/utils/validate-object-metadata-input.util';
import { mapUdtNameToFieldType } from 'src/engine/metadata-modules/remote-server/remote-table/utils/udt-name-mapper.util'; import { mapUdtNameToFieldType } from 'src/engine/metadata-modules/remote-server/remote-table/utils/udt-name-mapper.util';
import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service'; import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service';
@ -380,9 +374,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
await this.createObjectRelationsMetadataAndMigrations( await this.createObjectRelationsMetadataAndMigrations(
objectMetadataInput, objectMetadataInput,
createdObjectMetadata, createdObjectMetadata,
lastDataSourceMetadata,
workspaceDataSource,
objectMetadataInput.isRemote,
); );
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations( await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
@ -515,10 +506,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
private async createObjectRelationsMetadataAndMigrations( private async createObjectRelationsMetadataAndMigrations(
objectMetadataInput: CreateObjectInput, objectMetadataInput: CreateObjectInput,
createdObjectMetadata: ObjectMetadataEntity, createdObjectMetadata: ObjectMetadataEntity,
lastDataSourceMetadata: DataSourceEntity,
workspaceDataSource: DataSource | undefined,
isRemoteObject = false,
) { ) {
const isRemoteObject = objectMetadataInput.isRemote ?? false;
const { timelineActivityObjectMetadata } = const { timelineActivityObjectMetadata } =
await this.createTimelineActivityRelation( await this.createTimelineActivityRelation(
objectMetadataInput.workspaceId, objectMetadataInput.workspaceId,
@ -527,6 +517,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectMetadataInput.primaryKeyColumnType ?? 'uuid', objectMetadataInput.primaryKeyColumnType ?? 'uuid',
), ),
objectMetadataInput.primaryKeyFieldMetadataSettings, objectMetadataInput.primaryKeyFieldMetadataSettings,
isRemoteObject,
); );
const { activityTargetObjectMetadata } = const { activityTargetObjectMetadata } =
@ -537,6 +528,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectMetadataInput.primaryKeyColumnType ?? 'uuid', objectMetadataInput.primaryKeyColumnType ?? 'uuid',
), ),
objectMetadataInput.primaryKeyFieldMetadataSettings, objectMetadataInput.primaryKeyFieldMetadataSettings,
isRemoteObject,
); );
const { favoriteObjectMetadata } = await this.createFavoriteRelation( const { favoriteObjectMetadata } = await this.createFavoriteRelation(
@ -544,6 +536,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
createdObjectMetadata, createdObjectMetadata,
mapUdtNameToFieldType(objectMetadataInput.primaryKeyColumnType ?? 'uuid'), mapUdtNameToFieldType(objectMetadataInput.primaryKeyColumnType ?? 'uuid'),
objectMetadataInput.primaryKeyFieldMetadataSettings, objectMetadataInput.primaryKeyFieldMetadataSettings,
isRemoteObject,
); );
const { attachmentObjectMetadata } = await this.createAttachmentRelation( const { attachmentObjectMetadata } = await this.createAttachmentRelation(
@ -551,6 +544,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
createdObjectMetadata, createdObjectMetadata,
mapUdtNameToFieldType(objectMetadataInput.primaryKeyColumnType ?? 'uuid'), mapUdtNameToFieldType(objectMetadataInput.primaryKeyColumnType ?? 'uuid'),
objectMetadataInput.primaryKeyFieldMetadataSettings, objectMetadataInput.primaryKeyFieldMetadataSettings,
isRemoteObject,
); );
return this.workspaceMigrationService.createCustomMigration( return this.workspaceMigrationService.createCustomMigration(
@ -563,9 +557,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
attachmentObjectMetadata, attachmentObjectMetadata,
timelineActivityObjectMetadata, timelineActivityObjectMetadata,
favoriteObjectMetadata, favoriteObjectMetadata,
lastDataSourceMetadata.schema,
objectMetadataInput.primaryKeyColumnType ?? 'uuid', objectMetadataInput.primaryKeyColumnType ?? 'uuid',
workspaceDataSource,
) )
: createWorkspaceMigrationsForCustomObjectRelations( : createWorkspaceMigrationsForCustomObjectRelations(
createdObjectMetadata, createdObjectMetadata,
@ -584,6 +576,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectPrimaryKeyFieldSettings: objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'> | FieldMetadataSettings<FieldMetadataType | 'default'>
| undefined, | undefined,
isRemoteObject: boolean,
) { ) {
const activityTargetObjectMetadata = const activityTargetObjectMetadata =
await this.objectMetadataRepository.findOneByOrFail({ await this.objectMetadataRepository.findOneByOrFail({
@ -591,88 +584,93 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
workspaceId: workspaceId, workspaceId: workspaceId,
}); });
const activityTargetRelationFieldMetadata = await this.fieldMetadataRepository.save(
await this.fieldMetadataRepository.save([ // Foreign key
// FROM {
standardId: createForeignKeyDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: activityTargetObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: objectPrimaryKeyType,
name: `${createdObjectMetadata.nameSingular}Id`,
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
description: `ActivityTarget ${createdObjectMetadata.labelSingular} id foreign key`,
icon: undefined,
isNullable: true,
isSystem: true,
defaultValue: undefined,
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
},
);
if (!isRemoteObject) {
const activityTargetRelationFieldMetadata =
await this.fieldMetadataRepository.save([
// FROM
{
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.activityTargets,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: 'activityTargets',
label: 'Activities',
description: `Activities tied to the ${createdObjectMetadata.labelSingular}`,
icon: 'IconCheckbox',
isNullable: true,
},
// TO
{
standardId: createRelationDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: activityTargetObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: createdObjectMetadata.nameSingular,
label: createdObjectMetadata.labelSingular,
description: `ActivityTarget ${createdObjectMetadata.labelSingular}`,
icon: 'IconBuildingSkyscraper',
isNullable: true,
},
]);
const activityTargetRelationFieldMetadataMap =
activityTargetRelationFieldMetadata.reduce(
(acc, fieldMetadata: FieldMetadataEntity) => {
if (fieldMetadata.type === FieldMetadataType.RELATION) {
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
}
return acc;
},
{},
);
await this.relationMetadataRepository.save([
{ {
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.activityTargets,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId, workspaceId: workspaceId,
isCustom: false, relationType: RelationMetadataType.ONE_TO_MANY,
isActive: true, fromObjectMetadataId: createdObjectMetadata.id,
type: FieldMetadataType.RELATION, toObjectMetadataId: activityTargetObjectMetadata.id,
name: 'activityTargets', fromFieldMetadataId:
label: 'Activities', activityTargetRelationFieldMetadataMap[createdObjectMetadata.id].id,
description: `Activities tied to the ${createdObjectMetadata.labelSingular}`, toFieldMetadataId:
icon: 'IconCheckbox', activityTargetRelationFieldMetadataMap[
isNullable: true, activityTargetObjectMetadata.id
}, ].id,
// TO onDeleteAction: RelationOnDeleteAction.CASCADE,
{
standardId: createRelationDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: activityTargetObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: createdObjectMetadata.nameSingular,
label: createdObjectMetadata.labelSingular,
description: `ActivityTarget ${createdObjectMetadata.labelSingular}`,
icon: 'IconBuildingSkyscraper',
isNullable: true,
},
// Foreign key
{
standardId: createForeignKeyDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: ACTIVITY_TARGET_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: activityTargetObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: objectPrimaryKeyType,
name: `${createdObjectMetadata.nameSingular}Id`,
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
description: `ActivityTarget ${createdObjectMetadata.labelSingular} id foreign key`,
icon: undefined,
isNullable: true,
isSystem: true,
defaultValue: undefined,
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
}, },
]); ]);
}
const activityTargetRelationFieldMetadataMap =
activityTargetRelationFieldMetadata.reduce(
(acc, fieldMetadata: FieldMetadataEntity) => {
if (fieldMetadata.type === FieldMetadataType.RELATION) {
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
}
return acc;
},
{},
);
await this.relationMetadataRepository.save([
{
workspaceId: workspaceId,
relationType: RelationMetadataType.ONE_TO_MANY,
fromObjectMetadataId: createdObjectMetadata.id,
toObjectMetadataId: activityTargetObjectMetadata.id,
fromFieldMetadataId:
activityTargetRelationFieldMetadataMap[createdObjectMetadata.id].id,
toFieldMetadataId:
activityTargetRelationFieldMetadataMap[
activityTargetObjectMetadata.id
].id,
onDeleteAction: RelationOnDeleteAction.CASCADE,
},
]);
return { activityTargetObjectMetadata }; return { activityTargetObjectMetadata };
} }
@ -684,6 +682,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectPrimaryKeyFieldSettings: objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'> | FieldMetadataSettings<FieldMetadataType | 'default'>
| undefined, | undefined,
isRemoteObject: boolean,
) { ) {
const attachmentObjectMetadata = const attachmentObjectMetadata =
await this.objectMetadataRepository.findOneByOrFail({ await this.objectMetadataRepository.findOneByOrFail({
@ -691,86 +690,91 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
workspaceId: workspaceId, workspaceId: workspaceId,
}); });
const attachmentRelationFieldMetadata = await this.fieldMetadataRepository.save(
await this.fieldMetadataRepository.save([ // Foreign key
// FROM {
standardId: createForeignKeyDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: ATTACHMENT_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: attachmentObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: objectPrimaryKeyType,
name: `${createdObjectMetadata.nameSingular}Id`,
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
description: `Attachment ${createdObjectMetadata.labelSingular} id foreign key`,
icon: undefined,
isNullable: true,
isSystem: true,
defaultValue: undefined,
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
},
);
if (!isRemoteObject) {
const attachmentRelationFieldMetadata =
await this.fieldMetadataRepository.save([
// FROM
{
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.attachments,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: 'attachments',
label: 'Attachments',
description: `Attachments tied to the ${createdObjectMetadata.labelSingular}`,
icon: 'IconFileImport',
isNullable: true,
},
// TO
{
standardId: createRelationDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: ATTACHMENT_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: attachmentObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: createdObjectMetadata.nameSingular,
label: createdObjectMetadata.labelSingular,
description: `Attachment ${createdObjectMetadata.labelSingular}`,
icon: 'IconBuildingSkyscraper',
isNullable: true,
},
]);
const attachmentRelationFieldMetadataMap =
attachmentRelationFieldMetadata.reduce(
(acc, fieldMetadata: FieldMetadataEntity) => {
if (fieldMetadata.type === FieldMetadataType.RELATION) {
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
}
return acc;
},
{},
);
await this.relationMetadataRepository.save([
{ {
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.attachments,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId, workspaceId: workspaceId,
isCustom: false, relationType: RelationMetadataType.ONE_TO_MANY,
isActive: true, fromObjectMetadataId: createdObjectMetadata.id,
type: FieldMetadataType.RELATION, toObjectMetadataId: attachmentObjectMetadata.id,
name: 'attachments', fromFieldMetadataId:
label: 'Attachments', attachmentRelationFieldMetadataMap[createdObjectMetadata.id].id,
description: `Attachments tied to the ${createdObjectMetadata.labelSingular}`, toFieldMetadataId:
icon: 'IconFileImport', attachmentRelationFieldMetadataMap[attachmentObjectMetadata.id].id,
isNullable: true, onDeleteAction: RelationOnDeleteAction.CASCADE,
},
// TO
{
standardId: createRelationDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: ATTACHMENT_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: attachmentObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: createdObjectMetadata.nameSingular,
label: createdObjectMetadata.labelSingular,
description: `Attachment ${createdObjectMetadata.labelSingular}`,
icon: 'IconBuildingSkyscraper',
isNullable: true,
},
// Foreign key
{
standardId: createForeignKeyDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: ATTACHMENT_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: attachmentObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: objectPrimaryKeyType,
name: `${createdObjectMetadata.nameSingular}Id`,
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
description: `Attachment ${createdObjectMetadata.labelSingular} id foreign key`,
icon: undefined,
isNullable: true,
isSystem: true,
defaultValue: undefined,
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
}, },
]); ]);
}
const attachmentRelationFieldMetadataMap =
attachmentRelationFieldMetadata.reduce(
(acc, fieldMetadata: FieldMetadataEntity) => {
if (fieldMetadata.type === FieldMetadataType.RELATION) {
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
}
return acc;
},
{},
);
await this.relationMetadataRepository.save([
{
workspaceId: workspaceId,
relationType: RelationMetadataType.ONE_TO_MANY,
fromObjectMetadataId: createdObjectMetadata.id,
toObjectMetadataId: attachmentObjectMetadata.id,
fromFieldMetadataId:
attachmentRelationFieldMetadataMap[createdObjectMetadata.id].id,
toFieldMetadataId:
attachmentRelationFieldMetadataMap[attachmentObjectMetadata.id].id,
onDeleteAction: RelationOnDeleteAction.CASCADE,
},
]);
return { attachmentObjectMetadata }; return { attachmentObjectMetadata };
} }
@ -782,6 +786,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectPrimaryKeyFieldSettings: objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'> | FieldMetadataSettings<FieldMetadataType | 'default'>
| undefined, | undefined,
isRemoteObject: boolean,
) { ) {
const timelineActivityObjectMetadata = const timelineActivityObjectMetadata =
await this.objectMetadataRepository.findOneByOrFail({ await this.objectMetadataRepository.findOneByOrFail({
@ -789,88 +794,94 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
workspaceId: workspaceId, workspaceId: workspaceId,
}); });
const timelineActivityRelationFieldMetadata = await this.fieldMetadataRepository.save(
await this.fieldMetadataRepository.save([ // Foreign key
// FROM {
standardId: createForeignKeyDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: timelineActivityObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: objectPrimaryKeyType,
name: `${createdObjectMetadata.nameSingular}Id`,
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
description: `Timeline Activity ${createdObjectMetadata.labelSingular} id foreign key`,
icon: undefined,
isNullable: true,
isSystem: true,
defaultValue: undefined,
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
},
);
if (!isRemoteObject) {
const timelineActivityRelationFieldMetadata =
await this.fieldMetadataRepository.save([
// FROM
{
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.timelineActivities,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: 'timelineActivities',
label: 'Timeline Activities',
description: `Timeline Activities tied to the ${createdObjectMetadata.labelSingular}`,
icon: 'IconTimeline',
isNullable: true,
},
// TO
{
standardId: createRelationDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: timelineActivityObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: createdObjectMetadata.nameSingular,
label: createdObjectMetadata.labelSingular,
description: `Timeline Activity ${createdObjectMetadata.labelSingular}`,
icon: 'IconBuildingSkyscraper',
isNullable: true,
},
]);
const timelineActivityRelationFieldMetadataMap =
timelineActivityRelationFieldMetadata.reduce(
(acc, fieldMetadata: FieldMetadataEntity) => {
if (fieldMetadata.type === FieldMetadataType.RELATION) {
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
}
return acc;
},
{},
);
await this.relationMetadataRepository.save([
{ {
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.timelineActivities,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId, workspaceId: workspaceId,
isCustom: false, relationType: RelationMetadataType.ONE_TO_MANY,
isActive: true, fromObjectMetadataId: createdObjectMetadata.id,
type: FieldMetadataType.RELATION, toObjectMetadataId: timelineActivityObjectMetadata.id,
name: 'timelineActivities', fromFieldMetadataId:
label: 'Timeline Activities', timelineActivityRelationFieldMetadataMap[createdObjectMetadata.id]
description: `Timeline Activities tied to the ${createdObjectMetadata.labelSingular}`, .id,
icon: 'IconTimeline', toFieldMetadataId:
isNullable: true, timelineActivityRelationFieldMetadataMap[
}, timelineActivityObjectMetadata.id
// TO ].id,
{ onDeleteAction: RelationOnDeleteAction.CASCADE,
standardId: createRelationDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: timelineActivityObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: createdObjectMetadata.nameSingular,
label: createdObjectMetadata.labelSingular,
description: `Timeline Activity ${createdObjectMetadata.labelSingular}`,
icon: 'IconBuildingSkyscraper',
isNullable: true,
},
// Foreign key
{
standardId: createForeignKeyDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: timelineActivityObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: objectPrimaryKeyType,
name: `${createdObjectMetadata.nameSingular}Id`,
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
description: `Timeline Activity ${createdObjectMetadata.labelSingular} id foreign key`,
icon: undefined,
isNullable: true,
isSystem: true,
defaultValue: undefined,
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
}, },
]); ]);
}
const timelineActivityRelationFieldMetadataMap =
timelineActivityRelationFieldMetadata.reduce(
(acc, fieldMetadata: FieldMetadataEntity) => {
if (fieldMetadata.type === FieldMetadataType.RELATION) {
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
}
return acc;
},
{},
);
await this.relationMetadataRepository.save([
{
workspaceId: workspaceId,
relationType: RelationMetadataType.ONE_TO_MANY,
fromObjectMetadataId: createdObjectMetadata.id,
toObjectMetadataId: timelineActivityObjectMetadata.id,
fromFieldMetadataId:
timelineActivityRelationFieldMetadataMap[createdObjectMetadata.id].id,
toFieldMetadataId:
timelineActivityRelationFieldMetadataMap[
timelineActivityObjectMetadata.id
].id,
onDeleteAction: RelationOnDeleteAction.CASCADE,
},
]);
return { timelineActivityObjectMetadata }; return { timelineActivityObjectMetadata };
} }
@ -882,6 +893,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
objectPrimaryKeyFieldSettings: objectPrimaryKeyFieldSettings:
| FieldMetadataSettings<FieldMetadataType | 'default'> | FieldMetadataSettings<FieldMetadataType | 'default'>
| undefined, | undefined,
isRemoteObject: boolean,
) { ) {
const favoriteObjectMetadata = const favoriteObjectMetadata =
await this.objectMetadataRepository.findOneByOrFail({ await this.objectMetadataRepository.findOneByOrFail({
@ -889,87 +901,92 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
workspaceId: workspaceId, workspaceId: workspaceId,
}); });
const favoriteRelationFieldMetadata = await this.fieldMetadataRepository.save(
await this.fieldMetadataRepository.save([ // Foreign key
// FROM {
standardId: createForeignKeyDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: FAVORITE_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: favoriteObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: objectPrimaryKeyType,
name: `${createdObjectMetadata.nameSingular}Id`,
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
description: `Favorite ${createdObjectMetadata.labelSingular} id foreign key`,
icon: undefined,
isNullable: true,
isSystem: true,
defaultValue: undefined,
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
},
);
if (!isRemoteObject) {
const favoriteRelationFieldMetadata =
await this.fieldMetadataRepository.save([
// FROM
{
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.favorites,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
isSystem: true,
type: FieldMetadataType.RELATION,
name: 'favorites',
label: 'Favorites',
description: `Favorites tied to the ${createdObjectMetadata.labelSingular}`,
icon: 'IconHeart',
isNullable: true,
},
// TO
{
standardId: createRelationDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: FAVORITE_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: favoriteObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: createdObjectMetadata.nameSingular,
label: createdObjectMetadata.labelSingular,
description: `Favorite ${createdObjectMetadata.labelSingular}`,
icon: 'IconBuildingSkyscraper',
isNullable: true,
},
]);
const favoriteRelationFieldMetadataMap =
favoriteRelationFieldMetadata.reduce(
(acc, fieldMetadata: FieldMetadataEntity) => {
if (fieldMetadata.type === FieldMetadataType.RELATION) {
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
}
return acc;
},
{},
);
await this.relationMetadataRepository.save([
{ {
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.favorites,
objectMetadataId: createdObjectMetadata.id,
workspaceId: workspaceId, workspaceId: workspaceId,
isCustom: false, relationType: RelationMetadataType.ONE_TO_MANY,
isActive: true, fromObjectMetadataId: createdObjectMetadata.id,
isSystem: true, toObjectMetadataId: favoriteObjectMetadata.id,
type: FieldMetadataType.RELATION, fromFieldMetadataId:
name: 'favorites', favoriteRelationFieldMetadataMap[createdObjectMetadata.id].id,
label: 'Favorites', toFieldMetadataId:
description: `Favorites tied to the ${createdObjectMetadata.labelSingular}`, favoriteRelationFieldMetadataMap[favoriteObjectMetadata.id].id,
icon: 'IconHeart', onDeleteAction: RelationOnDeleteAction.CASCADE,
isNullable: true,
},
// TO
{
standardId: createRelationDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: FAVORITE_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: favoriteObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: FieldMetadataType.RELATION,
name: createdObjectMetadata.nameSingular,
label: createdObjectMetadata.labelSingular,
description: `Favorite ${createdObjectMetadata.labelSingular}`,
icon: 'IconBuildingSkyscraper',
isNullable: true,
},
// Foreign key
{
standardId: createForeignKeyDeterministicUuid({
objectId: createdObjectMetadata.id,
standardId: FAVORITE_STANDARD_FIELD_IDS.custom,
}),
objectMetadataId: favoriteObjectMetadata.id,
workspaceId: workspaceId,
isCustom: false,
isActive: true,
type: objectPrimaryKeyType,
name: `${createdObjectMetadata.nameSingular}Id`,
label: `${createdObjectMetadata.labelSingular} ID (foreign key)`,
description: `Favorite ${createdObjectMetadata.labelSingular} id foreign key`,
icon: undefined,
isNullable: true,
isSystem: true,
defaultValue: undefined,
settings: { ...objectPrimaryKeyFieldSettings, isForeignKey: true },
}, },
]); ]);
}
const favoriteRelationFieldMetadataMap =
favoriteRelationFieldMetadata.reduce(
(acc, fieldMetadata: FieldMetadataEntity) => {
if (fieldMetadata.type === FieldMetadataType.RELATION) {
acc[fieldMetadata.objectMetadataId] = fieldMetadata;
}
return acc;
},
{},
);
await this.relationMetadataRepository.save([
{
workspaceId: workspaceId,
relationType: RelationMetadataType.ONE_TO_MANY,
fromObjectMetadataId: createdObjectMetadata.id,
toObjectMetadataId: favoriteObjectMetadata.id,
fromFieldMetadataId:
favoriteRelationFieldMetadataMap[createdObjectMetadata.id].id,
toFieldMetadataId:
favoriteRelationFieldMetadataMap[favoriteObjectMetadata.id].id,
onDeleteAction: RelationOnDeleteAction.CASCADE,
},
]);
return { favoriteObjectMetadata }; return { favoriteObjectMetadata };
} }

View File

@ -13,7 +13,7 @@ export const createWorkspaceMigrationsForCustomObjectRelations = (
createdObjectMetadata: ObjectMetadataEntity, createdObjectMetadata: ObjectMetadataEntity,
activityTargetObjectMetadata: ObjectMetadataEntity, activityTargetObjectMetadata: ObjectMetadataEntity,
attachmentObjectMetadata: ObjectMetadataEntity, attachmentObjectMetadata: ObjectMetadataEntity,
eventObjectMetadata: ObjectMetadataEntity, timelineActivityObjectMetadata: ObjectMetadataEntity,
favoriteObjectMetadata: ObjectMetadataEntity, favoriteObjectMetadata: ObjectMetadataEntity,
): WorkspaceMigrationTableAction[] => [ ): WorkspaceMigrationTableAction[] => [
{ {
@ -80,9 +80,9 @@ export const createWorkspaceMigrationsForCustomObjectRelations = (
}, },
], ],
}, },
// Add event relation // Add timeline activity relation
{ {
name: computeObjectTargetTable(eventObjectMetadata), name: computeObjectTargetTable(timelineActivityObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER, action: WorkspaceMigrationTableActionType.ALTER,
columns: [ columns: [
{ {
@ -96,7 +96,7 @@ export const createWorkspaceMigrationsForCustomObjectRelations = (
], ],
}, },
{ {
name: computeObjectTargetTable(eventObjectMetadata), name: computeObjectTargetTable(timelineActivityObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER, action: WorkspaceMigrationTableActionType.ALTER,
columns: [ columns: [
{ {

View File

@ -1,5 +1,3 @@
import { DataSource } from 'typeorm';
import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util'; import { computeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { import {
@ -10,55 +8,14 @@ import {
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity'; } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
const buildCommentForRemoteObjectForeignKey = async (
localObjectMetadataName: string,
remoteObjectMetadataName: string,
schema: string,
workspaceDataSource: DataSource | undefined,
): Promise<string> => {
const existingComment = await workspaceDataSource?.query(
`SELECT col_description('${schema}."${localObjectMetadataName}"'::regclass, 0)`,
);
if (!existingComment[0]?.col_description) {
return `@graphql({"totalCount":{"enabled": true},"foreign_keys":[{"local_name":"${localObjectMetadataName}Collection","local_columns":["${remoteObjectMetadataName}Id"],"foreign_name":"${remoteObjectMetadataName}","foreign_schema":"${schema}","foreign_table":"${remoteObjectMetadataName}","foreign_columns":["id"]}]})`;
}
const commentWithoutGraphQL = existingComment[0].col_description
.replace('@graphql(', '')
.replace(')', '');
const parsedComment = JSON.parse(commentWithoutGraphQL);
const foreignKey = {
local_name: `${localObjectMetadataName}Collection`,
local_columns: [`${remoteObjectMetadataName}Id`],
foreign_name: `${remoteObjectMetadataName}`,
foreign_schema: schema,
foreign_table: remoteObjectMetadataName,
foreign_columns: ['id'],
};
if (parsedComment.foreign_keys) {
parsedComment.foreign_keys.push(foreignKey);
} else {
parsedComment.foreign_keys = [foreignKey];
}
return `@graphql(${JSON.stringify(parsedComment)})`;
};
export const createWorkspaceMigrationsForRemoteObjectRelations = async ( export const createWorkspaceMigrationsForRemoteObjectRelations = async (
createdObjectMetadata: ObjectMetadataEntity, createdObjectMetadata: ObjectMetadataEntity,
activityTargetObjectMetadata: ObjectMetadataEntity, activityTargetObjectMetadata: ObjectMetadataEntity,
attachmentObjectMetadata: ObjectMetadataEntity, attachmentObjectMetadata: ObjectMetadataEntity,
eventObjectMetadata: ObjectMetadataEntity, timelineActivityObjectMetadata: ObjectMetadataEntity,
favoriteObjectMetadata: ObjectMetadataEntity, favoriteObjectMetadata: ObjectMetadataEntity,
schema: string,
primaryKeyColumnType: string, primaryKeyColumnType: string,
workspaceDataSource: DataSource | undefined,
): Promise<WorkspaceMigrationTableAction[]> => { ): Promise<WorkspaceMigrationTableAction[]> => {
const createdObjectName = createdObjectMetadata.nameSingular;
return [ return [
{ {
name: computeObjectTargetTable(activityTargetObjectMetadata), name: computeObjectTargetTable(activityTargetObjectMetadata),
@ -74,22 +31,6 @@ export const createWorkspaceMigrationsForRemoteObjectRelations = async (
} satisfies WorkspaceMigrationColumnCreate, } satisfies WorkspaceMigrationColumnCreate,
], ],
}, },
{
name: computeObjectTargetTable(activityTargetObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE_COMMENT,
comment: await buildCommentForRemoteObjectForeignKey(
activityTargetObjectMetadata.nameSingular,
createdObjectName,
schema,
workspaceDataSource,
),
},
],
},
// Add attachment relation
{ {
name: computeObjectTargetTable(attachmentObjectMetadata), name: computeObjectTargetTable(attachmentObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER, action: WorkspaceMigrationTableActionType.ALTER,
@ -105,53 +46,7 @@ export const createWorkspaceMigrationsForRemoteObjectRelations = async (
], ],
}, },
{ {
name: computeObjectTargetTable(attachmentObjectMetadata), name: computeObjectTargetTable(timelineActivityObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE_COMMENT,
comment: await buildCommentForRemoteObjectForeignKey(
attachmentObjectMetadata.nameSingular,
createdObjectName,
schema,
workspaceDataSource,
),
},
],
},
// Add event relation
{
name: computeObjectTargetTable(eventObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE,
columnName: computeColumnName(createdObjectMetadata.nameSingular, {
isForeignKey: true,
}),
columnType: primaryKeyColumnType,
isNullable: true,
} satisfies WorkspaceMigrationColumnCreate,
],
},
{
name: computeObjectTargetTable(eventObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE_COMMENT,
comment: await buildCommentForRemoteObjectForeignKey(
eventObjectMetadata.nameSingular,
createdObjectName,
schema,
workspaceDataSource,
),
},
],
},
// Add favorite relation
{
name: computeObjectTargetTable(favoriteObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER, action: WorkspaceMigrationTableActionType.ALTER,
columns: [ columns: [
{ {
@ -169,14 +64,13 @@ export const createWorkspaceMigrationsForRemoteObjectRelations = async (
action: WorkspaceMigrationTableActionType.ALTER, action: WorkspaceMigrationTableActionType.ALTER,
columns: [ columns: [
{ {
action: WorkspaceMigrationColumnActionType.CREATE_COMMENT, action: WorkspaceMigrationColumnActionType.CREATE,
comment: await buildCommentForRemoteObjectForeignKey( columnName: computeColumnName(createdObjectMetadata.nameSingular, {
favoriteObjectMetadata.nameSingular, isForeignKey: true,
createdObjectName, }),
schema, columnType: primaryKeyColumnType,
workspaceDataSource, isNullable: true,
), } satisfies WorkspaceMigrationColumnCreate,
},
], ],
}, },
]; ];

View File

@ -1,4 +1,7 @@
import { FieldMetadataSettings } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface'; import {
FieldMetadataSettings,
NumberDataType,
} from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
@ -8,8 +11,6 @@ export const mapUdtNameToFieldType = (udtName: string): FieldMetadataType => {
return FieldMetadataType.UUID; return FieldMetadataType.UUID;
case 'varchar': case 'varchar':
case 'text': case 'text':
case 'bigint':
case 'int8':
return FieldMetadataType.TEXT; return FieldMetadataType.TEXT;
case 'bool': case 'bool':
return FieldMetadataType.BOOLEAN; return FieldMetadataType.BOOLEAN;
@ -19,6 +20,8 @@ export const mapUdtNameToFieldType = (udtName: string): FieldMetadataType => {
case 'integer': case 'integer':
case 'int2': case 'int2':
case 'int4': case 'int4':
case 'int8':
case 'bigint':
return FieldMetadataType.NUMBER; return FieldMetadataType.NUMBER;
default: default:
return FieldMetadataType.TEXT; return FieldMetadataType.TEXT;
@ -33,7 +36,12 @@ export const mapUdtNameToFieldSettings = (
case 'int2': case 'int2':
case 'int4': case 'int4':
return { return {
precision: 0, dataType: NumberDataType.INT,
} satisfies FieldMetadataSettings<FieldMetadataType.NUMBER>;
case 'int8':
case 'bigint':
return {
dataType: NumberDataType.BIGINT,
} satisfies FieldMetadataSettings<FieldMetadataType.NUMBER>; } satisfies FieldMetadataSettings<FieldMetadataType.NUMBER>;
default: default:
return undefined; return undefined;

View File

@ -28910,6 +28910,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"graphql-scalars@npm:^1.23.0":
version: 1.23.0
resolution: "graphql-scalars@npm:1.23.0"
dependencies:
tslib: "npm:^2.5.0"
peerDependencies:
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
checksum: 7666c305b8367528c4fbb583a2731d93d52f36043d71f4957ecc1d2db71d710d268e25535243beb1b2497db921daa94d3cfa83daaf4a3101a667f358ddbf3436
languageName: node
linkType: hard
"graphql-shield@npm:^7.5.0": "graphql-shield@npm:^7.5.0":
version: 7.6.5 version: 7.6.5
resolution: "graphql-shield@npm:7.6.5" resolution: "graphql-shield@npm:7.6.5"
@ -46585,6 +46596,7 @@ __metadata:
graphql-fields: "npm:^2.0.3" graphql-fields: "npm:^2.0.3"
graphql-middleware: "npm:^6.1.35" graphql-middleware: "npm:^6.1.35"
graphql-rate-limit: "npm:^3.3.0" graphql-rate-limit: "npm:^3.3.0"
graphql-scalars: "npm:^1.23.0"
graphql-subscriptions: "npm:2.0.0" graphql-subscriptions: "npm:2.0.0"
graphql-tag: "npm:^2.12.6" graphql-tag: "npm:^2.12.6"
graphql-type-json: "npm:^0.3.2" graphql-type-json: "npm:^0.3.2"