mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-23 03:51:36 +03:00
Fix Tasks/Notes created with null position (#9068)
Fixes https://github.com/twentyhq/twenty/issues/8810 Fixes https://github.com/twentyhq/twenty/issues/5268 Fixes https://github.com/twentyhq/twenty/issues/8971 - Fixing Task/Note creation not sending position during creation - Adding a command to backfill position being null, using existing backfill command. - Removed unused backfill job. - Updated workspace entities to set position non-nullable and set a default value to make it non-required on the API - Updated position factory to set a default position for all objects having a POSITION field instead of only company/people - Moved the try/catch in each resolver factory calling GraphqlQueryRunnerException handler, makes more sense to call it in the actual graphql-query-runner and removing some duplicate codes - Adding validations for input in QueryRunnerArgs factories - Allow sync-metadata to override and sync defaultValues for certain field types (that can't be updated by users) - Removing health-check from sync-metadata command during force mode to improve performances
This commit is contained in:
parent
2ceb1c87b3
commit
5a27491bb2
@ -31,7 +31,7 @@ export const useOpenCreateActivityDrawer = ({
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const { createOneRecord: createOneActivity } = useCreateOneRecord<
|
||||
Task | Note
|
||||
(Task | Note) & { position: 'first' | 'last' }
|
||||
>({
|
||||
objectNameSingular: activityObjectNameSingular,
|
||||
});
|
||||
@ -74,6 +74,7 @@ export const useOpenCreateActivityDrawer = ({
|
||||
|
||||
const activity = await createOneActivity({
|
||||
assigneeId: customAssignee?.id,
|
||||
position: 'last',
|
||||
});
|
||||
|
||||
if (targetableObjects.length > 0) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { DatabaseCommandModule } from 'src/database/commands/database-command.module';
|
||||
import { WorkspaceHealthCommandModule } from 'src/engine/workspace-manager/workspace-health/commands/workspace-health-command.module';
|
||||
import { WorkspaceCleanerModule } from 'src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module';
|
||||
import { AppModule } from 'src/app.module';
|
||||
import { WorkspaceMigrationRunnerCommandsModule } from 'src/engine/workspace-manager/workspace-migration-runner/commands/workspace-sync-metadata-commands.module';
|
||||
import { DatabaseCommandModule } from 'src/database/commands/database-command.module';
|
||||
import { WorkspaceCleanerModule } from 'src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module';
|
||||
import { WorkspaceHealthCommandModule } from 'src/engine/workspace-manager/workspace-health/commands/workspace-health-command.module';
|
||||
import { WorkspaceMigrationRunnerCommandsModule } from 'src/engine/workspace-manager/workspace-migration-runner/commands/workspace-migration-runner-commands.module';
|
||||
import { WorkspaceSyncMetadataCommandsModule } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module';
|
||||
|
||||
@Module({
|
||||
|
@ -10,6 +10,7 @@ import { ConfirmationQuestion } from 'src/database/commands/questions/confirmati
|
||||
import { UpgradeTo0_32CommandModule } from 'src/database/commands/upgrade-version/0-32/0-32-upgrade-version.module';
|
||||
import { UpgradeTo0_33CommandModule } from 'src/database/commands/upgrade-version/0-33/0-33-upgrade-version.module';
|
||||
import { UpgradeTo0_34CommandModule } from 'src/database/commands/upgrade-version/0-34/0-34-upgrade-version.module';
|
||||
import { UpgradeTo0_40CommandModule } from 'src/database/commands/upgrade-version/0-40/0-40-upgrade-version.module';
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
@ -52,6 +53,7 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp
|
||||
UpgradeTo0_33CommandModule,
|
||||
UpgradeTo0_34CommandModule,
|
||||
FeatureFlagModule,
|
||||
UpgradeTo0_40CommandModule,
|
||||
],
|
||||
providers: [
|
||||
DataSeedWorkspaceCommand,
|
||||
|
@ -0,0 +1,36 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { ActiveWorkspacesCommandRunner } from 'src/database/commands/active-workspaces.command';
|
||||
import { BaseCommandOptions } from 'src/database/commands/base.command';
|
||||
import { RecordPositionBackfillService } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
|
||||
@Command({
|
||||
name: 'migrate-0.40:backfill-record-position',
|
||||
description: 'Backfill record position',
|
||||
})
|
||||
export class RecordPositionBackfillCommand extends ActiveWorkspacesCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(Workspace, 'core')
|
||||
protected readonly workspaceRepository: Repository<Workspace>,
|
||||
private readonly recordPositionBackfillService: RecordPositionBackfillService,
|
||||
) {
|
||||
super(workspaceRepository);
|
||||
}
|
||||
|
||||
async executeActiveWorkspacesCommand(
|
||||
_passedParam: string[],
|
||||
options: BaseCommandOptions,
|
||||
workspaceIds: string[],
|
||||
): Promise<void> {
|
||||
for (const workspaceId of workspaceIds) {
|
||||
await this.recordPositionBackfillService.backfill(
|
||||
workspaceId,
|
||||
options.dryRun ?? false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { ActiveWorkspacesCommandRunner } from 'src/database/commands/active-workspaces.command';
|
||||
import { BaseCommandOptions } from 'src/database/commands/base.command';
|
||||
import { RecordPositionBackfillCommand } from 'src/database/commands/upgrade-version/0-40/0-40-record-position-backfill.command';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { SyncWorkspaceMetadataCommand } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade-0.40',
|
||||
description: 'Upgrade to 0.40',
|
||||
})
|
||||
export class UpgradeTo0_40Command extends ActiveWorkspacesCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(Workspace, 'core')
|
||||
protected readonly workspaceRepository: Repository<Workspace>,
|
||||
private readonly recordPositionBackfillCommand: RecordPositionBackfillCommand,
|
||||
private readonly syncWorkspaceMetadataCommand: SyncWorkspaceMetadataCommand,
|
||||
) {
|
||||
super(workspaceRepository);
|
||||
}
|
||||
|
||||
async executeActiveWorkspacesCommand(
|
||||
passedParam: string[],
|
||||
options: BaseCommandOptions,
|
||||
workspaceIds: string[],
|
||||
): Promise<void> {
|
||||
await this.recordPositionBackfillCommand.executeActiveWorkspacesCommand(
|
||||
passedParam,
|
||||
options,
|
||||
workspaceIds,
|
||||
);
|
||||
|
||||
await this.syncWorkspaceMetadataCommand.executeActiveWorkspacesCommand(
|
||||
passedParam,
|
||||
{
|
||||
...options,
|
||||
force: true,
|
||||
},
|
||||
workspaceIds,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { RecordPositionBackfillCommand } from 'src/database/commands/upgrade-version/0-40/0-40-record-position-backfill.command';
|
||||
import { UpgradeTo0_40Command } from 'src/database/commands/upgrade-version/0-40/0-40-upgrade-version.command';
|
||||
import { RecordPositionBackfillModule } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-module';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { WorkspaceSyncMetadataCommandsModule } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Workspace], 'core'),
|
||||
WorkspaceSyncMetadataCommandsModule,
|
||||
RecordPositionBackfillModule,
|
||||
],
|
||||
providers: [UpgradeTo0_40Command, RecordPositionBackfillCommand],
|
||||
})
|
||||
export class UpgradeTo0_40CommandModule {}
|
@ -18,6 +18,7 @@ import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/
|
||||
import { ApiEventEmitterService } from 'src/engine/api/graphql/graphql-query-runner/services/api-event-emitter.service';
|
||||
import { QueryResultGettersFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/query-result-getters.factory';
|
||||
import { QueryRunnerArgsFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/query-runner-args.factory';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
|
||||
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
@ -56,77 +57,81 @@ export abstract class GraphqlQueryBaseResolverService<
|
||||
args: Input,
|
||||
options: WorkspaceQueryRunnerOptions,
|
||||
operationName: WorkspaceResolverBuilderMethodNames,
|
||||
): Promise<Response> {
|
||||
const { authContext, objectMetadataItemWithFieldMaps } = options;
|
||||
): Promise<Response | undefined> {
|
||||
try {
|
||||
const { authContext, objectMetadataItemWithFieldMaps } = options;
|
||||
|
||||
await this.validate(args, options);
|
||||
await this.validate(args, options);
|
||||
|
||||
const hookedArgs =
|
||||
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||
const hookedArgs =
|
||||
await this.workspaceQueryHookService.executePreQueryHooks(
|
||||
authContext,
|
||||
objectMetadataItemWithFieldMaps.nameSingular,
|
||||
operationName,
|
||||
args,
|
||||
);
|
||||
|
||||
const computedArgs = (await this.queryRunnerArgsFactory.create(
|
||||
hookedArgs,
|
||||
options,
|
||||
ResolverArgsType[capitalize(operationName)],
|
||||
)) as Input;
|
||||
|
||||
const dataSource =
|
||||
await this.twentyORMGlobalManager.getDataSourceForWorkspace(
|
||||
authContext.workspace.id,
|
||||
);
|
||||
|
||||
const repository = dataSource.getRepository(
|
||||
objectMetadataItemWithFieldMaps.nameSingular,
|
||||
);
|
||||
|
||||
const graphqlQueryParser = new GraphqlQueryParser(
|
||||
objectMetadataItemWithFieldMaps.fieldsByName,
|
||||
options.objectMetadataMaps,
|
||||
);
|
||||
|
||||
const selectedFields = graphqlFields(options.info);
|
||||
|
||||
const graphqlQuerySelectedFieldsResult =
|
||||
graphqlQueryParser.parseSelectedFields(
|
||||
objectMetadataItemWithFieldMaps,
|
||||
selectedFields,
|
||||
);
|
||||
|
||||
const graphqlQueryResolverExecutionArgs = {
|
||||
args: computedArgs,
|
||||
options,
|
||||
dataSource,
|
||||
repository,
|
||||
graphqlQueryParser,
|
||||
graphqlQuerySelectedFieldsResult,
|
||||
};
|
||||
|
||||
const results = await this.resolve(graphqlQueryResolverExecutionArgs);
|
||||
|
||||
const resultWithGetters = await this.queryResultGettersFactory.create(
|
||||
results,
|
||||
objectMetadataItemWithFieldMaps,
|
||||
authContext.workspace.id,
|
||||
options.objectMetadataMaps,
|
||||
);
|
||||
|
||||
const resultWithGettersArray = Array.isArray(resultWithGetters)
|
||||
? resultWithGetters
|
||||
: [resultWithGetters];
|
||||
|
||||
await this.workspaceQueryHookService.executePostQueryHooks(
|
||||
authContext,
|
||||
objectMetadataItemWithFieldMaps.nameSingular,
|
||||
operationName,
|
||||
args,
|
||||
resultWithGettersArray,
|
||||
);
|
||||
|
||||
const computedArgs = (await this.queryRunnerArgsFactory.create(
|
||||
hookedArgs,
|
||||
options,
|
||||
ResolverArgsType[capitalize(operationName)],
|
||||
)) as Input;
|
||||
|
||||
const dataSource =
|
||||
await this.twentyORMGlobalManager.getDataSourceForWorkspace(
|
||||
authContext.workspace.id,
|
||||
);
|
||||
|
||||
const repository = dataSource.getRepository(
|
||||
objectMetadataItemWithFieldMaps.nameSingular,
|
||||
);
|
||||
|
||||
const graphqlQueryParser = new GraphqlQueryParser(
|
||||
objectMetadataItemWithFieldMaps.fieldsByName,
|
||||
options.objectMetadataMaps,
|
||||
);
|
||||
|
||||
const selectedFields = graphqlFields(options.info);
|
||||
|
||||
const graphqlQuerySelectedFieldsResult =
|
||||
graphqlQueryParser.parseSelectedFields(
|
||||
objectMetadataItemWithFieldMaps,
|
||||
selectedFields,
|
||||
);
|
||||
|
||||
const graphqlQueryResolverExecutionArgs = {
|
||||
args: computedArgs,
|
||||
options,
|
||||
dataSource,
|
||||
repository,
|
||||
graphqlQueryParser,
|
||||
graphqlQuerySelectedFieldsResult,
|
||||
};
|
||||
|
||||
const results = await this.resolve(graphqlQueryResolverExecutionArgs);
|
||||
|
||||
const resultWithGetters = await this.queryResultGettersFactory.create(
|
||||
results,
|
||||
objectMetadataItemWithFieldMaps,
|
||||
authContext.workspace.id,
|
||||
options.objectMetadataMaps,
|
||||
);
|
||||
|
||||
const resultWithGettersArray = Array.isArray(resultWithGetters)
|
||||
? resultWithGetters
|
||||
: [resultWithGetters];
|
||||
|
||||
await this.workspaceQueryHookService.executePostQueryHooks(
|
||||
authContext,
|
||||
objectMetadataItemWithFieldMaps.nameSingular,
|
||||
operationName,
|
||||
resultWithGettersArray,
|
||||
);
|
||||
|
||||
return resultWithGetters;
|
||||
return resultWithGetters;
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, options);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract resolve(
|
||||
|
@ -83,8 +83,6 @@ export class GraphqlQueryCreateOneResolverService extends GraphqlQueryBaseResolv
|
||||
});
|
||||
}
|
||||
|
||||
async;
|
||||
|
||||
async validate(
|
||||
args: CreateOneResolverArgs<Partial<ObjectRecord>>,
|
||||
options: WorkspaceQueryRunnerOptions,
|
||||
|
@ -45,7 +45,7 @@ export class RecordPositionQueryFactory {
|
||||
objectMetadata: { isCustom: boolean; nameSingular: string },
|
||||
dataSourceSchema: string,
|
||||
): [RecordPositionQuery, RecordPositionQueryParams] {
|
||||
const name = computeTableName(
|
||||
const tableName = computeTableName(
|
||||
objectMetadata.nameSingular,
|
||||
objectMetadata.isCustom,
|
||||
);
|
||||
@ -54,17 +54,17 @@ export class RecordPositionQueryFactory {
|
||||
case RecordPositionQueryType.FIND_BY_POSITION:
|
||||
return this.buildFindByPositionQuery(
|
||||
recordPositionQueryArgs satisfies FindByPositionQueryArgs,
|
||||
name,
|
||||
tableName,
|
||||
dataSourceSchema,
|
||||
);
|
||||
case RecordPositionQueryType.FIND_MIN_POSITION:
|
||||
return this.buildFindMinPositionQuery(name, dataSourceSchema);
|
||||
return this.buildFindMinPositionQuery(tableName, dataSourceSchema);
|
||||
case RecordPositionQueryType.FIND_MAX_POSITION:
|
||||
return this.buildFindMaxPositionQuery(name, dataSourceSchema);
|
||||
return this.buildFindMaxPositionQuery(tableName, dataSourceSchema);
|
||||
case RecordPositionQueryType.UPDATE_POSITION:
|
||||
return this.buildUpdatePositionQuery(
|
||||
recordPositionQueryArgs satisfies UpdatePositionQueryArgs,
|
||||
name,
|
||||
tableName,
|
||||
dataSourceSchema,
|
||||
);
|
||||
default:
|
||||
|
@ -1,56 +0,0 @@
|
||||
import { Command, CommandRunner, Option } from 'nest-commander';
|
||||
|
||||
import {
|
||||
RecordPositionBackfillJob,
|
||||
RecordPositionBackfillJobData,
|
||||
} from 'src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job';
|
||||
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
|
||||
export type RecordPositionBackfillCommandOptions = {
|
||||
workspaceId: string;
|
||||
dryRun?: boolean;
|
||||
};
|
||||
|
||||
@Command({
|
||||
name: 'migrate-0.20:backfill-record-position',
|
||||
description: 'Backfill record position',
|
||||
})
|
||||
export class RecordPositionBackfillCommand extends CommandRunner {
|
||||
constructor(
|
||||
@InjectMessageQueue(MessageQueue.recordPositionBackfillQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@Option({
|
||||
flags: '-w, --workspace-id [workspace_id]',
|
||||
description: 'workspace id',
|
||||
required: true,
|
||||
})
|
||||
parseWorkspaceId(value: string): string {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Option({
|
||||
flags: '-d, --dry-run [dry run]',
|
||||
description: 'Dry run: Log backfill actions.',
|
||||
required: false,
|
||||
})
|
||||
dryRun(value: string): boolean {
|
||||
return Boolean(value);
|
||||
}
|
||||
|
||||
async run(
|
||||
_passedParam: string[],
|
||||
options: RecordPositionBackfillCommandOptions,
|
||||
): Promise<void> {
|
||||
this.messageQueueService.add<RecordPositionBackfillJobData>(
|
||||
RecordPositionBackfillJob.name,
|
||||
{ workspaceId: options.workspaceId, dryRun: options.dryRun ?? false },
|
||||
{ retryLimit: 3 },
|
||||
);
|
||||
}
|
||||
}
|
@ -18,6 +18,23 @@ describe('QueryRunnerArgsFactory', () => {
|
||||
objectMetadataItemWithFieldMaps: {
|
||||
isCustom: true,
|
||||
nameSingular: 'testNumber',
|
||||
fields: [
|
||||
{
|
||||
type: FieldMetadataType.POSITION,
|
||||
isCustom: true,
|
||||
nameSingular: 'position',
|
||||
},
|
||||
{
|
||||
type: FieldMetadataType.NUMBER,
|
||||
isCustom: true,
|
||||
nameSingular: 'testNumber',
|
||||
},
|
||||
{
|
||||
type: FieldMetadataType.TEXT,
|
||||
isCustom: true,
|
||||
nameSingular: 'otherField',
|
||||
},
|
||||
],
|
||||
fieldsByName: {
|
||||
position: {
|
||||
type: FieldMetadataType.POSITION,
|
||||
|
@ -17,7 +17,6 @@ import {
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { hasPositionField } from 'src/engine/metadata-modules/object-metadata/utils/has-position-field.util';
|
||||
import { FieldMetadataMap } from 'src/engine/metadata-modules/types/field-metadata-map';
|
||||
|
||||
import { RecordPositionFactory } from './record-position.factory';
|
||||
@ -39,9 +38,10 @@ export class QueryRunnerArgsFactory {
|
||||
const fieldMetadataMapByNameByName =
|
||||
options.objectMetadataItemWithFieldMaps.fieldsByName;
|
||||
|
||||
const shouldBackfillPosition = hasPositionField(
|
||||
options.objectMetadataItemWithFieldMaps,
|
||||
);
|
||||
const shouldBackfillPosition =
|
||||
options.objectMetadataItemWithFieldMaps.fields.some(
|
||||
(field) => field.type === FieldMetadataType.POSITION,
|
||||
);
|
||||
|
||||
switch (resolverArgsType) {
|
||||
case ResolverArgsType.CreateOne:
|
||||
|
@ -2,12 +2,12 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import {
|
||||
RecordPositionQueryArgs,
|
||||
RecordPositionQueryFactory,
|
||||
RecordPositionQueryType,
|
||||
} from 'src/engine/api/graphql/workspace-query-builder/factories/record-position-query.factory';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
|
||||
@Injectable()
|
||||
export class RecordPositionFactory {
|
||||
|
@ -1,24 +0,0 @@
|
||||
import { RecordPositionBackfillService } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-service';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
|
||||
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
|
||||
|
||||
export type RecordPositionBackfillJobData = {
|
||||
workspaceId: string;
|
||||
dryRun: boolean;
|
||||
};
|
||||
|
||||
@Processor(MessageQueue.recordPositionBackfillQueue)
|
||||
export class RecordPositionBackfillJob {
|
||||
constructor(
|
||||
private readonly recordPositionBackfillService: RecordPositionBackfillService,
|
||||
) {}
|
||||
|
||||
@Process(RecordPositionBackfillJob.name)
|
||||
async handle(data: RecordPositionBackfillJobData): Promise<void> {
|
||||
await this.recordPositionBackfillService.backfill(
|
||||
data.workspaceId,
|
||||
data.dryRun,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { RecordPositionBackfillJob } from 'src/engine/api/graphql/workspace-query-runner/jobs/record-position-backfill.job';
|
||||
import { RecordPositionBackfillModule } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-module';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
WorkspaceDataSourceModule,
|
||||
DataSourceModule,
|
||||
RecordPositionBackfillModule,
|
||||
],
|
||||
providers: [RecordPositionBackfillJob],
|
||||
})
|
||||
export class WorkspaceQueryRunnerJobModule {}
|
@ -1,15 +1,17 @@
|
||||
import { TestingModule, Test } from '@nestjs/testing';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||
|
||||
import { RecordPositionQueryFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/record-position-query.factory';
|
||||
import { RecordPositionFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/record-position.factory';
|
||||
import { RecordPositionBackfillService } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-service';
|
||||
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
|
||||
describe('RecordPositionBackfillService', () => {
|
||||
let recordPositionQueryFactory;
|
||||
let recordPositionFactory;
|
||||
let objectMetadataService;
|
||||
let objectMetadataRepository;
|
||||
let workspaceDataSourceService;
|
||||
|
||||
let service: RecordPositionBackfillService;
|
||||
@ -27,8 +29,8 @@ describe('RecordPositionBackfillService', () => {
|
||||
]),
|
||||
};
|
||||
|
||||
objectMetadataService = {
|
||||
findManyWithinWorkspace: jest.fn().mockReturnValue([]),
|
||||
objectMetadataRepository = {
|
||||
find: jest.fn().mockReturnValue([]),
|
||||
};
|
||||
|
||||
workspaceDataSourceService = {
|
||||
@ -51,8 +53,8 @@ describe('RecordPositionBackfillService', () => {
|
||||
useValue: workspaceDataSourceService,
|
||||
},
|
||||
{
|
||||
provide: ObjectMetadataService,
|
||||
useValue: objectMetadataService,
|
||||
provide: getRepositoryToken(ObjectMetadataEntity, 'metadata'),
|
||||
useValue: objectMetadataRepository,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
@ -76,23 +78,23 @@ describe('RecordPositionBackfillService', () => {
|
||||
});
|
||||
|
||||
it('when objectMetadata without position, should do nothing', async () => {
|
||||
objectMetadataService.findManyWithinWorkspace.mockReturnValue([
|
||||
{
|
||||
id: '1',
|
||||
nameSingular: 'name',
|
||||
fields: [],
|
||||
},
|
||||
]);
|
||||
objectMetadataRepository.find.mockReturnValue([]);
|
||||
await service.backfill('workspaceId', false);
|
||||
expect(workspaceDataSourceService.executeRawQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('when objectMetadata but all record with position, should create and run query once', async () => {
|
||||
objectMetadataService.findManyWithinWorkspace.mockReturnValue([
|
||||
objectMetadataRepository.find.mockReturnValue([
|
||||
{
|
||||
id: '1',
|
||||
nameSingular: 'company',
|
||||
fields: [],
|
||||
fields: [
|
||||
{
|
||||
type: FieldMetadataType.POSITION,
|
||||
isCustom: true,
|
||||
nameSingular: 'position',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
await service.backfill('workspaceId', false);
|
||||
@ -100,11 +102,17 @@ describe('RecordPositionBackfillService', () => {
|
||||
});
|
||||
|
||||
it('when record without position, should create and run query twice', async () => {
|
||||
objectMetadataService.findManyWithinWorkspace.mockReturnValue([
|
||||
objectMetadataRepository.find.mockReturnValue([
|
||||
{
|
||||
id: '1',
|
||||
nameSingular: 'company',
|
||||
fields: [],
|
||||
fields: [
|
||||
{
|
||||
type: FieldMetadataType.POSITION,
|
||||
isCustom: true,
|
||||
nameSingular: 'position',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
workspaceDataSourceService.executeRawQuery.mockResolvedValueOnce([
|
||||
@ -119,11 +127,17 @@ describe('RecordPositionBackfillService', () => {
|
||||
});
|
||||
|
||||
it('when dryRun is true, should not update position', async () => {
|
||||
objectMetadataService.findManyWithinWorkspace.mockReturnValue([
|
||||
objectMetadataRepository.find.mockReturnValue([
|
||||
{
|
||||
id: '1',
|
||||
nameSingular: 'company',
|
||||
fields: [],
|
||||
fields: [
|
||||
{
|
||||
type: FieldMetadataType.POSITION,
|
||||
isCustom: true,
|
||||
nameSingular: 'position',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
workspaceDataSourceService.executeRawQuery.mockResolvedValueOnce([
|
||||
|
@ -1,13 +1,17 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||
import { RecordPositionQueryFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/record-position-query.factory';
|
||||
import { RecordPositionFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/record-position.factory';
|
||||
import { RecordPositionBackfillService } from 'src/engine/api/graphql/workspace-query-runner/services/record-position-backfill-service';
|
||||
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceDataSourceModule, ObjectMetadataModule],
|
||||
imports: [
|
||||
WorkspaceDataSourceModule,
|
||||
TypeOrmModule.forFeature([ObjectMetadataEntity], 'metadata'),
|
||||
],
|
||||
providers: [
|
||||
RecordPositionFactory,
|
||||
RecordPositionQueryFactory,
|
||||
|
@ -1,21 +1,24 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import {
|
||||
RecordPositionQueryFactory,
|
||||
RecordPositionQueryType,
|
||||
} from 'src/engine/api/graphql/workspace-query-builder/factories/record-position-query.factory';
|
||||
import { RecordPositionFactory } from 'src/engine/api/graphql/workspace-query-runner/factories/record-position.factory';
|
||||
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
||||
import { hasPositionField } from 'src/engine/metadata-modules/object-metadata/utils/has-position-field.util';
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
|
||||
@Injectable()
|
||||
export class RecordPositionBackfillService {
|
||||
private readonly logger = new Logger(RecordPositionBackfillService.name);
|
||||
constructor(
|
||||
private readonly objectMetadataService: ObjectMetadataService,
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
private readonly recordPositionFactory: RecordPositionFactory,
|
||||
private readonly recordPositionQueryFactory: RecordPositionQueryFactory,
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
@ -29,15 +32,20 @@ export class RecordPositionBackfillService {
|
||||
const dataSourceSchema =
|
||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||
|
||||
const objectMetadataEntities =
|
||||
await this.objectMetadataService.findManyWithinWorkspace(workspaceId, {
|
||||
where: { isSystem: false },
|
||||
});
|
||||
const objectMetadataCollection = await this.objectMetadataRepository.find({
|
||||
where: {
|
||||
workspaceId,
|
||||
fields: {
|
||||
name: 'position',
|
||||
type: FieldMetadataType.POSITION,
|
||||
},
|
||||
},
|
||||
relations: {
|
||||
fields: true,
|
||||
},
|
||||
});
|
||||
|
||||
const objectMetadataWithPosition =
|
||||
objectMetadataEntities.filter(hasPositionField);
|
||||
|
||||
for (const objectMetadata of objectMetadataWithPosition) {
|
||||
for (const objectMetadata of objectMetadataCollection) {
|
||||
const [recordsWithoutPositionQuery, recordsWithoutPositionQueryParams] =
|
||||
this.recordPositionQueryFactory.create(
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { QueryFailedError } from 'typeorm';
|
||||
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
|
||||
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
@ -20,7 +20,7 @@ import {
|
||||
|
||||
export const workspaceQueryRunnerGraphqlApiExceptionHandler = (
|
||||
error: Error,
|
||||
context: WorkspaceSchemaBuilderContext,
|
||||
context: WorkspaceQueryRunnerOptions,
|
||||
) => {
|
||||
if (error instanceof QueryFailedError) {
|
||||
if (
|
||||
@ -96,6 +96,7 @@ export const workspaceQueryRunnerGraphqlApiExceptionHandler = (
|
||||
case GraphqlQueryRunnerExceptionCode.UNSUPPORTED_OPERATOR:
|
||||
case GraphqlQueryRunnerExceptionCode.ARGS_CONFLICT:
|
||||
case GraphqlQueryRunnerExceptionCode.FIELD_NOT_FOUND:
|
||||
case GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT:
|
||||
throw new UserInputError(error.message);
|
||||
case GraphqlQueryRunnerExceptionCode.RECORD_NOT_FOUND:
|
||||
throw new NotFoundError(error.message);
|
||||
|
@ -2,7 +2,6 @@ import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { WorkspaceQueryBuilderModule } from 'src/engine/api/graphql/workspace-query-builder/workspace-query-builder.module';
|
||||
import { RecordPositionBackfillCommand } from 'src/engine/api/graphql/workspace-query-runner/commands/0-20-record-position-backfill.command';
|
||||
import { workspaceQueryRunnerFactories } from 'src/engine/api/graphql/workspace-query-runner/factories';
|
||||
import { TelemetryListener } from 'src/engine/api/graphql/workspace-query-runner/listeners/telemetry.listener';
|
||||
import { WorkspaceQueryHookModule } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.module';
|
||||
@ -35,7 +34,6 @@ import { EntityEventsToDbListener } from './listeners/entity-events-to-db.listen
|
||||
...workspaceQueryRunnerFactories,
|
||||
EntityEventsToDbListener,
|
||||
TelemetryListener,
|
||||
RecordPositionBackfillCommand,
|
||||
],
|
||||
exports: [...workspaceQueryRunnerFactories],
|
||||
})
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryCreateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class CreateManyResolverFactory
|
||||
@ -27,23 +26,19 @@ export class CreateManyResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, _context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
CreateManyResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, context);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
CreateManyResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryCreateOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-one-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class CreateOneResolverFactory
|
||||
@ -27,23 +26,19 @@ export class CreateOneResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, _context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
CreateOneResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
CreateOneResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryDeleteManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-many-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteManyResolverFactory
|
||||
@ -27,23 +26,19 @@ export class DeleteManyResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
DeleteManyResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
DeleteManyResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryDeleteOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-one-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteOneResolverFactory
|
||||
@ -27,23 +26,19 @@ export class DeleteOneResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
DeleteOneResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
DeleteOneResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryDestroyManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class DestroyManyResolverFactory
|
||||
@ -27,23 +26,19 @@ export class DestroyManyResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
DestroyManyResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
DestroyManyResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryDestroyOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class DestroyOneResolverFactory
|
||||
@ -27,23 +26,19 @@ export class DestroyOneResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphQLQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
DestroyOneResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphQLQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
DestroyOneResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryFindDuplicatesResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-duplicates-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class FindDuplicatesResolverFactory
|
||||
@ -27,23 +26,19 @@ export class FindDuplicatesResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
FindDuplicatesResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
FindDuplicatesResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryFindManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class FindManyResolverFactory
|
||||
@ -27,23 +26,19 @@ export class FindManyResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, _context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
FindManyResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
FindManyResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryFindOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class FindOneResolverFactory
|
||||
@ -27,23 +26,19 @@ export class FindOneResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, _context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
FindOneResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
FindOneResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryRestoreManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-many-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class RestoreManyResolverFactory
|
||||
@ -27,23 +26,19 @@ export class RestoreManyResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
RestoreManyResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
RestoreManyResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryRestoreOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-one-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class RestoreOneResolverFactory
|
||||
@ -27,23 +26,19 @@ export class RestoreOneResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
RestoreOneResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
RestoreOneResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQuerySearchResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-search-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class SearchResolverFactory
|
||||
@ -25,23 +24,19 @@ export class SearchResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, _context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
SearchResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
SearchResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryUpdateManyResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateManyResolverFactory
|
||||
@ -27,23 +26,19 @@ export class UpdateManyResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
UpdateManyResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
UpdateManyResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
import { WorkspaceSchemaBuilderContext } from 'src/engine/api/graphql/workspace-schema-builder/interfaces/workspace-schema-builder-context.interface';
|
||||
|
||||
import { GraphqlQueryUpdateOneResolverService } from 'src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service';
|
||||
import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-query-runner-graphql-api-exception-handler.util';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateOneResolverFactory
|
||||
@ -27,23 +26,19 @@ export class UpdateOneResolverFactory
|
||||
const internalContext = context;
|
||||
|
||||
return async (_source, args, context, info) => {
|
||||
try {
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
const options: WorkspaceQueryRunnerOptions = {
|
||||
authContext: internalContext.authContext,
|
||||
info,
|
||||
objectMetadataMaps: internalContext.objectMetadataMaps,
|
||||
objectMetadataItemWithFieldMaps:
|
||||
internalContext.objectMetadataItemWithFieldMaps,
|
||||
};
|
||||
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
UpdateOneResolverFactory.methodName,
|
||||
);
|
||||
} catch (error) {
|
||||
workspaceQueryRunnerGraphqlApiExceptionHandler(error, internalContext);
|
||||
}
|
||||
return await this.graphqlQueryRunnerService.execute(
|
||||
args,
|
||||
options,
|
||||
UpdateOneResolverFactory.methodName,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,16 @@
|
||||
import { Logger } from '@nestjs/common/services/logger.service';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||
import { buildCreatedByFromWorkspaceMember } from 'src/engine/core-modules/actor/utils/build-created-by-from-workspace-member.util';
|
||||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
@ -45,6 +50,13 @@ export class CreatedByCreateManyPreQueryHook
|
||||
): Promise<CreateManyResolverArgs<CustomWorkspaceItem>> {
|
||||
let createdBy: ActorMetadata | null = null;
|
||||
|
||||
if (!isDefined(payload.data)) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
'Payload data is required',
|
||||
GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Once all objects have it, we can remove this check
|
||||
const createdByFieldMetadata = await this.fieldMetadataRepository.findOne({
|
||||
where: {
|
||||
|
@ -1,11 +1,16 @@
|
||||
import { Logger } from '@nestjs/common/services/logger.service';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { WorkspaceQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface';
|
||||
import { CreateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
|
||||
|
||||
import {
|
||||
GraphqlQueryRunnerException,
|
||||
GraphqlQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator';
|
||||
import { buildCreatedByFromWorkspaceMember } from 'src/engine/core-modules/actor/utils/build-created-by-from-workspace-member.util';
|
||||
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
|
||||
@ -45,6 +50,13 @@ export class CreatedByCreateOnePreQueryHook
|
||||
): Promise<CreateOneResolverArgs<CustomWorkspaceItem>> {
|
||||
let createdBy: ActorMetadata | null = null;
|
||||
|
||||
if (!isDefined(payload.data)) {
|
||||
throw new GraphqlQueryRunnerException(
|
||||
'Payload data is required',
|
||||
GraphqlQueryRunnerExceptionCode.INVALID_QUERY_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Once all objects have it, we can remove this check
|
||||
const createdByFieldMetadata = await this.fieldMetadataRepository.findOne({
|
||||
where: {
|
||||
|
@ -5,7 +5,6 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { DataSeedDemoWorkspaceModule } from 'src/database/commands/data-seed-demo-workspace/data-seed-demo-workspace.module';
|
||||
import { DataSeedDemoWorkspaceJob } from 'src/database/commands/data-seed-demo-workspace/jobs/data-seed-demo-workspace.job';
|
||||
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
|
||||
import { WorkspaceQueryRunnerJobModule } from 'src/engine/api/graphql/workspace-query-runner/jobs/workspace-query-runner-job.module';
|
||||
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
|
||||
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
|
||||
import { UpdateSubscriptionQuantityJob } from 'src/engine/core-modules/billing/jobs/update-subscription-quantity.job';
|
||||
@ -47,7 +46,6 @@ import { WorkflowModule } from 'src/modules/workflow/workflow.module';
|
||||
CalendarEventParticipantManagerModule,
|
||||
TimelineActivityModule,
|
||||
StripeModule,
|
||||
WorkspaceQueryRunnerJobModule,
|
||||
AutoCompaniesAndContactsCreationJobModule,
|
||||
TimelineJobModule,
|
||||
WebhookJobModule,
|
||||
|
@ -1,6 +0,0 @@
|
||||
import { ObjectMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/object-metadata.interface';
|
||||
|
||||
export const hasPositionField = (objectMetadataItem: ObjectMetadataInterface) =>
|
||||
['opportunity', 'person', 'company'].includes(
|
||||
objectMetadataItem.nameSingular,
|
||||
) || objectMetadataItem.isCustom;
|
@ -52,10 +52,10 @@ export class CustomWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
description: 'Position',
|
||||
type: FieldMetadataType.POSITION,
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
position: number | null;
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.createdBy,
|
||||
|
@ -50,40 +50,43 @@ export class SyncWorkspaceMetadataCommand extends ActiveWorkspacesCommandRunner
|
||||
`Running workspace sync for workspace: ${workspaceId} (${count} out of ${workspaceIds.length})`,
|
||||
);
|
||||
count++;
|
||||
try {
|
||||
const issues =
|
||||
await this.workspaceHealthService.healthCheck(workspaceId);
|
||||
|
||||
// Security: abort if there are issues.
|
||||
if (issues.length > 0) {
|
||||
if (!options.force) {
|
||||
try {
|
||||
const issues =
|
||||
await this.workspaceHealthService.healthCheck(workspaceId);
|
||||
|
||||
// Security: abort if there are issues.
|
||||
if (issues.length > 0) {
|
||||
if (!options.force) {
|
||||
this.logger.error(
|
||||
`Workspace contains ${issues.length} issues, aborting.`,
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
'If you want to force the migration, use --force flag',
|
||||
);
|
||||
this.logger.log(
|
||||
'Please use `workspace:health` command to check issues and fix them before running this command.',
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
this.logger.warn(
|
||||
`Workspace contains ${issues.length} issues, sync has been forced.`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (!options.force) {
|
||||
this.logger.error(
|
||||
`Workspace contains ${issues.length} issues, aborting.`,
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
'If you want to force the migration, use --force flag',
|
||||
);
|
||||
this.logger.log(
|
||||
'Please use `workspace:health` command to check issues and fix them before running this command.',
|
||||
);
|
||||
|
||||
continue;
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.logger.warn(
|
||||
`Workspace contains ${issues.length} issues, sync has been forced.`,
|
||||
`Workspace health check failed with error, but sync has been forced.`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (!options.force) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
this.logger.warn(
|
||||
`Workspace health check failed with error, but sync has been forced.`,
|
||||
error,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -8,7 +8,10 @@ import {
|
||||
} from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/comparator.interface';
|
||||
import { ComputedPartialFieldMetadata } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/partial-field-metadata.interface';
|
||||
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import {
|
||||
FieldMetadataEntity,
|
||||
FieldMetadataType,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||
|
||||
const commonFieldPropertiesToIgnore = [
|
||||
@ -24,10 +27,24 @@ const commonFieldPropertiesToIgnore = [
|
||||
'asExpression',
|
||||
'generatedType',
|
||||
'defaultValue',
|
||||
'isLabelSyncedWithName',
|
||||
];
|
||||
|
||||
const fieldPropertiesToStringify = ['defaultValue'] as const;
|
||||
|
||||
const shouldNotOverrideDefaultValue = (
|
||||
fieldMetadata: FieldMetadataEntity | ComputedPartialFieldMetadata,
|
||||
) => {
|
||||
return [
|
||||
FieldMetadataType.BOOLEAN,
|
||||
FieldMetadataType.SELECT,
|
||||
FieldMetadataType.MULTI_SELECT,
|
||||
FieldMetadataType.CURRENCY,
|
||||
FieldMetadataType.PHONES,
|
||||
FieldMetadataType.ADDRESS,
|
||||
].includes(fieldMetadata.type);
|
||||
};
|
||||
|
||||
const shouldSkipFieldCreation = (
|
||||
standardFieldMetadata: ComputedPartialFieldMetadata | undefined,
|
||||
) => {
|
||||
@ -55,7 +72,17 @@ export class WorkspaceFieldComparator {
|
||||
const originalFieldMetadataMap = transformMetadataForComparison(
|
||||
filteredOriginalFieldCollection,
|
||||
{
|
||||
shouldIgnoreProperty: (property) => {
|
||||
shouldIgnoreProperty: (
|
||||
property,
|
||||
fieldMetadata: FieldMetadataEntity,
|
||||
) => {
|
||||
if (
|
||||
property === 'defaultValue' &&
|
||||
shouldNotOverrideDefaultValue(fieldMetadata)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (commonFieldPropertiesToIgnore.includes(property)) {
|
||||
return true;
|
||||
}
|
||||
@ -72,7 +99,17 @@ export class WorkspaceFieldComparator {
|
||||
const standardFieldMetadataMap = transformMetadataForComparison(
|
||||
standardFieldMetadataCollection,
|
||||
{
|
||||
shouldIgnoreProperty: (property) => {
|
||||
shouldIgnoreProperty: (
|
||||
property,
|
||||
fieldMetadata: ComputedPartialFieldMetadata,
|
||||
) => {
|
||||
if (
|
||||
property === 'defaultValue' &&
|
||||
shouldNotOverrideDefaultValue(fieldMetadata)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (commonFieldPropertiesToIgnore.includes(property)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -147,9 +147,9 @@ export class CompanyWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
label: 'Position',
|
||||
description: 'Company record position',
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNullable()
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
|
@ -37,6 +37,7 @@ export class FavoriteFolderWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconList',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
|
@ -48,6 +48,7 @@ export class FavoriteWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconList',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
position: number;
|
||||
|
||||
// Relations
|
||||
|
@ -55,10 +55,10 @@ export class NoteWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
label: 'Position',
|
||||
description: 'Note record position',
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNullable()
|
||||
position: number | null;
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: NOTE_STANDARD_FIELD_IDS.title,
|
||||
|
@ -113,10 +113,10 @@ export class OpportunityWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
label: 'Position',
|
||||
description: 'Opportunity record position',
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNullable()
|
||||
position: number | null;
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: OPPORTUNITY_STANDARD_FIELD_IDS.createdBy,
|
||||
|
@ -157,9 +157,9 @@ export class PersonWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
label: 'Position',
|
||||
description: 'Person record Position',
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNullable()
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
|
@ -57,10 +57,10 @@ export class TaskWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
label: 'Position',
|
||||
description: 'Task record position',
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNullable()
|
||||
position: number | null;
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
standardId: TASK_STANDARD_FIELD_IDS.title,
|
||||
|
@ -77,6 +77,7 @@ export class ViewFieldWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconList',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
position: number;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
@ -59,6 +59,7 @@ export class ViewGroupWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
icon: 'IconList',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
position: number;
|
||||
|
||||
@WorkspaceRelation({
|
||||
|
@ -97,8 +97,9 @@ export class ViewWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
type: FieldMetadataType.POSITION,
|
||||
label: 'Position',
|
||||
description: 'View position',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsNullable()
|
||||
@WorkspaceIsSystem()
|
||||
position: number;
|
||||
|
||||
@WorkspaceField({
|
||||
|
@ -155,10 +155,10 @@ export class WorkflowRunWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
label: 'Position',
|
||||
description: 'Workflow run position',
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNullable()
|
||||
position: number | null;
|
||||
position: number;
|
||||
|
||||
// Relations
|
||||
@WorkspaceRelation({
|
||||
|
@ -117,10 +117,10 @@ export class WorkflowVersionWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
label: 'Position',
|
||||
description: 'Workflow version position',
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNullable()
|
||||
position: number | null;
|
||||
position: number;
|
||||
|
||||
// Relations
|
||||
@WorkspaceRelation({
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { Relation } from 'src/engine/workspace-manager/workspace-sync-metadata/interfaces/relation.interface';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import {
|
||||
ActorMetadata,
|
||||
FieldActorSource,
|
||||
} from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import {
|
||||
RelationMetadataType,
|
||||
@ -21,10 +25,6 @@ import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-o
|
||||
import { WorkflowEventListenerWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-event-listener.workspace-entity';
|
||||
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||
import { WorkflowVersionWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||
import {
|
||||
ActorMetadata,
|
||||
FieldActorSource,
|
||||
} from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
||||
|
||||
export enum WorkflowStatus {
|
||||
DRAFT = 'DRAFT',
|
||||
@ -103,10 +103,10 @@ export class WorkflowWorkspaceEntity extends BaseWorkspaceEntity {
|
||||
label: 'Position',
|
||||
description: 'Workflow record position',
|
||||
icon: 'IconHierarchy2',
|
||||
defaultValue: 0,
|
||||
})
|
||||
@WorkspaceIsSystem()
|
||||
@WorkspaceIsNullable()
|
||||
position: number | null;
|
||||
position: number;
|
||||
|
||||
// Relations
|
||||
@WorkspaceRelation({
|
||||
|
Loading…
Reference in New Issue
Block a user