shared-utils.ts 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { CustomFieldConfig } from './generated-types';
  2. /**
  3. * Predicate with type guard, used to filter out null or undefined values
  4. * in a filter operation.
  5. */
  6. export function notNullOrUndefined<T>(val: T | undefined | null): val is T {
  7. return val !== undefined && val !== null;
  8. }
  9. /**
  10. * Used in exhaustiveness checks to assert a codepath should never be reached.
  11. */
  12. export function assertNever(value: never): never {
  13. throw new Error(`Expected never, got ${typeof value} (${JSON.stringify(value)})`);
  14. }
  15. /**
  16. * Simple object check.
  17. * From https://stackoverflow.com/a/34749873/772859
  18. */
  19. export function isObject(item: any): item is object {
  20. return item && typeof item === 'object' && !Array.isArray(item);
  21. }
  22. export function isClassInstance(item: any): boolean {
  23. return isObject(item) && item.constructor.name !== 'Object';
  24. }
  25. type NumericPropsOf<T> = {
  26. [K in keyof T]: T[K] extends number ? K : never;
  27. }[keyof T];
  28. type OnlyNumerics<T> = {
  29. [K in NumericPropsOf<T>]: T[K];
  30. };
  31. /**
  32. * Adds up all the values of a given numeric property of a list of objects.
  33. */
  34. export function summate<T extends OnlyNumerics<T>>(
  35. items: T[] | undefined | null,
  36. prop: keyof OnlyNumerics<T>,
  37. ): number {
  38. return (items || []).reduce((sum, i) => sum + i[prop], 0);
  39. }
  40. /**
  41. * Given an array of option arrays `[['red, 'blue'], ['small', 'large']]`, this method returns a new array
  42. * containing all the combinations of those options:
  43. *
  44. * @example
  45. * ```
  46. * generateAllCombinations([['red, 'blue'], ['small', 'large']]);
  47. * // =>
  48. * // [
  49. * // ['red', 'small'],
  50. * // ['red', 'large'],
  51. * // ['blue', 'small'],
  52. * // ['blue', 'large'],
  53. * // ]
  54. */
  55. export function generateAllCombinations<T>(
  56. optionGroups: T[][],
  57. combination: T[] = [],
  58. k: number = 0,
  59. output: T[][] = [],
  60. ): T[][] {
  61. if (k === 0) {
  62. optionGroups = optionGroups.filter(g => 0 < g.length);
  63. }
  64. if (k === optionGroups.length) {
  65. output.push(combination);
  66. return [];
  67. } else {
  68. // tslint:disable:prefer-for-of
  69. for (let i = 0; i < optionGroups[k].length; i++) {
  70. generateAllCombinations(optionGroups, combination.concat(optionGroups[k][i]), k + 1, output);
  71. }
  72. // tslint:enable:prefer-for-of
  73. return output;
  74. }
  75. }
  76. /**
  77. * @description
  78. * Returns the input field name of a relation custom field.
  79. */
  80. export function getGraphQlInputName(config: { name: string; type: string; list?: boolean }): string {
  81. if (config.type === 'relation') {
  82. return config.list === true ? `${config.name}Ids` : `${config.name}Id`;
  83. } else {
  84. return config.name;
  85. }
  86. }