ardatan / ardatan/graphql-tools

batchDelegateToSchema creates a duplicate of data from response for every resulting fields

Open
#4,958 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
5.4k
Forks
830
Avg merge
10h 59m
Merged PRs (30d)
45

Description

Hello,

I've been implementing in an API the method `batchDelegateToSchema` from the library.

I'm sharing the following media to show the issue I have with the response and details immediately below

![CleanShot 2023-01-10 at 12 00 21](https://user-images.githubusercontent.com/8559542/211563182-682e8d58-fc2e-409e-9d60-4c4e3e8dad3e.gif)

As you see from that query I'm calling I'm receiving a result and what is wrong I'm getting the data duplicated for the fields which should be empty objects.

In my example, I'm retrieving data for one candidate and I want to know the events that the candidate has signed.
As per DB the candidate has only APPOINTMENT_PHONE as event so I'm expecting this resulting object from the query

```Json
{
"data": {
"candidate": {
"id": "CY-001745",
"callReminders": {
"nodes": [
{
"id": "33116",
"startTime": "2023-01-10T08:57:00.000Z",
"type": "APPOINTMENT_PHONE"
}
],
"totalCount": 1
},
"siteAppointments": {
"nodes": [
],
"totalCount": 0
}
}
}
}
```

Instead, I see the same result replicated in the `siteAppointments` which is wrong.

As ref of wrong response

```json
{
"data": {
"candidate": {
"id": "CY-001745",
"callReminders": {
"nodes": [
{
"id": "33116",
"startTime": "2023-01-10T08:57:00.000Z",
"type": "APPOINTMENT_PHONE"
}
],
"totalCount": 1
},
"siteAppointments": { -- THIS HEAR HAS TO BE EMPTY [] --
"nodes": [
{
"id": "33116",
"startTime": "2023-01-10T08:57:00.000Z",
"type": "APPOINTMENT_PHONE"
}
],
"totalCount": 1
}
}
}
}
```

I spent already hours understanding the issue and I'm sharing what I debugged

This is the resolver

```javascript
events: {
selectionSet: '{ id }',
resolve(candidate, args, context, info) {
return batchDelegateToSchema({
schema: event,
operation: 'query',
fieldName: 'eventsByOwner',
key: candidate.id,
transforms: [transformEventsByOwner],
argsFromKeys: keys => ({
...args,
filter: {
...(args?.filter ?? {}),
ownerTypes: ['CANDIDATE'],
ownerIds: keys,
},
}),
valuesFromResults: (results, keys) => {
const allEvents = keys
.map(findByOwnerId(results))
.map(mapToConnection);
console.log('allEvents: ', JSON.stringify(allEvents, null, 2));

return allEvents;
},

context,
info,
});
},
},
```

On the `console.log('allEvents: ', JSON.stringify(allEvents, null, 2));`I see the result I need the correct one

```json
allEvents: [
{
"totalCount": 1,
"nodes": [
{
"id": "33116",
"startTime": "2023-01-10T08:57:00.000Z",
"type": "APPOINTMENT_PHONE",
"__typename": "Event"
}
]
}
]
```

But for some reason after that the result is duplicated inside the other field `siteAppointments`

I have no clue what's wrong here and I would like to find out a solution to that as it is blocking my release :(

As a detail the other methods used here

```javascript
/**
* Find an item in list of results by owner id.
*
* @param {Object[]} results - List of results.
* @param {string} results[].ownerId - The item's owner id.
* @returns {Object|undefined} - The item with matching owner id or undefined when item not found.
*/
export function findByOwnerId(results) {
return id => results?.find(item => item?.ownerId === id);
}

/**
* Map a result to a generic connection interface.
*
* @param {Object} result - A result (potentially empty or undefined).
* @param {?number} result.totalCount - Total count of entities.
* @param {?Object[]} result.nodes - Array of items.
* @returns {{totalCount: number, nodes: Object[]}} - A connection with nodes and totalCount.
*/
export function mapToConnection(result) {
return {
totalCount: result?.totalCount ?? 0,
nodes: result?.nodes ?? [],
};
}

export const transformEventsByOwner = new WrapQuery(
['eventsByOwner'],
extendedSelection('ownerId'),
identity,
);
```

I hope you can help me with this issue

Thanks :)

Contributor guide

Open the contributing guide

Research direction

Start at the batchDelegateToSchema entry point and compare its per-key result mapping with the resolver's valuesFromResults callback, including findByOwnerId and mapToConnection. Reproduce the candidate query and verify that an unmatched siteAppointments result stays as nodes: [] with totalCount: 0 rather than copying callReminders data.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, javascript, typescript
Domain
api, backend, backend-api-design
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.