Embark on your journey into the world of functional programming in typescript using the fp-ts library.
I find myself tangled in a complex web of nested data fetching, reminiscent of the ancient Egyptian pyramids. How can I tackle this problem with a more streamlined and less imperative approach?
The Challenge
export const getProgramWithAllElements = (programId: FirestoreDocumentId): TE.TaskEither<FirestoreError, Program> =>
pipe(
getProgram(programId),
TE.chain((program) =>
pipe(
getCollCollectionsFromPath(program.id),
TE.chain((collections) =>
pipe(
collections,
A.map((collection) =>
pipe(
getWeekCollectionsFromPath(program.id)(collection.id),
TE.chain((weeks) =>
pipe(
weeks,
A.map((week) =>
pipe(
getDayCollectionsFromPath(program.id)(collection.id)(week.id),
TE.chain((days) =>
pipe(
days,
A.map((day) =>
pipe(
getExerciseCollectionsFromPath(program.id)(collection.id)(week.id)(day.id),
TE.map(
(exercises) =>
({
...day,
exercises: exercises,
} as Day)
)
)
),
A.sequence(TE.taskEither)
)
),
TE.map(
(days) =>
({
...week,
days: days,
} as Week)
)
)
),
A.sequence(TE.taskEither)
)
),
TE.map(
(weeks) =>
({
...collection,
weeks: weeks,
} as Collection)
)
)
),
A.sequence(TE.taskEither)
)
),
TE.map(
(collections) =>
({
...program,
collections: collections,
} as Program)
)
)
)
);
Methods utilized in script
declare const getProgram: (programId: FirestoreDocumentId) => TE.TaskEither<FirestoreError, Program>;
declare const getCollCollectionsFromPath: (
programId: FirestoreDocumentId
) => TE.TaskEither<FirestoreError, Collection[]>;
declare const getWeekCollectionsFromPath: (
programId: FirestoreDocumentId
) => (collectionId: FirestoreDocumentId) => TE.TaskEither<FirestoreError, Week[]>;
declare const getDayCollectionsFromPath: (programId: FirestoreDocumentId) => (collectionId: FirestoreDocumentId) => (
weekId: FirestoreDocumentId
) => TE.TaskEither<FirestoreError, Day[]>;
declare const getExerciseCollectionsFromPath: (programId: FirestoreDocumentId) => (collectionId: FirestoreDocumentId) => (
weekId: FirestoreDocumentId
) => (dayId: FirestoreDocumentId) => TE.TaskEither<FirestoreError, Exercise[]>;
Refined Data Structure
export interface Program {
id: string;
// Other Fields
collections?: Collection[];
}
export interface Collection {
id: string;
// Other Fields
weeks?: Week[];
}
export interface Week {
id: string;
// Other Fields
days?: Day[];
}
export interface Day {
id: string;
// Other Fields
exercises: ProgramExercise[];
}
export interface ProgramExercise {
id: string;
// Other Fields
}