diff --git a/server/src/coreV2/user/services/user.service.spec.ts b/server/src/coreV2/user/services/user.service.spec.ts index 519b867928..b73bfe936a 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 69204ac30a..00d956d767 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 4d030e23e0..5084f91538 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 e70bd23d9e..6be643f827 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 69f35e21f1..0db186598e 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 1ed9c1b62d..753416f235 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 6397dd6546..c77f97fbea 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 113bcd3e90..bcd49fd518 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 6c6551af7b..28e6537c04 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 b99404a5a8..67b645c983 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 3d4a5eb746..244c069fc3 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 b5e59f48a0..12bddc5cbb 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 66b5c13bda..463b310197 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 039e5ebf5f..edca3289dc 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 12e4090770..a9203e6103 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 245a54c0fb..a657cf1589 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 05880a101d..b79ccb9ca3 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 3fb1affbe3..0000000000 --- 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 0000000000..d873257d93 --- /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 8881e6dd2b..a3a4920072 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 ef1c160bc7..64ca615a53 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 59bc2a04e2..9431e321b2 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 0000000000..2a259f4ddd --- /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 65580c811b..03f31ae0f5 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 0000000000..42a6180fc4 --- /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 187fd16d27..7e6b8edbcf 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 0000000000..6abae077e2 --- /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 0000000000..149ec172e2 --- /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 04e17ea6d6..3631fcbc26 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 0000000000..304e035d1f --- /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 0000000000..6bbea16802 --- /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 0000000000..76d976001e --- /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 0000000000..df04216af0 --- /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 7841e9538c..26d1c991c0 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 423a6d43ec..880f2bba4d 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 17c26cf8c7..59f226ca4a 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 5beee897bf..41c6ee19ce 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 ff42a5bc9e..12d1efd863 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 328d3335aa..de46e2fc90 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 924b57bcbe..8fd827c43f 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 79f7df8103..6c8e0fa666 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 1daa66a334..b3b6fe5ee0 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; }