Skip to content

Commit

Permalink
feat(database): add database module
Browse files Browse the repository at this point in the history
  • Loading branch information
andipaetzold committed Oct 15, 2021
1 parent a4a31f3 commit e202767
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@

# modules
/auth/
/database/
/firestore/
/storage/
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"require": "./lib/cjs/auth/index.js",
"default": "./lib/esm/auth/index.js"
},
"./database": {
"require": "./lib/cjs/database/index.js",
"default": "./lib/esm/database/index.js"
},
"./firestore": {
"require": "./lib/cjs/firestore/index.js",
"default": "./lib/esm/firestore/index.js"
Expand All @@ -26,6 +30,7 @@
"files": [
"lib",
"auth",
"database",
"firestore",
"storage"
],
Expand Down
2 changes: 1 addition & 1 deletion scripts/create-modules.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const fs = require("fs");

const modules = ["auth", "firestore", "storage"];
const modules = ["auth", "database", "firestore", "storage"];
for (const module of modules) {
const packageJson = {
main: `../lib/cjs/${module}/index.js`,
Expand Down
2 changes: 2 additions & 0 deletions src/database/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './useObject';
export * from './useObjectOnce';
18 changes: 18 additions & 0 deletions src/database/internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Query } from "firebase/database";
import { useStableValue } from "../util/useStableValue";

/**
* @internal
*/
function isQueryEqual(a: Query | undefined, b: Query | undefined): boolean {
const areBothUndefined = a === undefined || b === undefined;
const areSameRef = a !== undefined && b !== undefined && a.isEqual(b);
return areBothUndefined || areSameRef;
}

/**
* @internal
*/
export function useStableQuery(query: Query | undefined): Query | undefined {
return useStableValue(query, isQueryEqual);
}
42 changes: 42 additions & 0 deletions src/database/useObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { DataSnapshot, get, Query } from "firebase/database";
import { useEffect, useMemo } from "react";
import { ValueHookResult } from "../common";
import { useIsMounted } from "../util/useIsMounted";
import { useLoadingValue } from "../util/useLoadingValue";
import { useStableQuery } from "./internal";

export type UseObjectOnceResult = ValueHookResult<DataSnapshot, Error>;

export function useObjectOnce(query: Query | undefined | null): UseObjectOnceResult {
const isMounted = useIsMounted();
const { error, loading, setLoading, setError, setValue, value } = useLoadingValue<DataSnapshot, Error>();

const stableQuery = useStableQuery(query ?? undefined);

useEffect(() => {
(async () => {
if (stableQuery === undefined) {
setValue();
} else {
setLoading();

try {
const snap = await get(stableQuery);
if (!isMounted.current) {
return;
}

setValue(snap);
} catch (e) {
if (!isMounted.current) {
return;
}

setError(e as Error);
}
}
})();
}, [stableQuery]);

return useMemo(() => [value, loading, error], [value, loading, error]);
}
26 changes: 26 additions & 0 deletions src/database/useObjectOnce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { DataSnapshot, onValue, Query } from "firebase/database";
import { useEffect, useMemo } from "react";
import { ValueHookResult } from "../common";
import { useLoadingValue } from "../util/useLoadingValue";
import { useStableQuery } from "./internal";

export type UseObjectResult = ValueHookResult<DataSnapshot, Error>;

export function useObject(query: Query | undefined | null): UseObjectResult {
const { error, loading, setLoading, setError, setValue, value } = useLoadingValue<DataSnapshot, Error>();

const stableQuery = useStableQuery(query ?? undefined);

useEffect(() => {
if (stableQuery === undefined) {
setValue();
} else {
setLoading();

const unsubscribe = onValue(stableQuery, setValue, setError);
return () => unsubscribe();
}
}, [stableQuery]);

return useMemo(() => [value, loading, error], [value, loading, error]);
}
26 changes: 26 additions & 0 deletions src/database/useObjectValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { onValue, Query } from "firebase/database";
import { useEffect, useMemo } from "react";
import { ValueHookResult } from "../common";
import { useLoadingValue } from "../util/useLoadingValue";
import { useStableQuery } from "./internal";

export type UseObjectValueResult<Value = unknown> = ValueHookResult<Value, Error>;

export function useObjectValue<Value = unknown>(query: Query | undefined | null): UseObjectValueResult<Value> {
const { error, loading, setLoading, setError, setValue, value } = useLoadingValue<Value, Error>();

const stableQuery = useStableQuery(query ?? undefined);

useEffect(() => {
if (stableQuery === undefined) {
setValue();
} else {
setLoading();

const unsubscribe = onValue(stableQuery, (snap) => setValue(snap.val()), setError);
return () => unsubscribe();
}
}, [stableQuery]);

return useMemo(() => [value, loading, error], [value, loading, error]);
}
42 changes: 42 additions & 0 deletions src/database/useObjectValueOnce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { get, Query } from "firebase/database";
import { useEffect, useMemo } from "react";
import { ValueHookResult } from "../common";
import { useIsMounted } from "../util/useIsMounted";
import { useLoadingValue } from "../util/useLoadingValue";
import { useStableQuery } from "./internal";

export type UseObjectValueOnceResult<Value = unknown> = ValueHookResult<Value, Error>;

export function useObjectValueOnce<Value = unknown>(query: Query | undefined | null): UseObjectValueOnceResult<Value> {
const isMounted = useIsMounted();
const { error, loading, setLoading, setError, setValue, value } = useLoadingValue<Value, Error>();

const stableQuery = useStableQuery(query ?? undefined);

useEffect(() => {
(async () => {
if (stableQuery === undefined) {
setValue();
} else {
setLoading();

try {
const snap = await get(stableQuery);
if (!isMounted.current) {
return;
}

setValue(snap.val());
} catch (e) {
if (!isMounted.current) {
return;
}

setError(e as Error);
}
}
})();
}, [stableQuery]);

return useMemo(() => [value, loading, error], [value, loading, error]);
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from "./auth";
export * from "./common";
export * from "./database";
export * from "./firestore";
export * from "./storage";

2 changes: 1 addition & 1 deletion src/util/useLoadingValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export interface UseLoadingValueResult<Value, Error> {
/**
* @internal
*/
export function useLoadingValue<Value, Error = unknown>(defaultValue?: Value): UseLoadingValueResult<Value, Error> {
export function useLoadingValue<Value, Error>(defaultValue?: Value): UseLoadingValueResult<Value, Error> {
const [state, setState] = useState<State<Value, Error>>({
error: undefined,
loading: defaultValue === undefined ? true : false,
Expand Down

0 comments on commit e202767

Please sign in to comment.