Projection functions act on *documents*, not the diffs that are passed
to changed callbacks. For example, a projection `{'a.b': 1}` applied to
the *document* `{a: undefined}` will result in `{}`, but the *diff*
of `{a: undefined}` on a query with that projection should still result
in a `changed` callback with that diff being invoked.
Refactor various parts of minimongo to always have a projectionFn for
each observed query (perhaps a trivial one).
Pass the projection into _diffQueryChanges so that it can apply the
projection *before* taking the diff, in the two cases in Minimongo which
use _diffQueryChanges instead of direct application. (We could instead
make the query's results and resultsSnapshot be projected, but Minimongo
currently relies on the fact that these data structures alias the
documents stored in the collection.)
Stop applying the projection to the diffs in changed via
wrapCallback. (We could still use wrapCallback to apply the projection
for added/addedBefore calls, but it seems more consistent to use the
same mechanisms for added that we use for changed.
Fixes#3800. Fixes#2254. Fixes#3571.
This greatly reduces the number of places in the code where "stringified
IDs" are passed around.
Specifically, changed these maps into _IdMaps:
- minimongo
- the main LocalCollection docs map
- LocalCollection._savedOriginals
- unordered query results, in several places:
- query.results
- query.results_snapshot
- return value from _getRawObjects
- as passed to _diffQueryChanges
- livedata
- Connection._serverDocuments[collection]
- mongo-livedata
- SynchronousCursor._visitedIds
- return value from SynchronousCursor.getRawObjects
- PollingObserveDriver._results (when unordered)
Specifically, factor out the logic that keeps a cache of the current
cursor contents from the part that calls observe callbacks.
Also:
- move IdMap from mongo-livedata to minimongo
- get rid of references to the 'moved' callback which no longer exists
Unordered observations have no moved callback and don't pass indices to the
other callbacks. This is used for the automatic cursor publication (because DDP
collections are not ordered) and for Cursor.count(). Internally, the results of
unordered observations are stored as objects instead of an array. This change
has no publicly observable changes, but should increase performance, especially
server-side (since the _diffQuery that drives DDP subscription updates no longer
needs the full complexity of the ordered move detector).
Also, minor optimization to LocalCollection.Cursor._getRawObjects where the
selector is a single ID that is not in the collection (now O(1) instead of
O(n)).