UNPKG

sflow

Version:

sflow is a powerful and highly-extensible library designed for processing and manipulating streams of data effortlessly. Inspired by the functional programming paradigm, it provides a rich set of utilities for transforming streams, including chunking, fil

165 lines (147 loc) 5.75 kB
import { range } from "rambda"; import { forEachs } from "./forEachs"; import { mergeDescends } from "./mergeAscends"; import { mergeStreamsByAscend } from "./mergeStreamsBy"; import { sflow } from "./sflow"; it("merge asc", async () => { const req1 = sflow([0, 1, 2]); const req2 = sflow([1, 2, 3]); const req3 = sflow([0, 4, 5]); const ret = [0, 0, 1, 1, 2, 2, 3, 4, 5]; expect( await sflow(mergeStreamsByAscend((x) => x, [req1, req2, req3])) .log() // .peek(console.log) .toArray(), ).toEqual(ret); }); it("drains correctly for different length flow", async () => { const s = [0, 1, 2].map(() => jest.fn()); const f = [0, 1, 2].map(() => jest.fn()); const end = jest.fn(); const c = sflow( mergeStreamsByAscend( (x) => x, [ sflow([1]).onStart(s[0]).onFlush(f[0]), sflow([4, 5]).onStart(s[1]).onFlush(f[1]), sflow([7, 8, 9]).onStart(s[2]).onFlush(f[2]), ], ), ).onFlush(end); // all streams started expect(s[0]).toHaveBeenCalled(); expect(s[1]).toHaveBeenCalled(); expect(s[2]).toHaveBeenCalled(); const r = c.getReader(); // all streams not flushed expect(f[0]).not.toHaveBeenCalled(); expect(f[1]).not.toHaveBeenCalled(); expect(f[2]).not.toHaveBeenCalled(); expect((await r.read()).value).toBe(1); // pulled from [0|1|2] got [1,4,7] emit 1, f0 drain expect((await r.read()).value).toBe(4); // pulled from [0| | ] got [_,4,7] emit 4, expect(f[0]).toHaveBeenCalled(); // stream [1] flushed expect((await r.read()).value).toBe(5); // pulled from [ |1| ] got [_,5,7] emit 5 expect((await r.read()).value).toBe(7); // pulled from [ | |2] got [_,_,7] emit 7 expect(f[1]).toHaveBeenCalled(); // stream [4,5] flushed expect((await r.read()).value).toBe(8); // pulled from [ | |2] got [_,_,8] emit 8 expect((await r.read()).value).toBe(9); // pulled from [ | |2] got [_,_,9] emit 9 expect(end).not.toHaveBeenCalled(); expect((await r.read()).done).toBe(true); // pulled from [ | |2] got [_,_,_] drain expect(f[2]).toHaveBeenCalled(); // stream [7,8,9] flushed expect(end).toHaveBeenCalled(); }); it("merge asc lazy", async () => { const fn1 = jest.fn(); const req1 = sflow([0, 1, 2]).byLazy(forEachs(fn1)); const fn2 = jest.fn(); const req2 = sflow([1, 2, 3]).byLazy(forEachs(fn2)); const fn3 = jest.fn(); const req3 = sflow([0, 4, 5]).byLazy(forEachs(fn3)); const _ret = [0, 0, 1, 1, 2, 2, 3, 4, 5]; const _emi = [1, 3, 2, 1, 2, 1, 2, 3, 3]; // emit order const r = sflow(mergeStreamsByAscend((x) => x, [req1, req2, req3])); expect(fn1).toHaveBeenCalledTimes(0); expect(fn2).toHaveBeenCalledTimes(0); expect(fn3).toHaveBeenCalledTimes(0); const reader = r.getReader(); expect(fn1).toHaveBeenCalledTimes(0); expect(fn2).toHaveBeenCalledTimes(0); expect(fn3).toHaveBeenCalledTimes(0); await reader.read(); // slots: [0,1,0] => emit[0] 1 => [1,1,0] expect(fn1).toHaveBeenCalledTimes(1); expect(fn2).toHaveBeenCalledTimes(1); expect(fn3).toHaveBeenCalledTimes(1); await reader.read(); // slots: [1,1,0] => emit[2] 0 => [1,1,4] expect(fn1).toHaveBeenCalledTimes(2); expect(fn2).toHaveBeenCalledTimes(1); expect(fn3).toHaveBeenCalledTimes(1); await reader.read(); // slots: [1,1,4] => emit[0] 1 => [2,1,4] expect(fn1).toHaveBeenCalledTimes(2); expect(fn2).toHaveBeenCalledTimes(1); expect(fn3).toHaveBeenCalledTimes(2); }); // it("curried", async () => { // const req1 = sflow([0, 1, 2]); // const req2 = sflow([1, 2, 3]); // const req3 = sflow([0, 4, 5]); // const ret = [0, 0, 1, 1, 2, 2, 3, 4, 5]; // expect( // await sflow([req1, req2, req3]) // .through(mergeStreamsByAscend((x: number) => x)) // merge all flows into one by ascend order // .toArray() // ).toEqual(ret); // }); it("merge desc by invert use of asc", async () => { const req1 = sflow([0, 1, 2].toReversed()); const req2 = sflow([1, 2, 3].toReversed()); const req3 = sflow([0, 4, 5].toReversed()); const ret = [0, 0, 1, 1, 2, 2, 3, 4, 5].toReversed(); expect( await sflow(mergeStreamsByAscend((x) => -x, [req1, req2, req3])) // .peek(console.log) .toArray(), ).toEqual(ret); }); it("merge desc by desc export", async () => { const req1 = sflow([0, 1, 2].toReversed()); const req2 = sflow([1, 2, 3].toReversed()); const req3 = sflow([0, 4, 5].toReversed()); const ret = [0, 0, 1, 1, 2, 2, 3, 4, 5].toReversed(); expect( await sflow(mergeDescends((x) => x, [req1, req2, req3])) // .peek(console.log) .toArray(), ).toEqual(ret); }); it("merge a super long asc", async () => { const req1 = sflow(range(0, 9999).map((e) => 1 + e * 2)); // 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 ... const req2 = sflow(range(0, 9999).map((e) => 2 + e * 3)); // 2, 5, 8, 11, 14, 17, 20, 23, 26, 29 ... const req3 = sflow(range(0, 9999).map((e) => 3 + e * 5)); // 3, 8, 13, 18, 23, 28, 33, 38, 43, 48 ... const ret = range(0, 9999) .flatMap((e) => [1 + e * 2, 2 + e * 3, 3 + e * 5]) .sort((a, b) => a - b); expect( await sflow(mergeStreamsByAscend((x) => x, [req1, req2, req3])) // .peek(console.log) .toArray(), ).toEqual(ret); // cost about 60ms in my machine }); it("works asc", async () => { const req1 = sflow([1, 2, 3]); const req2 = sflow([0, 4, 5]); expect( await sflow(mergeStreamsByAscend((x) => x, [req1, req2])) // .peek(console.log) .toArray(), ).toEqual([0, 1, 2, 3, 4, 5]); }); it("throws not asc", async () => { const req1 = sflow([1, 2, 0]); // not asc const req2 = sflow([0, 4, 5]); await expect( sflow(mergeStreamsByAscend((x) => x, [req1, req2])) // .peek(console.log) .toArray(), ).rejects.toThrow("ascending"); });