@reduxjs/toolkit
Version:
The official, opinionated, batteries-included toolset for efficient Redux development
140 lines (111 loc) • 3.57 kB
text/typescript
import {
EntityState,
IdSelector,
Comparer,
EntityStateAdapter,
Update
} from './models'
import { createStateOperator } from './state_adapter'
import { createUnsortedStateAdapter } from './unsorted_state_adapter'
import { selectIdValue } from './utils'
export function createSortedStateAdapter<T>(
selectId: IdSelector<T>,
sort: Comparer<T>
): EntityStateAdapter<T> {
type R = EntityState<T>
const { removeOne, removeMany, removeAll } = createUnsortedStateAdapter(
selectId
)
function addOneMutably(entity: T, state: R): void {
return addManyMutably([entity], state)
}
function addManyMutably(newModels: T[], state: R): void {
const models = newModels.filter(
model => !(selectIdValue(model, selectId) in state.entities)
)
if (models.length !== 0) {
merge(models, state)
}
}
function setAllMutably(models: T[], state: R): void {
state.entities = {}
state.ids = []
addManyMutably(models, state)
}
function updateOneMutably(update: Update<T>, state: R): void {
return updateManyMutably([update], state)
}
function takeUpdatedModel(models: T[], update: Update<T>, state: R): boolean {
if (!(update.id in state.entities)) {
return false
}
const original = state.entities[update.id]
const updated = Object.assign({}, original, update.changes)
const newKey = selectIdValue(updated, selectId)
delete state.entities[update.id]
models.push(updated)
return newKey !== update.id
}
function updateManyMutably(updates: Update<T>[], state: R): void {
const models: T[] = []
updates.forEach(update => takeUpdatedModel(models, update, state))
if (models.length !== 0) {
merge(models, state)
}
}
function upsertOneMutably(entity: T, state: R): void {
return upsertManyMutably([entity], state)
}
function upsertManyMutably(entities: T[], state: R): void {
const added: T[] = []
const updated: Update<T>[] = []
for (const entity of entities) {
const id = selectIdValue(entity, selectId)
if (id in state.entities) {
updated.push({ id, changes: entity })
} else {
added.push(entity)
}
}
updateManyMutably(updated, state)
addManyMutably(added, state)
}
function areArraysEqual(a: unknown[], b: unknown[]) {
if (a.length !== b.length) {
return false
}
for (let i = 0; i < a.length && i < b.length; i++) {
if (a[i] === b[i]) {
continue
}
return false
}
return true
}
function merge(models: T[], state: R): void {
models.sort(sort)
// Insert/overwrite all new/updated
models.forEach(model => {
state.entities[selectId(model)] = model
})
const allEntities = Object.values(state.entities) as T[]
allEntities.sort(sort)
const newSortedIds = allEntities.map(selectId)
const { ids } = state
if (!areArraysEqual(ids, newSortedIds)) {
state.ids = newSortedIds
}
}
return {
removeOne,
removeMany,
removeAll,
addOne: createStateOperator(addOneMutably),
updateOne: createStateOperator(updateOneMutably),
upsertOne: createStateOperator(upsertOneMutably),
setAll: createStateOperator(setAllMutably),
addMany: createStateOperator(addManyMutably),
updateMany: createStateOperator(updateManyMutably),
upsertMany: createStateOperator(upsertManyMutably)
}
}