Skip to content

Commit 1bc2ccc

Browse files
Add equals methods (firebase#3176)
1 parent cc198ca commit 1bc2ccc

File tree

7 files changed

+248
-24
lines changed

7 files changed

+248
-24
lines changed

packages/firestore/exp/index.d.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ export class Query<T = DocumentData> {
286286
}
287287

288288
export class QuerySnapshot<T = DocumentData> {
289+
private constructor();
289290
readonly query: Query<T>;
290291
readonly docs: Array<QueryDocumentSnapshot<T>>;
291292
readonly metadata: SnapshotMetadata;
@@ -308,6 +309,7 @@ export interface DocumentChange<T = DocumentData> {
308309
}
309310

310311
export class CollectionReference<T = DocumentData> extends Query<T> {
312+
private constructor();
311313
readonly id: string;
312314
readonly path: string;
313315
withConverter<U>(
@@ -448,14 +450,14 @@ export class FieldPath {
448450

449451
export function documentId(): FieldPath;
450452

451-
export function refEqual(
452-
l: DocumentReference | CollectionReference,
453-
r: DocumentReference | CollectionReference
453+
export function refEqual<T>(
454+
left: DocumentReference<T> | CollectionReference<T>,
455+
right: DocumentReference<T> | CollectionReference<T>
454456
): boolean;
455-
export function queryEqual(l: Query, r: Query): boolean;
456-
export function snapshotEqual(
457-
l: DocumentSnapshot | QuerySnapshot,
458-
r: DocumentSnapshot | QuerySnapshot
457+
export function queryEqual<T>(left: Query<T>, right: Query<T>): boolean;
458+
export function snapshotEqual<T>(
459+
left: DocumentSnapshot<T> | QuerySnapshot<T>,
460+
right: DocumentSnapshot<T> | QuerySnapshot<T>
459461
): boolean;
460462

461463
export type FirestoreErrorCode =

packages/firestore/lite/index.d.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ export class Query<T = DocumentData> {
245245
}
246246

247247
export class QuerySnapshot<T = DocumentData> {
248+
private constructor();
248249
readonly query: Query<T>;
249250
readonly docs: Array<QueryDocumentSnapshot<T>>;
250251
readonly size: number;
@@ -256,6 +257,7 @@ export class QuerySnapshot<T = DocumentData> {
256257
}
257258

258259
export class CollectionReference<T = DocumentData> extends Query<T> {
260+
private constructor();
259261
readonly id: string;
260262
readonly path: string;
261263
withConverter<U>(
@@ -311,14 +313,14 @@ export class FieldPath {
311313

312314
export function documentId(): FieldPath;
313315

314-
export function refEqual(
315-
l: DocumentReference | CollectionReference,
316-
r: DocumentReference | CollectionReference
316+
export function refEqual<T>(
317+
left: DocumentReference<T> | CollectionReference<T>,
318+
right: DocumentReference<T> | CollectionReference<T>
317319
): boolean;
318-
export function queryEqual(l: Query, r: Query): boolean;
319-
export function snapshotEqual(
320-
l: DocumentSnapshot | QuerySnapshot,
321-
r: DocumentSnapshot | QuerySnapshot
320+
export function queryEqual<T>(left: Query<T>, right: Query<T>): boolean;
321+
export function snapshotEqual<T>(
322+
left: DocumentSnapshot<T> | QuerySnapshot<T>,
323+
right: DocumentSnapshot<T> | QuerySnapshot<T>
322324
): boolean;
323325

324326
export type FirestoreErrorCode =

packages/firestore/lite/index.node.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,17 @@ export {
3434
Query,
3535
CollectionReference,
3636
collection,
37+
collectionGroup,
3738
doc,
3839
parent,
3940
getDoc,
4041
getQuery,
4142
deleteDoc,
4243
setDoc,
4344
updateDoc,
44-
addDoc
45+
addDoc,
46+
refEqual,
47+
queryEqual
4548
} from './src/api/reference';
4649

4750
// TOOD(firestorelite): Add tests when Queries are usable
@@ -57,7 +60,11 @@ export {
5760
serverTimestamp
5861
} from './src/api/field_value';
5962

60-
export { DocumentSnapshot, QueryDocumentSnapshot } from './src/api/snapshot';
63+
export {
64+
DocumentSnapshot,
65+
QueryDocumentSnapshot,
66+
snapshotEqual
67+
} from './src/api/snapshot';
6168

6269
export { WriteBatch, writeBatch } from './src/api/write_batch';
6370

packages/firestore/lite/src/api/reference.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
validatePositiveNumber
6262
} from '../../../src/util/input_validation';
6363
import { FieldPath as ExternalFieldPath } from '../../../src/api/field_path';
64+
import { Code, FirestoreError } from '../../../src/util/error';
6465

6566
/**
6667
* A reference to a particular document in a collection in the database.
@@ -302,6 +303,28 @@ export function collection(
302303
}
303304
}
304305

306+
export function collectionGroup(
307+
firestore: firestore.FirebaseFirestore,
308+
collectionId: string
309+
): Query<firestore.DocumentData> {
310+
const firestoreClient = cast(firestore, Firestore);
311+
312+
validateArgType('collectionGroup', 'non-empty string', 1, collectionId);
313+
if (collectionId.indexOf('/') >= 0) {
314+
throw new FirestoreError(
315+
Code.INVALID_ARGUMENT,
316+
`Invalid collection ID '${collectionId}' passed to function ` +
317+
`collectionGroup(). Collection IDs must not contain '/'.`
318+
);
319+
}
320+
321+
return new Query(
322+
firestoreClient,
323+
new InternalQuery(ResourcePath.EMPTY_PATH, collectionId),
324+
/* converter= */ null
325+
);
326+
}
327+
305328
export function doc(
306329
firestore: firestore.FirebaseFirestore,
307330
documentPath: string
@@ -533,6 +556,38 @@ export function addDoc<T>(
533556
.then(() => docRef);
534557
}
535558

559+
export function refEqual<T>(
560+
left: firestore.DocumentReference<T> | firestore.CollectionReference<T>,
561+
right: firestore.DocumentReference<T> | firestore.CollectionReference<T>
562+
): boolean {
563+
if (
564+
(left instanceof DocumentReference ||
565+
left instanceof CollectionReference) &&
566+
(right instanceof DocumentReference || right instanceof CollectionReference)
567+
) {
568+
return (
569+
left.firestore === right.firestore &&
570+
left.path === right.path &&
571+
left._converter === right._converter
572+
);
573+
}
574+
return false;
575+
}
576+
577+
export function queryEqual<T>(
578+
left: firestore.Query<T>,
579+
right: firestore.Query<T>
580+
): boolean {
581+
if (left instanceof Query && right instanceof Query) {
582+
return (
583+
left.firestore === right.firestore &&
584+
left._query.isEqual(right._query) &&
585+
left._converter === right._converter
586+
);
587+
}
588+
return false;
589+
}
590+
536591
export function newUserDataReader(firestore: Firestore): UserDataReader {
537592
const settings = firestore._getSettings();
538593
const serializer = PlatformSupport.getPlatform().newSerializer(

packages/firestore/lite/src/api/snapshot.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818
import * as firestore from '../../index';
1919

2020
import { Firestore } from './database';
21-
import { DocumentReference } from './reference';
21+
import { DocumentReference, queryEqual } from './reference';
2222
import { FieldPath } from './field_path';
2323
import { cast } from './util';
2424
import { DocumentKey } from '../../../src/model/document_key';
2525
import { Document } from '../../../src/model/document';
2626
import { UserDataWriter } from '../../../src/api/user_data_writer';
2727
import { FieldPath as InternalFieldPath } from '../../../src/model/path';
2828
import { fieldPathFromDotSeparatedString } from '../../../src/api/user_data_reader';
29+
import { arrayEquals } from '../../../src/util/misc';
2930

3031
export class DocumentSnapshot<T = firestore.DocumentData>
3132
implements firestore.DocumentSnapshot<T> {
@@ -35,10 +36,10 @@ export class DocumentSnapshot<T = firestore.DocumentData>
3536
// - No support for SnapshotOptions.
3637

3738
constructor(
38-
private _firestore: Firestore,
39-
private _key: DocumentKey,
39+
public _firestore: Firestore,
40+
public _key: DocumentKey,
4041
public _document: Document | null,
41-
private _converter: firestore.FirestoreDataConverter<T> | null
42+
public _converter: firestore.FirestoreDataConverter<T> | null
4243
) {}
4344

4445
get id(): string {
@@ -112,8 +113,8 @@ export class QueryDocumentSnapshot<T = firestore.DocumentData>
112113
export class QuerySnapshot<T = firestore.DocumentData>
113114
implements firestore.QuerySnapshot<T> {
114115
constructor(
115-
readonly query: firestore.Query<T>,
116-
private readonly _docs: Array<QueryDocumentSnapshot<T>>
116+
public readonly query: firestore.Query<T>,
117+
public readonly _docs: Array<QueryDocumentSnapshot<T>>
117118
) {}
118119

119120
get docs(): Array<firestore.QueryDocumentSnapshot<T>> {
@@ -136,6 +137,29 @@ export class QuerySnapshot<T = firestore.DocumentData>
136137
}
137138
}
138139

140+
export function snapshotEqual<T>(
141+
left: firestore.DocumentSnapshot<T> | firestore.QuerySnapshot<T>,
142+
right: firestore.DocumentSnapshot<T> | firestore.QuerySnapshot<T>
143+
): boolean {
144+
if (left instanceof DocumentSnapshot && right instanceof DocumentSnapshot) {
145+
return (
146+
left._firestore === right._firestore &&
147+
left._key.isEqual(right._key) &&
148+
(left._document === null
149+
? right._document === null
150+
: left._document.isEqual(right._document)) &&
151+
left._converter === right._converter
152+
);
153+
} else if (left instanceof QuerySnapshot && right instanceof QuerySnapshot) {
154+
return (
155+
queryEqual(left.query, right.query) &&
156+
arrayEquals(left.docs, right.docs, snapshotEqual)
157+
);
158+
}
159+
160+
return false;
161+
}
162+
139163
/**
140164
* Helper that calls fromDotSeparatedString() but wraps any error thrown.
141165
*/

packages/firestore/lite/test/helpers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function withTestDocAndInitialData(
7070

7171
export function withTestCollectionAndInitialData(
7272
data: firestore.DocumentData[],
73-
fn: (doc: firestore.CollectionReference) => void | Promise<void>
73+
fn: (collRef: firestore.CollectionReference) => void | Promise<void>
7474
): Promise<void> {
7575
return withTestDb(async db => {
7676
const coll = collection(db, AutoId.newId());
@@ -83,7 +83,7 @@ export function withTestCollectionAndInitialData(
8383
}
8484

8585
export function withTestCollection(
86-
fn: (doc: firestore.CollectionReference) => void | Promise<void>
86+
fn: (collRef: firestore.CollectionReference) => void | Promise<void>
8787
): Promise<void> {
8888
return withTestDb(db => {
8989
return fn(collection(db, AutoId.newId()));

0 commit comments

Comments
 (0)