Search code examples
typegraphql

How to sort result set using computed fields (type-graphql)


I'm using type-graphql and typeorm. Is there a way to sort the result based on a computed field. Specifically, I want to return a list of Clients and sort the list based on a computed field: "sortName". Sort name is simply a string of the clent's "firstName lastName" or "lastName FirstName". The decision on how to generate the sortName is based on a flag in the Company table (that way the user can control how they want to view their clients). I just don't know how to do the sort prior to sending back to the front-end app. I know I can create a view and do it in sql - but I'd like to know if it's possible to do in code.

import {Arg, Ctx, Field, FieldResolver, ID, InputType, ObjectType, Query, Resolver, Root,} from 'type-graphql'
import {Client} from '../entities/Client'
import {ClientNameSort, Company} from '../entities/Company'
import {MyContext} from '../types/MyContext'

@InputType()
export class ClientsOptions {
  @Field(() => ID)
  companyId!: string
}


@ObjectType()
@Resolver(Client)
export class ClientResolver {

  @FieldResolver(() => String)
  async sortName(@Root() client: Client, @Ctx() { companyLoader }: MyContext) {

    const company:Company = await companyLoader.load(client.companyId)

    if (!company) {
      throw new Error(`Missing rec for Company Id ${client.companyId}`)
    }

    if (company.clientNameSort === ClientNameSort.FIRST_NAME) {
      return `${client.firstName} ${client.lastName} ${client.id}`
    } else {
      return `${client.lastName} ${client.firstName} ${client.id}`
    }
  }
  

  @Query(() => [Client])
  async clients(@Arg('options') options: ClientsOptions) {
    const clientList =  await Client.find({ where: { companyId: options.companyId } })
    return clientList;
  }
}


Solution

  • I believe you have to do the sorting on the "clients" method. Therefore i am not sure the field resolver is going to help you. You better separate that into a utility function and reuse it in both methods.

    To to the sorting on the clients method:

    • if you use mongodb, maybe you can do an aggregated query that will create this virtual field and order by it
    • if you use another DB , you will have to look if they have this kind of feature

    If you don't want to do sorting through DB, you can get the array of clients and do a sort

    clients.sort((a,b) => sortByCompanyName(company.CLIENT_NAME_SORT, a, b))

    getFullIdentificator(order, client) {
      if (order === ClientNameSort.FIRST_NAME) {
          return `${client.firstName} ${client.lastName} ${client.id}`
        } else {
          return `${client.lastName} ${client.firstName} ${client.id}`
        }
    }
    
    sortByCompanyName(order, prev, next) {
      return getFullIdentificator(order, prev) >  getFullIdentificator(order, next) ? 1 : -1 
    }