handles.service.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import { Service } from 'typedi';
  2. import { Member } from '../member/member.model';
  3. import { InjectRepository } from 'typeorm-typedi-extensions';
  4. import { Repository, getConnection } from 'typeorm';
  5. import { HandlesFTSOutput } from './handles.resolver';
  6. interface RawSQLResult {
  7. origin_table: string,
  8. id: string,
  9. rank: number,
  10. highlight: string
  11. }
  12. @Service('HandlesFTSService')
  13. export class HandlesFTSService {
  14. readonly memberRepository: Repository<Member>;
  15. constructor(@InjectRepository(Member) memberRepository: Repository<Member>
  16. ) {
  17. this.memberRepository = memberRepository;
  18. }
  19. async search(text: string, limit:number = 5): Promise<HandlesFTSOutput[]> {
  20. const connection = getConnection();
  21. const queryRunner = connection.createQueryRunner();
  22. // establish real database connection using our new query runner
  23. await queryRunner.connect();
  24. await queryRunner.startTransaction('REPEATABLE READ');
  25. try {
  26. const query = `
  27. SELECT origin_table, id,
  28. ts_rank(tsv, phraseto_tsquery('english', $1)) as rank,
  29. ts_headline(document, phraseto_tsquery('english', $1)) as highlight
  30. FROM handles_view
  31. WHERE phraseto_tsquery('english', $1) @@ tsv
  32. ORDER BY rank DESC
  33. LIMIT $2`;
  34. const results = await queryRunner.query(query, [text, limit]) as RawSQLResult[];
  35. if (results.length == 0) {
  36. return [];
  37. }
  38. const idMap:{ [id:string]: RawSQLResult } = {};
  39. results.forEach(item => idMap[item.id] = item);
  40. const ids: string[] = results.map(item => item.id);
  41. const members: Member[] = await this.memberRepository.createQueryBuilder()
  42. .where("id IN (:...ids)", { ids }).getMany();
  43. const enhancedEntities = [...members ].map((e) => {
  44. return { item: e,
  45. rank: idMap[e.id].rank,
  46. highlight: idMap[e.id].highlight,
  47. isTypeOf: idMap[e.id].origin_table } as HandlesFTSOutput;
  48. });
  49. return enhancedEntities.reduce((accum: HandlesFTSOutput[], entity) => {
  50. if (entity.rank > 0) {
  51. accum.push(entity);
  52. }
  53. return accum;
  54. }, []).sort((a,b) => b.rank - a.rank);
  55. } finally {
  56. await queryRunner.commitTransaction();
  57. }
  58. }
  59. }