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:
@ -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(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user