Skip to content

Commit 677538f

Browse files
committed
docgen devsite
1 parent 162a373 commit 677538f

File tree

2 files changed

+264
-244
lines changed

2 files changed

+264
-244
lines changed

docs-devsite/firestore_.firestoredataconverter.md

Lines changed: 132 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -101,149 +101,159 @@ toFirestore(modelObject: PartialWithFieldValue<AppModelType>, options: SetOption
101101
Simple Example
102102

103103
```typescript
104-
const numberConverter = {
105-
toFirestore(value: WithFieldValue<number>) {
106-
return { value };
107-
},
108-
fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
109-
return snapshot.data(options).value as number;
110-
}
104+
const numberConverter: FirestoreDataConverter<number, {value: number}> = {
105+
toFirestore(value: WithFieldValue<number>) {
106+
return { value };
107+
},
108+
fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
109+
return snapshot.data(options).value as number;
110+
}
111111
};
112112
113113
async function simpleDemo(db: Firestore): Promise<void> {
114-
const documentRef = doc(db, 'values/value123').withConverter(numberConverter);
114+
const documentRef = doc(db, 'values/value123').withConverter(numberConverter);
115115
116-
await setDoc(documentRef, 42);
117-
const snapshot1 = await getDoc(documentRef);
118-
assertEqual(snapshot1.data(), 42);
116+
// converters are used with `setDoc`, `addDoc`, and `getDoc`
117+
await setDoc(documentRef, 42);
118+
const snapshot1 = await getDoc(documentRef);
119+
assertEqual(snapshot1.data(), 42);
119120
120-
await updateDoc(documentRef, { value: 999 });
121-
const snapshot2 = await getDoc(documentRef);
122-
assertEqual(snapshot2.data(), 999);
121+
// converters are not used when writing data with `updateDoc`
122+
await updateDoc(documentRef, { value: 999 });
123+
const snapshot2 = await getDoc(documentRef);
124+
assertEqual(snapshot2.data(), 999);
123125
}
124126
125127
```
126128
Advanced Example
127129

128130
```typescript
131+
// The Post class is a model that is used by our application.
132+
// This class may have properties and methods that are specific
133+
// to our application execution, which do not need to be persisted
134+
// to Firestore.
129135
class Post {
130-
constructor(
131-
readonly title: string,
132-
readonly author: string,
133-
readonly lastUpdatedMillis: number
134-
) {}
135-
136-
toString(): string {
137-
return `${this.title} by ${this.author}`;
138-
}
136+
constructor(
137+
readonly title: string,
138+
readonly author: string,
139+
readonly lastUpdatedMillis: number
140+
) {}
141+
toString(): string {
142+
return `${this.title} by ${this.author}`;
143+
}
139144
}
140145
146+
// The PostDbModel represents how we want our posts to be stored
147+
// in Firestore. This DbModel has different properties (`ttl`,
148+
// `aut`, and `lut`) from the Post class we use in our application.
141149
interface PostDbModel {
142-
ttl: string;
143-
aut: { firstName: string; lastName: string };
144-
lut: Timestamp;
150+
ttl: string;
151+
aut: { firstName: string; lastName: string };
152+
lut: Timestamp;
145153
}
146154
147-
const postConverter = {
148-
toFirestore(post: WithFieldValue<Post>) {
149-
return {
150-
ttl: post.title,
151-
aut: this._autFromAuthor(post.author),
152-
lut: this._lutFromLastUpdatedMillis(post.lastUpdatedMillis)
153-
};
154-
},
155-
156-
fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
157-
const data = snapshot.data(options) as PostDbModel;
158-
const author = `${data.aut.firstName} ${data.aut.lastName}`;
159-
return new Post(data.ttl, author, data.lut.toMillis());
160-
},
161-
162-
_autFromAuthor(
163-
author: string | FieldValue
164-
): { firstName: string; lastName: string } | FieldValue {
165-
if (typeof author !== 'string') {
166-
// `author` is a FieldValue, so just return it.
167-
return author;
155+
// The `PostConverter` implements `FirestoreDataConverter<AppModelType, DbModelType>`
156+
// and specifies how the Firestore SDK can convert `Post` objects to `PostDbModel`
157+
// objects and vice versa.
158+
class PostConverter implements FirestoreDataConverter<Post, PostDbModel> {
159+
toFirestore(post: WithFieldValue<Post>) {
160+
return {
161+
ttl: post.title,
162+
aut: this._autFromAuthor(post.author),
163+
lut: this._lutFromLastUpdatedMillis(post.lastUpdatedMillis)
164+
};
165+
}
166+
167+
fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
168+
const data = snapshot.data(options) as PostDbModel;
169+
const author = `${data.aut.firstName} ${data.aut.lastName}`;
170+
return new Post(data.ttl, author, data.lut.toMillis());
168171
}
169-
const [firstName, lastName] = author.split(' ');
170-
return { firstName, lastName };
171-
},
172-
173-
_lutFromLastUpdatedMillis(
174-
lastUpdatedMillis: number | FieldValue
175-
): Timestamp | FieldValue {
176-
if (typeof lastUpdatedMillis !== 'number') {
177-
// `lastUpdatedMillis` must be a FieldValue, so just return it.
178-
return lastUpdatedMillis;
172+
173+
_autFromAuthor(
174+
author: string | FieldValue
175+
): { firstName: string; lastName: string } | FieldValue {
176+
if (typeof author !== 'string') {
177+
// `author` is a FieldValue, so just return it.
178+
return author;
179+
}
180+
const [firstName, lastName] = author.split(' ');
181+
return {firstName, lastName};
179182
}
180-
return Timestamp.fromMillis(lastUpdatedMillis);
181-
}
182-
};
183+
184+
_lutFromLastUpdatedMillis(
185+
lastUpdatedMillis: number | FieldValue
186+
): Timestamp | FieldValue {
187+
if (typeof lastUpdatedMillis !== 'number') {
188+
// `lastUpdatedMillis` must be a FieldValue, so just return it.
189+
return lastUpdatedMillis;
190+
}
191+
return Timestamp.fromMillis(lastUpdatedMillis);
192+
}
193+
}
183194
184195
async function advancedDemo(db: Firestore): Promise<void> {
185-
// Create a `DocumentReference` with a `FirestoreDataConverter`.
186-
const documentRef = doc(db, 'posts/post123').withConverter(postConverter);
187-
188-
// The `data` argument specified to `setDoc()` is type checked by the
189-
// TypeScript compiler to be compatible with `Post`. Since the `data`
190-
// argument is typed as `WithFieldValue<Post>` rather than just `Post`,
191-
// this allows properties of the `data` argument to also be special
192-
// Firestore values that perform server-side mutations, such as
193-
// `arrayRemove()`, `deleteField()`, and `serverTimestamp()`.
194-
await setDoc(documentRef, {
195-
title: 'My Life',
196-
author: 'Foo Bar',
197-
lastUpdatedMillis: serverTimestamp()
198-
});
199-
200-
// The TypeScript compiler will fail to compile if the `data` argument to
201-
// `setDoc()` is _not_ be compatible with `WithFieldValue<Post>`. This
202-
// type checking prevents the caller from specifying objects with incorrect
203-
// properties or property values.
204-
// @ts-expect-error "Argument of type { ttl: string; } is not assignable
205-
// to parameter of type WithFieldValue<Post>"
206-
await setDoc(documentRef, { ttl: 'The Title' });
207-
208-
// When retrieving a document with `getDoc()` the `DocumentSnapshot`
209-
// object's `data()` method returns a `Post`, rather than a generic object,
210-
// which is returned if the `DocumentReference` did _not_ have a
211-
// `FirestoreDataConverter` attached to it.
212-
const snapshot1: DocumentSnapshot<Post> = await getDoc(documentRef);
213-
const post1: Post = snapshot1.data()!;
214-
if (post1) {
215-
assertEqual(post1.title, 'My Life');
216-
assertEqual(post1.author, 'Foo Bar');
217-
}
218-
219-
// The `data` argument specified to `updateDoc()` is type checked by the
220-
// TypeScript compiler to be compatible with `PostDbModel`. Note that
221-
// unlike `setDoc()`, whose `data` argument must be compatible with `Post`,
222-
// the `data` argument to `updateDoc()` must be compatible with
223-
// `PostDbModel`. Similar to `setDoc()`, since the `data` argument is typed
224-
// as `WithFieldValue<PostDbModel>` rather than just `PostDbModel`, this
225-
// allows properties of the `data` argument to also be those special
226-
// Firestore values, like as `arrayRemove()`, `deleteField()`, and
227-
// `serverTimestamp()`.
228-
await updateDoc(documentRef, {
229-
'aut.firstName': 'NewFirstName',
230-
lut: serverTimestamp()
231-
});
232-
233-
// The TypeScript compiler will fail to compile if the `data` argument to
234-
// `updateDoc()` is _not_ be compatible with `WithFieldValue<PostDbModel>`.
235-
// This type checking prevents the caller from specifying objects with
236-
// incorrect properties or property values.
237-
// @ts-expect-error "Argument of type { title: string; } is not assignable
238-
// to parameter of type WithFieldValue<PostDbModel>"
239-
await updateDoc(documentRef, { title: 'New Title' });
240-
241-
const snapshot2: DocumentSnapshot<Post> = await getDoc(documentRef);
242-
const post2: Post = snapshot2.data()!;
243-
if (post2) {
244-
assertEqual(post2.title, 'My Life');
245-
assertEqual(post2.author, 'NewFirstName Bar');
246-
}
196+
// Create a `DocumentReference` with a `FirestoreDataConverter`.
197+
const documentRef = doc(db, 'posts/post123').withConverter(new PostConverter());
198+
199+
// The `data` argument specified to `setDoc()` is type checked by the
200+
// TypeScript compiler to be compatible with `Post`. Since the `data`
201+
// argument is typed as `WithFieldValue<Post>` rather than just `Post`,
202+
// this allows properties of the `data` argument to also be special
203+
// Firestore values that perform server-side mutations, such as
204+
// `arrayRemove()`, `deleteField()`, and `serverTimestamp()`.
205+
await setDoc(documentRef, {
206+
title: 'My Life',
207+
author: 'Foo Bar',
208+
lastUpdatedMillis: serverTimestamp()
209+
});
210+
211+
// The TypeScript compiler will fail to compile if the `data` argument to
212+
// `setDoc()` is _not_ be compatible with `WithFieldValue<Post>`. This
213+
// type checking prevents the caller from specifying objects with incorrect
214+
// properties or property values.
215+
// @ts-expect-error "Argument of type { ttl: string; } is not assignable
216+
// to parameter of type WithFieldValue<Post>"
217+
await setDoc(documentRef, { ttl: 'The Title' });
218+
219+
// When retrieving a document with `getDoc()` the `DocumentSnapshot`
220+
// object's `data()` method returns a `Post`, rather than a generic object,
221+
// which would have been returned if the `DocumentReference` did _not_ have a
222+
// `FirestoreDataConverter` attached to it.
223+
const snapshot1: DocumentSnapshot<Post> = await getDoc(documentRef);
224+
const post1: Post = snapshot1.data()!;
225+
if (post1) {
226+
assertEqual(post1.title, 'My Life');
227+
assertEqual(post1.author, 'Foo Bar');
228+
}
229+
230+
// The `data` argument specified to `updateDoc()` is type checked by the
231+
// TypeScript compiler to be compatible with `PostDbModel`. Note that
232+
// unlike `setDoc()`, whose `data` argument must be compatible with `Post`,
233+
// the `data` argument to `updateDoc()` must be compatible with
234+
// `PostDbModel`. Similar to `setDoc()`, since the `data` argument is typed
235+
// as `WithFieldValue<PostDbModel>` rather than just `PostDbModel`, this
236+
// allows properties of the `data` argument to also be those special
237+
// Firestore values, like as `arrayRemove()`, `deleteField()`, and
238+
// `serverTimestamp()`.
239+
await updateDoc(documentRef, {
240+
'aut.firstName': 'NewFirstName',
241+
lut: serverTimestamp()
242+
});
243+
244+
// The TypeScript compiler will fail to compile if the `data` argument to
245+
// `updateDoc()` is _not_ be compatible with `WithFieldValue<PostDbModel>`.
246+
// This type checking prevents the caller from specifying objects with
247+
// incorrect properties or property values.
248+
// @ts-expect-error "Argument of type { title: string; } is not assignable
249+
// to parameter of type WithFieldValue<PostDbModel>"
250+
await updateDoc(documentRef, { title: 'New Title' });
251+
const snapshot2: DocumentSnapshot<Post> = await getDoc(documentRef);
252+
const post2: Post = snapshot2.data()!;
253+
if (post2) {
254+
assertEqual(post2.title, 'My Life');
255+
assertEqual(post2.author, 'NewFirstName Bar');
256+
}
247257
}
248258
249259
```

0 commit comments

Comments
 (0)