Skip to content

Commit 6be9225

Browse files
FieldPath Compat class (#4038)
1 parent 2d325e7 commit 6be9225

File tree

6 files changed

+122
-158
lines changed

6 files changed

+122
-158
lines changed

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

+19-9
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { _BaseFieldPath } from '../../../src/api/field_path';
19-
import { DOCUMENT_KEY_NAME } from '../../../src/model/path';
18+
import {
19+
DOCUMENT_KEY_NAME,
20+
FieldPath as InternalFieldPath
21+
} from '../../../src/model/path';
22+
import { Code, FirestoreError } from '../../../src/util/error';
2023

2124
/**
2225
* A `FieldPath` refers to a field in a document. The path may consist of a
@@ -26,12 +29,9 @@ import { DOCUMENT_KEY_NAME } from '../../../src/model/path';
2629
* Create a `FieldPath` by providing field names. If more than one field
2730
* name is provided, the path will point to a nested field in a document.
2831
*/
29-
export class FieldPath extends _BaseFieldPath {
30-
// Note: This class is stripped down a copy of the FieldPath class in the
31-
// legacy SDK. The changes are:
32-
// - The `documentId()` static method has been removed
33-
// - Input validation is limited to errors that cannot be caught by the
34-
// TypeScript transpiler.
32+
export class FieldPath {
33+
/** Internal representation of a Firestore field path. */
34+
readonly _internalPath: InternalFieldPath;
3535

3636
/**
3737
* Creates a FieldPath from the provided field names. If more than one field
@@ -40,7 +40,17 @@ export class FieldPath extends _BaseFieldPath {
4040
* @param fieldNames A list of field names.
4141
*/
4242
constructor(...fieldNames: string[]) {
43-
super(fieldNames);
43+
for (let i = 0; i < fieldNames.length; ++i) {
44+
if (fieldNames[i].length === 0) {
45+
throw new FirestoreError(
46+
Code.INVALID_ARGUMENT,
47+
`Invalid field name at argument $(i + 1). ` +
48+
'Field names must not be empty.'
49+
);
50+
}
51+
}
52+
53+
this._internalPath = new InternalFieldPath(fieldNames);
4454
}
4555

4656
/**

packages/firestore/src/api/database.ts

+38-39
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ import {
7777
} from '../util/input_validation';
7878
import { logWarn, setLogLevel as setClientLogLevel } from '../util/log';
7979
import { AutoId } from '../util/misc';
80-
import { _BaseFieldPath, FieldPath as ExternalFieldPath } from './field_path';
80+
import { FieldPath as ExpFieldPath } from '../../lite/src/api/field_path';
8181
import {
8282
CompleteFn,
8383
ErrorFn,
@@ -119,6 +119,7 @@ import {
119119
DocumentData as PublicDocumentData,
120120
DocumentReference as PublicDocumentReference,
121121
DocumentSnapshot as PublicDocumentSnapshot,
122+
FieldPath as PublicFieldPath,
122123
FirebaseFirestore as PublicFirestore,
123124
FirestoreDataConverter as PublicFirestoreDataConverter,
124125
GetOptions as PublicGetOptions,
@@ -518,28 +519,33 @@ export class Transaction implements PublicTransaction {
518519
): Transaction;
519520
update(
520521
documentRef: PublicDocumentReference<unknown>,
521-
field: string | ExternalFieldPath,
522+
field: string | PublicFieldPath,
522523
value: unknown,
523524
...moreFieldsAndValues: unknown[]
524525
): Transaction;
525526
update(
526527
documentRef: PublicDocumentReference<unknown>,
527-
fieldOrUpdateData: string | ExternalFieldPath | PublicUpdateData,
528+
fieldOrUpdateData: string | PublicFieldPath | PublicUpdateData,
528529
value?: unknown,
529530
...moreFieldsAndValues: unknown[]
530531
): Transaction {
531-
let ref;
532-
let parsed;
532+
const ref = validateReference(
533+
'Transaction.update',
534+
documentRef,
535+
this._firestore
536+
);
533537

538+
// For Compat types, we have to "extract" the underlying types before
539+
// performing validation.
540+
if (fieldOrUpdateData instanceof Compat) {
541+
fieldOrUpdateData = (fieldOrUpdateData as Compat<ExpFieldPath>)._delegate;
542+
}
543+
544+
let parsed;
534545
if (
535546
typeof fieldOrUpdateData === 'string' ||
536-
fieldOrUpdateData instanceof ExternalFieldPath
547+
fieldOrUpdateData instanceof ExpFieldPath
537548
) {
538-
ref = validateReference(
539-
'Transaction.update',
540-
documentRef,
541-
this._firestore
542-
);
543549
parsed = parseUpdateVarargs(
544550
this._dataReader,
545551
'Transaction.update',
@@ -549,11 +555,6 @@ export class Transaction implements PublicTransaction {
549555
moreFieldsAndValues
550556
);
551557
} else {
552-
ref = validateReference(
553-
'Transaction.update',
554-
documentRef,
555-
this._firestore
556-
);
557558
parsed = parseUpdateData(
558559
this._dataReader,
559560
'Transaction.update',
@@ -629,30 +630,34 @@ export class WriteBatch implements PublicWriteBatch {
629630
): WriteBatch;
630631
update(
631632
documentRef: PublicDocumentReference<unknown>,
632-
field: string | ExternalFieldPath,
633+
field: string | PublicFieldPath,
633634
value: unknown,
634635
...moreFieldsAndValues: unknown[]
635636
): WriteBatch;
636637
update(
637638
documentRef: PublicDocumentReference<unknown>,
638-
fieldOrUpdateData: string | ExternalFieldPath | PublicUpdateData,
639+
fieldOrUpdateData: string | PublicFieldPath | PublicUpdateData,
639640
value?: unknown,
640641
...moreFieldsAndValues: unknown[]
641642
): WriteBatch {
642643
this.verifyNotCommitted();
644+
const ref = validateReference(
645+
'WriteBatch.update',
646+
documentRef,
647+
this._firestore
648+
);
643649

644-
let ref;
645-
let parsed;
650+
// For Compat types, we have to "extract" the underlying types before
651+
// performing validation.
652+
if (fieldOrUpdateData instanceof Compat) {
653+
fieldOrUpdateData = (fieldOrUpdateData as Compat<ExpFieldPath>)._delegate;
654+
}
646655

656+
let parsed;
647657
if (
648658
typeof fieldOrUpdateData === 'string' ||
649-
fieldOrUpdateData instanceof ExternalFieldPath
659+
fieldOrUpdateData instanceof ExpFieldPath
650660
) {
651-
ref = validateReference(
652-
'WriteBatch.update',
653-
documentRef,
654-
this._firestore
655-
);
656661
parsed = parseUpdateVarargs(
657662
this._dataReader,
658663
'WriteBatch.update',
@@ -662,11 +667,6 @@ export class WriteBatch implements PublicWriteBatch {
662667
moreFieldsAndValues
663668
);
664669
} else {
665-
ref = validateReference(
666-
'WriteBatch.update',
667-
documentRef,
668-
this._firestore
669-
);
670670
parsed = parseUpdateData(
671671
this._dataReader,
672672
'WriteBatch.update',
@@ -825,26 +825,25 @@ export class DocumentReference<T = PublicDocumentData>
825825

826826
update(value: PublicUpdateData): Promise<void>;
827827
update(
828-
field: string | ExternalFieldPath,
828+
field: string | PublicFieldPath,
829829
value: unknown,
830830
...moreFieldsAndValues: unknown[]
831831
): Promise<void>;
832832
update(
833-
fieldOrUpdateData: string | ExternalFieldPath | PublicUpdateData,
833+
fieldOrUpdateData: string | PublicFieldPath | PublicUpdateData,
834834
value?: unknown,
835835
...moreFieldsAndValues: unknown[]
836836
): Promise<void> {
837837
// For Compat types, we have to "extract" the underlying types before
838838
// performing validation.
839839
if (fieldOrUpdateData instanceof Compat) {
840-
fieldOrUpdateData = (fieldOrUpdateData as Compat<_BaseFieldPath>)
841-
._delegate;
840+
fieldOrUpdateData = (fieldOrUpdateData as Compat<ExpFieldPath>)._delegate;
842841
}
843842

844843
let parsed;
845844
if (
846845
typeof fieldOrUpdateData === 'string' ||
847-
fieldOrUpdateData instanceof _BaseFieldPath
846+
fieldOrUpdateData instanceof ExpFieldPath
848847
) {
849848
parsed = parseUpdateVarargs(
850849
this._dataReader,
@@ -1080,7 +1079,7 @@ export class DocumentSnapshot<T = PublicDocumentData>
10801079
}
10811080

10821081
get(
1083-
fieldPath: string | ExternalFieldPath,
1082+
fieldPath: string | PublicFieldPath,
10841083
options: PublicSnapshotOptions = {}
10851084
): unknown {
10861085
if (this._document) {
@@ -1556,7 +1555,7 @@ export class Query<T = PublicDocumentData> implements PublicQuery<T> {
15561555
}
15571556

15581557
where(
1559-
field: string | ExternalFieldPath,
1558+
field: string | PublicFieldPath,
15601559
opStr: PublicWhereFilterOp,
15611560
value: unknown
15621561
): PublicQuery<T> {
@@ -1578,7 +1577,7 @@ export class Query<T = PublicDocumentData> implements PublicQuery<T> {
15781577
}
15791578

15801579
orderBy(
1581-
field: string | ExternalFieldPath,
1580+
field: string | PublicFieldPath,
15821581
directionStr?: PublicOrderByDirection
15831582
): PublicQuery<T> {
15841583
let direction: Direction;

packages/firestore/src/api/field_path.ts

+9-58
Original file line numberDiff line numberDiff line change
@@ -17,52 +17,28 @@
1717

1818
import { FieldPath as PublicFieldPath } from '@firebase/firestore-types';
1919

20+
import { FieldPath as ExpFieldPath } from '../../lite/src/api/field_path';
2021
import { FieldPath as InternalFieldPath } from '../model/path';
21-
import { Code, FirestoreError } from '../util/error';
22+
import { Compat } from '../compat/compat';
2223

2324
// The objects that are a part of this API are exposed to third-parties as
2425
// compiled javascript so we want to flag our private members with a leading
2526
// underscore to discourage their use.
2627

27-
/**
28-
* A field class base class that is shared by the lite, full and legacy SDK,
29-
* which supports shared code that deals with FieldPaths.
30-
*/
31-
// Use underscore prefix to hide this class from our Public API.
32-
// eslint-disable-next-line @typescript-eslint/naming-convention
33-
export abstract class _BaseFieldPath {
34-
/** Internal representation of a Firestore field path. */
35-
readonly _internalPath: InternalFieldPath;
36-
37-
constructor(fieldNames: string[]) {
38-
for (let i = 0; i < fieldNames.length; ++i) {
39-
if (fieldNames[i].length === 0) {
40-
throw new FirestoreError(
41-
Code.INVALID_ARGUMENT,
42-
`Invalid field name at argument $(i + 1). ` +
43-
'Field names must not be empty.'
44-
);
45-
}
46-
}
47-
48-
this._internalPath = new InternalFieldPath(fieldNames);
49-
}
50-
}
51-
5228
/**
5329
* A `FieldPath` refers to a field in a document. The path may consist of a
5430
* single field name (referring to a top-level field in the document), or a list
5531
* of field names (referring to a nested field in the document).
5632
*/
57-
export class FieldPath extends _BaseFieldPath implements PublicFieldPath {
33+
export class FieldPath extends Compat<ExpFieldPath> implements PublicFieldPath {
5834
/**
5935
* Creates a FieldPath from the provided field names. If more than one field
6036
* name is provided, the path will point to a nested field in a document.
6137
*
6238
* @param fieldNames A list of field names.
6339
*/
6440
constructor(...fieldNames: string[]) {
65-
super(fieldNames);
41+
super(new ExpFieldPath(...fieldNames));
6642
}
6743

6844
static documentId(): FieldPath {
@@ -76,37 +52,12 @@ export class FieldPath extends _BaseFieldPath implements PublicFieldPath {
7652
}
7753

7854
isEqual(other: PublicFieldPath): boolean {
79-
if (!(other instanceof FieldPath)) {
55+
if (other instanceof Compat) {
56+
other = other._delegate;
57+
}
58+
if (!(other instanceof ExpFieldPath)) {
8059
return false;
8160
}
82-
return this._internalPath.isEqual(other._internalPath);
83-
}
84-
}
85-
86-
/**
87-
* Matches any characters in a field path string that are reserved.
88-
*/
89-
const RESERVED = new RegExp('[~\\*/\\[\\]]');
90-
91-
/**
92-
* Parses a field path string into a FieldPath, treating dots as separators.
93-
*/
94-
export function fromDotSeparatedString(path: string): FieldPath {
95-
const found = path.search(RESERVED);
96-
if (found >= 0) {
97-
throw new FirestoreError(
98-
Code.INVALID_ARGUMENT,
99-
`Invalid field path (${path}). Paths must not contain ` +
100-
`'~', '*', '/', '[', or ']'`
101-
);
102-
}
103-
try {
104-
return new FieldPath(...path.split('.'));
105-
} catch (e) {
106-
throw new FirestoreError(
107-
Code.INVALID_ARGUMENT,
108-
`Invalid field path (${path}). Paths must not be empty, ` +
109-
`begin with '.', end with '.', or contain '..'`
110-
);
61+
return this._delegate._internalPath.isEqual(other._internalPath);
11162
}
11263
}

0 commit comments

Comments
 (0)