diff --git a/modules/entity/src/sorted_state_adapter.ts b/modules/entity/src/sorted_state_adapter.ts index 13ece9f8e5..ad95428e52 100644 --- a/modules/entity/src/sorted_state_adapter.ts +++ b/modules/entity/src/sorted_state_adapter.ts @@ -20,102 +20,93 @@ export function createSortedStateAdapter( ); function addOneMutably(entity: T, state: R): boolean { - const key = selectId(entity); - - if (key in state.entities) { - return false; - } - - const insertAt = findTargetIndex(state, entity); - state.ids.splice(insertAt, 0, key); - state.entities[key] = entity; - - return true; + return addManyMutably([entity], state); } function addManyMutably(newModels: T[], state: R): boolean { - let didMutate = false; - - for (let index in newModels) { - didMutate = addOneMutably(newModels[index], state) || didMutate; - } + const models = newModels.filter( + model => !(selectId(model) in state.entities) + ); - return didMutate; + return merge(models, state); } function addAllMutably(models: T[], state: R): boolean { - const sortedModels = models.sort(sort); - state.entities = {}; - state.ids = sortedModels.map(model => { - const id = selectId(model); - state.entities[id] = model; - return id; - }); + state.ids = []; + + addManyMutably(models, state); return true; } function updateOneMutably(update: Update, state: R): boolean { + return updateManyMutably([update], state); + } + + function takeUpdatedModel(models: T[], update: Update, state: R): void { if (!(update.id in state.entities)) { - return false; + return; } const original = state.entities[update.id]; - const updated: T = Object.assign({}, original, update.changes); - const updatedKey = selectId(updated); - const result = sort(original, updated); - - if (result === 0) { - if (updatedKey !== update.id) { - delete state.entities[update.id]; - const index = state.ids.indexOf(update.id); - state.ids[index] = updatedKey; - } - - state.entities[updatedKey] = updated; + const updated = Object.assign({}, original, update.changes); - return true; - } - - const index = state.ids.indexOf(update.id); - state.ids.splice(index, 1); - state.ids.splice(findTargetIndex(state, updated), 0, updatedKey); - - if (updatedKey !== update.id) { - delete state.entities[update.id]; - } + delete state.entities[update.id]; - state.entities[updatedKey] = updated; - - return true; + models.push(updated); } function updateManyMutably(updates: Update[], state: R): boolean { - let didMutate = false; + const models: T[] = []; - for (let index in updates) { - didMutate = updateOneMutably(updates[index], state) || didMutate; + updates.forEach(update => takeUpdatedModel(models, update, state)); + + if (models.length) { + state.ids = state.ids.filter(id => id in state.entities); } - return didMutate; + return merge(models, state); } - function findTargetIndex(state: R, model: T) { - if (state.ids.length === 0) { - return 0; + function merge(models: T[], state: R): boolean { + if (models.length === 0) { + return false; } - for (let i = 0; i < state.ids.length; i++) { - const entity = state.entities[state.ids[i]]; - const isSmaller = sort(model, entity) < 0; + models.sort(sort); - if (isSmaller) { - return i; + const ids: string[] = []; + + let i = 0; + let j = 0; + + while (i < models.length && j < state.ids.length) { + const model = models[i]; + const modelId = selectId(model); + const entityId = state.ids[j]; + const entity = state.entities[entityId]; + + if (sort(model, entity) <= 0) { + ids.push(modelId); + i++; + } else { + ids.push(entityId); + j++; } } - return state.ids.length - 1; + if (i < models.length) { + state.ids = ids.concat(models.slice(i).map(selectId)); + } else { + state.ids = ids.concat(state.ids.slice(j)); + } + + models.forEach((model, i) => { + state.entities[selectId(model)] = model; + }); + + return true; } return { diff --git a/modules/entity/src/unsorted_state_adapter.ts b/modules/entity/src/unsorted_state_adapter.ts index 3f1cad07e7..5f23f2d8e9 100644 --- a/modules/entity/src/unsorted_state_adapter.ts +++ b/modules/entity/src/unsorted_state_adapter.ts @@ -39,23 +39,17 @@ export function createUnsortedStateAdapter( } function removeOneMutably(key: string, state: R): boolean { - const index = state.ids.indexOf(key); - - if (index === -1) { - return false; - } - - state.ids.splice(index, 1); - delete state.entities[key]; - - return true; + return removeManyMutably([key], state); } function removeManyMutably(keys: string[], state: R): boolean { - let didMutate = false; + const didMutate = + keys + .filter(key => key in state.entities) + .map(key => delete state.entities[key]).length > 0; - for (let index in keys) { - didMutate = removeOneMutably(keys[index], state) || didMutate; + if (didMutate) { + state.ids = state.ids.filter(id => id in state.entities); } return didMutate; @@ -68,32 +62,37 @@ export function createUnsortedStateAdapter( }); } - function updateOneMutably(update: Update, state: R): boolean { - const index = state.ids.indexOf(update.id); - - if (index === -1) { - return false; - } - + function takeNewKey( + keys: { [id: string]: string }, + update: Update, + state: R + ): void { const original = state.entities[update.id]; const updated: T = Object.assign({}, original, update.changes); const newKey = selectId(updated); if (newKey !== update.id) { - state.ids[index] = newKey; + keys[update.id] = newKey; delete state.entities[update.id]; } state.entities[newKey] = updated; + } - return true; + function updateOneMutably(update: Update, state: R): boolean { + return updateManyMutably([update], state); } function updateManyMutably(updates: Update[], state: R): boolean { - let didMutate = false; + const newKeys: { [id: string]: string } = {}; + + const didMutate = + updates + .filter(update => update.id in state.entities) + .map(update => takeNewKey(newKeys, update, state)).length > 0; - for (let index in updates) { - didMutate = updateOneMutably(updates[index], state) || didMutate; + if (didMutate) { + state.ids = state.ids.map(id => newKeys[id] || id); } return didMutate;