Skip to content

Commit

Permalink
feat: mapfunction supports Iterable<Promise<T>>
Browse files Browse the repository at this point in the history
  • Loading branch information
ppeeou committed Oct 14, 2024
1 parent e28b55e commit ebe3ea1
Show file tree
Hide file tree
Showing 10 changed files with 48 additions and 19 deletions.
3 changes: 2 additions & 1 deletion src/Lazy/differenceBy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { throwIfPromiseError } from "../_internal/error";
import { isAsyncIterable, isIterable } from "../_internal/utils";
import pipe from "../pipe";
import pipe1 from "../pipe1";
Expand All @@ -13,7 +14,7 @@ function* sync<T>(
iterable1: Iterable<T>,
iterable2: Iterable<T>,
) {
const set = new Set(map(f, iterable1));
const set = new Set(map((a) => throwIfPromiseError(f(a)), iterable1));

yield* pipe(
iterable2,
Expand Down
5 changes: 3 additions & 2 deletions src/Lazy/flatMap.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { throwIfPromiseError } from "../_internal/error";
import { isAsyncIterable, isIterable } from "../_internal/utils";
import type Awaited from "../types/Awaited";
import type { DeepFlat, DeepFlatSync } from "../types/DeepFlat";
Expand Down Expand Up @@ -87,12 +88,12 @@ function flatMap<
): ReturnFlatMapType<A, B> | ((iterable: A) => ReturnFlatMapType<A, B>) {
if (iterable === undefined) {
return (iterable: A) => {
return flat(map(f, iterable as any)) as any;
return flatMap(f, iterable) as any;
};
}

if (isIterable<IterableInfer<A>>(iterable)) {
return flat(map(f, iterable as any)) as any;
return flat(map((a) => throwIfPromiseError(f(a)), iterable)) as any;
}

if (isAsyncIterable<Awaited<IterableInfer<A>>>(iterable)) {
Expand Down
3 changes: 2 additions & 1 deletion src/Lazy/intersectionBy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { throwIfPromiseError } from "../_internal/error";
import { isAsyncIterable, isIterable } from "../_internal/utils";
import pipe from "../pipe";
import pipe1 from "../pipe1";
Expand All @@ -13,7 +14,7 @@ function* sync<T>(
iterable1: Iterable<T>,
iterable2: Iterable<T>,
) {
const set = new Set(map(f, iterable1));
const set = new Set(map((a) => throwIfPromiseError(f(a)), iterable1));

yield* pipe(
iterable2,
Expand Down
7 changes: 1 addition & 6 deletions src/Lazy/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,9 @@ function sync<A, B>(
};
}

const res = f(value);
if (isPromise(res)) {
throw new AsyncFunctionException();
}

return {
done: false,
value: res,
value: f(value),
};
},
[Symbol.iterator]() {
Expand Down
6 changes: 5 additions & 1 deletion src/Lazy/zipWith.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { throwIfPromiseError } from "../_internal/error";
import { isAsyncIterable, isIterable } from "../_internal/utils";
import map from "./map";
import zip from "./zip";
Expand Down Expand Up @@ -44,7 +45,10 @@ function zipWith<A, B, C>(
iterable2: Iterable<B> | AsyncIterable<B>,
): IterableIterator<C> | AsyncIterableIterator<C> {
if (isIterable(iterable1) && isIterable(iterable2)) {
return map(([a, b]) => f(a, b), zip(iterable1, iterable2));
return map(
([a, b]) => throwIfPromiseError(f(a, b)),
zip(iterable1, iterable2),
);
}
if (isIterable(iterable1) && isAsyncIterable(iterable2)) {
return map(([a, b]) => f(a, b), zip(iterable1, iterable2));
Expand Down
10 changes: 10 additions & 0 deletions src/_internal/error.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isPromise } from "./utils";

export class AsyncFunctionException extends Error {
static MESSAGE = `'Iterable' can not used with async function.
If you want to deal with async function, see: [toAsync](https://fxts.dev/docs/toAsync)`;
Expand All @@ -6,3 +8,11 @@ If you want to deal with async function, see: [toAsync](https://fxts.dev/docs/to
super(message);
}
}

export const throwIfPromiseError = <T>(a: Promise<T> | T): T => {
if (isPromise(a)) {
throw new AsyncFunctionException();
}

return a;
};
3 changes: 2 additions & 1 deletion src/every.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { throwIfPromiseError } from "./_internal/error";
import { isAsyncIterable, isIterable } from "./_internal/utils";
import map from "./Lazy/map";
import takeUntil from "./Lazy/takeUntil";
Expand Down Expand Up @@ -56,7 +57,7 @@ function every<

if (isIterable<IterableInfer<A>>(iterable)) {
return pipe(
map(f, iterable),
map((a) => throwIfPromiseError(f(a)), iterable),
takeUntil(not),
(acc) =>
reduce(
Expand Down
3 changes: 2 additions & 1 deletion src/some.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { throwIfPromiseError } from "./_internal/error";
import { isAsyncIterable, isIterable } from "./_internal/utils";
import identity from "./identity";
import map from "./Lazy/map";
Expand Down Expand Up @@ -76,7 +77,7 @@ function some<

if (isIterable<IterableInfer<A>>(iterable)) {
return pipe(
map(f, iterable),
map((a) => throwIfPromiseError(f(a)), iterable),
takeUntil(identity),
(acc) =>
reduce(
Expand Down
18 changes: 12 additions & 6 deletions test/Lazy/map.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AsyncFunctionException } from "../../src/_internal/error";
import { fx, map, pipe, range, toArray, toAsync } from "../../src/index";
import { Concurrent } from "../../src/Lazy/concurrent";
import { generatorMock } from "../utils";
Expand All @@ -16,11 +15,6 @@ describe("map", function () {
expect(acc).toEqual([11, 12, 13, 14, 15]);
});

it("should throw an error when the callback is asynchronous", function () {
const res = () => [...map(add10Async, [1, 2, 3, 4, 5])];
expect(res).toThrowError(new AsyncFunctionException());
});

it("should be able to be used as a curried function in the pipeline", function () {
const res = pipe(
[1, 2, 3, 4],
Expand Down Expand Up @@ -92,6 +86,18 @@ describe("map", function () {

expect(res).toEqual(["1", "2", "3", "4"]);
});
it("should be able to be used as a promise function", async function () {
const res1 = map(async (a) => a, [1, 2, 3, 4]);

expect(await Promise.all(res1)).toEqual([1, 2, 3, 4]);

const res2 = pipe(
[1, 2, 3, 4],
map(async (a) => a),
);

expect(await Promise.all(res2)).toEqual([1, 2, 3, 4]);
});

it("should be able to be used as a chaining method in the `fx`", async function () {
const res = await fx(toAsync([1, 2, 3, 4]))
Expand Down
9 changes: 9 additions & 0 deletions type-check/Lazy/map.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ const res10 = pipe(
map(async (a) => a),
);

const res11 = map(async (a) => a, [1, 2, 3, 4]);
const res12 = pipe(
[1, 2, 3, 4],
map(async (a) => a),
);

checks([
check<typeof res1, IterableIterator<number>, Test.Pass>(),
check<typeof res2, IterableIterator<string>, Test.Pass>(),
Expand All @@ -42,4 +48,7 @@ checks([
check<typeof res8, IterableIterator<Promise<number>>, Test.Pass>(),
check<typeof res9, AsyncIterableIterator<number>, Test.Pass>(),
check<typeof res10, AsyncIterableIterator<number>, Test.Pass>(),

check<typeof res11, IterableIterator<Promise<number>>, Test.Pass>(),
check<typeof res12, IterableIterator<Promise<number>>, Test.Pass>(),
]);

0 comments on commit ebe3ea1

Please sign in to comment.