Skip to content

Instantly share code, notes, and snippets.

@n1ru4l
Created February 26, 2020 09:34
Show Gist options
  • Save n1ru4l/a3aea793628ba0c825e33727c3cbdaeb to your computer and use it in GitHub Desktop.
Save n1ru4l/a3aea793628ba0c825e33727c3cbdaeb to your computer and use it in GitHub Desktop.
export type OperatorMatcher<
  TProperty extends string = any,
  TPossibleTypes extends string = any,
  TInput extends { [key in TProperty]: TPossibleTypes } = any
> = {
  [Type in TPossibleTypes]: Operator<
    Extract<TInput, { [key in TProperty]: Type }>,
    any
  >;
};

export const operatorMatch = <
  TProperty extends string,
  TPossibleTypes extends string,
  TInput extends { [key in TProperty]: TPossibleTypes },
  TMatcher extends OperatorMatcher<TProperty, TPossibleTypes, TInput>
>(
  property: TProperty,
  input: TInput,
  matcher: TMatcher
): [
  Extract<TInput, { [key in TProperty]: TInput[TProperty] }>,
  TMatcher[TInput[TProperty]]
] => {
  return [
    input as Extract<TInput, { [key in TProperty]: TInput[TProperty] }>,
    matcher[input[property]]
  ];
};

export const match = <
  TProperty extends string,
  TMatcher extends OperatorMatcher<TProperty>
>(
  property: TProperty,
  matcher: TMatcher
): Operator<TMatcher[TProperty], any> => {
  return createOperator("match", property, (err, context, value, next) => {
    if (err) return next(err, value);
    const [newValue, operator] = operatorMatch(property, value, matcher);
    next(null, newValue, {
      path: {
        name: newValue[property],
        operator
      }
    });
  });
};

Usage example:

export const matchReference = (
  matcher: OperatorMatcher<
    "mode",
    "noReference" | "hasReference",
    | {
        mode: "noReference";
        id: string;
        referenceId: null;
      }
    | {
        mode: "hasReference";
        id: string;
        referenceId: string;
      }
  >
) => match("mode", matcher);

export const setActiveToken = pipe(
  o.matchReference({
    noReference: o.enterNotFoundState(),
    hasReference: pipe(
      o.enterLoadingState(),
      o.loadNoteById(),
      o.matchHasRemoteReference({
        notFound: o.enterNotFoundState(),
        found: o.enterLoadedState()
      })
    )
  })
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment