Skip to content

Commit 5e3620d

Browse files
committed
QuerySnapshot toJSON impl, but it has bugs
name and parent fields aren't properly populated. Looks like we have extraneous "orderBy" fields, too, which might be harmless.
1 parent a1e6a0b commit 5e3620d

File tree

3 files changed

+77
-26
lines changed

3 files changed

+77
-26
lines changed

common/api-review/firestore.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,8 @@ export class QuerySnapshot<AppModelType = DocumentData, DbModelType extends Docu
616616
readonly metadata: SnapshotMetadata;
617617
readonly query: Query<AppModelType, DbModelType>;
618618
get size(): number;
619+
// (undocumented)
620+
toJSON(): object;
619621
}
620622

621623
// @public

packages/firestore/src/api/snapshot.ts

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { DocumentKey } from '../model/document_key';
3838
import { debugAssert, fail } from '../util/assert';
3939
import { BundleBuilder, DocumentBundleData } from '../util/bundle_builder_impl';
4040
import { Code, FirestoreError } from '../util/error';
41+
import { AutoId } from '../util/misc';
4142

4243
import { Firestore } from './database';
4344
import { SnapshotListenOptions } from './reference_impl';
@@ -507,13 +508,23 @@ export class DocumentSnapshot<
507508
return { bundle: '' };
508509
}
509510

510-
const builder: BundleBuilder = new BundleBuilder(this._firestore, 'abc123');
511+
const builder: BundleBuilder = new BundleBuilder(
512+
this._firestore,
513+
AutoId.newId()
514+
);
511515
const documentData = this._userDataWriter.convertObjectMap(
512516
this._document.data.value.mapValue.fields,
513517
'previous'
514518
);
515519

516-
builder.addBundleDocument(DocumentToDocumentBundleData(this._firestore, this.ref.path, documentData, this._document));
520+
builder.addBundleDocument(
521+
DocumentToDocumentBundleData(
522+
this._firestore,
523+
this.ref.path,
524+
documentData,
525+
this._document
526+
)
527+
);
517528
return {
518529
bundle: builder.build()
519530
};
@@ -659,7 +670,7 @@ export class QuerySnapshot<
659670
throw new FirestoreError(
660671
Code.INVALID_ARGUMENT,
661672
'To include metadata changes with your document changes, you must ' +
662-
'also pass { includeMetadataChanges:true } to onSnapshot().'
673+
'also pass { includeMetadataChanges:true } to onSnapshot().'
663674
);
664675
}
665676

@@ -673,6 +684,35 @@ export class QuerySnapshot<
673684

674685
return this._cachedChanges;
675686
}
687+
688+
toJSON(): object {
689+
const builder: BundleBuilder = new BundleBuilder(
690+
this._firestore,
691+
AutoId.newId()
692+
);
693+
const docBundleDataArray: DocumentBundleData[] = [];
694+
const docArray = this.docs;
695+
docArray.forEach(doc => {
696+
if (doc._document === null) {
697+
return;
698+
}
699+
const documentData = this._userDataWriter.convertObjectMap(
700+
doc._document.data.value.mapValue.fields,
701+
'previous'
702+
);
703+
docBundleDataArray.push(
704+
DocumentToDocumentBundleData(
705+
this._firestore,
706+
doc.ref.path,
707+
documentData,
708+
doc._document
709+
)
710+
);
711+
});
712+
713+
builder.addBundleQuery(this.query._query, docBundleDataArray);
714+
return { bundle: builder.build() };
715+
}
676716
}
677717

678718
/** Calculates the array of `DocumentChange`s for a given `ViewSnapshot`. */
@@ -695,10 +735,10 @@ export function changesFromSnapshot<
695735
);
696736
debugAssert(
697737
!lastDoc ||
698-
newQueryComparator(querySnapshot._snapshot.query)(
699-
lastDoc,
700-
change.doc
701-
) < 0,
738+
newQueryComparator(querySnapshot._snapshot.query)(
739+
lastDoc,
740+
change.doc
741+
) < 0,
702742
'Got added events in wrong order'
703743
);
704744
const doc = new QueryDocumentSnapshot<AppModelType, DbModelType>(
@@ -813,7 +853,12 @@ export function snapshotEqual<AppModelType, DbModelType extends DocumentData>(
813853
return false;
814854
}
815855

816-
function DocumentToDocumentBundleData(firestore: Firestore, path: string, documentData: DocumentData, document: Document): DocumentBundleData {
856+
function DocumentToDocumentBundleData(
857+
firestore: Firestore,
858+
path: string,
859+
documentData: DocumentData,
860+
document: Document
861+
): DocumentBundleData {
817862
return {
818863
documentData,
819864
documentKey: document.mutableCopy().key,
@@ -823,4 +868,4 @@ function DocumentToDocumentBundleData(firestore: Firestore, path: string, docume
823868
readTime: document.readTime.toTimestamp(),
824869
versionTime: document.version.toTimestamp()
825870
};
826-
}
871+
}

packages/firestore/src/util/bundle_builder_impl.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
import {
1919
JsonProtoSerializer,
2020
toName,
21+
toQueryTarget,
2122
toTimestamp
2223
} from '../../src/remote/serializer';
2324
import { encoder } from '../../test/unit/util/bundle_data';
2425
import { Firestore } from '../api/database';
2526
import { DatabaseId } from '../core/database_info';
27+
import { Query, queryToTarget } from '../core/query';
2628
import { DocumentData } from '../lite-api/reference';
2729
import { Timestamp } from '../lite-api/timestamp';
2830
import {
@@ -103,7 +105,10 @@ export class BundleBuilder {
103105
};
104106
}
105107

106-
addBundleDocument(docBundleData: DocumentBundleData): void {
108+
addBundleDocument(
109+
docBundleData: DocumentBundleData,
110+
queryName?: string
111+
): void {
107112
const originalDocument = this.documents.get(docBundleData.documentPath);
108113
const originalQueries = originalDocument?.metadata.queries;
109114

@@ -127,32 +132,32 @@ export class BundleBuilder {
127132
}
128133

129134
// Update `queries` to include both original and `queryName`.
130-
const newDocument = this.documents.get(docBundleData.documentPath)!;
131-
newDocument.metadata.queries = originalQueries || [];
132-
if (docBundleData.queryName) {
133-
newDocument.metadata.queries!.push(docBundleData.queryName);
135+
if (queryName) {
136+
const newDocument = this.documents.get(docBundleData.documentPath)!;
137+
newDocument.metadata.queries = originalQueries || [];
138+
if (queryName) {
139+
newDocument.metadata.queries!.push(queryName);
140+
}
134141
}
135142
if (readTime && readTime > this.latestReadTime) {
136143
this.latestReadTime = readTime;
137144
}
138145
}
139146

140-
/*private addNamedQuery(name: string, querySnap: QuerySnapshot): void {
147+
addBundleQuery(query: Query, docBundleDataArray: DocumentBundleData[]): void {
148+
const queryTarget = toQueryTarget(this.serializer, queryToTarget(query));
149+
const name = queryTarget.parent.canonicalString();
150+
141151
if (this.namedQueries.has(name)) {
142152
throw new Error(`Query name conflict: ${name} has already been added.`);
143153
}
144-
const queryTarget = toQueryTarget(
145-
this.serializer,
146-
queryToTarget(querySnap.query._query)
147-
);
148154

149155
let latestReadTime = new Timestamp(0, 0);
150-
for (const snap of querySnap.docs) {
151-
const readTime = snap.readTime;
152-
if (readTime && readTime > latestReadTime) {
153-
latestReadTime = readTime;
156+
for (const docBundleData of docBundleDataArray) {
157+
this.addBundleDocument(docBundleData, name);
158+
if (docBundleData.readTime && docBundleData.readTime > latestReadTime) {
159+
latestReadTime = docBundleData.readTime;
154160
}
155-
this.addBundledDocument(snap, name);
156161
}
157162

158163
const bundledQuery = {
@@ -166,7 +171,7 @@ export class BundleBuilder {
166171
bundledQuery,
167172
readTime: toTimestamp(this.serializer, latestReadTime)
168173
});
169-
} */
174+
}
170175

171176
/**
172177
* Converts a IBundleElement to a Buffer whose content is the length prefixed JSON representation
@@ -234,7 +239,6 @@ export interface DocumentBundleData {
234239
readonly createdTime: Timestamp;
235240
readonly readTime?: Timestamp;
236241
readonly versionTime: Timestamp;
237-
readonly queryName?: string;
238242
}
239243

240244
/**

0 commit comments

Comments
 (0)