代码之家  ›  专栏  ›  技术社区  ›  Abraham P

左/右任务的分区列表

  •  0
  • Abraham P  · 技术社区  · 5 年前

    假设我有以下类型:

    export type CreateChildEntity = () => TaskEither<ServiceError, void>;
    
    export type CheckParentMappable = (
      id: UUID
    ) => TaskEither<ServiceError, Option<UUID>>;
    
    export type GetHydratedParentForMapping = (
      id: UUID
    ) => TaskEither<ServiceError, HydratedType>;
    
    export type MarkParentMapped = (id: UUID) => TaskEither<ServiceError, void>;
    
    export type MarkParentFailed = (id: UUID) => TaskEither<ServiceError, void>;
    
    export type LookupDetails = (
      id: UUID,
      firstName: string,
      lastName: string
    ) => TaskEither<ServiceError, Option<ValidatedDetails>>;
    
    export type TrackParentMappingError = (
      id: UUID,
      author: ValidatedAuthor,
      message: string
    ) => TaskEither<ServiceError, void>;
    
    export type Deps = Readonly<{
      createChildEntity: CreateChildEntity;
      checkParentMappable: CheckParentMappable;
      getHydratedParentForMapping: GetHydratedParentForMapping;
      markParentMapped: MarkParentMapped;
      markParentFailed: MarkParentFailed;
      lookupDetails: LookupDetails;
      trackParentMappingError: TrackParentMappingError;
    }>;
    

    然后执行以下功能:

    import { Ctx, Deps, Input, Error } from "./types";
    import { pipe } from "fp-ts/lib/pipeable";
    import * as TE from "fp-ts/lib/TaskEither";
    import { isSome } from "fp-ts/lib/Option";
    
    export default (input: Input): Ctx<void> => mapParent(input);
    
    const mapParent = (input: Input): Ctx<void> => (
      deps: Deps
    ): TE.TaskEither<Error, void> =>
      pipe(
        deps.getHydratedParentForMapping(input.id),
        TE.chain(hydratedParent =>
          pipe(
            TE.sequenceArray(
              hydratedParent.authors.map(a => {
                return pipe(
                  deps.lookupDetails(hydratedParent.id, a.firstName, a.lastName),
                  TE.chain(detail => {
                    if (isSome(detail)) {
                      return deps.createChildEntity();
                    } else {
                      return pipe(
                        deps.trackParentMappingError(
                          hydratedParent.id,
                          a,
                          "MISSING_DETAILS_ERROR"
                        ),
                        TE.chain(_ => deps.markParentFailed(hydratedParent.id))
                      );
                    }
                  })
                );
              })
            ),
            TE.chain(_ => deps.markParentMapped(hydratedParent.id))
          )
        )
      );
    

    https://stackblitz.com/edit/typescript-3qv4t1?file=index-bad.ts

    只要里面有验证规则 markParentFailed markParentMapped 要确定父级是否附加了子级/错误,此代码有效。

    相反,我想要实现的是拥有 lookupDetails 穿过 hydratedParent.authors

    const constructEither = (hydratedParent: HydratedType): Ctx<void> => (deps: Deps): TE.TaskEither<Error, Either<ReadonlyArray<Readonly<{id: UUID, author: ValidatedAuthor, errorMessage: string}>>, ReadonlyArray<ValidatedDetails>>> => {
      return TE.sequenceArray(
        hydratedParent.authors.map(a => {
          return pipe(
            deps.lookupDetails(hydratedParent.id, a.firstName, a.lastName),
            TE.chain(val => {
              if(isSome(val)) {
                return right(val.value)
              } else {
                return left({id: hydratedParent.id, author: a, errorMessage: "MISSING_DETAILS_ERROR"})
              }
            })
          )
        }))
    }
    
    const mapParent = (input: Input): Ctx<void> => (
      deps: Deps
    ): TE.TaskEither<Error, void> =>
      pipe(
        deps.getHydratedParentForMapping(input.id),
        TE.chain(hydratedParent =>
        pipe(
          constructEither(deps)(hydratedParent),
          TE.chain(res => {
            if(isRight(res)) {
              pipe(
                res.map(r => deps.createChildEntity()),
                ,TE.chain(_ => deps.markParentMapped(hydratedParent.id))
              )
            } else {
              pipe(
                res.map(r => deps.trackParentMappingError(
                  r.left.id,
                  r.left.author,
                  r.left.errorMessage
                )),
                TE.chain(_ => deps.markParentFailed(hydratedParent.id))
              )
            }
          })
        )
        )
      );
    

    这无法编译。

    以这种方式划分任务的fp ts咒语是什么?

    0 回复  |  直到 5 年前
    推荐文章