Skip to content

Commit

Permalink
Merge branch 'firebase-10' into useAggregateFromServer
Browse files Browse the repository at this point in the history
  • Loading branch information
andipaetzold committed Oct 12, 2023
2 parents b1c6848 + 068daa0 commit 9394404
Show file tree
Hide file tree
Showing 30 changed files with 241 additions and 192 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ yarn add react-firehooks

## Compatibility

- [firebase](https://www.npmjs.com/package/firebase): 9.11.0 or later
- [firebase](https://www.npmjs.com/package/firebase): 10.5.0 or later
- [react](https://www.npmjs.com/package/react): 16.8.0 or later

## Usage
Expand Down
5 changes: 5 additions & 0 deletions migrations/v4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Migrate from v3 to v4

## Peer dependency

This library now requires firebase 10.5.0 or later
6 changes: 3 additions & 3 deletions src/app-check/useAppCheckToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const onChange: UseListenOnChange<AppCheckTokenResult | null, Error, AppCheck> =
* Returns and updates the current App Check token
* @param appCheck Firebase App Check instance
* @returns App Check token, loading state, and error
* value: App Check token; `undefined` if token is currently being fetched, or an error occurred
* loading: `true` while fetching the token; `false` if the token was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: App Check token; `undefined` if token is currently being fetched, or an error occurred
* - loading: `true` while fetching the token; `false` if the token was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useAppCheckToken(appCheck: AppCheck): UseAppCheckToken {
return useListen(appCheck, onChange, () => true, LoadingState);
Expand Down
6 changes: 3 additions & 3 deletions src/auth/useAuthIdToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ const onChange: UseListenOnChange<string | null, AuthError, Auth> = (stableAuth,
* Returns and updates the JWT of the currently authenticated user
* @param auth Firebase Auth instance
* @returns JWT, loading state, and error
* value: JWT; `undefined` if the JWT is currently being fetched, or an error occurred
* loading: `true` while fetching the JWT; `false` if the JWT was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: JWT; `undefined` if the JWT is currently being fetched, or an error occurred
* - loading: `true` while fetching the JWT; `false` if the JWT was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useAuthIdToken(auth: Auth): UseAuthIdTokenResult {
return useListen(auth, onChange, () => true, LoadingState);
Expand Down
6 changes: 3 additions & 3 deletions src/auth/useAuthIdTokenResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ const onChange: UseListenOnChange<IdTokenResult | null, AuthError, Auth> = (stab
* Returns and updates the deserialized JWT of the currently authenticated user
* @param auth Firebase Auth instance
* @returns Deserialized JWT, loading state, and error
* value: Deserialized JWT; `undefined` if the JWT is currently being fetched, or an error occurred
* loading: `true` while fetching JWT; `false` if the JWT was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: Deserialized JWT; `undefined` if the JWT is currently being fetched, or an error occurred
* - loading: `true` while fetching JWT; `false` if the JWT was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useAuthIdTokenResult(auth: Auth): UseAuthIdTokenResultResult {
return useListen(auth, onChange, () => true, LoadingState);
Expand Down
6 changes: 3 additions & 3 deletions src/auth/useAuthState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ const onChange: UseListenOnChange<User | null, AuthError, Auth> = (stableAuth, n
* Returns and updates the currently authenticated user
* @param auth Firebase Auth instance
* @returns User, loading state, and error
* value: User; `undefined` if user is currently being fetched, or an error occurred
* loading: `true` while fetching the user; `false` if the user was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: User; `undefined` if user is currently being fetched, or an error occurred
* - loading: `true` while fetching the user; `false` if the user was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useAuthState(auth: Auth): UseAuthStateResult {
return useListen(auth, onChange, () => true, auth.currentUser ? auth.currentUser : LoadingState);
Expand Down
6 changes: 3 additions & 3 deletions src/database/useObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export type UseObjectResult = ValueHookResult<DataSnapshot, Error>;
* Returns the DataSnapshot of the Realtime Database query
* @param query Realtime Database query
* @returns User, loading state, and error
* value: DataSnapshot; `undefined` if query is currently being fetched, or an error occurred
* loading: `true` while fetching the query; `false` if the query was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: DataSnapshot; `undefined` if query is currently being fetched, or an error occurred
* - loading: `true` while fetching the query; `false` if the query was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useObject(query: Query | undefined | null): UseObjectResult {
return useListen(query ?? undefined, onValue, isQueryEqual, LoadingState);
Expand Down
6 changes: 3 additions & 3 deletions src/database/useObjectOnce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export type UseObjectOnceResult = ValueHookResult<DataSnapshot, Error>;
* Returns and updates the DataSnapshot of the Realtime Database query. Does not update the DataSnapshot once initially fetched
* @param query Realtime Database query
* @returns User, loading state, and error
* value: DataSnapshot; `undefined` if query is currently being fetched, or an error occurred
* loading: `true` while fetching the query; `false` if the query was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: DataSnapshot; `undefined` if query is currently being fetched, or an error occurred
* - loading: `true` while fetching the query; `false` if the query was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useObjectOnce(query: Query | undefined | null): UseObjectOnceResult {
const getData = useCallback((stableQuery: Query) => get(stableQuery), []);
Expand Down
6 changes: 3 additions & 3 deletions src/database/useObjectValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ export interface UseObjectValueOptions<Value> {
* `converter`: Function to extract the desired data from the DataSnapshot. Similar to Firestore converters. Default: `snap.val()`.
* `initialValue`: Value that is returned while the object is being fetched.
* @returns User, loading state, and error
* value: Object value; `undefined` if query is currently being fetched, or an error occurred
* loading: `true` while fetching the query; `false` if the query was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: Object value; `undefined` if query is currently being fetched, or an error occurred
* - loading: `true` while fetching the query; `false` if the query was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useObjectValue<Value = unknown>(
query: Query | undefined | null,
Expand Down
6 changes: 3 additions & 3 deletions src/database/useObjectValueOnce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ export interface UseObjectValueOnceOptions<Value> {
* @param options Options to configure how the object is fetched
* `converter`: Function to extract the desired data from the DataSnapshot. Similar to Firestore converters. Default: `snap.val()`.
* @returns User, loading state, and error
* value: Object value; `undefined` if query is currently being fetched, or an error occurred
* loading: `true` while fetching the query; `false` if the query was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: Object value; `undefined` if query is currently being fetched, or an error occurred
* - loading: `true` while fetching the query; `false` if the query was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useObjectValueOnce<Value = unknown>(
query: Query | undefined | null,
Expand Down
23 changes: 13 additions & 10 deletions src/firestore/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ import type { Source } from "./types.js";
/**
* @internal
*/
export async function getDocFromSource<Value extends DocumentData = DocumentData>(
reference: DocumentReference<Value>,
export async function getDocFromSource<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData>(
reference: DocumentReference<AppModelType, DbModelType>,
source: Source,
): Promise<DocumentSnapshot<Value>> {
): Promise<DocumentSnapshot<AppModelType, DbModelType>> {
switch (source) {
case "cache":
return await getDocFromCache(reference);
Expand All @@ -37,10 +37,10 @@ export async function getDocFromSource<Value extends DocumentData = DocumentData
/**
* @internal
*/
export async function getDocsFromSource<Value extends DocumentData = DocumentData>(
query: Query<Value>,
export async function getDocsFromSource<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData>(
query: Query<AppModelType, DbModelType>,
source: Source,
): Promise<QuerySnapshot<Value>> {
): Promise<QuerySnapshot<AppModelType, DbModelType>> {
switch (source) {
case "cache":
return await getDocsFromCache(query);
Expand All @@ -54,9 +54,9 @@ export async function getDocsFromSource<Value extends DocumentData = DocumentDat
/**
* @internal
*/
export function isDocRefEqual<Value>(
a: DocumentReference<Value> | undefined,
b: DocumentReference<Value> | undefined,
export function isDocRefEqual<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData>(
a: DocumentReference<AppModelType, DbModelType> | undefined,
b: DocumentReference<AppModelType, DbModelType> | undefined,
): boolean {
const areBothUndefined = a === undefined && b === undefined;
const areSameRef = a !== undefined && b !== undefined && refEqual(a, b);
Expand All @@ -66,7 +66,10 @@ export function isDocRefEqual<Value>(
/**
* @internal
*/
export function isQueryEqual<Value>(a: Query<Value> | undefined, b: Query<Value> | undefined): boolean {
export function isQueryEqual<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData>(
a: Query<AppModelType, DbModelType> | undefined,
b: Query<AppModelType, DbModelType> | undefined,
): boolean {
const areBothUndefined = a === undefined && b === undefined;
const areSameRef = a !== undefined && b !== undefined && queryEqual(a, b);
return areBothUndefined || areSameRef;
Expand Down
6 changes: 3 additions & 3 deletions src/firestore/useCountFromServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ async function getData(stableQuery: Query<unknown>): Promise<number> {
* Returns the number of documents in the result set of a Firestore Query. Does not update the count once initially calculated.
* @param query Firestore query whose result set size is calculated
* @returns Size of the result set, loading state, and error
* value: Size of the result set; `undefined` if the result set size is currently being calculated, or an error occurred
* loading: `true` while calculating the result size set; `false` if the result size set was calculated successfully or an error occurred
* error: `undefined` if no error occurred
* - value: Size of the result set; `undefined` if the result set size is currently being calculated, or an error occurred
* - loading: `true` while calculating the result size set; `false` if the result size set was calculated successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useCountFromServer(query: Query<unknown> | undefined | null): UseCountFromServerResult {
return useGet(query ?? undefined, getData, isQueryEqual);
Expand Down
28 changes: 15 additions & 13 deletions src/firestore/useDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ import { useListen, UseListenOnChange } from "../internal/useListen.js";
import { LoadingState } from "../internal/useLoadingValue.js";
import { isDocRefEqual } from "./internal.js";

export type UseDocumentResult<Value extends DocumentData = DocumentData> = ValueHookResult<
DocumentSnapshot<Value>,
FirestoreError
>;
export type UseDocumentResult<AppModelType = DocumentData> = ValueHookResult<DocumentSnapshot<AppModelType>, FirestoreError>;

/**
* Options to configure the subscription
Expand All @@ -26,24 +23,29 @@ export interface UseDocumentOptions {

/**
* Returns and updates a DocumentSnapshot of a Firestore DocumentReference
* @template Value Type of the document data
* @template AppModelType Shape of the data after it was converted from firestore
* @template DbModelType Shape of the data in firestore
* @param reference Firestore DocumentReference that will be subscribed to
* @param options Options to configure the subscription
* @returns Document snapshot, loading state, and error
* value: DocumentSnapshot; `undefined` if document does not exist, is currently being fetched, or an error occurred
* loading: `true` while fetching the document; `false` if the document was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: DocumentSnapshot; `undefined` if document does not exist, is currently being fetched, or an error occurred
* - loading: `true` while fetching the document; `false` if the document was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useDocument<Value extends DocumentData = DocumentData>(
reference: DocumentReference<Value> | undefined | null,
export function useDocument<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData>(
reference: DocumentReference<AppModelType, DbModelType> | undefined | null,
options?: UseDocumentOptions,
): UseDocumentResult<Value> {
): UseDocumentResult<AppModelType> {
const { snapshotListenOptions } = options ?? {};
const { includeMetadataChanges } = snapshotListenOptions ?? {};

const onChange: UseListenOnChange<DocumentSnapshot<Value>, FirestoreError, DocumentReference<Value>> = useCallback(
const onChange: UseListenOnChange<
DocumentSnapshot<AppModelType, DbModelType>,
FirestoreError,
DocumentReference<AppModelType, DbModelType>
> = useCallback(
(stableRef, next, error) =>
onSnapshot<Value>(
onSnapshot(
stableRef,
{ includeMetadataChanges },
{
Expand Down
31 changes: 18 additions & 13 deletions src/firestore/useDocumentData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,44 @@ import { useListen, UseListenOnChange } from "../internal/useListen.js";
import { LoadingState } from "../internal/useLoadingValue.js";
import { isDocRefEqual } from "./internal.js";

export type UseDocumentDataResult<Value extends DocumentData = DocumentData> = ValueHookResult<Value, FirestoreError>;
export type UseDocumentDataResult<AppModelType = DocumentData> = ValueHookResult<AppModelType, FirestoreError>;

/**
* Options to configure the subscription
*/
export interface UseDocumentDataOptions<Value extends DocumentData = DocumentData> {
export interface UseDocumentDataOptions<AppModelType = DocumentData> {
snapshotListenOptions?: SnapshotListenOptions;
snapshotOptions?: SnapshotOptions;
initialValue?: Value;
initialValue?: AppModelType;
}

/**
* Returns and updates the data of a Firestore DocumentReference
* @template Value Type of the document data
* @template AppModelType Shape of the data after it was converted from firestore
* @template DbModelType Shape of the data in firestore
* @param reference Firestore DocumentReference that will be subscribed to
* @param options Options to configure the subscription
* `initialValue`: Value that is returned while the document is being fetched.
* @returns Document data, loading state, and error
* value: Document data; `undefined` if document does not exist, is currently being fetched, or an error occurred
* loading: `true` while fetching the document; `false` if the document was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: Document data; `undefined` if document does not exist, is currently being fetched, or an error occurred
* - loading: `true` while fetching the document; `false` if the document was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useDocumentData<Value extends DocumentData = DocumentData>(
reference: DocumentReference<Value> | undefined | null,
options?: UseDocumentDataOptions<Value>,
): UseDocumentDataResult<Value> {
export function useDocumentData<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData>(
reference: DocumentReference<AppModelType, DbModelType> | undefined | null,
options?: UseDocumentDataOptions<AppModelType>,
): UseDocumentDataResult<AppModelType> {
const { snapshotListenOptions, snapshotOptions } = options ?? {};
const { includeMetadataChanges } = snapshotListenOptions ?? {};
const { serverTimestamps } = snapshotOptions ?? {};

const onChange: UseListenOnChange<Value, FirestoreError, DocumentReference<Value>> = useCallback(
const onChange: UseListenOnChange<
AppModelType,
FirestoreError,
DocumentReference<AppModelType, DbModelType>
> = useCallback(
(stableRef, next, error) =>
onSnapshot<Value>(
onSnapshot(
stableRef,
{ includeMetadataChanges },
{
Expand Down
19 changes: 10 additions & 9 deletions src/firestore/useDocumentDataOnce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useGet } from "../internal/useGet.js";
import { getDocFromSource, isDocRefEqual } from "./internal.js";
import type { Source } from "./types.js";

export type UseDocumentDataOnceResult<Value extends DocumentData = DocumentData> = ValueHookResult<Value, FirestoreError>;
export type UseDocumentDataOnceResult<AppModelType = DocumentData> = ValueHookResult<AppModelType, FirestoreError>;

/**
* Options to configure how the document is fetched
Expand All @@ -17,23 +17,24 @@ export interface UseDocumentDataOnceOptions {

/**
* Returns the data of a Firestore DocumentReference
* @template Value Type of the document data
* @template AppModelType Shape of the data after it was converted from firestore
* @template DbModelType Shape of the data in firestore
* @param reference Firestore DocumentReference that will be subscribed to
* @param options Options to configure how the document is fetched
* @returns Document data, loading state, and error
* value: Document data; `undefined` if document does not exist, is currently being fetched, or an error occurred
* loading: `true` while fetching the document; `false` if the document was fetched successfully or an error occurred
* error: `undefined` if no error occurred
* - value: Document data; `undefined` if document does not exist, is currently being fetched, or an error occurred
* - loading: `true` while fetching the document; `false` if the document was fetched successfully or an error occurred
* - error: `undefined` if no error occurred
*/
export function useDocumentDataOnce<Value extends DocumentData = DocumentData>(
reference: DocumentReference<Value> | undefined | null,
export function useDocumentDataOnce<AppModelType = DocumentData, DbModelType extends DocumentData = DocumentData>(
reference: DocumentReference<AppModelType, DbModelType> | undefined | null,
options?: UseDocumentDataOnceOptions,
): UseDocumentDataOnceResult<Value> {
): UseDocumentDataOnceResult<AppModelType> {
const { source = "default", snapshotOptions } = options ?? {};
const { serverTimestamps } = snapshotOptions ?? {};

const getData = useCallback(
async (stableRef: DocumentReference<Value>) => {
async (stableRef: DocumentReference<AppModelType, DbModelType>) => {
const snap = await getDocFromSource(stableRef, source);
return snap.data({ serverTimestamps });
},
Expand Down
Loading

0 comments on commit 9394404

Please sign in to comment.