-
Notifications
You must be signed in to change notification settings - Fork 927
Firestore: QoL improvements for converters #5268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
f5a00fc
e87b617
fdd432a
01e1529
1d48049
de10404
d2df5e8
21cc4bf
c5bb26f
c2e0e38
479b6bb
1ffaad2
eb7d26c
b0568bb
826fff2
d94b0f4
0b620ca
da10a15
cf41539
a2df21b
c11e067
706c060
a8123d8
f9d4b3e
416850e
5a175a4
635c9e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,6 +36,7 @@ import { AutoId } from '../util/misc'; | |
|
||
import { Firestore } from './database'; | ||
import { FieldPath } from './field_path'; | ||
import { FieldValue } from './field_value'; | ||
import { FirestoreDataConverter } from './snapshot'; | ||
|
||
/** | ||
|
@@ -48,6 +49,21 @@ export interface DocumentData { | |
[field: string]: any; | ||
} | ||
|
||
type Primitive = string | number | boolean | bigint | undefined | null; | ||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
type Builtin = Primitive | Function; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we use Function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used it when I had special FieldValue return types. Removed it. |
||
|
||
/** Like Partial but recursive */ | ||
export type NestedPartialWithFieldValue<T> = T extends Builtin | ||
? T | ||
: T extends Map<infer K, infer V> | ||
? Map<NestedPartialWithFieldValue<K>, NestedPartialWithFieldValue<V>> | ||
: T extends {} | ||
? { [K in keyof T]?: NestedPartialWithFieldValue<T[K]> | FieldValue } | ||
: Partial<T>; | ||
|
||
export type WithFieldValue<T> = { [P in keyof T]: T[P] | FieldValue }; | ||
thebrianchen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* Update data (for use with {@link @firebase/firestore/lite#(updateDoc:1)}) consists of field paths (e.g. | ||
* 'foo' or 'foo.baz') mapped to values. Fields that contain dots reference | ||
|
@@ -58,6 +74,39 @@ export interface UpdateData { | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[fieldPath: string]: any; | ||
} | ||
// Represents an update object to Firestore document data, which can contain either fields like {a: 2} | ||
// or dot-separated paths such as {"a.b" : 2} (which updates the nested property "b" in map field "a"). | ||
thebrianchen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
export type TypedUpdateData<T> = T extends Builtin | ||
? T | ||
: T extends Map<infer K, infer V> | ||
? Map<TypedUpdateData<K>, TypedUpdateData<V>> | ||
: T extends {} | ||
? { [K in keyof T]?: TypedUpdateData<T[K]> | FieldValue } & | ||
NestedUpdateFields<T> | ||
: Partial<T>; | ||
|
||
// For each field (e.g. "bar"), calculate its nested keys (e.g. {"bar.baz": T1, "bar.quax": T2}), and then | ||
// intersect them together to make one giant map containing all possible keys (all marked as optional). | ||
type NestedUpdateFields<T extends Record<string, any>> = UnionToIntersection< | ||
{ | ||
[K in keyof T & string]: T[K] extends Record<string, any> // Only allow nesting for map values | ||
? AddPrefixToKeys<K, TypedUpdateData<T[K]>> // Recurse into map and add "bar." in front of every key | ||
: never; | ||
}[keyof T & string] | ||
>; | ||
|
||
// Return a new map where every key is prepended with Prefix + dot. | ||
type AddPrefixToKeys<Prefix extends string, T extends Record<string, any>> = | ||
// Remap K => Prefix.K. See https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#key-remapping-via-as | ||
{ [K in keyof T & string as `${Prefix}.${K}`]+?: T[K] }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be more impressive if you didn't cite the source :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, I cannot cite yuchen. |
||
|
||
// This takes union type U = T1 | T2 | ... and returns a intersected type (T1 & T2 & ...) | ||
type UnionToIntersection<U> = | ||
// Works because "multiple candidates for the same type variable in contra-variant positions causes an intersection type to be inferred" | ||
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-inference-in-conditional-types | ||
(U extends any ? (k: U) => void : never) extends (k: infer I) => void | ||
? I | ||
: never; | ||
|
||
/** | ||
* An options object that configures the behavior of {@link @firebase/firestore/lite#(setDoc:1)}, {@link | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WithFieldValue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this._delegate
'stoFirestore
methods use the types onPublicFirestoreDataConverter
, which have the old types.