From 1cf08c797fbcc50539cc60ca74dc260a0dbe220c Mon Sep 17 00:00:00 2001 From: Weiko Date: Thu, 9 Nov 2023 20:06:10 +0100 Subject: [PATCH] Convert metadata tables to camelCase (#2400) * Convert metadata tables to camelCase * datasourcemetadataid to datasourceid * refactor metadata folders * fix command * move commands out of metadata * fix seed * rename objectId and fieldId in objectMetadataId and fieldMetadataId in FE * fix field-metadata * Fix * Fix * remove logs --------- Co-authored-by: Charles Bochet --- front/src/generated-metadata/graphql.ts | 54 ++++++- front/src/generated/graphql.tsx | 39 +++++ .../ActivityAssigneeEditableField.tsx | 2 +- .../components/ActivityEditorDateField.tsx | 2 +- .../tasks/hooks/useCurrentUserDueTaskCount.ts | 2 +- .../companies/components/CompanyBoardCard.tsx | 6 +- .../companiesAvailableFieldDefinitions.tsx | 24 +-- .../metadata/components/RecordShowPage.tsx | 8 +- .../metadata/hooks/useCreateOneObject.ts | 1 + .../metadata/hooks/useFindOneObject.ts | 10 +- .../metadata/hooks/useMetadataField.ts | 10 +- .../hooks/useUpdateOneMetadataField.ts | 6 +- .../formatMetadataFieldAsColumnDefinition.ts | 2 +- .../formatMetadataFieldAsFilterDefinition.ts | 2 +- .../formatMetadataFieldAsSortDefinition.ts | 2 +- .../utils/generateFindOneCustomObjectQuery.ts | 4 +- .../peopleAvailableFieldDefinitions.tsx | 18 +-- .../pipelineAvailableFieldDefinitions.tsx | 8 +- .../components/SettingsObjectFieldPreview.tsx | 2 +- front/src/modules/types/AppPath.ts | 2 +- .../layout/board/hooks/useBoardCardFields.ts | 2 +- .../boardCardFieldsByKeyScopedSelector.ts | 2 +- .../hiddenBoardCardFieldsScopedSelector.ts | 4 +- ...savedBoardCardFieldsByKeyFamilySelector.ts | 2 +- .../field/hooks/useFieldInitialValue.ts | 2 +- .../ui/object/field/hooks/useIsFieldEmpty.ts | 2 +- .../__stories__/DateFieldDisplay.stories.tsx | 2 +- .../DoubleTextFieldDisplay.stories.tsx | 2 +- .../__stories__/EmailFieldDisplay.stories.tsx | 2 +- .../__stories__/MoneyFieldDisplay.stories.tsx | 2 +- .../NumberFieldDisplay.stories.tsx | 2 +- .../__stories__/PhoneFieldDisplay.stories.tsx | 2 +- .../__stories__/TextFieldDisplay.stories.tsx | 2 +- .../__stories__/URLFieldDisplay.stories.tsx | 2 +- .../__stories__/BooleanFieldInput.stories.tsx | 2 +- .../__stories__/ChipFieldInput.stories.tsx | 2 +- .../__stories__/DateFieldInput.stories.tsx | 2 +- .../DoubleTextChipFieldInput.stories.tsx | 2 +- .../DoubleTextFieldInput.stories.tsx | 2 +- .../__stories__/EmailFieldInput.stories.tsx | 2 +- .../__stories__/MoneyFieldInput.stories.tsx | 2 +- .../__stories__/NumberFieldInput.stories.tsx | 2 +- .../__stories__/PhoneFieldInput.stories.tsx | 2 +- .../ProbabilityFieldInput.stories.tsx | 2 +- .../RelationFieldInput.stories.tsx | 2 +- .../__stories__/TextFieldInput.stories.tsx | 2 +- .../__stories__/URLFieldInput.stories.tsx | 2 +- .../entityFieldInitialValueFamilyState.ts | 2 +- .../isEntityFieldEmptyFamilySelector.ts | 2 +- .../ui/object/field/types/FieldDefinition.ts | 2 +- .../ObjectFilterDropdownDateSearchInput.tsx | 2 +- ...ObjectFilterDropdownEntitySearchSelect.tsx | 4 +- .../ObjectFilterDropdownNumberSearchInput.tsx | 2 +- .../ObjectFilterDropdownOperandSelect.tsx | 2 +- .../ObjectFilterDropdownTextSearchInput.tsx | 2 +- .../object-filter-dropdown/types/Filter.ts | 2 +- .../types/FilterDefinition.ts | 2 +- .../types/FilterDefinitionByEntity.ts | 2 +- .../utils/turnFilterIntoWhereClause.ts | 18 +-- .../utils/turnFiltersIntoWhereClauseV2.ts | 4 +- .../components/ObjectSortDropdownButton.tsx | 2 +- .../object/object-sort-dropdown/types/Sort.ts | 2 +- .../types/SortDefinition.ts | 2 +- .../object-sort-dropdown/utils/helpers.ts | 2 +- .../utils/turnSortsIntoOrderByV2.ts | 4 +- .../components/ColumnHeadWithDropdown.tsx | 4 +- .../RecordTableColumnDropdownMenu.tsx | 2 +- .../components/RecordTableHeader.tsx | 25 +-- .../RecordTableHeaderPlusButtonContent.tsx | 2 +- .../components/RecordTableRow.tsx | 2 +- .../record-table/hooks/useTableColumns.ts | 10 +- .../record-table-cell/hooks/useTableCell.ts | 2 +- .../hiddenTableColumnsScopedSelector.ts | 4 +- .../savedTableColumnsByKeyFamilySelector.ts | 5 +- .../tableColumnsByKeyScopedSelector.ts | 5 +- .../visibleTableColumnsScopedSelector.ts | 5 +- .../views/components/ViewBarDetails.tsx | 12 +- .../views/components/ViewBarEffect.tsx | 11 +- .../ViewFieldsVisibilityDropdownSection.tsx | 8 +- .../views/hooks/internal/useViewFields.ts | 16 +- .../views/hooks/internal/useViewFilters.ts | 25 +-- .../views/hooks/internal/useViewSorts.ts | 19 +-- .../modules/views/hooks/internal/useViews.ts | 2 +- ...savedViewFieldByKeyScopedFamilySelector.ts | 2 +- ...vedViewFiltersByKeyScopedFamilySelector.ts | 2 +- ...savedViewSortsByKeyScopedFamilySelector.ts | 2 +- front/src/modules/views/types/View.ts | 2 +- front/src/modules/views/types/ViewField.ts | 2 +- front/src/modules/views/types/ViewFilter.ts | 2 +- front/src/modules/views/types/ViewSort.ts | 2 +- .../utils/mapColumnDefinitionToViewField.ts | 2 +- .../mapViewFieldsToBoardFieldDefinitions.ts | 4 +- .../utils/mapViewFieldsToColumnDefinitions.ts | 4 +- .../views/utils/mapViewFiltersToFilters.ts | 2 +- .../views/utils/mapViewSortsToSorts.ts | 2 +- front/src/pages/companies/CompanyShow.tsx | 5 +- .../constants/companyShowFieldDefinitions.tsx | 14 +- .../companyTableFilterDefinitions.tsx | 12 +- .../constants/companyTableSortDefinitions.tsx | 10 +- .../opportunityBoardFilterDefinitions.tsx | 8 +- .../opportunityBoardSortDefinitions.tsx | 6 +- .../constants/personShowFieldDefinitions.tsx | 16 +- .../personTableFilterDefinitions.tsx | 14 +- .../constants/personTableSortDefinitions.tsx | 12 +- .../settings/data-model/SettingsNewObject.tsx | 2 +- .../SettingsObjectNewFieldStep1.tsx | 6 +- .../SettingsObjectNewFieldStep2.tsx | 6 +- front/src/pages/tasks/TasksEffect.tsx | 2 +- .../pages/tasks/tasks-filter-definitions.tsx | 2 +- front/src/testing/graphqlMocks.ts | 6 +- front/src/testing/mock-data/metadata.ts | 4 +- front/src/testing/mock-data/view-fields.ts | 44 ++--- front/src/testing/mock-data/views.ts | 8 +- server/ormconfig.ts | 2 +- server/package.json | 2 +- server/src/command.module.ts | 10 +- .../services/workspace.service.spec.ts | 4 +- .../workspace/services/workspace.service.ts | 8 +- server/src/core/workspace/workspace.module.ts | 4 +- .../commands/data-seed-tenant.command.ts | 19 +-- .../commands/database-command.module.ts | 23 ++- server/src/database/seeds/metadata.ts | 4 +- .../typeorm-seeds/metadata/field-metadata.ts | 60 +++---- .../typeorm-seeds/metadata/object-metadata.ts | 2 +- .../typeorm-seeds/tenant/view-fields.ts | 36 ++--- .../database/typeorm-seeds/tenant/views.ts | 15 +- .../metadata/entities/data-source.entity.ts} | 20 +-- .../entities/field-metadata.entity.ts | 102 ++++++++++++ .../entities/object-metadata.entity.ts | 81 ++++++++++ .../entities/relation-metadata.entity.ts | 75 +++++++++ .../entities}/tenant-migration.entity.ts | 4 +- .../typeorm}/metadata/metadata.datasource.ts | 2 +- .../1699543628458-setupMetadataTables.ts | 65 ++++++++ server/src/database/typeorm/typeorm.module.ts | 23 +++ .../src/database/typeorm/typeorm.service.ts | 106 ++++++++++++ .../commands/metadata-command.module.ts | 31 ---- .../data-source-metadata.module.ts | 5 +- .../data-source-metadata.service.spec.ts | 27 ---- .../data-source-metadata.service.ts | 6 +- .../data-source/data-source.module.ts | 12 -- .../data-source/data-source.service.spec.ts | 34 ---- .../data-source/data-source.service.ts | 153 ------------------ .../metadata/data-source/data-source.util.ts | 21 --- .../field-metadata/dtos/create-field.input.ts | 17 +- .../field-metadata/dtos/field-metadata.dto.ts | 81 ++++++++++ .../field-metadata.auto-resolver-opts.ts | 44 ----- .../field-metadata/field-metadata.entity.ts | 141 ---------------- .../field-metadata/field-metadata.module.ts | 44 ++++- .../{services => }/field-metadata.service.ts | 39 ++--- .../hooks/before-create-one-field.hook.ts | 6 +- .../services/field-metadata.service.spec.ts | 43 ----- .../utils/field-metadata.util.spec.ts | 2 +- .../utils/field-metadata.util.ts | 10 +- server/src/metadata/metadata.module.ts | 19 +-- .../migration-runner.module.ts | 13 -- .../migration-runner.service.spec.ts | 32 ---- .../1695214465080-InitMetadataTables.ts | 32 ---- ...695717691800-alter-field-metadata-table.ts | 61 ------- .../1696409050890-add-target-column-map.ts | 71 -------- ...7126636202-MetadataNameLabelRefactoring.ts | 149 ----------------- ...71445015-removeFieldMetadataPlaceholder.ts | 19 --- .../migrations/1697474804403-addSoftDelete.ts | 23 --- ...moveSingularPluralFromFieldLabelAndName.ts | 49 ------ ...467-addNameAndIsCustomToTenantMigration.ts | 55 ------- ...dUniqueConstraintsOnFieldObjectMetadata.ts | 43 ----- .../1698328717102-removeMetadataSoftDelete.ts | 37 ----- .../1699289664146-addRelationMetadata.ts | 39 ----- .../dtos/create-object.input.ts | 12 +- .../dtos/object-metadata.dto.ts | 64 ++++++++ .../hooks/before-create-one-object.hook.ts | 7 +- .../object-metadata.auto-resolver-opts.ts | 44 ----- .../object-metadata/object-metadata.entity.ts | 112 ------------- .../object-metadata/object-metadata.module.ts | 44 ++++- .../{services => }/object-metadata.service.ts | 64 +++----- .../services/object-metadata.service.spec.ts | 38 ----- .../dtos/create-relation.input.ts | 6 +- .../dtos/relation-metadata.dto.ts | 62 +++++++ .../relation-metadata.auto-resolver-opts.ts | 35 ---- .../relation-metadata.entity.ts | 93 ----------- .../relation-metadata.module.ts | 38 ++++- .../relation-metadata.service.ts | 34 ++-- .../tenant-initialisation.service.ts | 90 ----------- .../migrations/1697618009-addCompanyTable.ts | 4 +- .../migrations/1697618011-addViewTable.ts | 6 +- .../1697618012-addViewFieldTable.ts | 6 +- .../1697618013-addViewFilterTable.ts | 6 +- .../migrations/1697618014-addViewSortTable.ts | 6 +- .../tenant-migration.module.ts | 5 +- .../tenant-migration.service.spec.ts | 27 ---- .../tenant-migration.service.ts | 13 +- .../tenant-datasource.module.ts | 13 ++ .../tenant-datasource.service.ts | 101 ++++++++++++ .../commands/sync-tenant-metadata.command.ts | 10 +- .../tenant-manager-commands.module.ts | 12 ++ .../companies/companies.metadata.ts | 0 .../standard-object-metadata.ts | 0 .../view-fields/view-fields.metadata.ts | 4 +- .../view-filters/view-filters.metadata.ts | 4 +- .../view-sorts/view-sorts.metadata.ts | 4 +- .../views/views.metadata.ts | 4 +- .../standard-objects-prefill-data.ts | 58 +++---- .../tenant-manager.module.ts} | 20 +-- .../tenant-manager/tenant-manager.service.ts | 143 ++++++++++++++++ .../commands/run-tenant-migrations.command.ts | 6 +- ...tenant-migration-runner-commands.module.ts | 12 ++ .../tenant-migration-runner.module.ts | 13 ++ .../tenant-migration-runner.service.ts} | 20 +-- .../custom-table-default-column.util.ts | 0 .../factories/create-many-resolver.factory.ts | 8 +- .../factories/create-one-resolver.factory.ts | 12 +- .../factories/delete-one-resolver.factory.ts | 12 +- .../factories/find-many-resolver.factory.ts | 8 +- .../factories/find-one-resolver.factory.ts | 12 +- .../factories/update-one-resolver.factory.ts | 12 +- .../pg-graphql-query-builder.spec.ts | 6 +- .../pg-graphql/pg-graphql-query-runner.ts | 12 +- .../resolver-builder.module.ts | 4 +- .../utils/__tests__/convert-arguments.spec.ts | 8 +- .../convert-fields-to-graphql.spec.ts | 8 +- .../filter-type-definition.factory.ts | 4 +- .../input-type-definition.factory.ts | 4 +- .../object-type-definition.factory.ts | 4 +- .../order-by-type-definition.factory.ts | 4 +- .../schema-builder/graphql-schema.factory.ts | 2 +- ...ld-metadata-target-column-map.interface.ts | 2 +- .../interfaces/field-metadata.interface.ts | 4 +- .../interfaces/param-metadata.interface.ts | 2 +- .../money.object-definition.ts | 2 +- .../url.object-definition.ts | 2 +- .../services/type-mapper.service.ts | 2 +- .../storages/type-definitions.storage.ts | 2 +- .../type-definitions.generator.ts | 6 +- .../__tests__/get-field-metadata-type.spec.ts | 2 +- .../utils/__tests__/get-resolver-args.spec.ts | 2 +- .../utils/get-field-metadata-type.util.ts | 2 +- .../utils/get-resolver-args.util.ts | 2 +- server/src/tenant/tenant.service.spec.ts | 2 +- server/src/tenant/tenant.service.ts | 4 +- 238 files changed, 1851 insertions(+), 2252 deletions(-) rename server/src/{metadata => database}/commands/data-seed-tenant.command.ts (80%) rename server/src/{metadata/data-source-metadata/data-source-metadata.entity.ts => database/typeorm/metadata/entities/data-source.entity.ts} (63%) create mode 100644 server/src/database/typeorm/metadata/entities/field-metadata.entity.ts create mode 100644 server/src/database/typeorm/metadata/entities/object-metadata.entity.ts create mode 100644 server/src/database/typeorm/metadata/entities/relation-metadata.entity.ts rename server/src/{metadata/tenant-migration => database/typeorm/metadata/entities}/tenant-migration.entity.ts (94%) rename server/src/{ => database/typeorm}/metadata/metadata.datasource.ts (92%) create mode 100644 server/src/database/typeorm/metadata/migrations/1699543628458-setupMetadataTables.ts create mode 100644 server/src/database/typeorm/typeorm.module.ts create mode 100644 server/src/database/typeorm/typeorm.service.ts delete mode 100644 server/src/metadata/commands/metadata-command.module.ts delete mode 100644 server/src/metadata/data-source-metadata/data-source-metadata.service.spec.ts delete mode 100644 server/src/metadata/data-source/data-source.module.ts delete mode 100644 server/src/metadata/data-source/data-source.service.spec.ts delete mode 100644 server/src/metadata/data-source/data-source.service.ts delete mode 100644 server/src/metadata/data-source/data-source.util.ts create mode 100644 server/src/metadata/field-metadata/dtos/field-metadata.dto.ts delete mode 100644 server/src/metadata/field-metadata/field-metadata.auto-resolver-opts.ts delete mode 100644 server/src/metadata/field-metadata/field-metadata.entity.ts rename server/src/metadata/field-metadata/{services => }/field-metadata.service.ts (71%) delete mode 100644 server/src/metadata/field-metadata/services/field-metadata.service.spec.ts delete mode 100644 server/src/metadata/migration-runner/migration-runner.module.ts delete mode 100644 server/src/metadata/migration-runner/migration-runner.service.spec.ts delete mode 100644 server/src/metadata/migrations/1695214465080-InitMetadataTables.ts delete mode 100644 server/src/metadata/migrations/1695717691800-alter-field-metadata-table.ts delete mode 100644 server/src/metadata/migrations/1696409050890-add-target-column-map.ts delete mode 100644 server/src/metadata/migrations/1697126636202-MetadataNameLabelRefactoring.ts delete mode 100644 server/src/metadata/migrations/1697471445015-removeFieldMetadataPlaceholder.ts delete mode 100644 server/src/metadata/migrations/1697474804403-addSoftDelete.ts delete mode 100644 server/src/metadata/migrations/1697534910933-removeSingularPluralFromFieldLabelAndName.ts delete mode 100644 server/src/metadata/migrations/1697622715467-addNameAndIsCustomToTenantMigration.ts delete mode 100644 server/src/metadata/migrations/1697630766924-addUniqueConstraintsOnFieldObjectMetadata.ts delete mode 100644 server/src/metadata/migrations/1698328717102-removeMetadataSoftDelete.ts delete mode 100644 server/src/metadata/migrations/1699289664146-addRelationMetadata.ts create mode 100644 server/src/metadata/object-metadata/dtos/object-metadata.dto.ts delete mode 100644 server/src/metadata/object-metadata/object-metadata.auto-resolver-opts.ts delete mode 100644 server/src/metadata/object-metadata/object-metadata.entity.ts rename server/src/metadata/object-metadata/{services => }/object-metadata.service.ts (60%) delete mode 100644 server/src/metadata/object-metadata/services/object-metadata.service.spec.ts create mode 100644 server/src/metadata/relation-metadata/dtos/relation-metadata.dto.ts delete mode 100644 server/src/metadata/relation-metadata/relation-metadata.auto-resolver-opts.ts delete mode 100644 server/src/metadata/relation-metadata/relation-metadata.entity.ts rename server/src/metadata/relation-metadata/{services => }/relation-metadata.service.ts (84%) delete mode 100644 server/src/metadata/tenant-initialisation/tenant-initialisation.service.ts delete mode 100644 server/src/metadata/tenant-migration/tenant-migration.service.spec.ts create mode 100644 server/src/tenant-datasource/tenant-datasource.module.ts create mode 100644 server/src/tenant-datasource/tenant-datasource.service.ts rename server/src/{metadata => tenant-manager}/commands/sync-tenant-metadata.command.ts (77%) create mode 100644 server/src/tenant-manager/commands/tenant-manager-commands.module.ts rename server/src/{metadata/standard-objects => tenant-manager/standard-objects-metadata}/companies/companies.metadata.ts (100%) rename server/src/{metadata/standard-objects => tenant-manager/standard-objects-metadata}/standard-object-metadata.ts (100%) rename server/src/{metadata/standard-objects => tenant-manager/standard-objects-metadata}/view-fields/view-fields.metadata.ts (95%) rename server/src/{metadata/standard-objects => tenant-manager/standard-objects-metadata}/view-filters/view-filters.metadata.ts (95%) rename server/src/{metadata/standard-objects => tenant-manager/standard-objects-metadata}/view-sorts/view-sorts.metadata.ts (93%) rename server/src/{metadata/standard-objects => tenant-manager/standard-objects-metadata}/views/views.metadata.ts (92%) rename server/src/{metadata/tenant-initialisation => tenant-manager}/standard-objects-prefill-data/standard-objects-prefill-data.ts (82%) rename server/src/{metadata/tenant-initialisation/tenant-initialisation.module.ts => tenant-manager/tenant-manager.module.ts} (56%) create mode 100644 server/src/tenant-manager/tenant-manager.service.ts rename server/src/{metadata => tenant-migration-runner}/commands/run-tenant-migrations.command.ts (80%) create mode 100644 server/src/tenant-migration-runner/commands/tenant-migration-runner-commands.module.ts create mode 100644 server/src/tenant-migration-runner/tenant-migration-runner.module.ts rename server/src/{metadata/migration-runner/migration-runner.service.ts => tenant-migration-runner/tenant-migration-runner.service.ts} (91%) rename server/src/{metadata/migration-runner => tenant-migration-runner/utils}/custom-table-default-column.util.ts (100%) rename server/src/{metadata/field-metadata => tenant/schema-builder}/interfaces/field-metadata-target-column-map.interface.ts (89%) diff --git a/front/src/generated-metadata/graphql.ts b/front/src/generated-metadata/graphql.ts index 8b25c5a115..2b462fd57c 100644 --- a/front/src/generated-metadata/graphql.ts +++ b/front/src/generated-metadata/graphql.ts @@ -173,7 +173,7 @@ export type CreateFieldInput = { icon?: InputMaybe; label: Scalars['String']['input']; name: Scalars['String']['input']; - objectId: Scalars['String']['input']; + objectMetadataId: Scalars['String']['input']; type: FieldMetadataType; }; @@ -196,6 +196,21 @@ export type CreateOneObjectInput = { object: CreateObjectInput; }; +export type CreateOneRelationInput = { + /** The record to create */ + relation: CreateRelationInput; +}; + +export type CreateRelationInput = { + description?: InputMaybe; + fromObjectMetadataId: Scalars['String']['input']; + icon?: InputMaybe; + label: Scalars['String']['input']; + name: Scalars['String']['input']; + relationType: Scalars['String']['input']; + toObjectMetadataId: Scalars['String']['input']; +}; + export enum Currency { Aed = 'AED', Afn = 'AFN', @@ -437,6 +452,7 @@ export enum FieldMetadataType { Money = 'MONEY', Number = 'NUMBER', Phone = 'PHONE', + Relation = 'RELATION', Text = 'TEXT', Url = 'URL', Uuid = 'UUID' @@ -446,6 +462,7 @@ export type Mutation = { __typename?: 'Mutation'; createOneField: Field; createOneObject: Object; + createOneRelation: Relation; deleteOneField: FieldDeleteResponse; deleteOneObject: ObjectDeleteResponse; updateOneField: Field; @@ -463,6 +480,11 @@ export type MutationCreateOneObjectArgs = { }; +export type MutationCreateOneRelationArgs = { + input: CreateOneRelationInput; +}; + + export type MutationDeleteOneFieldArgs = { input: DeleteOneFieldInput; }; @@ -611,6 +633,7 @@ export type Query = { fields: FieldConnection; object: Object; objects: ObjectConnection; + relation: Relation; }; @@ -633,6 +656,11 @@ export type QueryObjectsArgs = { paging?: CursorPaging; }; + +export type QueryRelationArgs = { + id: Scalars['ID']['input']; +}; + export type Support = { __typename?: 'Support'; supportDriver: Scalars['String']['output']; @@ -769,6 +797,7 @@ export type Field = { __typename?: 'field'; createdAt: Scalars['DateTime']['output']; description?: Maybe; + fromRelationMetadata?: Maybe; icon?: Maybe; id: Scalars['ID']['output']; isActive: Scalars['Boolean']['output']; @@ -778,6 +807,7 @@ export type Field = { name: Scalars['String']['output']; /** @deprecated Use label name instead */ placeholder?: Maybe; + toRelationMetadata?: Maybe; type: FieldMetadataType; updatedAt: Scalars['DateTime']['output']; }; @@ -820,6 +850,28 @@ export type ObjectEdge = { node: Object; }; +export type Relation = { + __typename?: 'relation'; + createdAt: Scalars['DateTime']['output']; + fromFieldMetadataId: Scalars['String']['output']; + fromObjectMetadata: Object; + fromObjectMetadataId: Scalars['String']['output']; + id: Scalars['ID']['output']; + relationType: Scalars['String']['output']; + toFieldMetadataId: Scalars['String']['output']; + toObjectMetadata: Object; + toObjectMetadataId: Scalars['String']['output']; + updatedAt: Scalars['DateTime']['output']; +}; + +export type RelationEdge = { + __typename?: 'relationEdge'; + /** Cursor for this node. */ + cursor: Scalars['ConnectionCursor']['output']; + /** The node containing the relation */ + node: Relation; +}; + export type CreateOneObjectMetadataItemMutationVariables = Exact<{ input: CreateOneObjectInput; }>; diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index 54e61db1e3..f8e6652dd5 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -1322,6 +1322,7 @@ export enum FieldMetadataType { Money = 'MONEY', Number = 'NUMBER', Phone = 'PHONE', + Relation = 'RELATION', Text = 'TEXT', Url = 'URL', Uuid = 'UUID' @@ -1391,6 +1392,7 @@ export type Mutation = { createOneApiKey: ApiKeyToken; createOneComment: Comment; createOneCompany: Company; + createOneField: Field; createOneObject: Object; createOnePerson: Person; createOnePipelineProgress: PipelineProgress; @@ -1402,6 +1404,7 @@ export type Mutation = { deleteManyCompany: AffectedRows; deleteManyPerson: AffectedRows; deleteManyPipelineProgress: AffectedRows; + deleteOneField: FieldDeleteResponse; deleteOneObject: ObjectDeleteResponse; deleteOnePipelineStage: PipelineStage; deleteOneWebHook: WebHook; @@ -1414,6 +1417,7 @@ export type Mutation = { updateOneActivity: Activity; updateOneCompany?: Maybe; updateOneFavorites: Favorite; + updateOneField: Field; updateOneObject: Object; updateOnePerson?: Maybe; updateOnePipelineProgress?: Maybe; @@ -2404,6 +2408,8 @@ export type Query = { clientConfig: ClientConfig; currentUser: User; currentWorkspace: Workspace; + field: Field; + fields: FieldConnection; findFavorites: Array; findManyActivities: Array; findManyApiKey: Array; @@ -2593,6 +2599,15 @@ export type Support = { supportFrontChatId?: Maybe; }; +export type TUser = { + __typename?: 'TUser'; + email: Scalars['String']; + emailVerified: Scalars['Boolean']; + firstName?: Maybe; + id: Scalars['ID']; + lastName?: Maybe; +}; + export type Telemetry = { __typename?: 'Telemetry'; anonymizationEnabled: Scalars['Boolean']; @@ -3093,6 +3108,7 @@ export type Field = { __typename?: 'field'; createdAt: Scalars['DateTime']; description?: Maybe; + fromRelationMetadata?: Maybe; icon?: Maybe; id: Scalars['ID']; isActive: Scalars['Boolean']; @@ -3102,6 +3118,7 @@ export type Field = { name: Scalars['String']; /** @deprecated Use label name instead */ placeholder?: Maybe; + toRelationMetadata?: Maybe; type: FieldMetadataType; updatedAt: Scalars['DateTime']; }; @@ -3144,6 +3161,28 @@ export type ObjectEdge = { node: Object; }; +export type Relation = { + __typename?: 'relation'; + createdAt: Scalars['DateTime']; + fromFieldMetadataId: Scalars['String']; + fromObjectMetadata: Object; + fromObjectMetadataId: Scalars['String']; + id: Scalars['ID']; + relationType: Scalars['String']; + toFieldMetadataId: Scalars['String']; + toObjectMetadata: Object; + toObjectMetadataId: Scalars['String']; + updatedAt: Scalars['DateTime']; +}; + +export type RelationEdge = { + __typename?: 'relationEdge'; + /** Cursor for this node. */ + cursor: Scalars['ConnectionCursor']; + /** The node containing the relation */ + node: Relation; +}; + export type ActivityWithTargetsFragment = { __typename?: 'Activity', id: string, createdAt: string, updatedAt: string, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, createdAt: string, updatedAt: string, companyId?: string | null, personId?: string | null }> | null }; export type ActivityQueryFragmentFragment = { __typename?: 'Activity', id: string, createdAt: string, title?: string | null, body?: string | null, type: ActivityType, completedAt?: string | null, dueAt?: string | null, assignee?: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string, avatarUrl?: string | null } | null, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, activityTargets?: Array<{ __typename?: 'ActivityTarget', id: string, companyId?: string | null, personId?: string | null, company?: { __typename?: 'Company', id: string, name: string, domainName: string } | null, person?: { __typename?: 'Person', id: string, displayName: string, avatarUrl?: string | null } | null }> | null }; diff --git a/front/src/modules/activities/editable-fields/components/ActivityAssigneeEditableField.tsx b/front/src/modules/activities/editable-fields/components/ActivityAssigneeEditableField.tsx index f97b93eb95..1c8cc55b18 100644 --- a/front/src/modules/activities/editable-fields/components/ActivityAssigneeEditableField.tsx +++ b/front/src/modules/activities/editable-fields/components/ActivityAssigneeEditableField.tsx @@ -23,7 +23,7 @@ export const ActivityAssigneeEditableField = ({ entityId: activity.id, recoilScopeId: 'assignee', fieldDefinition: { - fieldId: 'assignee', + fieldMetadataId: 'assignee', label: 'Assignee', Icon: IconUserCircle, type: 'RELATION', diff --git a/front/src/modules/activities/editable-fields/components/ActivityEditorDateField.tsx b/front/src/modules/activities/editable-fields/components/ActivityEditorDateField.tsx index d7e4680f30..e4daac9421 100644 --- a/front/src/modules/activities/editable-fields/components/ActivityEditorDateField.tsx +++ b/front/src/modules/activities/editable-fields/components/ActivityEditorDateField.tsx @@ -21,7 +21,7 @@ export const ActivityEditorDateField = ({ entityId: activityId, recoilScopeId: 'activityDueAt', fieldDefinition: { - fieldId: 'activityDueAt', + fieldMetadataId: 'activityDueAt', label: 'Due date', Icon: IconCalendar, type: 'DATE', diff --git a/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts b/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts index c31af5e609..a6281c1e54 100644 --- a/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts +++ b/front/src/modules/activities/tasks/hooks/useCurrentUserDueTaskCount.ts @@ -17,7 +17,7 @@ export const useCurrentUserTaskCount = () => { completedAt: { equals: null }, ...(currentUser ? turnFilterIntoWhereClause({ - fieldId: 'assigneeId', + fieldMetadataId: 'assigneeId', value: currentUser.id, operand: ViewFilterOperand.Is, displayValue: currentUser.displayName, diff --git a/front/src/modules/companies/components/CompanyBoardCard.tsx b/front/src/modules/companies/components/CompanyBoardCard.tsx index 85652feb29..10e9cc2e0e 100644 --- a/front/src/modules/companies/components/CompanyBoardCard.tsx +++ b/front/src/modules/companies/components/CompanyBoardCard.tsx @@ -222,13 +222,13 @@ export const CompanyBoardCard = () => { {visibleBoardCardFields.map((viewField) => ( - + [] = [ { - fieldId: 'name', + fieldMetadataId: 'name', label: 'Name', Icon: IconBuildingSkyscraper, size: 180, @@ -45,7 +45,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition basePathToShowPage: '/companies/', } satisfies ColumnDefinition, { - fieldId: 'domainName', + fieldMetadataId: 'domainName', label: 'URL', Icon: IconLink, size: 100, @@ -60,7 +60,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition 'The company website URL. We use this url to fetch the company icon.', } satisfies ColumnDefinition, { - fieldId: 'accountOwner', + fieldMetadataId: 'accountOwner', label: 'Account Owner', Icon: IconUserCircle, size: 150, @@ -82,7 +82,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition }, } satisfies ColumnDefinition, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Creation', Icon: IconCalendarEvent, size: 150, @@ -95,7 +95,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition infoTooltipContent: "Date when the company's record was created.", } satisfies ColumnDefinition, { - fieldId: 'employees', + fieldMetadataId: 'employees', label: 'Employees', Icon: IconUsers, size: 150, @@ -110,7 +110,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition infoTooltipContent: 'Number of employees in the company.', } satisfies ColumnDefinition, { - fieldId: 'linkedin', + fieldMetadataId: 'linkedin', label: 'LinkedIn', Icon: IconBrandLinkedin, size: 170, @@ -124,7 +124,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition infoTooltipContent: 'The company Linkedin account.', } satisfies ColumnDefinition, { - fieldId: 'address', + fieldMetadataId: 'address', label: 'Address', Icon: IconMap, size: 170, @@ -138,7 +138,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition infoTooltipContent: 'The company address.', } satisfies ColumnDefinition, { - fieldId: 'idealCustomerProfile', + fieldMetadataId: 'idealCustomerProfile', label: 'ICP', Icon: IconTarget, size: 150, @@ -152,7 +152,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition 'Ideal Customer Profile: Indicates whether the company is the most suitable and valuable customer for you.', } satisfies ColumnDefinition, { - fieldId: 'annualRecurringRevenue', + fieldMetadataId: 'annualRecurringRevenue', label: 'ARR', Icon: IconMoneybag, size: 150, @@ -166,7 +166,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition 'Annual Recurring Revenue: The actual or estimated annual revenue of the company.', } satisfies ColumnDefinition, { - fieldId: 'xUrl', + fieldMetadataId: 'xUrl', label: 'Twitter', Icon: IconBrandX, size: 150, @@ -184,7 +184,7 @@ export const companiesAvailableFieldDefinitions: ColumnDefinition export const suppliersAvailableColumnDefinitions: ColumnDefinition[] = [ { - fieldId: 'name', + fieldMetadataId: 'name', label: 'Name', Icon: IconBuildingSkyscraper, size: 180, @@ -199,7 +199,7 @@ export const suppliersAvailableColumnDefinitions: ColumnDefinition, { - fieldId: 'city', + fieldMetadataId: 'city', label: 'City', Icon: IconBuildingSkyscraper, size: 180, diff --git a/front/src/modules/metadata/components/RecordShowPage.tsx b/front/src/modules/metadata/components/RecordShowPage.tsx index 4c73d38812..54ce627f1d 100644 --- a/front/src/modules/metadata/components/RecordShowPage.tsx +++ b/front/src/modules/metadata/components/RecordShowPage.tsx @@ -29,9 +29,9 @@ import { useUpdateOneObject } from '../hooks/useUpdateOneObject'; import { formatMetadataFieldAsColumnDefinition } from '../utils/formatMetadataFieldAsColumnDefinition'; export const RecordShowPage = () => { - const { objectNameSingular, objectId } = useParams<{ + const { objectNameSingular, objectMetadataId } = useParams<{ objectNameSingular: string; - objectId: string; + objectMetadataId: string; }>(); const { icons } = useLazyLoadIcons(); @@ -41,11 +41,11 @@ export const RecordShowPage = () => { }); const [, setEntityFields] = useRecoilState( - entityFieldsFamilyState(objectId ?? ''), + entityFieldsFamilyState(objectMetadataId ?? ''), ); const { object } = useFindOneObject({ - objectId: objectId, + objectMetadataId: objectMetadataId, objectNameSingular, onCompleted: (data) => { setEntityFields(data); diff --git a/front/src/modules/metadata/hooks/useCreateOneObject.ts b/front/src/modules/metadata/hooks/useCreateOneObject.ts index 5d2f9e1617..d470986197 100644 --- a/front/src/modules/metadata/hooks/useCreateOneObject.ts +++ b/front/src/modules/metadata/hooks/useCreateOneObject.ts @@ -14,6 +14,7 @@ const defaultFieldValues: Record = { [FieldMetadataType.Email]: '', [FieldMetadataType.Enum]: null, [FieldMetadataType.Number]: null, + [FieldMetadataType.Relation]: null, [FieldMetadataType.Phone]: '', [FieldMetadataType.Text]: '', [FieldMetadataType.Url]: { link: '', text: '' }, diff --git a/front/src/modules/metadata/hooks/useFindOneObject.ts b/front/src/modules/metadata/hooks/useFindOneObject.ts index 6bf4baf420..454d96566f 100644 --- a/front/src/modules/metadata/hooks/useFindOneObject.ts +++ b/front/src/modules/metadata/hooks/useFindOneObject.ts @@ -8,10 +8,10 @@ export const useFindOneObject = < ObjectType extends { id: string } & Record, >({ objectNameSingular, - objectId, + objectMetadataId, onCompleted, }: Pick & { - objectId: string | undefined; + objectMetadataId: string | undefined; onCompleted?: (data: ObjectType) => void; }) => { const { foundObjectMetadataItem, objectNotFoundInMetadata, findOneQuery } = @@ -21,11 +21,11 @@ export const useFindOneObject = < const { data, loading, error } = useQuery< { [nameSingular: string]: ObjectType }, - { objectId: string } + { objectMetadataId: string } >(findOneQuery, { - skip: !foundObjectMetadataItem || !objectId, + skip: !foundObjectMetadataItem || !objectMetadataId, variables: { - objectId: objectId ?? '', + objectMetadataId: objectMetadataId ?? '', }, onCompleted: (data) => { if (onCompleted && objectNameSingular) { diff --git a/front/src/modules/metadata/hooks/useMetadataField.ts b/front/src/modules/metadata/hooks/useMetadataField.ts index bb898d3e90..a72bf40a36 100644 --- a/front/src/modules/metadata/hooks/useMetadataField.ts +++ b/front/src/modules/metadata/hooks/useMetadataField.ts @@ -14,13 +14,13 @@ export const useMetadataField = () => { const createMetadataField = ( input: Pick & { - objectId: string; + objectMetadataId: string; type: MetadataFieldDataType; }, ) => createOneMetadataField({ ...formatMetadataFieldInput(input), - objectId: input.objectId, + objectMetadataId: input.objectMetadataId, type: input.type, }); @@ -28,19 +28,19 @@ export const useMetadataField = () => { input: Pick, ) => updateOneMetadataField({ - fieldIdToUpdate: input.id, + fieldMetadataIdToUpdate: input.id, updatePayload: formatMetadataFieldInput(input), }); const activateMetadataField = (metadataField: Field) => updateOneMetadataField({ - fieldIdToUpdate: metadataField.id, + fieldMetadataIdToUpdate: metadataField.id, updatePayload: { isActive: true }, }); const disableMetadataField = (metadataField: Field) => updateOneMetadataField({ - fieldIdToUpdate: metadataField.id, + fieldMetadataIdToUpdate: metadataField.id, updatePayload: { isActive: false }, }); diff --git a/front/src/modules/metadata/hooks/useUpdateOneMetadataField.ts b/front/src/modules/metadata/hooks/useUpdateOneMetadataField.ts index 43506b9bae..8df8fbdbb3 100644 --- a/front/src/modules/metadata/hooks/useUpdateOneMetadataField.ts +++ b/front/src/modules/metadata/hooks/useUpdateOneMetadataField.ts @@ -22,10 +22,10 @@ export const useUpdateOneMetadataField = () => { }); const updateOneMetadataField = async ({ - fieldIdToUpdate, + fieldMetadataIdToUpdate, updatePayload, }: { - fieldIdToUpdate: UpdateOneMetadataFieldMutationVariables['idToUpdate']; + fieldMetadataIdToUpdate: UpdateOneMetadataFieldMutationVariables['idToUpdate']; updatePayload: Pick< UpdateOneMetadataFieldMutationVariables['updatePayload'], 'description' | 'icon' | 'isActive' | 'label' | 'name' @@ -33,7 +33,7 @@ export const useUpdateOneMetadataField = () => { }) => { return await mutate({ variables: { - idToUpdate: fieldIdToUpdate, + idToUpdate: fieldMetadataIdToUpdate, updatePayload: { ...updatePayload, label: updatePayload.label ?? undefined, diff --git a/front/src/modules/metadata/utils/formatMetadataFieldAsColumnDefinition.ts b/front/src/modules/metadata/utils/formatMetadataFieldAsColumnDefinition.ts index c2c2d53aa8..f744d64b05 100644 --- a/front/src/modules/metadata/utils/formatMetadataFieldAsColumnDefinition.ts +++ b/front/src/modules/metadata/utils/formatMetadataFieldAsColumnDefinition.ts @@ -19,7 +19,7 @@ export const formatMetadataFieldAsColumnDefinition = ({ icons: Record; }): ColumnDefinition => ({ position, - fieldId: field.id, + fieldMetadataId: field.id, label: field.label, size: 100, type: parseFieldType(field.type), diff --git a/front/src/modules/metadata/utils/formatMetadataFieldAsFilterDefinition.ts b/front/src/modules/metadata/utils/formatMetadataFieldAsFilterDefinition.ts index 016fb10164..56bc5b8375 100644 --- a/front/src/modules/metadata/utils/formatMetadataFieldAsFilterDefinition.ts +++ b/front/src/modules/metadata/utils/formatMetadataFieldAsFilterDefinition.ts @@ -9,7 +9,7 @@ export const formatMetadataFieldAsFilterDefinition = ({ field: ObjectMetadataItem['fields'][0]; icons: Record; }): FilterDefinition => ({ - fieldId: field.id, + fieldMetadataId: field.id, label: field.label, Icon: icons[field.icon ?? 'Icon123'], type: 'TEXT', diff --git a/front/src/modules/metadata/utils/formatMetadataFieldAsSortDefinition.ts b/front/src/modules/metadata/utils/formatMetadataFieldAsSortDefinition.ts index 2b5fd8d26b..899d5c4d70 100644 --- a/front/src/modules/metadata/utils/formatMetadataFieldAsSortDefinition.ts +++ b/front/src/modules/metadata/utils/formatMetadataFieldAsSortDefinition.ts @@ -9,7 +9,7 @@ export const formatMetadataFieldAsSortDefinition = ({ field: ObjectMetadataItem['fields'][0]; icons: Record; }): SortDefinition => ({ - fieldId: field.id, + fieldMetadataId: field.id, label: field.label, Icon: icons[field.icon ?? 'Icon123'], }); diff --git a/front/src/modules/metadata/utils/generateFindOneCustomObjectQuery.ts b/front/src/modules/metadata/utils/generateFindOneCustomObjectQuery.ts index 4a996e4e75..c585b11d24 100644 --- a/front/src/modules/metadata/utils/generateFindOneCustomObjectQuery.ts +++ b/front/src/modules/metadata/utils/generateFindOneCustomObjectQuery.ts @@ -10,10 +10,10 @@ export const generateFindOneCustomObjectQuery = ({ objectMetadataItem: ObjectMetadataItem; }) => { return gql` - query FindOne${objectMetadataItem.nameSingular}($objectId: UUID!) { + query FindOne${objectMetadataItem.nameSingular}($objectMetadataId: UUID!) { ${objectMetadataItem.nameSingular}(filter: { id: { - eq: $objectId + eq: $objectMetadataId } }){ id diff --git a/front/src/modules/people/constants/peopleAvailableFieldDefinitions.tsx b/front/src/modules/people/constants/peopleAvailableFieldDefinitions.tsx index ad82e79144..9365386a04 100644 --- a/front/src/modules/people/constants/peopleAvailableFieldDefinitions.tsx +++ b/front/src/modules/people/constants/peopleAvailableFieldDefinitions.tsx @@ -27,7 +27,7 @@ import { getLogoUrlFromDomainName } from '~/utils'; export const peopleAvailableFieldDefinitions: ColumnDefinition[] = [ { - fieldId: 'displayName', + fieldMetadataId: 'displayName', label: 'People', Icon: IconUser, size: 210, @@ -45,7 +45,7 @@ export const peopleAvailableFieldDefinitions: ColumnDefinition[] basePathToShowPage: '/person/', } satisfies ColumnDefinition, { - fieldId: 'email', + fieldMetadataId: 'email', label: 'Email', Icon: IconMail, size: 150, @@ -58,7 +58,7 @@ export const peopleAvailableFieldDefinitions: ColumnDefinition[] infoTooltipContent: 'Contact’s Email.', } satisfies ColumnDefinition, { - fieldId: 'company', + fieldMetadataId: 'company', label: 'Company', Icon: IconBuildingSkyscraper, size: 150, @@ -78,7 +78,7 @@ export const peopleAvailableFieldDefinitions: ColumnDefinition[] }, } satisfies ColumnDefinition, { - fieldId: 'phone', + fieldMetadataId: 'phone', label: 'Phone', Icon: IconPhone, size: 150, @@ -91,7 +91,7 @@ export const peopleAvailableFieldDefinitions: ColumnDefinition[] infoTooltipContent: 'Contact’s phone number.', } satisfies ColumnDefinition, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Creation', Icon: IconCalendarEvent, size: 150, @@ -103,7 +103,7 @@ export const peopleAvailableFieldDefinitions: ColumnDefinition[] infoTooltipContent: 'Date when the contact was added.', } satisfies ColumnDefinition, { - fieldId: 'city', + fieldMetadataId: 'city', label: 'City', Icon: IconMap, size: 150, @@ -116,7 +116,7 @@ export const peopleAvailableFieldDefinitions: ColumnDefinition[] infoTooltipContent: 'Contact’s city.', } satisfies ColumnDefinition, { - fieldId: 'jobTitle', + fieldMetadataId: 'jobTitle', label: 'Job title', Icon: IconBriefcase, size: 150, @@ -129,7 +129,7 @@ export const peopleAvailableFieldDefinitions: ColumnDefinition[] infoTooltipContent: 'Contact’s job title.', } satisfies ColumnDefinition, { - fieldId: 'linkedin', + fieldMetadataId: 'linkedin', label: 'LinkedIn', Icon: IconBrandLinkedin, size: 150, @@ -142,7 +142,7 @@ export const peopleAvailableFieldDefinitions: ColumnDefinition[] infoTooltipContent: 'Contact’s Linkedin account.', } satisfies ColumnDefinition, { - fieldId: 'x', + fieldMetadataId: 'x', label: 'Twitter', Icon: IconBrandX, size: 150, diff --git a/front/src/modules/pipeline/constants/pipelineAvailableFieldDefinitions.tsx b/front/src/modules/pipeline/constants/pipelineAvailableFieldDefinitions.tsx index c29caff32d..49834d68c4 100644 --- a/front/src/modules/pipeline/constants/pipelineAvailableFieldDefinitions.tsx +++ b/front/src/modules/pipeline/constants/pipelineAvailableFieldDefinitions.tsx @@ -18,7 +18,7 @@ import { Person } from '~/generated/graphql'; export const pipelineAvailableFieldDefinitions: ColumnDefinition[] = [ { - fieldId: 'closeDate', + fieldMetadataId: 'closeDate', label: 'Close Date', Icon: IconCalendarEvent, position: 0, @@ -32,7 +32,7 @@ export const pipelineAvailableFieldDefinitions: ColumnDefinition[ 'Specified date by which an opportunity must be completed.', } satisfies ColumnDefinition, { - fieldId: 'amount', + fieldMetadataId: 'amount', label: 'Amount', Icon: IconCurrencyDollar, position: 1, @@ -46,7 +46,7 @@ export const pipelineAvailableFieldDefinitions: ColumnDefinition[ infoTooltipContent: 'Potential monetary value of a business opportunity.', } satisfies ColumnDefinition, { - fieldId: 'probability', + fieldMetadataId: 'probability', label: 'Probability', Icon: IconProgressCheck, position: 2, @@ -60,7 +60,7 @@ export const pipelineAvailableFieldDefinitions: ColumnDefinition[ "Level of certainty in the lead's potential to convert into a success.", } satisfies ColumnDefinition, { - fieldId: 'pointOfContact', + fieldMetadataId: 'pointOfContact', label: 'Point of Contact', Icon: IconUser, position: 3, diff --git a/front/src/modules/settings/data-model/components/SettingsObjectFieldPreview.tsx b/front/src/modules/settings/data-model/components/SettingsObjectFieldPreview.tsx index ae8ab2b845..b53bc1b50a 100644 --- a/front/src/modules/settings/data-model/components/SettingsObjectFieldPreview.tsx +++ b/front/src/modules/settings/data-model/components/SettingsObjectFieldPreview.tsx @@ -141,7 +141,7 @@ export const SettingsObjectFieldPreview = ({ fieldDefinition: { type: parseFieldType(fieldType as FieldMetadataType), Icon: FieldIcon, - fieldId: '', + fieldMetadataId: '', label: fieldLabel, metadata: { fieldName: fieldName || 'new-field' }, }, diff --git a/front/src/modules/types/AppPath.ts b/front/src/modules/types/AppPath.ts index 629c2ccb97..11f501e21d 100644 --- a/front/src/modules/types/AppPath.ts +++ b/front/src/modules/types/AppPath.ts @@ -19,7 +19,7 @@ export enum AppPath { OpportunitiesPage = '/opportunities', RecordTablePage = '/objects/:objectNamePlural', - RecordShowPage = '/object/:objectNameSingular/:objectId', + RecordShowPage = '/object/:objectNameSingular/:objectMetadataId', SettingsCatchAll = `/settings/*`, DevelopersCatchAll = `/developers/*`, diff --git a/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts b/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts index 71818f3629..35cc98415b 100644 --- a/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts +++ b/front/src/modules/ui/layout/board/hooks/useBoardCardFields.ts @@ -19,7 +19,7 @@ export const useBoardCardFields = () => { ) => { setBoardCardFields((previousFields) => previousFields.map((previousField) => - previousField.fieldId === field.fieldId + previousField.fieldMetadataId === field.fieldMetadataId ? { ...previousField, isVisible: !field.isVisible } : previousField, ), diff --git a/front/src/modules/ui/layout/board/states/selectors/boardCardFieldsByKeyScopedSelector.ts b/front/src/modules/ui/layout/board/states/selectors/boardCardFieldsByKeyScopedSelector.ts index ef741eaf5f..cebd20e36d 100644 --- a/front/src/modules/ui/layout/board/states/selectors/boardCardFieldsByKeyScopedSelector.ts +++ b/front/src/modules/ui/layout/board/states/selectors/boardCardFieldsByKeyScopedSelector.ts @@ -12,5 +12,5 @@ export const boardCardFieldsByKeyScopedSelector = selectorFamily({ ({ get }) => get(boardCardFieldsScopedState(scopeId)).reduce< Record> - >((result, field) => ({ ...result, [field.fieldId]: field }), {}), + >((result, field) => ({ ...result, [field.fieldMetadataId]: field }), {}), }); diff --git a/front/src/modules/ui/layout/board/states/selectors/hiddenBoardCardFieldsScopedSelector.ts b/front/src/modules/ui/layout/board/states/selectors/hiddenBoardCardFieldsScopedSelector.ts index 2376296f1b..29c56cc4c8 100644 --- a/front/src/modules/ui/layout/board/states/selectors/hiddenBoardCardFieldsScopedSelector.ts +++ b/front/src/modules/ui/layout/board/states/selectors/hiddenBoardCardFieldsScopedSelector.ts @@ -9,10 +9,10 @@ export const hiddenBoardCardFieldsScopedSelector = selectorFamily({ (scopeId: string) => ({ get }) => { const fields = get(boardCardFieldsScopedState(scopeId)); - const fieldKeys = fields.map(({ fieldId }) => fieldId); + const fieldKeys = fields.map(({ fieldMetadataId }) => fieldMetadataId); const otherAvailableKeys = get( availableBoardCardFieldsScopedState(scopeId), - ).filter(({ fieldId }) => !fieldKeys.includes(fieldId)); + ).filter(({ fieldMetadataId }) => !fieldKeys.includes(fieldMetadataId)); return [ ...fields.filter((field) => !field.isVisible), diff --git a/front/src/modules/ui/layout/board/states/selectors/savedBoardCardFieldsByKeyFamilySelector.ts b/front/src/modules/ui/layout/board/states/selectors/savedBoardCardFieldsByKeyFamilySelector.ts index af64c0fb2d..891ed831f1 100644 --- a/front/src/modules/ui/layout/board/states/selectors/savedBoardCardFieldsByKeyFamilySelector.ts +++ b/front/src/modules/ui/layout/board/states/selectors/savedBoardCardFieldsByKeyFamilySelector.ts @@ -12,5 +12,5 @@ export const savedBoardCardFieldsByKeyFamilySelector = selectorFamily({ ({ get }) => get(savedBoardCardFieldsFamilyState(viewId)).reduce< Record> - >((result, field) => ({ ...result, [field.fieldId]: field }), {}), + >((result, field) => ({ ...result, [field.fieldMetadataId]: field }), {}), }); diff --git a/front/src/modules/ui/object/field/hooks/useFieldInitialValue.ts b/front/src/modules/ui/object/field/hooks/useFieldInitialValue.ts index b228b1b985..a99563a40d 100644 --- a/front/src/modules/ui/object/field/hooks/useFieldInitialValue.ts +++ b/front/src/modules/ui/object/field/hooks/useFieldInitialValue.ts @@ -9,7 +9,7 @@ export const useFieldInitialValue = () => { const fieldInitialValue = useRecoilValue( entityFieldInitialValueFamilyState({ - fieldId: fieldDefinition.fieldId, + fieldMetadataId: fieldDefinition.fieldMetadataId, entityId, }), ); diff --git a/front/src/modules/ui/object/field/hooks/useIsFieldEmpty.ts b/front/src/modules/ui/object/field/hooks/useIsFieldEmpty.ts index cbb75fefc4..b7af6865a9 100644 --- a/front/src/modules/ui/object/field/hooks/useIsFieldEmpty.ts +++ b/front/src/modules/ui/object/field/hooks/useIsFieldEmpty.ts @@ -10,7 +10,7 @@ export const useIsFieldEmpty = () => { const isFieldEmpty = useRecoilValue( isEntityFieldEmptyFamilySelector({ fieldDefinition: { - fieldId: fieldDefinition.fieldId, + fieldMetadataId: fieldDefinition.fieldMetadataId, label: fieldDefinition.label, type: fieldDefinition.type, metadata: fieldDefinition.metadata, diff --git a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/DateFieldDisplay.stories.tsx b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/DateFieldDisplay.stories.tsx index 97b4736941..cf05e8a536 100644 --- a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/DateFieldDisplay.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/DateFieldDisplay.stories.tsx @@ -27,7 +27,7 @@ const meta: Meta = { value={{ entityId: '', fieldDefinition: { - fieldId: 'date', + fieldMetadataId: 'date', label: 'Date', type: 'DATE', metadata: { diff --git a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/DoubleTextFieldDisplay.stories.tsx b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/DoubleTextFieldDisplay.stories.tsx index 0385c176f7..dd9ab566b4 100644 --- a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/DoubleTextFieldDisplay.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/DoubleTextFieldDisplay.stories.tsx @@ -32,7 +32,7 @@ const meta: Meta = { value={{ entityId: '', fieldDefinition: { - fieldId: 'double-text', + fieldMetadataId: 'double-text', label: 'Double-Text', type: 'DOUBLE_TEXT', metadata: { diff --git a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/EmailFieldDisplay.stories.tsx b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/EmailFieldDisplay.stories.tsx index e0d7b612df..76fa24092f 100644 --- a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/EmailFieldDisplay.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/EmailFieldDisplay.stories.tsx @@ -26,7 +26,7 @@ const meta: Meta = { value={{ entityId: '', fieldDefinition: { - fieldId: 'email', + fieldMetadataId: 'email', label: 'Email', type: 'EMAIL', metadata: { diff --git a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/MoneyFieldDisplay.stories.tsx b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/MoneyFieldDisplay.stories.tsx index 157f27b73d..2028056a64 100644 --- a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/MoneyFieldDisplay.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/MoneyFieldDisplay.stories.tsx @@ -25,7 +25,7 @@ const meta: Meta = { value={{ entityId: '', fieldDefinition: { - fieldId: 'money', + fieldMetadataId: 'money', label: 'Money', type: 'MONEY_AMOUNT', metadata: { diff --git a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/NumberFieldDisplay.stories.tsx b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/NumberFieldDisplay.stories.tsx index 02bdffdef6..456096f634 100644 --- a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/NumberFieldDisplay.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/NumberFieldDisplay.stories.tsx @@ -25,7 +25,7 @@ const meta: Meta = { value={{ entityId: '', fieldDefinition: { - fieldId: 'number', + fieldMetadataId: 'number', label: 'Number', type: 'NUMBER', metadata: { diff --git a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/PhoneFieldDisplay.stories.tsx b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/PhoneFieldDisplay.stories.tsx index 1d8265d52d..dfd48f2b95 100644 --- a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/PhoneFieldDisplay.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/PhoneFieldDisplay.stories.tsx @@ -26,7 +26,7 @@ const meta: Meta = { value={{ entityId: '', fieldDefinition: { - fieldId: 'phone', + fieldMetadataId: 'phone', label: 'Phone', type: 'PHONE', metadata: { diff --git a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/TextFieldDisplay.stories.tsx b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/TextFieldDisplay.stories.tsx index d405fafe75..9434539af4 100644 --- a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/TextFieldDisplay.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/TextFieldDisplay.stories.tsx @@ -25,7 +25,7 @@ const meta: Meta = { value={{ entityId: '', fieldDefinition: { - fieldId: 'text', + fieldMetadataId: 'text', label: 'Text', type: 'TEXT', metadata: { diff --git a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/URLFieldDisplay.stories.tsx b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/URLFieldDisplay.stories.tsx index f377fa945d..aaee996624 100644 --- a/front/src/modules/ui/object/field/meta-types/display/components/__stories__/URLFieldDisplay.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/display/components/__stories__/URLFieldDisplay.stories.tsx @@ -26,7 +26,7 @@ const meta: Meta = { value={{ entityId: '', fieldDefinition: { - fieldId: 'URL', + fieldMetadataId: 'URL', label: 'URL', type: 'URL', metadata: { diff --git a/front/src/modules/ui/object/field/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx b/front/src/modules/ui/object/field/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx index 9b9df6376b..0a5c1c1b50 100644 --- a/front/src/modules/ui/object/field/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx +++ b/front/src/modules/ui/object/field/meta-types/input/components/__stories__/BooleanFieldInput.stories.tsx @@ -34,7 +34,7 @@ const BooleanFieldInputWithContext = ({ return ( ({ key: 'entityFieldInitialValueFamilyState', default: undefined, diff --git a/front/src/modules/ui/object/field/states/selectors/isEntityFieldEmptyFamilySelector.ts b/front/src/modules/ui/object/field/states/selectors/isEntityFieldEmptyFamilySelector.ts index df376d025d..8b1f479eaf 100644 --- a/front/src/modules/ui/object/field/states/selectors/isEntityFieldEmptyFamilySelector.ts +++ b/front/src/modules/ui/object/field/states/selectors/isEntityFieldEmptyFamilySelector.ts @@ -33,7 +33,7 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({ }: { fieldDefinition: Pick< FieldDefinition, - 'type' | 'metadata' | 'fieldId' | 'label' + 'type' | 'metadata' | 'fieldMetadataId' | 'label' >; entityId: string; }) => { diff --git a/front/src/modules/ui/object/field/types/FieldDefinition.ts b/front/src/modules/ui/object/field/types/FieldDefinition.ts index 92113e5d6f..37b6a618d9 100644 --- a/front/src/modules/ui/object/field/types/FieldDefinition.ts +++ b/front/src/modules/ui/object/field/types/FieldDefinition.ts @@ -5,7 +5,7 @@ import { FieldMetadata } from './FieldMetadata'; import { FieldType } from './FieldType'; export type FieldDefinition = { - fieldId: string; + fieldMetadataId: string; label: string; Icon?: IconComponent; type: FieldType; diff --git a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownDateSearchInput.tsx b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownDateSearchInput.tsx index 333d968d3e..bcad9464e0 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownDateSearchInput.tsx +++ b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownDateSearchInput.tsx @@ -14,7 +14,7 @@ export const ObjectFilterDropdownDateSearchInput = () => { if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; selectFilter?.({ - fieldId: filterDefinitionUsedInDropdown.fieldId, + fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: date.toISOString(), operand: selectedOperandInDropdown, displayValue: date.toLocaleDateString(), diff --git a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySearchSelect.tsx b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySearchSelect.tsx index f697b541c6..9e1b2b627e 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySearchSelect.tsx +++ b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownEntitySearchSelect.tsx @@ -42,7 +42,7 @@ export const ObjectFilterDropdownEntitySearchSelect = ({ selectFilter?.({ displayValue: selectedEntity.name, - fieldId: filterDefinitionUsedInDropdown.fieldId, + fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, operand: selectedOperandInDropdown, value: selectedEntity.id, displayAvatarUrl: selectedEntity.avatarUrl, @@ -72,7 +72,7 @@ export const ObjectFilterDropdownEntitySearchSelect = ({ selectFilter?.({ displayValue: filterDefinitionUsedInDropdown.selectAllLabel, - fieldId: filterDefinitionUsedInDropdown.fieldId, + fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, operand: ViewFilterOperand.IsNotNull, value: '', definition: filterDefinitionUsedInDropdown, diff --git a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownNumberSearchInput.tsx b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownNumberSearchInput.tsx index a7130feb00..e4c58a1adf 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownNumberSearchInput.tsx +++ b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownNumberSearchInput.tsx @@ -20,7 +20,7 @@ export const ObjectFilterDropdownNumberSearchInput = () => { placeholder={filterDefinitionUsedInDropdown.label} onChange={(event: ChangeEvent) => { selectFilter?.({ - fieldId: filterDefinitionUsedInDropdown.fieldId, + fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: event.target.value, operand: selectedOperandInDropdown, displayValue: event.target.value, diff --git a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx index 82ca978d27..596efe79c1 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx +++ b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownOperandSelect.tsx @@ -26,7 +26,7 @@ export const ObjectFilterDropdownOperandSelect = () => { if (filterDefinitionUsedInDropdown && selectedFilter) { selectFilter?.({ - fieldId: selectedFilter.fieldId, + fieldMetadataId: selectedFilter.fieldMetadataId, displayValue: selectedFilter.displayValue, operand: newOperand, value: selectedFilter.value, diff --git a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx index 66811672b5..f33106cd23 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx +++ b/front/src/modules/ui/object/object-filter-dropdown/components/ObjectFilterDropdownTextSearchInput.tsx @@ -26,7 +26,7 @@ export const ObjectFilterDropdownTextSearchInput = () => { setObjectFilterDropdownSearchInput(event.target.value); selectFilter?.({ - fieldId: filterDefinitionUsedInDropdown.fieldId, + fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId, value: event.target.value, operand: selectedOperandInDropdown, displayValue: event.target.value, diff --git a/front/src/modules/ui/object/object-filter-dropdown/types/Filter.ts b/front/src/modules/ui/object/object-filter-dropdown/types/Filter.ts index a41fdfdb40..bb72dfd46a 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/types/Filter.ts +++ b/front/src/modules/ui/object/object-filter-dropdown/types/Filter.ts @@ -3,7 +3,7 @@ import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { FilterDefinition } from './FilterDefinition'; export type Filter = { - fieldId: string; + fieldMetadataId: string; value: string; displayValue: string; displayAvatarUrl?: string; diff --git a/front/src/modules/ui/object/object-filter-dropdown/types/FilterDefinition.ts b/front/src/modules/ui/object/object-filter-dropdown/types/FilterDefinition.ts index dd9bc07f51..6968c509ec 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/types/FilterDefinition.ts +++ b/front/src/modules/ui/object/object-filter-dropdown/types/FilterDefinition.ts @@ -3,7 +3,7 @@ import { IconComponent } from '@/ui/display/icon/types/IconComponent'; import { FilterType } from './FilterType'; export type FilterDefinition = { - fieldId: string; + fieldMetadataId: string; label: string; Icon: IconComponent; type: FilterType; diff --git a/front/src/modules/ui/object/object-filter-dropdown/types/FilterDefinitionByEntity.ts b/front/src/modules/ui/object/object-filter-dropdown/types/FilterDefinitionByEntity.ts index f351f9e014..4723227eb0 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/types/FilterDefinitionByEntity.ts +++ b/front/src/modules/ui/object/object-filter-dropdown/types/FilterDefinitionByEntity.ts @@ -1,5 +1,5 @@ import { FilterDefinition } from './FilterDefinition'; export type FilterDefinitionByEntity = FilterDefinition & { - fieldId: keyof T; + fieldMetadataId: keyof T; }; diff --git a/front/src/modules/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause.ts b/front/src/modules/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause.ts index e6c600f4a5..c0a9e66621 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause.ts +++ b/front/src/modules/ui/object/object-filter-dropdown/utils/turnFilterIntoWhereClause.ts @@ -18,7 +18,7 @@ export const turnFilterIntoWhereClause = ( switch (filter.operand) { case ViewFilterOperand.IsNotNull: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { not: null, }, }; @@ -28,14 +28,14 @@ export const turnFilterIntoWhereClause = ( switch (filter.operand) { case ViewFilterOperand.Contains: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { contains: filter.value, mode: QueryMode.Insensitive, }, }; case ViewFilterOperand.DoesNotContain: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { not: { contains: filter.value, mode: QueryMode.Insensitive, @@ -51,13 +51,13 @@ export const turnFilterIntoWhereClause = ( switch (filter.operand) { case ViewFilterOperand.GreaterThan: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { gte: parseFloat(filter.value), }, }; case ViewFilterOperand.LessThan: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { lte: parseFloat(filter.value), }, }; @@ -70,13 +70,13 @@ export const turnFilterIntoWhereClause = ( switch (filter.operand) { case ViewFilterOperand.GreaterThan: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { gte: filter.value, }, }; case ViewFilterOperand.LessThan: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { lte: filter.value, }, }; @@ -89,13 +89,13 @@ export const turnFilterIntoWhereClause = ( switch (filter.operand) { case ViewFilterOperand.Is: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { equals: filter.value, }, }; case ViewFilterOperand.IsNot: return { - [filter.fieldId]: { + [filter.fieldMetadataId]: { not: { equals: filter.value }, }, }; diff --git a/front/src/modules/ui/object/object-filter-dropdown/utils/turnFiltersIntoWhereClauseV2.ts b/front/src/modules/ui/object/object-filter-dropdown/utils/turnFiltersIntoWhereClauseV2.ts index 1458830060..781fa21ea8 100644 --- a/front/src/modules/ui/object/object-filter-dropdown/utils/turnFiltersIntoWhereClauseV2.ts +++ b/front/src/modules/ui/object/object-filter-dropdown/utils/turnFiltersIntoWhereClauseV2.ts @@ -17,11 +17,11 @@ export const turnFiltersIntoWhereClauseV2 = ( filters.forEach((filter) => { const correspondingField = fields.find( - (field) => field.id === filter.fieldId, + (field) => field.id === filter.fieldMetadataId, ); if (!correspondingField) { throw new Error( - `Could not find field ${filter.fieldId} in metadata object`, + `Could not find field ${filter.fieldMetadataId} in metadata object`, ); } diff --git a/front/src/modules/ui/object/object-sort-dropdown/components/ObjectSortDropdownButton.tsx b/front/src/modules/ui/object/object-sort-dropdown/components/ObjectSortDropdownButton.tsx index 1586f20af8..bdcabc66f3 100644 --- a/front/src/modules/ui/object/object-sort-dropdown/components/ObjectSortDropdownButton.tsx +++ b/front/src/modules/ui/object/object-sort-dropdown/components/ObjectSortDropdownButton.tsx @@ -50,7 +50,7 @@ export const ObjectSortDropdownButton = ({ const handleAddSort = (selectedSortDefinition: SortDefinition) => { toggleDropdown(); onSortSelect?.({ - fieldId: selectedSortDefinition.fieldId, + fieldMetadataId: selectedSortDefinition.fieldMetadataId, direction: selectedSortDirection, definition: selectedSortDefinition, }); diff --git a/front/src/modules/ui/object/object-sort-dropdown/types/Sort.ts b/front/src/modules/ui/object/object-sort-dropdown/types/Sort.ts index 2f39094b61..64a6b25da8 100644 --- a/front/src/modules/ui/object/object-sort-dropdown/types/Sort.ts +++ b/front/src/modules/ui/object/object-sort-dropdown/types/Sort.ts @@ -2,7 +2,7 @@ import { SortDefinition } from './SortDefinition'; import { SortDirection } from './SortDirection'; export type Sort = { - fieldId: string; + fieldMetadataId: string; direction: SortDirection; definition: SortDefinition; }; diff --git a/front/src/modules/ui/object/object-sort-dropdown/types/SortDefinition.ts b/front/src/modules/ui/object/object-sort-dropdown/types/SortDefinition.ts index 83a1134e84..4fe06f5af5 100644 --- a/front/src/modules/ui/object/object-sort-dropdown/types/SortDefinition.ts +++ b/front/src/modules/ui/object/object-sort-dropdown/types/SortDefinition.ts @@ -3,7 +3,7 @@ import { IconComponent } from '@/ui/display/icon/types/IconComponent'; import { SortDirection } from './SortDirection'; export type SortDefinition = { - fieldId: string; + fieldMetadataId: string; label: string; Icon?: IconComponent; getOrderByTemplate?: (direction: SortDirection) => any[]; diff --git a/front/src/modules/ui/object/object-sort-dropdown/utils/helpers.ts b/front/src/modules/ui/object/object-sort-dropdown/utils/helpers.ts index 0280139418..e5bc4a0851 100644 --- a/front/src/modules/ui/object/object-sort-dropdown/utils/helpers.ts +++ b/front/src/modules/ui/object/object-sort-dropdown/utils/helpers.ts @@ -10,7 +10,7 @@ export const reduceSortsToOrderBy = (sorts: Sort[]): any[] => if (sort.definition.getOrderByTemplate) { return sort.definition.getOrderByTemplate(direction); } else { - return [{ [sort.definition.fieldId]: direction }]; + return [{ [sort.definition.fieldMetadataId]: direction }]; } }) .flat(); diff --git a/front/src/modules/ui/object/object-sort-dropdown/utils/turnSortsIntoOrderByV2.ts b/front/src/modules/ui/object/object-sort-dropdown/utils/turnSortsIntoOrderByV2.ts index 306a030a23..b8a90a95b7 100644 --- a/front/src/modules/ui/object/object-sort-dropdown/utils/turnSortsIntoOrderByV2.ts +++ b/front/src/modules/ui/object/object-sort-dropdown/utils/turnSortsIntoOrderByV2.ts @@ -9,11 +9,11 @@ export const turnSortsIntoOrderByV2 = ( const sortsObject: Record = {}; sorts.forEach((sort) => { const correspondingField = fields.find( - (field) => field.id === sort.fieldId, + (field) => field.id === sort.fieldMetadataId, ); if (!correspondingField) { throw new Error( - `Could not find field ${sort.fieldId} in metadata object`, + `Could not find field ${sort.fieldMetadataId} in metadata object`, ); } const direction = diff --git a/front/src/modules/ui/object/record-table/components/ColumnHeadWithDropdown.tsx b/front/src/modules/ui/object/record-table/components/ColumnHeadWithDropdown.tsx index 4f92fc954c..dd84a7fef7 100644 --- a/front/src/modules/ui/object/record-table/components/ColumnHeadWithDropdown.tsx +++ b/front/src/modules/ui/object/record-table/components/ColumnHeadWithDropdown.tsx @@ -21,7 +21,7 @@ export const ColumnHeadWithDropdown = ({ primaryColumnKey, }: ColumnHeadWithDropdownProps) => { return ( - + } dropdownComponents={ @@ -34,7 +34,7 @@ export const ColumnHeadWithDropdown = ({ } dropdownOffset={{ x: -1 }} dropdownPlacement="bottom-start" - dropdownHotkeyScope={{ scope: column.fieldId + '-header' }} + dropdownHotkeyScope={{ scope: column.fieldMetadataId + '-header' }} /> ); diff --git a/front/src/modules/ui/object/record-table/components/RecordTableColumnDropdownMenu.tsx b/front/src/modules/ui/object/record-table/components/RecordTableColumnDropdownMenu.tsx index ad2ba13a15..902b7a01df 100644 --- a/front/src/modules/ui/object/record-table/components/RecordTableColumnDropdownMenu.tsx +++ b/front/src/modules/ui/object/record-table/components/RecordTableColumnDropdownMenu.tsx @@ -46,7 +46,7 @@ export const RecordTableColumnDropdownMenu = ({ handleColumnVisibilityChange(column); }; - return column.fieldId === primaryColumnKey ? ( + return column.fieldMetadataId === primaryColumnKey ? ( <> ) : ( diff --git a/front/src/modules/ui/object/record-table/components/RecordTableHeader.tsx b/front/src/modules/ui/object/record-table/components/RecordTableHeader.tsx index 0fbbae3a12..196e6f17d9 100644 --- a/front/src/modules/ui/object/record-table/components/RecordTableHeader.tsx +++ b/front/src/modules/ui/object/record-table/components/RecordTableHeader.tsx @@ -156,7 +156,7 @@ export const RecordTableHeader = () => { if (nextWidth !== tableColumnsByKey[resizedFieldKey].size) { const nextColumns = tableColumns.map((column) => - column.fieldId === resizedFieldKey + column.fieldMetadataId === resizedFieldKey ? { ...column, size: nextWidth } : column, ); @@ -194,11 +194,13 @@ export const RecordTableHeader = () => { {visibleTableColumns.map((column) => ( @@ -209,20 +211,21 @@ export const RecordTableHeader = () => { isLastColumn={ column.position === visibleTableColumns.length - 1 } - primaryColumnKey={primaryColumn?.fieldId || ''} + primaryColumnKey={primaryColumn?.fieldMetadataId || ''} /> { - setResizedFieldKey(column.fieldId); + setResizedFieldKey(column.fieldMetadataId); }} /> ))} - {hiddenTableColumns.length > 0 && ( - + + + {hiddenTableColumns.length > 0 && ( @@ -239,8 +242,8 @@ export const RecordTableHeader = () => { }} /> - - )} + )} + ); diff --git a/front/src/modules/ui/object/record-table/components/RecordTableHeaderPlusButtonContent.tsx b/front/src/modules/ui/object/record-table/components/RecordTableHeaderPlusButtonContent.tsx index cb9b1b791e..2be385f24c 100644 --- a/front/src/modules/ui/object/record-table/components/RecordTableHeaderPlusButtonContent.tsx +++ b/front/src/modules/ui/object/record-table/components/RecordTableHeaderPlusButtonContent.tsx @@ -32,7 +32,7 @@ export const RecordTableHeaderPlusButtonContent = () => { {hiddenTableColumns.map((column) => ( columnA.position - columnB.position) .map((column, columnIndex) => { return ( - + ); diff --git a/front/src/modules/ui/object/record-table/hooks/useTableColumns.ts b/front/src/modules/ui/object/record-table/hooks/useTableColumns.ts index 1e8f380de1..ced3ebe546 100644 --- a/front/src/modules/ui/object/record-table/hooks/useTableColumns.ts +++ b/front/src/modules/ui/object/record-table/hooks/useTableColumns.ts @@ -47,13 +47,14 @@ export const useTableColumns = () => { viewField: Omit, 'size' | 'position'>, ) => { const isNewColumn = !tableColumns.some( - (tableColumns) => tableColumns.fieldId === viewField.fieldId, + (tableColumns) => + tableColumns.fieldMetadataId === viewField.fieldMetadataId, ); if (isNewColumn) { const newColumn = availableTableColumns.find( (availableTableColumn) => - availableTableColumn.fieldId === viewField.fieldId, + availableTableColumn.fieldMetadataId === viewField.fieldMetadataId, ); if (!newColumn) return; @@ -65,7 +66,7 @@ export const useTableColumns = () => { await handleColumnsChange(nextColumns); } else { const nextColumns = tableColumns.map((previousColumn) => - previousColumn.fieldId === viewField.fieldId + previousColumn.fieldMetadataId === viewField.fieldMetadataId ? { ...previousColumn, isVisible: !viewField.isVisible } : previousColumn, ); @@ -82,7 +83,8 @@ export const useTableColumns = () => { column: ColumnDefinition, ) => { const currentColumnArrayIndex = visibleTableColumns.findIndex( - (visibleColumn) => visibleColumn.fieldId === column.fieldId, + (visibleColumn) => + visibleColumn.fieldMetadataId === column.fieldMetadataId, ); const columns = handleColumnMove( diff --git a/front/src/modules/ui/object/record-table/record-table-cell/hooks/useTableCell.ts b/front/src/modules/ui/object/record-table/record-table-cell/hooks/useTableCell.ts index 9b7d357ac9..b578bbacf2 100644 --- a/front/src/modules/ui/object/record-table/record-table-cell/hooks/useTableCell.ts +++ b/front/src/modules/ui/object/record-table/record-table-cell/hooks/useTableCell.ts @@ -42,7 +42,7 @@ export const useTableCell = () => { const [, setFieldInitialValue] = useRecoilState( entityFieldInitialValueFamilyState({ entityId, - fieldId: fieldDefinition.fieldId, + fieldMetadataId: fieldDefinition.fieldMetadataId, }), ); diff --git a/front/src/modules/ui/object/record-table/states/selectors/hiddenTableColumnsScopedSelector.ts b/front/src/modules/ui/object/record-table/states/selectors/hiddenTableColumnsScopedSelector.ts index d672233f85..658bf6e307 100644 --- a/front/src/modules/ui/object/record-table/states/selectors/hiddenTableColumnsScopedSelector.ts +++ b/front/src/modules/ui/object/record-table/states/selectors/hiddenTableColumnsScopedSelector.ts @@ -9,10 +9,10 @@ export const hiddenTableColumnsScopedSelector = selectorFamily({ (scopeId: string) => ({ get }) => { const columns = get(tableColumnsScopedState({ scopeId })); - const columnKeys = columns.map(({ fieldId }) => fieldId); + const columnKeys = columns.map(({ fieldMetadataId }) => fieldMetadataId); const otherAvailableColumns = get( availableTableColumnsScopedState({ scopeId }), - ).filter(({ fieldId }) => !columnKeys.includes(fieldId)); + ).filter(({ fieldMetadataId }) => !columnKeys.includes(fieldMetadataId)); return [ ...columns.filter((column) => !column.isVisible), diff --git a/front/src/modules/ui/object/record-table/states/selectors/savedTableColumnsByKeyFamilySelector.ts b/front/src/modules/ui/object/record-table/states/selectors/savedTableColumnsByKeyFamilySelector.ts index 1b8f121f84..094d74f620 100644 --- a/front/src/modules/ui/object/record-table/states/selectors/savedTableColumnsByKeyFamilySelector.ts +++ b/front/src/modules/ui/object/record-table/states/selectors/savedTableColumnsByKeyFamilySelector.ts @@ -12,5 +12,8 @@ export const savedTableColumnsByKeyFamilySelector = selectorFamily({ ({ get }) => get(savedTableColumnsFamilyState(viewId)).reduce< Record> - >((result, column) => ({ ...result, [column.fieldId]: column }), {}), + >( + (result, column) => ({ ...result, [column.fieldMetadataId]: column }), + {}, + ), }); diff --git a/front/src/modules/ui/object/record-table/states/selectors/tableColumnsByKeyScopedSelector.ts b/front/src/modules/ui/object/record-table/states/selectors/tableColumnsByKeyScopedSelector.ts index 419e32b557..7e4ab58263 100644 --- a/front/src/modules/ui/object/record-table/states/selectors/tableColumnsByKeyScopedSelector.ts +++ b/front/src/modules/ui/object/record-table/states/selectors/tableColumnsByKeyScopedSelector.ts @@ -12,5 +12,8 @@ export const tableColumnsByKeyScopedSelector = selectorFamily({ ({ get }) => get(tableColumnsScopedState({ scopeId })).reduce< Record> - >((result, column) => ({ ...result, [column.fieldId]: column }), {}), + >( + (result, column) => ({ ...result, [column.fieldMetadataId]: column }), + {}, + ), }); diff --git a/front/src/modules/ui/object/record-table/states/selectors/visibleTableColumnsScopedSelector.ts b/front/src/modules/ui/object/record-table/states/selectors/visibleTableColumnsScopedSelector.ts index 476a1a1d36..348f371d84 100644 --- a/front/src/modules/ui/object/record-table/states/selectors/visibleTableColumnsScopedSelector.ts +++ b/front/src/modules/ui/object/record-table/states/selectors/visibleTableColumnsScopedSelector.ts @@ -11,12 +11,13 @@ export const visibleTableColumnsScopedSelector = selectorFamily({ const columns = get(tableColumnsScopedState({ scopeId })); const availableColumnKeys = get( availableTableColumnsScopedState({ scopeId }), - ).map(({ fieldId }) => fieldId); + ).map(({ fieldMetadataId }) => fieldMetadataId); return [...columns] .filter( (column) => - column.isVisible && availableColumnKeys.includes(column.fieldId), + column.isVisible && + availableColumnKeys.includes(column.fieldMetadataId), ) .sort((a, b) => a.position - b.position); }, diff --git a/front/src/modules/views/components/ViewBarDetails.tsx b/front/src/modules/views/components/ViewBarDetails.tsx index 97a2542846..a362e50f74 100644 --- a/front/src/modules/views/components/ViewBarDetails.tsx +++ b/front/src/modules/views/components/ViewBarDetails.tsx @@ -126,12 +126,12 @@ export const ViewBarDetails = ({ {currentViewSorts?.map((sort) => { return ( removeViewSort(sort.fieldId)} + onRemove={() => removeViewSort(sort.fieldMetadataId)} /> ); })} @@ -143,15 +143,15 @@ export const ViewBarDetails = ({ {currentViewFilters?.map((filter) => { return ( { - removeViewFilter(filter.fieldId); + removeViewFilter(filter.fieldMetadataId); }} /> ); diff --git a/front/src/modules/views/components/ViewBarEffect.tsx b/front/src/modules/views/components/ViewBarEffect.tsx index 24e97e52a1..fa074ab982 100644 --- a/front/src/modules/views/components/ViewBarEffect.tsx +++ b/front/src/modules/views/components/ViewBarEffect.tsx @@ -35,14 +35,14 @@ export const ViewBarEffect = () => { useFindManyObjects({ objectNamePlural: 'viewsV2', - filter: { type: { eq: viewType }, objectId: { eq: viewObjectId } }, + filter: { type: { eq: viewType }, objectMetadataId: { eq: viewObjectId } }, onCompleted: useRecoilCallback( ({ snapshot, set }) => async (data: PaginatedObjectTypeResults) => { const nextViews = data.edges.map((view) => ({ id: view.node.id, name: view.node.name, - objectId: view.node.objectId, + objectMetadataId: view.node.objectMetadataId, })); const { viewsState } = getViewScopedStatesFromSnapshot({ @@ -132,7 +132,8 @@ export const ViewBarEffect = () => { const queriedViewFilters = data.edges .map(({ node }) => { const availableFilterDefinition = availableFilterDefinitions.find( - (filterDefinition) => filterDefinition.fieldId === node.fieldId, + (filterDefinition) => + filterDefinition.fieldMetadataId === node.fieldMetadataId, ); if (!availableFilterDefinition) return null; @@ -185,14 +186,14 @@ export const ViewBarEffect = () => { const queriedViewSorts = data.edges .map(({ node }) => { const availableSortDefinition = availableSortDefinitions.find( - (sort) => sort.fieldId === node.fieldId, + (sort) => sort.fieldMetadataId === node.fieldMetadataId, ); if (!availableSortDefinition) return null; return { id: node.id, - fieldId: node.fieldId, + fieldMetadataId: node.fieldMetadataId, direction: node.direction, definition: availableSortDefinition, }; diff --git a/front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx b/front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx index a8eab87b73..bcfe9a5377 100644 --- a/front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx +++ b/front/src/modules/views/components/ViewFieldsVisibilityDropdownSection.tsx @@ -97,12 +97,12 @@ export const ViewFieldsVisibilityDropdownSection = ({ .sort((a, b) => a.position - b.position) .map((field, index) => ( ( { mutation: createOneMutation, variables: { input: { - fieldId: viewField.fieldId, + fieldMetadataId: viewField.fieldMetadataId, viewId: viewIdToPersist, isVisible: viewField.isVisible, size: viewField.size, @@ -76,18 +76,18 @@ export const useViewFields = (viewScopeId: string) => { }; const viewFieldsToCreate = viewFieldsToPersist.filter( - (viewField) => !savedViewFieldsByKey[viewField.fieldId], + (viewField) => !savedViewFieldsByKey[viewField.fieldMetadataId], ); const viewFieldsToUpdate = viewFieldsToPersist.filter( (viewFieldToPersit) => - savedViewFieldsByKey[viewFieldToPersit.fieldId] && - (savedViewFieldsByKey[viewFieldToPersit.fieldId].size !== + savedViewFieldsByKey[viewFieldToPersit.fieldMetadataId] && + (savedViewFieldsByKey[viewFieldToPersit.fieldMetadataId].size !== viewFieldToPersit.size || - savedViewFieldsByKey[viewFieldToPersit.fieldId].position !== - viewFieldToPersit.position || - savedViewFieldsByKey[viewFieldToPersit.fieldId].isVisible !== - viewFieldToPersit.isVisible), + savedViewFieldsByKey[viewFieldToPersit.fieldMetadataId] + .position !== viewFieldToPersit.position || + savedViewFieldsByKey[viewFieldToPersit.fieldMetadataId] + .isVisible !== viewFieldToPersit.isVisible), ); await _createViewFields(viewFieldsToCreate); diff --git a/front/src/modules/views/hooks/internal/useViewFilters.ts b/front/src/modules/views/hooks/internal/useViewFilters.ts index e1354347bb..8ec7d7620e 100644 --- a/front/src/modules/views/hooks/internal/useViewFilters.ts +++ b/front/src/modules/views/hooks/internal/useViewFilters.ts @@ -53,7 +53,7 @@ export const useViewFilters = (viewScopeId: string) => { mutation: createOneMutation, variables: { input: { - fieldId: viewFilter.fieldId, + fieldMetadataId: viewFilter.fieldMetadataId, viewId: viewId ?? currentViewId, value: viewFilter.value, displayValue: viewFilter.displayValue, @@ -102,19 +102,23 @@ export const useViewFilters = (viewScopeId: string) => { }; const filtersToCreate = currentViewFilters.filter( - (filter) => !savedViewFiltersByKey[filter.fieldId], + (filter) => !savedViewFiltersByKey[filter.fieldMetadataId], ); await createViewFilters(filtersToCreate); const filtersToUpdate = currentViewFilters.filter( (filter) => - savedViewFiltersByKey[filter.fieldId] && - (savedViewFiltersByKey[filter.fieldId].operand !== filter.operand || - savedViewFiltersByKey[filter.fieldId].value !== filter.value), + savedViewFiltersByKey[filter.fieldMetadataId] && + (savedViewFiltersByKey[filter.fieldMetadataId].operand !== + filter.operand || + savedViewFiltersByKey[filter.fieldMetadataId].value !== + filter.value), ); await updateViewFilters(filtersToUpdate); - const filterKeys = currentViewFilters.map((filter) => filter.fieldId); + const filterKeys = currentViewFilters.map( + (filter) => filter.fieldMetadataId, + ); const filterKeysToDelete = Object.keys(savedViewFiltersByKey).filter( (previousFilterKey) => !filterKeys.includes(previousFilterKey), ); @@ -159,12 +163,13 @@ export const useViewFilters = (viewScopeId: string) => { } const existingSavedFilterId = - savedViewFiltersByKey[filterToUpsert.fieldId]?.id; + savedViewFiltersByKey[filterToUpsert.fieldMetadataId]?.id; set(currentViewFiltersState, (filters) => { const newViewFilters = produce(filters, (filtersDraft) => { const existingFilterIndex = filtersDraft.findIndex( - (filter) => filter.fieldId === filterToUpsert.fieldId, + (filter) => + filter.fieldMetadataId === filterToUpsert.fieldMetadataId, ); if (existingFilterIndex === -1) { @@ -189,7 +194,7 @@ export const useViewFilters = (viewScopeId: string) => { const removeViewFilter = useRecoilCallback( ({ snapshot, set }) => - (fieldId: string) => { + (fieldMetadataId: string) => { const { currentViewId, currentViewFilters, onViewFiltersChange } = getViewScopedStateValuesFromSnapshot({ snapshot, @@ -201,7 +206,7 @@ export const useViewFilters = (viewScopeId: string) => { } const newViewFilters = currentViewFilters.filter((filter) => { - return filter.fieldId !== fieldId; + return filter.fieldMetadataId !== fieldMetadataId; }); set(currentViewFiltersState, newViewFilters); onViewFiltersChange?.(newViewFilters); diff --git a/front/src/modules/views/hooks/internal/useViewSorts.ts b/front/src/modules/views/hooks/internal/useViewSorts.ts index 3b815764eb..9e308f8087 100644 --- a/front/src/modules/views/hooks/internal/useViewSorts.ts +++ b/front/src/modules/views/hooks/internal/useViewSorts.ts @@ -54,7 +54,7 @@ export const useViewSorts = (viewScopeId: string) => { mutation: createOneMutation, variables: { input: { - fieldId: viewSort.fieldId, + fieldMetadataId: viewSort.fieldMetadataId, viewId: viewId ?? currentViewId, direction: viewSort.direction, }, @@ -99,19 +99,20 @@ export const useViewSorts = (viewScopeId: string) => { }; const sortsToCreate = currentViewSorts.filter( - (sort) => !savedViewSortsByKey[sort.fieldId], + (sort) => !savedViewSortsByKey[sort.fieldMetadataId], ); await createViewSorts(sortsToCreate); const sortsToUpdate = currentViewSorts.filter( (sort) => - savedViewSortsByKey[sort.fieldId] && - savedViewSortsByKey[sort.fieldId].direction !== sort.direction, + savedViewSortsByKey[sort.fieldMetadataId] && + savedViewSortsByKey[sort.fieldMetadataId].direction !== + sort.direction, ); await updateViewSorts(sortsToUpdate); - const sortKeys = currentViewSorts.map((sort) => sort.fieldId); + const sortKeys = currentViewSorts.map((sort) => sort.fieldMetadataId); const sortKeysToDelete = Object.keys(savedViewSortsByKey).filter( (previousSortKey) => !sortKeys.includes(previousSortKey), ); @@ -155,12 +156,12 @@ export const useViewSorts = (viewScopeId: string) => { } const existingSavedSortId = - savedViewSortsByKey[sortToUpsert.fieldId]?.id; + savedViewSortsByKey[sortToUpsert.fieldMetadataId]?.id; set(currentViewSortsState, (sorts) => { const newViewSorts = produce(sorts, (sortsDraft) => { const existingSortIndex = sortsDraft.findIndex( - (sort) => sort.fieldId === sortToUpsert.fieldId, + (sort) => sort.fieldMetadataId === sortToUpsert.fieldMetadataId, ); if (existingSortIndex === -1) { @@ -182,7 +183,7 @@ export const useViewSorts = (viewScopeId: string) => { const removeViewSort = useRecoilCallback( ({ snapshot, set }) => - (fieldId: string) => { + (fieldMetadataId: string) => { const { currentViewId, onViewSortsChange, currentViewSorts } = getViewScopedStateValuesFromSnapshot({ snapshot, @@ -194,7 +195,7 @@ export const useViewSorts = (viewScopeId: string) => { } const newViewSorts = currentViewSorts.filter((filter) => { - return filter.fieldId !== fieldId; + return filter.fieldMetadataId !== fieldMetadataId; }); set(currentViewSortsState, newViewSorts); onViewSortsChange?.(newViewSorts); diff --git a/front/src/modules/views/hooks/internal/useViews.ts b/front/src/modules/views/hooks/internal/useViews.ts index 5190607b33..a41edf6237 100644 --- a/front/src/modules/views/hooks/internal/useViews.ts +++ b/front/src/modules/views/hooks/internal/useViews.ts @@ -34,7 +34,7 @@ export const useViews = (scopeId: string) => { variables: { input: { ...view, - objectId: viewObjectId, + objectMetadataId: viewObjectId, type: viewType, }, }, diff --git a/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts b/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts index aba69d834c..fc56e7fdee 100644 --- a/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts +++ b/front/src/modules/views/states/selectors/savedViewFieldByKeyScopedFamilySelector.ts @@ -25,7 +25,7 @@ export const savedViewFieldByKeyScopedFamilySelector = selectorFamily({ familyKey: viewId, }), ).reduce>( - (result, column) => ({ ...result, [column.fieldId]: column }), + (result, column) => ({ ...result, [column.fieldMetadataId]: column }), {}, ); }, diff --git a/front/src/modules/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector.ts b/front/src/modules/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector.ts index d7e03a0bb5..235d5375f6 100644 --- a/front/src/modules/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector.ts +++ b/front/src/modules/views/states/selectors/savedViewFiltersByKeyScopedFamilySelector.ts @@ -18,7 +18,7 @@ export const savedViewFiltersByKeyScopedFamilySelector = selectorFamily({ familyKey: viewId, }), ).reduce>( - (result, filter) => ({ ...result, [filter.fieldId]: filter }), + (result, filter) => ({ ...result, [filter.fieldMetadataId]: filter }), {}, ); }, diff --git a/front/src/modules/views/states/selectors/savedViewSortsByKeyScopedFamilySelector.ts b/front/src/modules/views/states/selectors/savedViewSortsByKeyScopedFamilySelector.ts index cdfe2bfaee..2348464d40 100644 --- a/front/src/modules/views/states/selectors/savedViewSortsByKeyScopedFamilySelector.ts +++ b/front/src/modules/views/states/selectors/savedViewSortsByKeyScopedFamilySelector.ts @@ -18,7 +18,7 @@ export const savedViewSortsByKeyScopedFamilySelector = selectorFamily({ familyKey: viewId, }), ).reduce>( - (result, sort) => ({ ...result, [sort.fieldId]: sort }), + (result, sort) => ({ ...result, [sort.fieldMetadataId]: sort }), {}, ); }, diff --git a/front/src/modules/views/types/View.ts b/front/src/modules/views/types/View.ts index 484b49db77..c2e312219c 100644 --- a/front/src/modules/views/types/View.ts +++ b/front/src/modules/views/types/View.ts @@ -1 +1 @@ -export type View = { id: string; name: string; objectId: string }; +export type View = { id: string; name: string; objectMetadataId: string }; diff --git a/front/src/modules/views/types/ViewField.ts b/front/src/modules/views/types/ViewField.ts index c7d3c1aa6c..536796da9a 100644 --- a/front/src/modules/views/types/ViewField.ts +++ b/front/src/modules/views/types/ViewField.ts @@ -3,7 +3,7 @@ import { ColumnDefinition } from '@/ui/object/record-table/types/ColumnDefinitio export type ViewField = { id: string; - fieldId: string; + fieldMetadataId: string; position: number; isVisible: boolean; size: number; diff --git a/front/src/modules/views/types/ViewFilter.ts b/front/src/modules/views/types/ViewFilter.ts index 44c3edb76e..49e78ee1f6 100644 --- a/front/src/modules/views/types/ViewFilter.ts +++ b/front/src/modules/views/types/ViewFilter.ts @@ -4,7 +4,7 @@ import { ViewFilterOperand } from './ViewFilterOperand'; export type ViewFilter = { id?: string; - fieldId: string; + fieldMetadataId: string; operand: ViewFilterOperand; value: string; displayValue: string; diff --git a/front/src/modules/views/types/ViewSort.ts b/front/src/modules/views/types/ViewSort.ts index 8e486c7170..e2b2581d25 100644 --- a/front/src/modules/views/types/ViewSort.ts +++ b/front/src/modules/views/types/ViewSort.ts @@ -3,7 +3,7 @@ import { SortDirection } from '@/ui/object/object-sort-dropdown/types/SortDirect export type ViewSort = { id?: string; - fieldId: string; + fieldMetadataId: string; direction: SortDirection; definition: SortDefinition; }; diff --git a/front/src/modules/views/utils/mapColumnDefinitionToViewField.ts b/front/src/modules/views/utils/mapColumnDefinitionToViewField.ts index 7e4ed2a701..470bd42f39 100644 --- a/front/src/modules/views/utils/mapColumnDefinitionToViewField.ts +++ b/front/src/modules/views/utils/mapColumnDefinitionToViewField.ts @@ -8,7 +8,7 @@ export const mapColumnDefinitionsToViewFields = ( ): ViewField[] => { return columnDefinitions.map((columnDefinition) => ({ id: columnDefinition.viewFieldId || '', - fieldId: columnDefinition.fieldId, + fieldMetadataId: columnDefinition.fieldMetadataId, position: columnDefinition.position, size: columnDefinition.size, isVisible: columnDefinition.isVisible ?? true, diff --git a/front/src/modules/views/utils/mapViewFieldsToBoardFieldDefinitions.ts b/front/src/modules/views/utils/mapViewFieldsToBoardFieldDefinitions.ts index 700c477be0..be4f299091 100644 --- a/front/src/modules/views/utils/mapViewFieldsToBoardFieldDefinitions.ts +++ b/front/src/modules/views/utils/mapViewFieldsToBoardFieldDefinitions.ts @@ -11,12 +11,12 @@ export const mapViewFieldsToBoardFieldDefinitions = ( return viewFields .map((viewField) => { const correspondingFieldMetadata = fieldsMetadata.find( - ({ fieldId }) => viewField.fieldId === fieldId, + ({ fieldMetadataId }) => viewField.fieldMetadataId === fieldMetadataId, ); return correspondingFieldMetadata ? { - fieldId: viewField.fieldId, + fieldMetadataId: viewField.fieldMetadataId, label: correspondingFieldMetadata.label, metadata: correspondingFieldMetadata.metadata, entityChipDisplayMapper: diff --git a/front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts b/front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts index 901b07e057..d3119a6ee0 100644 --- a/front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts +++ b/front/src/modules/views/utils/mapViewFieldsToColumnDefinitions.ts @@ -11,12 +11,12 @@ export const mapViewFieldsToColumnDefinitions = ( return viewFields .map((viewField) => { const correspondingFieldMetadata = fieldsMetadata.find( - ({ fieldId }) => viewField.fieldId === fieldId, + ({ fieldMetadataId }) => viewField.fieldMetadataId === fieldMetadataId, ); return correspondingFieldMetadata ? { - fieldId: viewField.fieldId, + fieldMetadataId: viewField.fieldMetadataId, label: correspondingFieldMetadata.label, metadata: correspondingFieldMetadata.metadata, entityChipDisplayMapper: diff --git a/front/src/modules/views/utils/mapViewFiltersToFilters.ts b/front/src/modules/views/utils/mapViewFiltersToFilters.ts index fcc1144c20..00ae879130 100644 --- a/front/src/modules/views/utils/mapViewFiltersToFilters.ts +++ b/front/src/modules/views/utils/mapViewFiltersToFilters.ts @@ -7,7 +7,7 @@ export const mapViewFiltersToFilters = ( ): Filter[] => { return viewFilters.map((viewFilter) => { return { - fieldId: viewFilter.fieldId, + fieldMetadataId: viewFilter.fieldMetadataId, value: viewFilter.value, displayValue: viewFilter.displayValue, operand: viewFilter.operand, diff --git a/front/src/modules/views/utils/mapViewSortsToSorts.ts b/front/src/modules/views/utils/mapViewSortsToSorts.ts index 360d0df19d..d49250054c 100644 --- a/front/src/modules/views/utils/mapViewSortsToSorts.ts +++ b/front/src/modules/views/utils/mapViewSortsToSorts.ts @@ -5,7 +5,7 @@ import { ViewSort } from '../types/ViewSort'; export const mapViewSortsToSorts = (viewSorts: ViewSort[]): Sort[] => { return viewSorts.map((viewSort) => { return { - fieldId: viewSort.fieldId, + fieldMetadataId: viewSort.fieldMetadataId, direction: viewSort.direction, definition: viewSort.definition, }; diff --git a/front/src/pages/companies/CompanyShow.tsx b/front/src/pages/companies/CompanyShow.tsx index ec02de3e91..e3a9e0e234 100644 --- a/front/src/pages/companies/CompanyShow.tsx +++ b/front/src/pages/companies/CompanyShow.tsx @@ -93,10 +93,11 @@ export const CompanyShow = () => { {companyShowFieldDefinitions.map((fieldDefinition) => { return ( [] = [ { - fieldId: 'domainName', + fieldMetadataId: 'domainName', label: 'Domain name', Icon: IconLink, type: 'URL', @@ -32,7 +32,7 @@ export const companyShowFieldDefinitions: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'accountOwner', + fieldMetadataId: 'accountOwner', label: 'Account owner', Icon: IconUserCircle, type: 'RELATION', @@ -49,7 +49,7 @@ export const companyShowFieldDefinitions: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'employees', + fieldMetadataId: 'employees', label: 'Employees', Icon: IconUsers, type: 'NUMBER', @@ -59,7 +59,7 @@ export const companyShowFieldDefinitions: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'address', + fieldMetadataId: 'address', label: 'Address', Icon: IconMap, type: 'TEXT', @@ -69,7 +69,7 @@ export const companyShowFieldDefinitions: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'idealCustomerProfile', + fieldMetadataId: 'idealCustomerProfile', label: 'ICP', Icon: IconTarget, type: 'BOOLEAN', @@ -78,7 +78,7 @@ export const companyShowFieldDefinitions: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'xUrl', + fieldMetadataId: 'xUrl', label: 'Twitter', Icon: IconBrandX, type: 'URL', @@ -88,7 +88,7 @@ export const companyShowFieldDefinitions: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Created at', Icon: IconCalendar, type: 'DATE', diff --git a/front/src/pages/companies/constants/companyTableFilterDefinitions.tsx b/front/src/pages/companies/constants/companyTableFilterDefinitions.tsx index 8a467c9132..ace176c23f 100644 --- a/front/src/pages/companies/constants/companyTableFilterDefinitions.tsx +++ b/front/src/pages/companies/constants/companyTableFilterDefinitions.tsx @@ -13,37 +13,37 @@ import { Company } from '~/generated/graphql'; export const companyTableFilterDefinitions: FilterDefinitionByEntity[] = [ { - fieldId: 'name', + fieldMetadataId: 'name', label: 'Name', Icon: IconBuildingSkyscraper, type: 'TEXT', }, { - fieldId: 'employees', + fieldMetadataId: 'employees', label: 'Employees', Icon: IconUsers, type: 'NUMBER', }, { - fieldId: 'domainName', + fieldMetadataId: 'domainName', label: 'URL', Icon: IconLink, type: 'TEXT', }, { - fieldId: 'address', + fieldMetadataId: 'address', label: 'Address', Icon: IconMap, type: 'TEXT', }, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Created at', Icon: IconCalendarEvent, type: 'DATE', }, { - fieldId: 'accountOwnerId', + fieldMetadataId: 'accountOwnerId', label: 'Account owner', Icon: IconUser, type: 'ENTITY', diff --git a/front/src/pages/companies/constants/companyTableSortDefinitions.tsx b/front/src/pages/companies/constants/companyTableSortDefinitions.tsx index b2e999338b..284ababfb3 100644 --- a/front/src/pages/companies/constants/companyTableSortDefinitions.tsx +++ b/front/src/pages/companies/constants/companyTableSortDefinitions.tsx @@ -9,27 +9,27 @@ import { SortDefinition } from '@/ui/object/object-sort-dropdown/types/SortDefin export const companyTableSortDefinitions: SortDefinition[] = [ { - fieldId: 'name', + fieldMetadataId: 'name', label: 'Name', Icon: IconBuildingSkyscraper, }, { - fieldId: 'employees', + fieldMetadataId: 'employees', label: 'Employees', Icon: IconUsers, }, { - fieldId: 'domainName', + fieldMetadataId: 'domainName', label: 'Url', Icon: IconLink, }, { - fieldId: 'address', + fieldMetadataId: 'address', label: 'Address', Icon: IconMap, }, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Creation', Icon: IconCalendarEvent, }, diff --git a/front/src/pages/opportunities/constants/opportunityBoardFilterDefinitions.tsx b/front/src/pages/opportunities/constants/opportunityBoardFilterDefinitions.tsx index 00210f28eb..17218af0cf 100644 --- a/front/src/pages/opportunities/constants/opportunityBoardFilterDefinitions.tsx +++ b/front/src/pages/opportunities/constants/opportunityBoardFilterDefinitions.tsx @@ -13,26 +13,26 @@ import { FilterDropdownPeopleSearchSelect } from '../../../modules/people/compon export const opportunityBoardFilterDefinitions: FilterDefinitionByEntity[] = [ { - fieldId: 'amount', + fieldMetadataId: 'amount', label: 'Amount', Icon: IconCurrencyDollar, type: 'NUMBER', }, { - fieldId: 'closeDate', + fieldMetadataId: 'closeDate', label: 'Close date', Icon: IconCalendarEvent, type: 'DATE', }, { - fieldId: 'companyId', + fieldMetadataId: 'companyId', label: 'Company', Icon: IconBuildingSkyscraper, type: 'ENTITY', entitySelectComponent: , }, { - fieldId: 'pointOfContactId', + fieldMetadataId: 'pointOfContactId', label: 'Point of contact', Icon: IconUser, type: 'ENTITY', diff --git a/front/src/pages/opportunities/constants/opportunityBoardSortDefinitions.tsx b/front/src/pages/opportunities/constants/opportunityBoardSortDefinitions.tsx index 4cd9de0d31..cc75e15e00 100644 --- a/front/src/pages/opportunities/constants/opportunityBoardSortDefinitions.tsx +++ b/front/src/pages/opportunities/constants/opportunityBoardSortDefinitions.tsx @@ -3,17 +3,17 @@ import { SortDefinition } from '@/ui/object/object-sort-dropdown/types/SortDefin export const opportunityBoardSortDefinitions: SortDefinition[] = [ { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Creation', Icon: IconCalendarEvent, }, { - fieldId: 'amount', + fieldMetadataId: 'amount', label: 'Amount', Icon: IconCurrencyDollar, }, { - fieldId: 'closeDate', + fieldMetadataId: 'closeDate', label: 'Expected close date', Icon: IconCalendarEvent, }, diff --git a/front/src/pages/people/constants/personShowFieldDefinitions.tsx b/front/src/pages/people/constants/personShowFieldDefinitions.tsx index 38a4ed0c47..08abc5ac77 100644 --- a/front/src/pages/people/constants/personShowFieldDefinitions.tsx +++ b/front/src/pages/people/constants/personShowFieldDefinitions.tsx @@ -23,7 +23,7 @@ import { getLogoUrlFromDomainName } from '~/utils'; export const personShowFieldDefinition: FieldDefinition[] = [ { - fieldId: 'email', + fieldMetadataId: 'email', label: 'Email', Icon: IconMail, type: 'TEXT', @@ -33,7 +33,7 @@ export const personShowFieldDefinition: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'company', + fieldMetadataId: 'company', label: 'Company', Icon: IconBuildingSkyscraper, type: 'RELATION', @@ -50,7 +50,7 @@ export const personShowFieldDefinition: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'phone', + fieldMetadataId: 'phone', label: 'Phone', Icon: IconPhone, type: 'PHONE', @@ -60,7 +60,7 @@ export const personShowFieldDefinition: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'jobTitle', + fieldMetadataId: 'jobTitle', label: 'Job Title', Icon: IconBriefcase, type: 'TEXT', @@ -70,7 +70,7 @@ export const personShowFieldDefinition: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'city', + fieldMetadataId: 'city', label: 'City', Icon: IconMap, type: 'TEXT', @@ -80,7 +80,7 @@ export const personShowFieldDefinition: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'linkedinUrl', + fieldMetadataId: 'linkedinUrl', label: 'Linkedin URL', Icon: IconBrandLinkedin, type: 'URL', @@ -90,7 +90,7 @@ export const personShowFieldDefinition: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'xUrl', + fieldMetadataId: 'xUrl', label: 'X URL', Icon: IconBrandX, type: 'URL', @@ -100,7 +100,7 @@ export const personShowFieldDefinition: FieldDefinition[] = [ }, } satisfies FieldDefinition, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Created at', Icon: IconCalendar, type: 'DATE', diff --git a/front/src/pages/people/constants/personTableFilterDefinitions.tsx b/front/src/pages/people/constants/personTableFilterDefinitions.tsx index 983c6de72f..be4ade7e11 100644 --- a/front/src/pages/people/constants/personTableFilterDefinitions.tsx +++ b/front/src/pages/people/constants/personTableFilterDefinitions.tsx @@ -13,25 +13,25 @@ import { Person } from '~/generated/graphql'; export const personTableFilterDefinitions: FilterDefinitionByEntity[] = [ { - fieldId: 'firstName', + fieldMetadataId: 'firstName', label: 'First name', Icon: IconUser, type: 'TEXT', }, { - fieldId: 'lastName', + fieldMetadataId: 'lastName', label: 'Last name', Icon: IconUser, type: 'TEXT', }, { - fieldId: 'email', + fieldMetadataId: 'email', label: 'Email', Icon: IconMail, type: 'TEXT', }, { - fieldId: 'companyId', + fieldMetadataId: 'companyId', label: 'Company', Icon: IconBuildingSkyscraper, type: 'ENTITY', @@ -39,19 +39,19 @@ export const personTableFilterDefinitions: FilterDefinitionByEntity[] = entitySelectComponent: , }, { - fieldId: 'phone', + fieldMetadataId: 'phone', label: 'Phone', Icon: IconPhone, type: 'TEXT', }, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Created at', Icon: IconCalendarEvent, type: 'DATE', }, { - fieldId: 'city', + fieldMetadataId: 'city', label: 'City', Icon: IconMap, type: 'TEXT', diff --git a/front/src/pages/people/constants/personTableSortDefinitions.tsx b/front/src/pages/people/constants/personTableSortDefinitions.tsx index 10e2e440e6..6c9eff6308 100644 --- a/front/src/pages/people/constants/personTableSortDefinitions.tsx +++ b/front/src/pages/people/constants/personTableSortDefinitions.tsx @@ -11,7 +11,7 @@ import { SortDirection } from '@/ui/object/object-sort-dropdown/types/SortDirect export const personTableSortDefinitions: SortDefinition[] = [ { - fieldId: 'fullname', + fieldMetadataId: 'fullname', label: 'People', Icon: IconUser, @@ -21,7 +21,7 @@ export const personTableSortDefinitions: SortDefinition[] = [ ], }, { - fieldId: 'company_name', + fieldMetadataId: 'company_name', label: 'Company', Icon: IconBuildingSkyscraper, getOrderByTemplate: (direction: SortDirection) => [ @@ -29,22 +29,22 @@ export const personTableSortDefinitions: SortDefinition[] = [ ], }, { - fieldId: 'email', + fieldMetadataId: 'email', label: 'Email', Icon: IconMail, }, { - fieldId: 'phone', + fieldMetadataId: 'phone', label: 'Phone', Icon: IconPhone, }, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', label: 'Created at', Icon: IconCalendarEvent, }, { - fieldId: 'city', + fieldMetadataId: 'city', label: 'City', Icon: IconMap, }, diff --git a/front/src/pages/settings/data-model/SettingsNewObject.tsx b/front/src/pages/settings/data-model/SettingsNewObject.tsx index eb1be07c90..8512081616 100644 --- a/front/src/pages/settings/data-model/SettingsNewObject.tsx +++ b/front/src/pages/settings/data-model/SettingsNewObject.tsx @@ -77,7 +77,7 @@ export const SettingsNewObject = () => { }); await createOneView?.({ - objectId: createdObject.data?.createOneObject.id, + objectMetadataId: createdObject.data?.createOneObject.id, type: ViewType.Table, name: `All ${customFormValues.labelPlural}`, }); diff --git a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1.tsx b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1.tsx index fd6ca594ec..942f1ba502 100644 --- a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1.tsx +++ b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep1.tsx @@ -72,10 +72,12 @@ export const SettingsObjectNewFieldStep1 = () => { if (!activeObjectMetadataItem) return null; - const handleToggleField = (fieldId: string) => + const handleToggleField = (fieldMetadataId: string) => setMetadataFields((previousFields) => previousFields.map((field) => - field.id === fieldId ? { ...field, isActive: !field.isActive } : field, + field.id === fieldMetadataId + ? { ...field, isActive: !field.isActive } + : field, ), ); diff --git a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx index 1329b59bb6..ff7d91c277 100644 --- a/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx +++ b/front/src/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldStep2.tsx @@ -52,7 +52,7 @@ export const SettingsObjectNewFieldStep2 = () => { objectNamePlural: 'viewsV2', filter: { type: { eq: ViewType.Table }, - objectId: { eq: activeObjectMetadataItem?.id }, + objectMetadataId: { eq: activeObjectMetadataItem?.id }, }, onCompleted: async (data: PaginatedObjectTypeResults) => { const views = data.edges; @@ -72,12 +72,12 @@ export const SettingsObjectNewFieldStep2 = () => { const handleSave = async () => { const createdField = await createMetadataField({ ...formValues, - objectId: activeObjectMetadataItem.id, + objectMetadataId: activeObjectMetadataItem.id, }); objectViews.forEach(async (view) => { await createOneViewField?.({ viewId: view.id, - fieldId: createdField.data?.createOneField.id, + fieldMetadataId: createdField.data?.createOneField.id, position: activeObjectMetadataItem.fields.length, isVisible: true, size: 100, diff --git a/front/src/pages/tasks/TasksEffect.tsx b/front/src/pages/tasks/TasksEffect.tsx index 045fa758de..5665775311 100644 --- a/front/src/pages/tasks/TasksEffect.tsx +++ b/front/src/pages/tasks/TasksEffect.tsx @@ -18,7 +18,7 @@ export const TasksEffect = () => { useEffect(() => { if (currentUser) { setSelectedFilter({ - fieldId: 'assigneeId', + fieldMetadataId: 'assigneeId', value: currentUser.id, operand: ViewFilterOperand.Is, displayValue: currentUser.displayName, diff --git a/front/src/pages/tasks/tasks-filter-definitions.tsx b/front/src/pages/tasks/tasks-filter-definitions.tsx index 7d860b454d..2349693df6 100644 --- a/front/src/pages/tasks/tasks-filter-definitions.tsx +++ b/front/src/pages/tasks/tasks-filter-definitions.tsx @@ -5,7 +5,7 @@ import { Activity } from '~/generated/graphql'; export const tasksFilterDefinitions: FilterDefinitionByEntity[] = [ { - fieldId: 'assigneeId', + fieldMetadataId: 'assigneeId', label: 'Assignee', Icon: IconUser, type: 'ENTITY', diff --git a/front/src/testing/graphqlMocks.ts b/front/src/testing/graphqlMocks.ts index d6614a3dfc..22048d0fbb 100644 --- a/front/src/testing/graphqlMocks.ts +++ b/front/src/testing/graphqlMocks.ts @@ -318,7 +318,7 @@ export const graphqlMocks = [ }, ), graphql.query('FindManyviewsV2', (req, res, ctx) => { - const objectId = req.variables.filter.objectId.eq; + const objectMetadataId = req.variables.filter.objectMetadataId.eq; const viewType = req.variables.filter.type.eq; return res( @@ -326,7 +326,9 @@ export const graphqlMocks = [ viewsV2: { edges: mockedViewsData .filter( - (view) => view.objectId === objectId && view.type === viewType, + (view) => + view.objectMetadataId === objectMetadataId && + view.type === viewType, ) .map((view) => ({ node: view, diff --git a/front/src/testing/mock-data/metadata.ts b/front/src/testing/mock-data/metadata.ts index 8d9ea59135..8db9843473 100644 --- a/front/src/testing/mock-data/metadata.ts +++ b/front/src/testing/mock-data/metadata.ts @@ -20,7 +20,7 @@ export const mockedObjectMetadataItems = { node: { id: '5db475e7-8208-402d-97a1-62c9ce344dd4', type: 'TEXT', - name: 'objectId', + name: 'objectMetadataId', label: 'Object Id', description: 'View target object', icon: null, @@ -127,7 +127,7 @@ export const mockedObjectMetadataItems = { node: { id: '4d77c2dd-2b04-4989-b11e-cb0e386d1b4d', type: 'TEXT', - name: 'fieldId', + name: 'fieldMetadataId', label: 'Field Id', description: 'View Field target field', icon: null, diff --git a/front/src/testing/mock-data/view-fields.ts b/front/src/testing/mock-data/view-fields.ts index 4bb4f89777..c644510c90 100644 --- a/front/src/testing/mock-data/view-fields.ts +++ b/front/src/testing/mock-data/view-fields.ts @@ -4,7 +4,7 @@ export const mockedViewFieldsData = [ // Companies { id: '79035310-e955-4986-a4a4-73f9d9949c6a', - fieldId: 'name', + fieldMetadataId: 'name', viewId: mockedViewsData[0].id, position: 0, isVisible: true, @@ -12,7 +12,7 @@ export const mockedViewFieldsData = [ }, { id: '2a96bbc8-d86d-439a-8e50-4b07ebd27750', - fieldId: 'domainName', + fieldMetadataId: 'domainName', viewId: mockedViewsData[0].id, position: 1, isVisible: true, @@ -20,7 +20,7 @@ export const mockedViewFieldsData = [ }, { id: '0c1b4c7b-6a3d-4fb0-bf2b-5d7c8fb844ed', - fieldId: 'accountOwner', + fieldMetadataId: 'accountOwner', viewId: mockedViewsData[0].id, position: 2, isVisible: true, @@ -28,7 +28,7 @@ export const mockedViewFieldsData = [ }, { id: 'cc7f9560-32b5-4b82-8fd9-b05fe77c8cf7', - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', viewId: mockedViewsData[0].id, position: 3, isVisible: true, @@ -36,7 +36,7 @@ export const mockedViewFieldsData = [ }, { id: '3de4d078-3396-4480-be2d-6f3b1a228b0d', - fieldId: 'employees', + fieldMetadataId: 'employees', viewId: mockedViewsData[0].id, position: 4, isVisible: true, @@ -44,7 +44,7 @@ export const mockedViewFieldsData = [ }, { id: '4650c8fb-0f1e-4342-88dc-adedae1445f9', - fieldId: 'linkedin', + fieldMetadataId: 'linkedin', viewId: mockedViewsData[0].id, position: 5, isVisible: true, @@ -52,7 +52,7 @@ export const mockedViewFieldsData = [ }, { id: '727430bf-6ff8-4c85-9828-cbe72ac0fc27', - fieldId: 'address', + fieldMetadataId: 'address', viewId: mockedViewsData[0].id, position: 6, isVisible: true, @@ -62,7 +62,7 @@ export const mockedViewFieldsData = [ // People { id: '28894146-4fde-4a16-a9ca-1a31b5b788b4', - fieldId: 'displayName', + fieldMetadataId: 'displayName', viewId: mockedViewsData[1].id, position: 0, isVisible: true, @@ -70,7 +70,7 @@ export const mockedViewFieldsData = [ }, { id: 'e1e24864-8601-4cd8-8a63-09c1285f2e39', - fieldId: 'email', + fieldMetadataId: 'email', viewId: mockedViewsData[1].id, position: 1, isVisible: true, @@ -78,7 +78,7 @@ export const mockedViewFieldsData = [ }, { id: '5a1df716-7211-445a-9f16-9783a00998a7', - fieldId: 'company', + fieldMetadataId: 'company', viewId: mockedViewsData[1].id, position: 2, isVisible: true, @@ -86,7 +86,7 @@ export const mockedViewFieldsData = [ }, { id: 'a6e1197a-7e84-4d92-ace2-367c0bc46c49', - fieldId: 'phone', + fieldMetadataId: 'phone', viewId: mockedViewsData[1].id, position: 3, isVisible: true, @@ -94,7 +94,7 @@ export const mockedViewFieldsData = [ }, { id: 'c9343097-d14b-4559-a5fa-626c1527d39f', - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', viewId: mockedViewsData[1].id, position: 4, isVisible: true, @@ -102,7 +102,7 @@ export const mockedViewFieldsData = [ }, { id: 'a873e5f0-fed6-47e9-a712-6854eab3ec77', - fieldId: 'city', + fieldMetadataId: 'city', viewId: mockedViewsData[1].id, position: 5, isVisible: true, @@ -110,7 +110,7 @@ export const mockedViewFieldsData = [ }, { id: '66f134b8-5329-422f-b88e-83e6bb707eb5', - fieldId: 'jobTitle', + fieldMetadataId: 'jobTitle', viewId: mockedViewsData[1].id, position: 6, isVisible: true, @@ -118,7 +118,7 @@ export const mockedViewFieldsData = [ }, { id: '648faa24-cabb-482a-8578-ba3f09906017', - fieldId: 'linkedin', + fieldMetadataId: 'linkedin', viewId: mockedViewsData[1].id, position: 7, isVisible: true, @@ -126,7 +126,7 @@ export const mockedViewFieldsData = [ }, { id: '3a9e7f0d-a4ce-4ad5-aac7-3a24eb1a412d', - fieldId: 'x', + fieldMetadataId: 'x', viewId: mockedViewsData[1].id, position: 8, isVisible: true, @@ -136,7 +136,7 @@ export const mockedViewFieldsData = [ // Opportunities { id: '35a42e2d-83dd-4b57-ada6-f90616da706d', - fieldId: 'amount', + fieldMetadataId: 'amount', viewId: mockedViewsData[2].id, position: 0, isVisible: true, @@ -144,7 +144,7 @@ export const mockedViewFieldsData = [ }, { id: 'e5a731bb-82b9-4abe-ad22-1ddea94722f9', - fieldId: 'probability', + fieldMetadataId: 'probability', viewId: mockedViewsData[2].id, position: 1, isVisible: true, @@ -152,7 +152,7 @@ export const mockedViewFieldsData = [ }, { id: '3159acd8-463f-458d-bf9a-af8ac6f57dc0', - fieldId: 'closeDate', + fieldMetadataId: 'closeDate', viewId: mockedViewsData[2].id, position: 2, isVisible: true, @@ -160,7 +160,7 @@ export const mockedViewFieldsData = [ }, { id: 'afc0819d-b694-4e3c-a2e6-25261aa3ed2c', - fieldId: 'company', + fieldMetadataId: 'company', viewId: mockedViewsData[2].id, position: 3, isVisible: true, @@ -168,7 +168,7 @@ export const mockedViewFieldsData = [ }, { id: 'ec0507bb-aedc-4695-ba96-d81bdeb9db83', - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', viewId: mockedViewsData[2].id, position: 4, isVisible: true, @@ -176,7 +176,7 @@ export const mockedViewFieldsData = [ }, { id: '3f1585f6-44f6-45c5-b840-bc05af5d0008', - fieldId: 'pointOfContact', + fieldMetadataId: 'pointOfContact', viewId: mockedViewsData[2].id, position: 5, isVisible: true, diff --git a/front/src/testing/mock-data/views.ts b/front/src/testing/mock-data/views.ts index f007560dc5..c58e50846e 100644 --- a/front/src/testing/mock-data/views.ts +++ b/front/src/testing/mock-data/views.ts @@ -2,25 +2,25 @@ export const mockedViewsData = [ { id: '37a8a866-eb17-4e76-9382-03143a2f6a80', name: 'All companies', - objectId: 'company', + objectMetadataId: 'company', type: 'table', }, { id: '6095799e-b48f-4e00-b071-10818083593a', name: 'All people', - objectId: 'person', + objectMetadataId: 'person', type: 'table', }, { id: 'e26f66b7-f890-4a5c-b4d2-ec09987b5308', name: 'All opportunities', - objectId: 'company', + objectMetadataId: 'company', type: 'kanban', }, { id: '5c307222-1dd5-4ff3-ab06-8d990e9b3c74', name: 'All companies (v2)', - objectId: 'a3195559-cc20-4749-9565-572a2f506581', + objectMetadataId: 'a3195559-cc20-4749-9565-572a2f506581', type: 'table', }, ]; diff --git a/server/ormconfig.ts b/server/ormconfig.ts index 19a3d8f28b..153603fdc6 100644 --- a/server/ormconfig.ts +++ b/server/ormconfig.ts @@ -7,7 +7,7 @@ export default { type: 'postgres', entities: [__dirname + '/src/coreV2/**/*.entity{.ts,.js}'], synchronize: false, - migrationsRun: true, + migrationsRun: false, migrationsTableName: '_typeorm_migrations', migrations: [__dirname + '/migrations/**/*{.ts,.js}'], cli: { diff --git a/server/package.json b/server/package.json index 76a88ff9bc..703a33ba1b 100644 --- a/server/package.json +++ b/server/package.json @@ -27,7 +27,7 @@ "prisma:seed": "npx prisma db seed", "prisma:migrate": "npx prisma migrate deploy", "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js", - "typeorm:migrate": "yarn typeorm migration:run -d ./src/metadata/metadata.datasource.ts", + "typeorm:migrate": "yarn typeorm migration:run -d ./src/database/typeorm/metadata/metadata.datasource.ts", "database:init": "yarn database:setup && yarn database:seed", "database:setup": "npx ts-node ./scripts/setup-db.ts && yarn database:migrate && yarn database:generate", "database:truncate": "npx ts-node ./scripts/truncate-db.ts", diff --git a/server/src/command.module.ts b/server/src/command.module.ts index a875dbd6ae..c74dfed988 100644 --- a/server/src/command.module.ts +++ b/server/src/command.module.ts @@ -4,9 +4,15 @@ import { DatabaseCommandModule } from 'src/database/commands/database-command.mo import { AppModule } from './app.module'; -import { MetadataCommandModule } from './metadata/commands/metadata-command.module'; +import { TenantMigrationRunnerCommandsModule } from './tenant-migration-runner/commands/tenant-migration-runner-commands.module'; +import { TenantManagerCommandsModule } from './tenant-manager/commands/tenant-manager-commands.module'; @Module({ - imports: [AppModule, MetadataCommandModule, DatabaseCommandModule], + imports: [ + AppModule, + TenantMigrationRunnerCommandsModule, + TenantManagerCommandsModule, + DatabaseCommandModule, + ], }) export class CommandModule {} diff --git a/server/src/core/workspace/services/workspace.service.spec.ts b/server/src/core/workspace/services/workspace.service.spec.ts index 3a73c544e0..6e3e9f80a7 100644 --- a/server/src/core/workspace/services/workspace.service.spec.ts +++ b/server/src/core/workspace/services/workspace.service.spec.ts @@ -7,7 +7,7 @@ import { PipelineStageService } from 'src/core/pipeline/services/pipeline-stage. import { PersonService } from 'src/core/person/person.service'; import { CompanyService } from 'src/core/company/company.service'; import { PipelineProgressService } from 'src/core/pipeline/services/pipeline-progress.service'; -import { TenantInitialisationService } from 'src/metadata/tenant-initialisation/tenant-initialisation.service'; +import { TenantManagerService } from 'src/tenant-manager/tenant-manager.service'; import { WorkspaceService } from './workspace.service'; @@ -43,7 +43,7 @@ describe('WorkspaceService', () => { useValue: {}, }, { - provide: TenantInitialisationService, + provide: TenantManagerService, useValue: {}, }, ], diff --git a/server/src/core/workspace/services/workspace.service.ts b/server/src/core/workspace/services/workspace.service.ts index 17c2fb7c3d..075c2d96bd 100644 --- a/server/src/core/workspace/services/workspace.service.ts +++ b/server/src/core/workspace/services/workspace.service.ts @@ -10,7 +10,7 @@ import { PipelineStageService } from 'src/core/pipeline/services/pipeline-stage. import { PipelineService } from 'src/core/pipeline/services/pipeline.service'; import { PrismaService } from 'src/database/prisma.service'; import { assert } from 'src/utils/assert'; -import { TenantInitialisationService } from 'src/metadata/tenant-initialisation/tenant-initialisation.service'; +import { TenantManagerService } from 'src/tenant-manager/tenant-manager.service'; @Injectable() export class WorkspaceService { @@ -21,7 +21,7 @@ export class WorkspaceService { private readonly personService: PersonService, private readonly pipelineStageService: PipelineStageService, private readonly pipelineProgressService: PipelineProgressService, - private readonly tenantInitialisationService: TenantInitialisationService, + private readonly tenantManagerService: TenantManagerService, ) {} // Find @@ -64,7 +64,7 @@ export class WorkspaceService { }); // Create workspace schema - await this.tenantInitialisationService.init(workspace.id); + await this.tenantManagerService.init(workspace.id); // Create default companies const companies = await this.companyService.createDefaultCompanies({ @@ -161,7 +161,7 @@ export class WorkspaceService { this.delete({ where: { id: workspaceId } }), ]); - await this.tenantInitialisationService.delete(workspaceId); + await this.tenantManagerService.delete(workspaceId); return workspace; } diff --git a/server/src/core/workspace/workspace.module.ts b/server/src/core/workspace/workspace.module.ts index be1e24c037..f2faf7171b 100644 --- a/server/src/core/workspace/workspace.module.ts +++ b/server/src/core/workspace/workspace.module.ts @@ -4,9 +4,9 @@ import { FileUploadService } from 'src/core/file/services/file-upload.service'; import { PipelineModule } from 'src/core/pipeline/pipeline.module'; import { CompanyModule } from 'src/core/company/company.module'; import { PersonModule } from 'src/core/person/person.module'; -import { TenantInitialisationModule } from 'src/metadata/tenant-initialisation/tenant-initialisation.module'; import { AbilityModule } from 'src/ability/ability.module'; import { PrismaModule } from 'src/database/prisma.module'; +import { TenantManagerModule } from 'src/tenant-manager/tenant-manager.module'; import { WorkspaceService } from './services/workspace.service'; import { WorkspaceMemberService } from './services/workspace-member.service'; @@ -19,7 +19,7 @@ import { WorkspaceResolver } from './resolvers/workspace.resolver'; PipelineModule, CompanyModule, PersonModule, - TenantInitialisationModule, + TenantManagerModule, PrismaModule, ], providers: [ diff --git a/server/src/metadata/commands/data-seed-tenant.command.ts b/server/src/database/commands/data-seed-tenant.command.ts similarity index 80% rename from server/src/metadata/commands/data-seed-tenant.command.ts rename to server/src/database/commands/data-seed-tenant.command.ts index 107aa917dc..07b96444a2 100644 --- a/server/src/metadata/commands/data-seed-tenant.command.ts +++ b/server/src/database/commands/data-seed-tenant.command.ts @@ -4,14 +4,14 @@ import { Command, CommandRunner } from 'nest-commander'; import { DataSource } from 'typeorm'; import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; -import { MigrationRunnerService } from 'src/metadata/migration-runner/migration-runner.service'; +import { TenantMigrationRunnerService } from 'src/tenant-migration-runner/tenant-migration-runner.service'; import { seedCompanies } from 'src/database/typeorm-seeds/tenant/companies'; import { seedViewFields } from 'src/database/typeorm-seeds/tenant/view-fields'; import { seedViews } from 'src/database/typeorm-seeds/tenant/views'; import { seedFieldMetadata } from 'src/database/typeorm-seeds/metadata/field-metadata'; import { seedObjectMetadata } from 'src/database/typeorm-seeds/metadata/object-metadata'; +import { TypeORMService } from 'src/database/typeorm/typeorm.service'; // TODO: implement dry-run @Command({ @@ -26,9 +26,9 @@ export class DataSeedTenantCommand extends CommandRunner { @InjectDataSource('metadata') private readonly metadataDataSource: DataSource, private readonly dataSourceMetadataService: DataSourceMetadataService, - private readonly dataSourceService: DataSourceService, + private readonly typeORMService: TypeORMService, private readonly tenantMigrationService: TenantMigrationService, - private readonly migrationRunnerService: MigrationRunnerService, + private readonly migrationRunnerService: TenantMigrationRunnerService, ) { super(); } @@ -39,10 +39,9 @@ export class DataSeedTenantCommand extends CommandRunner { this.workspaceId, ); - const workspaceDataSource = - await this.dataSourceService.connectToWorkspaceDataSource( - this.workspaceId, - ); + const workspaceDataSource = await this.typeORMService.connectToDataSource( + dataSourceMetadata, + ); if (!workspaceDataSource) { throw new Error('Could not connect to workspace data source'); @@ -62,8 +61,6 @@ export class DataSeedTenantCommand extends CommandRunner { await seedViewFields(workspaceDataSource, dataSourceMetadata.schema); await seedViews(workspaceDataSource, dataSourceMetadata.schema); - await this.dataSourceService.disconnectFromWorkspaceDataSource( - this.workspaceId, - ); + await this.typeORMService.disconnectFromDataSource(dataSourceMetadata.id); } } diff --git a/server/src/database/commands/database-command.module.ts b/server/src/database/commands/database-command.module.ts index 3d89ee29ec..bb4b084faa 100644 --- a/server/src/database/commands/database-command.module.ts +++ b/server/src/database/commands/database-command.module.ts @@ -2,21 +2,36 @@ import { Module } from '@nestjs/common'; import { DataCleanInactiveCommand } from 'src/database/commands/clean-inactive-workspaces.command'; import { ConfirmationQuestion } from 'src/database/commands/questions/confirmation.question'; -import { WorkspaceService } from 'src/core/workspace/services/workspace.service'; import { PipelineModule } from 'src/core/pipeline/pipeline.module'; import { CompanyModule } from 'src/core/company/company.module'; import { PersonModule } from 'src/core/person/person.module'; -import { TenantInitialisationModule } from 'src/metadata/tenant-initialisation/tenant-initialisation.module'; import { PrismaModule } from 'src/database/prisma.module'; +import { TenantManagerModule } from 'src/tenant-manager/tenant-manager.module'; +import { DataSourceMetadataModule } from 'src/metadata/data-source-metadata/data-source-metadata.module'; +import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; +import { TenantMigrationRunnerModule } from 'src/tenant-migration-runner/tenant-migration-runner.module'; +import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; +import { WorkspaceModule } from 'src/core/workspace/workspace.module'; + +import { DataSeedTenantCommand } from './data-seed-tenant.command'; @Module({ imports: [ PipelineModule, CompanyModule, PersonModule, - TenantInitialisationModule, + TenantManagerModule, PrismaModule, + DataSourceMetadataModule, + TypeORMModule, + TenantMigrationModule, + TenantMigrationRunnerModule, + WorkspaceModule, + ], + providers: [ + DataSeedTenantCommand, + DataCleanInactiveCommand, + ConfirmationQuestion, ], - providers: [DataCleanInactiveCommand, ConfirmationQuestion, WorkspaceService], }) export class DatabaseCommandModule {} diff --git a/server/src/database/seeds/metadata.ts b/server/src/database/seeds/metadata.ts index 575ace3b0c..bf62ea6b05 100644 --- a/server/src/database/seeds/metadata.ts +++ b/server/src/database/seeds/metadata.ts @@ -5,8 +5,8 @@ export const seedMetadata = async (prisma: PrismaClient) => { 'CREATE SCHEMA IF NOT EXISTS workspace_twenty_7icsva0r6s00mpcp6cwg4w4rd', ); await prisma.$queryRawUnsafe( - `INSERT INTO metadata.data_source_metadata( - id, schema, type, workspace_id + `INSERT INTO metadata."dataSource"( + id, schema, type, "workspaceId" ) VALUES ( 'b37b2163-7f63-47a9-b1b3-6c7290ca9fb1', 'workspace_twenty_7icsva0r6s00mpcp6cwg4w4rd', 'postgres', 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419' diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata.ts b/server/src/database/typeorm-seeds/metadata/field-metadata.ts index d3c913c5fb..f5bf6f3925 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata.ts @@ -1,6 +1,6 @@ import { DataSource } from 'typeorm'; -const tableName = 'field_metadata'; +const tableName = 'fieldMetadata'; export const seedFieldMetadata = async ( workspaceDataSource: DataSource, @@ -10,7 +10,7 @@ export const seedFieldMetadata = async ( .createQueryBuilder() .insert() .into(`${schemaName}.${tableName}`, [ - 'objectId', + 'objectMetadataId', 'isCustom', 'workspaceId', 'isActive', @@ -26,7 +26,7 @@ export const seedFieldMetadata = async ( .values([ // Companies { - objectId: '1a8487a0-480c-434e-b4c7-e22408b97047', + objectMetadataId: '1a8487a0-480c-434e-b4c7-e22408b97047', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -41,7 +41,7 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '1a8487a0-480c-434e-b4c7-e22408b97047', + objectMetadataId: '1a8487a0-480c-434e-b4c7-e22408b97047', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -56,7 +56,7 @@ export const seedFieldMetadata = async ( isNullable: true, }, { - objectId: '1a8487a0-480c-434e-b4c7-e22408b97047', + objectMetadataId: '1a8487a0-480c-434e-b4c7-e22408b97047', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -71,7 +71,7 @@ export const seedFieldMetadata = async ( isNullable: true, }, { - objectId: '1a8487a0-480c-434e-b4c7-e22408b97047', + objectMetadataId: '1a8487a0-480c-434e-b4c7-e22408b97047', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -87,7 +87,7 @@ export const seedFieldMetadata = async ( }, // Views { - objectId: '9ab6b3dc-767f-473f-8fd0-6cdbefbf8dbe', + objectMetadataId: '9ab6b3dc-767f-473f-8fd0-6cdbefbf8dbe', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -102,22 +102,22 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '9ab6b3dc-767f-473f-8fd0-6cdbefbf8dbe', + objectMetadataId: '9ab6b3dc-767f-473f-8fd0-6cdbefbf8dbe', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, type: 'TEXT', - name: 'objectId', + name: 'objectMetadataId', label: 'Object Id', targetColumnMap: { - value: 'objectId', + value: 'objectMetadataId', }, description: 'View target object', icon: null, isNullable: false, }, { - objectId: '9ab6b3dc-767f-473f-8fd0-6cdbefbf8dbe', + objectMetadataId: '9ab6b3dc-767f-473f-8fd0-6cdbefbf8dbe', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -133,22 +133,22 @@ export const seedFieldMetadata = async ( }, // View Fields { - objectId: '61d9000b-485c-4c48-a22e-0d9a164f9647', + objectMetadataId: '61d9000b-485c-4c48-a22e-0d9a164f9647', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, type: 'TEXT', - name: 'fieldId', + name: 'fieldMetadataId', label: 'Field Id', targetColumnMap: { - value: 'fieldId', + value: 'fieldMetadataId', }, description: 'View Field target field', icon: null, isNullable: false, }, { - objectId: '61d9000b-485c-4c48-a22e-0d9a164f9647', + objectMetadataId: '61d9000b-485c-4c48-a22e-0d9a164f9647', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -163,7 +163,7 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '61d9000b-485c-4c48-a22e-0d9a164f9647', + objectMetadataId: '61d9000b-485c-4c48-a22e-0d9a164f9647', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -178,7 +178,7 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '61d9000b-485c-4c48-a22e-0d9a164f9647', + objectMetadataId: '61d9000b-485c-4c48-a22e-0d9a164f9647', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -193,7 +193,7 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '61d9000b-485c-4c48-a22e-0d9a164f9647', + objectMetadataId: '61d9000b-485c-4c48-a22e-0d9a164f9647', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -209,22 +209,22 @@ export const seedFieldMetadata = async ( }, // View Filters { - objectId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', + objectMetadataId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, type: 'TEXT', - name: 'fieldId', + name: 'fieldMetadataId', label: 'Field Id', targetColumnMap: { - value: 'fieldId', + value: 'fieldMetadataId', }, description: 'View Filter target field', icon: null, isNullable: false, }, { - objectId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', + objectMetadataId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -239,7 +239,7 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', + objectMetadataId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -254,7 +254,7 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', + objectMetadataId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -269,7 +269,7 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', + objectMetadataId: '5d9b1ab9-4461-4e2d-bf9e-9b47e68846d3', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -285,22 +285,22 @@ export const seedFieldMetadata = async ( }, // View Sorts { - objectId: '6f8dcd4b-cf28-41dd-b98b-d6e1f5b3a251', + objectMetadataId: '6f8dcd4b-cf28-41dd-b98b-d6e1f5b3a251', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, type: 'TEXT', - name: 'fieldId', + name: 'fieldMetadataId', label: 'Field Id', targetColumnMap: { - value: 'fieldId', + value: 'fieldMetadataId', }, description: 'View Sort target field', icon: null, isNullable: false, }, { - objectId: '6f8dcd4b-cf28-41dd-b98b-d6e1f5b3a251', + objectMetadataId: '6f8dcd4b-cf28-41dd-b98b-d6e1f5b3a251', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, @@ -315,7 +315,7 @@ export const seedFieldMetadata = async ( isNullable: false, }, { - objectId: '6f8dcd4b-cf28-41dd-b98b-d6e1f5b3a251', + objectMetadataId: '6f8dcd4b-cf28-41dd-b98b-d6e1f5b3a251', isCustom: false, workspaceId: 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419', isActive: true, diff --git a/server/src/database/typeorm-seeds/metadata/object-metadata.ts b/server/src/database/typeorm-seeds/metadata/object-metadata.ts index 25131b86c9..5f96fced6d 100644 --- a/server/src/database/typeorm-seeds/metadata/object-metadata.ts +++ b/server/src/database/typeorm-seeds/metadata/object-metadata.ts @@ -1,6 +1,6 @@ import { DataSource } from 'typeorm'; -const tableName = 'object_metadata'; +const tableName = 'objectMetadata'; export const seedObjectMetadata = async ( workspaceDataSource: DataSource, diff --git a/server/src/database/typeorm-seeds/tenant/view-fields.ts b/server/src/database/typeorm-seeds/tenant/view-fields.ts index 987a5ce8a1..d8d0a9b038 100644 --- a/server/src/database/typeorm-seeds/tenant/view-fields.ts +++ b/server/src/database/typeorm-seeds/tenant/view-fields.ts @@ -11,7 +11,7 @@ export const seedViewFields = async ( .insert() .into(`${schemaName}.${tableName}`, [ 'id', - 'fieldId', + 'fieldMetadataId', 'viewId', 'position', 'isVisible', @@ -21,7 +21,7 @@ export const seedViewFields = async ( .values([ { id: '46a72a5b-276e-4241-a05f-c054410aebcb', - fieldId: 'name', + fieldMetadataId: 'name', viewId: '10bec73c-0aea-4cc4-a3b2-8c2186f29b43', position: 0, isVisible: true, @@ -29,7 +29,7 @@ export const seedViewFields = async ( }, { id: 'f15b26ff-8f79-49dd-8f53-4286dd1af846', - fieldId: 'name', + fieldMetadataId: 'name', viewId: '37a8a866-eb17-4e76-9382-03143a2f6a80', position: 0, isVisible: true, @@ -37,7 +37,7 @@ export const seedViewFields = async ( }, { id: '8d1dbb50-c97f-42c4-8575-3d2c9bdeb6e5', - fieldId: 'domainName', + fieldMetadataId: 'domainName', viewId: '37a8a866-eb17-4e76-9382-03143a2f6a80', position: 1, isVisible: true, @@ -45,7 +45,7 @@ export const seedViewFields = async ( }, { id: '33833b3b-4e02-4f10-91fc-c594422952af', - fieldId: 'accountOwner', + fieldMetadataId: 'accountOwner', viewId: '37a8a866-eb17-4e76-9382-03143a2f6a80', position: 2, isVisible: true, @@ -53,7 +53,7 @@ export const seedViewFields = async ( }, { id: 'c750a968-832e-4812-a1a2-74f515af55c1', - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', viewId: '37a8a866-eb17-4e76-9382-03143a2f6a80', position: 3, isVisible: true, @@ -61,7 +61,7 @@ export const seedViewFields = async ( }, { id: '2fde3187-a0bc-47ca-80bd-457bd826fb4a', - fieldId: 'employees', + fieldMetadataId: 'employees', viewId: '37a8a866-eb17-4e76-9382-03143a2f6a80', position: 4, isVisible: true, @@ -69,7 +69,7 @@ export const seedViewFields = async ( }, { id: '2fead26f-3f4f-4a4d-a4c6-3abe7b2f74c9', - fieldId: 'linkedin', + fieldMetadataId: 'linkedin', viewId: '37a8a866-eb17-4e76-9382-03143a2f6a80', position: 5, isVisible: true, @@ -77,7 +77,7 @@ export const seedViewFields = async ( }, { id: '0cffa82a-c851-4e17-b46c-2c4642d78329', - fieldId: 'address', + fieldMetadataId: 'address', viewId: '37a8a866-eb17-4e76-9382-03143a2f6a80', position: 6, isVisible: true, @@ -85,7 +85,7 @@ export const seedViewFields = async ( }, { id: '93a68c4a-8107-409a-9adb-06305ffbd692', - fieldId: 'displayName', + fieldMetadataId: 'displayName', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 0, isVisible: true, @@ -93,7 +93,7 @@ export const seedViewFields = async ( }, { id: 'd955ee31-6316-4cb2-af71-9609dede4d7e', - fieldId: 'email', + fieldMetadataId: 'email', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 1, isVisible: true, @@ -101,7 +101,7 @@ export const seedViewFields = async ( }, { id: 'bceb4d84-8ad1-4a0e-9333-efb870b42eb8', - fieldId: 'company', + fieldMetadataId: 'company', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 2, isVisible: true, @@ -109,7 +109,7 @@ export const seedViewFields = async ( }, { id: 'bef874d4-f349-4cdb-ae28-6e9fc497449b', - fieldId: 'phone', + fieldMetadataId: 'phone', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 3, isVisible: true, @@ -117,7 +117,7 @@ export const seedViewFields = async ( }, { id: 'e06f920d-1af9-404d-8b9a-4f97c4009a4a', - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 4, isVisible: true, @@ -125,7 +125,7 @@ export const seedViewFields = async ( }, { id: '92d94ee8-31fc-4025-a427-29291abb2b19', - fieldId: 'city', + fieldMetadataId: 'city', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 5, isVisible: true, @@ -133,7 +133,7 @@ export const seedViewFields = async ( }, { id: 'b38e4022-1559-40da-bd5e-29d89b6c8330', - fieldId: 'jobTitle', + fieldMetadataId: 'jobTitle', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 6, isVisible: true, @@ -141,7 +141,7 @@ export const seedViewFields = async ( }, { id: '30147fab-9666-4db5-a11b-20af4544c712', - fieldId: 'linkedin', + fieldMetadataId: 'linkedin', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 7, isVisible: true, @@ -149,7 +149,7 @@ export const seedViewFields = async ( }, { id: 'f0870949-21ac-46a2-b3ec-d1b0107c434c', - fieldId: 'x', + fieldMetadataId: 'x', viewId: '6095799e-b48f-4e00-b071-10818083593a', position: 8, isVisible: true, diff --git a/server/src/database/typeorm-seeds/tenant/views.ts b/server/src/database/typeorm-seeds/tenant/views.ts index 6f253d3418..aadf4c7e28 100644 --- a/server/src/database/typeorm-seeds/tenant/views.ts +++ b/server/src/database/typeorm-seeds/tenant/views.ts @@ -9,31 +9,36 @@ export const seedViews = async ( await workspaceDataSource .createQueryBuilder() .insert() - .into(`${schemaName}.${tableName}`, ['id', 'name', 'objectId', 'type']) + .into(`${schemaName}.${tableName}`, [ + 'id', + 'name', + 'objectMetadataId', + 'type', + ]) .orIgnore() .values([ { id: '37a8a866-eb17-4e76-9382-03143a2f6a80', name: 'All companies', - objectId: 'company', + objectMetadataId: 'company', type: 'table', }, { id: '6095799e-b48f-4e00-b071-10818083593a', name: 'All people', - objectId: 'person', + objectMetadataId: 'person', type: 'table', }, { id: 'e26f66b7-f890-4a5c-b4d2-ec09987b5308', name: 'All opportunities', - objectId: 'company', + objectMetadataId: 'company', type: 'kanban', }, { id: '10bec73c-0aea-4cc4-a3b2-8c2186f29b43', name: 'All Companies (V2)', - objectId: '1a8487a0-480c-434e-b4c7-e22408b97047', + objectMetadataId: '1a8487a0-480c-434e-b4c7-e22408b97047', type: 'table', }, ]) diff --git a/server/src/metadata/data-source-metadata/data-source-metadata.entity.ts b/server/src/database/typeorm/metadata/entities/data-source.entity.ts similarity index 63% rename from server/src/metadata/data-source-metadata/data-source-metadata.entity.ts rename to server/src/database/typeorm/metadata/entities/data-source.entity.ts index 0af0aa0ed5..29011c72d8 100644 --- a/server/src/metadata/data-source-metadata/data-source-metadata.entity.ts +++ b/server/src/database/typeorm/metadata/entities/data-source.entity.ts @@ -1,16 +1,16 @@ import { - Column, - CreateDateColumn, + DataSourceOptions, Entity, PrimaryGeneratedColumn, + Column, + CreateDateColumn, UpdateDateColumn, - DataSourceOptions, } from 'typeorm'; type DataSourceType = DataSourceOptions['type']; -@Entity('data_source_metadata') -export class DataSourceMetadata { +@Entity('dataSource') +export class DataSourceEntity { @PrimaryGeneratedColumn('uuid') id: string; @@ -23,18 +23,18 @@ export class DataSourceMetadata { @Column({ type: 'enum', enum: ['postgres'], default: 'postgres' }) type: DataSourceType; - @Column({ nullable: true, name: 'label' }) + @Column({ nullable: true }) label: string; - @Column({ default: false, name: 'is_remote' }) + @Column({ default: false }) isRemote: boolean; - @Column({ nullable: false, name: 'workspace_id' }) + @Column({ nullable: false }) workspaceId: string; - @CreateDateColumn({ name: 'created_at' }) + @CreateDateColumn() createdAt: Date; - @UpdateDateColumn({ name: 'updated_at' }) + @UpdateDateColumn() updatedAt: Date; } diff --git a/server/src/database/typeorm/metadata/entities/field-metadata.entity.ts b/server/src/database/typeorm/metadata/entities/field-metadata.entity.ts new file mode 100644 index 0000000000..d4818e184f --- /dev/null +++ b/server/src/database/typeorm/metadata/entities/field-metadata.entity.ts @@ -0,0 +1,102 @@ +import { + Entity, + Unique, + PrimaryGeneratedColumn, + Column, + ManyToOne, + JoinColumn, + OneToOne, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { FieldMetadataInterface } from 'src/tenant/schema-builder/interfaces/field-metadata.interface'; +import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; + +import { ObjectMetadataEntity } from './object-metadata.entity'; +import { RelationMetadataEntity } from './relation-metadata.entity'; + +export enum FieldMetadataType { + UUID = 'uuid', + TEXT = 'TEXT', + PHONE = 'PHONE', + EMAIL = 'EMAIL', + DATE = 'DATE', + BOOLEAN = 'BOOLEAN', + NUMBER = 'NUMBER', + ENUM = 'ENUM', + URL = 'URL', + MONEY = 'MONEY', + RELATION = 'RELATION', +} + +@Entity('fieldMetadata') +@Unique('IndexOnNameObjectMetadataIdAndWorkspaceIdUnique', [ + 'name', + 'objectMetadataId', + 'workspaceId', +]) +export class FieldMetadataEntity implements FieldMetadataInterface { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ nullable: false, type: 'uuid' }) + objectMetadataId: string; + + @ManyToOne(() => ObjectMetadataEntity, (object) => object.fields, { + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'objectMetadataId' }) + object: ObjectMetadataEntity; + + @Column({ nullable: false }) + type: FieldMetadataType; + + @Column({ nullable: false }) + name: string; + + @Column({ nullable: false }) + label: string; + + @Column({ nullable: false, type: 'jsonb' }) + targetColumnMap: FieldMetadataTargetColumnMap; + + @Column({ nullable: true, type: 'text' }) + description: string; + + @Column({ nullable: true }) + icon: string; + + @Column('text', { nullable: true, array: true }) + enums: string[]; + + @Column({ default: false }) + isCustom: boolean; + + @Column({ default: false }) + isActive: boolean; + + @Column({ nullable: true, default: true }) + isNullable: boolean; + + @Column({ nullable: false }) + workspaceId: string; + + @OneToOne( + () => RelationMetadataEntity, + (relation: RelationMetadataEntity) => relation.fromFieldMetadata, + ) + fromRelationMetadata: RelationMetadataEntity; + + @OneToOne( + () => RelationMetadataEntity, + (relation: RelationMetadataEntity) => relation.toFieldMetadata, + ) + toRelationMetadata: RelationMetadataEntity; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/server/src/database/typeorm/metadata/entities/object-metadata.entity.ts b/server/src/database/typeorm/metadata/entities/object-metadata.entity.ts new file mode 100644 index 0000000000..3140ca20fd --- /dev/null +++ b/server/src/database/typeorm/metadata/entities/object-metadata.entity.ts @@ -0,0 +1,81 @@ +import { + Entity, + Unique, + PrimaryGeneratedColumn, + Column, + OneToMany, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface'; + +import { FieldMetadataEntity } from './field-metadata.entity'; +import { RelationMetadataEntity } from './relation-metadata.entity'; + +@Entity('objectMetadata') +@Unique('IndexOnNameSingularAndWorkspaceIdUnique', [ + 'nameSingular', + 'workspaceId', +]) +@Unique('IndexOnNamePluralAndWorkspaceIdUnique', ['namePlural', 'workspaceId']) +export class ObjectMetadataEntity implements ObjectMetadataInterface { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ nullable: false, type: 'uuid' }) + dataSourceId: string; + + @Column({ nullable: false }) + nameSingular: string; + + @Column({ nullable: false }) + namePlural: string; + + @Column({ nullable: false }) + labelSingular: string; + + @Column({ nullable: false }) + labelPlural: string; + + @Column({ nullable: true, type: 'text' }) + description: string; + + @Column({ nullable: true }) + icon: string; + + @Column({ nullable: false }) + targetTableName: string; + + @Column({ default: false }) + isCustom: boolean; + + @Column({ default: false }) + isActive: boolean; + + @Column({ nullable: false }) + workspaceId: string; + + @OneToMany(() => FieldMetadataEntity, (field) => field.object, { + cascade: true, + }) + fields: FieldMetadataEntity[]; + + @OneToMany( + () => RelationMetadataEntity, + (relation: RelationMetadataEntity) => relation.fromObjectMetadata, + ) + fromRelations: RelationMetadataEntity[]; + + @OneToMany( + () => RelationMetadataEntity, + (relation: RelationMetadataEntity) => relation.toObjectMetadata, + ) + toRelations: RelationMetadataEntity[]; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/server/src/database/typeorm/metadata/entities/relation-metadata.entity.ts b/server/src/database/typeorm/metadata/entities/relation-metadata.entity.ts new file mode 100644 index 0000000000..3a3b53c324 --- /dev/null +++ b/server/src/database/typeorm/metadata/entities/relation-metadata.entity.ts @@ -0,0 +1,75 @@ +import { + Column, + CreateDateColumn, + Entity, + JoinColumn, + ManyToOne, + OneToOne, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +import { FieldMetadataEntity } from './field-metadata.entity'; +import { ObjectMetadataEntity } from './object-metadata.entity'; + +export enum RelationType { + ONE_TO_ONE = 'ONE_TO_ONE', + ONE_TO_MANY = 'ONE_TO_MANY', + MANY_TO_MANY = 'MANY_TO_MANY', +} + +@Entity('relationMetadata') +export class RelationMetadataEntity { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ nullable: false }) + relationType: RelationType; + + @Column({ nullable: false, type: 'uuid' }) + fromObjectMetadataId: string; + + @Column({ nullable: false, type: 'uuid' }) + toObjectMetadataId: string; + + @Column({ nullable: false, type: 'uuid' }) + fromFieldMetadataId: string; + + @Column({ nullable: false, type: 'uuid' }) + toFieldMetadataId: string; + + @Column({ nullable: false }) + workspaceId: string; + + @ManyToOne( + () => ObjectMetadataEntity, + (object: ObjectMetadataEntity) => object.fromRelations, + ) + fromObjectMetadata: ObjectMetadataEntity; + + @ManyToOne( + () => ObjectMetadataEntity, + (object: ObjectMetadataEntity) => object.toRelations, + ) + toObjectMetadata: ObjectMetadataEntity; + + @OneToOne( + () => FieldMetadataEntity, + (field: FieldMetadataEntity) => field.fromRelationMetadata, + ) + @JoinColumn() + fromFieldMetadata: FieldMetadataEntity; + + @OneToOne( + () => FieldMetadataEntity, + (field: FieldMetadataEntity) => field.toRelationMetadata, + ) + @JoinColumn() + toFieldMetadata: FieldMetadataEntity; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/server/src/metadata/tenant-migration/tenant-migration.entity.ts b/server/src/database/typeorm/metadata/entities/tenant-migration.entity.ts similarity index 94% rename from server/src/metadata/tenant-migration/tenant-migration.entity.ts rename to server/src/database/typeorm/metadata/entities/tenant-migration.entity.ts index de10716d37..110ba58bb2 100644 --- a/server/src/metadata/tenant-migration/tenant-migration.entity.ts +++ b/server/src/database/typeorm/metadata/entities/tenant-migration.entity.ts @@ -32,8 +32,8 @@ export type TenantMigrationTableAction = { action: 'create' | 'alter'; columns?: TenantMigrationColumnAction[]; }; -@Entity('tenant_migrations') -export class TenantMigration { +@Entity('tenantMigration') +export class TenantMigrationEntity { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/server/src/metadata/metadata.datasource.ts b/server/src/database/typeorm/metadata/metadata.datasource.ts similarity index 92% rename from server/src/metadata/metadata.datasource.ts rename to server/src/database/typeorm/metadata/metadata.datasource.ts index 4671d174a0..f40482df13 100644 --- a/server/src/metadata/metadata.datasource.ts +++ b/server/src/database/typeorm/metadata/metadata.datasource.ts @@ -13,7 +13,7 @@ export const typeORMMetadataModuleOptions: TypeOrmModuleOptions = { type: 'postgres', logging: ['error'], schema: 'metadata', - entities: [__dirname + '/**/*.entity{.ts,.js}'], + entities: [__dirname + '/entities/*.entity{.ts,.js}'], synchronize: false, migrationsRun: false, migrationsTableName: '_typeorm_migrations', diff --git a/server/src/database/typeorm/metadata/migrations/1699543628458-setupMetadataTables.ts b/server/src/database/typeorm/metadata/migrations/1699543628458-setupMetadataTables.ts new file mode 100644 index 0000000000..1d07b4b0c9 --- /dev/null +++ b/server/src/database/typeorm/metadata/migrations/1699543628458-setupMetadataTables.ts @@ -0,0 +1,65 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class SetupMetadataTables1699543628458 implements MigrationInterface { + name = 'SetupMetadataTables1699543628458'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "metadata"."objectMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "dataSourceId" uuid NOT NULL, "nameSingular" character varying NOT NULL, "namePlural" character varying NOT NULL, "labelSingular" character varying NOT NULL, "labelPlural" character varying NOT NULL, "description" text, "icon" character varying, "targetTableName" character varying NOT NULL, "isCustom" boolean NOT NULL DEFAULT false, "isActive" boolean NOT NULL DEFAULT false, "workspaceId" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "IndexOnNamePluralAndWorkspaceIdUnique" UNIQUE ("namePlural", "workspaceId"), CONSTRAINT "IndexOnNameSingularAndWorkspaceIdUnique" UNIQUE ("nameSingular", "workspaceId"), CONSTRAINT "PK_81fb7f4f4244211cfbd188af1e8" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TABLE "metadata"."fieldMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "objectMetadataId" uuid NOT NULL, "type" character varying NOT NULL, "name" character varying NOT NULL, "label" character varying NOT NULL, "targetColumnMap" jsonb NOT NULL, "description" text, "icon" character varying, "enums" text array, "isCustom" boolean NOT NULL DEFAULT false, "isActive" boolean NOT NULL DEFAULT false, "isNullable" boolean DEFAULT true, "workspaceId" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "IndexOnNameObjectMetadataIdAndWorkspaceIdUnique" UNIQUE ("name", "objectMetadataId", "workspaceId"), CONSTRAINT "PK_d046b1c7cea325ebc4cdc25e7a9" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TABLE "metadata"."relationMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "relationType" character varying NOT NULL, "fromObjectMetadataId" uuid NOT NULL, "toObjectMetadataId" uuid NOT NULL, "fromFieldMetadataId" uuid NOT NULL, "toFieldMetadataId" uuid NOT NULL, "workspaceId" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "REL_3deb257254145a3bdde9575e7d" UNIQUE ("fromFieldMetadataId"), CONSTRAINT "REL_9dea8f90d04edbbf9c541a95c3" UNIQUE ("toFieldMetadataId"), CONSTRAINT "PK_2724f60cb4f17a89481a7e8d7d3" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TYPE "metadata"."dataSource_type_enum" AS ENUM('postgres')`, + ); + await queryRunner.query( + `CREATE TABLE "metadata"."dataSource" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "url" character varying, "schema" character varying, "type" "metadata"."dataSource_type_enum" NOT NULL DEFAULT 'postgres', "label" character varying, "isRemote" boolean NOT NULL DEFAULT false, "workspaceId" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_6d01ae6c0f47baf4f8e37342268" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `CREATE TABLE "metadata"."tenantMigration" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "migrations" jsonb, "name" character varying, "isCustom" boolean NOT NULL DEFAULT false, "appliedAt" TIMESTAMP, "workspaceId" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_f9b06eb42494795f73acb5c2350" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."fieldMetadata" ADD CONSTRAINT "FK_de2a09b9e3e690440480d2dee26" FOREIGN KEY ("objectMetadataId") REFERENCES "metadata"."objectMetadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."relationMetadata" ADD CONSTRAINT "FK_f2a0acd3a548ee446a1a35df44d" FOREIGN KEY ("fromObjectMetadataId") REFERENCES "metadata"."objectMetadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."relationMetadata" ADD CONSTRAINT "FK_0f781f589e5a527b8f3d3a4b824" FOREIGN KEY ("toObjectMetadataId") REFERENCES "metadata"."objectMetadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."relationMetadata" ADD CONSTRAINT "FK_3deb257254145a3bdde9575e7d6" FOREIGN KEY ("fromFieldMetadataId") REFERENCES "metadata"."fieldMetadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."relationMetadata" ADD CONSTRAINT "FK_9dea8f90d04edbbf9c541a95c3b" FOREIGN KEY ("toFieldMetadataId") REFERENCES "metadata"."fieldMetadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "metadata"."relationMetadata" DROP CONSTRAINT "FK_9dea8f90d04edbbf9c541a95c3b"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."relationMetadata" DROP CONSTRAINT "FK_3deb257254145a3bdde9575e7d6"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."relationMetadata" DROP CONSTRAINT "FK_0f781f589e5a527b8f3d3a4b824"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."relationMetadata" DROP CONSTRAINT "FK_f2a0acd3a548ee446a1a35df44d"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."fieldMetadata" DROP CONSTRAINT "FK_de2a09b9e3e690440480d2dee26"`, + ); + await queryRunner.query(`DROP TABLE "metadata"."tenantMigration"`); + await queryRunner.query(`DROP TABLE "metadata"."dataSource"`); + await queryRunner.query(`DROP TYPE "metadata"."dataSource_type_enum"`); + await queryRunner.query(`DROP TABLE "metadata"."relationMetadata"`); + await queryRunner.query(`DROP TABLE "metadata"."fieldMetadata"`); + await queryRunner.query(`DROP TABLE "metadata"."objectMetadata"`); + } +} diff --git a/server/src/database/typeorm/typeorm.module.ts b/server/src/database/typeorm/typeorm.module.ts new file mode 100644 index 0000000000..955f44f8f8 --- /dev/null +++ b/server/src/database/typeorm/typeorm.module.ts @@ -0,0 +1,23 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; + +import { TypeORMService } from './typeorm.service'; + +import { typeORMMetadataModuleOptions } from './metadata/metadata.datasource'; + +const metadataTypeORMFactory = async (): Promise => ({ + ...typeORMMetadataModuleOptions, + name: 'metadata', +}); + +@Module({ + imports: [ + TypeOrmModule.forRootAsync({ + useFactory: metadataTypeORMFactory, + name: 'metadata', + }), + ], + providers: [TypeORMService], + exports: [TypeORMService], +}) +export class TypeORMModule {} diff --git a/server/src/database/typeorm/typeorm.service.ts b/server/src/database/typeorm/typeorm.service.ts new file mode 100644 index 0000000000..df0d6c34fa --- /dev/null +++ b/server/src/database/typeorm/typeorm.service.ts @@ -0,0 +1,106 @@ +import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; + +import { DataSource } from 'typeorm'; + +import { EnvironmentService } from 'src/integrations/environment/environment.service'; + +import { DataSourceEntity } from './metadata/entities/data-source.entity'; + +@Injectable() +export class TypeORMService implements OnModuleInit, OnModuleDestroy { + private mainDataSource: DataSource; + private dataSources: Map = new Map(); + + constructor(private readonly environmentService: EnvironmentService) { + this.mainDataSource = new DataSource({ + url: environmentService.getPGDatabaseUrl(), + type: 'postgres', + logging: false, + schema: 'public', + }); + } + + /** + * Connects to a data source using metadata. Returns a cached connection if it exists. + * @param dataSource DataSourceEntity + * @returns Promise + */ + public async connectToDataSource( + dataSource: DataSourceEntity, + ): Promise { + if (this.dataSources.has(dataSource.id)) { + return this.dataSources.get(dataSource.id); + } + + const schema = dataSource.schema; + + const workspaceDataSource = new DataSource({ + url: dataSource.url ?? this.environmentService.getPGDatabaseUrl(), + type: 'postgres', + logging: ['query'], + schema, + }); + + await workspaceDataSource.initialize(); + + this.dataSources.set(dataSource.id, workspaceDataSource); + + return workspaceDataSource; + } + + /** + * Disconnects from a workspace data source. + * @param dataSourceId + * @returns Promise + * + */ + public async disconnectFromDataSource(dataSourceId: string) { + if (!this.dataSources.has(dataSourceId)) { + return; + } + + const dataSource = this.dataSources.get(dataSourceId); + + await dataSource?.destroy(); + + this.dataSources.delete(dataSourceId); + } + + /** + * Creates a new schema + * @param workspaceId + * @returns Promise + */ + public async createSchema(schemaName: string): Promise { + const queryRunner = this.mainDataSource.createQueryRunner(); + + await queryRunner.createSchema(schemaName, true); + + await queryRunner.release(); + + return schemaName; + } + + public async deleteSchema(schemaName: string) { + const queryRunner = this.mainDataSource.createQueryRunner(); + + await queryRunner.dropSchema(schemaName, true, true); + + await queryRunner.release(); + } + + async onModuleInit() { + // Init main data source "default" schema + await this.mainDataSource.initialize(); + } + + async onModuleDestroy() { + // Destroy main data source "default" schema + await this.mainDataSource.destroy(); + + // Destroy all workspace data sources + for (const [, dataSource] of this.dataSources) { + await dataSource.destroy(); + } + } +} diff --git a/server/src/metadata/commands/metadata-command.module.ts b/server/src/metadata/commands/metadata-command.module.ts deleted file mode 100644 index 14f0919c22..0000000000 --- a/server/src/metadata/commands/metadata-command.module.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; -import { MigrationRunnerModule } from 'src/metadata/migration-runner/migration-runner.module'; -import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module'; -import { FieldMetadataModule } from 'src/metadata/field-metadata/field-metadata.module'; -import { TenantInitialisationModule } from 'src/metadata/tenant-initialisation/tenant-initialisation.module'; -import { DataSourceMetadataModule } from 'src/metadata/data-source-metadata/data-source-metadata.module'; -import { DataSourceModule } from 'src/metadata/data-source/data-source.module'; - -import { SyncTenantMetadataCommand } from './sync-tenant-metadata.command'; -import { RunTenantMigrationsCommand } from './run-tenant-migrations.command'; -import { DataSeedTenantCommand } from './data-seed-tenant.command'; - -@Module({ - imports: [ - TenantMigrationModule, - MigrationRunnerModule, - ObjectMetadataModule, - FieldMetadataModule, - DataSourceMetadataModule, - TenantInitialisationModule, - DataSourceModule, - ], - providers: [ - RunTenantMigrationsCommand, - SyncTenantMetadataCommand, - DataSeedTenantCommand, - ], -}) -export class MetadataCommandModule {} diff --git a/server/src/metadata/data-source-metadata/data-source-metadata.module.ts b/server/src/metadata/data-source-metadata/data-source-metadata.module.ts index b4fdc2f38d..511588db6e 100644 --- a/server/src/metadata/data-source-metadata/data-source-metadata.module.ts +++ b/server/src/metadata/data-source-metadata/data-source-metadata.module.ts @@ -1,11 +1,12 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { DataSourceEntity } from 'src/database/typeorm/metadata/entities/data-source.entity'; + import { DataSourceMetadataService } from './data-source-metadata.service'; -import { DataSourceMetadata } from './data-source-metadata.entity'; @Module({ - imports: [TypeOrmModule.forFeature([DataSourceMetadata], 'metadata')], + imports: [TypeOrmModule.forFeature([DataSourceEntity], 'metadata')], providers: [DataSourceMetadataService], exports: [DataSourceMetadataService], }) diff --git a/server/src/metadata/data-source-metadata/data-source-metadata.service.spec.ts b/server/src/metadata/data-source-metadata/data-source-metadata.service.spec.ts deleted file mode 100644 index 50403ed8b8..0000000000 --- a/server/src/metadata/data-source-metadata/data-source-metadata.service.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; - -import { DataSourceMetadataService } from './data-source-metadata.service'; -import { DataSourceMetadata } from './data-source-metadata.entity'; - -describe('DataSourceMetadataService', () => { - let service: DataSourceMetadataService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - DataSourceMetadataService, - { - provide: getRepositoryToken(DataSourceMetadata, 'metadata'), - useValue: {}, - }, - ], - }).compile(); - - service = module.get(DataSourceMetadataService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/server/src/metadata/data-source-metadata/data-source-metadata.service.ts b/server/src/metadata/data-source-metadata/data-source-metadata.service.ts index 6698a2bf63..2ab2acea94 100644 --- a/server/src/metadata/data-source-metadata/data-source-metadata.service.ts +++ b/server/src/metadata/data-source-metadata/data-source-metadata.service.ts @@ -3,13 +3,13 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { DataSourceMetadata } from './data-source-metadata.entity'; +import { DataSourceEntity } from 'src/database/typeorm/metadata/entities/data-source.entity'; @Injectable() export class DataSourceMetadataService { constructor( - @InjectRepository(DataSourceMetadata, 'metadata') - private readonly dataSourceMetadataRepository: Repository, + @InjectRepository(DataSourceEntity, 'metadata') + private readonly dataSourceMetadataRepository: Repository, ) {} async createDataSourceMetadata(workspaceId: string, workspaceSchema: string) { diff --git a/server/src/metadata/data-source/data-source.module.ts b/server/src/metadata/data-source/data-source.module.ts deleted file mode 100644 index 48cd14143b..0000000000 --- a/server/src/metadata/data-source/data-source.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { DataSourceMetadataModule } from 'src/metadata/data-source-metadata/data-source-metadata.module'; - -import { DataSourceService } from './data-source.service'; - -@Module({ - imports: [DataSourceMetadataModule], - providers: [DataSourceService], - exports: [DataSourceService], -}) -export class DataSourceModule {} diff --git a/server/src/metadata/data-source/data-source.service.spec.ts b/server/src/metadata/data-source/data-source.service.spec.ts deleted file mode 100644 index a4026407fc..0000000000 --- a/server/src/metadata/data-source/data-source.service.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; - -import { EnvironmentService } from 'src/integrations/environment/environment.service'; -import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; - -import { DataSourceService } from './data-source.service'; - -describe('DataSourceService', () => { - let service: DataSourceService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - DataSourceService, - { - provide: EnvironmentService, - useValue: { - getPGDatabaseUrl: () => '', - }, - }, - { - provide: DataSourceMetadataService, - useValue: {}, - }, - ], - }).compile(); - - service = module.get(DataSourceService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/server/src/metadata/data-source/data-source.service.ts b/server/src/metadata/data-source/data-source.service.ts deleted file mode 100644 index 60d7617662..0000000000 --- a/server/src/metadata/data-source/data-source.service.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; - -import { DataSource } from 'typeorm'; - -import { EnvironmentService } from 'src/integrations/environment/environment.service'; -import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; -import { TenantMigration } from 'src/metadata/tenant-migration/tenant-migration.entity'; - -import { uuidToBase36 } from './data-source.util'; - -@Injectable() -export class DataSourceService implements OnModuleInit, OnModuleDestroy { - private mainDataSource: DataSource; - private dataSources: Map = new Map(); - - constructor( - private readonly environmentService: EnvironmentService, - private readonly dataSourceMetadataService: DataSourceMetadataService, - ) { - this.mainDataSource = new DataSource({ - url: environmentService.getPGDatabaseUrl(), - type: 'postgres', - logging: false, - schema: 'public', - }); - } - - /** - * Creates a new schema for a given workspaceId - * @param workspaceId - * @returns Promise - */ - public async createWorkspaceSchema(workspaceId: string): Promise { - const schemaName = this.getSchemaName(workspaceId); - - const queryRunner = this.mainDataSource.createQueryRunner(); - const schemaAlreadyExists = await queryRunner.hasSchema(schemaName); - - if (schemaAlreadyExists) { - throw new Error(`Schema ${schemaName} already exists`); - } - - await queryRunner.createSchema(schemaName, true); - - await queryRunner.release(); - - return schemaName; - } - - /** - * Connects to a workspace data source using the workspace metadata. Returns a cached connection if it exists. - * @param workspaceId - * @returns Promise - */ - public async connectToWorkspaceDataSource( - workspaceId: string, - ): Promise { - if (this.dataSources.has(workspaceId)) { - const cachedDataSource = this.dataSources.get(workspaceId); - return cachedDataSource; - } - - // We only want the first one for now, we will handle multiple data sources later with remote datasources. - // However, we will need to differentiate the data sources because we won't run migrations on remote data sources for example. - const dataSourceMetadata = - await this.dataSourceMetadataService.getLastDataSourceMetadataFromWorkspaceIdOrFail( - workspaceId, - ); - const schema = dataSourceMetadata.schema; - - // Probably not needed as we will ask for the schema name OR store public by default if it's remote - if (!schema && !dataSourceMetadata.isRemote) { - throw Error( - "No schema found for this non-remote data source, we don't want to fallback to public for workspace data sources.", - ); - } - - const workspaceDataSource = new DataSource({ - // TODO: We should use later dataSourceMetadata.type and use a switch case condition to create the right data source - url: dataSourceMetadata.url ?? this.environmentService.getPGDatabaseUrl(), - type: 'postgres', - logging: ['query'], - schema, - entities: { - TenantMigration, - }, - }); - - await workspaceDataSource.initialize(); - - this.dataSources.set(workspaceId, workspaceDataSource); - - return workspaceDataSource; - } - - /** - * Disconnects from a workspace data source. - * @param workspaceId - * @returns Promise - * - */ - public async disconnectFromWorkspaceDataSource(workspaceId: string) { - if (!this.dataSources.has(workspaceId)) { - return; - } - - const dataSource = this.dataSources.get(workspaceId); - - await dataSource?.destroy(); - - this.dataSources.delete(workspaceId); - } - - /** - * - * Returns the schema name for a given workspaceId - * @param workspaceId - * @returns string - */ - public getSchemaName(workspaceId: string): string { - return `workspace_${uuidToBase36(workspaceId)}`; - } - - public async deleteWorkspaceSchema(workspaceId: string) { - const schemaName = this.getSchemaName(workspaceId); - const queryRunner = this.mainDataSource.createQueryRunner(); - const schemaAlreadyExists = await queryRunner.hasSchema(schemaName); - - if (!schemaAlreadyExists) { - await queryRunner.release(); - return; - } - - await queryRunner.dropSchema(schemaName, true, true); - - await queryRunner.release(); - } - - async onModuleInit() { - // Init main data source "default" schema - await this.mainDataSource.initialize(); - } - - async onModuleDestroy() { - // Destroy main data source "default" schema - await this.mainDataSource.destroy(); - - // Destroy all workspace data sources - for (const [, dataSource] of this.dataSources) { - await dataSource.destroy(); - } - } -} diff --git a/server/src/metadata/data-source/data-source.util.ts b/server/src/metadata/data-source/data-source.util.ts deleted file mode 100644 index 0658a1e468..0000000000 --- a/server/src/metadata/data-source/data-source.util.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Converts a UUID to a base 36 string. - * This is used to generate the schema name since hyphens from workspace uuid are not allowed in postgres schema names. - * - * @param uuid - * @returns - */ -export function uuidToBase36(uuid: string): string { - let devId = false; - - if (uuid.startsWith('twenty-')) { - devId = true; - // Clean dev uuids (twenty-) - uuid = uuid.replace('twenty-', ''); - } - const hexString = uuid.replace(/-/g, ''); - const base10Number = BigInt('0x' + hexString); - const base36String = base10Number.toString(36); - - return `${devId ? 'twenty_' : ''}${base36String}`; -} diff --git a/server/src/metadata/field-metadata/dtos/create-field.input.ts b/server/src/metadata/field-metadata/dtos/create-field.input.ts index 04b445aac1..cc4e7d8cf1 100644 --- a/server/src/metadata/field-metadata/dtos/create-field.input.ts +++ b/server/src/metadata/field-metadata/dtos/create-field.input.ts @@ -1,5 +1,6 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, HideField, InputType } from '@nestjs/graphql'; +import { BeforeCreateOne } from '@ptc-org/nestjs-query-graphql'; import { IsEnum, IsNotEmpty, @@ -8,9 +9,13 @@ import { IsUUID, } from 'class-validator'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; + +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { BeforeCreateOneField } from 'src/metadata/field-metadata/hooks/before-create-one-field.hook'; @InputType() +@BeforeCreateOne(BeforeCreateOneField) export class CreateFieldInput { @IsString() @IsNotEmpty() @@ -29,7 +34,7 @@ export class CreateFieldInput { @IsUUID() @Field() - objectId: string; + objectMetadataId: string; @IsString() @IsOptional() @@ -40,4 +45,10 @@ export class CreateFieldInput { @IsOptional() @Field({ nullable: true }) icon?: string; + + @HideField() + targetColumnMap: FieldMetadataTargetColumnMap; + + @HideField() + workspaceId: string; } diff --git a/server/src/metadata/field-metadata/dtos/field-metadata.dto.ts b/server/src/metadata/field-metadata/dtos/field-metadata.dto.ts new file mode 100644 index 0000000000..70636d24d2 --- /dev/null +++ b/server/src/metadata/field-metadata/dtos/field-metadata.dto.ts @@ -0,0 +1,81 @@ +import { + Field, + HideField, + ID, + ObjectType, + registerEnumType, +} from '@nestjs/graphql'; + +import { + Authorize, + IDField, + QueryOptions, + Relation, +} from '@ptc-org/nestjs-query-graphql'; + +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { RelationMetadataDTO } from 'src/metadata/relation-metadata/dtos/relation-metadata.dto'; + +registerEnumType(FieldMetadataType, { + name: 'FieldMetadataType', + description: 'Type of the field', +}); + +@ObjectType('field') +@Authorize({ + authorize: (context: any) => ({ + workspaceId: { eq: context?.req?.user?.workspace?.id }, + }), +}) +@QueryOptions({ + defaultResultSize: 10, + disableFilter: true, + disableSort: true, + maxResultsSize: 1000, +}) +@Relation('toRelationMetadata', () => RelationMetadataDTO, { + nullable: true, +}) +@Relation('fromRelationMetadata', () => RelationMetadataDTO, { + nullable: true, +}) +export class FieldMetadataDTO { + @IDField(() => ID) + id: string; + + @Field(() => FieldMetadataType) + type: FieldMetadataType; + + @Field() + name: string; + + @Field() + label: string; + + @Field({ nullable: true }) + description: string; + + @Field({ nullable: true }) + icon: string; + + @Field({ nullable: true, deprecationReason: 'Use label name instead' }) + placeholder?: string; + + @Field() + isCustom: boolean; + + @Field() + isActive: boolean; + + @Field() + isNullable: boolean; + + @HideField() + workspaceId: string; + + @Field() + createdAt: Date; + + @Field() + updatedAt: Date; +} diff --git a/server/src/metadata/field-metadata/field-metadata.auto-resolver-opts.ts b/server/src/metadata/field-metadata/field-metadata.auto-resolver-opts.ts deleted file mode 100644 index 66f3c53dac..0000000000 --- a/server/src/metadata/field-metadata/field-metadata.auto-resolver-opts.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { SortDirection } from '@ptc-org/nestjs-query-core'; -import { - AutoResolverOpts, - PagingStrategies, - ReadResolverOpts, -} from '@ptc-org/nestjs-query-graphql'; - -import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; - -import { FieldMetadata } from './field-metadata.entity'; - -import { FieldMetadataService } from './services/field-metadata.service'; -import { CreateFieldInput } from './dtos/create-field.input'; -import { UpdateFieldInput } from './dtos/update-field.input'; - -export const fieldMetadataAutoResolverOpts: AutoResolverOpts< - any, - any, - unknown, - unknown, - ReadResolverOpts, - PagingStrategies ->[] = [ - { - EntityClass: FieldMetadata, - DTOClass: FieldMetadata, - CreateDTOClass: CreateFieldInput, - UpdateDTOClass: UpdateFieldInput, - ServiceClass: FieldMetadataService, - enableTotalCount: true, - pagingStrategy: PagingStrategies.CURSOR, - read: { - defaultSort: [{ field: 'id', direction: SortDirection.DESC }], - }, - create: { - many: { disabled: true }, - }, - update: { - many: { disabled: true }, - }, - delete: { many: { disabled: true } }, - guards: [JwtAuthGuard], - }, -]; diff --git a/server/src/metadata/field-metadata/field-metadata.entity.ts b/server/src/metadata/field-metadata/field-metadata.entity.ts deleted file mode 100644 index 0d78f56e80..0000000000 --- a/server/src/metadata/field-metadata/field-metadata.entity.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { Field, ID, ObjectType, registerEnumType } from '@nestjs/graphql'; - -import { - Column, - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - OneToOne, - PrimaryGeneratedColumn, - Unique, - UpdateDateColumn, -} from 'typeorm'; -import { - Authorize, - BeforeCreateOne, - IDField, - QueryOptions, - Relation, -} from '@ptc-org/nestjs-query-graphql'; - -import { FieldMetadataInterface } from 'src/tenant/schema-builder/interfaces/field-metadata.interface'; - -import { ObjectMetadata } from 'src/metadata/object-metadata/object-metadata.entity'; -import { RelationMetadata } from 'src/metadata/relation-metadata/relation-metadata.entity'; - -import { BeforeCreateOneField } from './hooks/before-create-one-field.hook'; -import { FieldMetadataTargetColumnMap } from './interfaces/field-metadata-target-column-map.interface'; - -export enum FieldMetadataType { - UUID = 'uuid', - TEXT = 'TEXT', - PHONE = 'PHONE', - EMAIL = 'EMAIL', - DATE = 'DATE', - BOOLEAN = 'BOOLEAN', - NUMBER = 'NUMBER', - ENUM = 'ENUM', - URL = 'URL', - MONEY = 'MONEY', - RELATION = 'RELATION', -} - -registerEnumType(FieldMetadataType, { - name: 'FieldMetadataType', - description: 'Type of the field', -}); - -@Entity('field_metadata') -@ObjectType('field') -@BeforeCreateOne(BeforeCreateOneField) -@Authorize({ - authorize: (context: any) => ({ - workspaceId: { eq: context?.req?.user?.workspace?.id }, - }), -}) -@QueryOptions({ - defaultResultSize: 10, - disableFilter: true, - disableSort: true, - maxResultsSize: 1000, -}) -@Unique('IndexOnNameObjectIdAndWorkspaceIdUnique', [ - 'name', - 'objectId', - 'workspaceId', -]) -@Relation('toRelationMetadata', () => RelationMetadata, { nullable: true }) -@Relation('fromRelationMetadata', () => RelationMetadata, { nullable: true }) -export class FieldMetadata implements FieldMetadataInterface { - @IDField(() => ID) - @PrimaryGeneratedColumn('uuid') - id: string; - - @Column({ nullable: false, name: 'object_id' }) - objectId: string; - - @Field(() => FieldMetadataType) - @Column({ nullable: false }) - type: FieldMetadataType; - - @Field() - @Column({ nullable: false }) - name: string; - - @Field() - @Column({ nullable: false }) - label: string; - - @Column({ nullable: false, name: 'target_column_map', type: 'jsonb' }) - targetColumnMap: FieldMetadataTargetColumnMap; - - @Field({ nullable: true }) - @Column({ nullable: true, name: 'description', type: 'text' }) - description: string; - - @Field({ nullable: true }) - @Column({ nullable: true, name: 'icon' }) - icon: string; - - @Field({ nullable: true, deprecationReason: 'Use label name instead' }) - placeholder: string; - - @Column('text', { nullable: true, array: true }) - enums: string[]; - - @Field() - @Column({ default: false, name: 'is_custom' }) - isCustom: boolean; - - @Field() - @Column({ default: false, name: 'is_active' }) - isActive: boolean; - - @Field() - @Column({ nullable: true, default: true, name: 'is_nullable' }) - isNullable: boolean; - - @Column({ nullable: false, name: 'workspace_id' }) - workspaceId: string; - - @ManyToOne(() => ObjectMetadata, (object) => object.fields, { - onDelete: 'CASCADE', - }) - @JoinColumn({ name: 'object_id' }) - object: ObjectMetadata; - - @OneToOne(() => RelationMetadata, (relation) => relation.fromFieldMetadata) - fromRelationMetadata: RelationMetadata; - - @OneToOne(() => RelationMetadata, (relation) => relation.toFieldMetadata) - toRelationMetadata: RelationMetadata; - - @Field() - @CreateDateColumn({ name: 'created_at' }) - createdAt: Date; - - @Field() - @UpdateDateColumn({ name: 'updated_at' }) - updatedAt: Date; -} diff --git a/server/src/metadata/field-metadata/field-metadata.module.ts b/server/src/metadata/field-metadata/field-metadata.module.ts index 45b1ae6260..87bfa82cb0 100644 --- a/server/src/metadata/field-metadata/field-metadata.module.ts +++ b/server/src/metadata/field-metadata/field-metadata.module.ts @@ -1,28 +1,56 @@ import { Module } from '@nestjs/common'; -import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql'; +import { + NestjsQueryGraphQLModule, + PagingStrategies, +} from '@ptc-org/nestjs-query-graphql'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; +import { SortDirection } from '@ptc-org/nestjs-query-core'; -import { MigrationRunnerModule } from 'src/metadata/migration-runner/migration-runner.module'; +import { TenantMigrationRunnerModule } from 'src/tenant-migration-runner/tenant-migration-runner.module'; import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; -import { FieldMetadata } from './field-metadata.entity'; -import { fieldMetadataAutoResolverOpts } from './field-metadata.auto-resolver-opts'; +import { FieldMetadataService } from './field-metadata.service'; -import { FieldMetadataService } from './services/field-metadata.service'; +import { CreateFieldInput } from './dtos/create-field.input'; +import { FieldMetadataDTO } from './dtos/field-metadata.dto'; +import { UpdateFieldInput } from './dtos/update-field.input'; @Module({ imports: [ NestjsQueryGraphQLModule.forFeature({ imports: [ - NestjsQueryTypeOrmModule.forFeature([FieldMetadata], 'metadata'), + NestjsQueryTypeOrmModule.forFeature([FieldMetadataEntity], 'metadata'), TenantMigrationModule, - MigrationRunnerModule, + TenantMigrationRunnerModule, ObjectMetadataModule, ], services: [FieldMetadataService], - resolvers: fieldMetadataAutoResolverOpts, + resolvers: [ + { + EntityClass: FieldMetadataEntity, + DTOClass: FieldMetadataDTO, + CreateDTOClass: CreateFieldInput, + UpdateDTOClass: UpdateFieldInput, + ServiceClass: FieldMetadataService, + enableTotalCount: true, + pagingStrategy: PagingStrategies.CURSOR, + read: { + defaultSort: [{ field: 'id', direction: SortDirection.DESC }], + }, + create: { + many: { disabled: true }, + }, + update: { + many: { disabled: true }, + }, + delete: { many: { disabled: true } }, + guards: [JwtAuthGuard], + }, + ], }), ], providers: [FieldMetadataService], diff --git a/server/src/metadata/field-metadata/services/field-metadata.service.ts b/server/src/metadata/field-metadata/field-metadata.service.ts similarity index 71% rename from server/src/metadata/field-metadata/services/field-metadata.service.ts rename to server/src/metadata/field-metadata/field-metadata.service.ts index 36a4185415..c0cce5f922 100644 --- a/server/src/metadata/field-metadata/services/field-metadata.service.ts +++ b/server/src/metadata/field-metadata/field-metadata.service.ts @@ -10,37 +10,38 @@ import { Repository } from 'typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { DeleteOneOptions } from '@ptc-org/nestjs-query-core'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; import { convertFieldMetadataToColumnActions, generateTargetColumnMap, } from 'src/metadata/field-metadata/utils/field-metadata.util'; -import { MigrationRunnerService } from 'src/metadata/migration-runner/migration-runner.service'; +import { TenantMigrationRunnerService } from 'src/tenant-migration-runner/tenant-migration-runner.service'; import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; -import { ObjectMetadataService } from 'src/metadata/object-metadata/services/object-metadata.service'; -import { TenantMigrationTableAction } from 'src/metadata/tenant-migration/tenant-migration.entity'; +import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { FieldMetadataDTO } from 'src/metadata/field-metadata/dtos/field-metadata.dto'; +import { CreateFieldInput } from 'src/metadata/field-metadata/dtos/create-field.input'; +import { TenantMigrationTableAction } from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; @Injectable() -export class FieldMetadataService extends TypeOrmQueryService { +export class FieldMetadataService extends TypeOrmQueryService { constructor( - @InjectRepository(FieldMetadata, 'metadata') - private readonly fieldMetadataRepository: Repository, + @InjectRepository(FieldMetadataEntity, 'metadata') + private readonly fieldMetadataRepository: Repository, private readonly objectMetadataService: ObjectMetadataService, private readonly tenantMigrationService: TenantMigrationService, - private readonly migrationRunnerService: MigrationRunnerService, + private readonly migrationRunnerService: TenantMigrationRunnerService, ) { super(fieldMetadataRepository); } override async deleteOne( id: string, - opts?: DeleteOneOptions | undefined, - ): Promise { + opts?: DeleteOneOptions | undefined, + ): Promise { const fieldMetadata = await this.fieldMetadataRepository.findOne({ where: { id }, }); - if (!fieldMetadata) { throw new NotFoundException('Field does not exist'); } @@ -58,10 +59,12 @@ export class FieldMetadataService extends TypeOrmQueryService { return super.deleteOne(id, opts); } - override async createOne(record: FieldMetadata): Promise { + override async createOne( + record: CreateFieldInput, + ): Promise { const objectMetadata = await this.objectMetadataService.findOneWithinWorkspace( - record.objectId, + record.objectMetadataId, record.workspaceId, ); @@ -72,7 +75,7 @@ export class FieldMetadataService extends TypeOrmQueryService { const fieldAlreadyExists = await this.fieldMetadataRepository.findOne({ where: { name: record.name, - objectId: record.objectId, + objectMetadataId: record.objectMetadataId, workspaceId: record.workspaceId, }, }); @@ -83,11 +86,9 @@ export class FieldMetadataService extends TypeOrmQueryService { const createdFieldMetadata = await super.createOne({ ...record, - targetColumnMap: generateTargetColumnMap( - record.type, - record.isCustom, - record.name, - ), + targetColumnMap: generateTargetColumnMap(record.type, true, record.name), + isActive: true, + isCustom: true, }); await this.tenantMigrationService.createCustomMigration( diff --git a/server/src/metadata/field-metadata/hooks/before-create-one-field.hook.ts b/server/src/metadata/field-metadata/hooks/before-create-one-field.hook.ts index 1d44025785..bd878871f9 100644 --- a/server/src/metadata/field-metadata/hooks/before-create-one-field.hook.ts +++ b/server/src/metadata/field-metadata/hooks/before-create-one-field.hook.ts @@ -5,10 +5,10 @@ import { CreateOneInputType, } from '@ptc-org/nestjs-query-graphql'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; +import { CreateFieldInput } from 'src/metadata/field-metadata/dtos/create-field.input'; @Injectable() -export class BeforeCreateOneField +export class BeforeCreateOneField implements BeforeCreateOneHook { async run( @@ -22,8 +22,6 @@ export class BeforeCreateOneField } instance.input.workspaceId = workspaceId; - instance.input.isActive = true; - instance.input.isCustom = true; return instance; } } diff --git a/server/src/metadata/field-metadata/services/field-metadata.service.spec.ts b/server/src/metadata/field-metadata/services/field-metadata.service.spec.ts deleted file mode 100644 index 87b62cad30..0000000000 --- a/server/src/metadata/field-metadata/services/field-metadata.service.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; - -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; -import { MigrationRunnerService } from 'src/metadata/migration-runner/migration-runner.service'; -import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; -import { ObjectMetadataService } from 'src/metadata/object-metadata/services/object-metadata.service'; - -import { FieldMetadataService } from './field-metadata.service'; - -describe('FieldMetadataService', () => { - let service: FieldMetadataService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - FieldMetadataService, - { - provide: getRepositoryToken(FieldMetadata, 'metadata'), - useValue: {}, - }, - { - provide: ObjectMetadataService, - useValue: {}, - }, - { - provide: TenantMigrationService, - useValue: {}, - }, - { - provide: MigrationRunnerService, - useValue: {}, - }, - ], - }).compile(); - - service = module.get(FieldMetadataService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/server/src/metadata/field-metadata/utils/field-metadata.util.spec.ts b/server/src/metadata/field-metadata/utils/field-metadata.util.spec.ts index 187fd16d27..4380eada70 100644 --- a/server/src/metadata/field-metadata/utils/field-metadata.util.spec.ts +++ b/server/src/metadata/field-metadata/utils/field-metadata.util.spec.ts @@ -1,4 +1,4 @@ -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { generateTargetColumnMap, diff --git a/server/src/metadata/field-metadata/utils/field-metadata.util.ts b/server/src/metadata/field-metadata/utils/field-metadata.util.ts index 1e55fbf5c2..93492085ec 100644 --- a/server/src/metadata/field-metadata/utils/field-metadata.util.ts +++ b/server/src/metadata/field-metadata/utils/field-metadata.util.ts @@ -1,13 +1,13 @@ -import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; import { - FieldMetadata, + FieldMetadataEntity, FieldMetadataType, -} from 'src/metadata/field-metadata/field-metadata.entity'; +} from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { TenantMigrationColumnAction, TenantMigrationColumnActionType, -} from 'src/metadata/tenant-migration/tenant-migration.entity'; +} from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; /** * Generate a target column map for a given type, this is used to map the field to the correct column(s) in the database. @@ -49,7 +49,7 @@ export function generateTargetColumnMap( } export function convertFieldMetadataToColumnActions( - fieldMetadata: FieldMetadata, + fieldMetadata: FieldMetadataEntity, ): TenantMigrationColumnAction[] { switch (fieldMetadata.type) { case FieldMetadataType.TEXT: diff --git a/server/src/metadata/metadata.module.ts b/server/src/metadata/metadata.module.ts index d7461d6b78..fa7bd15953 100644 --- a/server/src/metadata/metadata.module.ts +++ b/server/src/metadata/metadata.module.ts @@ -1,32 +1,18 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; import { GraphQLModule } from '@nestjs/graphql'; import { YogaDriverConfig, YogaDriver } from '@graphql-yoga/nestjs'; import GraphQLJSON from 'graphql-type-json'; -import { MigrationRunnerModule } from 'src/metadata/migration-runner/migration-runner.module'; +import { TenantMigrationRunnerModule } from 'src/tenant-migration-runner/tenant-migration-runner.module'; import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; -import { typeORMMetadataModuleOptions } from './metadata.datasource'; - -import { DataSourceModule } from './data-source/data-source.module'; import { DataSourceMetadataModule } from './data-source-metadata/data-source-metadata.module'; import { FieldMetadataModule } from './field-metadata/field-metadata.module'; import { ObjectMetadataModule } from './object-metadata/object-metadata.module'; import { RelationMetadataModule } from './relation-metadata/relation-metadata.module'; - -const typeORMFactory = async (): Promise => ({ - ...typeORMMetadataModuleOptions, - name: 'metadata', -}); - @Module({ imports: [ - TypeOrmModule.forRootAsync({ - useFactory: typeORMFactory, - name: 'metadata', - }), GraphQLModule.forRoot({ context: ({ req }) => ({ req }), driver: YogaDriver, @@ -36,11 +22,10 @@ const typeORMFactory = async (): Promise => ({ plugins: [], path: '/metadata', }), - DataSourceModule, DataSourceMetadataModule, FieldMetadataModule, ObjectMetadataModule, - MigrationRunnerModule, + TenantMigrationRunnerModule, TenantMigrationModule, RelationMetadataModule, ], diff --git a/server/src/metadata/migration-runner/migration-runner.module.ts b/server/src/metadata/migration-runner/migration-runner.module.ts deleted file mode 100644 index c042a7671d..0000000000 --- a/server/src/metadata/migration-runner/migration-runner.module.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { DataSourceModule } from 'src/metadata/data-source/data-source.module'; -import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; - -import { MigrationRunnerService } from './migration-runner.service'; - -@Module({ - imports: [DataSourceModule, TenantMigrationModule], - exports: [MigrationRunnerService], - providers: [MigrationRunnerService], -}) -export class MigrationRunnerModule {} diff --git a/server/src/metadata/migration-runner/migration-runner.service.spec.ts b/server/src/metadata/migration-runner/migration-runner.service.spec.ts deleted file mode 100644 index e97caafe2c..0000000000 --- a/server/src/metadata/migration-runner/migration-runner.service.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; - -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; -import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; - -import { MigrationRunnerService } from './migration-runner.service'; - -describe('MigrationRunnerService', () => { - let service: MigrationRunnerService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - MigrationRunnerService, - { - provide: DataSourceService, - useValue: {}, - }, - { - provide: TenantMigrationService, - useValue: {}, - }, - ], - }).compile(); - - service = module.get(MigrationRunnerService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/server/src/metadata/migrations/1695214465080-InitMetadataTables.ts b/server/src/metadata/migrations/1695214465080-InitMetadataTables.ts deleted file mode 100644 index 13647df58d..0000000000 --- a/server/src/metadata/migrations/1695214465080-InitMetadataTables.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class InitMetadataTables1695214465080 implements MigrationInterface { - name = 'InitMetadataTables1695214465080'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TYPE "metadata"."data_source_metadata_type_enum" AS ENUM ('postgres', 'mysql');`, - ); - await queryRunner.query( - `CREATE TABLE "metadata"."data_source_metadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "url" character varying, "schema" character varying, "type" "metadata"."data_source_metadata_type_enum" NOT NULL DEFAULT 'postgres', "display_name" character varying, "is_remote" boolean NOT NULL DEFAULT false, "workspace_id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_923752b7e62a300a4969bd0e038" PRIMARY KEY ("id"))`, - ); - await queryRunner.query( - `CREATE TABLE "metadata"."field_metadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "object_id" uuid NOT NULL, "type" character varying NOT NULL, "display_name" character varying NOT NULL, "target_column_name" character varying NOT NULL, "is_custom" boolean NOT NULL DEFAULT false, "workspace_id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_c75db587904cad6af109b5c65f1" PRIMARY KEY ("id"))`, - ); - await queryRunner.query( - `CREATE TABLE "metadata"."object_metadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "data_source_id" character varying NOT NULL, "display_name" character varying NOT NULL, "target_table_name" character varying NOT NULL, "is_custom" boolean NOT NULL DEFAULT false, "workspace_id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_c8c5f885767b356949c18c201c1" PRIMARY KEY ("id"))`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "FK_38179b299795e48887fc99f937a" FOREIGN KEY ("object_id") REFERENCES "metadata"."object_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "FK_38179b299795e48887fc99f937a"`, - ); - await queryRunner.query(`DROP TABLE "metadata"."object_metadata"`); - await queryRunner.query(`DROP TABLE "metadata"."field_metadata"`); - await queryRunner.query(`DROP TABLE "metadata"."data_source_metadata"`); - } -} diff --git a/server/src/metadata/migrations/1695717691800-alter-field-metadata-table.ts b/server/src/metadata/migrations/1695717691800-alter-field-metadata-table.ts deleted file mode 100644 index 4483db8dfe..0000000000 --- a/server/src/metadata/migrations/1695717691800-alter-field-metadata-table.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AlterFieldMetadataTable1695717691800 - implements MigrationInterface -{ - name = 'AlterFieldMetadataTable1695717691800'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "enums" text array`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "is_nullable" boolean DEFAULT true`, - ); - await queryRunner.query( - `ALTER TYPE "metadata"."data_source_metadata_type_enum" RENAME TO "data_source_metadata_type_enum_old"`, - ); - await queryRunner.query( - `CREATE TYPE "metadata"."data_source_metadata_type_enum" AS ENUM('postgres')`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" ALTER COLUMN "type" DROP DEFAULT`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" ALTER COLUMN "type" TYPE "metadata"."data_source_metadata_type_enum" USING "type"::"text"::"metadata"."data_source_metadata_type_enum"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" ALTER COLUMN "type" SET DEFAULT 'postgres'`, - ); - await queryRunner.query( - `DROP TYPE "metadata"."data_source_metadata_type_enum_old"`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TYPE "metadata"."data_source_metadata_type_enum_old" AS ENUM('postgres', 'mysql')`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" ALTER COLUMN "type" DROP DEFAULT`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" ALTER COLUMN "type" TYPE "metadata"."data_source_metadata_type_enum_old" USING "type"::"text"::"metadata"."data_source_metadata_type_enum_old"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" ALTER COLUMN "type" SET DEFAULT 'postgres'`, - ); - await queryRunner.query( - `DROP TYPE "metadata"."data_source_metadata_type_enum"`, - ); - await queryRunner.query( - `ALTER TYPE "metadata"."data_source_metadata_type_enum_old" RENAME TO "data_source_metadata_type_enum"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "is_nullable"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "enums"`, - ); - } -} diff --git a/server/src/metadata/migrations/1696409050890-add-target-column-map.ts b/server/src/metadata/migrations/1696409050890-add-target-column-map.ts deleted file mode 100644 index 23da21eb01..0000000000 --- a/server/src/metadata/migrations/1696409050890-add-target-column-map.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddTargetColumnMap1696409050890 implements MigrationInterface { - name = 'AddTargetColumnMap1696409050890'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "description" text`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "icon" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "placeholder" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "target_column_map" jsonb`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "is_active" boolean NOT NULL DEFAULT false`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "display_name_singular" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "display_name_plural" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "description" text`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "icon" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "is_active" boolean NOT NULL DEFAULT false`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "is_active"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "icon"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "description"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "display_name_plural"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "display_name_singular"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "is_active"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "target_column_map"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "placeholder"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "icon"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "description"`, - ); - } -} diff --git a/server/src/metadata/migrations/1697126636202-MetadataNameLabelRefactoring.ts b/server/src/metadata/migrations/1697126636202-MetadataNameLabelRefactoring.ts deleted file mode 100644 index 1f0bc5094c..0000000000 --- a/server/src/metadata/migrations/1697126636202-MetadataNameLabelRefactoring.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class MetadataNameLabelRefactoring1697126636202 - implements MigrationInterface -{ - name = 'MetadataNameLabelRefactoring1697126636202'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" RENAME COLUMN "display_name" TO "label"`, - ); - await queryRunner.query( - `CREATE TABLE "metadata"."tenant_migrations" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "migrations" jsonb, "applied_at" TIMESTAMP, "created_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_cb644cbc7f5092850f25eecb465" PRIMARY KEY ("id"))`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "display_name"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "display_name_singular"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "display_name_plural"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "display_name"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "target_column_name"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "name_singular" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD CONSTRAINT "UQ_8b063d2a685474dbae56cd685d2" UNIQUE ("name_singular")`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "name_plural" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD CONSTRAINT "UQ_a2387e1b21120110b7e3db83da1" UNIQUE ("name_plural")`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "label_singular" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "label_plural" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "name_singular" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "name_plural" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "label_singular" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "label_plural" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" ALTER COLUMN "id" SET DEFAULT uuid_generate_v4()`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "FK_38179b299795e48887fc99f937a"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ALTER COLUMN "id" SET DEFAULT uuid_generate_v4()`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ALTER COLUMN "id" SET DEFAULT uuid_generate_v4()`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ALTER COLUMN "target_column_map" SET NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "FK_38179b299795e48887fc99f937a" FOREIGN KEY ("object_id") REFERENCES "metadata"."object_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "FK_38179b299795e48887fc99f937a"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ALTER COLUMN "target_column_map" DROP NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ALTER COLUMN "id" DROP DEFAULT`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ALTER COLUMN "id" DROP DEFAULT`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "FK_38179b299795e48887fc99f937a" FOREIGN KEY ("object_id") REFERENCES "metadata"."object_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" ALTER COLUMN "id" DROP DEFAULT`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "label_plural"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "label_singular"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "name_plural"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "name_singular"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "label_plural"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "label_singular"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP CONSTRAINT "UQ_a2387e1b21120110b7e3db83da1"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "name_plural"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP CONSTRAINT "UQ_8b063d2a685474dbae56cd685d2"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "name_singular"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "target_column_name" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "display_name" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "display_name_plural" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "display_name_singular" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "display_name" character varying NOT NULL`, - ); - await queryRunner.query(`DROP TABLE "metadata"."tenant_migrations"`); - await queryRunner.query( - `ALTER TABLE "metadata"."data_source_metadata" RENAME COLUMN "label" TO "display_name"`, - ); - } -} diff --git a/server/src/metadata/migrations/1697471445015-removeFieldMetadataPlaceholder.ts b/server/src/metadata/migrations/1697471445015-removeFieldMetadataPlaceholder.ts deleted file mode 100644 index b1235e2e56..0000000000 --- a/server/src/metadata/migrations/1697471445015-removeFieldMetadataPlaceholder.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveFieldMetadataPlaceholder1697471445015 - implements MigrationInterface -{ - name = 'RemoveFieldMetadataPlaceholder1697471445015'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "placeholder"`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "placeholder" character varying`, - ); - } -} diff --git a/server/src/metadata/migrations/1697474804403-addSoftDelete.ts b/server/src/metadata/migrations/1697474804403-addSoftDelete.ts deleted file mode 100644 index 675525c67f..0000000000 --- a/server/src/metadata/migrations/1697474804403-addSoftDelete.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddSoftDelete1697474804403 implements MigrationInterface { - name = 'AddSoftDelete1697474804403'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "deleted_at" TIMESTAMP`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "deleted_at" TIMESTAMP`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "deleted_at"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "deleted_at"`, - ); - } -} diff --git a/server/src/metadata/migrations/1697534910933-removeSingularPluralFromFieldLabelAndName.ts b/server/src/metadata/migrations/1697534910933-removeSingularPluralFromFieldLabelAndName.ts deleted file mode 100644 index e8a3515135..0000000000 --- a/server/src/metadata/migrations/1697534910933-removeSingularPluralFromFieldLabelAndName.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveSingularPluralFromFieldLabelAndName1697534910933 - implements MigrationInterface -{ - name = 'RemoveSingularPluralFromFieldLabelAndName1697534910933'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "name_singular"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "name_plural"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "label_singular"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "label_plural"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "name" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "label" character varying NOT NULL`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "label"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "name"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "label_plural" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "label_singular" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "name_plural" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "name_singular" character varying NOT NULL`, - ); - } -} diff --git a/server/src/metadata/migrations/1697622715467-addNameAndIsCustomToTenantMigration.ts b/server/src/metadata/migrations/1697622715467-addNameAndIsCustomToTenantMigration.ts deleted file mode 100644 index 7e828d9f2a..0000000000 --- a/server/src/metadata/migrations/1697622715467-addNameAndIsCustomToTenantMigration.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddNameAndIsCustomToTenantMigration1697622715467 - implements MigrationInterface -{ - name = 'AddNameAndIsCustomToTenantMigration1697622715467'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" DROP COLUMN "applied_at"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" DROP COLUMN "created_at"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" ADD "name" character varying`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" ADD "isCustom" boolean NOT NULL DEFAULT false`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" ADD "appliedAt" TIMESTAMP`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" ADD "workspaceId" character varying NOT NULL`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" ADD "createdAt" TIMESTAMP NOT NULL DEFAULT now()`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" DROP COLUMN "createdAt"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" DROP COLUMN "workspaceId"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" DROP COLUMN "appliedAt"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" DROP COLUMN "isCustom"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" DROP COLUMN "name"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" ADD "created_at" TIMESTAMP NOT NULL DEFAULT now()`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."tenant_migrations" ADD "applied_at" TIMESTAMP`, - ); - } -} diff --git a/server/src/metadata/migrations/1697630766924-addUniqueConstraintsOnFieldObjectMetadata.ts b/server/src/metadata/migrations/1697630766924-addUniqueConstraintsOnFieldObjectMetadata.ts deleted file mode 100644 index cf1b580372..0000000000 --- a/server/src/metadata/migrations/1697630766924-addUniqueConstraintsOnFieldObjectMetadata.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddUniqueConstraintsOnFieldObjectMetadata1697630766924 - implements MigrationInterface -{ - name = 'AddUniqueConstraintsOnFieldObjectMetadata1697630766924'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP CONSTRAINT "UQ_8b063d2a685474dbae56cd685d2"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP CONSTRAINT "UQ_a2387e1b21120110b7e3db83da1"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "IndexOnNameObjectIdAndWorkspaceIdUnique" UNIQUE ("name", "object_id", "workspace_id")`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD CONSTRAINT "IndexOnNamePluralAndWorkspaceIdUnique" UNIQUE ("name_plural", "workspace_id")`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD CONSTRAINT "IndexOnNameSingularAndWorkspaceIdUnique" UNIQUE ("name_singular", "workspace_id")`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP CONSTRAINT "IndexOnNameSingularAndWorkspaceIdUnique"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP CONSTRAINT "IndexOnNamePluralAndWorkspaceIdUnique"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "IndexOnNameAndWorkspaceIdUnique"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD CONSTRAINT "UQ_a2387e1b21120110b7e3db83da1" UNIQUE ("name_plural")`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD CONSTRAINT "UQ_8b063d2a685474dbae56cd685d2" UNIQUE ("name_singular")`, - ); - } -} diff --git a/server/src/metadata/migrations/1698328717102-removeMetadataSoftDelete.ts b/server/src/metadata/migrations/1698328717102-removeMetadataSoftDelete.ts deleted file mode 100644 index 1f960e7116..0000000000 --- a/server/src/metadata/migrations/1698328717102-removeMetadataSoftDelete.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class RemoveMetadataSoftDelete1698328717102 - implements MigrationInterface -{ - name = 'RemoveMetadataSoftDelete1698328717102'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "FK_38179b299795e48887fc99f937a"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" DROP COLUMN "deleted_at"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP COLUMN "deleted_at"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "FK_38179b299795e48887fc99f937a" FOREIGN KEY ("object_id") REFERENCES "metadata"."object_metadata"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "FK_38179b299795e48887fc99f937a"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD "deleted_at" TIMESTAMP`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."object_metadata" ADD "deleted_at" TIMESTAMP`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "FK_38179b299795e48887fc99f937a" FOREIGN KEY ("object_id") REFERENCES "metadata"."object_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - } -} diff --git a/server/src/metadata/migrations/1699289664146-addRelationMetadata.ts b/server/src/metadata/migrations/1699289664146-addRelationMetadata.ts deleted file mode 100644 index f2b7d333b4..0000000000 --- a/server/src/metadata/migrations/1699289664146-addRelationMetadata.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; - -export class AddRelationMetadata1699289664146 implements MigrationInterface { - name = 'AddRelationMetadata1699289664146'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "metadata"."relationMetadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "relationType" character varying NOT NULL, "fromObjectMetadataId" uuid NOT NULL, "toObjectMetadataId" uuid NOT NULL, "fromFieldMetadataId" uuid NOT NULL, "toFieldMetadataId" uuid NOT NULL, "workspaceId" character varying NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "REL_3deb257254145a3bdde9575e7d" UNIQUE ("fromFieldMetadataId"), CONSTRAINT "REL_9dea8f90d04edbbf9c541a95c3" UNIQUE ("toFieldMetadataId"), CONSTRAINT "PK_2724f60cb4f17a89481a7e8d7d3" PRIMARY KEY ("id"))`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."relationMetadata" ADD CONSTRAINT "FK_f2a0acd3a548ee446a1a35df44d" FOREIGN KEY ("fromObjectMetadataId") REFERENCES "metadata"."object_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."relationMetadata" ADD CONSTRAINT "FK_0f781f589e5a527b8f3d3a4b824" FOREIGN KEY ("toObjectMetadataId") REFERENCES "metadata"."object_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."relationMetadata" ADD CONSTRAINT "FK_3deb257254145a3bdde9575e7d6" FOREIGN KEY ("fromFieldMetadataId") REFERENCES "metadata"."field_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."relationMetadata" ADD CONSTRAINT "FK_9dea8f90d04edbbf9c541a95c3b" FOREIGN KEY ("toFieldMetadataId") REFERENCES "metadata"."field_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "metadata"."relationMetadata" DROP CONSTRAINT "FK_9dea8f90d04edbbf9c541a95c3b"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."relationMetadata" DROP CONSTRAINT "FK_3deb257254145a3bdde9575e7d6"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."relationMetadata" DROP CONSTRAINT "FK_0f781f589e5a527b8f3d3a4b824"`, - ); - await queryRunner.query( - `ALTER TABLE "metadata"."relationMetadata" DROP CONSTRAINT "FK_f2a0acd3a548ee446a1a35df44d"`, - ); - await queryRunner.query(`DROP TABLE "metadata"."relationMetadata"`); - } -} diff --git a/server/src/metadata/object-metadata/dtos/create-object.input.ts b/server/src/metadata/object-metadata/dtos/create-object.input.ts index 4c0ac158ed..505bb7a609 100644 --- a/server/src/metadata/object-metadata/dtos/create-object.input.ts +++ b/server/src/metadata/object-metadata/dtos/create-object.input.ts @@ -1,8 +1,12 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, HideField, InputType } from '@nestjs/graphql'; +import { BeforeCreateOne } from '@ptc-org/nestjs-query-graphql'; import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { BeforeCreateOneObject } from 'src/metadata/object-metadata/hooks/before-create-one-object.hook'; + @InputType() +@BeforeCreateOne(BeforeCreateOneObject) export class CreateObjectInput { @IsString() @IsNotEmpty() @@ -33,4 +37,10 @@ export class CreateObjectInput { @IsOptional() @Field({ nullable: true }) icon?: string; + + @HideField() + dataSourceId: string; + + @HideField() + workspaceId: string; } diff --git a/server/src/metadata/object-metadata/dtos/object-metadata.dto.ts b/server/src/metadata/object-metadata/dtos/object-metadata.dto.ts new file mode 100644 index 0000000000..5baaec569e --- /dev/null +++ b/server/src/metadata/object-metadata/dtos/object-metadata.dto.ts @@ -0,0 +1,64 @@ +import { ObjectType, ID, Field, HideField } from '@nestjs/graphql'; + +import { + Authorize, + CursorConnection, + IDField, + QueryOptions, +} from '@ptc-org/nestjs-query-graphql'; + +import { FieldMetadataDTO } from 'src/metadata/field-metadata/dtos/field-metadata.dto'; + +@ObjectType('object') +@Authorize({ + authorize: (context: any) => ({ + workspaceId: { eq: context?.req?.user?.workspace?.id }, + }), +}) +@QueryOptions({ + defaultResultSize: 10, + disableFilter: true, + disableSort: true, + maxResultsSize: 1000, +}) +@CursorConnection('fields', () => FieldMetadataDTO) +export class ObjectMetadataDTO { + @IDField(() => ID) + id: string; + + @Field() + dataSourceId: string; + + @Field() + nameSingular: string; + + @Field() + namePlural: string; + + @Field() + labelSingular: string; + + @Field() + labelPlural: string; + + @Field({ nullable: true }) + description: string; + + @Field({ nullable: true }) + icon: string; + + @Field() + isCustom: boolean; + + @Field() + isActive: boolean; + + @HideField() + workspaceId: string; + + @Field() + createdAt: Date; + + @Field() + updatedAt: Date; +} diff --git a/server/src/metadata/object-metadata/hooks/before-create-one-object.hook.ts b/server/src/metadata/object-metadata/hooks/before-create-one-object.hook.ts index b291d2bbd1..0d0f0c20b1 100644 --- a/server/src/metadata/object-metadata/hooks/before-create-one-object.hook.ts +++ b/server/src/metadata/object-metadata/hooks/before-create-one-object.hook.ts @@ -6,10 +6,10 @@ import { } from '@ptc-org/nestjs-query-graphql'; import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; -import { ObjectMetadata } from 'src/metadata/object-metadata/object-metadata.entity'; +import { CreateObjectInput } from 'src/metadata/object-metadata/dtos/create-object.input'; @Injectable() -export class BeforeCreateOneObject +export class BeforeCreateOneObject implements BeforeCreateOneHook { constructor(readonly dataSourceMetadataService: DataSourceMetadataService) {} @@ -30,10 +30,7 @@ export class BeforeCreateOneObject ); instance.input.dataSourceId = lastDataSourceMetadata.id; - instance.input.targetTableName = `_${instance.input.namePlural}`; instance.input.workspaceId = workspaceId; - instance.input.isActive = true; - instance.input.isCustom = true; return instance; } } diff --git a/server/src/metadata/object-metadata/object-metadata.auto-resolver-opts.ts b/server/src/metadata/object-metadata/object-metadata.auto-resolver-opts.ts deleted file mode 100644 index dd0477c50e..0000000000 --- a/server/src/metadata/object-metadata/object-metadata.auto-resolver-opts.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { SortDirection } from '@ptc-org/nestjs-query-core'; -import { - AutoResolverOpts, - PagingStrategies, - ReadResolverOpts, -} from '@ptc-org/nestjs-query-graphql'; - -import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; - -import { ObjectMetadata } from './object-metadata.entity'; - -import { ObjectMetadataService } from './services/object-metadata.service'; -import { CreateObjectInput } from './dtos/create-object.input'; -import { UpdateObjectInput } from './dtos/update-object.input'; - -export const objectMetadataAutoResolverOpts: AutoResolverOpts< - any, - any, - unknown, - unknown, - ReadResolverOpts, - PagingStrategies ->[] = [ - { - EntityClass: ObjectMetadata, - DTOClass: ObjectMetadata, - CreateDTOClass: CreateObjectInput, - UpdateDTOClass: UpdateObjectInput, - ServiceClass: ObjectMetadataService, - enableTotalCount: true, - pagingStrategy: PagingStrategies.CURSOR, - read: { - defaultSort: [{ field: 'id', direction: SortDirection.DESC }], - }, - create: { - many: { disabled: true }, - }, - update: { - many: { disabled: true }, - }, - delete: { many: { disabled: true } }, - guards: [JwtAuthGuard], - }, -]; diff --git a/server/src/metadata/object-metadata/object-metadata.entity.ts b/server/src/metadata/object-metadata/object-metadata.entity.ts deleted file mode 100644 index 4caabefb13..0000000000 --- a/server/src/metadata/object-metadata/object-metadata.entity.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { ObjectType, ID, Field } from '@nestjs/graphql'; - -import { - Column, - CreateDateColumn, - Entity, - OneToMany, - PrimaryGeneratedColumn, - Unique, - UpdateDateColumn, -} from 'typeorm'; -import { - Authorize, - BeforeCreateOne, - CursorConnection, - IDField, - QueryOptions, -} from '@ptc-org/nestjs-query-graphql'; - -import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface'; - -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; -import { RelationMetadata } from 'src/metadata/relation-metadata/relation-metadata.entity'; - -import { BeforeCreateOneObject } from './hooks/before-create-one-object.hook'; - -@Entity('object_metadata') -@ObjectType('object') -@BeforeCreateOne(BeforeCreateOneObject) -@Authorize({ - authorize: (context: any) => ({ - workspaceId: { eq: context?.req?.user?.workspace?.id }, - }), -}) -@QueryOptions({ - defaultResultSize: 10, - disableFilter: true, - disableSort: true, - maxResultsSize: 1000, -}) -@CursorConnection('fields', () => FieldMetadata) -@Unique('IndexOnNameSingularAndWorkspaceIdUnique', [ - 'nameSingular', - 'workspaceId', -]) -@Unique('IndexOnNamePluralAndWorkspaceIdUnique', ['namePlural', 'workspaceId']) -export class ObjectMetadata implements ObjectMetadataInterface { - @IDField(() => ID) - @PrimaryGeneratedColumn('uuid') - id: string; - - @Field() - @Column({ nullable: false, name: 'data_source_id' }) - dataSourceId: string; - - @Field() - @Column({ nullable: false, name: 'name_singular' }) - nameSingular: string; - - @Field() - @Column({ nullable: false, name: 'name_plural' }) - namePlural: string; - - @Field() - @Column({ nullable: false, name: 'label_singular' }) - labelSingular: string; - - @Field() - @Column({ nullable: false, name: 'label_plural' }) - labelPlural: string; - - @Field({ nullable: true }) - @Column({ nullable: true, name: 'description', type: 'text' }) - description: string; - - @Field({ nullable: true }) - @Column({ nullable: true, name: 'icon' }) - icon: string; - - @Column({ nullable: false, name: 'target_table_name' }) - targetTableName: string; - - @Field() - @Column({ default: false, name: 'is_custom' }) - isCustom: boolean; - - @Field() - @Column({ default: false, name: 'is_active' }) - isActive: boolean; - - @Column({ nullable: false, name: 'workspace_id' }) - workspaceId: string; - - @OneToMany(() => FieldMetadata, (field) => field.object, { - cascade: true, - }) - fields: FieldMetadata[]; - - @OneToMany(() => RelationMetadata, (relation) => relation.fromObjectMetadata) - fromRelations: RelationMetadata[]; - - @OneToMany(() => RelationMetadata, (relation) => relation.toObjectMetadata) - toRelations: RelationMetadata[]; - - @Field() - @CreateDateColumn({ name: 'created_at' }) - createdAt: Date; - - @Field() - @UpdateDateColumn({ name: 'updated_at' }) - updatedAt: Date; -} diff --git a/server/src/metadata/object-metadata/object-metadata.module.ts b/server/src/metadata/object-metadata/object-metadata.module.ts index 24822972aa..1b24985fdb 100644 --- a/server/src/metadata/object-metadata/object-metadata.module.ts +++ b/server/src/metadata/object-metadata/object-metadata.module.ts @@ -1,28 +1,56 @@ import { Module } from '@nestjs/common'; -import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql'; +import { + NestjsQueryGraphQLModule, + PagingStrategies, +} from '@ptc-org/nestjs-query-graphql'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; +import { SortDirection } from '@ptc-org/nestjs-query-core'; import { DataSourceMetadataModule } from 'src/metadata/data-source-metadata/data-source-metadata.module'; -import { MigrationRunnerModule } from 'src/metadata/migration-runner/migration-runner.module'; +import { TenantMigrationRunnerModule } from 'src/tenant-migration-runner/tenant-migration-runner.module'; import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; +import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; +import { ObjectMetadataEntity } from 'src/database/typeorm/metadata/entities/object-metadata.entity'; -import { ObjectMetadata } from './object-metadata.entity'; -import { objectMetadataAutoResolverOpts } from './object-metadata.auto-resolver-opts'; +import { ObjectMetadataService } from './object-metadata.service'; -import { ObjectMetadataService } from './services/object-metadata.service'; +import { CreateObjectInput } from './dtos/create-object.input'; +import { UpdateObjectInput } from './dtos/update-object.input'; +import { ObjectMetadataDTO } from './dtos/object-metadata.dto'; @Module({ imports: [ NestjsQueryGraphQLModule.forFeature({ imports: [ - NestjsQueryTypeOrmModule.forFeature([ObjectMetadata], 'metadata'), + NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'), DataSourceMetadataModule, TenantMigrationModule, - MigrationRunnerModule, + TenantMigrationRunnerModule, ], services: [ObjectMetadataService], - resolvers: objectMetadataAutoResolverOpts, + resolvers: [ + { + EntityClass: ObjectMetadataEntity, + DTOClass: ObjectMetadataDTO, + CreateDTOClass: CreateObjectInput, + UpdateDTOClass: UpdateObjectInput, + ServiceClass: ObjectMetadataService, + enableTotalCount: true, + pagingStrategy: PagingStrategies.CURSOR, + read: { + defaultSort: [{ field: 'id', direction: SortDirection.DESC }], + }, + create: { + many: { disabled: true }, + }, + update: { + many: { disabled: true }, + }, + delete: { many: { disabled: true } }, + guards: [JwtAuthGuard], + }, + ], }), ], providers: [ObjectMetadataService], diff --git a/server/src/metadata/object-metadata/services/object-metadata.service.ts b/server/src/metadata/object-metadata/object-metadata.service.ts similarity index 60% rename from server/src/metadata/object-metadata/services/object-metadata.service.ts rename to server/src/metadata/object-metadata/object-metadata.service.ts index 3324d3b9c4..f14a66e4e4 100644 --- a/server/src/metadata/object-metadata/services/object-metadata.service.ts +++ b/server/src/metadata/object-metadata/object-metadata.service.ts @@ -7,30 +7,27 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Equal, In, Repository } from 'typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; -import { DeleteOneOptions } from '@ptc-org/nestjs-query-core'; import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; -import { TenantMigrationTableAction } from 'src/metadata/tenant-migration/tenant-migration.entity'; -import { MigrationRunnerService } from 'src/metadata/migration-runner/migration-runner.service'; -import { ObjectMetadata } from 'src/metadata/object-metadata/object-metadata.entity'; -import { standardObjectsMetadata } from 'src/metadata/standard-objects/standard-object-metadata'; +import { TenantMigrationRunnerService } from 'src/tenant-migration-runner/tenant-migration-runner.service'; +import { ObjectMetadataEntity } from 'src/database/typeorm/metadata/entities/object-metadata.entity'; +import { TenantMigrationTableAction } from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; + +import { CreateObjectInput } from './dtos/create-object.input'; @Injectable() -export class ObjectMetadataService extends TypeOrmQueryService { +export class ObjectMetadataService extends TypeOrmQueryService { constructor( - @InjectRepository(ObjectMetadata, 'metadata') - private readonly objectMetadataRepository: Repository, + @InjectRepository(ObjectMetadataEntity, 'metadata') + private readonly objectMetadataRepository: Repository, private readonly tenantMigrationService: TenantMigrationService, - private readonly migrationRunnerService: MigrationRunnerService, + private readonly migrationRunnerService: TenantMigrationRunnerService, ) { super(objectMetadataRepository); } - override async deleteOne( - id: string, - opts?: DeleteOneOptions | undefined, - ): Promise { + override async deleteOne(id: string): Promise { const objectMetadata = await this.objectMetadataRepository.findOne({ where: { id }, }); @@ -47,11 +44,18 @@ export class ObjectMetadataService extends TypeOrmQueryService { throw new BadRequestException("Active objects can't be deleted"); } - return super.deleteOne(id, opts); + return super.deleteOne(id); } - override async createOne(record: ObjectMetadata): Promise { - const createdObjectMetadata = await super.createOne(record); + override async createOne( + record: CreateObjectInput, + ): Promise { + const createdObjectMetadata = await super.createOne({ + ...record, + targetTableName: `_${record.nameSingular}`, + isActive: true, + isCustom: true, + }); await this.tenantMigrationService.createCustomMigration( createdObjectMetadata.workspaceId, @@ -103,34 +107,6 @@ export class ObjectMetadataService extends TypeOrmQueryService { }); } - /** - * - * Create all standard objects and fields metadata for a given workspace - * - * @param dataSourceMetadataId - * @param workspaceId - */ - public async createStandardObjectsAndFieldsMetadata( - dataSourceMetadataId: string, - workspaceId: string, - ) { - await this.objectMetadataRepository.save( - Object.values(standardObjectsMetadata).map((objectMetadata) => ({ - ...objectMetadata, - dataSourceId: dataSourceMetadataId, - workspaceId, - isCustom: false, - isActive: true, - fields: objectMetadata.fields.map((field) => ({ - ...field, - workspaceId, - isCustom: false, - isActive: true, - })), - })), - ); - } - public async deleteObjectsMetadata(workspaceId: string) { await this.objectMetadataRepository.delete({ workspaceId }); } diff --git a/server/src/metadata/object-metadata/services/object-metadata.service.spec.ts b/server/src/metadata/object-metadata/services/object-metadata.service.spec.ts deleted file mode 100644 index 8b179110b3..0000000000 --- a/server/src/metadata/object-metadata/services/object-metadata.service.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; - -import { ObjectMetadata } from 'src/metadata/object-metadata/object-metadata.entity'; -import { MigrationRunnerService } from 'src/metadata/migration-runner/migration-runner.service'; -import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; - -import { ObjectMetadataService } from './object-metadata.service'; - -describe('ObjectMetadataService', () => { - let service: ObjectMetadataService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - ObjectMetadataService, - { - provide: getRepositoryToken(ObjectMetadata, 'metadata'), - useValue: {}, - }, - { - provide: TenantMigrationService, - useValue: {}, - }, - { - provide: MigrationRunnerService, - useValue: {}, - }, - ], - }).compile(); - - service = module.get(ObjectMetadataService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/server/src/metadata/relation-metadata/dtos/create-relation.input.ts b/server/src/metadata/relation-metadata/dtos/create-relation.input.ts index 2068b1fd07..cc6a7f6153 100644 --- a/server/src/metadata/relation-metadata/dtos/create-relation.input.ts +++ b/server/src/metadata/relation-metadata/dtos/create-relation.input.ts @@ -1,4 +1,4 @@ -import { Field, InputType } from '@nestjs/graphql'; +import { Field, HideField, InputType } from '@nestjs/graphql'; import { BeforeCreateOne } from '@ptc-org/nestjs-query-graphql'; import { @@ -9,9 +9,10 @@ import { IsUUID, } from 'class-validator'; -import { RelationType } from 'src/metadata/relation-metadata/relation-metadata.entity'; import { BeforeCreateOneRelation } from 'src/metadata/relation-metadata/hooks/before-create-one-relation.hook'; +import { RelationType } from './relation-metadata.dto'; + @InputType() @BeforeCreateOne(BeforeCreateOneRelation) export class CreateRelationInput { @@ -50,5 +51,6 @@ export class CreateRelationInput { @Field({ nullable: true }) icon?: string; + @HideField() workspaceId: string; } diff --git a/server/src/metadata/relation-metadata/dtos/relation-metadata.dto.ts b/server/src/metadata/relation-metadata/dtos/relation-metadata.dto.ts new file mode 100644 index 0000000000..9c8ffac66e --- /dev/null +++ b/server/src/metadata/relation-metadata/dtos/relation-metadata.dto.ts @@ -0,0 +1,62 @@ +import { ObjectType, ID, Field, HideField } from '@nestjs/graphql'; + +import { CreateDateColumn, UpdateDateColumn } from 'typeorm'; +import { + Authorize, + IDField, + QueryOptions, + Relation, +} from '@ptc-org/nestjs-query-graphql'; + +import { ObjectMetadataDTO } from 'src/metadata/object-metadata/dtos/object-metadata.dto'; + +export enum RelationType { + ONE_TO_ONE = 'ONE_TO_ONE', + ONE_TO_MANY = 'ONE_TO_MANY', + MANY_TO_MANY = 'MANY_TO_MANY', +} + +@ObjectType('relation') +@Authorize({ + authorize: (context: any) => ({ + workspaceId: { eq: context?.req?.user?.workspace?.id }, + }), +}) +@QueryOptions({ + defaultResultSize: 10, + disableFilter: true, + disableSort: true, + maxResultsSize: 1000, +}) +@Relation('fromObjectMetadata', () => ObjectMetadataDTO) +@Relation('toObjectMetadata', () => ObjectMetadataDTO) +export class RelationMetadataDTO { + @IDField(() => ID) + id: string; + + @Field() + relationType: RelationType; + + @Field() + fromObjectMetadataId: string; + + @Field() + toObjectMetadataId: string; + + @Field() + fromFieldMetadataId: string; + + @Field() + toFieldMetadataId: string; + + @HideField() + workspaceId: string; + + @Field() + @CreateDateColumn() + createdAt: Date; + + @Field() + @UpdateDateColumn() + updatedAt: Date; +} diff --git a/server/src/metadata/relation-metadata/relation-metadata.auto-resolver-opts.ts b/server/src/metadata/relation-metadata/relation-metadata.auto-resolver-opts.ts deleted file mode 100644 index c9e902321a..0000000000 --- a/server/src/metadata/relation-metadata/relation-metadata.auto-resolver-opts.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { - AutoResolverOpts, - PagingStrategies, - ReadResolverOpts, -} from '@ptc-org/nestjs-query-graphql'; - -import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; - -import { RelationMetadata } from './relation-metadata.entity'; - -import { RelationMetadataService } from './services/relation-metadata.service'; -import { CreateRelationInput } from './dtos/create-relation.input'; - -export const relationMetadataAutoResolverOpts: AutoResolverOpts< - any, - any, - unknown, - unknown, - ReadResolverOpts, - PagingStrategies ->[] = [ - { - EntityClass: RelationMetadata, - DTOClass: RelationMetadata, - ServiceClass: RelationMetadataService, - CreateDTOClass: CreateRelationInput, - enableTotalCount: true, - pagingStrategy: PagingStrategies.CURSOR, - read: { many: { disabled: true } }, - create: { many: { disabled: true } }, - update: { disabled: true }, - delete: { disabled: true }, - guards: [JwtAuthGuard], - }, -]; diff --git a/server/src/metadata/relation-metadata/relation-metadata.entity.ts b/server/src/metadata/relation-metadata/relation-metadata.entity.ts deleted file mode 100644 index 7e7e66ee85..0000000000 --- a/server/src/metadata/relation-metadata/relation-metadata.entity.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { ObjectType, ID, Field } from '@nestjs/graphql'; - -import { - Column, - CreateDateColumn, - Entity, - JoinColumn, - ManyToOne, - OneToOne, - PrimaryGeneratedColumn, - UpdateDateColumn, -} from 'typeorm'; -import { - Authorize, - IDField, - QueryOptions, - Relation, -} from '@ptc-org/nestjs-query-graphql'; - -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; -import { ObjectMetadata } from 'src/metadata/object-metadata/object-metadata.entity'; - -export enum RelationType { - ONE_TO_ONE = 'ONE_TO_ONE', - ONE_TO_MANY = 'ONE_TO_MANY', - MANY_TO_MANY = 'MANY_TO_MANY', -} - -@Entity('relationMetadata') -@ObjectType('relation') -@Authorize({ - authorize: (context: any) => ({ - workspaceId: { eq: context?.req?.user?.workspace?.id }, - }), -}) -@QueryOptions({ - defaultResultSize: 10, - disableFilter: true, - disableSort: true, - maxResultsSize: 1000, -}) -@Relation('fromObjectMetadata', () => ObjectMetadata) -@Relation('toObjectMetadata', () => ObjectMetadata) -export class RelationMetadata { - @IDField(() => ID) - @PrimaryGeneratedColumn('uuid') - id: string; - - @Field() - @Column({ nullable: false }) - relationType: RelationType; - - @Field() - @Column({ nullable: false, type: 'uuid' }) - fromObjectMetadataId: string; - - @Field() - @Column({ nullable: false, type: 'uuid' }) - toObjectMetadataId: string; - - @Field() - @Column({ nullable: false, type: 'uuid' }) - fromFieldMetadataId: string; - - @Field() - @Column({ nullable: false, type: 'uuid' }) - toFieldMetadataId: string; - - @Column({ nullable: false }) - workspaceId: string; - - @ManyToOne(() => ObjectMetadata, (object) => object.fromRelations) - fromObjectMetadata: ObjectMetadata; - - @ManyToOne(() => ObjectMetadata, (object) => object.toRelations) - toObjectMetadata: ObjectMetadata; - - @OneToOne(() => FieldMetadata, (field) => field.fromRelationMetadata) - @JoinColumn() - fromFieldMetadata: FieldMetadata; - - @OneToOne(() => FieldMetadata, (field) => field.toRelationMetadata) - @JoinColumn() - toFieldMetadata: FieldMetadata; - - @Field() - @CreateDateColumn() - createdAt: Date; - - @Field() - @UpdateDateColumn() - updatedAt: Date; -} diff --git a/server/src/metadata/relation-metadata/relation-metadata.module.ts b/server/src/metadata/relation-metadata/relation-metadata.module.ts index 1900be0ade..1759eab717 100644 --- a/server/src/metadata/relation-metadata/relation-metadata.module.ts +++ b/server/src/metadata/relation-metadata/relation-metadata.module.ts @@ -1,30 +1,52 @@ import { Module } from '@nestjs/common'; -import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql'; +import { + NestjsQueryGraphQLModule, + PagingStrategies, +} from '@ptc-org/nestjs-query-graphql'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; import { FieldMetadataModule } from 'src/metadata/field-metadata/field-metadata.module'; import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module'; -import { MigrationRunnerModule } from 'src/metadata/migration-runner/migration-runner.module'; +import { TenantMigrationRunnerModule } from 'src/tenant-migration-runner/tenant-migration-runner.module'; import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; +import { JwtAuthGuard } from 'src/guards/jwt.auth.guard'; +import { RelationMetadataEntity } from 'src/database/typeorm/metadata/entities/relation-metadata.entity'; -import { RelationMetadata } from './relation-metadata.entity'; -import { relationMetadataAutoResolverOpts } from './relation-metadata.auto-resolver-opts'; +import { RelationMetadataService } from './relation-metadata.service'; -import { RelationMetadataService } from './services/relation-metadata.service'; +import { CreateRelationInput } from './dtos/create-relation.input'; +import { RelationMetadataDTO } from './dtos/relation-metadata.dto'; @Module({ imports: [ NestjsQueryGraphQLModule.forFeature({ imports: [ - NestjsQueryTypeOrmModule.forFeature([RelationMetadata], 'metadata'), + NestjsQueryTypeOrmModule.forFeature( + [RelationMetadataEntity], + 'metadata', + ), ObjectMetadataModule, FieldMetadataModule, - MigrationRunnerModule, + TenantMigrationRunnerModule, TenantMigrationModule, ], services: [RelationMetadataService], - resolvers: relationMetadataAutoResolverOpts, + resolvers: [ + { + EntityClass: RelationMetadataEntity, + DTOClass: RelationMetadataDTO, + ServiceClass: RelationMetadataService, + CreateDTOClass: CreateRelationInput, + enableTotalCount: true, + pagingStrategy: PagingStrategies.CURSOR, + read: { many: { disabled: true } }, + create: { many: { disabled: true } }, + update: { disabled: true }, + delete: { disabled: true }, + guards: [JwtAuthGuard], + }, + ], }), ], providers: [RelationMetadataService], diff --git a/server/src/metadata/relation-metadata/services/relation-metadata.service.ts b/server/src/metadata/relation-metadata/relation-metadata.service.ts similarity index 84% rename from server/src/metadata/relation-metadata/services/relation-metadata.service.ts rename to server/src/metadata/relation-metadata/relation-metadata.service.ts index ebe108537d..53cfa19c14 100644 --- a/server/src/metadata/relation-metadata/services/relation-metadata.service.ts +++ b/server/src/metadata/relation-metadata/relation-metadata.service.ts @@ -8,34 +8,34 @@ import { InjectRepository } from '@nestjs/typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { Repository } from 'typeorm'; -import { - RelationMetadata, - RelationType, -} from 'src/metadata/relation-metadata/relation-metadata.entity'; -import { ObjectMetadataService } from 'src/metadata/object-metadata/services/object-metadata.service'; -import { FieldMetadataService } from 'src/metadata/field-metadata/services/field-metadata.service'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service'; +import { FieldMetadataService } from 'src/metadata/field-metadata/field-metadata.service'; import { CreateRelationInput } from 'src/metadata/relation-metadata/dtos/create-relation.input'; -import { MigrationRunnerService } from 'src/metadata/migration-runner/migration-runner.service'; +import { TenantMigrationRunnerService } from 'src/tenant-migration-runner/tenant-migration-runner.service'; import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; -import { TenantMigrationColumnActionType } from 'src/metadata/tenant-migration/tenant-migration.entity'; +import { + RelationMetadataEntity, + RelationType, +} from 'src/database/typeorm/metadata/entities/relation-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { TenantMigrationColumnActionType } from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; @Injectable() -export class RelationMetadataService extends TypeOrmQueryService { +export class RelationMetadataService extends TypeOrmQueryService { constructor( - @InjectRepository(RelationMetadata, 'metadata') - private readonly relationMetadataRepository: Repository, + @InjectRepository(RelationMetadataEntity, 'metadata') + private readonly relationMetadataRepository: Repository, private readonly objectMetadataService: ObjectMetadataService, private readonly fieldMetadataService: FieldMetadataService, private readonly tenantMigrationService: TenantMigrationService, - private readonly migrationRunnerService: MigrationRunnerService, + private readonly migrationRunnerService: TenantMigrationRunnerService, ) { super(relationMetadataRepository); } override async createOne( record: CreateRelationInput, - ): Promise { + ): Promise { if (record.relationType === RelationType.MANY_TO_MANY) { throw new BadRequestException( 'Many to many relations are not supported yet', @@ -72,7 +72,7 @@ export class RelationMetadataService extends TypeOrmQueryService { - acc[curr.objectId] = curr; + acc[curr.objectMetadataId] = curr; return acc; }, {}); diff --git a/server/src/metadata/tenant-initialisation/tenant-initialisation.service.ts b/server/src/metadata/tenant-initialisation/tenant-initialisation.service.ts deleted file mode 100644 index 31154e52bd..0000000000 --- a/server/src/metadata/tenant-initialisation/tenant-initialisation.service.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; -import { MigrationRunnerService } from 'src/metadata/migration-runner/migration-runner.service'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; -import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; -import { ObjectMetadataService } from 'src/metadata/object-metadata/services/object-metadata.service'; -import { DataSourceMetadata } from 'src/metadata/data-source-metadata/data-source-metadata.entity'; -import { FieldMetadataService } from 'src/metadata/field-metadata/services/field-metadata.service'; - -import { standardObjectsPrefillData } from './standard-objects-prefill-data/standard-objects-prefill-data'; - -@Injectable() -export class TenantInitialisationService { - constructor( - private readonly dataSourceService: DataSourceService, - private readonly tenantMigrationService: TenantMigrationService, - private readonly migrationRunnerService: MigrationRunnerService, - private readonly objectMetadataService: ObjectMetadataService, - private readonly fieldMetadataService: FieldMetadataService, - private readonly dataSourceMetadataService: DataSourceMetadataService, - ) {} - - /** - * Init a workspace by creating a new data source and running all migrations - * @param workspaceId - * @returns Promise - */ - public async init(workspaceId: string): Promise { - const schemaName = await this.dataSourceService.createWorkspaceSchema( - workspaceId, - ); - - const dataSourceMetadata = - await this.dataSourceMetadataService.createDataSourceMetadata( - workspaceId, - schemaName, - ); - - await this.tenantMigrationService.insertStandardMigrations(workspaceId); - - // Todo: keep in mind that we don't handle concurrency issues such as migrations being created at the same time - // but it shouldn't be the role of this service to handle this kind of issues for now. - // To check later when we run this in a job. - await this.migrationRunnerService.executeMigrationFromPendingMigrations( - workspaceId, - ); - - await this.objectMetadataService.createStandardObjectsAndFieldsMetadata( - dataSourceMetadata.id, - workspaceId, - ); - - await this.prefillWorkspaceWithStandardObjects( - dataSourceMetadata, - workspaceId, - ); - } - - /** - * - * We are prefilling a few standard objects with data to make it easier for the user to get started. - * - * @param dataSourceMetadata - * @param workspaceId - */ - private async prefillWorkspaceWithStandardObjects( - dataSourceMetadata: DataSourceMetadata, - workspaceId: string, - ) { - const workspaceDataSource = - await this.dataSourceService.connectToWorkspaceDataSource(workspaceId); - - if (!workspaceDataSource) { - throw new Error('Could not connect to workspace data source'); - } - - standardObjectsPrefillData(workspaceDataSource, dataSourceMetadata.schema); - } - - public async delete(workspaceId: string): Promise { - // Delete data from metadata tables - await this.fieldMetadataService.deleteFieldsMetadata(workspaceId); - await this.objectMetadataService.deleteObjectsMetadata(workspaceId); - await this.tenantMigrationService.delete(workspaceId); - await this.dataSourceMetadataService.delete(workspaceId); - // Delete schema - await this.dataSourceService.deleteWorkspaceSchema(workspaceId); - } -} diff --git a/server/src/metadata/tenant-migration/migrations/1697618009-addCompanyTable.ts b/server/src/metadata/tenant-migration/migrations/1697618009-addCompanyTable.ts index 4039d58dcb..34af4615fd 100644 --- a/server/src/metadata/tenant-migration/migrations/1697618009-addCompanyTable.ts +++ b/server/src/metadata/tenant-migration/migrations/1697618009-addCompanyTable.ts @@ -1,7 +1,7 @@ import { - TenantMigrationColumnActionType, TenantMigrationTableAction, -} from 'src/metadata/tenant-migration/tenant-migration.entity'; + TenantMigrationColumnActionType, +} from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; export const addCompanyTable: TenantMigrationTableAction[] = [ { diff --git a/server/src/metadata/tenant-migration/migrations/1697618011-addViewTable.ts b/server/src/metadata/tenant-migration/migrations/1697618011-addViewTable.ts index 60570a89ff..406b21882e 100644 --- a/server/src/metadata/tenant-migration/migrations/1697618011-addViewTable.ts +++ b/server/src/metadata/tenant-migration/migrations/1697618011-addViewTable.ts @@ -1,7 +1,7 @@ import { - TenantMigrationColumnActionType, TenantMigrationTableAction, -} from 'src/metadata/tenant-migration/tenant-migration.entity'; + TenantMigrationColumnActionType, +} from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; export const addViewTable: TenantMigrationTableAction[] = [ { @@ -18,7 +18,7 @@ export const addViewTable: TenantMigrationTableAction[] = [ action: TenantMigrationColumnActionType.CREATE, }, { - columnName: 'objectId', + columnName: 'objectMetadataId', columnType: 'varchar', action: TenantMigrationColumnActionType.CREATE, }, diff --git a/server/src/metadata/tenant-migration/migrations/1697618012-addViewFieldTable.ts b/server/src/metadata/tenant-migration/migrations/1697618012-addViewFieldTable.ts index b479d929d7..1e0f311c06 100644 --- a/server/src/metadata/tenant-migration/migrations/1697618012-addViewFieldTable.ts +++ b/server/src/metadata/tenant-migration/migrations/1697618012-addViewFieldTable.ts @@ -1,7 +1,7 @@ import { - TenantMigrationColumnActionType, TenantMigrationTableAction, -} from 'src/metadata/tenant-migration/tenant-migration.entity'; + TenantMigrationColumnActionType, +} from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; export const addViewFieldTable: TenantMigrationTableAction[] = [ { @@ -13,7 +13,7 @@ export const addViewFieldTable: TenantMigrationTableAction[] = [ action: 'alter', columns: [ { - columnName: 'fieldId', + columnName: 'fieldMetadataId', columnType: 'varchar', action: TenantMigrationColumnActionType.CREATE, }, diff --git a/server/src/metadata/tenant-migration/migrations/1697618013-addViewFilterTable.ts b/server/src/metadata/tenant-migration/migrations/1697618013-addViewFilterTable.ts index 7ff19c319e..2e1d1d394e 100644 --- a/server/src/metadata/tenant-migration/migrations/1697618013-addViewFilterTable.ts +++ b/server/src/metadata/tenant-migration/migrations/1697618013-addViewFilterTable.ts @@ -1,7 +1,7 @@ import { - TenantMigrationColumnActionType, TenantMigrationTableAction, -} from 'src/metadata/tenant-migration/tenant-migration.entity'; + TenantMigrationColumnActionType, +} from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; export const addViewFilterTable: TenantMigrationTableAction[] = [ { @@ -13,7 +13,7 @@ export const addViewFilterTable: TenantMigrationTableAction[] = [ action: 'alter', columns: [ { - columnName: 'fieldId', + columnName: 'fieldMetadataId', columnType: 'varchar', action: TenantMigrationColumnActionType.CREATE, }, diff --git a/server/src/metadata/tenant-migration/migrations/1697618014-addViewSortTable.ts b/server/src/metadata/tenant-migration/migrations/1697618014-addViewSortTable.ts index 1bb4307c91..9bd7be2109 100644 --- a/server/src/metadata/tenant-migration/migrations/1697618014-addViewSortTable.ts +++ b/server/src/metadata/tenant-migration/migrations/1697618014-addViewSortTable.ts @@ -1,7 +1,7 @@ import { - TenantMigrationColumnActionType, TenantMigrationTableAction, -} from 'src/metadata/tenant-migration/tenant-migration.entity'; + TenantMigrationColumnActionType, +} from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; export const addViewSortTable: TenantMigrationTableAction[] = [ { @@ -13,7 +13,7 @@ export const addViewSortTable: TenantMigrationTableAction[] = [ action: 'alter', columns: [ { - columnName: 'fieldId', + columnName: 'fieldMetadataId', columnType: 'varchar', action: TenantMigrationColumnActionType.CREATE, }, diff --git a/server/src/metadata/tenant-migration/tenant-migration.module.ts b/server/src/metadata/tenant-migration/tenant-migration.module.ts index 4bd73b39ad..758bcfeafe 100644 --- a/server/src/metadata/tenant-migration/tenant-migration.module.ts +++ b/server/src/metadata/tenant-migration/tenant-migration.module.ts @@ -1,11 +1,12 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { TenantMigrationEntity } from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; + import { TenantMigrationService } from './tenant-migration.service'; -import { TenantMigration } from './tenant-migration.entity'; @Module({ - imports: [TypeOrmModule.forFeature([TenantMigration], 'metadata')], + imports: [TypeOrmModule.forFeature([TenantMigrationEntity], 'metadata')], exports: [TenantMigrationService], providers: [TenantMigrationService], }) diff --git a/server/src/metadata/tenant-migration/tenant-migration.service.spec.ts b/server/src/metadata/tenant-migration/tenant-migration.service.spec.ts deleted file mode 100644 index 371fbdbadc..0000000000 --- a/server/src/metadata/tenant-migration/tenant-migration.service.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { getRepositoryToken } from '@nestjs/typeorm'; - -import { TenantMigrationService } from './tenant-migration.service'; -import { TenantMigration } from './tenant-migration.entity'; - -describe('TenantMigrationService', () => { - let service: TenantMigrationService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - TenantMigrationService, - { - provide: getRepositoryToken(TenantMigration, 'metadata'), - useValue: {}, - }, - ], - }).compile(); - - service = module.get(TenantMigrationService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/server/src/metadata/tenant-migration/tenant-migration.service.ts b/server/src/metadata/tenant-migration/tenant-migration.service.ts index aa8af710aa..9e252cec94 100644 --- a/server/src/metadata/tenant-migration/tenant-migration.service.ts +++ b/server/src/metadata/tenant-migration/tenant-migration.service.ts @@ -4,16 +4,17 @@ import { InjectRepository } from '@nestjs/typeorm'; import { IsNull, Repository } from 'typeorm'; import { - TenantMigration, + TenantMigrationEntity, TenantMigrationTableAction, -} from './tenant-migration.entity'; +} from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; + import { standardMigrations } from './standard-migrations'; @Injectable() export class TenantMigrationService { constructor( - @InjectRepository(TenantMigration, 'metadata') - private readonly tenantMigrationRepository: Repository, + @InjectRepository(TenantMigrationEntity, 'metadata') + private readonly tenantMigrationRepository: Repository, ) {} /** @@ -60,7 +61,7 @@ export class TenantMigrationService { */ public async getPendingMigrations( workspaceId: string, - ): Promise { + ): Promise { return await this.tenantMigrationRepository.find({ order: { createdAt: 'ASC' }, where: { @@ -79,7 +80,7 @@ export class TenantMigrationService { */ public async setAppliedAtForMigration( workspaceId: string, - migration: TenantMigration, + migration: TenantMigrationEntity, ) { await this.tenantMigrationRepository.save({ id: migration.id, diff --git a/server/src/tenant-datasource/tenant-datasource.module.ts b/server/src/tenant-datasource/tenant-datasource.module.ts new file mode 100644 index 0000000000..514f3d5d5e --- /dev/null +++ b/server/src/tenant-datasource/tenant-datasource.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; + +import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; +import { DataSourceMetadataModule } from 'src/metadata/data-source-metadata/data-source-metadata.module'; + +import { TenantDataSourceService } from './tenant-datasource.service'; + +@Module({ + imports: [DataSourceMetadataModule, TypeORMModule], + exports: [TenantDataSourceService], + providers: [TenantDataSourceService], +}) +export class TenantDataSourceModule {} diff --git a/server/src/tenant-datasource/tenant-datasource.service.ts b/server/src/tenant-datasource/tenant-datasource.service.ts new file mode 100644 index 0000000000..4e2428d7cd --- /dev/null +++ b/server/src/tenant-datasource/tenant-datasource.service.ts @@ -0,0 +1,101 @@ +import { Injectable } from '@nestjs/common'; + +import { DataSource } from 'typeorm'; + +import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; +import { TypeORMService } from 'src/database/typeorm/typeorm.service'; + +@Injectable() +export class TenantDataSourceService { + constructor( + private readonly dataSourceMetadataService: DataSourceMetadataService, + private readonly typeormService: TypeORMService, + ) {} + + /** + * + * Connect to the workspace data source + * + * @param workspaceId + * @returns + */ + public async connectToWorkspaceDataSource( + workspaceId: string, + ): Promise { + const dataSourceMetadata = + await this.dataSourceMetadataService.getLastDataSourceMetadataFromWorkspaceIdOrFail( + workspaceId, + ); + + const dataSource = await this.typeormService.connectToDataSource( + dataSourceMetadata, + ); + + if (!dataSource) { + throw new Error( + `Could not connect to workspace data source for workspace ${workspaceId}`, + ); + } + + return dataSource; + } + + /** + * + * Create a new DB schema for a workspace + * + * @param workspaceId + * @returns + */ + public async createWorkspaceDBSchema(workspaceId: string): Promise { + const schemaName = this.getSchemaName(workspaceId); + + return await this.typeormService.createSchema(schemaName); + } + + /** + * + * Delete a DB schema for a workspace + * + * @param workspaceId + * @returns + */ + public async deleteWorkspaceDBSchema(workspaceId: string): Promise { + const schemaName = this.getSchemaName(workspaceId); + + return await this.typeormService.deleteSchema(schemaName); + } + + /** + * + * Get the schema name for a workspace + * + * @param workspaceId + * @returns string + */ + public getSchemaName(workspaceId: string): string { + return `workspace_${this.uuidToBase36(workspaceId)}`; + } + + /** + * + * Convert a uuid to base36 + * + * @param uuid + * @returns string + */ + private uuidToBase36(uuid: string): string { + let devId = false; + + if (uuid.startsWith('twenty-')) { + devId = true; + // Clean dev uuids (twenty-) + uuid = uuid.replace('twenty-', ''); + } + const hexString = uuid.replace(/-/g, ''); + const base10Number = BigInt('0x' + hexString); + const base36String = base10Number.toString(36); + + return `${devId ? 'twenty_' : ''}${base36String}`; + } +} diff --git a/server/src/metadata/commands/sync-tenant-metadata.command.ts b/server/src/tenant-manager/commands/sync-tenant-metadata.command.ts similarity index 77% rename from server/src/metadata/commands/sync-tenant-metadata.command.ts rename to server/src/tenant-manager/commands/sync-tenant-metadata.command.ts index ffa299d275..f489d47a29 100644 --- a/server/src/metadata/commands/sync-tenant-metadata.command.ts +++ b/server/src/tenant-manager/commands/sync-tenant-metadata.command.ts @@ -1,7 +1,7 @@ import { Command, CommandRunner, Option } from 'nest-commander'; -import { ObjectMetadataService } from 'src/metadata/object-metadata/services/object-metadata.service'; import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; +import { TenantManagerService } from 'src/tenant-manager/tenant-manager.service'; // TODO: implement dry-run interface RunTenantMigrationsOptions { @@ -14,7 +14,7 @@ interface RunTenantMigrationsOptions { }) export class SyncTenantMetadataCommand extends CommandRunner { constructor( - private readonly objectMetadataService: ObjectMetadataService, + private readonly tenantManagerService: TenantManagerService, private readonly dataSourceMetadataService: DataSourceMetadataService, ) { super(); @@ -31,11 +31,7 @@ export class SyncTenantMetadataCommand extends CommandRunner { ); // TODO: This solution could be improved, using a diff for example, we should not have to delete all metadata and recreate them. - await this.objectMetadataService.deleteMany({ - workspaceId: { eq: options.workspaceId }, - }); - - await this.objectMetadataService.createStandardObjectsAndFieldsMetadata( + await this.tenantManagerService.resetStandardObjectsAndFieldsMetadata( dataSourceMetadata.id, options.workspaceId, ); diff --git a/server/src/tenant-manager/commands/tenant-manager-commands.module.ts b/server/src/tenant-manager/commands/tenant-manager-commands.module.ts new file mode 100644 index 0000000000..fed8cd2ac5 --- /dev/null +++ b/server/src/tenant-manager/commands/tenant-manager-commands.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; + +import { TenantManagerModule } from 'src/tenant-manager/tenant-manager.module'; +import { DataSourceMetadataModule } from 'src/metadata/data-source-metadata/data-source-metadata.module'; + +import { SyncTenantMetadataCommand } from './sync-tenant-metadata.command'; + +@Module({ + imports: [TenantManagerModule, DataSourceMetadataModule], + providers: [SyncTenantMetadataCommand], +}) +export class TenantManagerCommandsModule {} diff --git a/server/src/metadata/standard-objects/companies/companies.metadata.ts b/server/src/tenant-manager/standard-objects-metadata/companies/companies.metadata.ts similarity index 100% rename from server/src/metadata/standard-objects/companies/companies.metadata.ts rename to server/src/tenant-manager/standard-objects-metadata/companies/companies.metadata.ts diff --git a/server/src/metadata/standard-objects/standard-object-metadata.ts b/server/src/tenant-manager/standard-objects-metadata/standard-object-metadata.ts similarity index 100% rename from server/src/metadata/standard-objects/standard-object-metadata.ts rename to server/src/tenant-manager/standard-objects-metadata/standard-object-metadata.ts diff --git a/server/src/metadata/standard-objects/view-fields/view-fields.metadata.ts b/server/src/tenant-manager/standard-objects-metadata/view-fields/view-fields.metadata.ts similarity index 95% rename from server/src/metadata/standard-objects/view-fields/view-fields.metadata.ts rename to server/src/tenant-manager/standard-objects-metadata/view-fields/view-fields.metadata.ts index 0995fc24f6..fecd270e46 100644 --- a/server/src/metadata/standard-objects/view-fields/view-fields.metadata.ts +++ b/server/src/tenant-manager/standard-objects-metadata/view-fields/view-fields.metadata.ts @@ -9,10 +9,10 @@ const viewFieldsMetadata = { fields: [ { type: 'TEXT', - name: 'fieldId', + name: 'fieldMetadataId', label: 'Field Id', targetColumnMap: { - value: 'fieldId', + value: 'fieldMetadataId', }, description: 'View Field target field', icon: null, diff --git a/server/src/metadata/standard-objects/view-filters/view-filters.metadata.ts b/server/src/tenant-manager/standard-objects-metadata/view-filters/view-filters.metadata.ts similarity index 95% rename from server/src/metadata/standard-objects/view-filters/view-filters.metadata.ts rename to server/src/tenant-manager/standard-objects-metadata/view-filters/view-filters.metadata.ts index 8fa165fd40..8ee351c41d 100644 --- a/server/src/metadata/standard-objects/view-filters/view-filters.metadata.ts +++ b/server/src/tenant-manager/standard-objects-metadata/view-filters/view-filters.metadata.ts @@ -9,10 +9,10 @@ const viewFiltersMetadata = { fields: [ { type: 'TEXT', - name: 'fieldId', + name: 'fieldMetadataId', label: 'Field Id', targetColumnMap: { - value: 'fieldId', + value: 'fieldMetadataId', }, description: 'View Filter target field', icon: null, diff --git a/server/src/metadata/standard-objects/view-sorts/view-sorts.metadata.ts b/server/src/tenant-manager/standard-objects-metadata/view-sorts/view-sorts.metadata.ts similarity index 93% rename from server/src/metadata/standard-objects/view-sorts/view-sorts.metadata.ts rename to server/src/tenant-manager/standard-objects-metadata/view-sorts/view-sorts.metadata.ts index eb08b3921e..596a6b3513 100644 --- a/server/src/metadata/standard-objects/view-sorts/view-sorts.metadata.ts +++ b/server/src/tenant-manager/standard-objects-metadata/view-sorts/view-sorts.metadata.ts @@ -9,10 +9,10 @@ const viewSortsMetadata = { fields: [ { type: 'TEXT', - name: 'fieldId', + name: 'fieldMetadataId', label: 'Field Id', targetColumnMap: { - value: 'fieldId', + value: 'fieldMetadataId', }, description: 'View Sort target field', icon: null, diff --git a/server/src/metadata/standard-objects/views/views.metadata.ts b/server/src/tenant-manager/standard-objects-metadata/views/views.metadata.ts similarity index 92% rename from server/src/metadata/standard-objects/views/views.metadata.ts rename to server/src/tenant-manager/standard-objects-metadata/views/views.metadata.ts index 82dd3ac6fc..c03d148169 100644 --- a/server/src/metadata/standard-objects/views/views.metadata.ts +++ b/server/src/tenant-manager/standard-objects-metadata/views/views.metadata.ts @@ -20,10 +20,10 @@ const viewsMetadata = { }, { type: 'TEXT', - name: 'objectId', + name: 'objectMetadataId', label: 'Object Id', targetColumnMap: { - value: 'objectId', + value: 'objectMetadataId', }, description: 'View target object', icon: null, diff --git a/server/src/metadata/tenant-initialisation/standard-objects-prefill-data/standard-objects-prefill-data.ts b/server/src/tenant-manager/standard-objects-prefill-data/standard-objects-prefill-data.ts similarity index 82% rename from server/src/metadata/tenant-initialisation/standard-objects-prefill-data/standard-objects-prefill-data.ts rename to server/src/tenant-manager/standard-objects-prefill-data/standard-objects-prefill-data.ts index 10e2929853..2fcca6d855 100644 --- a/server/src/metadata/tenant-initialisation/standard-objects-prefill-data/standard-objects-prefill-data.ts +++ b/server/src/tenant-manager/standard-objects-prefill-data/standard-objects-prefill-data.ts @@ -58,27 +58,27 @@ export const standardObjectsPrefillData = async ( const createdViews = await entityManager .createQueryBuilder() .insert() - .into(`${schemaName}.view`, ['name', 'objectId', 'type']) + .into(`${schemaName}.view`, ['name', 'objectMetadataId', 'type']) .orIgnore() .values([ { name: 'All companies', - objectId: 'company', + objectMetadataId: 'company', type: 'table', }, { name: 'All people', - objectId: 'person', + objectMetadataId: 'person', type: 'table', }, { name: 'All opportunities', - objectId: 'company', + objectMetadataId: 'company', type: 'kanban', }, { name: 'All Companies (V2)', - objectId: companyIdMap['Airbnb'], + objectMetadataId: companyIdMap['Airbnb'], type: 'table', }, ]) @@ -94,7 +94,7 @@ export const standardObjectsPrefillData = async ( .createQueryBuilder() .insert() .into(`${schemaName}.viewField`, [ - 'fieldId', + 'fieldMetadataId', 'viewId', 'position', 'isVisible', @@ -103,161 +103,161 @@ export const standardObjectsPrefillData = async ( .orIgnore() .values([ { - fieldId: 'name', + fieldMetadataId: 'name', viewId: viewIdMap['All Companies (V2)'], position: 0, isVisible: true, size: 180, }, { - fieldId: 'name', + fieldMetadataId: 'name', viewId: viewIdMap['All companies'], position: 0, isVisible: true, size: 180, }, { - fieldId: 'domainName', + fieldMetadataId: 'domainName', viewId: viewIdMap['All companies'], position: 1, isVisible: true, size: 100, }, { - fieldId: 'accountOwner', + fieldMetadataId: 'accountOwner', viewId: viewIdMap['All companies'], position: 2, isVisible: true, size: 150, }, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', viewId: viewIdMap['All companies'], position: 3, isVisible: true, size: 150, }, { - fieldId: 'employees', + fieldMetadataId: 'employees', viewId: viewIdMap['All companies'], position: 4, isVisible: true, size: 150, }, { - fieldId: 'linkedin', + fieldMetadataId: 'linkedin', viewId: viewIdMap['All companies'], position: 5, isVisible: true, size: 170, }, { - fieldId: 'address', + fieldMetadataId: 'address', viewId: viewIdMap['All companies'], position: 6, isVisible: true, size: 170, }, { - fieldId: 'displayName', + fieldMetadataId: 'displayName', viewId: viewIdMap['All people'], position: 0, isVisible: true, size: 210, }, { - fieldId: 'email', + fieldMetadataId: 'email', viewId: viewIdMap['All people'], position: 1, isVisible: true, size: 150, }, { - fieldId: 'company', + fieldMetadataId: 'company', viewId: viewIdMap['All people'], position: 2, isVisible: true, size: 150, }, { - fieldId: 'phone', + fieldMetadataId: 'phone', viewId: viewIdMap['All people'], position: 3, isVisible: true, size: 150, }, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', viewId: viewIdMap['All people'], position: 4, isVisible: true, size: 150, }, { - fieldId: 'city', + fieldMetadataId: 'city', viewId: viewIdMap['All people'], position: 5, isVisible: true, size: 150, }, { - fieldId: 'jobTitle', + fieldMetadataId: 'jobTitle', viewId: viewIdMap['All people'], position: 6, isVisible: true, size: 150, }, { - fieldId: 'linkedin', + fieldMetadataId: 'linkedin', viewId: viewIdMap['All people'], position: 7, isVisible: true, size: 150, }, { - fieldId: 'x', + fieldMetadataId: 'x', viewId: viewIdMap['All people'], position: 8, isVisible: true, size: 150, }, { - fieldId: 'amount', + fieldMetadataId: 'amount', viewId: viewIdMap['All opportunities'], position: 0, isVisible: true, size: 180, }, { - fieldId: 'probability', + fieldMetadataId: 'probability', viewId: viewIdMap['All opportunities'], position: 1, isVisible: true, size: 150, }, { - fieldId: 'closeDate', + fieldMetadataId: 'closeDate', viewId: viewIdMap['All opportunities'], position: 2, isVisible: true, size: 100, }, { - fieldId: 'company', + fieldMetadataId: 'company', viewId: viewIdMap['All opportunities'], position: 3, isVisible: true, size: 150, }, { - fieldId: 'createdAt', + fieldMetadataId: 'createdAt', viewId: viewIdMap['All opportunities'], position: 4, isVisible: true, size: 150, }, { - fieldId: 'pointOfContact', + fieldMetadataId: 'pointOfContact', viewId: viewIdMap['All opportunities'], position: 5, isVisible: true, diff --git a/server/src/metadata/tenant-initialisation/tenant-initialisation.module.ts b/server/src/tenant-manager/tenant-manager.module.ts similarity index 56% rename from server/src/metadata/tenant-initialisation/tenant-initialisation.module.ts rename to server/src/tenant-manager/tenant-manager.module.ts index 07d8d0f735..de6bc167f9 100644 --- a/server/src/metadata/tenant-initialisation/tenant-initialisation.module.ts +++ b/server/src/tenant-manager/tenant-manager.module.ts @@ -1,24 +1,24 @@ import { Module } from '@nestjs/common'; -import { DataSourceModule } from 'src/metadata/data-source/data-source.module'; -import { MigrationRunnerModule } from 'src/metadata/migration-runner/migration-runner.module'; -import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; import { DataSourceMetadataModule } from 'src/metadata/data-source-metadata/data-source-metadata.module'; -import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module'; import { FieldMetadataModule } from 'src/metadata/field-metadata/field-metadata.module'; +import { ObjectMetadataModule } from 'src/metadata/object-metadata/object-metadata.module'; +import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; +import { TenantDataSourceModule } from 'src/tenant-datasource/tenant-datasource.module'; +import { TenantMigrationRunnerModule } from 'src/tenant-migration-runner/tenant-migration-runner.module'; -import { TenantInitialisationService } from './tenant-initialisation.service'; +import { TenantManagerService } from './tenant-manager.service'; @Module({ imports: [ - DataSourceModule, + TenantDataSourceModule, TenantMigrationModule, - MigrationRunnerModule, + TenantMigrationRunnerModule, ObjectMetadataModule, FieldMetadataModule, DataSourceMetadataModule, ], - exports: [TenantInitialisationService], - providers: [TenantInitialisationService], + exports: [TenantManagerService], + providers: [TenantManagerService], }) -export class TenantInitialisationModule {} +export class TenantManagerModule {} diff --git a/server/src/tenant-manager/tenant-manager.service.ts b/server/src/tenant-manager/tenant-manager.service.ts new file mode 100644 index 0000000000..ea5732f832 --- /dev/null +++ b/server/src/tenant-manager/tenant-manager.service.ts @@ -0,0 +1,143 @@ +import { Injectable } from '@nestjs/common'; + +import { DataSourceEntity } from 'src/database/typeorm/metadata/entities/data-source.entity'; +import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; +import { FieldMetadataService } from 'src/metadata/field-metadata/field-metadata.service'; +import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service'; +import { TenantMigrationRunnerService } from 'src/tenant-migration-runner/tenant-migration-runner.service'; +import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; +import { standardObjectsPrefillData } from 'src/tenant-manager/standard-objects-prefill-data/standard-objects-prefill-data'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; +import { standardObjectsMetadata } from 'src/tenant-manager/standard-objects-metadata/standard-object-metadata'; + +@Injectable() +export class TenantManagerService { + constructor( + private readonly tenantDataSourceService: TenantDataSourceService, + private readonly tenantMigrationService: TenantMigrationService, + private readonly migrationRunnerService: TenantMigrationRunnerService, + private readonly objectMetadataService: ObjectMetadataService, + private readonly fieldMetadataService: FieldMetadataService, + private readonly dataSourceMetadataService: DataSourceMetadataService, + ) {} + + /** + * Init a workspace by creating a new data source and running all migrations + * @param workspaceId + * @returns Promise + */ + public async init(workspaceId: string): Promise { + const schemaName = + await this.tenantDataSourceService.createWorkspaceDBSchema(workspaceId); + + const dataSourceMetadata = + await this.dataSourceMetadataService.createDataSourceMetadata( + workspaceId, + schemaName, + ); + + await this.tenantMigrationService.insertStandardMigrations(workspaceId); + + await this.migrationRunnerService.executeMigrationFromPendingMigrations( + workspaceId, + ); + + await this.createStandardObjectsAndFieldsMetadata( + dataSourceMetadata.id, + workspaceId, + ); + + await this.prefillWorkspaceWithStandardObjects( + dataSourceMetadata, + workspaceId, + ); + } + + /** + * + * Create all standard objects and fields metadata for a given workspace + * + * @param dataSourceId + * @param workspaceId + */ + public async createStandardObjectsAndFieldsMetadata( + dataSourceId: string, + workspaceId: string, + ) { + await this.objectMetadataService.createMany( + Object.values(standardObjectsMetadata).map((objectMetadata) => ({ + ...objectMetadata, + dataSourceId, + workspaceId, + isCustom: false, + isActive: true, + fields: objectMetadata.fields.map((field) => ({ + ...field, + workspaceId, + isCustom: false, + isActive: true, + })), + })), + ); + } + + /** + * + * Reset all standard objects and fields metadata for a given workspace + * + * @param dataSourceId + * @param workspaceId + */ + public async resetStandardObjectsAndFieldsMetadata( + dataSourceId: string, + workspaceId: string, + ) { + await this.objectMetadataService.deleteMany({ + workspaceId: { eq: workspaceId }, + }); + + await this.createStandardObjectsAndFieldsMetadata( + dataSourceId, + workspaceId, + ); + } + + /** + * + * We are prefilling a few standard objects with data to make it easier for the user to get started. + * + * @param dataSourceMetadata + * @param workspaceId + */ + private async prefillWorkspaceWithStandardObjects( + dataSourceMetadata: DataSourceEntity, + workspaceId: string, + ) { + const workspaceDataSource = + await this.tenantDataSourceService.connectToWorkspaceDataSource( + workspaceId, + ); + + if (!workspaceDataSource) { + throw new Error('Could not connect to workspace data source'); + } + + standardObjectsPrefillData(workspaceDataSource, dataSourceMetadata.schema); + } + + /** + * + * Delete a workspace by deleting all metadata and the schema + * + * @param workspaceId + */ + public async delete(workspaceId: string): Promise { + // Delete data from metadata tables + await this.fieldMetadataService.deleteFieldsMetadata(workspaceId); + await this.objectMetadataService.deleteObjectsMetadata(workspaceId); + await this.tenantMigrationService.delete(workspaceId); + await this.dataSourceMetadataService.delete(workspaceId); + // Delete schema + await this.tenantDataSourceService.deleteWorkspaceDBSchema(workspaceId); + } +} diff --git a/server/src/metadata/commands/run-tenant-migrations.command.ts b/server/src/tenant-migration-runner/commands/run-tenant-migrations.command.ts similarity index 80% rename from server/src/metadata/commands/run-tenant-migrations.command.ts rename to server/src/tenant-migration-runner/commands/run-tenant-migrations.command.ts index 557a235746..89ec659cae 100644 --- a/server/src/metadata/commands/run-tenant-migrations.command.ts +++ b/server/src/tenant-migration-runner/commands/run-tenant-migrations.command.ts @@ -1,7 +1,7 @@ import { Command, CommandRunner, Option } from 'nest-commander'; import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; -import { MigrationRunnerService } from 'src/metadata/migration-runner/migration-runner.service'; +import { TenantMigrationRunnerService } from 'src/tenant-migration-runner/tenant-migration-runner.service'; // TODO: implement dry-run interface RunTenantMigrationsOptions { @@ -15,7 +15,7 @@ interface RunTenantMigrationsOptions { export class RunTenantMigrationsCommand extends CommandRunner { constructor( private readonly tenantMigrationService: TenantMigrationService, - private readonly migrationRunnerService: MigrationRunnerService, + private readonly tenantMigrationRunnerService: TenantMigrationRunnerService, ) { super(); } @@ -28,7 +28,7 @@ export class RunTenantMigrationsCommand extends CommandRunner { await this.tenantMigrationService.insertStandardMigrations( options.workspaceId, ); - await this.migrationRunnerService.executeMigrationFromPendingMigrations( + await this.tenantMigrationRunnerService.executeMigrationFromPendingMigrations( options.workspaceId, ); } diff --git a/server/src/tenant-migration-runner/commands/tenant-migration-runner-commands.module.ts b/server/src/tenant-migration-runner/commands/tenant-migration-runner-commands.module.ts new file mode 100644 index 0000000000..dff01df6d3 --- /dev/null +++ b/server/src/tenant-migration-runner/commands/tenant-migration-runner-commands.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; + +import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; +import { TenantMigrationRunnerModule } from 'src/tenant-migration-runner/tenant-migration-runner.module'; + +import { RunTenantMigrationsCommand } from './run-tenant-migrations.command'; + +@Module({ + imports: [TenantMigrationModule, TenantMigrationRunnerModule], + providers: [RunTenantMigrationsCommand], +}) +export class TenantMigrationRunnerCommandsModule {} diff --git a/server/src/tenant-migration-runner/tenant-migration-runner.module.ts b/server/src/tenant-migration-runner/tenant-migration-runner.module.ts new file mode 100644 index 0000000000..a96340cf38 --- /dev/null +++ b/server/src/tenant-migration-runner/tenant-migration-runner.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; + +import { TenantMigrationModule } from 'src/metadata/tenant-migration/tenant-migration.module'; +import { TenantDataSourceModule } from 'src/tenant-datasource/tenant-datasource.module'; + +import { TenantMigrationRunnerService } from './tenant-migration-runner.service'; + +@Module({ + imports: [TenantDataSourceModule, TenantMigrationModule], + exports: [TenantMigrationRunnerService], + providers: [TenantMigrationRunnerService], +}) +export class TenantMigrationRunnerModule {} diff --git a/server/src/metadata/migration-runner/migration-runner.service.ts b/server/src/tenant-migration-runner/tenant-migration-runner.service.ts similarity index 91% rename from server/src/metadata/migration-runner/migration-runner.service.ts rename to server/src/tenant-migration-runner/tenant-migration-runner.service.ts index ca21931038..b0517b205e 100644 --- a/server/src/metadata/migration-runner/migration-runner.service.ts +++ b/server/src/tenant-migration-runner/tenant-migration-runner.service.ts @@ -2,22 +2,22 @@ import { Injectable } from '@nestjs/common'; import { QueryRunner, Table, TableColumn, TableForeignKey } from 'typeorm'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; +import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; import { TenantMigrationTableAction, TenantMigrationColumnAction, + TenantMigrationColumnActionType, TenantMigrationColumnCreate, TenantMigrationColumnRelation, - TenantMigrationColumnActionType, -} from 'src/metadata/tenant-migration/tenant-migration.entity'; -import { TenantMigrationService } from 'src/metadata/tenant-migration/tenant-migration.service'; +} from 'src/database/typeorm/metadata/entities/tenant-migration.entity'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; -import { customTableDefaultColumns } from './custom-table-default-column.util'; +import { customTableDefaultColumns } from './utils/custom-table-default-column.util'; @Injectable() -export class MigrationRunnerService { +export class TenantMigrationRunnerService { constructor( - private readonly dataSourceService: DataSourceService, + private readonly tenantDataSourceService: TenantDataSourceService, private readonly tenantMigrationService: TenantMigrationService, ) {} @@ -31,7 +31,9 @@ export class MigrationRunnerService { workspaceId: string, ): Promise { const workspaceDataSource = - await this.dataSourceService.connectToWorkspaceDataSource(workspaceId); + await this.tenantDataSourceService.connectToWorkspaceDataSource( + workspaceId, + ); if (!workspaceDataSource) { throw new Error('Workspace data source not found'); @@ -50,7 +52,7 @@ export class MigrationRunnerService { }, []); const queryRunner = workspaceDataSource?.createQueryRunner(); - const schemaName = this.dataSourceService.getSchemaName(workspaceId); + const schemaName = this.tenantDataSourceService.getSchemaName(workspaceId); // Loop over each migration and create or update the table // TODO: Should be done in a transaction diff --git a/server/src/metadata/migration-runner/custom-table-default-column.util.ts b/server/src/tenant-migration-runner/utils/custom-table-default-column.util.ts similarity index 100% rename from server/src/metadata/migration-runner/custom-table-default-column.util.ts rename to server/src/tenant-migration-runner/utils/custom-table-default-column.util.ts diff --git a/server/src/tenant/resolver-builder/factories/create-many-resolver.factory.ts b/server/src/tenant/resolver-builder/factories/create-many-resolver.factory.ts index 78a432270d..cda2dc788c 100644 --- a/server/src/tenant/resolver-builder/factories/create-many-resolver.factory.ts +++ b/server/src/tenant/resolver-builder/factories/create-many-resolver.factory.ts @@ -7,8 +7,8 @@ import { import { SchemaBuilderContext } from 'src/tenant/schema-builder/interfaces/schema-builder-context.interface'; import { ResolverBuilderFactoryInterface } from 'src/tenant/resolver-builder/interfaces/resolver-builder-factory.interface'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; import { PGGraphQLQueryRunner } from 'src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; @Injectable() export class CreateManyResolverFactory @@ -16,13 +16,15 @@ export class CreateManyResolverFactory { public static methodName = 'createMany' as const; - constructor(private readonly dataSourceService: DataSourceService) {} + constructor( + private readonly tenantDataSourceService: TenantDataSourceService, + ) {} create(context: SchemaBuilderContext): Resolver { const internalContext = context; return (_source, args, context, info) => { - const runner = new PGGraphQLQueryRunner(this.dataSourceService, { + const runner = new PGGraphQLQueryRunner(this.tenantDataSourceService, { targetTableName: internalContext.targetTableName, workspaceId: internalContext.workspaceId, info, diff --git a/server/src/tenant/resolver-builder/factories/create-one-resolver.factory.ts b/server/src/tenant/resolver-builder/factories/create-one-resolver.factory.ts index c599682fba..2d35ecbc08 100644 --- a/server/src/tenant/resolver-builder/factories/create-one-resolver.factory.ts +++ b/server/src/tenant/resolver-builder/factories/create-one-resolver.factory.ts @@ -7,9 +7,9 @@ import { import { SchemaBuilderContext } from 'src/tenant/schema-builder/interfaces/schema-builder-context.interface'; import { ResolverBuilderFactoryInterface } from 'src/tenant/resolver-builder/interfaces/resolver-builder-factory.interface'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; import { PGGraphQLQueryRunner } from 'src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; @Injectable() export class CreateOneResolverFactory @@ -17,18 +17,20 @@ export class CreateOneResolverFactory { public static methodName = 'createOne' as const; - constructor(private readonly dataSourceService: DataSourceService) {} + constructor( + private readonly tenantDataSourceService: TenantDataSourceService, + ) {} create(context: SchemaBuilderContext): Resolver { const internalContext = context; return (_source, args, context, info) => { - const runner = new PGGraphQLQueryRunner(this.dataSourceService, { + const runner = new PGGraphQLQueryRunner(this.tenantDataSourceService, { targetTableName: internalContext.targetTableName, workspaceId: internalContext.workspaceId, info, fieldMetadataCollection: - internalContext.fieldMetadataCollection as FieldMetadata[], + internalContext.fieldMetadataCollection as FieldMetadataEntity[], }); return runner.createOne(args); diff --git a/server/src/tenant/resolver-builder/factories/delete-one-resolver.factory.ts b/server/src/tenant/resolver-builder/factories/delete-one-resolver.factory.ts index 4bd2f00cf3..08ddf71717 100644 --- a/server/src/tenant/resolver-builder/factories/delete-one-resolver.factory.ts +++ b/server/src/tenant/resolver-builder/factories/delete-one-resolver.factory.ts @@ -7,9 +7,9 @@ import { import { SchemaBuilderContext } from 'src/tenant/schema-builder/interfaces/schema-builder-context.interface'; import { ResolverBuilderFactoryInterface } from 'src/tenant/resolver-builder/interfaces/resolver-builder-factory.interface'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; import { PGGraphQLQueryRunner } from 'src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; @Injectable() export class DeleteOneResolverFactory @@ -17,18 +17,20 @@ export class DeleteOneResolverFactory { public static methodName = 'deleteOne' as const; - constructor(private readonly dataSourceService: DataSourceService) {} + constructor( + private readonly tenantDataSourceService: TenantDataSourceService, + ) {} create(context: SchemaBuilderContext): Resolver { const internalContext = context; return (_source, args, context, info) => { - const runner = new PGGraphQLQueryRunner(this.dataSourceService, { + const runner = new PGGraphQLQueryRunner(this.tenantDataSourceService, { targetTableName: internalContext.targetTableName, workspaceId: internalContext.workspaceId, info, fieldMetadataCollection: - internalContext.fieldMetadataCollection as FieldMetadata[], + internalContext.fieldMetadataCollection as FieldMetadataEntity[], }); return runner.deleteOne(args); diff --git a/server/src/tenant/resolver-builder/factories/find-many-resolver.factory.ts b/server/src/tenant/resolver-builder/factories/find-many-resolver.factory.ts index 450c8ae4b8..765441a389 100644 --- a/server/src/tenant/resolver-builder/factories/find-many-resolver.factory.ts +++ b/server/src/tenant/resolver-builder/factories/find-many-resolver.factory.ts @@ -7,8 +7,8 @@ import { import { SchemaBuilderContext } from 'src/tenant/schema-builder/interfaces/schema-builder-context.interface'; import { ResolverBuilderFactoryInterface } from 'src/tenant/resolver-builder/interfaces/resolver-builder-factory.interface'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; import { PGGraphQLQueryRunner } from 'src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; @Injectable() export class FindManyResolverFactory @@ -16,13 +16,15 @@ export class FindManyResolverFactory { public static methodName = 'findMany' as const; - constructor(private readonly dataSourceService: DataSourceService) {} + constructor( + private readonly tenantDataSourceService: TenantDataSourceService, + ) {} create(context: SchemaBuilderContext): Resolver { const internalContext = context; return (_source, args, context, info) => { - const runner = new PGGraphQLQueryRunner(this.dataSourceService, { + const runner = new PGGraphQLQueryRunner(this.tenantDataSourceService, { targetTableName: internalContext.targetTableName, workspaceId: internalContext.workspaceId, info, diff --git a/server/src/tenant/resolver-builder/factories/find-one-resolver.factory.ts b/server/src/tenant/resolver-builder/factories/find-one-resolver.factory.ts index 806fac3ecc..f98669abb4 100644 --- a/server/src/tenant/resolver-builder/factories/find-one-resolver.factory.ts +++ b/server/src/tenant/resolver-builder/factories/find-one-resolver.factory.ts @@ -7,26 +7,28 @@ import { import { SchemaBuilderContext } from 'src/tenant/schema-builder/interfaces/schema-builder-context.interface'; import { ResolverBuilderFactoryInterface } from 'src/tenant/resolver-builder/interfaces/resolver-builder-factory.interface'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; import { PGGraphQLQueryRunner } from 'src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; @Injectable() export class FindOneResolverFactory implements ResolverBuilderFactoryInterface { public static methodName = 'findOne' as const; - constructor(private readonly dataSourceService: DataSourceService) {} + constructor( + private readonly tenantDataSourceService: TenantDataSourceService, + ) {} create(context: SchemaBuilderContext): Resolver { const internalContext = context; return (_source, args, context, info) => { - const runner = new PGGraphQLQueryRunner(this.dataSourceService, { + const runner = new PGGraphQLQueryRunner(this.tenantDataSourceService, { targetTableName: internalContext.targetTableName, workspaceId: internalContext.workspaceId, info, fieldMetadataCollection: - internalContext.fieldMetadataCollection as FieldMetadata[], + internalContext.fieldMetadataCollection as FieldMetadataEntity[], }); return runner.findOne(args); diff --git a/server/src/tenant/resolver-builder/factories/update-one-resolver.factory.ts b/server/src/tenant/resolver-builder/factories/update-one-resolver.factory.ts index 8374681294..fa91a13d11 100644 --- a/server/src/tenant/resolver-builder/factories/update-one-resolver.factory.ts +++ b/server/src/tenant/resolver-builder/factories/update-one-resolver.factory.ts @@ -7,9 +7,9 @@ import { import { SchemaBuilderContext } from 'src/tenant/schema-builder/interfaces/schema-builder-context.interface'; import { ResolverBuilderFactoryInterface } from 'src/tenant/resolver-builder/interfaces/resolver-builder-factory.interface'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; import { PGGraphQLQueryRunner } from 'src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; @Injectable() export class UpdateOneResolverFactory @@ -17,18 +17,20 @@ export class UpdateOneResolverFactory { public static methodName = 'updateOne' as const; - constructor(private readonly dataSourceService: DataSourceService) {} + constructor( + private readonly tenantDataSourceService: TenantDataSourceService, + ) {} create(context: SchemaBuilderContext): Resolver { const internalContext = context; return (_source, args, context, info) => { - const runner = new PGGraphQLQueryRunner(this.dataSourceService, { + const runner = new PGGraphQLQueryRunner(this.tenantDataSourceService, { targetTableName: internalContext.targetTableName, workspaceId: internalContext.workspaceId, info, fieldMetadataCollection: - internalContext.fieldMetadataCollection as FieldMetadata[], + internalContext.fieldMetadataCollection as FieldMetadataEntity[], }); return runner.updateOne(args); diff --git a/server/src/tenant/resolver-builder/pg-graphql/__tests__/pg-graphql-query-builder.spec.ts b/server/src/tenant/resolver-builder/pg-graphql/__tests__/pg-graphql-query-builder.spec.ts index 0905dab462..a75b8e874c 100644 --- a/server/src/tenant/resolver-builder/pg-graphql/__tests__/pg-graphql-query-builder.spec.ts +++ b/server/src/tenant/resolver-builder/pg-graphql/__tests__/pg-graphql-query-builder.spec.ts @@ -1,12 +1,12 @@ import { GraphQLResolveInfo } from 'graphql'; -import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; import { PGGraphQLQueryBuilder, PGGraphQLQueryBuilderOptions, } from 'src/tenant/resolver-builder/pg-graphql/pg-graphql-query-builder'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; const testUUID = '123e4567-e89b-12d3-a456-426614174001'; @@ -53,7 +53,7 @@ describe('PGGraphQLQueryBuilder', () => { subField2: 'column_subField2', } as FieldMetadataTargetColumnMap, }, - ] as FieldMetadata[]; + ] as FieldMetadataEntity[]; mockOptions = { targetTableName: 'TestTable', diff --git a/server/src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner.ts b/server/src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner.ts index 254821a9ea..0c088dec66 100644 --- a/server/src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner.ts +++ b/server/src/tenant/resolver-builder/pg-graphql/pg-graphql-query-runner.ts @@ -22,8 +22,8 @@ import { PGGraphQLResult, } from 'src/tenant/resolver-builder/interfaces/pg-graphql.interface'; -import { DataSourceService } from 'src/metadata/data-source/data-source.service'; import { parseResult } from 'src/tenant/resolver-builder/utils/parse-result.util'; +import { TenantDataSourceService } from 'src/tenant-datasource/tenant-datasource.service'; import { PGGraphQLQueryBuilder } from './pg-graphql-query-builder'; @@ -43,7 +43,7 @@ export class PGGraphQLQueryRunner< private options: QueryRunnerOptions; constructor( - private dataSourceService: DataSourceService, + private tenantDataSourceService: TenantDataSourceService, options: QueryRunnerOptions, ) { this.queryBuilder = new PGGraphQLQueryBuilder({ @@ -59,10 +59,14 @@ export class PGGraphQLQueryRunner< workspaceId: string, ): Promise { const workspaceDataSource = - await this.dataSourceService.connectToWorkspaceDataSource(workspaceId); + await this.tenantDataSourceService.connectToWorkspaceDataSource( + workspaceId, + ); await workspaceDataSource?.query(` - SET search_path TO ${this.dataSourceService.getSchemaName(workspaceId)}; + SET search_path TO ${this.tenantDataSourceService.getSchemaName( + workspaceId, + )}; `); return workspaceDataSource?.query(` diff --git a/server/src/tenant/resolver-builder/resolver-builder.module.ts b/server/src/tenant/resolver-builder/resolver-builder.module.ts index a580fb4634..e1e2534f33 100644 --- a/server/src/tenant/resolver-builder/resolver-builder.module.ts +++ b/server/src/tenant/resolver-builder/resolver-builder.module.ts @@ -1,13 +1,13 @@ import { Module } from '@nestjs/common'; -import { DataSourceModule } from 'src/metadata/data-source/data-source.module'; +import { TenantDataSourceModule } from 'src/tenant-datasource/tenant-datasource.module'; import { ResolverFactory } from './resolver.factory'; import { resolverBuilderFactories } from './factories/factories'; @Module({ - imports: [DataSourceModule], + imports: [TenantDataSourceModule], providers: [...resolverBuilderFactories, ResolverFactory], exports: [ResolverFactory], }) diff --git a/server/src/tenant/resolver-builder/utils/__tests__/convert-arguments.spec.ts b/server/src/tenant/resolver-builder/utils/__tests__/convert-arguments.spec.ts index 582b9aeee7..ec4ed204c3 100644 --- a/server/src/tenant/resolver-builder/utils/__tests__/convert-arguments.spec.ts +++ b/server/src/tenant/resolver-builder/utils/__tests__/convert-arguments.spec.ts @@ -1,9 +1,9 @@ -import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; import { - FieldMetadata, + FieldMetadataEntity, FieldMetadataType, -} from 'src/metadata/field-metadata/field-metadata.entity'; +} from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { convertArguments } from 'src/tenant/resolver-builder/utils/convert-arguments.util'; describe('convertArguments', () => { @@ -33,7 +33,7 @@ describe('convertArguments', () => { } as FieldMetadataTargetColumnMap, type: FieldMetadataType.URL, }, - ] as FieldMetadata[]; + ] as FieldMetadataEntity[]; }); test('should handle non-array arguments', () => { diff --git a/server/src/tenant/resolver-builder/utils/__tests__/convert-fields-to-graphql.spec.ts b/server/src/tenant/resolver-builder/utils/__tests__/convert-fields-to-graphql.spec.ts index 54c7a9ec46..3b33ecf247 100644 --- a/server/src/tenant/resolver-builder/utils/__tests__/convert-fields-to-graphql.spec.ts +++ b/server/src/tenant/resolver-builder/utils/__tests__/convert-fields-to-graphql.spec.ts @@ -1,7 +1,7 @@ -import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; import { convertFieldsToGraphQL } from 'src/tenant/resolver-builder/utils/convert-fields-to-graphql.util'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; const normalizeWhitespace = (str) => str.replace(/\s+/g, ' ').trim(); @@ -23,7 +23,7 @@ describe('convertFieldsToGraphQL', () => { text: 'column_RANDOMSTRING3', } as FieldMetadataTargetColumnMap, }, - ] as FieldMetadata[]; + ] as FieldMetadataEntity[]; }); test('should handle simple fields correctly', () => { @@ -75,7 +75,7 @@ describe('convertFieldsToGraphQL', () => { const emptyField = { name: 'emptyField', targetColumnMap: {}, - } as FieldMetadata; + } as FieldMetadataEntity; fields.push(emptyField); diff --git a/server/src/tenant/schema-builder/factories/filter-type-definition.factory.ts b/server/src/tenant/schema-builder/factories/filter-type-definition.factory.ts index 6b330b2c69..318d509198 100644 --- a/server/src/tenant/schema-builder/factories/filter-type-definition.factory.ts +++ b/server/src/tenant/schema-builder/factories/filter-type-definition.factory.ts @@ -6,8 +6,8 @@ import { BuildSchemaOptions } from 'src/tenant/schema-builder/interfaces/build-s import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface'; import { pascalCase } from 'src/utils/pascal-case'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; import { TypeMapperService } from 'src/tenant/schema-builder/services/type-mapper.service'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { FilterTypeFactory } from './filter-type.factory'; import { @@ -67,7 +67,7 @@ export class FilterTypeDefinitionFactory { ): GraphQLInputFieldConfigMap { const fields: GraphQLInputFieldConfigMap = {}; - objectMetadata.fields.forEach((fieldMetadata: FieldMetadata) => { + objectMetadata.fields.forEach((fieldMetadata: FieldMetadataEntity) => { const type = this.filterTypeFactory.create(fieldMetadata, options, { nullable: fieldMetadata.isNullable, }); diff --git a/server/src/tenant/schema-builder/factories/input-type-definition.factory.ts b/server/src/tenant/schema-builder/factories/input-type-definition.factory.ts index 9dcb3e0e65..ca32e25b18 100644 --- a/server/src/tenant/schema-builder/factories/input-type-definition.factory.ts +++ b/server/src/tenant/schema-builder/factories/input-type-definition.factory.ts @@ -6,7 +6,7 @@ import { BuildSchemaOptions } from 'src/tenant/schema-builder/interfaces/build-s import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface'; import { pascalCase } from 'src/utils/pascal-case'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { InputTypeFactory } from './input-type.factory'; @@ -52,7 +52,7 @@ export class InputTypeDefinitionFactory { ): GraphQLInputFieldConfigMap { const fields: GraphQLInputFieldConfigMap = {}; - objectMetadata.fields.forEach((fieldMetadata: FieldMetadata) => { + objectMetadata.fields.forEach((fieldMetadata: FieldMetadataEntity) => { const type = this.inputTypeFactory.create(fieldMetadata, kind, options, { nullable: fieldMetadata.isNullable, }); diff --git a/server/src/tenant/schema-builder/factories/object-type-definition.factory.ts b/server/src/tenant/schema-builder/factories/object-type-definition.factory.ts index 336ee76001..2d3ddb63cf 100644 --- a/server/src/tenant/schema-builder/factories/object-type-definition.factory.ts +++ b/server/src/tenant/schema-builder/factories/object-type-definition.factory.ts @@ -5,8 +5,8 @@ import { GraphQLFieldConfigMap, GraphQLObjectType } from 'graphql'; import { BuildSchemaOptions } from 'src/tenant/schema-builder/interfaces/build-schema-optionts.interface'; import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; import { pascalCase } from 'src/utils/pascal-case'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { OutputTypeFactory } from './output-type.factory'; @@ -49,7 +49,7 @@ export class ObjectTypeDefinitionFactory { ): GraphQLFieldConfigMap { const fields: GraphQLFieldConfigMap = {}; - objectMetadata.fields.forEach((fieldMetadata: FieldMetadata) => { + objectMetadata.fields.forEach((fieldMetadata: FieldMetadataEntity) => { const type = this.outputTypeFactory.create(fieldMetadata, kind, options, { nullable: fieldMetadata.isNullable, }); diff --git a/server/src/tenant/schema-builder/factories/order-by-type-definition.factory.ts b/server/src/tenant/schema-builder/factories/order-by-type-definition.factory.ts index 74452fd5b8..0e871ab80d 100644 --- a/server/src/tenant/schema-builder/factories/order-by-type-definition.factory.ts +++ b/server/src/tenant/schema-builder/factories/order-by-type-definition.factory.ts @@ -6,7 +6,7 @@ import { BuildSchemaOptions } from 'src/tenant/schema-builder/interfaces/build-s import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface'; import { pascalCase } from 'src/utils/pascal-case'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { InputTypeDefinition, @@ -43,7 +43,7 @@ export class OrderByTypeDefinitionFactory { ): GraphQLInputFieldConfigMap { const fields: GraphQLInputFieldConfigMap = {}; - objectMetadata.fields.forEach((fieldMetadata: FieldMetadata) => { + objectMetadata.fields.forEach((fieldMetadata: FieldMetadataEntity) => { const type = this.orderByTypeFactory.create(fieldMetadata, options, { nullable: fieldMetadata.isNullable, }); diff --git a/server/src/tenant/schema-builder/graphql-schema.factory.ts b/server/src/tenant/schema-builder/graphql-schema.factory.ts index 70d8cc14fc..f563f5b164 100644 --- a/server/src/tenant/schema-builder/graphql-schema.factory.ts +++ b/server/src/tenant/schema-builder/graphql-schema.factory.ts @@ -4,7 +4,7 @@ import { GraphQLSchema } from 'graphql'; import { ResolverBuilderMethods } from 'src/tenant/resolver-builder/interfaces/resolvers-builder.interface'; -import { ObjectMetadataService } from 'src/metadata/object-metadata/services/object-metadata.service'; +import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service'; import { TypeDefinitionsGenerator } from './type-definitions.generator'; diff --git a/server/src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface.ts b/server/src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface.ts similarity index 89% rename from server/src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface.ts rename to server/src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface.ts index 65580c811b..cdde4daa07 100644 --- a/server/src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface.ts +++ b/server/src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface.ts @@ -1,4 +1,4 @@ -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; export interface FieldMetadataTargetColumnMapValue { value: string; diff --git a/server/src/tenant/schema-builder/interfaces/field-metadata.interface.ts b/server/src/tenant/schema-builder/interfaces/field-metadata.interface.ts index 3ea023842e..5b36f26efd 100644 --- a/server/src/tenant/schema-builder/interfaces/field-metadata.interface.ts +++ b/server/src/tenant/schema-builder/interfaces/field-metadata.interface.ts @@ -1,6 +1,6 @@ -import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataTargetColumnMap } from './field-metadata-target-column-map.interface'; export interface FieldMetadataInterface< T extends FieldMetadataType | 'default' = 'default', diff --git a/server/src/tenant/schema-builder/interfaces/param-metadata.interface.ts b/server/src/tenant/schema-builder/interfaces/param-metadata.interface.ts index 79f7df8103..196dba8c24 100644 --- a/server/src/tenant/schema-builder/interfaces/param-metadata.interface.ts +++ b/server/src/tenant/schema-builder/interfaces/param-metadata.interface.ts @@ -1,5 +1,5 @@ import { InputTypeDefinitionKind } from 'src/tenant/schema-builder/factories/input-type-definition.factory'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { ObjectMetadataInterface } from './object-metadata.interface'; diff --git a/server/src/tenant/schema-builder/object-definitions/money.object-definition.ts b/server/src/tenant/schema-builder/object-definitions/money.object-definition.ts index 86975033b9..cfc8e8c77c 100644 --- a/server/src/tenant/schema-builder/object-definitions/money.object-definition.ts +++ b/server/src/tenant/schema-builder/object-definitions/money.object-definition.ts @@ -1,6 +1,6 @@ import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; export const moneyObjectDefinition = { id: FieldMetadataType.MONEY.toString(), diff --git a/server/src/tenant/schema-builder/object-definitions/url.object-definition.ts b/server/src/tenant/schema-builder/object-definitions/url.object-definition.ts index e10bc11551..169c9b2420 100644 --- a/server/src/tenant/schema-builder/object-definitions/url.object-definition.ts +++ b/server/src/tenant/schema-builder/object-definitions/url.object-definition.ts @@ -1,6 +1,6 @@ import { ObjectMetadataInterface } from 'src/tenant/schema-builder/interfaces/object-metadata.interface'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; export const urlObjectDefinition = { id: FieldMetadataType.URL.toString(), diff --git a/server/src/tenant/schema-builder/services/type-mapper.service.ts b/server/src/tenant/schema-builder/services/type-mapper.service.ts index 3ef70a3e80..5e61d9c786 100644 --- a/server/src/tenant/schema-builder/services/type-mapper.service.ts +++ b/server/src/tenant/schema-builder/services/type-mapper.service.ts @@ -21,7 +21,6 @@ import { NumberScalarMode, } from 'src/tenant/schema-builder/interfaces/build-schema-optionts.interface'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; import { UUIDFilterType, StringFilterType, @@ -31,6 +30,7 @@ import { IntFilterType, } from 'src/tenant/schema-builder/graphql-types/input'; import { OrderByDirectionType } from 'src/tenant/schema-builder/graphql-types/enum'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; export interface TypeOptions { nullable?: boolean; diff --git a/server/src/tenant/schema-builder/storages/type-definitions.storage.ts b/server/src/tenant/schema-builder/storages/type-definitions.storage.ts index 34a221c583..7fbcae7c49 100644 --- a/server/src/tenant/schema-builder/storages/type-definitions.storage.ts +++ b/server/src/tenant/schema-builder/storages/type-definitions.storage.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { GraphQLInputObjectType, GraphQLObjectType } from 'graphql'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { InputTypeDefinition, InputTypeDefinitionKind, diff --git a/server/src/tenant/schema-builder/type-definitions.generator.ts b/server/src/tenant/schema-builder/type-definitions.generator.ts index 2ce205961d..395e71d0d8 100644 --- a/server/src/tenant/schema-builder/type-definitions.generator.ts +++ b/server/src/tenant/schema-builder/type-definitions.generator.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; -import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity'; -import { customTableDefaultColumns } from 'src/metadata/migration-runner/custom-table-default-column.util'; +import { customTableDefaultColumns } from 'src/tenant-migration-runner/utils/custom-table-default-column.util'; +import { FieldMetadataEntity } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { TypeDefinitionsStorage } from './storages/type-definitions.storage'; import { @@ -29,7 +29,7 @@ const defaultFields = customTableDefaultColumns.map((column) => { type: getFieldMetadataType(column.type), name: column.name, isNullable: true, - } as FieldMetadata; + } as FieldMetadataEntity; }); @Injectable() diff --git a/server/src/tenant/schema-builder/utils/__tests__/get-field-metadata-type.spec.ts b/server/src/tenant/schema-builder/utils/__tests__/get-field-metadata-type.spec.ts index 27b1761dc7..6ab3b011b7 100644 --- a/server/src/tenant/schema-builder/utils/__tests__/get-field-metadata-type.spec.ts +++ b/server/src/tenant/schema-builder/utils/__tests__/get-field-metadata-type.spec.ts @@ -1,4 +1,4 @@ -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { getFieldMetadataType } from 'src/tenant/schema-builder/utils/get-field-metadata-type.util'; describe('getFieldMetadataType', () => { diff --git a/server/src/tenant/schema-builder/utils/__tests__/get-resolver-args.spec.ts b/server/src/tenant/schema-builder/utils/__tests__/get-resolver-args.spec.ts index 86271e8c38..7bec3613cd 100644 --- a/server/src/tenant/schema-builder/utils/__tests__/get-resolver-args.spec.ts +++ b/server/src/tenant/schema-builder/utils/__tests__/get-resolver-args.spec.ts @@ -1,6 +1,6 @@ import { ResolverBuilderMethodNames } from 'src/tenant/resolver-builder/interfaces/resolvers-builder.interface'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; import { InputTypeDefinitionKind } from 'src/tenant/schema-builder/factories/input-type-definition.factory'; import { getResolverArgs } from 'src/tenant/schema-builder/utils/get-resolver-args.util'; diff --git a/server/src/tenant/schema-builder/utils/get-field-metadata-type.util.ts b/server/src/tenant/schema-builder/utils/get-field-metadata-type.util.ts index 0de04521f5..c8fdaee007 100644 --- a/server/src/tenant/schema-builder/utils/get-field-metadata-type.util.ts +++ b/server/src/tenant/schema-builder/utils/get-field-metadata-type.util.ts @@ -1,4 +1,4 @@ -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; const typeOrmTypeMapping = new Map([ ['uuid', FieldMetadataType.UUID], diff --git a/server/src/tenant/schema-builder/utils/get-resolver-args.util.ts b/server/src/tenant/schema-builder/utils/get-resolver-args.util.ts index 3ccaa73fc3..91222a7331 100644 --- a/server/src/tenant/schema-builder/utils/get-resolver-args.util.ts +++ b/server/src/tenant/schema-builder/utils/get-resolver-args.util.ts @@ -1,8 +1,8 @@ import { ResolverBuilderMethodNames } from 'src/tenant/resolver-builder/interfaces/resolvers-builder.interface'; import { ArgMetadata } from 'src/tenant/schema-builder/interfaces/param-metadata.interface'; -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; import { InputTypeDefinitionKind } from 'src/tenant/schema-builder/factories/input-type-definition.factory'; +import { FieldMetadataType } from 'src/database/typeorm/metadata/entities/field-metadata.entity'; export const getResolverArgs = ( type: ResolverBuilderMethodNames, diff --git a/server/src/tenant/tenant.service.spec.ts b/server/src/tenant/tenant.service.spec.ts index a8c64dd979..8a9e6ccf4e 100644 --- a/server/src/tenant/tenant.service.spec.ts +++ b/server/src/tenant/tenant.service.spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; -import { ObjectMetadataService } from 'src/metadata/object-metadata/services/object-metadata.service'; +import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service'; import { TenantService } from './tenant.service'; diff --git a/server/src/tenant/tenant.service.ts b/server/src/tenant/tenant.service.ts index 679e09e11a..fc8b9086a3 100644 --- a/server/src/tenant/tenant.service.ts +++ b/server/src/tenant/tenant.service.ts @@ -6,7 +6,7 @@ import { makeExecutableSchema } from '@graphql-tools/schema'; import { gql } from 'graphql-tag'; import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service'; -import { ObjectMetadataService } from 'src/metadata/object-metadata/services/object-metadata.service'; +import { ObjectMetadataService } from 'src/metadata/object-metadata/object-metadata.service'; import { GraphQLSchemaFactory } from './schema-builder/graphql-schema.factory'; import { resolverBuilderMethodNames } from './resolver-builder/factories/factories'; @@ -31,7 +31,7 @@ export class TenantService { workspaceId, ); - // Can'f find any data sources for this workspace + // Can't find any data sources for this workspace if (!dataSourcesMetadata || dataSourcesMetadata.length === 0) { return new GraphQLSchema({}); }