Skip to content

Commit 9a37bd7

Browse files
authored
fix #541: invoke removeAll mutably within produce (#544)
add tests
1 parent b835eae commit 9a37bd7

File tree

4 files changed

+542
-5
lines changed

4 files changed

+542
-5
lines changed

src/entities/sorted_state_adapter.test.ts

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
AClockworkOrange,
88
AnimalFarm
99
} from './fixtures/book'
10+
import { createNextState } from '..'
1011

1112
describe('Sorted State Adapter', () => {
1213
let adapter: EntityStateAdapter<BookModel>
@@ -436,4 +437,263 @@ describe('Sorted State Adapter', () => {
436437
}
437438
})
438439
})
440+
441+
describe('can be used mutably when wrapped in createNextState', () => {
442+
test('removeAll', () => {
443+
const withTwo = adapter.addMany(state, [TheGreatGatsby, AnimalFarm])
444+
const result = createNextState(withTwo, draft => {
445+
adapter.removeAll(draft)
446+
})
447+
expect(result).toMatchInlineSnapshot(`
448+
Object {
449+
"entities": Object {},
450+
"ids": Array [],
451+
}
452+
`)
453+
})
454+
455+
test('addOne', () => {
456+
const result = createNextState(state, draft => {
457+
adapter.addOne(draft, TheGreatGatsby)
458+
})
459+
460+
expect(result).toMatchInlineSnapshot(`
461+
Object {
462+
"entities": Object {
463+
"tgg": Object {
464+
"id": "tgg",
465+
"title": "The Great Gatsby",
466+
},
467+
},
468+
"ids": Array [
469+
"tgg",
470+
],
471+
}
472+
`)
473+
})
474+
475+
test('addMany', () => {
476+
const result = createNextState(state, draft => {
477+
adapter.addMany(draft, [TheGreatGatsby, AnimalFarm])
478+
})
479+
480+
expect(result).toMatchInlineSnapshot(`
481+
Object {
482+
"entities": Object {
483+
"af": Object {
484+
"id": "af",
485+
"title": "Animal Farm",
486+
},
487+
"tgg": Object {
488+
"id": "tgg",
489+
"title": "The Great Gatsby",
490+
},
491+
},
492+
"ids": Array [
493+
"af",
494+
"tgg",
495+
],
496+
}
497+
`)
498+
})
499+
500+
test('setAll', () => {
501+
const result = createNextState(state, draft => {
502+
adapter.setAll(draft, [TheGreatGatsby, AnimalFarm])
503+
})
504+
505+
expect(result).toMatchInlineSnapshot(`
506+
Object {
507+
"entities": Object {
508+
"af": Object {
509+
"id": "af",
510+
"title": "Animal Farm",
511+
},
512+
"tgg": Object {
513+
"id": "tgg",
514+
"title": "The Great Gatsby",
515+
},
516+
},
517+
"ids": Array [
518+
"af",
519+
"tgg",
520+
],
521+
}
522+
`)
523+
})
524+
525+
test('updateOne', () => {
526+
const withOne = adapter.addOne(state, TheGreatGatsby)
527+
const changes = { title: 'A New Hope' }
528+
const result = createNextState(withOne, draft => {
529+
adapter.updateOne(draft, {
530+
id: TheGreatGatsby.id,
531+
changes
532+
})
533+
})
534+
535+
expect(result).toMatchInlineSnapshot(`
536+
Object {
537+
"entities": Object {
538+
"tgg": Object {
539+
"id": "tgg",
540+
"title": "A New Hope",
541+
},
542+
},
543+
"ids": Array [
544+
"tgg",
545+
],
546+
}
547+
`)
548+
})
549+
550+
test('updateMany', () => {
551+
const firstChange = { title: 'First Change' }
552+
const secondChange = { title: 'Second Change' }
553+
const withMany = adapter.setAll(state, [TheGreatGatsby, AClockworkOrange])
554+
555+
const result = createNextState(withMany, draft => {
556+
adapter.updateMany(draft, [
557+
{ id: TheGreatGatsby.id, changes: firstChange },
558+
{ id: AClockworkOrange.id, changes: secondChange }
559+
])
560+
})
561+
562+
expect(result).toMatchInlineSnapshot(`
563+
Object {
564+
"entities": Object {
565+
"aco": Object {
566+
"id": "aco",
567+
"title": "Second Change",
568+
},
569+
"tgg": Object {
570+
"id": "tgg",
571+
"title": "First Change",
572+
},
573+
},
574+
"ids": Array [
575+
"tgg",
576+
"aco",
577+
],
578+
}
579+
`)
580+
})
581+
582+
test('upsertOne (insert)', () => {
583+
const result = createNextState(state, draft => {
584+
adapter.upsertOne(draft, TheGreatGatsby)
585+
})
586+
expect(result).toMatchInlineSnapshot(`
587+
Object {
588+
"entities": Object {
589+
"tgg": Object {
590+
"id": "tgg",
591+
"title": "The Great Gatsby",
592+
},
593+
},
594+
"ids": Array [
595+
"tgg",
596+
],
597+
}
598+
`)
599+
})
600+
601+
test('upsertOne (update)', () => {
602+
const withOne = adapter.upsertOne(state, TheGreatGatsby)
603+
const result = createNextState(withOne, draft => {
604+
adapter.upsertOne(draft, {
605+
id: TheGreatGatsby.id,
606+
title: 'A New Hope'
607+
})
608+
})
609+
expect(result).toMatchInlineSnapshot(`
610+
Object {
611+
"entities": Object {
612+
"tgg": Object {
613+
"id": "tgg",
614+
"title": "A New Hope",
615+
},
616+
},
617+
"ids": Array [
618+
"tgg",
619+
],
620+
}
621+
`)
622+
})
623+
624+
test('upsertMany', () => {
625+
const withOne = adapter.upsertOne(state, TheGreatGatsby)
626+
const result = createNextState(withOne, draft => {
627+
adapter.upsertMany(draft, [
628+
{
629+
id: TheGreatGatsby.id,
630+
title: 'A New Hope'
631+
},
632+
AnimalFarm
633+
])
634+
})
635+
expect(result).toMatchInlineSnapshot(`
636+
Object {
637+
"entities": Object {
638+
"af": Object {
639+
"id": "af",
640+
"title": "Animal Farm",
641+
},
642+
"tgg": Object {
643+
"id": "tgg",
644+
"title": "A New Hope",
645+
},
646+
},
647+
"ids": Array [
648+
"tgg",
649+
"af",
650+
],
651+
}
652+
`)
653+
})
654+
655+
test('removeOne', () => {
656+
const withTwo = adapter.addMany(state, [TheGreatGatsby, AnimalFarm])
657+
const result = createNextState(withTwo, draft => {
658+
adapter.removeOne(draft, TheGreatGatsby.id)
659+
})
660+
expect(result).toMatchInlineSnapshot(`
661+
Object {
662+
"entities": Object {
663+
"af": Object {
664+
"id": "af",
665+
"title": "Animal Farm",
666+
},
667+
},
668+
"ids": Array [
669+
"af",
670+
],
671+
}
672+
`)
673+
})
674+
675+
test('removeMany', () => {
676+
const withThree = adapter.addMany(state, [
677+
TheGreatGatsby,
678+
AnimalFarm,
679+
AClockworkOrange
680+
])
681+
const result = createNextState(withThree, draft => {
682+
adapter.removeMany(draft, [TheGreatGatsby.id, AnimalFarm.id])
683+
})
684+
expect(result).toMatchInlineSnapshot(`
685+
Object {
686+
"entities": Object {
687+
"aco": Object {
688+
"id": "aco",
689+
"title": "A Clockwork Orange",
690+
},
691+
},
692+
"ids": Array [
693+
"aco",
694+
],
695+
}
696+
`)
697+
})
698+
})
439699
})

src/entities/state_adapter.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
import createNextState, { isDraft } from 'immer'
2-
import { EntityState } from './models'
2+
import { EntityState, PreventAny } from './models'
33
import { PayloadAction, isFSA } from '../createAction'
44

5+
export function createSingleArgumentStateOperator<V>(
6+
mutator: (state: EntityState<V>) => void
7+
) {
8+
const operator = createStateOperator((_: undefined, state: EntityState<V>) =>
9+
mutator(state)
10+
)
11+
12+
return function operation<S extends EntityState<V>>(
13+
state: PreventAny<S, V>
14+
): S {
15+
return operator(state as S, undefined)
16+
}
17+
}
18+
519
export function createStateOperator<V, R>(
620
mutator: (arg: R, state: EntityState<V>) => void
721
) {

0 commit comments

Comments
 (0)