Search code examples
typescripttypeorm

How can I avoid duplicate code when I create a query builder?


Good morning, I have an order's service. Here I have two methods find( findAll ) and findByKey( find all by keys ) because it is a query builder I need to join in other tables.

Method find:

find(): Promise<Order[]> {
    return this.orderRepository
      .createQueryBuilder('order')
      .leftJoinAndSelect('order.restaurant', 'restaurant')
      .leftJoinAndSelect('order.user', 'media')
      .leftJoinAndSelect('order.orderCustomer', 'orderCustomer')
      .innerJoinAndSelect('order.orderCart', 'orderCart')
      .leftJoinAndSelect('orderCart.product', 'product')
      .leftJoinAndSelect('product.media', 'product_media')
      .leftJoinAndSelect('order.orderPayment', 'orderPayment')
      .getMany();
  }

Method findByKey:

findByKey(data: FindByKeyInput): Promise<Order[]> {
    const { field, value } = data;
    return this.orderRepository
      .createQueryBuilder('order')
      .where(`order.${field} = :${field}`, { [field]: value })
      .leftJoinAndSelect('order.restaurant', 'restaurant')
      .leftJoinAndSelect('order.user', 'media')
      .leftJoinAndSelect('order.orderCustomer', 'orderCustomer')
      .innerJoinAndSelect('order.orderCart', 'orderCart')
      .leftJoinAndSelect('orderCart.product', 'product')
      .leftJoinAndSelect('product.media', 'product_media')
      .leftJoinAndSelect('order.orderPayment', 'orderPayment')
      .getMany();
  }

How Can I avoid this duplication, Can I put this part of the code into a variable and reuse it? Thanks!


Solution

  • You can make one function with optional params, something like:

    find(data: FindByKeyInput = { field=null, value=null }): Promise<Order[]> {
    const { field, value } = data;
    let query = this.orderRepository
      .createQueryBuilder('order') ;
    
     if(field != null && value != null)
     query.where(`order.${field} = :${field}`, { [field]: value });
    
     query.leftJoinAndSelect('order.restaurant', 'restaurant')
      .leftJoinAndSelect('order.user', 'media')
      .leftJoinAndSelect('order.orderCustomer', 'orderCustomer')
      .innerJoinAndSelect('order.orderCart', 'orderCart')
      .leftJoinAndSelect('orderCart.product', 'product')
      .leftJoinAndSelect('product.media', 'product_media')
      .leftJoinAndSelect('order.orderPayment', 'orderPayment')
      .getMany();
     return query
       }
    

    UPDATE
    to do what you desire, you can create a function that return the querybuilder:

    getOrderRepoWithRelations(){
     return  this.orderRepository
       .createQueryBuilder('order')
      .leftJoinAndSelect('order.restaurant', 'restaurant')
      .leftJoinAndSelect('order.user', 'media')
      .leftJoinAndSelect('order.orderCustomer', 'orderCustomer')
      .innerJoinAndSelect('order.orderCart', 'orderCart')
      .leftJoinAndSelect('orderCart.product', 'product')
      .leftJoinAndSelect('product.media', 'product_media')
      .leftJoinAndSelect('order.orderPayment', 'orderPayment')
    }
    

    then you can use it in your functions like:

    find(): Promise<Order[]> {
    return this.getOrderRepoWithRelations()
      .getMany();
     }
    
    
     findByKey(data: FindByKeyInput): Promise<Order[]> {
        const { field, value } = data;
        let query = this.getOrderRepoWithRelations();
        return query
          .where(`order.${field} = :${field}`, { [field]: value })
          .getMany();
      }