From ff39c05bbdc79129142592734d8003c9494ce7a0 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Tue, 21 Nov 2023 15:28:20 +0300 Subject: [PATCH 1/6] add ability to fetch common from cache --- .../commonFeed/hooks/useCommonData/index.ts | 2 +- src/services/Common.ts | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/pages/commonFeed/hooks/useCommonData/index.ts b/src/pages/commonFeed/hooks/useCommonData/index.ts index c2a84ee823..aaa0ae154d 100644 --- a/src/pages/commonFeed/hooks/useCommonData/index.ts +++ b/src/pages/commonFeed/hooks/useCommonData/index.ts @@ -47,7 +47,7 @@ export const useCommonData = (userId?: string): Return => { (async () => { try { const [common, governance, sharedFeedItem] = await Promise.all([ - CommonService.getCommonById(commonId), + CommonService.getCommonById(commonId, true), GovernanceService.getGovernanceByCommonId(commonId), sharedFeedItemId ? CommonFeedService.getCommonFeedItemById( diff --git a/src/services/Common.ts b/src/services/Common.ts index 50bd9192f5..7d5573ffe4 100644 --- a/src/services/Common.ts +++ b/src/services/Common.ts @@ -30,16 +30,25 @@ const converter = firestoreDataConverter(); const commonMemberConverter = firestoreDataConverter(); class CommonService { - public getCommonById = async (commonId: string): Promise => { - const common = await firebase + public getCommonById = async ( + commonId: string, + cached = false, + ): Promise => { + const snapshot = await firebase .firestore() .collection(Collection.Daos) .where("id", "==", commonId) .where("state", "==", CommonState.ACTIVE) - .get(); - const data = transformFirebaseDataList(common); + .withConverter(converter) + .get({ source: cached ? "cache" : "default" }); + const commons = snapshot.docs.map((doc) => doc.data()); + const common = commons[0] || null; + + if (cached && !common) { + return this.getCommonById(commonId); + } - return data[0] ? convertObjectDatesToFirestoreTimestamps(data[0]) : null; + return common; }; public getCachedCommonById = async ( From 162bda5174d5c50519cf5ceacf6bd6c634bf5e66 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Tue, 21 Nov 2023 15:30:59 +0300 Subject: [PATCH 2/6] add ability to fetch governance by common id from cache --- src/pages/commonFeed/hooks/useCommonData/index.ts | 2 +- src/services/Governance.ts | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/pages/commonFeed/hooks/useCommonData/index.ts b/src/pages/commonFeed/hooks/useCommonData/index.ts index aaa0ae154d..4cca25c1f3 100644 --- a/src/pages/commonFeed/hooks/useCommonData/index.ts +++ b/src/pages/commonFeed/hooks/useCommonData/index.ts @@ -48,7 +48,7 @@ export const useCommonData = (userId?: string): Return => { try { const [common, governance, sharedFeedItem] = await Promise.all([ CommonService.getCommonById(commonId, true), - GovernanceService.getGovernanceByCommonId(commonId), + GovernanceService.getGovernanceByCommonId(commonId, true), sharedFeedItemId ? CommonFeedService.getCommonFeedItemById( commonId, diff --git a/src/services/Governance.ts b/src/services/Governance.ts index 3a1784db95..eb94536183 100644 --- a/src/services/Governance.ts +++ b/src/services/Governance.ts @@ -13,12 +13,20 @@ const converter = firestoreDataConverter(); class GovernanceService { public getGovernanceByCommonId = async ( commonId: string, + cached = false, ): Promise => { - const governanceList = await governanceCollection + const snapshot = await governanceCollection .where("commonId", "==", commonId) - .get(); + .withConverter(converter) + .get({ source: cached ? "cache" : "default" }); + const governanceList = snapshot.docs.map((doc) => doc.data()); + const governance = governanceList[0] || null; - return transformFirebaseDataList(governanceList)[0] || null; + if (cached && !governance) { + return this.getGovernanceByCommonId(commonId); + } + + return governance; }; public getGovernanceListByCommonIds = async ( From e3531fd137c5890f48643912862b60cc7e7d6172 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Tue, 21 Nov 2023 15:49:13 +0300 Subject: [PATCH 3/6] add ability to fetch common feed item by id from cache --- .../commonFeed/hooks/useCommonData/index.ts | 1 + src/services/CommonFeed.ts | 19 ++++++++++++++----- src/shared/utils/firebase.tsx | 9 ++++++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/pages/commonFeed/hooks/useCommonData/index.ts b/src/pages/commonFeed/hooks/useCommonData/index.ts index 4cca25c1f3..fd11a97fcf 100644 --- a/src/pages/commonFeed/hooks/useCommonData/index.ts +++ b/src/pages/commonFeed/hooks/useCommonData/index.ts @@ -53,6 +53,7 @@ export const useCommonData = (userId?: string): Return => { ? CommonFeedService.getCommonFeedItemById( commonId, sharedFeedItemId, + true, ) : null, ]); diff --git a/src/services/CommonFeed.ts b/src/services/CommonFeed.ts index f9920217aa..7ab52352fb 100644 --- a/src/services/CommonFeed.ts +++ b/src/services/CommonFeed.ts @@ -25,7 +25,7 @@ import { convertToTimestamp, firestoreDataConverter, } from "@/shared/utils"; -import firebase from "@/shared/utils/firebase"; +import firebase, { isFirestoreCacheError } from "@/shared/utils/firebase"; import Api, { CancelToken } from "./Api"; const converter = firestoreDataConverter(); @@ -42,12 +42,21 @@ class CommonFeedService { public getCommonFeedItemById = async ( commonId: string, commonFeedId: string, + cached = false, ): Promise => { - const snapshot = await this.getCommonFeedSubCollection(commonId) - .doc(commonFeedId) - .get(); + try { + const snapshot = await this.getCommonFeedSubCollection(commonId) + .doc(commonFeedId) + .get({ source: cached ? "cache" : "default" }); - return snapshot?.data() || null; + return snapshot?.data() || null; + } catch (error) { + if (cached && isFirestoreCacheError(error)) { + return this.getCommonFeedItemById(commonId, commonFeedId); + } else { + throw error; + } + } }; public getCommonFeedItemWithSnapshot = async ( diff --git a/src/shared/utils/firebase.tsx b/src/shared/utils/firebase.tsx index 57d0f0f0e7..783c5e5cd3 100644 --- a/src/shared/utils/firebase.tsx +++ b/src/shared/utils/firebase.tsx @@ -32,8 +32,11 @@ if (REACT_APP_ENV === Environment.Local) { }); } -export const isFirebaseError = (error: any): error is FirebaseError => { - return error && error.code && error.code.startsWith("auth/"); -}; +export const isFirebaseError = (error: any): error is FirebaseError => + (error && error.code && error.code.startsWith("auth/")) || + error.name === "FirebaseError"; + +export const isFirestoreCacheError = (error: any): boolean => + isFirebaseError(error) && error.code === "unavailable"; export default firebase; From 1a30206ad04e627c18f39fd62564aaa3820db503 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Tue, 21 Nov 2023 15:50:58 +0300 Subject: [PATCH 4/6] add ability to fetch all parent commons for common from cache --- src/pages/commonFeed/hooks/useCommonData/index.ts | 2 +- src/services/Common.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/commonFeed/hooks/useCommonData/index.ts b/src/pages/commonFeed/hooks/useCommonData/index.ts index fd11a97fcf..018aab6ca8 100644 --- a/src/pages/commonFeed/hooks/useCommonData/index.ts +++ b/src/pages/commonFeed/hooks/useCommonData/index.ts @@ -70,7 +70,7 @@ export const useCommonData = (userId?: string): Return => { const { rootCommonId } = common; const [parentCommons, subCommons, rootCommonGovernance] = await Promise.all([ - CommonService.getAllParentCommonsForCommon(common), + CommonService.getAllParentCommonsForCommon(common, true), CommonService.getCommonsByDirectParentIds([common.id]), rootCommonId ? GovernanceService.getGovernanceByCommonId(rootCommonId) diff --git a/src/services/Common.ts b/src/services/Common.ts index 7d5573ffe4..7415f283de 100644 --- a/src/services/Common.ts +++ b/src/services/Common.ts @@ -17,7 +17,6 @@ import { SubCollections, } from "@/shared/models"; import { - convertObjectDatesToFirestoreTimestamps, emptyFunction, firestoreDataConverter, transformFirebaseDataList, @@ -258,10 +257,11 @@ class CommonService { // Fetch all parent commons. Order: from root parent common to lowest ones public getAllParentCommonsForCommon = async ( commonToCheck: Pick | string, + cached = false, ): Promise => { const common = typeof commonToCheck === "string" - ? await this.getCommonById(commonToCheck) + ? await this.getCommonById(commonToCheck, cached) : commonToCheck; if (!common || common.directParent === null) { @@ -272,7 +272,7 @@ class CommonService { let nextCommonId = common.directParent.commonId; while (nextCommonId) { - const common = await this.getCommonById(nextCommonId); + const common = await this.getCommonById(nextCommonId, cached); if (common) { finalCommons = [common, ...finalCommons]; From c722fdfb55f4e4aaed52eb744757ec8b89112594 Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Tue, 21 Nov 2023 15:53:10 +0300 Subject: [PATCH 5/6] use cache in root common data fetch --- src/pages/commonFeed/hooks/useCommonData/index.ts | 2 +- src/shared/hooks/useCases/useFullCommonData/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/commonFeed/hooks/useCommonData/index.ts b/src/pages/commonFeed/hooks/useCommonData/index.ts index 018aab6ca8..633bfc49c5 100644 --- a/src/pages/commonFeed/hooks/useCommonData/index.ts +++ b/src/pages/commonFeed/hooks/useCommonData/index.ts @@ -73,7 +73,7 @@ export const useCommonData = (userId?: string): Return => { CommonService.getAllParentCommonsForCommon(common, true), CommonService.getCommonsByDirectParentIds([common.id]), rootCommonId - ? GovernanceService.getGovernanceByCommonId(rootCommonId) + ? GovernanceService.getGovernanceByCommonId(rootCommonId, true) : null, ]); const rootCommon = await getRootCommon( diff --git a/src/shared/hooks/useCases/useFullCommonData/index.ts b/src/shared/hooks/useCases/useFullCommonData/index.ts index 20a85949cb..0e6133a3f9 100644 --- a/src/shared/hooks/useCases/useFullCommonData/index.ts +++ b/src/shared/hooks/useCases/useFullCommonData/index.ts @@ -26,7 +26,7 @@ export const getRootCommon = async ( return initialRootCommon; } - return CommonService.getCommonById(rootCommonId); + return CommonService.getCommonById(rootCommonId, true); }; export const useFullCommonData = (): Return => { From a30f2a4c9e73fea05bbda6791963d8eab06e5ccc Mon Sep 17 00:00:00 2001 From: Andrey Mikhadyuk Date: Tue, 21 Nov 2023 16:02:15 +0300 Subject: [PATCH 6/6] add logic to fetch sub-commons with cache --- .../commonFeed/hooks/useCommonData/index.ts | 2 +- src/services/Common.ts | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/pages/commonFeed/hooks/useCommonData/index.ts b/src/pages/commonFeed/hooks/useCommonData/index.ts index 633bfc49c5..20e5efdbba 100644 --- a/src/pages/commonFeed/hooks/useCommonData/index.ts +++ b/src/pages/commonFeed/hooks/useCommonData/index.ts @@ -71,7 +71,7 @@ export const useCommonData = (userId?: string): Return => { const [parentCommons, subCommons, rootCommonGovernance] = await Promise.all([ CommonService.getAllParentCommonsForCommon(common, true), - CommonService.getCommonsByDirectParentIds([common.id]), + CommonService.getCommonsByDirectParentId(common.id, true), rootCommonId ? GovernanceService.getGovernanceByCommonId(rootCommonId, true) : null, diff --git a/src/services/Common.ts b/src/services/Common.ts index 7415f283de..4ba3541c9a 100644 --- a/src/services/Common.ts +++ b/src/services/Common.ts @@ -101,6 +101,26 @@ class CommonService { .reduce((acc, items) => [...acc, ...items], []); }; + public getCommonsByDirectParentId = async ( + parentCommonId: string, + cached = false, + ): Promise => { + const snapshot = await firebase + .firestore() + .collection(Collection.Daos) + .where("state", "==", CommonState.ACTIVE) + .where("directParent.commonId", "==", parentCommonId) + .withConverter(converter) + .get({ source: cached ? "cache" : "default" }); + const commons = snapshot.docs.map((doc) => doc.data()); + + if (cached && commons.length === 0) { + return this.getCommonsByDirectParentId(parentCommonId); + } + + return commons; + }; + public getCommonsByDirectParentIds = async ( ids: string[], ): Promise => {