Skip to content

Commit 624979c

Browse files
committed
Adding additional comments and types to the sample code for clarity.
1 parent 6584666 commit 624979c

File tree

2 files changed

+248
-228
lines changed

2 files changed

+248
-228
lines changed

packages/firestore/src/api/snapshot.ts

Lines changed: 124 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -53,149 +53,159 @@ import { SnapshotListenOptions } from './reference_impl';
5353
* Simple Example
5454
*
5555
* ```typescript
56-
* const numberConverter = {
57-
* toFirestore(value: WithFieldValue<number>) {
58-
* return { value };
59-
* },
60-
* fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
61-
* return snapshot.data(options).value as number;
62-
* }
56+
* const numberConverter: FirestoreDataConverter<number, {value: number}> = {
57+
* toFirestore(value: WithFieldValue<number>) {
58+
* return { value };
59+
* },
60+
* fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
61+
* return snapshot.data(options).value as number;
62+
* }
6363
* };
6464
*
6565
* async function simpleDemo(db: Firestore): Promise<void> {
66-
* const documentRef = doc(db, 'values/value123').withConverter(numberConverter);
66+
* const documentRef = doc(db, 'values/value123').withConverter(numberConverter);
6767
*
68-
* await setDoc(documentRef, 42);
69-
* const snapshot1 = await getDoc(documentRef);
70-
* assertEqual(snapshot1.data(), 42);
68+
* // converters are used with `setDoc`, `addDoc`, and `getDoc`
69+
* await setDoc(documentRef, 42);
70+
* const snapshot1 = await getDoc(documentRef);
71+
* assertEqual(snapshot1.data(), 42);
7172
*
72-
* await updateDoc(documentRef, { value: 999 });
73-
* const snapshot2 = await getDoc(documentRef);
74-
* assertEqual(snapshot2.data(), 999);
73+
* // converters are not used when writing data with `updateDoc`
74+
* await updateDoc(documentRef, { value: 999 });
75+
* const snapshot2 = await getDoc(documentRef);
76+
* assertEqual(snapshot2.data(), 999);
7577
* }
7678
* ```
7779
*
7880
* Advanced Example
7981
*
8082
* ```typescript
83+
* // The Post class is a model that is used by our application.
84+
* // This class may have properties and methods that are specific
85+
* // to our application execution, which do not need to be persisted
86+
* // to Firestore.
8187
* class Post {
82-
* constructor(
83-
* readonly title: string,
84-
* readonly author: string,
85-
* readonly lastUpdatedMillis: number
86-
* ) {}
87-
*
88-
* toString(): string {
89-
* return `${this.title} by ${this.author}`;
90-
* }
88+
* constructor(
89+
* readonly title: string,
90+
* readonly author: string,
91+
* readonly lastUpdatedMillis: number
92+
* ) {}
93+
* toString(): string {
94+
* return `${this.title} by ${this.author}`;
95+
* }
9196
* }
9297
*
98+
* // The PostDbModel represents how we want our posts to be stored
99+
* // in Firestore. This DbModel has different properties (`ttl`,
100+
* // `aut`, and `lut`) from the Post class we use in our application.
93101
* interface PostDbModel {
94-
* ttl: string;
95-
* aut: { firstName: string; lastName: string };
96-
* lut: Timestamp;
102+
* ttl: string;
103+
* aut: { firstName: string; lastName: string };
104+
* lut: Timestamp;
97105
* }
98106
*
99-
* const postConverter = {
100-
* toFirestore(post: WithFieldValue<Post>) {
101-
* return {
102-
* ttl: post.title,
103-
* aut: this._autFromAuthor(post.author),
104-
* lut: this._lutFromLastUpdatedMillis(post.lastUpdatedMillis)
105-
* };
106-
* },
107+
* // The `PostConverter` implements `FirestoreDataConverter<AppModelType, DbModelType>`
108+
* // and specifies how the Firestore SDK can convert `Post` objects to `PostDbModel`
109+
* // objects and vice versa.
110+
* class PostConverter implements FirestoreDataConverter<Post, PostDbModel> {
111+
* toFirestore(post: WithFieldValue<Post>) {
112+
* return {
113+
* ttl: post.title,
114+
* aut: this._autFromAuthor(post.author),
115+
* lut: this._lutFromLastUpdatedMillis(post.lastUpdatedMillis)
116+
* };
117+
* }
107118
*
108-
* fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
109-
* const data = snapshot.data(options) as PostDbModel;
110-
* const author = `${data.aut.firstName} ${data.aut.lastName}`;
111-
* return new Post(data.ttl, author, data.lut.toMillis());
112-
* },
119+
* fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
120+
* const data = snapshot.data(options) as PostDbModel;
121+
* const author = `${data.aut.firstName} ${data.aut.lastName}`;
122+
* return new Post(data.ttl, author, data.lut.toMillis());
123+
* }
113124
*
114-
* _autFromAuthor(
115-
* author: string | FieldValue
116-
* ): { firstName: string; lastName: string } | FieldValue {
117-
* if (typeof author !== 'string') {
118-
* // `author` is a FieldValue, so just return it.
119-
* return author;
125+
* _autFromAuthor(
126+
* author: string | FieldValue
127+
* ): { firstName: string; lastName: string } | FieldValue {
128+
* if (typeof author !== 'string') {
129+
* // `author` is a FieldValue, so just return it.
130+
* return author;
131+
* }
132+
* const [firstName, lastName] = author.split(' ');
133+
* return {firstName, lastName};
120134
* }
121-
* const [firstName, lastName] = author.split(' ');
122-
* return { firstName, lastName };
123-
* },
124135
*
125-
* _lutFromLastUpdatedMillis(
126-
* lastUpdatedMillis: number | FieldValue
127-
* ): Timestamp | FieldValue {
128-
* if (typeof lastUpdatedMillis !== 'number') {
129-
* // `lastUpdatedMillis` must be a FieldValue, so just return it.
130-
* return lastUpdatedMillis;
136+
* _lutFromLastUpdatedMillis(
137+
* lastUpdatedMillis: number | FieldValue
138+
* ): Timestamp | FieldValue {
139+
* if (typeof lastUpdatedMillis !== 'number') {
140+
* // `lastUpdatedMillis` must be a FieldValue, so just return it.
141+
* return lastUpdatedMillis;
142+
* }
143+
* return Timestamp.fromMillis(lastUpdatedMillis);
131144
* }
132-
* return Timestamp.fromMillis(lastUpdatedMillis);
133-
* }
134-
* };
145+
* }
135146
*
136147
* async function advancedDemo(db: Firestore): Promise<void> {
137-
* // Create a `DocumentReference` with a `FirestoreDataConverter`.
138-
* const documentRef = doc(db, 'posts/post123').withConverter(postConverter);
139-
*
140-
* // The `data` argument specified to `setDoc()` is type checked by the
141-
* // TypeScript compiler to be compatible with `Post`. Since the `data`
142-
* // argument is typed as `WithFieldValue<Post>` rather than just `Post`,
143-
* // this allows properties of the `data` argument to also be special
144-
* // Firestore values that perform server-side mutations, such as
145-
* // `arrayRemove()`, `deleteField()`, and `serverTimestamp()`.
146-
* await setDoc(documentRef, {
147-
* title: 'My Life',
148-
* author: 'Foo Bar',
149-
* lastUpdatedMillis: serverTimestamp()
150-
* });
148+
* // Create a `DocumentReference` with a `FirestoreDataConverter`.
149+
* const documentRef = doc(db, 'posts/post123').withConverter(new PostConverter());
151150
*
152-
* // The TypeScript compiler will fail to compile if the `data` argument to
153-
* // `setDoc()` is _not_ be compatible with `WithFieldValue<Post>`. This
154-
* // type checking prevents the caller from specifying objects with incorrect
155-
* // properties or property values.
156-
* // @ts-expect-error "Argument of type { ttl: string; } is not assignable
157-
* // to parameter of type WithFieldValue<Post>"
158-
* await setDoc(documentRef, { ttl: 'The Title' });
151+
* // The `data` argument specified to `setDoc()` is type checked by the
152+
* // TypeScript compiler to be compatible with `Post`. Since the `data`
153+
* // argument is typed as `WithFieldValue<Post>` rather than just `Post`,
154+
* // this allows properties of the `data` argument to also be special
155+
* // Firestore values that perform server-side mutations, such as
156+
* // `arrayRemove()`, `deleteField()`, and `serverTimestamp()`.
157+
* await setDoc(documentRef, {
158+
* title: 'My Life',
159+
* author: 'Foo Bar',
160+
* lastUpdatedMillis: serverTimestamp()
161+
* });
159162
*
160-
* // When retrieving a document with `getDoc()` the `DocumentSnapshot`
161-
* // object's `data()` method returns a `Post`, rather than a generic object,
162-
* // which is returned if the `DocumentReference` did _not_ have a
163-
* // `FirestoreDataConverter` attached to it.
164-
* const snapshot1: DocumentSnapshot<Post> = await getDoc(documentRef);
165-
* const post1: Post = snapshot1.data()!;
166-
* if (post1) {
167-
* assertEqual(post1.title, 'My Life');
168-
* assertEqual(post1.author, 'Foo Bar');
169-
* }
163+
* // The TypeScript compiler will fail to compile if the `data` argument to
164+
* // `setDoc()` is _not_ be compatible with `WithFieldValue<Post>`. This
165+
* // type checking prevents the caller from specifying objects with incorrect
166+
* // properties or property values.
167+
* // @ts-expect-error "Argument of type { ttl: string; } is not assignable
168+
* // to parameter of type WithFieldValue<Post>"
169+
* await setDoc(documentRef, { ttl: 'The Title' });
170170
*
171-
* // The `data` argument specified to `updateDoc()` is type checked by the
172-
* // TypeScript compiler to be compatible with `PostDbModel`. Note that
173-
* // unlike `setDoc()`, whose `data` argument must be compatible with `Post`,
174-
* // the `data` argument to `updateDoc()` must be compatible with
175-
* // `PostDbModel`. Similar to `setDoc()`, since the `data` argument is typed
176-
* // as `WithFieldValue<PostDbModel>` rather than just `PostDbModel`, this
177-
* // allows properties of the `data` argument to also be those special
178-
* // Firestore values, like as `arrayRemove()`, `deleteField()`, and
179-
* // `serverTimestamp()`.
180-
* await updateDoc(documentRef, {
181-
* 'aut.firstName': 'NewFirstName',
182-
* lut: serverTimestamp()
183-
* });
171+
* // When retrieving a document with `getDoc()` the `DocumentSnapshot`
172+
* // object's `data()` method returns a `Post`, rather than a generic object,
173+
* // which would have been returned if the `DocumentReference` did _not_ have a
174+
* // `FirestoreDataConverter` attached to it.
175+
* const snapshot1: DocumentSnapshot<Post> = await getDoc(documentRef);
176+
* const post1: Post = snapshot1.data()!;
177+
* if (post1) {
178+
* assertEqual(post1.title, 'My Life');
179+
* assertEqual(post1.author, 'Foo Bar');
180+
* }
184181
*
185-
* // The TypeScript compiler will fail to compile if the `data` argument to
186-
* // `updateDoc()` is _not_ be compatible with `WithFieldValue<PostDbModel>`.
187-
* // This type checking prevents the caller from specifying objects with
188-
* // incorrect properties or property values.
189-
* // @ts-expect-error "Argument of type { title: string; } is not assignable
190-
* // to parameter of type WithFieldValue<PostDbModel>"
191-
* await updateDoc(documentRef, { title: 'New Title' });
182+
* // The `data` argument specified to `updateDoc()` is type checked by the
183+
* // TypeScript compiler to be compatible with `PostDbModel`. Note that
184+
* // unlike `setDoc()`, whose `data` argument must be compatible with `Post`,
185+
* // the `data` argument to `updateDoc()` must be compatible with
186+
* // `PostDbModel`. Similar to `setDoc()`, since the `data` argument is typed
187+
* // as `WithFieldValue<PostDbModel>` rather than just `PostDbModel`, this
188+
* // allows properties of the `data` argument to also be those special
189+
* // Firestore values, like as `arrayRemove()`, `deleteField()`, and
190+
* // `serverTimestamp()`.
191+
* await updateDoc(documentRef, {
192+
* 'aut.firstName': 'NewFirstName',
193+
* lut: serverTimestamp()
194+
* });
192195
*
193-
* const snapshot2: DocumentSnapshot<Post> = await getDoc(documentRef);
194-
* const post2: Post = snapshot2.data()!;
195-
* if (post2) {
196-
* assertEqual(post2.title, 'My Life');
197-
* assertEqual(post2.author, 'NewFirstName Bar');
198-
* }
196+
* // The TypeScript compiler will fail to compile if the `data` argument to
197+
* // `updateDoc()` is _not_ be compatible with `WithFieldValue<PostDbModel>`.
198+
* // This type checking prevents the caller from specifying objects with
199+
* // incorrect properties or property values.
200+
* // @ts-expect-error "Argument of type { title: string; } is not assignable
201+
* // to parameter of type WithFieldValue<PostDbModel>"
202+
* await updateDoc(documentRef, { title: 'New Title' });
203+
* const snapshot2: DocumentSnapshot<Post> = await getDoc(documentRef);
204+
* const post2: Post = snapshot2.data()!;
205+
* if (post2) {
206+
* assertEqual(post2.title, 'My Life');
207+
* assertEqual(post2.author, 'NewFirstName Bar');
208+
* }
199209
* }
200210
* ```
201211
*/

0 commit comments

Comments
 (0)