diff --git a/server/src/coreV2/user/services/user.service.spec.ts b/server/src/coreV2/user/services/user.service.spec.ts index 519b8679287..b73bfe936a9 100644 --- a/server/src/coreV2/user/services/user.service.spec.ts +++ b/server/src/coreV2/user/services/user.service.spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; -import { User } from 'src/coreV2/user/user.entity'; +import { UserV2 } from 'src/coreV2/user/user.entity'; import { UserService } from './user.service'; @@ -13,7 +13,7 @@ describe('UserService', () => { providers: [ UserService, { - provide: getRepositoryToken(User), + provide: getRepositoryToken(UserV2), useValue: {}, }, ], diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/activity-target.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/activity-target.ts index 69204ac30af..00d956d7674 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/activity-target.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/activity-target.ts @@ -40,6 +40,7 @@ export const seedActivityTargetFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -58,8 +59,9 @@ export const seedActivityTargetFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedActivityTargetFieldMetadataIds.CreatedAt, @@ -75,8 +77,9 @@ export const seedActivityTargetFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedActivityTargetFieldMetadataIds.UpdatedAt, @@ -92,8 +95,9 @@ export const seedActivityTargetFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Relationships { @@ -110,6 +114,7 @@ export const seedActivityTargetFieldMetadata = async ( icon: 'IconNotes', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityTargetFieldMetadataIds.ActivityForeignKey, @@ -125,6 +130,7 @@ export const seedActivityTargetFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedActivityTargetFieldMetadataIds.Person, @@ -140,6 +146,7 @@ export const seedActivityTargetFieldMetadata = async ( icon: 'IconUser', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityTargetFieldMetadataIds.PersonForeignKey, @@ -155,6 +162,7 @@ export const seedActivityTargetFieldMetadata = async ( icon: undefined, isNullable: true, isSystem: true, + defaultValue: undefined, }, { id: SeedActivityTargetFieldMetadataIds.Company, @@ -170,6 +178,7 @@ export const seedActivityTargetFieldMetadata = async ( icon: 'IconBuildingSkyscraper', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityTargetFieldMetadataIds.CompanyForeignKey, @@ -185,6 +194,7 @@ export const seedActivityTargetFieldMetadata = async ( icon: undefined, isNullable: true, isSystem: true, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/activity.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/activity.ts index 4d030e23e06..5084f91538a 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/activity.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/activity.ts @@ -48,6 +48,7 @@ export const seedActivityFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -66,8 +67,9 @@ export const seedActivityFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedActivityFieldMetadataIds.CreatedAt, @@ -83,8 +85,9 @@ export const seedActivityFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedActivityFieldMetadataIds.UpdatedAt, @@ -100,8 +103,9 @@ export const seedActivityFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Primary identifier { @@ -120,6 +124,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconNotes', isNullable: true, isSystem: false, + defaultValue: undefined, }, // Scalar fields @@ -139,6 +144,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconList', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.Type, @@ -156,6 +162,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconCheckbox', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.ReminderAt, @@ -173,6 +180,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconCalendarEvent', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.DueAt, @@ -190,6 +198,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconCalendarEvent', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.CompletedAt, @@ -207,6 +216,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconCheck', isNullable: true, isSystem: false, + defaultValue: undefined, }, // Relationships @@ -224,6 +234,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconCheckbox', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.Attachments, @@ -239,6 +250,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconFileImport', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.Comments, @@ -254,6 +266,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconComment', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.Author, @@ -272,6 +285,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconUserCircle', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.AuthorForeignKey, @@ -287,6 +301,7 @@ export const seedActivityFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.Assignee, @@ -303,6 +318,7 @@ export const seedActivityFieldMetadata = async ( icon: 'IconUserCircle', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedActivityFieldMetadataIds.AssigneeForeignKey, @@ -318,6 +334,7 @@ export const seedActivityFieldMetadata = async ( icon: undefined, isNullable: true, isSystem: true, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/api-key.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/api-key.ts index e70bd23d9e9..6be643f827c 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/api-key.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/api-key.ts @@ -37,6 +37,7 @@ export const seedApiKeyFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -57,6 +58,7 @@ export const seedApiKeyFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedApiKeyFieldMetadataIds.CreatedAt, @@ -72,8 +74,9 @@ export const seedApiKeyFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedApiKeyFieldMetadataIds.UpdatedAt, @@ -89,8 +92,9 @@ export const seedApiKeyFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Scalar fields { @@ -109,6 +113,7 @@ export const seedApiKeyFieldMetadata = async ( icon: 'IconLink', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedApiKeyFieldMetadataIds.ExpiresAt, @@ -126,6 +131,7 @@ export const seedApiKeyFieldMetadata = async ( icon: 'IconCalendar', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedApiKeyFieldMetadataIds.RevokedAt, @@ -143,6 +149,7 @@ export const seedApiKeyFieldMetadata = async ( icon: 'IconCalendar', isNullable: true, isSystem: false, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/attachment.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/attachment.ts index 69f35e21f1c..0db186598ea 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/attachment.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/attachment.ts @@ -46,6 +46,7 @@ export const seedAttachmentFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -64,8 +65,9 @@ export const seedAttachmentFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedAttachmentFieldMetadataIds.CreatedAt, @@ -81,8 +83,9 @@ export const seedAttachmentFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedAttachmentFieldMetadataIds.UpdatedAt, @@ -98,8 +101,9 @@ export const seedAttachmentFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Primary Identifier { @@ -118,6 +122,7 @@ export const seedAttachmentFieldMetadata = async ( icon: 'IconFileUpload', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, // Scalar fields { @@ -136,6 +141,7 @@ export const seedAttachmentFieldMetadata = async ( icon: 'IconLink', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedAttachmentFieldMetadataIds.Type, @@ -153,6 +159,7 @@ export const seedAttachmentFieldMetadata = async ( icon: 'IconList', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, // Relationships @@ -170,6 +177,7 @@ export const seedAttachmentFieldMetadata = async ( icon: 'IconCircleUser', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedAttachmentFieldMetadataIds.AuthorForeignKey, @@ -185,6 +193,7 @@ export const seedAttachmentFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedAttachmentFieldMetadataIds.Activity, @@ -200,6 +209,7 @@ export const seedAttachmentFieldMetadata = async ( icon: 'IconNotes', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedAttachmentFieldMetadataIds.ActivityForeignKey, @@ -215,6 +225,7 @@ export const seedAttachmentFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedAttachmentFieldMetadataIds.Person, @@ -230,6 +241,7 @@ export const seedAttachmentFieldMetadata = async ( icon: 'IconUser', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedAttachmentFieldMetadataIds.PersonForeignKey, @@ -245,6 +257,7 @@ export const seedAttachmentFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedAttachmentFieldMetadataIds.Company, @@ -260,6 +273,7 @@ export const seedAttachmentFieldMetadata = async ( icon: 'IconBuildingSkyscraper', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedAttachmentFieldMetadataIds.CompanyForeignKey, @@ -275,6 +289,7 @@ export const seedAttachmentFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/comment.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/comment.ts index 1ed9c1b62d5..753416f2350 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/comment.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/comment.ts @@ -39,6 +39,7 @@ export const seedCommentFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -57,8 +58,9 @@ export const seedCommentFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedCommentFieldMetadataIds.CreatedAt, @@ -74,8 +76,9 @@ export const seedCommentFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedCommentFieldMetadataIds.UpdatedAt, @@ -91,8 +94,9 @@ export const seedCommentFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Scalar fields { @@ -111,6 +115,7 @@ export const seedCommentFieldMetadata = async ( icon: 'IconLink', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, // Relationships { @@ -127,6 +132,7 @@ export const seedCommentFieldMetadata = async ( icon: 'IconCircleUser', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedCommentFieldMetadataIds.AuthorForeignKey, @@ -142,6 +148,7 @@ export const seedCommentFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedCommentFieldMetadataIds.Activity, @@ -157,6 +164,7 @@ export const seedCommentFieldMetadata = async ( icon: 'IconNotes', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedCommentFieldMetadataIds.ActivityForeignKey, @@ -172,6 +180,7 @@ export const seedCommentFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/company.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/company.ts index 6397dd6546d..c77f97fbead 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/company.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/company.ts @@ -51,6 +51,7 @@ export const seedCompanyFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -69,8 +70,9 @@ export const seedCompanyFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedCompanyFieldMetadataIds.CreatedAt, @@ -86,8 +88,9 @@ export const seedCompanyFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedCompanyFieldMetadataIds.UpdatedAt, @@ -103,8 +106,9 @@ export const seedCompanyFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Main Identifier { @@ -123,6 +127,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconBuildingSkyscraper', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, // Scalar Fields @@ -143,6 +148,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconLink', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.Address, @@ -160,6 +166,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconMap', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.Employees, @@ -177,6 +184,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconUsers', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.LinkedinUrl, @@ -194,6 +202,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconBrandLinkedin', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.XUrl, @@ -211,6 +220,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconBrandX', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.AnnualRecurringRevenue, @@ -229,6 +239,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconMoneybag', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.IdealCustomerProfile, @@ -247,6 +258,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconTarget', isNullable: true, isSystem: false, + defaultValue: undefined, }, // Relationships @@ -264,6 +276,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconUsers', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.AccountOwner, @@ -280,6 +293,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconUserCircle', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.AccountOwnerForeignKey, @@ -295,6 +309,7 @@ export const seedCompanyFieldMetadata = async ( icon: undefined, isNullable: true, isSystem: true, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.ActivityTargets, @@ -310,6 +325,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconCheckbox', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.Opportunities, @@ -325,6 +341,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconTargetArrow', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.Favorites, @@ -340,6 +357,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconHeart', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedCompanyFieldMetadataIds.Attachments, @@ -355,6 +373,7 @@ export const seedCompanyFieldMetadata = async ( icon: 'IconFileImport', isNullable: true, isSystem: false, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/favorite.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/favorite.ts index 113bcd3e907..bcd49fd5183 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/favorite.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/favorite.ts @@ -43,6 +43,7 @@ export const seedFavoriteFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -61,8 +62,9 @@ export const seedFavoriteFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedFavoriteFieldMetadataIds.CreatedAt, @@ -78,8 +80,9 @@ export const seedFavoriteFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedFavoriteFieldMetadataIds.UpdatedAt, @@ -95,8 +98,9 @@ export const seedFavoriteFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Scalar fields { @@ -115,6 +119,7 @@ export const seedFavoriteFieldMetadata = async ( icon: 'IconList', isNullable: false, isSystem: false, + defaultValue: { value: 0 }, }, // Relationships @@ -132,6 +137,7 @@ export const seedFavoriteFieldMetadata = async ( icon: 'IconCircleUser', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedFavoriteFieldMetadataIds.WorkspaceMemberForeignKey, @@ -147,6 +153,7 @@ export const seedFavoriteFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedFavoriteFieldMetadataIds.Person, @@ -164,6 +171,7 @@ export const seedFavoriteFieldMetadata = async ( icon: 'IconUser', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedFavoriteFieldMetadataIds.PersonForeignKey, @@ -179,6 +187,7 @@ export const seedFavoriteFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedFavoriteFieldMetadataIds.Company, @@ -194,6 +203,7 @@ export const seedFavoriteFieldMetadata = async ( icon: 'IconBuildingSkyscraper', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedFavoriteFieldMetadataIds.CompanyForeignKey, @@ -209,6 +219,7 @@ export const seedFavoriteFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/opportunity.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/opportunity.ts index 6c6551af7bd..28e6537c040 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/opportunity.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/opportunity.ts @@ -46,6 +46,7 @@ export const seedOpportunityFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -64,8 +65,9 @@ export const seedOpportunityFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedOpportunityFieldMetadataIds.CreatedAt, @@ -81,8 +83,9 @@ export const seedOpportunityFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedOpportunityFieldMetadataIds.UpdatedAt, @@ -98,8 +101,9 @@ export const seedOpportunityFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Scalar fields { @@ -118,6 +122,7 @@ export const seedOpportunityFieldMetadata = async ( icon: 'IconCurrencyDollar', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.CloseDate, @@ -135,6 +140,7 @@ export const seedOpportunityFieldMetadata = async ( icon: 'IconCalendarEvent', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.Probability, @@ -152,6 +158,7 @@ export const seedOpportunityFieldMetadata = async ( icon: 'IconProgressCheck', isNullable: true, isSystem: false, + defaultValue: undefined, }, // Relationships { @@ -168,6 +175,7 @@ export const seedOpportunityFieldMetadata = async ( icon: 'IconKanban', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.PipelineStepForeignKey, @@ -183,6 +191,7 @@ export const seedOpportunityFieldMetadata = async ( icon: undefined, isNullable: true, isSystem: true, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.PointOfContact, @@ -198,6 +207,7 @@ export const seedOpportunityFieldMetadata = async ( icon: 'IconUser', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.PointOfContactForeignKey, @@ -213,6 +223,7 @@ export const seedOpportunityFieldMetadata = async ( icon: undefined, isNullable: true, isSystem: true, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.Person, @@ -228,6 +239,7 @@ export const seedOpportunityFieldMetadata = async ( icon: 'IconUser', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.PersonForeignKey, @@ -243,6 +255,7 @@ export const seedOpportunityFieldMetadata = async ( icon: undefined, isNullable: true, isSystem: true, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.Company, @@ -258,6 +271,7 @@ export const seedOpportunityFieldMetadata = async ( icon: 'IconBuildingSkyscraper', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedOpportunityFieldMetadataIds.CompanyForeignKey, @@ -273,6 +287,7 @@ export const seedOpportunityFieldMetadata = async ( icon: undefined, isNullable: true, isSystem: true, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/person.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/person.ts index b99404a5a8b..67b645c9832 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/person.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/person.ts @@ -52,6 +52,7 @@ export const seedPersonFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -70,8 +71,9 @@ export const seedPersonFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedPersonFieldMetadataIds.CreatedAt, @@ -87,8 +89,9 @@ export const seedPersonFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedPersonFieldMetadataIds.UpdatedAt, @@ -104,8 +107,9 @@ export const seedPersonFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Main Identifier { @@ -124,6 +128,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconUser', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedPersonFieldMetadataIds.LastName, @@ -141,6 +146,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconUser', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, // Scalar Fields @@ -160,6 +166,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconMail', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.LinkedinUrl, @@ -177,6 +184,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconBrandLinkedin', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.XUrl, @@ -194,6 +202,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconUser', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.JobTitle, @@ -211,6 +220,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconBriefcase', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.Phone, @@ -228,6 +238,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconPhone', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.City, @@ -245,6 +256,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconMap', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.AvatarUrl, @@ -262,6 +274,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconFileUpload', isNullable: true, isSystem: false, + defaultValue: undefined, }, // Relationships @@ -279,6 +292,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconBuildingSkyscraper', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.CompanyForeignKey, @@ -294,6 +308,7 @@ export const seedPersonFieldMetadata = async ( icon: undefined, isNullable: false, isSystem: true, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.ContactForOpportunities, @@ -309,6 +324,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconArrowTarget', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.ActivityTargets, @@ -324,6 +340,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconCheckbox', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.Opportunities, @@ -339,6 +356,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconTargetArrow', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.Favorites, @@ -354,6 +372,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconHeart', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedPersonFieldMetadataIds.Attachments, @@ -369,6 +388,7 @@ export const seedPersonFieldMetadata = async ( icon: 'IconFileImport', isNullable: true, isSystem: false, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/pipeline-step.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/pipeline-step.ts index 3d4a5eb7465..244c069fc31 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/pipeline-step.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/pipeline-step.ts @@ -38,6 +38,7 @@ export const seedPipelineStepFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -56,8 +57,9 @@ export const seedPipelineStepFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedPipelineStepFieldMetadataIds.CreatedAt, @@ -73,8 +75,9 @@ export const seedPipelineStepFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedPipelineStepFieldMetadataIds.UpdatedAt, @@ -90,8 +93,9 @@ export const seedPipelineStepFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Main Identifier { @@ -110,6 +114,7 @@ export const seedPipelineStepFieldMetadata = async ( icon: 'IconCurrencyDollar', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, // Scalar Fields @@ -129,6 +134,7 @@ export const seedPipelineStepFieldMetadata = async ( icon: 'IconColorSwatch', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedPipelineStepFieldMetadataIds.Position, @@ -146,6 +152,7 @@ export const seedPipelineStepFieldMetadata = async ( icon: 'IconHierarchy2', isNullable: false, isSystem: false, + defaultValue: { value: 0 }, }, // Relationships @@ -163,6 +170,7 @@ export const seedPipelineStepFieldMetadata = async ( icon: 'IconTargetArrow', isNullable: true, isSystem: false, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/view-field.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/view-field.ts index b5e59f48a09..12bddc5cbba 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/view-field.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/view-field.ts @@ -39,6 +39,7 @@ export const seedViewFieldFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -57,8 +58,9 @@ export const seedViewFieldFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedViewFieldFieldMetadataIds.CreatedAt, @@ -74,8 +76,9 @@ export const seedViewFieldFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedViewFieldFieldMetadataIds.UpdatedAt, @@ -91,8 +94,9 @@ export const seedViewFieldFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Fields { @@ -111,6 +115,7 @@ export const seedViewFieldFieldMetadata = async ( icon: 'IconTag', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedViewFieldFieldMetadataIds.View, @@ -126,6 +131,7 @@ export const seedViewFieldFieldMetadata = async ( icon: 'IconLayoutCollage', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedViewFieldFieldMetadataIds.IsVisible, @@ -143,6 +149,7 @@ export const seedViewFieldFieldMetadata = async ( icon: 'IconEye', isNullable: false, isSystem: false, + defaultValue: { value: true }, }, { id: SeedViewFieldFieldMetadataIds.Size, @@ -160,6 +167,7 @@ export const seedViewFieldFieldMetadata = async ( icon: 'IconEye', isNullable: false, isSystem: false, + defaultValue: { value: 0 }, }, { id: SeedViewFieldFieldMetadataIds.Position, @@ -177,6 +185,7 @@ export const seedViewFieldFieldMetadata = async ( icon: 'IconList', isNullable: false, isSystem: false, + defaultValue: { value: 0 }, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/view-filter.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/view-filter.ts index 66b5c13bdac..463b3101972 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/view-filter.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/view-filter.ts @@ -39,6 +39,7 @@ export const seedViewFilterFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -57,8 +58,9 @@ export const seedViewFilterFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedViewFilterFieldMetadataIds.CreatedAt, @@ -74,8 +76,9 @@ export const seedViewFilterFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedViewFilterFieldMetadataIds.UpdatedAt, @@ -91,8 +94,9 @@ export const seedViewFilterFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Fields { @@ -111,6 +115,7 @@ export const seedViewFilterFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedViewFilterFieldMetadataIds.View, @@ -128,6 +133,7 @@ export const seedViewFilterFieldMetadata = async ( icon: 'IconLayoutCollage', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedViewFilterFieldMetadataIds.Operand, @@ -145,6 +151,7 @@ export const seedViewFilterFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedViewFilterFieldMetadataIds.Value, @@ -162,6 +169,7 @@ export const seedViewFilterFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedViewFilterFieldMetadataIds.DisplayValue, @@ -179,6 +187,7 @@ export const seedViewFilterFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/view-sort.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/view-sort.ts index 039e5ebf5f2..edca3289dc9 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/view-sort.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/view-sort.ts @@ -37,6 +37,7 @@ export const seedViewSortFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -55,8 +56,9 @@ export const seedViewSortFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedViewSortFieldMetadataIds.CreatedAt, @@ -72,8 +74,9 @@ export const seedViewSortFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedViewSortFieldMetadataIds.UpdatedAt, @@ -89,8 +92,9 @@ export const seedViewSortFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Fields { @@ -109,6 +113,7 @@ export const seedViewSortFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedViewSortFieldMetadataIds.View, @@ -126,6 +131,7 @@ export const seedViewSortFieldMetadata = async ( icon: 'IconLayoutCollage', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedViewSortFieldMetadataIds.Direction, @@ -143,6 +149,7 @@ export const seedViewSortFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/view.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/view.ts index 12e40907708..a9203e6103d 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/view.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/view.ts @@ -40,6 +40,7 @@ export const seedViewFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -58,8 +59,9 @@ export const seedViewFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedViewFieldMetadataIds.CreatedAt, @@ -75,8 +77,9 @@ export const seedViewFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedViewFieldMetadataIds.UpdatedAt, @@ -92,8 +95,9 @@ export const seedViewFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Fields { @@ -112,6 +116,7 @@ export const seedViewFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedViewFieldMetadataIds.ObjectMetadataId, @@ -129,6 +134,7 @@ export const seedViewFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedViewFieldMetadataIds.Type, @@ -146,6 +152,7 @@ export const seedViewFieldMetadata = async ( icon: null, isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedViewFieldMetadataIds.ViewFields, @@ -161,6 +168,7 @@ export const seedViewFieldMetadata = async ( icon: 'IconTag', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedViewFieldMetadataIds.ViewSorts, @@ -176,6 +184,7 @@ export const seedViewFieldMetadata = async ( icon: 'IconArrowsSort', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedViewFieldMetadataIds.ViewFilters, @@ -191,6 +200,7 @@ export const seedViewFieldMetadata = async ( icon: 'IconFilterBolt', isNullable: true, isSystem: false, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/webhook.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/webhook.ts index 245a54c0fbc..a657cf15890 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/webhook.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/webhook.ts @@ -36,6 +36,7 @@ export const seedWebhookFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -54,8 +55,9 @@ export const seedWebhookFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedWebhookFieldMetadataIds.CreatedAt, @@ -71,8 +73,9 @@ export const seedWebhookFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedWebhookFieldMetadataIds.UpdatedAt, @@ -88,8 +91,9 @@ export const seedWebhookFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Scalar fields { @@ -108,6 +112,7 @@ export const seedWebhookFieldMetadata = async ( icon: 'IconLink', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedWebhookFieldMetadataIds.Operation, @@ -125,6 +130,7 @@ export const seedWebhookFieldMetadata = async ( icon: 'IconCheckbox', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, ]) .execute(); diff --git a/server/src/database/typeorm-seeds/metadata/field-metadata/workspace-member.ts b/server/src/database/typeorm-seeds/metadata/field-metadata/workspace-member.ts index 05880a101df..b79ccb9ca3e 100644 --- a/server/src/database/typeorm-seeds/metadata/field-metadata/workspace-member.ts +++ b/server/src/database/typeorm-seeds/metadata/field-metadata/workspace-member.ts @@ -48,6 +48,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( 'icon', 'isNullable', 'isSystem', + 'defaultValue', ]) .orIgnore() .values([ @@ -66,8 +67,9 @@ export const seedWorkspaceMemberFieldMetadata = async ( }, description: undefined, icon: undefined, - isNullable: true, + isNullable: false, isSystem: true, + defaultValue: { type: 'uuid' }, }, { id: SeedWorkspaceMemberFieldMetadataIds.CreatedAt, @@ -83,8 +85,9 @@ export const seedWorkspaceMemberFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, { id: SeedWorkspaceMemberFieldMetadataIds.UpdatedAt, @@ -100,8 +103,9 @@ export const seedWorkspaceMemberFieldMetadata = async ( }, description: undefined, icon: 'IconCalendar', - isNullable: true, - isSystem: false, + isNullable: false, + isSystem: true, + defaultValue: { type: 'now' }, }, // Scalar fields { @@ -120,6 +124,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconCircleUser', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedWorkspaceMemberFieldMetadataIds.LastName, @@ -137,6 +142,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconCircleUser', isNullable: false, isSystem: false, + defaultValue: { value: '' }, }, { id: SeedWorkspaceMemberFieldMetadataIds.AvatarUrl, @@ -154,6 +160,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconFileUpload', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedWorkspaceMemberFieldMetadataIds.UserId, @@ -171,6 +178,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconCircleUsers', isNullable: false, isSystem: false, + defaultValue: undefined, }, { id: SeedWorkspaceMemberFieldMetadataIds.AllowImpersonation, @@ -188,6 +196,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconEye', isNullable: false, isSystem: false, + defaultValue: { value: false }, }, { id: SeedWorkspaceMemberFieldMetadataIds.ColorScheme, @@ -205,6 +214,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconColorSwatch', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedWorkspaceMemberFieldMetadataIds.Locale, @@ -222,6 +232,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconLanguage', isNullable: false, isSystem: false, + defaultValue: { value: 'fr' }, }, // Relationships @@ -239,6 +250,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconCheckbox', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedWorkspaceMemberFieldMetadataIds.AssignedActivities, @@ -254,6 +266,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconCheckbox', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedWorkspaceMemberFieldMetadataIds.Favorites, @@ -269,6 +282,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconHeart', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedWorkspaceMemberFieldMetadataIds.AccountOwnerForCompanies, @@ -284,6 +298,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconBriefcase', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedWorkspaceMemberFieldMetadataIds.AuthoredAttachments, @@ -299,6 +314,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconFileImport', isNullable: true, isSystem: false, + defaultValue: undefined, }, { id: SeedWorkspaceMemberFieldMetadataIds.AuthoredComments, @@ -314,6 +330,7 @@ export const seedWorkspaceMemberFieldMetadata = async ( icon: 'IconComment', isNullable: true, isSystem: false, + defaultValue: undefined, }, ]) .execute(); diff --git a/server/src/database/typeorm/metadata/migrations/1700133603735-setupMetadataTables.ts b/server/src/database/typeorm/metadata/migrations/1700133603735-setupMetadataTables.ts deleted file mode 100644 index 3fb1affbe3b..00000000000 --- a/server/src/database/typeorm/metadata/migrations/1700133603735-setupMetadataTables.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; - -export class SetupMetadataTables1700133603735 implements MigrationInterface { - name = 'SetupMetadataTables1700133603735' - - 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(`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"."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, "isSystem" 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, "isSystem" 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"."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"."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`); - await queryRunner.query(`ALTER TABLE "metadata"."objectMetadata" ADD CONSTRAINT "FK_0b19dd17369574578bc18c405b2" FOREIGN KEY ("dataSourceId") REFERENCES "metadata"."dataSource"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); - 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`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "metadata"."fieldMetadata" DROP CONSTRAINT "FK_de2a09b9e3e690440480d2dee26"`); - await queryRunner.query(`ALTER TABLE "metadata"."objectMetadata" DROP CONSTRAINT "FK_0b19dd17369574578bc18c405b2"`); - 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"."tenantMigration"`); - await queryRunner.query(`DROP TABLE "metadata"."fieldMetadata"`); - await queryRunner.query(`DROP TABLE "metadata"."objectMetadata"`); - await queryRunner.query(`DROP TABLE "metadata"."dataSource"`); - await queryRunner.query(`DROP TYPE "metadata"."dataSource_type_enum"`); - await queryRunner.query(`DROP TABLE "metadata"."relationMetadata"`); - } - -} diff --git a/server/src/database/typeorm/metadata/migrations/1700140427984-setupMetadataTables.ts b/server/src/database/typeorm/metadata/migrations/1700140427984-setupMetadataTables.ts new file mode 100644 index 00000000000..d873257d934 --- /dev/null +++ b/server/src/database/typeorm/metadata/migrations/1700140427984-setupMetadataTables.ts @@ -0,0 +1,71 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class SetupMetadataTables1700140427984 implements MigrationInterface { + name = 'SetupMetadataTables1700140427984'; + + 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( + `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, "defaultValue" jsonb, "description" text, "icon" character varying, "enums" text array, "isCustom" boolean NOT NULL DEFAULT false, "isActive" boolean NOT NULL DEFAULT false, "isSystem" 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"."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, "isSystem" 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 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"."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`, + ); + 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"."objectMetadata" ADD CONSTRAINT "FK_0b19dd17369574578bc18c405b2" FOREIGN KEY ("dataSourceId") REFERENCES "metadata"."dataSource"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "metadata"."objectMetadata" DROP CONSTRAINT "FK_0b19dd17369574578bc18c405b2"`, + ); + await queryRunner.query( + `ALTER TABLE "metadata"."fieldMetadata" DROP CONSTRAINT "FK_de2a09b9e3e690440480d2dee26"`, + ); + 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"."tenantMigration"`); + await queryRunner.query(`DROP TABLE "metadata"."dataSource"`); + await queryRunner.query(`DROP TYPE "metadata"."dataSource_type_enum"`); + await queryRunner.query(`DROP TABLE "metadata"."objectMetadata"`); + await queryRunner.query(`DROP TABLE "metadata"."fieldMetadata"`); + await queryRunner.query(`DROP TABLE "metadata"."relationMetadata"`); + } +} 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 8881e6dd2bf..a3a49200722 100644 --- a/server/src/metadata/field-metadata/dtos/create-field.input.ts +++ b/server/src/metadata/field-metadata/dtos/create-field.input.ts @@ -2,17 +2,21 @@ import { Field, HideField, InputType } from '@nestjs/graphql'; import { BeforeCreateOne } from '@ptc-org/nestjs-query-graphql'; import { + IsBoolean, IsEnum, IsNotEmpty, IsOptional, IsString, IsUUID, } from 'class-validator'; +import { GraphQLJSONObject } from 'graphql-type-json'; -import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataDefaultValue } from 'src/metadata/field-metadata/interfaces/field-metadata-default-value.interface'; import { BeforeCreateOneField } from 'src/metadata/field-metadata/hooks/before-create-one-field.hook'; import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { IsDefaultValue } from 'src/metadata/field-metadata/validators/is-default-value.validator'; @InputType() @BeforeCreateOne(BeforeCreateOneField) @@ -21,10 +25,12 @@ export class CreateFieldInput { @IsNotEmpty() @Field() name: string; + @IsString() @IsNotEmpty() @Field() label: string; + @IsEnum(FieldMetadataType) @IsNotEmpty() @Field(() => FieldMetadataType) @@ -38,11 +44,22 @@ export class CreateFieldInput { @IsOptional() @Field({ nullable: true }) description?: string; + @IsString() @IsOptional() @Field({ nullable: true }) icon?: string; + @IsBoolean() + @IsOptional() + @Field({ nullable: true }) + isNullable: boolean; + + @IsDefaultValue({ message: 'Invalid default value for the specified type' }) + @IsOptional() + @Field(() => GraphQLJSONObject, { nullable: true }) + defaultValue: FieldMetadataDefaultValue; + @HideField() targetColumnMap: FieldMetadataTargetColumnMap; diff --git a/server/src/metadata/field-metadata/field-metadata.entity.ts b/server/src/metadata/field-metadata/field-metadata.entity.ts index ef1c160bc75..64ca615a538 100644 --- a/server/src/metadata/field-metadata/field-metadata.entity.ts +++ b/server/src/metadata/field-metadata/field-metadata.entity.ts @@ -11,7 +11,8 @@ import { } 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 { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataDefaultValue } from 'src/metadata/field-metadata/interfaces/field-metadata-default-value.interface'; import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity'; import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity'; @@ -62,6 +63,9 @@ export class FieldMetadataEntity implements FieldMetadataInterface { @Column({ nullable: false, type: 'jsonb' }) targetColumnMap: FieldMetadataTargetColumnMap; + @Column({ nullable: true, type: 'jsonb' }) + defaultValue: FieldMetadataDefaultValue; + @Column({ nullable: true, type: 'text' }) description: string; diff --git a/server/src/metadata/field-metadata/field-metadata.service.ts b/server/src/metadata/field-metadata/field-metadata.service.ts index 59bc2a04e25..9431e321b20 100644 --- a/server/src/metadata/field-metadata/field-metadata.service.ts +++ b/server/src/metadata/field-metadata/field-metadata.service.ts @@ -10,16 +10,14 @@ import { Repository } from 'typeorm'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; import { DeleteOneOptions } from '@ptc-org/nestjs-query-core'; -import { - convertFieldMetadataToColumnActions, - generateTargetColumnMap, -} from 'src/metadata/field-metadata/utils/field-metadata.util'; 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/object-metadata.service'; 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/metadata/tenant-migration/tenant-migration.entity'; +import { generateTargetColumnMap } from 'src/metadata/field-metadata/utils/generate-target-column-map.util'; +import { convertFieldMetadataToColumnActions } from 'src/metadata/field-metadata/utils/convert-field-metadata-to-column-action.util'; import { FieldMetadataEntity } from './field-metadata.entity'; diff --git a/server/src/metadata/field-metadata/interfaces/field-metadata-default-value.interface.ts b/server/src/metadata/field-metadata/interfaces/field-metadata-default-value.interface.ts new file mode 100644 index 00000000000..2a259f4ddd7 --- /dev/null +++ b/server/src/metadata/field-metadata/interfaces/field-metadata-default-value.interface.ts @@ -0,0 +1,85 @@ +import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; + +export interface FieldMetadataDefaultValueString { + value: string; +} +export interface FieldMetadataDefaultValueNumber { + value: number; +} +export interface FieldMetadataDefaultValueBoolean { + value: boolean; +} +export interface FieldMetadataDefaultValueDate { + value: Date; +} + +type FieldMetadataScalarDefaultValue = + | FieldMetadataDefaultValueString + | FieldMetadataDefaultValueNumber + | FieldMetadataDefaultValueBoolean + | FieldMetadataDefaultValueDate; + +export type FieldMetadataDynamicDefaultValue = + | { type: 'uuid' } + | { type: 'now' }; + +interface FieldMetadataDefaultValueUrl { + text: string; + link: string; +} + +interface FieldMetadataDefaultValueMoney { + amount: number; + currency: string; +} + +type AllFieldMetadataDefaultValueTypes = + | FieldMetadataScalarDefaultValue + | FieldMetadataDynamicDefaultValue + | FieldMetadataDefaultValueUrl + | FieldMetadataDefaultValueMoney; + +type FieldMetadataDefaultValueMapping = { + [FieldMetadataType.UUID]: FieldMetadataDefaultValueString; + [FieldMetadataType.TEXT]: FieldMetadataDefaultValueString; + [FieldMetadataType.PHONE]: FieldMetadataDefaultValueString; + [FieldMetadataType.EMAIL]: FieldMetadataDefaultValueString; + [FieldMetadataType.DATE]: FieldMetadataDefaultValueDate; + [FieldMetadataType.BOOLEAN]: FieldMetadataDefaultValueBoolean; + [FieldMetadataType.NUMBER]: FieldMetadataDefaultValueNumber; + [FieldMetadataType.PROBABILITY]: FieldMetadataDefaultValueNumber; + [FieldMetadataType.ENUM]: FieldMetadataDefaultValueString; + [FieldMetadataType.URL]: FieldMetadataDefaultValueUrl; + [FieldMetadataType.MONEY]: FieldMetadataDefaultValueMoney; +}; + +type DefaultValueByFieldMetadata = [ + T, +] extends [keyof FieldMetadataDefaultValueMapping] + ? FieldMetadataDefaultValueMapping[T] | null + : T extends 'default' + ? AllFieldMetadataDefaultValueTypes | null + : never; + +export type FieldMetadataDefaultValue< + T extends FieldMetadataType | 'default' = 'default', +> = DefaultValueByFieldMetadata; + +type FieldMetadataDefaultValueExtractNestedType = T extends { + value: infer U; +} + ? U + : T extends object + ? T[keyof T] + : never; + +type FieldMetadataDefaultValueExtractedTypes = { + [K in keyof FieldMetadataDefaultValueMapping]: FieldMetadataDefaultValueExtractNestedType< + FieldMetadataDefaultValueMapping[K] + >; +}; + +export type FieldMetadataDefaultSerializableValue = + | FieldMetadataDefaultValueExtractedTypes[keyof FieldMetadataDefaultValueExtractedTypes] + | FieldMetadataDynamicDefaultValue + | null; diff --git a/server/src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface.ts b/server/src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface.ts similarity index 95% rename from server/src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface.ts rename to server/src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface.ts index 65580c811b7..03f31ae0f59 100644 --- a/server/src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface.ts +++ b/server/src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface.ts @@ -10,12 +10,12 @@ export interface FieldMetadataTargetColumnMapUrl { } export interface FieldMetadataTargetColumnMapMoney { - amount: number; + amount: string; currency: string; } type AllFieldMetadataTypes = { - [key: string]: any; + [key: string]: string; }; type FieldMetadataTypeMapping = { diff --git a/server/src/metadata/field-metadata/utils/__tests__/convert-field-metadata-to-column-action.spec.ts b/server/src/metadata/field-metadata/utils/__tests__/convert-field-metadata-to-column-action.spec.ts new file mode 100644 index 00000000000..42a6180fc43 --- /dev/null +++ b/server/src/metadata/field-metadata/utils/__tests__/convert-field-metadata-to-column-action.spec.ts @@ -0,0 +1,67 @@ +import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { convertFieldMetadataToColumnActions } from 'src/metadata/field-metadata/utils/convert-field-metadata-to-column-action.util'; + +describe('convertFieldMetadataToColumnActions', () => { + it('should convert TEXT field metadata to column actions', () => { + const fieldMetadata = { + type: FieldMetadataType.TEXT, + targetColumnMap: { value: 'name' }, + defaultValue: { value: 'default text' }, + } as any; + const columnActions = convertFieldMetadataToColumnActions(fieldMetadata); + expect(columnActions).toEqual([ + { + action: 'CREATE', + columnName: 'name', + columnType: 'text', + defaultValue: "'default text'", + }, + ]); + }); + + it('should convert URL field metadata to column actions', () => { + const fieldMetadata = { + type: FieldMetadataType.URL, + targetColumnMap: { text: 'url_text', link: 'url_link' }, + defaultValue: { text: 'http://example.com', link: 'Example' }, + } as any; + const columnActions = convertFieldMetadataToColumnActions(fieldMetadata); + expect(columnActions).toEqual([ + { + action: 'CREATE', + columnName: 'url_text', + columnType: 'varchar', + defaultValue: "'http://example.com'", + }, + { + action: 'CREATE', + columnName: 'url_link', + columnType: 'varchar', + defaultValue: "'Example'", + }, + ]); + }); + + it('should convert MONEY field metadata to column actions', () => { + const fieldMetadata = { + type: FieldMetadataType.MONEY, + targetColumnMap: { amount: 'money_amount', currency: 'money_currency' }, + defaultValue: { amount: 100, currency: 'USD' }, + } as any; + const columnActions = convertFieldMetadataToColumnActions(fieldMetadata); + expect(columnActions).toEqual([ + { + action: 'CREATE', + columnName: 'money_amount', + columnType: 'integer', + defaultValue: 100, + }, + { + action: 'CREATE', + columnName: 'money_currency', + columnType: 'varchar', + defaultValue: "'USD'", + }, + ]); + }); +}); diff --git a/server/src/metadata/field-metadata/utils/field-metadata.util.spec.ts b/server/src/metadata/field-metadata/utils/__tests__/generate-target-column-map.spec.ts similarity index 59% rename from server/src/metadata/field-metadata/utils/field-metadata.util.spec.ts rename to server/src/metadata/field-metadata/utils/__tests__/generate-target-column-map.spec.ts index 187fd16d279..7e6b8edbcfd 100644 --- a/server/src/metadata/field-metadata/utils/field-metadata.util.spec.ts +++ b/server/src/metadata/field-metadata/utils/__tests__/generate-target-column-map.spec.ts @@ -1,9 +1,7 @@ -import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { BadRequestException } from '@nestjs/common'; -import { - generateTargetColumnMap, - convertFieldMetadataToColumnActions, -} from './field-metadata.util'; +import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { generateTargetColumnMap } from 'src/metadata/field-metadata/utils/generate-target-column-map.util'; describe('generateTargetColumnMap', () => { it('should generate a target column map for a given type', () => { @@ -35,23 +33,6 @@ describe('generateTargetColumnMap', () => { it('should throw an error for an unknown type', () => { expect(() => generateTargetColumnMap('invalid' as FieldMetadataType, false, 'name'), - ).toThrowError('Unknown type invalid'); - }); -}); - -describe('convertFieldMetadataToColumnActions', () => { - it('should convert field metadata to column actions', () => { - const fieldMetadata = { - type: FieldMetadataType.TEXT, - targetColumnMap: { value: 'name' }, - } as any; - const columnActions = convertFieldMetadataToColumnActions(fieldMetadata); - expect(columnActions).toEqual([ - { - action: 'CREATE', - columnName: 'name', - columnType: 'text', - }, - ]); + ).toThrow(BadRequestException); }); }); diff --git a/server/src/metadata/field-metadata/utils/__tests__/serialize-default-value.spec.ts b/server/src/metadata/field-metadata/utils/__tests__/serialize-default-value.spec.ts new file mode 100644 index 00000000000..6abae077e2b --- /dev/null +++ b/server/src/metadata/field-metadata/utils/__tests__/serialize-default-value.spec.ts @@ -0,0 +1,43 @@ +import { BadRequestException } from '@nestjs/common'; + +import { serializeDefaultValue } from 'src/metadata/field-metadata/utils/serialize-default-value'; + +describe('serializeDefaultValue', () => { + it('should return null for undefined defaultValue', () => { + expect(serializeDefaultValue()).toBeNull(); + }); + + it('should handle uuid dynamic default value', () => { + expect(serializeDefaultValue({ type: 'uuid' })).toBe('uuid_generate_v4()'); + }); + + it('should handle now dynamic default value', () => { + expect(serializeDefaultValue({ type: 'now' })).toBe('now()'); + }); + + it('should throw BadRequestException for invalid dynamic default value type', () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error Just for testing purposes + expect(() => serializeDefaultValue({ type: 'invalid' })).toThrow( + BadRequestException, + ); + }); + + it('should handle string static default value', () => { + expect(serializeDefaultValue('test')).toBe("'test'"); + }); + + it('should handle number static default value', () => { + expect(serializeDefaultValue(123)).toBe(123); + }); + + it('should handle boolean static default value', () => { + expect(serializeDefaultValue(true)).toBe(true); + expect(serializeDefaultValue(false)).toBe(false); + }); + + it('should handle Date static default value', () => { + const date = new Date('2023-01-01'); + expect(serializeDefaultValue(date)).toBe(`'${date.toISOString()}'`); + }); +}); diff --git a/server/src/metadata/field-metadata/utils/__tests__/validate-default-value-based-on-type.spec.ts b/server/src/metadata/field-metadata/utils/__tests__/validate-default-value-based-on-type.spec.ts new file mode 100644 index 00000000000..149ec172e22 --- /dev/null +++ b/server/src/metadata/field-metadata/utils/__tests__/validate-default-value-based-on-type.spec.ts @@ -0,0 +1,178 @@ +import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; +import { validateDefaultValueBasedOnType } from 'src/metadata/field-metadata/utils/validate-default-value-based-on-type.util'; + +describe('validateDefaultValueBasedOnType', () => { + it('should return true for null defaultValue', () => { + expect(validateDefaultValueBasedOnType(null, FieldMetadataType.TEXT)).toBe( + true, + ); + }); + + // Dynamic default values + it('should validate uuid dynamic default value for UUID type', () => { + expect( + validateDefaultValueBasedOnType({ type: 'uuid' }, FieldMetadataType.UUID), + ).toBe(true); + }); + + it('should validate now dynamic default value for DATE type', () => { + expect( + validateDefaultValueBasedOnType({ type: 'now' }, FieldMetadataType.DATE), + ).toBe(true); + }); + + it('should return false for mismatched dynamic default value', () => { + expect( + validateDefaultValueBasedOnType({ type: 'now' }, FieldMetadataType.UUID), + ).toBe(false); + }); + + // Static default values + it('should validate string default value for TEXT type', () => { + expect( + validateDefaultValueBasedOnType( + { value: 'test' }, + FieldMetadataType.TEXT, + ), + ).toBe(true); + }); + + it('should return false for invalid string default value for TEXT type', () => { + expect( + validateDefaultValueBasedOnType({ value: 123 }, FieldMetadataType.TEXT), + ).toBe(false); + }); + + it('should validate string default value for PHONE type', () => { + expect( + validateDefaultValueBasedOnType( + { value: '+123456789' }, + FieldMetadataType.PHONE, + ), + ).toBe(true); + }); + + it('should return false for invalid string default value for PHONE type', () => { + expect( + validateDefaultValueBasedOnType({ value: 123 }, FieldMetadataType.PHONE), + ).toBe(false); + }); + + it('should validate string default value for EMAIL type', () => { + expect( + validateDefaultValueBasedOnType( + { value: 'test@example.com' }, + FieldMetadataType.EMAIL, + ), + ).toBe(true); + }); + + it('should return false for invalid string default value for EMAIL type', () => { + expect( + validateDefaultValueBasedOnType({ value: 123 }, FieldMetadataType.EMAIL), + ).toBe(false); + }); + + it('should validate number default value for NUMBER type', () => { + expect( + validateDefaultValueBasedOnType({ value: 100 }, FieldMetadataType.NUMBER), + ).toBe(true); + }); + + it('should return false for invalid number default value for NUMBER type', () => { + expect( + validateDefaultValueBasedOnType( + { value: '100' }, + FieldMetadataType.NUMBER, + ), + ).toBe(false); + }); + + it('should validate number default value for PROBABILITY type', () => { + expect( + validateDefaultValueBasedOnType( + { value: 0.5 }, + FieldMetadataType.PROBABILITY, + ), + ).toBe(true); + }); + + it('should return false for invalid number default value for PROBABILITY type', () => { + expect( + validateDefaultValueBasedOnType( + { value: '50%' }, + FieldMetadataType.PROBABILITY, + ), + ).toBe(false); + }); + + it('should validate boolean default value for BOOLEAN type', () => { + expect( + validateDefaultValueBasedOnType( + { value: true }, + FieldMetadataType.BOOLEAN, + ), + ).toBe(true); + }); + + it('should return false for invalid boolean default value for BOOLEAN type', () => { + expect( + validateDefaultValueBasedOnType( + { value: 'true' }, + FieldMetadataType.BOOLEAN, + ), + ).toBe(false); + }); + + // URL type + it('should validate URL default value', () => { + expect( + validateDefaultValueBasedOnType( + { text: 'http://example.com', link: 'Example' }, + FieldMetadataType.URL, + ), + ).toBe(true); + }); + + it('should return false for invalid URL default value', () => { + expect( + validateDefaultValueBasedOnType( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error Just for testing purposes + { text: 123, link: {} }, + FieldMetadataType.URL, + ), + ).toBe(false); + }); + + // MONEY type + it('should validate MONEY default value', () => { + expect( + validateDefaultValueBasedOnType( + { amount: 100, currency: 'USD' }, + FieldMetadataType.MONEY, + ), + ).toBe(true); + }); + + it('should return false for invalid MONEY default value', () => { + expect( + validateDefaultValueBasedOnType( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error Just for testing purposes + { amount: '100', currency: 'USD' }, + FieldMetadataType.MONEY, + ), + ).toBe(false); + }); + + // Unknown type + it('should return false for unknown type', () => { + expect( + validateDefaultValueBasedOnType( + { value: 'test' }, + 'unknown' as FieldMetadataType, + ), + ).toBe(false); + }); +}); diff --git a/server/src/metadata/field-metadata/utils/field-metadata.util.ts b/server/src/metadata/field-metadata/utils/convert-field-metadata-to-column-action.util.ts similarity index 52% rename from server/src/metadata/field-metadata/utils/field-metadata.util.ts rename to server/src/metadata/field-metadata/utils/convert-field-metadata-to-column-action.util.ts index 04e17ea6d62..3631fcbc268 100644 --- a/server/src/metadata/field-metadata/utils/field-metadata.util.ts +++ b/server/src/metadata/field-metadata/utils/convert-field-metadata-to-column-action.util.ts @@ -1,4 +1,4 @@ -import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataDefaultValue } from 'src/metadata/field-metadata/interfaces/field-metadata-default-value.interface'; import { FieldMetadataEntity, @@ -8,119 +8,121 @@ import { TenantMigrationColumnAction, TenantMigrationColumnActionType, } from 'src/metadata/tenant-migration/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. - * This is used to support fields that map to multiple columns in the database. - * - * @param type string - * @returns FieldMetadataTargetColumnMap - */ -export function generateTargetColumnMap( - type: FieldMetadataType, - isCustomField: boolean, - fieldName: string, -): FieldMetadataTargetColumnMap { - const columnName = isCustomField ? `_${fieldName}` : fieldName; - - switch (type) { - case FieldMetadataType.TEXT: - case FieldMetadataType.PHONE: - case FieldMetadataType.EMAIL: - case FieldMetadataType.NUMBER: - case FieldMetadataType.PROBABILITY: - case FieldMetadataType.BOOLEAN: - case FieldMetadataType.DATE: - return { - value: columnName, - }; - case FieldMetadataType.URL: - return { - text: `${columnName}_text`, - link: `${columnName}_link`, - }; - case FieldMetadataType.MONEY: - return { - amount: `${columnName}_amount`, - currency: `${columnName}_currency`, - }; - default: - throw new Error(`Unknown type ${type}`); - } -} +import { serializeDefaultValue } from 'src/metadata/field-metadata/utils/serialize-default-value'; export function convertFieldMetadataToColumnActions( fieldMetadata: FieldMetadataEntity, ): TenantMigrationColumnAction[] { switch (fieldMetadata.type) { - case FieldMetadataType.TEXT: + case FieldMetadataType.TEXT: { + const defaultValue = + fieldMetadata.defaultValue as FieldMetadataDefaultValue; + return [ { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.value, columnType: 'text', + defaultValue: serializeDefaultValue(defaultValue?.value), }, ]; + } case FieldMetadataType.PHONE: - case FieldMetadataType.EMAIL: + case FieldMetadataType.EMAIL: { + const defaultValue = + fieldMetadata.defaultValue as FieldMetadataDefaultValue< + FieldMetadataType.PHONE | FieldMetadataType.EMAIL + >; + return [ { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.value, columnType: 'varchar', + defaultValue: serializeDefaultValue(defaultValue?.value), }, ]; + } case FieldMetadataType.NUMBER: - case FieldMetadataType.PROBABILITY: + case FieldMetadataType.PROBABILITY: { + const defaultValue = + fieldMetadata.defaultValue as FieldMetadataDefaultValue< + FieldMetadataType.NUMBER | FieldMetadataType.PROBABILITY + >; + return [ { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.value, columnType: 'float', + defaultValue: serializeDefaultValue(defaultValue?.value), }, ]; - case FieldMetadataType.BOOLEAN: + } + case FieldMetadataType.BOOLEAN: { + const defaultValue = + fieldMetadata.defaultValue as FieldMetadataDefaultValue; + return [ { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.value, columnType: 'boolean', + defaultValue: serializeDefaultValue(defaultValue?.value), }, ]; - case FieldMetadataType.DATE: + } + case FieldMetadataType.DATE: { + const defaultValue = + fieldMetadata.defaultValue as FieldMetadataDefaultValue; + return [ { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.value, columnType: 'timestamp', + defaultValue: serializeDefaultValue(defaultValue?.value), }, ]; - case FieldMetadataType.URL: + } + case FieldMetadataType.URL: { + const defaultValue = + fieldMetadata.defaultValue as FieldMetadataDefaultValue; + return [ { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.text, columnType: 'varchar', + defaultValue: serializeDefaultValue(defaultValue?.text), }, { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.link, columnType: 'varchar', + defaultValue: serializeDefaultValue(defaultValue?.link), }, ]; - case FieldMetadataType.MONEY: + } + case FieldMetadataType.MONEY: { + const defaultValue = + fieldMetadata.defaultValue as FieldMetadataDefaultValue; + return [ { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.amount, columnType: 'integer', + defaultValue: serializeDefaultValue(defaultValue?.amount), }, { action: TenantMigrationColumnActionType.CREATE, columnName: fieldMetadata.targetColumnMap.currency, columnType: 'varchar', + defaultValue: serializeDefaultValue(defaultValue?.currency), }, ]; + } default: throw new Error(`Unknown type ${fieldMetadata.type}`); } diff --git a/server/src/metadata/field-metadata/utils/generate-target-column-map.util.ts b/server/src/metadata/field-metadata/utils/generate-target-column-map.util.ts new file mode 100644 index 00000000000..304e035d1f9 --- /dev/null +++ b/server/src/metadata/field-metadata/utils/generate-target-column-map.util.ts @@ -0,0 +1,45 @@ +import { BadRequestException } from '@nestjs/common'; + +import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; + +import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.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. + * This is used to support fields that map to multiple columns in the database. + * + * @param type string + * @returns FieldMetadataTargetColumnMap + */ +export function generateTargetColumnMap( + type: FieldMetadataType, + isCustomField: boolean, + fieldName: string, +): FieldMetadataTargetColumnMap { + const columnName = isCustomField ? `_${fieldName}` : fieldName; + + switch (type) { + case FieldMetadataType.TEXT: + case FieldMetadataType.PHONE: + case FieldMetadataType.EMAIL: + case FieldMetadataType.NUMBER: + case FieldMetadataType.PROBABILITY: + case FieldMetadataType.BOOLEAN: + case FieldMetadataType.DATE: + return { + value: columnName, + }; + case FieldMetadataType.URL: + return { + text: `${columnName}_text`, + link: `${columnName}_link`, + }; + case FieldMetadataType.MONEY: + return { + amount: `${columnName}_amount`, + currency: `${columnName}_currency`, + }; + default: + throw new BadRequestException(`Unknown type ${type}`); + } +} diff --git a/server/src/metadata/field-metadata/utils/serialize-default-value.ts b/server/src/metadata/field-metadata/utils/serialize-default-value.ts new file mode 100644 index 00000000000..6bbea168023 --- /dev/null +++ b/server/src/metadata/field-metadata/utils/serialize-default-value.ts @@ -0,0 +1,46 @@ +import { BadRequestException } from '@nestjs/common'; + +import { FieldMetadataDefaultSerializableValue } from 'src/metadata/field-metadata/interfaces/field-metadata-default-value.interface'; + +export const serializeDefaultValue = ( + defaultValue?: FieldMetadataDefaultSerializableValue, +) => { + if (defaultValue === undefined || defaultValue === null) { + return null; + } + + // Dynamic default values + if (typeof defaultValue === 'object' && 'type' in defaultValue) { + switch (defaultValue.type) { + case 'uuid': + return 'uuid_generate_v4()'; + case 'now': + return 'now()'; + default: + throw new BadRequestException('Invalid dynamic default value type'); + } + } + + // Static default values + if (typeof defaultValue === 'string') { + return `'${defaultValue}'`; + } + + if (typeof defaultValue === 'number') { + return defaultValue; + } + + if (typeof defaultValue === 'boolean') { + return defaultValue; + } + + if (defaultValue instanceof Date) { + return `'${defaultValue.toISOString()}'`; + } + + if (typeof defaultValue === 'object') { + return `'${JSON.stringify(defaultValue)}'`; + } + + throw new BadRequestException('Invalid default value'); +}; diff --git a/server/src/metadata/field-metadata/utils/validate-default-value-based-on-type.util.ts b/server/src/metadata/field-metadata/utils/validate-default-value-based-on-type.util.ts new file mode 100644 index 00000000000..76d976001e8 --- /dev/null +++ b/server/src/metadata/field-metadata/utils/validate-default-value-based-on-type.util.ts @@ -0,0 +1,78 @@ +import { FieldMetadataDefaultValue } from 'src/metadata/field-metadata/interfaces/field-metadata-default-value.interface'; + +import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; + +export const validateDefaultValueBasedOnType = ( + defaultValue: FieldMetadataDefaultValue, + type: FieldMetadataType, +): boolean => { + if (defaultValue === null) return true; + + // Dynamic default values + if (typeof defaultValue === 'object' && 'type' in defaultValue) { + if (type === FieldMetadataType.UUID && defaultValue.type === 'uuid') { + return true; + } + if (type === FieldMetadataType.DATE && defaultValue.type === 'now') { + return true; + } + + return false; + } + + // Static default values + switch (type) { + case FieldMetadataType.TEXT: + case FieldMetadataType.PHONE: + case FieldMetadataType.EMAIL: + case FieldMetadataType.ENUM: + return ( + typeof defaultValue === 'object' && + 'value' in defaultValue && + typeof defaultValue.value === 'string' + ); + + case FieldMetadataType.NUMBER: + case FieldMetadataType.PROBABILITY: + return ( + typeof defaultValue === 'object' && + 'value' in defaultValue && + typeof defaultValue.value === 'number' + ); + + case FieldMetadataType.BOOLEAN: + return ( + typeof defaultValue === 'object' && + 'value' in defaultValue && + typeof defaultValue.value === 'boolean' + ); + + case FieldMetadataType.DATE: + return ( + typeof defaultValue === 'object' && + 'value' in defaultValue && + defaultValue.value instanceof Date + ); + + case FieldMetadataType.URL: + return ( + typeof defaultValue === 'object' && + 'text' in defaultValue && + typeof defaultValue.text === 'string' && + 'link' in defaultValue && + typeof defaultValue.link === 'string' + ); + + case FieldMetadataType.MONEY: + return ( + typeof defaultValue === 'object' && + 'amount' in defaultValue && + typeof defaultValue.amount === 'number' && + 'currency' in defaultValue && + typeof defaultValue.currency === 'string' + ); + + default: + return false; + } +}; diff --git a/server/src/metadata/field-metadata/validators/is-default-value.validator.ts b/server/src/metadata/field-metadata/validators/is-default-value.validator.ts new file mode 100644 index 00000000000..df04216af03 --- /dev/null +++ b/server/src/metadata/field-metadata/validators/is-default-value.validator.ts @@ -0,0 +1,27 @@ +import { + registerDecorator, + ValidationOptions, + ValidationArguments, +} from 'class-validator'; + +import { validateDefaultValueBasedOnType } from 'src/metadata/field-metadata/utils/validate-default-value-based-on-type.util'; + +export const IsDefaultValue = (validationOptions?: ValidationOptions) => { + return function (object: any, propertyName: string) { + registerDecorator({ + name: 'isDefaultValue', + target: object.constructor, + propertyName: propertyName, + constraints: [], + options: validationOptions, + validator: { + validate(value: any, args: ValidationArguments) { + // Extract type value from the object + const type = (args.object as any)['type']; + + return validateDefaultValueBasedOnType(value, type); + }, + }, + }); + }; +}; diff --git a/server/src/metadata/tenant-migration/tenant-migration.entity.ts b/server/src/metadata/tenant-migration/tenant-migration.entity.ts index 7841e9538c6..26d1c991c05 100644 --- a/server/src/metadata/tenant-migration/tenant-migration.entity.ts +++ b/server/src/metadata/tenant-migration/tenant-migration.entity.ts @@ -14,6 +14,7 @@ export type TenantMigrationColumnCreate = { action: TenantMigrationColumnActionType.CREATE; columnName: string; columnType: string; + defaultValue?: any; }; export type TenantMigrationColumnRelation = { diff --git a/server/src/tenant-migration-runner/tenant-migration-runner.service.ts b/server/src/tenant-migration-runner/tenant-migration-runner.service.ts index 423a6d43eca..880f2bba4df 100644 --- a/server/src/tenant-migration-runner/tenant-migration-runner.service.ts +++ b/server/src/tenant-migration-runner/tenant-migration-runner.service.ts @@ -203,6 +203,7 @@ export class TenantMigrationRunnerService { new TableColumn({ name: migrationColumn.columnName, type: migrationColumn.columnType, + default: migrationColumn.defaultValue, isNullable: true, }), ); diff --git a/server/src/tenant/schema-builder/factories/args.factory.ts b/server/src/tenant/schema-builder/factories/args.factory.ts index 17c26cf8c7a..59f226ca4ab 100644 --- a/server/src/tenant/schema-builder/factories/args.factory.ts +++ b/server/src/tenant/schema-builder/factories/args.factory.ts @@ -52,6 +52,7 @@ export class ArgsFactory { } const gqlType = this.typeMapperService.mapToGqlType(fieldType, { + defaultValue: arg.defaultValue, nullable: arg.isNullable, isArray: arg.isArray, }); 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 5beee897bf4..41c6ee19ce4 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 @@ -75,6 +75,7 @@ export class FilterTypeDefinitionFactory { const type = this.filterTypeFactory.create(fieldMetadata, options, { nullable: fieldMetadata.isNullable, + defaultValue: fieldMetadata.defaultValue, }); fields[fieldMetadata.name] = { 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 ff42a5bc9ee..12d1efd8630 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 @@ -60,6 +60,7 @@ export class InputTypeDefinitionFactory { const type = this.inputTypeFactory.create(fieldMetadata, kind, options, { nullable: fieldMetadata.isNullable, + defaultValue: fieldMetadata.defaultValue, }); fields[fieldMetadata.name] = { diff --git a/server/src/tenant/schema-builder/graphql-types/scalars/uuid.scalar.ts b/server/src/tenant/schema-builder/graphql-types/scalars/uuid.scalar.ts index 328d3335aa3..de46e2fc906 100644 --- a/server/src/tenant/schema-builder/graphql-types/scalars/uuid.scalar.ts +++ b/server/src/tenant/schema-builder/graphql-types/scalars/uuid.scalar.ts @@ -1,22 +1,22 @@ import { GraphQLScalarType, Kind } from 'graphql'; +import { validate as uuidValidate } from 'uuid'; + +const checkUUID = (value: any): string => { + if (typeof value !== 'string') { + throw new Error('UUID must be a string'); + } + if (!uuidValidate(value)) { + throw new Error('Invalid UUID'); + } + + return value; +}; export const UUIDScalarType = new GraphQLScalarType({ name: 'UUID', description: 'A UUID scalar type', - serialize(value: string): string { - if (typeof value !== 'string') { - throw new Error('UUID must be a string'); - } - - return value; - }, - parseValue(value: string): string { - if (typeof value !== 'string') { - throw new Error('UUID must be a string'); - } - - return value; - }, + serialize: checkUUID, + parseValue: checkUUID, parseLiteral(ast): string { if (ast.kind !== Kind.STRING) { throw new Error('UUID must be a 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 924b57bcbe9..8fd827c43f4 100644 --- a/server/src/tenant/schema-builder/interfaces/field-metadata.interface.ts +++ b/server/src/tenant/schema-builder/interfaces/field-metadata.interface.ts @@ -1,4 +1,5 @@ -import { FieldMetadataTargetColumnMap } from 'src/tenant/schema-builder/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface'; +import { FieldMetadataDefaultValue } from 'src/metadata/field-metadata/interfaces/field-metadata-default-value.interface'; import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity'; @@ -11,6 +12,7 @@ export interface FieldMetadataInterface< name: string; label: string; targetColumnMap: FieldMetadataTargetColumnMap; + defaultValue?: FieldMetadataDefaultValue; objectMetadataId: string; description?: string; isNullable?: boolean; 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 79f7df81036..6c8e0fa6660 100644 --- a/server/src/tenant/schema-builder/interfaces/param-metadata.interface.ts +++ b/server/src/tenant/schema-builder/interfaces/param-metadata.interface.ts @@ -3,11 +3,12 @@ import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.en import { ObjectMetadataInterface } from './object-metadata.interface'; -export interface ArgMetadata { +export interface ArgMetadata { kind?: InputTypeDefinitionKind; type?: FieldMetadataType; isNullable?: boolean; isArray?: boolean; + defaultValue?: T; } export interface ArgsMetadata { 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 1daa66a3343..b3b6fe5ee0e 100644 --- a/server/src/tenant/schema-builder/services/type-mapper.service.ts +++ b/server/src/tenant/schema-builder/services/type-mapper.service.ts @@ -129,7 +129,7 @@ export class TypeMapperService { ); } - if (!options.nullable) { + if (!options.nullable && !options.defaultValue) { graphqlType = new GraphQLNonNull(graphqlType) as unknown as T; }