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>
This commit is contained in:
@ -1,9 +1,14 @@
|
||||
import { InsertResult } from 'typeorm';
|
||||
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 {
|
||||
@ -17,17 +22,58 @@ export class GraphqlQueryCreateManyResolverService {
|
||||
args: CreateManyResolverArgs<Partial<ObjectRecord>>,
|
||||
options: WorkspaceQueryRunnerOptions,
|
||||
): Promise<ObjectRecord[] | undefined> {
|
||||
const { authContext, objectMetadataItem } = options;
|
||||
const { authContext, objectMetadataItem, objectMetadataCollection, info } =
|
||||
options;
|
||||
const repository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
|
||||
authContext.workspace.id,
|
||||
objectMetadataItem.nameSingular,
|
||||
);
|
||||
|
||||
const insertResult: InsertResult = !args.upsert
|
||||
? await repository.insert(args.data)
|
||||
: await repository.upsert(args.data, ['id']);
|
||||
const objectMetadataMap = generateObjectMetadataMap(
|
||||
objectMetadataCollection,
|
||||
);
|
||||
const objectMetadata = getObjectMetadataOrThrow(
|
||||
objectMetadataMap,
|
||||
objectMetadataItem.nameSingular,
|
||||
);
|
||||
const graphqlQueryParser = new GraphqlQueryParser(
|
||||
objectMetadata.fields,
|
||||
objectMetadataMap,
|
||||
);
|
||||
|
||||
return insertResult.generatedMaps as ObjectRecord[];
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,9 +61,11 @@ export class GraphqlQueryFindManyResolverService {
|
||||
objectMetadataMap,
|
||||
);
|
||||
|
||||
const selectedFields = graphqlFields(info);
|
||||
|
||||
const { select, relations } = graphqlQueryParser.parseSelectedFields(
|
||||
objectMetadataItem,
|
||||
graphqlFields(info),
|
||||
selectedFields,
|
||||
);
|
||||
const isForwardPagination = !isDefined(args.before);
|
||||
const order = graphqlQueryParser.parseOrder(
|
||||
@ -84,7 +86,10 @@ export class GraphqlQueryFindManyResolverService {
|
||||
relations,
|
||||
take: limit + 1,
|
||||
};
|
||||
const totalCount = await repository.count({ where });
|
||||
|
||||
const totalCount = isDefined(selectedFields.totalCount)
|
||||
? await repository.count({ where })
|
||||
: 0;
|
||||
|
||||
if (cursor) {
|
||||
applyRangeFilter(where, cursor, isForwardPagination);
|
||||
|
||||
@ -51,9 +51,11 @@ export class GraphqlQueryFindOneResolverService {
|
||||
objectMetadataMap,
|
||||
);
|
||||
|
||||
const selectedFields = graphqlFields(info);
|
||||
|
||||
const { select, relations } = graphqlQueryParser.parseSelectedFields(
|
||||
objectMetadataItem,
|
||||
graphqlFields(info),
|
||||
selectedFields,
|
||||
);
|
||||
const where = graphqlQueryParser.parseFilter(args.filter ?? ({} as Filter));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user