Skip to content

Commit

Permalink
refactor(Entity): Rewrite entity adapters for better performance
Browse files Browse the repository at this point in the history
  • Loading branch information
dinvlad authored and MikeRyanDev committed Oct 3, 2017
1 parent e63720e commit 7fa0cf2
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 88 deletions.
117 changes: 54 additions & 63 deletions modules/entity/src/sorted_state_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,102 +20,93 @@ export function createSortedStateAdapter<T>(
);

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<T>, state: R): boolean {
return updateManyMutably([update], state);
}

function takeUpdatedModel(models: T[], update: Update<T>, 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<T>[], 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 {
Expand Down
49 changes: 24 additions & 25 deletions modules/entity/src/unsorted_state_adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,17 @@ export function createUnsortedStateAdapter<T>(
}

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;
Expand All @@ -68,32 +62,37 @@ export function createUnsortedStateAdapter<T>(
});
}

function updateOneMutably(update: Update<T>, state: R): boolean {
const index = state.ids.indexOf(update.id);

if (index === -1) {
return false;
}

function takeNewKey(
keys: { [id: string]: string },
update: Update<T>,
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<T>, state: R): boolean {
return updateManyMutably([update], state);
}

function updateManyMutably(updates: Update<T>[], 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;
Expand Down

0 comments on commit 7fa0cf2

Please sign in to comment.