Files
twenty/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts
Weiko 02618b3e6a Fix graphql query createMany resolver with nested relations (#7061)
Looks like insert() does not return foreign keys. We could eventually
call findMany after but it seems that's what save() is doing so I'm
replacing insert with save.
```typescript
/**
 * Flag to determine whether the entity that is being persisted
 * should be reloaded during the persistence operation.
 *
 * It will work only on databases which does not support RETURNING / OUTPUT statement.
 * Enabled by default.
 */
reload?: boolean;
```

Note: save() also does an upsert by default with no way to configure
that so if we want to keep that behaviour we will need to add a check
before
```typescript
if (args.upsert) {
    const existingRecords = await repository.findBy({
      id: Any(args.data.map((record) => record.id)),
    });
    ...
```

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-09-18 18:45:52 +02:00

80 lines
3.0 KiB
TypeScript

import graphqlFields from 'graphql-fields';
import { In, InsertResult } from 'typeorm';
import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
import { WorkspaceQueryRunnerOptions } from 'src/engine/api/graphql/workspace-query-runner/interfaces/query-runner-option.interface';
import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
import { ObjectRecordsToGraphqlConnectionMapper } from 'src/engine/api/graphql/graphql-query-runner/orm-mappers/object-records-to-graphql-connection.mapper';
import { getObjectMetadataOrThrow } from 'src/engine/api/graphql/graphql-query-runner/utils/get-object-metadata-or-throw.util';
import { generateObjectMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
export class GraphqlQueryCreateManyResolverService {
private twentyORMGlobalManager: TwentyORMGlobalManager;
constructor(twentyORMGlobalManager: TwentyORMGlobalManager) {
this.twentyORMGlobalManager = twentyORMGlobalManager;
}
async createMany<ObjectRecord extends IRecord = IRecord>(
args: CreateManyResolverArgs<Partial<ObjectRecord>>,
options: WorkspaceQueryRunnerOptions,
): Promise<ObjectRecord[] | undefined> {
const { authContext, objectMetadataItem, objectMetadataCollection, info } =
options;
const repository =
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
authContext.workspace.id,
objectMetadataItem.nameSingular,
);
const objectMetadataMap = generateObjectMetadataMap(
objectMetadataCollection,
);
const objectMetadata = getObjectMetadataOrThrow(
objectMetadataMap,
objectMetadataItem.nameSingular,
);
const graphqlQueryParser = new GraphqlQueryParser(
objectMetadata.fields,
objectMetadataMap,
);
const selectedFields = graphqlFields(info);
const { select, relations } = graphqlQueryParser.parseSelectedFields(
objectMetadataItem,
selectedFields,
);
const objectRecords: InsertResult = !args.upsert
? await repository.insert(args.data)
: await repository.upsert(args.data, {
conflictPaths: ['id'],
skipUpdateIfNoValuesChanged: true,
});
const upsertedRecords = await repository.find({
where: {
id: In(objectRecords.generatedMaps.map((record) => record.id)),
},
select,
relations,
});
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionMapper(objectMetadataMap);
return upsertedRecords.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord(
record,
objectMetadataItem.nameSingular,
1,
1,
),
);
}
}