使用type-graphql

时间:2019-05-25 19:35:12

标签: graphql typeorm type-graphql

我对graphql / typeorm之间的关系数据查询有疑问。 最好的解释方法是举一个例子:)

出于我的问题,我使用了例如Arizona(https://www.graphqlbin.com/v2/6RQ6TM) 该API是StarWars GraphQL API的示例

如果我想获得所有电影和相关角色,我会这样查询:

案例A

 {
   allFilms{
    title
    characters{
        name
    }
   }
 }

在这种情况下,可以一次完成关系数据库调用,一起检索影片和角色(通过联接选择sql) 我的问题是在这样的查询中添加过滤器时如何保持sql性能

案例B

{
   allFilms{
    title
    characters(filter: {name_contains: "PO"}){
        name
    }
   }
 }

在这种情况下,似乎我们必须使用FieldResolver进行此操作,并执行其他数据库调用来检索子项

为澄清起见,请参见以下示例:

案例A(简单实施) 如果是typescript和typeorm ORM中的nodejs后端,我们可以这样: 实体:

    @Entity()
    @ObjectType()
    export class Film { 

        @PrimaryColumn()
        @Field(type => ID, { description: 'The id of the object.'})
        id: string;

        @Column()
        @Field({ description: 'The title of this film'})
        title: string;

        .....

        @ManyToMany(type => Person, person => person.films )
        @JoinTable({ name: 'film_person' })   
        @Field(type => [Person], { nullable: true }) 
        characters?: Person[];
    }

解析器:

    @Resolver(of => Film)
    export class FilmResolvers { 

      constructor(private readonly filmService: FilmService) {}

      @Query(returns => [Film])  
      async allFilms(@Args() args: QueryAllFilmDTO): Promise<Film[]> {    
        return this.filmService.findAll(args);
      }
    }

案例B(扩展实施)

解析器:

 @Resolver(of => Film)
 export class FilmResolvers {

  constructor(
    private readonly filmService: FilmService,    
    @InjectRepository(Person) private readonly personRepository: Repository<Person>,
    ) {}

  @ResolveProperty(type => [Person])  
  async characters(@Parent() film: Film, @Args() args: PersonQueryAllDTO) {

    // Low Performance in this case 
    const persons = await this.personRepository
      .createQueryBuilder('person')
      .leftJoin('person.films', 'film','film.id = :films_param',{films_param: [film.id]})      
      .getMany();

    return persons;
  }

  @Query(returns => [Film])  
  async allFilms(@Args() args: QueryAllFilmDTO): Promise<Film[]> {
    this.detectRelation(info.operation.selectionSet);        
    return this.filmService.findAll(args);
  }
}

这里的问题是我们进行手动联接(两个数据库调用) 我正在考虑其他解决方案,但需要您的审查:

案例B(其他扩展实施) 我的目标检索extendend graphql请求信息,检测查询中的关系并使用join构造sql查询

 @Resolver(of => Film)
 export class FilmResolvers { 

  constructor(
    private readonly filmService: FilmService,  
    @InjectRepository(Person) private readonly personRepository: Repository<Person>,
    ) {}


    @Query(returns => [Film])  
  async allFilms(@Args() args: QueryAllFilmDTO, @Info() info: GraphQLResolveInfo): Promise<Film[]> {

    const relations: string[] = [];
    this.getRelations(info.operation.selectionSet, (relation) =>{
      relations.push(relation);
    });

    return this.filmService.findAll(args, relations);
  }




  private getRelations(selectionSetNode: SelectionSetNode, callback: relationCallback, level=0){      
      selectionSetNode.selections.forEach( (subSelection) => {                
        if(subSelection.kind === 'Field'){
          const fieldNode = subSelection as FieldNode;          
          if(fieldNode.selectionSet){
            if(level)              
              callback(fieldNode.name.value);            
            this.getRelations(fieldNode.selectionSet, callback, ++level);        
          }
        }        
      });
  }
}

这是一个好选择吗?还是有其他方法可以优化数据库调用?

0 个答案:

没有答案