1515 * limitations under the License.
1616 */
1717
18- import { queryToTarget } from '../../src/core/query' ;
1918import {
2019 JsonProtoSerializer ,
2120 toName ,
22- toQueryTarget ,
2321 toTimestamp
2422} from '../../src/remote/serializer' ;
2523import { encoder } from '../../test/unit/util/bundle_data' ;
2624import { Firestore } from '../api/database' ;
27- import { ExpUserDataWriter } from '../api/reference_impl' ;
2825import { DatabaseId } from '../core/database_info' ;
29- import { DocumentSnapshot , QuerySnapshot } from '../lite-api/snapshot ' ;
26+ import { DocumentData } from '../lite-api/reference ' ;
3027import { Timestamp } from '../lite-api/timestamp' ;
3128import {
3229 parseObject ,
3330 UserDataReader ,
3431 UserDataSource
3532} from '../lite-api/user_data_reader' ;
36- import { AbstractUserDataWriter } from '../lite-api/user_data_writer' ;
37- import { MutableDocument } from '../model/document' ;
33+ import { DocumentKey } from '../model/document_key' ;
3834import {
3935 BundledDocumentMetadata as ProtoBundledDocumentMetadata ,
4036 BundleElement as ProtoBundleElement ,
@@ -66,7 +62,6 @@ export class BundleBuilder {
6662
6763 private readonly serializer : JsonProtoSerializer ;
6864 private readonly userDataReader : UserDataReader ;
69- private readonly userDataWriter : AbstractUserDataWriter ;
7065
7166 constructor ( private firestore : Firestore , readonly bundleId : string ) {
7267 this . databaseId = firestore . _databaseId ;
@@ -78,133 +73,71 @@ export class BundleBuilder {
7873 /*useProto3Json=*/ true
7974 ) ;
8075
81- this . userDataWriter = new ExpUserDataWriter ( firestore ) ;
8276 this . userDataReader = new UserDataReader (
8377 this . databaseId ,
8478 true ,
8579 this . serializer
8680 ) ;
8781 }
8882
89- /**
90- * Adds a Firestore document snapshot or query snapshot to the bundle.
91- * Both the documents data and the query read time will be included in the bundle.
92- *
93- * @param {DocumentSnapshot | string } documentOrName A document snapshot to add or a name of a query.
94- * @param {Query= } querySnapshot A query snapshot to add to the bundle, if provided.
95- * @returns {BundleBuilder } This instance.
96- *
97- * @example
98- * ```
99- * const bundle = firestore.bundle('data-bundle');
100- * const docSnapshot = await firestore.doc('abc/123').get();
101- * const querySnapshot = await firestore.collection('coll').get();
102- *
103- * const bundleBuffer = bundle.add(docSnapshot) // Add a document
104- * .add('coll-query', querySnapshot) // Add a named query.
105- * .build()
106- * // Save `bundleBuffer` to CDN or stream it to clients.
107- * ```
108- */
109- add (
110- documentOrName : DocumentSnapshot | string ,
111- querySnapshot ?: QuerySnapshot
112- ) : BundleBuilder {
113- if ( arguments . length < 1 || arguments . length > 2 ) {
114- throw new Error (
115- 'Function BundleBuilder.add() requires 1 or 2 arguments.'
116- ) ;
117- }
118- if ( arguments . length === 1 ) {
119- validateDocumentSnapshot ( 'documentOrName' , documentOrName ) ;
120- this . addBundledDocument ( documentOrName as DocumentSnapshot ) ;
121- } else {
122- validateString ( 'documentOrName' , documentOrName ) ;
123- validateQuerySnapshot ( 'querySnapshot' , querySnapshot ) ;
124- this . addNamedQuery ( documentOrName as string , querySnapshot ! ) ;
125- }
126- return this ;
127- }
128-
129- toBundleDocument ( document : MutableDocument ) : ProtoDocument {
83+ toBundleDocument ( docBundleData : DocumentBundleData ) : ProtoDocument {
13084 // TODO handle documents that have mutations
13185 debugAssert (
132- ! document . hasLocalMutations ,
86+ ! docBundleData . documentData . hasLocalMutations ,
13387 "Can't serialize documents with mutations."
13488 ) ;
13589
136- // Convert document fields proto to DocumentData and then back
137- // to Proto3 JSON objects. This is the same approach used in
138- // bundling in the nodejs-firestore SDK. It may not be the most
139- // performant approach.
140- const documentData = this . userDataWriter . convertObjectMap (
141- document . data . value . mapValue . fields ,
142- 'previous'
143- ) ;
14490 // a parse context is typically used for validating and parsing user data, but in this
14591 // case we are using it internally to convert DocumentData to Proto3 JSON
14692 const context = this . userDataReader . createContext (
14793 UserDataSource . ArrayArgument ,
14894 'internal toBundledDocument'
14995 ) ;
150- const proto3Fields = parseObject ( documentData , context ) ;
96+ const proto3Fields = parseObject ( docBundleData . documentData , context ) ;
15197
15298 return {
153- name : toName ( this . serializer , document . key ) ,
99+ name : toName ( this . serializer , docBundleData . documentKey ) ,
154100 fields : proto3Fields . mapValue . fields ,
155- updateTime : toTimestamp ( this . serializer , document . version . toTimestamp ( ) ) ,
156- createTime : toTimestamp (
157- this . serializer ,
158- document . createTime . toTimestamp ( )
159- )
101+ updateTime : toTimestamp ( this . serializer , docBundleData . versionTime ) ,
102+ createTime : toTimestamp ( this . serializer , docBundleData . createdTime )
160103 } ;
161104 }
162105
163- private addBundledDocument ( snap : DocumentSnapshot , queryName ?: string ) : void {
164- if (
165- ! snap . _document ||
166- ! snap . _document . isValidDocument ( ) ||
167- ! snap . _document . isFoundDocument ( )
168- ) {
169- return ;
170- }
171- const originalDocument = this . documents . get ( snap . ref . path ) ;
106+ addBundleDocument ( docBundleData : DocumentBundleData ) : void {
107+ const originalDocument = this . documents . get ( docBundleData . documentPath ) ;
172108 const originalQueries = originalDocument ?. metadata . queries ;
173- const mutableCopy = snap . _document . mutableCopy ( ) ;
174109
110+ const readTime = docBundleData . readTime ;
175111 // Update with document built from `snap` because it is newer.
176- const snapReadTime = snap . readTime ;
177112 if (
178113 ! originalDocument ||
179- ( ! snapReadTime && ! originalDocument . metadata . readTime ) ||
180- ( snapReadTime && originalDocument . metadata . readTime ! < snapReadTime )
114+ ( ! readTime && ! originalDocument . metadata . readTime ) ||
115+ ( readTime && originalDocument . metadata . readTime ! < readTime )
181116 ) {
182- this . documents . set ( snap . ref . path , {
183- document : this . toBundleDocument ( mutableCopy ) ,
117+ this . documents . set ( docBundleData . documentPath , {
118+ document : this . toBundleDocument ( docBundleData ) ,
184119 metadata : {
185- name : toName ( this . serializer , mutableCopy . key ) ,
186- readTime : ! ! snapReadTime
187- ? toTimestamp ( this . serializer , snapReadTime )
120+ name : toName ( this . serializer , docBundleData . documentKey ) ,
121+ readTime : ! ! readTime
122+ ? toTimestamp ( this . serializer , readTime )
188123 : undefined ,
189- exists : snap . exists ( )
124+ exists : docBundleData . documentExists
190125 }
191126 } ) ;
192127 }
193128
194129 // Update `queries` to include both original and `queryName`.
195- const newDocument = this . documents . get ( snap . ref . path ) ! ;
130+ const newDocument = this . documents . get ( docBundleData . documentPath ) ! ;
196131 newDocument . metadata . queries = originalQueries || [ ] ;
197- if ( queryName ) {
198- newDocument . metadata . queries ! . push ( queryName ) ;
132+ if ( docBundleData . queryName ) {
133+ newDocument . metadata . queries ! . push ( docBundleData . queryName ) ;
199134 }
200-
201- if ( snapReadTime && snapReadTime > this . latestReadTime ) {
202- this . latestReadTime = snapReadTime ;
135+ if ( readTime && readTime > this . latestReadTime ) {
136+ this . latestReadTime = readTime ;
203137 }
204138 }
205139
206- // TODO: remove this since we're not planning to serialize named queries.
207- private addNamedQuery ( name : string , querySnap : QuerySnapshot ) : void {
140+ /*private addNamedQuery(name: string, querySnap: QuerySnapshot): void {
208141 if (this.namedQueries.has(name)) {
209142 throw new Error(`Query name conflict: ${name} has already been added.`);
210143 }
@@ -233,7 +166,7 @@ export class BundleBuilder {
233166 bundledQuery,
234167 readTime: toTimestamp(this.serializer, latestReadTime)
235168 });
236- }
169+ } */
237170
238171 /**
239172 * Converts a IBundleElement to a Buffer whose content is the length prefixed JSON representation
@@ -252,7 +185,7 @@ export class BundleBuilder {
252185 return `${ l } ${ str } ` ;
253186 }
254187
255- build ( ) : Uint8Array {
188+ build ( ) : string {
256189 let bundleString = '' ;
257190
258191 for ( const namedQuery of this . namedQueries . values ( ) ) {
@@ -282,51 +215,38 @@ export class BundleBuilder {
282215 // Prepends the metadata element to the bundleBuffer: `bundleBuffer` is the second argument to `Buffer.concat`.
283216 bundleString = this . lengthPrefixedString ( { metadata } ) + bundleString ;
284217
285- // TODO: it's not ideal to have to re-encode all of these strings multiple times
286- // the implementation in nodejs-firestore concatenates Buffers instead of
287- // concatenating strings.
288- return encoder . encode ( bundleString ) ;
218+ return bundleString ;
289219 }
290220}
291221
292222/**
293- * Convenient class to hold both the metadata and the actual content of a document to be bundled.
294- * @private
295- * @internal
296- */
297- class BundledDocument {
298- constructor (
299- readonly metadata : ProtoBundledDocumentMetadata ,
300- readonly document ?: Document
301- ) { }
302- }
303-
304- /**
305- * Validates that 'value' is DocumentSnapshot.
223+ * Interface for an object that contains data required to bundle a DocumentSnapshot.
224+ * Accessing the methods of DocumentSnapshot directly to retreivew this data in this
225+ * implementation would create a circular dependency.
306226 *
307- * @private
308227 * @internal
309- * @param arg The argument name or argument index (for varargs methods).
310- * @param value The input to validate.
311228 */
312- function validateDocumentSnapshot ( arg : string | number , value : unknown ) : void {
313- if ( ! ( value instanceof DocumentSnapshot ) ) {
314- throw new Error ( invalidArgumentMessage ( arg , 'DocumentSnapshot' ) ) ;
315- }
229+ export interface DocumentBundleData {
230+ readonly documentData : DocumentData ;
231+ readonly documentKey : DocumentKey ;
232+ readonly documentPath : string ;
233+ readonly documentExists : boolean ;
234+ readonly createdTime : Timestamp ;
235+ readonly readTime ?: Timestamp ;
236+ readonly versionTime : Timestamp ;
237+ readonly queryName ?: string ;
316238}
317239
318240/**
319- * Validates that 'value' is QuerySnapshot.
320- *
241+ * Convenient class to hold both the metadata and the actual content of a document to be bundled.
321242 * @private
322243 * @internal
323- * @param arg The argument name or argument index (for varargs methods).
324- * @param value The input to validate.
325244 */
326- function validateQuerySnapshot ( arg : string | number , value : unknown ) : void {
327- if ( ! ( value instanceof QuerySnapshot ) ) {
328- throw new Error ( invalidArgumentMessage ( arg , 'QuerySnapshot' ) ) ;
329- }
245+ class BundledDocument {
246+ constructor (
247+ readonly metadata : ProtoBundledDocumentMetadata ,
248+ readonly document ?: Document
249+ ) { }
330250}
331251
332252/**
0 commit comments