Skip to content

Commit 3bae066

Browse files
Return Firestore-Compat types from QuerySnapshot.docs
1 parent 068edfa commit 3bae066

File tree

3 files changed

+58
-10
lines changed

3 files changed

+58
-10
lines changed

packages/firestore/src/api/database.ts

+25-2
Original file line numberDiff line numberDiff line change
@@ -967,8 +967,11 @@ export class QueryDocumentSnapshot<T = PublicDocumentData>
967967
export class Query<T = PublicDocumentData>
968968
extends Compat<ExpQuery<T>>
969969
implements PublicQuery<T> {
970+
private readonly _userDataWriter: UserDataWriter;
971+
970972
constructor(readonly firestore: Firestore, delegate: ExpQuery<T>) {
971973
super(delegate);
974+
this._userDataWriter = new UserDataWriter(firestore);
972975
}
973976

974977
where(
@@ -1076,7 +1079,18 @@ export class Query<T = PublicDocumentData>
10761079
} else {
10771080
query = getDocs(this._delegate);
10781081
}
1079-
return query.then(result => new QuerySnapshot(this.firestore, result));
1082+
return query.then(
1083+
result =>
1084+
new QuerySnapshot(
1085+
this.firestore,
1086+
new ExpQuerySnapshot<T>(
1087+
this.firestore._delegate,
1088+
this._userDataWriter,
1089+
this._delegate,
1090+
result._snapshot
1091+
)
1092+
)
1093+
);
10801094
}
10811095

10821096
onSnapshot(observer: PartialObserver<PublicQuerySnapshot<T>>): Unsubscribe;
@@ -1100,7 +1114,16 @@ export class Query<T = PublicDocumentData>
11001114
const options = extractSnapshotOptions(args);
11011115
const observer = wrapObserver<QuerySnapshot<T>, ExpQuerySnapshot<T>>(
11021116
args,
1103-
snap => new QuerySnapshot(this.firestore, snap)
1117+
snap =>
1118+
new QuerySnapshot(
1119+
this.firestore,
1120+
new ExpQuerySnapshot<T>(
1121+
this.firestore._delegate,
1122+
this._userDataWriter,
1123+
this._delegate,
1124+
snap._snapshot
1125+
)
1126+
)
11041127
);
11051128
return onSnapshot(this._delegate, options, observer);
11061129
}

packages/firestore/test/integration/api/type.test.ts

+23-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { expect } from 'chai';
2020
import { addEqualityMatcher } from '../../util/equality_matcher';
2121
import * as firebaseExport from '../util/firebase_export';
2222
import { apiDescribe, withTestDb, withTestDoc } from '../util/helpers';
23+
import { EventsAccumulator } from '../util/events_accumulator';
2324

2425
const Blob = firebaseExport.Blob;
2526
const GeoPoint = firebaseExport.GeoPoint;
@@ -28,17 +29,31 @@ const Timestamp = firebaseExport.Timestamp;
2829
apiDescribe('Firestore', (persistence: boolean) => {
2930
addEqualityMatcher();
3031

31-
function expectRoundtrip(
32+
async function expectRoundtrip(
3233
db: firestore.FirebaseFirestore,
3334
data: {}
3435
): Promise<void> {
35-
const doc = db.collection('rooms').doc();
36-
return doc
37-
.set(data)
38-
.then(() => doc.get())
39-
.then(snapshot => {
40-
expect(snapshot.data()).to.deep.equal(data);
41-
});
36+
const collection = db.collection(db.collection('a').doc().id);
37+
const doc = collection.doc();
38+
await doc.set(data);
39+
40+
let docSnapshot = await doc.get();
41+
expect(docSnapshot.data()).to.deep.equal(data);
42+
43+
// TODO(b/174486484): If we wait for the backend response, the "can read
44+
// and write number fields" test fails since we store the backend proto
45+
// directly in IndexedDb, which turns -0.0 into 0.0
46+
let querySnapshot = await collection.get({ source: 'cache' });
47+
docSnapshot = querySnapshot.docs[0];
48+
expect(docSnapshot.data()).to.deep.equal(data);
49+
50+
const eventsAccumulator = new EventsAccumulator<firestore.QuerySnapshot>();
51+
const unlisten = collection.onSnapshot(eventsAccumulator.storeEvent);
52+
querySnapshot = await eventsAccumulator.awaitEvent();
53+
docSnapshot = querySnapshot.docs[0];
54+
expect(docSnapshot.data()).to.deep.equal(data);
55+
56+
unlisten();
4257
}
4358

4459
it('can read and write null fields', () => {

packages/firestore/test/util/equality_matcher.ts

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import { use } from 'chai';
19+
import { Indexable } from '../../src/util/misc';
1920

2021
/**
2122
* Duck-typed interface for objects that have an isEqual() method.
@@ -57,6 +58,15 @@ function customDeepEqual(
5758
return customMatcher.equalsFn(left, right);
5859
}
5960
}
61+
if (left && typeof left === 'object' && right && typeof right === 'object') {
62+
// The `isEqual` check below returns true if firestore-exp types are
63+
// compared with API types from Firestore classic. We do want to
64+
// differentiate between these types in our tests to ensure that the we do
65+
// not return firestore-exp types in the classic SDK.
66+
if ((left as Indexable).constructor !== (right as Indexable).constructor) {
67+
return false;
68+
}
69+
}
6070
if (typeof left === 'object' && left && 'isEqual' in left) {
6171
return (left as Equatable<unknown>).isEqual(right);
6272
}

0 commit comments

Comments
 (0)