channel.resolver.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import {
  2. Arg,
  3. Args,
  4. Mutation,
  5. Query,
  6. Root,
  7. Resolver,
  8. FieldResolver,
  9. ObjectType,
  10. Field,
  11. Int,
  12. ArgsType,
  13. Info,
  14. } from 'type-graphql';
  15. import graphqlFields from 'graphql-fields';
  16. import { Inject } from 'typedi';
  17. import { Min } from 'class-validator';
  18. import { Fields, StandardDeleteResponse, UserId, PageInfo, RawFields } from 'warthog';
  19. import {
  20. ChannelCreateInput,
  21. ChannelCreateManyArgs,
  22. ChannelUpdateArgs,
  23. ChannelWhereArgs,
  24. ChannelWhereInput,
  25. ChannelWhereUniqueInput,
  26. ChannelOrderByEnum,
  27. } from '../../../generated';
  28. import { Channel } from './channel.model';
  29. import { ChannelService } from './channel.service';
  30. import { Membership } from '../membership/membership.model';
  31. import { CuratorGroup } from '../curator-group/curator-group.model';
  32. import { ChannelCategory } from '../channel-category/channel-category.model';
  33. import { DataObject } from '../data-object/data-object.model';
  34. import { Language } from '../language/language.model';
  35. import { Video } from '../video/video.model';
  36. import { getConnection } from 'typeorm';
  37. @ObjectType()
  38. export class ChannelEdge {
  39. @Field(() => Channel, { nullable: false })
  40. node!: Channel;
  41. @Field(() => String, { nullable: false })
  42. cursor!: string;
  43. }
  44. @ObjectType()
  45. export class ChannelConnection {
  46. @Field(() => Int, { nullable: false })
  47. totalCount!: number;
  48. @Field(() => [ChannelEdge], { nullable: false })
  49. edges!: ChannelEdge[];
  50. @Field(() => PageInfo, { nullable: false })
  51. pageInfo!: PageInfo;
  52. }
  53. @ArgsType()
  54. export class ConnectionPageInputOptions {
  55. @Field(() => Int, { nullable: true })
  56. @Min(0)
  57. first?: number;
  58. @Field(() => String, { nullable: true })
  59. after?: string; // V3: TODO: should we make a RelayCursor scalar?
  60. @Field(() => Int, { nullable: true })
  61. @Min(0)
  62. last?: number;
  63. @Field(() => String, { nullable: true })
  64. before?: string;
  65. }
  66. @ArgsType()
  67. export class ChannelConnectionWhereArgs extends ConnectionPageInputOptions {
  68. @Field(() => ChannelWhereInput, { nullable: true })
  69. where?: ChannelWhereInput;
  70. @Field(() => ChannelOrderByEnum, { nullable: true })
  71. orderBy?: ChannelOrderByEnum;
  72. }
  73. @Resolver(Channel)
  74. export class ChannelResolver {
  75. constructor(@Inject('ChannelService') public readonly service: ChannelService) {}
  76. @Query(() => [Channel])
  77. async channels(
  78. @Args() { where, orderBy, limit, offset }: ChannelWhereArgs,
  79. @Fields() fields: string[]
  80. ): Promise<Channel[]> {
  81. return this.service.find<ChannelWhereInput>(where, orderBy, limit, offset, fields);
  82. }
  83. @Query(() => Channel, { nullable: true })
  84. async channelByUniqueInput(
  85. @Arg('where') where: ChannelWhereUniqueInput,
  86. @Fields() fields: string[]
  87. ): Promise<Channel | null> {
  88. const result = await this.service.find(where, undefined, 1, 0, fields);
  89. return result && result.length >= 1 ? result[0] : null;
  90. }
  91. @Query(() => ChannelConnection)
  92. async channelsConnection(
  93. @Args() { where, orderBy, ...pageOptions }: ChannelConnectionWhereArgs,
  94. @Info() info: any
  95. ): Promise<ChannelConnection> {
  96. const rawFields = graphqlFields(info, {}, { excludedFields: ['__typename'] });
  97. let result: any = {
  98. totalCount: 0,
  99. edges: [],
  100. pageInfo: {
  101. hasNextPage: false,
  102. hasPreviousPage: false,
  103. },
  104. };
  105. // If the related database table does not have any records then an error is thrown to the client
  106. // by warthog
  107. try {
  108. result = await this.service.findConnection<ChannelWhereInput>(where, orderBy, pageOptions, rawFields);
  109. } catch (err) {
  110. console.log(err);
  111. // TODO: should continue to return this on `Error: Items is empty` or throw the error
  112. if (!(err.message as string).includes('Items is empty')) throw err;
  113. }
  114. return result as Promise<ChannelConnection>;
  115. }
  116. @FieldResolver(() => Membership)
  117. async ownerMember(@Root() r: Channel): Promise<Membership | null> {
  118. const result = await getConnection()
  119. .getRepository(Channel)
  120. .findOne(r.id, { relations: ['ownerMember'] });
  121. if (result && result.ownerMember !== undefined) {
  122. return result.ownerMember;
  123. }
  124. return null;
  125. }
  126. @FieldResolver(() => CuratorGroup)
  127. async ownerCuratorGroup(@Root() r: Channel): Promise<CuratorGroup | null> {
  128. const result = await getConnection()
  129. .getRepository(Channel)
  130. .findOne(r.id, { relations: ['ownerCuratorGroup'] });
  131. if (result && result.ownerCuratorGroup !== undefined) {
  132. return result.ownerCuratorGroup;
  133. }
  134. return null;
  135. }
  136. @FieldResolver(() => ChannelCategory)
  137. async category(@Root() r: Channel): Promise<ChannelCategory | null> {
  138. const result = await getConnection()
  139. .getRepository(Channel)
  140. .findOne(r.id, { relations: ['category'] });
  141. if (result && result.category !== undefined) {
  142. return result.category;
  143. }
  144. return null;
  145. }
  146. @FieldResolver(() => DataObject)
  147. async coverPhotoDataObject(@Root() r: Channel): Promise<DataObject | null> {
  148. const result = await getConnection()
  149. .getRepository(Channel)
  150. .findOne(r.id, { relations: ['coverPhotoDataObject'] });
  151. if (result && result.coverPhotoDataObject !== undefined) {
  152. return result.coverPhotoDataObject;
  153. }
  154. return null;
  155. }
  156. @FieldResolver(() => DataObject)
  157. async avatarPhotoDataObject(@Root() r: Channel): Promise<DataObject | null> {
  158. const result = await getConnection()
  159. .getRepository(Channel)
  160. .findOne(r.id, { relations: ['avatarPhotoDataObject'] });
  161. if (result && result.avatarPhotoDataObject !== undefined) {
  162. return result.avatarPhotoDataObject;
  163. }
  164. return null;
  165. }
  166. @FieldResolver(() => Language)
  167. async language(@Root() r: Channel): Promise<Language | null> {
  168. const result = await getConnection()
  169. .getRepository(Channel)
  170. .findOne(r.id, { relations: ['language'] });
  171. if (result && result.language !== undefined) {
  172. return result.language;
  173. }
  174. return null;
  175. }
  176. @FieldResolver(() => Video)
  177. async videos(@Root() r: Channel): Promise<Video[] | null> {
  178. const result = await getConnection()
  179. .getRepository(Channel)
  180. .findOne(r.id, { relations: ['videos'] });
  181. if (result && result.videos !== undefined) {
  182. return result.videos;
  183. }
  184. return null;
  185. }
  186. }