All files / builtins group-by.ts

100% Statements 35/35
100% Branches 12/12
100% Functions 6/6
100% Lines 34/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 964x 4x             4x   4x   4x   4x         4x 1x             1x         9x 6x   6x 6x   6x 3x       2x   1x       6x     9x             1x 5x 7x 5x 10x 2x     8x     3x         3x           1x 7x 1x     6x       6x     1x    
import {z} from 'zod';
import {ERRORS} from '@grnsft/if-core/utils';
import {
  GroupByPlugin,
  PluginParams,
  GroupByConfig,
} from '@grnsft/if-core/types';
 
import {STRINGS} from '../config';
 
import {validate} from '../util/validations';
 
const {InvalidGroupingError, GlobalConfigError} = ERRORS;
 
const {INVALID_GROUP_BY, MISSING_GLOBAL_CONFIG} = STRINGS;
 
/**
 * Plugin for inputs grouping.
 */
export const GroupBy = (): GroupByPlugin => {
  const metadata = {
    kind: 'groupby',
  };
 
  /**
   * Creates structure to insert inputs by groups.
   */
  const appendGroup = (
    value: PluginParams,
    object: any,
    groups: string[]
  ): any => {
    if (groups.length > 0) {
      const group = groups.shift() as string;
 
      object.children = object.children ?? {};
      object.children[group] = object.children[group] ?? {};
 
      if (groups.length === 0) {
        if (
          object.children[group].inputs &&
          object.children[group].inputs.length > 0
        ) {
          object.children[group].inputs.push(value);
        } else {
          object.children[group].inputs = [value];
        }
      }
 
      appendGroup(value, object.children[group], groups);
    }
 
    return object;
  };
 
  /**
   * Interates over inputs, grabs config-group types values for each one.
   * Based on grouping types, initializes the structure grouped structure.
   */
  const execute = (inputs: PluginParams[], config: GroupByConfig) =>
    inputs.reduce((acc, input) => {
      const validatedConfig = validateConfig(config);
      const groups = validatedConfig.group.map(groupType => {
        if (!input[groupType]) {
          throw new InvalidGroupingError(INVALID_GROUP_BY(groupType));
        }
 
        return input[groupType];
      });
 
      acc = {
        ...acc,
        ...appendGroup(input, acc, groups),
      };
 
      return acc;
    }, {} as any).children;
 
  /**
   * Validates config parameter.
   */
  const validateConfig = (config: GroupByConfig) => {
    if (!config) {
      throw new GlobalConfigError(MISSING_GLOBAL_CONFIG);
    }
 
    const schema = z.object({
      group: z.array(z.string()).min(1),
    });
 
    return validate<z.infer<typeof schema>>(schema, config);
  };
 
  return {metadata, execute};
};