import type { EntityState , IdSelector , Comparer , EntityStateAdapter , Update , EntityId , } from './models' ; import { createStateOperator } from './state_adapter' ; import { createUnsortedStateAdapter } from './unsorted_state_adapter' ; import { selectIdValue , ensureEntitiesArray , splitAddedUpdatedEntities , } from './utils' ; export function createSortedStateAdapter < T > ( selectId , sort ) { type R = EntityState < T > ; const { removeOne , removeMany , removeAll } = createUnsortedStateAdapter ( selectId ) ; function addOneMutably ( entity , state ) { return addManyMutably ( [ entity ] , state ) ; } function addManyMutably ( newEntities , state ) { newEntities = ensureEntitiesArray ( newEntities ) ; const models = newEntities . filter ( ( model ) => ! ( selectIdValue ( model , selectId ) in state . entities ) ) ; if ( models . length !== 0 ) { merge ( models , state ) ; } } function setOneMutably ( entity , state ) { return setManyMutably ( [ entity ] , state ) ; } function setManyMutably ( newEntities , state ) { newEntities = ensureEntitiesArray ( newEntities ) ; if ( newEntities . length !== 0 ) { merge ( newEntities , state ) ; } } function setAllMutably ( newEntities , state ) { newEntities = ensureEntitiesArray ( newEntities ) ; state . entities = { } ; state . ids = [ ] ; addManyMutably ( newEntities , state ) ; } function updateOneMutably ( update , state ) { return updateManyMutably ( [ update ] , state ) ; } function takeUpdatedModel ( models , update , state ) { 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 , state ) { const models = [ ] ; updates . forEach ( ( update ) => takeUpdatedModel ( models , update , state ) ) ; if ( models . length !== 0 ) { merge ( models , state ) ; } } function upsertOneMutably ( entity , state ) { return upsertManyMutably ( [ entity ] , state ) ; } function upsertManyMutably ( newEntities , state ) { const [ added , updated ] = splitAddedUpdatedEntities < T > ( newEntities , selectId , state ) ; updateManyMutably ( updated , state ) ; addManyMutably ( added , state ) ; } function areArraysEqual ( a , b ) { 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 , state ) { 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 ) , setOne : createStateOperator ( setOneMutably ) , setMany : createStateOperator ( setManyMutably ) , setAll : createStateOperator ( setAllMutably ) , addMany : createStateOperator ( addManyMutably ) , updateMany : createStateOperator ( updateManyMutably ) , upsertMany : createStateOperator ( upsertManyMutably ) , } ; }