Skip to content

Commit

Permalink
fix: itemAccumulatorInstance fix
Browse files Browse the repository at this point in the history
- Fixed issue where ItemAccumulatorInstance would flatten item arrays instead of adding them to the accumulator as arrays
  • Loading branch information
dereekb committed May 2, 2022
1 parent a96ffa8 commit d67c9d1
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 16 deletions.
4 changes: 2 additions & 2 deletions packages/rxjs/src/lib/iterator/iteration.accumulator.rxjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export function flattenIterationResultItemArray<T>(iteration: ItemAccumulator<T[
/**
* A PageListLoadingState that captures all the values that have been loaded so far, and the current loading state of currentPageResult$.
*/
export function iterationCurrentPageListLoadingState<V>(iteration: PageItemAccumulator<V>): Observable<PageListLoadingState<V>> {
return combineLatest([iteration.itemIteration.currentState$, iteration.allItems$]).pipe(
export function iterationCurrentPageListLoadingState<V>(accumulator: PageItemAccumulator<V>): Observable<PageListLoadingState<V>> {
return combineLatest([accumulator.itemIteration.currentState$, accumulator.allItems$]).pipe(
map(([state, values]) => mapLoadingStateResults(state, {
mapValue: () => values
}) as PageListLoadingState<V>),
Expand Down
102 changes: 97 additions & 5 deletions packages/rxjs/src/lib/iterator/iteration.accumulator.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { SubscriptionObject } from './../subscription';
import { ItemPageIterator, ItemPageIterationInstance } from './iterator.page';
import { loadingStateHasFinishedLoading } from '../loading';
import { filter, first, skip } from 'rxjs';
import { iteratorNextPageUntilPage } from './iteration.next';
import { itemAccumulator, ItemAccumulatorInstance } from './iteration.accumulator';
import { TestPageIteratorFilter, TEST_PAGE_ITERATOR_DELEGATE } from './iterator.page.spec';
import { TestPageIteratorFilter, TEST_PAGE_ARRAY_ITERATOR_DELEGATE, TEST_PAGE_ITERATOR_DELEGATE } from './iterator.page.spec';

describe('ItemPageIterator', () => {

Expand Down Expand Up @@ -57,6 +58,97 @@ describe('ItemPageIterator', () => {

describe('allItems$', () => {

let sub: SubscriptionObject;

beforeEach(() => {
sub = new SubscriptionObject();
})

afterEach(() => {
sub.destroy();
});

describe('with array value accumulator', () => {
let arrayIterator: ItemPageIterator<number[], TestPageIteratorFilter>;

beforeEach(() => {
arrayIterator = new ItemPageIterator(TEST_PAGE_ARRAY_ITERATOR_DELEGATE);
});

let arrayInstance: ItemPageIterationInstance<number[], TestPageIteratorFilter>;
let arrayAccumulator: ItemAccumulatorInstance<number[], number[]>;

function initInstanceWithFilter(filter?: TestPageIteratorFilter) {
arrayInstance = arrayIterator.instance({
filter: filter ?? {}
});
arrayAccumulator = itemAccumulator(arrayInstance);
}

beforeEach(() => {
initInstanceWithFilter();
});

afterEach(() => {
arrayInstance.destroy();
arrayAccumulator.destroy();
});

it('should accumulate the array values to a 2 dimensional array.', (done) => {
arrayAccumulator.allItems$.pipe(filter((x) => x.length > 0), first()).subscribe((value) => {
expect(Array.isArray(value)).toBe(true);
expect(Array.isArray(value[0])).toBe(true);

done();
});
});

it('should accumulate the multiple array values to a 2 dimensional array.', (done) => {
const pagesToLoad = 2;

iteratorNextPageUntilPage(arrayInstance, pagesToLoad).then(() => {

arrayAccumulator.allItems$.pipe(first()).subscribe((value) => {
expect(value.length).toBe(pagesToLoad);
expect(Array.isArray(value)).toBe(true);
expect(Array.isArray(value[0])).toBe(true);

done();
});

});

});

it('should accumulate the multiple array values to a 2 dimensional array and any subsequent values too.', (done) => {
const pagesToLoad = 2;

iteratorNextPageUntilPage(arrayInstance, pagesToLoad).then(() => {

arrayAccumulator.allItems$.pipe(first()).subscribe((value) => {
expect(value.length).toBe(pagesToLoad);
expect(Array.isArray(value)).toBe(true);
expect(Array.isArray(value[0])).toBe(true);
expect(Array.isArray(value[1])).toBe(true);

iteratorNextPageUntilPage(arrayInstance, pagesToLoad + 1).then(() => {

arrayAccumulator.allItems$.pipe(first()).subscribe((value) => {
expect(value.length).toBe(pagesToLoad + 1);
expect(Array.isArray(value)).toBe(true);
expect(Array.isArray(value[value.length - 1])).toBe(true);
done();
});

});
});

});

});

});

describe('with error and no successes', () => {

beforeEach(() => {
Expand Down Expand Up @@ -90,7 +182,7 @@ describe('ItemPageIterator', () => {

it('should map the items', (done) => {

mappedAccumulator.allItems$.pipe(filter(x => x.length > 0)).subscribe((items) => {
sub.subscription = mappedAccumulator.allItems$.pipe(filter(x => x.length > 0)).subscribe((items) => {
expect(items).toBeDefined();
expect(typeof items[0]).toBe('string');
done();
Expand All @@ -106,7 +198,7 @@ describe('ItemPageIterator', () => {

iteratorNextPageUntilPage(instance, pagesToLoad).then(() => {

instance.numberOfPagesLoaded$.subscribe((pagesLoaded) => {
sub.subscription = instance.numberOfPagesLoaded$.subscribe((pagesLoaded) => {
expect(pagesLoaded).toBe(pagesToLoad);

accumulator.allItems$.subscribe((allItems) => {
Expand All @@ -131,7 +223,7 @@ describe('ItemPageIterator', () => {
let emissions = 0;

// Should trigger first page to be loaded.
accumulator.allItems$.subscribe((allItems) => {
sub.subscription = accumulator.allItems$.subscribe((allItems) => {
emissions += 1;

if (emissions === 1) {
Expand All @@ -150,7 +242,7 @@ describe('ItemPageIterator', () => {
let latestAllItems: number[];

// Should trigger first page to be loaded.
accumulator.allItems$.pipe(
sub.subscription = accumulator.allItems$.pipe(
skip(1) // skip the first empty emission
).subscribe((allItems) => {
emissions += 1;
Expand Down
11 changes: 5 additions & 6 deletions packages/rxjs/src/lib/iterator/iteration.accumulator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { startWith } from 'rxjs/operators';
import { SubscriptionObject } from '../subscription';
import { map, Observable, shareReplay, skipWhile, distinctUntilChanged, filter } from 'rxjs';
import { startWith, map, Observable, shareReplay, skipWhile, distinctUntilChanged, filter } from 'rxjs';
import { distinctUntilArrayLengthChanges, scanBuildArray, filterMaybe, scanIntoArray } from "../rxjs";
import { lastValue, filterMaybeValues, Destroyable, Maybe } from "@dereekb/util";
import { ItemIteration, PageItemIteration } from "./iteration";
Expand Down Expand Up @@ -128,10 +127,10 @@ export class ItemAccumulatorInstance<O, I = any, N extends ItemIteration<I> = It
*/
export function itemAccumulator<I, N extends ItemIteration<I>>(itemIteration: N): ItemAccumulatorInstance<I, I, N>;
export function itemAccumulator<O, I, N extends ItemIteration<I>>(itemIteration: N, mapItem?: ItemAccumulatorMapFunction<O, I>): ItemAccumulatorInstance<O, I, N>;
export function itemAccumulator<O, I, N extends ItemIteration<I>>(itemIteration: N, mapItemFunction?: ItemAccumulatorMapFunction<O, I>): ItemAccumulatorInstance<O, I, N> {
if (!mapItemFunction) {
mapItemFunction = (a: any) => a;
export function itemAccumulator<O, I, N extends ItemIteration<I>>(itemIteration: N, mapItem?: ItemAccumulatorMapFunction<O, I>): ItemAccumulatorInstance<O, I, N> {
if (!mapItem) {
mapItem = (a: any) => a;
}

return new ItemAccumulatorInstance<O, I, N>(itemIteration, mapItemFunction);
return new ItemAccumulatorInstance<O, I, N>(itemIteration, mapItem);
}
13 changes: 10 additions & 3 deletions packages/rxjs/src/lib/rxjs/array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ export function scanIntoArray<T>(config: { immutable?: boolean } = {}): Operator

// MARK: ScanBuildArray
export interface ScanBuildArrayConfig<T> {
/**
*
*/
seed?: Maybe<T[]>;
/**
*
*/
accumulatorObs: Observable<Maybe<T>>;
};

Expand All @@ -64,13 +70,14 @@ export function scanBuildArray<S, T>(init: ScanBuildArrayConfigFn<S, T>): Operat

return accumulatorObs.pipe(
startWith(undefined as any), // Start with to not wait for the accumulator to pass a value.
scan((acc: Maybe<T[]>, next: Maybe<ArrayOrValue<T>>) => {
scan((acc: T[], next: Maybe<T>) => {

if (next != null) {
acc = mergeArrayOrValueIntoArray(acc!, next!);
acc.push(next);
}

return acc!;
}, seed!) as OperatorFunction<ArrayOrValue<T>, T[]>,
}, seed ?? []) as OperatorFunction<ArrayOrValue<T>, T[]>,
distinctUntilArrayLengthChanges(),
shareReplay(1)
);
Expand Down

0 comments on commit d67c9d1

Please sign in to comment.