@@ -26,6 +26,7 @@ import {
26
26
} from '../model/collections' ;
27
27
import { Document , MaybeDocument , NoDocument } from '../model/document' ;
28
28
import { DocumentKey } from '../model/document_key' ;
29
+ import { MutationBatch } from '../model/mutation_batch' ;
29
30
import { ResourcePath } from '../model/path' ;
30
31
import { fail } from '../util/assert' ;
31
32
@@ -55,11 +56,25 @@ export class LocalDocumentsView {
55
56
getDocument (
56
57
transaction : PersistenceTransaction ,
57
58
key : DocumentKey
59
+ ) : PersistencePromise < MaybeDocument | null > {
60
+ return this . mutationQueue
61
+ . getAllMutationBatchesAffectingDocumentKey ( transaction , key )
62
+ . next ( batches => this . getDocumentInBatches ( transaction , key , batches ) ) ;
63
+ }
64
+
65
+ /** Internal version of `getDocument` that allows reusing batches. */
66
+ private getDocumentInBatches (
67
+ transaction : PersistenceTransaction ,
68
+ key : DocumentKey ,
69
+ inBatches : MutationBatch [ ]
58
70
) : PersistencePromise < MaybeDocument | null > {
59
71
return this . remoteDocumentCache
60
72
. getEntry ( transaction , key )
61
- . next ( remoteDoc => {
62
- return this . computeLocalDocument ( transaction , key , remoteDoc ) ;
73
+ . next ( doc => {
74
+ for ( const batch of inBatches ) {
75
+ doc = batch . applyToLocalView ( key , doc ) ;
76
+ }
77
+ return doc ;
63
78
} ) ;
64
79
}
65
80
@@ -73,20 +88,23 @@ export class LocalDocumentsView {
73
88
transaction : PersistenceTransaction ,
74
89
keys : DocumentKeySet
75
90
) : PersistencePromise < MaybeDocumentMap > {
76
- const promises = [ ] as Array < PersistencePromise < void > > ;
77
- let results = maybeDocumentMap ( ) ;
78
- keys . forEach ( key => {
79
- promises . push (
80
- this . getDocument ( transaction , key ) . next ( maybeDoc => {
81
- // TODO(http://b/32275378): Don't conflate missing / deleted.
82
- if ( ! maybeDoc ) {
83
- maybeDoc = new NoDocument ( key , SnapshotVersion . forDeletedDoc ( ) ) ;
84
- }
85
- results = results . insert ( key , maybeDoc ) ;
86
- } )
87
- ) ;
91
+ return this . mutationQueue
92
+ . getAllMutationBatchesAffectingDocumentKeys ( transaction , keys ) . next ( batches => {
93
+ const promises = [ ] as Array < PersistencePromise < void > > ;
94
+ let results = maybeDocumentMap ( ) ;
95
+ keys . forEach ( key => {
96
+ promises . push (
97
+ this . getDocumentInBatches ( transaction , key , batches ) . next ( maybeDoc => {
98
+ // TODO(http://b/32275378): Don't conflate missing / deleted.
99
+ if ( ! maybeDoc ) {
100
+ maybeDoc = new NoDocument ( key , SnapshotVersion . forDeletedDoc ( ) ) ;
101
+ }
102
+ results = results . insert ( key , maybeDoc ) ;
103
+ } )
104
+ ) ;
105
+ } ) ;
106
+ return PersistencePromise . waitFor ( promises ) . next ( ( ) => results ) ;
88
107
} ) ;
89
- return PersistencePromise . waitFor ( promises ) . next ( ( ) => results ) ;
90
108
}
91
109
92
110
/** Performs a query against the local view of all documents. */
@@ -122,48 +140,37 @@ export class LocalDocumentsView {
122
140
query : Query
123
141
) : PersistencePromise < DocumentMap > {
124
142
// Query the remote documents and overlay mutations.
125
- // TODO(mikelehen): There may be significant overlap between the mutations
126
- // affecting these remote documents and the
127
- // getAllMutationBatchesAffectingQuery() mutations. Consider optimizing.
128
143
let results : DocumentMap ;
129
144
return this . remoteDocumentCache
130
145
. getDocumentsMatchingQuery ( transaction , query )
131
146
. next ( queryResults => {
132
- return this . computeLocalDocuments ( transaction , queryResults ) ;
133
- } )
134
- . next ( promisedResults => {
135
- results = promisedResults ;
136
- // Now use the mutation queue to discover any other documents that may
137
- // match the query after applying mutations.
147
+ results = queryResults ;
138
148
return this . mutationQueue . getAllMutationBatchesAffectingQuery (
139
149
transaction ,
140
150
query
141
151
) ;
142
152
} )
143
153
. next ( matchingMutationBatches => {
144
- let matchingKeys = documentKeySet ( ) ;
145
154
for ( const batch of matchingMutationBatches ) {
155
+ // TODO(mikelehen): PERF: Check if this mutation actually affects the
156
+ // query to reduce work.
146
157
for ( const mutation of batch . mutations ) {
147
- // TODO(mikelehen): PERF: Check if this mutation actually
148
- // affects the query to reduce work.
149
- if ( ! results . get ( mutation . key ) ) {
150
- matchingKeys = matchingKeys . add ( mutation . key ) ;
158
+ if ( ! query . path . isImmediateParentOf ( mutation . key . path ) ) {
159
+ continue ;
160
+ }
161
+
162
+ const key = mutation . key ;
163
+ const baseDoc = results . get ( key ) ;
164
+ const mutatedDoc = mutation . applyToLocalView ( baseDoc , baseDoc , batch . localWriteTime ) ;
165
+ if ( ! mutatedDoc || mutatedDoc instanceof NoDocument ) {
166
+ results = results . remove ( mutatedDoc . key ) ;
167
+ } else if ( mutatedDoc instanceof Document ) {
168
+ results = results . insert ( mutatedDoc . key , mutatedDoc ) ;
169
+ } else {
170
+ fail ( 'Unknown MaybeDocument: ' + mutatedDoc ) ;
151
171
}
152
172
}
153
173
}
154
-
155
- // Now add in the results for the matchingKeys.
156
- const promises = [ ] as Array < PersistencePromise < void > > ;
157
- matchingKeys . forEach ( key => {
158
- promises . push (
159
- this . getDocument ( transaction , key ) . next ( doc => {
160
- if ( doc instanceof Document ) {
161
- results = results . insert ( doc . key , doc ) ;
162
- }
163
- } )
164
- ) ;
165
- } ) ;
166
- return PersistencePromise . waitFor ( promises ) ;
167
174
} )
168
175
. next ( ( ) => {
169
176
// Finally, filter out any documents that don't actually match
@@ -177,57 +184,4 @@ export class LocalDocumentsView {
177
184
return results ;
178
185
} ) ;
179
186
}
180
-
181
- /**
182
- * Takes a remote document and applies local mutations to generate the local
183
- * view of the document.
184
- * @param transaction The transaction in which to perform any persistence
185
- * operations.
186
- * @param documentKey The key of the document (necessary when remoteDocument
187
- * is null).
188
- * @param document The base remote document to apply mutations to or null.
189
- */
190
- private computeLocalDocument (
191
- transaction : PersistenceTransaction ,
192
- documentKey : DocumentKey ,
193
- document : MaybeDocument | null
194
- ) : PersistencePromise < MaybeDocument | null > {
195
- return this . mutationQueue
196
- . getAllMutationBatchesAffectingDocumentKey ( transaction , documentKey )
197
- . next ( batches => {
198
- for ( const batch of batches ) {
199
- document = batch . applyToLocalView ( documentKey , document ) ;
200
- }
201
- return document ;
202
- } ) ;
203
- }
204
-
205
- /**
206
- * Takes a set of remote documents and applies local mutations to generate the
207
- * local view of the documents.
208
- * @param transaction The transaction in which to perform any persistence
209
- * operations.
210
- * @param documents The base remote documents to apply mutations to.
211
- * @return The local view of the documents.
212
- */
213
- private computeLocalDocuments (
214
- transaction : PersistenceTransaction ,
215
- documents : DocumentMap
216
- ) : PersistencePromise < DocumentMap > {
217
- const promises = [ ] as Array < PersistencePromise < void > > ;
218
- documents . forEach ( ( key , doc ) => {
219
- promises . push (
220
- this . computeLocalDocument ( transaction , key , doc ) . next ( mutatedDoc => {
221
- if ( mutatedDoc instanceof Document ) {
222
- documents = documents . insert ( mutatedDoc . key , mutatedDoc ) ;
223
- } else if ( mutatedDoc instanceof NoDocument ) {
224
- documents = documents . remove ( mutatedDoc . key ) ;
225
- } else {
226
- fail ( 'Unknown MaybeDocument: ' + mutatedDoc ) ;
227
- }
228
- } )
229
- ) ;
230
- } ) ;
231
- return PersistencePromise . waitFor ( promises ) . next ( ( ) => documents ) ;
232
- }
233
187
}
0 commit comments