Optimize QueryResultSet so offset lookups are O[1] after initial scan

This commit is contained in:
Ben Gotow 2016-01-27 11:13:39 -08:00
parent 32ccaad1e7
commit b043c30565
2 changed files with 21 additions and 8 deletions

View file

@ -30,6 +30,7 @@ class MutableQueryResultSet extends QueryResultSet
models = @models()
@_modelsHash = {}
@_idToIndexHash = null
@replaceModel(m) for m in models
addModelsInRange: (rangeModels, range) ->
@ -39,6 +40,7 @@ class MutableQueryResultSet extends QueryResultSet
addIdsInRange: (rangeIds, range) ->
if @_offset is null or range.isInfinite()
@_ids = rangeIds
@_idToIndexHash = null
@_offset = range.offset
else
currentEnd = @_offset + @_ids.length
@ -58,18 +60,21 @@ class MutableQueryResultSet extends QueryResultSet
existingAfter = @_ids.slice(rangeIdsEnd - @_offset)
@_ids = [].concat(existingBefore, rangeIds, existingAfter)
@_idToIndexHash = null
@_offset = Math.min(@_offset, range.offset)
replaceModel: (item) ->
return unless item
@_modelsHash[item.clientId] = item
@_modelsHash[item.id] = item
@_idToIndexHash = null
removeModelAtOffset: (item, offset) ->
idx = offset - @_offset
delete @_modelsHash[item.clientId]
delete @_modelsHash[item.id]
@_ids.splice(idx, 1)
@_idToIndexHash = null
setQuery: (query) ->
@_query = query.clone()

View file

@ -31,6 +31,7 @@ class QueryResultSet
throw new Error("setByApplyingModels: A hash of models is required.")
set = set.clone()
set._modelsHash = models
set._idToIndexHash = null
set
constructor: (other = {}) ->
@ -38,11 +39,13 @@ class QueryResultSet
@_offset = other._offset ? null
@_query = other._query ? null
@_ids = other._ids ? []
@_idToIndexHash = other._idToIndexHash ? null
clone: ->
new @constructor({
_ids: [].concat(@_ids)
_modelsHash: _.extend({}, @_modelsHash)
_idToIndexHash: _.extend({}, @_idToIndexHash)
_query: @_query
_offset: @_offset
})
@ -82,15 +85,20 @@ class QueryResultSet
modelWithId: (id) ->
@_modelsHash[id]
buildIdToIndexHash: ->
@_idToIndexHash = {}
for id, idx in @_ids
@_idToIndexHash[id] = idx
model = @_modelsHash[id]
@_idToIndexHash[model.clientId] = idx if model
offsetOfId: (id) ->
idx = @_ids.indexOf(id)
if @_idToIndexHash is null
@buildIdToIndexHash()
# If we can't find the item, try to match against client ids as well. Some
# items in the models() array may not be loaded, but we can try our best.
if idx is -1
idx = _.findIndex @models(), (m) -> m and (m.id is id or m.clientId is id)
return -1 if idx is -1
return @_offset + idx
if @_idToIndexHash[id]
return @_idToIndexHash[id] + @_offset
else
return -1
module.exports = QueryResultSet