Skip to content

Commit 0a9304a

Browse files
committed
yarn docgen devsite
1 parent 9afea69 commit 0a9304a

File tree

2 files changed

+190
-37
lines changed

2 files changed

+190
-37
lines changed

docs-devsite/firestore_.firestoredataconverter.md

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -101,40 +101,115 @@ toFirestore(modelObject: PartialWithFieldValue<AppModelType>, options: SetOption
101101

102102
```typescript
103103
class Post {
104-
constructor(readonly title: string, readonly author: string) {}
104+
constructor(
105+
readonly title: string,
106+
readonly author: string,
107+
readonly lastUpdatedMillis: number
108+
) {}
105109
106110
toString(): string {
107-
return this.title + ', by ' + this.author;
111+
return `${this.title} by ${this.author}`;
108112
}
109113
}
110114
111115
interface PostDbModel {
112-
title: string;
113-
author: string;
116+
ttl: string;
117+
aut: { firstName: string; lastName: string };
118+
lut: Timestamp;
114119
}
115120
116121
const postConverter = {
117-
toFirestore(post: WithFieldValue<Post>): PostDbModel {
118-
return {title: post.title, author: post.author};
122+
toFirestore(post: WithFieldValue<Post>) {
123+
return {
124+
ttl: post.title,
125+
aut: this._autFromAuthor(post.author),
126+
lut: this._lutFromLastUpdatedMillis(post.lastUpdatedMillis)
127+
};
119128
},
120-
fromFirestore(
121-
snapshot: QueryDocumentSnapshot,
122-
options: SnapshotOptions
123-
): Post {
129+
130+
fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
124131
const data = snapshot.data(options) as PostDbModel;
125-
return new Post(data.title, data.author);
132+
const author = `${data.aut.firstName} ${data.aut.lastName}`;
133+
return new Post(data.ttl, author, data.lut.toMillis());
134+
},
135+
136+
_autFromAuthor(
137+
author: string | FieldValue
138+
): { firstName: string; lastName: string } | FieldValue {
139+
if (typeof author !== 'string') {
140+
// `author` is a FieldValue, so just return it.
141+
return author;
142+
}
143+
const [firstName, lastName] = author.split(' ');
144+
return { firstName, lastName };
145+
},
146+
147+
_lutFromLastUpdatedMillis(
148+
lastUpdatedMillis: number | FieldValue
149+
): Timestamp | FieldValue {
150+
if (typeof lastUpdatedMillis !== 'number') {
151+
// `lastUpdatedMillis` must be a FieldValue, so just return it.
152+
return lastUpdatedMillis;
153+
}
154+
return Timestamp.fromMillis(lastUpdatedMillis);
126155
}
127156
};
128157
129-
const postSnap = await firebase.firestore()
130-
.collection('posts')
131-
.withConverter(postConverter)
132-
.doc().get();
133-
const post = postSnap.data();
134-
if (post !== undefined) {
135-
post.title; // string
136-
post.toString(); // Should be defined
137-
post.someNonExistentProperty; // TS error
158+
async function demo(db: Firestore): Promise<void> {
159+
// Create a `DocumentReference` with a `FirestoreDataConverter`.
160+
const documentRef = doc(db, 'posts/post123').withConverter(postConverter);
161+
162+
// The `data` argument specified to `setDoc()` is type checked by the
163+
// TypeScript compiler to be compatible with `Post`. Since the `data`
164+
// argument is typed as `WithFieldValue<Post>` rather than just `Post`,
165+
// this allows properties of the `data` argument to also be special
166+
// Firestore values that perform server-side mutations, such as
167+
// `arrayRemove()`, `deleteField()`, and `serverTimestamp()`.
168+
await setDoc(documentRef, {
169+
title: 'My Life',
170+
author: 'Foo Bar',
171+
lastUpdatedMillis: serverTimestamp()
172+
});
173+
174+
// The TypeScript compiler will fail to compile if the `data` argument to
175+
// `setDoc()` is _not_ be compatible with `WithFieldValue<Post>`. This
176+
// type checking prevents the caller from specifying objects with incorrect
177+
// properties or property values.
178+
// @ts-expect-error "Argument of type { ttl: String; } is not assignable to
179+
// parameter of type WithFieldValue<Post>"
180+
await setDoc(documentRef, { ttl: 'The Title' });
181+
182+
// When retrieving a document with `getDoc()` the `DocumentSnapshot`
183+
// object's `data()` method returns a `Post`, rather than a generic object,
184+
// which is returned if the `DocumentReference` did _not_ have a
185+
// `FirestoreDataConverter` attached to it.
186+
const postSnap: DocumentSnapshot<Post> = await getDoc(documentRef);
187+
const post: Post | undefined = postSnap.data();
188+
if (post) {
189+
console.log(`Post ${documentRef.path} has title=${post.title}`);
190+
}
191+
192+
// The `data` argument specified to `updateDoc()` is type checked by the
193+
// TypeScript compiler to be compatible with `PostDbModel`. Note that
194+
// unlike `setDoc()`, whose `data` argument must be compatible with `Post`,
195+
// the `data` argument to `updateDoc()` must be compatible with
196+
// `PostDbModel`. Similar to `setDoc()`, since the `data` argument is typed
197+
// as `WithFieldValue<PostDbModel>` rather than just `PostDbModel`, this
198+
// allows properties of the `data` argument to also be those special
199+
// Firestore values, like as `arrayRemove()`, `deleteField()`, and
200+
// `serverTimestamp()`.
201+
await updateDoc(documentRef, {
202+
'aut.firstName': 'NewFirstName',
203+
lut: serverTimestamp()
204+
});
205+
206+
// The TypeScript compiler will fail to compile if the `data` argument to
207+
// `updateDoc()` is _not_ be compatible with `WithFieldValue<PostDbModel>`.
208+
// This type checking prevents the caller from specifying objects with
209+
// incorrect properties or property values.
210+
// @ts-expect-error "Argument of type { title: String; } is not assignable
211+
// to parameter of type WithFieldValue<PostDbModel>"
212+
await updateDoc(documentRef, { title: 'New Title' });
138213
}
139214
140215
```

docs-devsite/firestore_lite.firestoredataconverter.md

Lines changed: 95 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -100,37 +100,115 @@ toFirestore(modelObject: PartialWithFieldValue<AppModelType>, options: SetOption
100100

101101
```typescript
102102
class Post {
103-
constructor(readonly title: string, readonly author: string) {}
103+
constructor(
104+
readonly title: string,
105+
readonly author: string,
106+
readonly lastUpdatedMillis: number
107+
) {}
104108
105109
toString(): string {
106-
return this.title + ', by ' + this.author;
110+
return `${this.title} by ${this.author}`;
107111
}
108112
}
109113
110114
interface PostDbModel {
111-
title: string;
112-
author: string;
115+
ttl: string;
116+
aut: { firstName: string; lastName: string };
117+
lut: Timestamp;
113118
}
114119
115120
const postConverter = {
116-
toFirestore(post: WithFieldValue<Post>): PostDbModel {
117-
return {title: post.title, author: post.author};
121+
toFirestore(post: WithFieldValue<Post>) {
122+
return {
123+
ttl: post.title,
124+
aut: this._autFromAuthor(post.author),
125+
lut: this._lutFromLastUpdatedMillis(post.lastUpdatedMillis)
126+
};
118127
},
119-
fromFirestore(snapshot: QueryDocumentSnapshot): Post {
128+
129+
fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
120130
const data = snapshot.data(options) as PostDbModel;
121-
return new Post(data.title, data.author);
131+
const author = `${data.aut.firstName} ${data.aut.lastName}`;
132+
return new Post(data.ttl, author, data.lut.toMillis());
133+
},
134+
135+
_autFromAuthor(
136+
author: string | FieldValue
137+
): { firstName: string; lastName: string } | FieldValue {
138+
if (typeof author !== 'string') {
139+
// `author` is a FieldValue, so just return it.
140+
return author;
141+
}
142+
const [firstName, lastName] = author.split(' ');
143+
return { firstName, lastName };
144+
},
145+
146+
_lutFromLastUpdatedMillis(
147+
lastUpdatedMillis: number | FieldValue
148+
): Timestamp | FieldValue {
149+
if (typeof lastUpdatedMillis !== 'number') {
150+
// `lastUpdatedMillis` must be a FieldValue, so just return it.
151+
return lastUpdatedMillis;
152+
}
153+
return Timestamp.fromMillis(lastUpdatedMillis);
122154
}
123155
};
124156
125-
const postSnap = await firebase.firestore()
126-
.collection('posts')
127-
.withConverter(postConverter)
128-
.doc().get();
129-
const post = postSnap.data();
130-
if (post !== undefined) {
131-
post.title; // string
132-
post.toString(); // Should be defined
133-
post.someNonExistentProperty; // TS error
157+
async function demo(db: Firestore): Promise<void> {
158+
// Create a `DocumentReference` with a `FirestoreDataConverter`.
159+
const documentRef = doc(db, 'posts/post123').withConverter(postConverter);
160+
161+
// The `data` argument specified to `setDoc()` is type checked by the
162+
// TypeScript compiler to be compatible with `Post`. Since the `data`
163+
// argument is typed as `WithFieldValue<Post>` rather than just `Post`,
164+
// this allows properties of the `data` argument to also be special
165+
// Firestore values that perform server-side mutations, such as
166+
// `arrayRemove()`, `deleteField()`, and `serverTimestamp()`.
167+
await setDoc(documentRef, {
168+
title: 'My Life',
169+
author: 'Foo Bar',
170+
lastUpdatedMillis: serverTimestamp()
171+
});
172+
173+
// The TypeScript compiler will fail to compile if the `data` argument to
174+
// `setDoc()` is _not_ be compatible with `WithFieldValue<Post>`. This
175+
// type checking prevents the caller from specifying objects with incorrect
176+
// properties or property values.
177+
// @ts-expect-error "Argument of type { ttl: String; } is not assignable to
178+
// parameter of type WithFieldValue<Post>"
179+
await setDoc(documentRef, { ttl: 'The Title' });
180+
181+
// When retrieving a document with `getDoc()` the `DocumentSnapshot`
182+
// object's `data()` method returns a `Post`, rather than a generic object,
183+
// which is returned if the `DocumentReference` did _not_ have a
184+
// `FirestoreDataConverter` attached to it.
185+
const postSnap: DocumentSnapshot<Post> = await getDoc(documentRef);
186+
const post: Post | undefined = postSnap.data();
187+
if (post) {
188+
console.log(`Post ${documentRef.path} has title=${post.title}`);
189+
}
190+
191+
// The `data` argument specified to `updateDoc()` is type checked by the
192+
// TypeScript compiler to be compatible with `PostDbModel`. Note that
193+
// unlike `setDoc()`, whose `data` argument must be compatible with `Post`,
194+
// the `data` argument to `updateDoc()` must be compatible with
195+
// `PostDbModel`. Similar to `setDoc()`, since the `data` argument is typed
196+
// as `WithFieldValue<PostDbModel>` rather than just `PostDbModel`, this
197+
// allows properties of the `data` argument to also be those special
198+
// Firestore values, like as `arrayRemove()`, `deleteField()`, and
199+
// `serverTimestamp()`.
200+
await updateDoc(documentRef, {
201+
'aut.firstName': 'NewFirstName',
202+
lut: serverTimestamp()
203+
});
204+
205+
// The TypeScript compiler will fail to compile if the `data` argument to
206+
// `updateDoc()` is _not_ be compatible with `WithFieldValue<PostDbModel>`.
207+
// This type checking prevents the caller from specifying objects with
208+
// incorrect properties or property values.
209+
// @ts-expect-error "Argument of type { title: String; } is not assignable
210+
// to parameter of type WithFieldValue<PostDbModel>"
211+
await updateDoc(documentRef, { title: 'New Title' });
134212
}
135213
136214
```

0 commit comments

Comments
 (0)