UNPKG

4.3 kBPlain TextView Raw
1import type {
2 EntityState,
3 IdSelector,
4 Comparer,
5 EntityStateAdapter,
6 Update,
7 EntityId,
8} from './models'
9import { createStateOperator } from './state_adapter'
10import { createUnsortedStateAdapter } from './unsorted_state_adapter'
11import {
12 selectIdValue,
13 ensureEntitiesArray,
14 splitAddedUpdatedEntities,
15} from './utils'
16
17export function createSortedStateAdapter<T>(
18 selectId: IdSelector<T>,
19 sort: Comparer<T>
20): EntityStateAdapter<T> {
21 type R = EntityState<T>
22
23 const { removeOne, removeMany, removeAll } =
24 createUnsortedStateAdapter(selectId)
25
26 function addOneMutably(entity: T, state: R): void {
27 return addManyMutably([entity], state)
28 }
29
30 function addManyMutably(
31 newEntities: readonly T[] | Record<EntityId, T>,
32 state: R
33 ): void {
34 newEntities = ensureEntitiesArray(newEntities)
35
36 const models = newEntities.filter(
37 (model) => !(selectIdValue(model, selectId) in state.entities)
38 )
39
40 if (models.length !== 0) {
41 merge(models, state)
42 }
43 }
44
45 function setOneMutably(entity: T, state: R): void {
46 return setManyMutably([entity], state)
47 }
48
49 function setManyMutably(
50 newEntities: readonly T[] | Record<EntityId, T>,
51 state: R
52 ): void {
53 newEntities = ensureEntitiesArray(newEntities)
54 if (newEntities.length !== 0) {
55 merge(newEntities, state)
56 }
57 }
58
59 function setAllMutably(
60 newEntities: readonly T[] | Record<EntityId, T>,
61 state: R
62 ): void {
63 newEntities = ensureEntitiesArray(newEntities)
64 state.entities = {}
65 state.ids = []
66
67 addManyMutably(newEntities, state)
68 }
69
70 function updateOneMutably(update: Update<T>, state: R): void {
71 return updateManyMutably([update], state)
72 }
73
74 // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
75 function takeUpdatedModel(models: T[], update: Update<T>, state: R): boolean {
76 if (!(update.id in state.entities)) {
77 return false
78 }
79
80 const original = state.entities[update.id]
81 const updated = Object.assign({}, original, update.changes)
82 const newKey = selectIdValue(updated, selectId)
83
84 delete state.entities[update.id]
85
86 models.push(updated)
87
88 return newKey !== update.id
89 }
90
91 function updateManyMutably(
92 updates: ReadonlyArray<Update<T>>,
93 state: R
94 ): void {
95 const models: T[] = []
96
97 updates.forEach((update) => takeUpdatedModel(models, update, state))
98
99 if (models.length !== 0) {
100 merge(models, state)
101 }
102 }
103
104 function upsertOneMutably(entity: T, state: R): void {
105 return upsertManyMutably([entity], state)
106 }
107
108 function upsertManyMutably(
109 newEntities: readonly T[] | Record<EntityId, T>,
110 state: R
111 ): void {
112 const [added, updated] = splitAddedUpdatedEntities<T>(
113 newEntities,
114 selectId,
115 state
116 )
117
118 updateManyMutably(updated, state)
119 addManyMutably(added, state)
120 }
121
122 function areArraysEqual(a: readonly unknown[], b: readonly unknown[]) {
123 if (a.length !== b.length) {
124 return false
125 }
126
127 for (let i = 0; i < a.length && i < b.length; i++) {
128 if (a[i] === b[i]) {
129 continue
130 }
131 return false
132 }
133 return true
134 }
135
136 function merge(models: readonly T[], state: R): void {
137 // Insert/overwrite all new/updated
138 models.forEach((model) => {
139 state.entities[selectId(model)] = model
140 })
141
142 const allEntities = Object.values(state.entities) as T[]
143 allEntities.sort(sort)
144
145 const newSortedIds = allEntities.map(selectId)
146 const { ids } = state
147
148 if (!areArraysEqual(ids, newSortedIds)) {
149 state.ids = newSortedIds
150 }
151 }
152
153 return {
154 removeOne,
155 removeMany,
156 removeAll,
157 addOne: createStateOperator(addOneMutably),
158 updateOne: createStateOperator(updateOneMutably),
159 upsertOne: createStateOperator(upsertOneMutably),
160 setOne: createStateOperator(setOneMutably),
161 setMany: createStateOperator(setManyMutably),
162 setAll: createStateOperator(setAllMutably),
163 addMany: createStateOperator(addManyMutably),
164 updateMany: createStateOperator(updateManyMutably),
165 upsertMany: createStateOperator(upsertManyMutably),
166 }
167}