calculated-decorator.ts 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { OrderByCondition, SelectQueryBuilder } from 'typeorm';
  2. /**
  3. * The property name we use to store the CalculatedColumnDefinitions to the
  4. * entity class.
  5. */
  6. export const CALCULATED_PROPERTIES = '__calculatedProperties__';
  7. /**
  8. * @description
  9. * Optional metadata used to tell the {@link ListQueryBuilder} & {@link Relations} decorator how to deal with
  10. * calculated columns when sorting, filtering and deriving required relations from GraphQL operations.
  11. *
  12. * @docsCategory data-access
  13. * @docsPage Calculated
  14. */
  15. export interface CalculatedColumnQueryInstruction {
  16. /**
  17. * @description
  18. * If the calculated property depends on one or more relations being present
  19. * on the entity (e.g. an `Order` entity calculating the `totalQuantity` by adding
  20. * up the quantities of each `OrderLine`), then those relations should be defined here.
  21. */
  22. relations?: string[];
  23. query?: (qb: SelectQueryBuilder<any>) => void;
  24. expression?: string;
  25. }
  26. export interface CalculatedColumnDefinition {
  27. name: string | symbol;
  28. listQuery?: CalculatedColumnQueryInstruction;
  29. }
  30. /**
  31. * @description
  32. * Used to define calculated entity getters. The decorator simply attaches an array of "calculated"
  33. * property names to the entity's prototype. This array is then used by the {@link CalculatedPropertySubscriber}
  34. * to transfer the getter function from the prototype to the entity instance.
  35. *
  36. * @docsCategory data-access
  37. * @docsWeight 0
  38. */
  39. export function Calculated(queryInstruction?: CalculatedColumnQueryInstruction): MethodDecorator {
  40. return (
  41. target: object & { [key: string]: any },
  42. propertyKey: string | symbol,
  43. descriptor: PropertyDescriptor,
  44. ) => {
  45. const definition: CalculatedColumnDefinition = {
  46. name: propertyKey,
  47. listQuery: queryInstruction,
  48. };
  49. if (target[CALCULATED_PROPERTIES]) {
  50. if (
  51. !target[CALCULATED_PROPERTIES].map((p: CalculatedColumnDefinition) => p.name).includes(
  52. definition.name,
  53. )
  54. ) {
  55. target[CALCULATED_PROPERTIES].push(definition);
  56. }
  57. } else {
  58. target[CALCULATED_PROPERTIES] = [definition];
  59. }
  60. };
  61. }