Skip to content

Commit

Permalink
Ensure object types across multiple schemas have __isTypeOf in `Pic…
Browse files Browse the repository at this point in the history
…k` values (#319)

* Make sure __isTypeOf is in the picked properties

* Update e2e tests

* Add changeset
  • Loading branch information
eddeee888 authored Aug 1, 2024
1 parent 741c9e1 commit de78270
Show file tree
Hide file tree
Showing 25 changed files with 62 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .changeset/seven-camels-compete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eddeee888/gcg-typescript-resolver-files': patch
---

Ensure \_\_isTypeOf is in the picked properties so users can choose this way to handle abstract type should they choose
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { TopicResolvers } from './../../types.generated';
export const Topic: Pick<TopicResolvers, 'bookStore_for_topic'> = {
/* Implement Topic resolver logic here */
bookStore_for_topic: async (_parent, _arg, _ctx) => {
/* Topic.bookStore_for_topic resolver is required because Topic.bookStore_for_topic exists but TopicMapper.bookStore_for_topic does not */
},
};
export const Topic: Pick<TopicResolvers, 'bookStore_for_topic' | '__isTypeOf'> =
{
/* Implement Topic resolver logic here */
bookStore_for_topic: async (_parent, _arg, _ctx) => {
/* Topic.bookStore_for_topic resolver is required because Topic.bookStore_for_topic exists but TopicMapper.bookStore_for_topic does not */
},
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { UserResolvers } from './../../types.generated';
export const User: Pick<UserResolvers, 'bookStore_4_user'> = {
export const User: Pick<UserResolvers, 'bookStore_4_user' | '__isTypeOf'> = {
/* Implement User resolver logic here */
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const Topic: Pick<
| 'id'
| 'name'
| 'url'
| '__isTypeOf'
> = {
/* Implement Topic resolver logic here */
extendedTopicFieldInDifferentFileAndSameModule1: async (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const Topic: Pick<
| 'extendedTopicFieldInDifferentFileAndDifferentModule1'
| 'extendedTopicFieldInDifferentFileAndDifferentModule2'
| 'extendedTopicFieldInDifferentFileAndDifferentModule3'
| '__isTypeOf'
> = {
/* Implement Topic resolver logic here */
creator: ({ creator }, _arg, _ctx) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const User: Pick<
| 'avatar'
| 'id'
| 'name'
| '__isTypeOf'
> = {
/* Implement User resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ForeignTypeResolvers } from './../../types.generated';
export const ForeignType: Pick<
ForeignTypeResolvers,
'id' | 'topics' | '__resolveReference'
'id' | 'topics' | '__isTypeOf' | '__resolveReference'
> = {
/* Implement ForeignType resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ForeignTypeResolvers } from './../../types.generated';
export const ForeignType: Pick<
ForeignTypeResolvers,
'users' | '__resolveReference'
'users' | '__isTypeOf' | '__resolveReference'
> = {
/* Implement ForeignType resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SchoolResolvers } from './../../../types.generated';
export const School: Pick<SchoolResolvers, 'courses'> = {
export const School: Pick<SchoolResolvers, 'courses' | '__isTypeOf'> = {
/* Implement School resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SchoolResolvers } from './../../../types.generated';
export const School: Pick<SchoolResolvers, 'demographics'> = {
export const School: Pick<SchoolResolvers, 'demographics' | '__isTypeOf'> = {
/* Implement School resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SchoolResolvers } from './../../../types.generated';
export const School: Pick<SchoolResolvers, 'id' | 'name'> = {
export const School: Pick<SchoolResolvers, 'id' | 'name' | '__isTypeOf'> = {
/* Implement School resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { StudentProfileResolvers } from './../../../types.generated';
export const StudentProfile: Pick<StudentProfileResolvers, 'avatar'> = {
export const StudentProfile: Pick<
StudentProfileResolvers,
'avatar' | '__isTypeOf'
> = {
/* Implement StudentProfile resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { StudentResolvers } from './../../../types.generated';
export const Student: Pick<StudentResolvers, 'guardians'> = {
export const Student: Pick<StudentResolvers, 'guardians' | '__isTypeOf'> = {
/* Implement Student resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { StudentResolvers } from './../../../types.generated';
export const Student: Pick<StudentResolvers, 'profile'> = {
export const Student: Pick<StudentResolvers, 'profile' | '__isTypeOf'> = {
/* Implement Student resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { StudentProfileResolvers } from './../../../types.generated';
export const StudentProfile: Pick<
StudentProfileResolvers,
'email' | 'firstName' | 'id' | 'lastName' | 'phoneNumber'
'email' | 'firstName' | 'id' | 'lastName' | 'phoneNumber' | '__isTypeOf'
> = {
/* Implement StudentProfile resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { StudentResolvers } from './../../../types.generated';
export const Student: Pick<StudentResolvers, 'id'> = {
export const Student: Pick<StudentResolvers, 'id' | '__isTypeOf'> = {
/* Implement Student resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { TeacherProfileResolvers } from './../../../types.generated';
export const TeacherProfile: Pick<TeacherProfileResolvers, 'avatar'> = {
export const TeacherProfile: Pick<
TeacherProfileResolvers,
'avatar' | '__isTypeOf'
> = {
/* Implement TeacherProfile resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TeacherResolvers } from './../../../types.generated';
export const Teacher: Pick<TeacherResolvers, 'profile'> = {
export const Teacher: Pick<TeacherResolvers, 'profile' | '__isTypeOf'> = {
/* Implement Teacher resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { TeacherProfileResolvers } from './../../../types.generated';
export const TeacherProfile: Pick<
TeacherProfileResolvers,
'email' | 'firstName' | 'id' | 'lastName' | 'phoneNumber'
'email' | 'firstName' | 'id' | 'lastName' | 'phoneNumber' | '__isTypeOf'
> = {
/* Implement TeacherProfile resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TeacherResolvers } from './../../../types.generated';
export const Teacher: Pick<TeacherResolvers, 'id'> = {
export const Teacher: Pick<TeacherResolvers, 'id' | '__isTypeOf'> = {
/* Implement Teacher resolver logic here */
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { UserResolvers } from './../../types.generated';
*
* If you want to skip this file generation, remove the mapper or update the pattern in the `resolverGeneration.object` config.
*/
export const User: Pick<UserResolvers, 'topics'> = {
export const User: Pick<UserResolvers, 'topics' | '__isTypeOf'> = {
/* Implement User resolver logic here */
topics: async (_parent, _arg, _ctx) => {
/* User.topics resolver is required because User.topics exists but UserMapper.topics does not */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const User: Pick<
| 'avatar'
| 'id'
| 'name'
| '__isTypeOf'
> = {
/* Implement User resolver logic here */
accountGitHub: async (_parent, _arg, _ctx) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { UserResolvers } from './../../types.generated';
export const User: Pick<UserResolvers, 'pets'> = {
export const User: Pick<UserResolvers, 'pets' | '__isTypeOf'> = {
/* Implement User resolver logic here */
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ProfileResolvers } from './../../types.generated';
export const Profile: Pick<ProfileResolvers, 'zoo'> = {
export const Profile: Pick<ProfileResolvers, 'zoo' | '__isTypeOf'> = {
/* Implement Profile resolver logic here */
};
Original file line number Diff line number Diff line change
Expand Up @@ -64,35 +64,38 @@ export const handleGraphQLObjectType: GraphQLTypeHandler<
return '';
})();

if (fieldsToPick.length > 0 && pickReferenceResolver) {
const hasFieldsToPick = fieldsToPick.length > 0;

// __isTypeOf is required to resolve abstract types, should user chooses this approach.
// TODO: Run static analysis to enforce only one __isTypeOf per Object type, so users cannot accidentally implement/override it across modules
if (hasFieldsToPick) {
fieldsToPick.push('__isTypeOf');
}

if (hasFieldsToPick && pickReferenceResolver) {
fieldsToPick.push('__resolveReference');
}

// `typeString` contains the resolver type
// If there's fieldsToPick, we must only pick said fields from the original resolver type
const typeString =
fieldsToPick.length > 0
? `Pick<${resolversTypeMeta.typeString}, ${fieldsToPick
.map((fieldName) => `'${fieldName}'`)
.join('|')}>`
: resolversTypeMeta.typeString;
const typeString = hasFieldsToPick
? `Pick<${resolversTypeMeta.typeString}, ${fieldsToPick
.map((fieldName) => `'${fieldName}'`)
.join('|')}>`
: resolversTypeMeta.typeString;

// Array of all resolvers that may need type checking
// If there's fieldsToPick, we must only generate said fields
const allResolversToGenerate =
graphQLObjectTypeResolversToGenerate[resolverName];
const resolversToGenerate =
fieldsToPick.length > 0
? fieldsToPick.reduce<typeof allResolversToGenerate>(
(res, fieldToPick) => {
if (allResolversToGenerate) {
res[fieldToPick] = allResolversToGenerate[fieldToPick];
}
return res;
},
{}
)
: allResolversToGenerate;
const resolversToGenerate = hasFieldsToPick
? fieldsToPick.reduce<typeof allResolversToGenerate>((res, fieldToPick) => {
if (allResolversToGenerate && allResolversToGenerate[fieldToPick]) {
res[fieldToPick] = allResolversToGenerate[fieldToPick];
}
return res;
}, {})
: allResolversToGenerate;

const variableStatement = `${forcedGenerationWarning}export const ${resolverName}: ${typeString} = {
/* Implement ${resolverName} resolver logic here */
Expand Down

0 comments on commit de78270

Please sign in to comment.