fix: add wrapper function for caching

This commit is contained in:
Christel Westerberg
2024-11-25 13:47:25 +01:00
parent 503b0bf186
commit 8bfc4065ed
7 changed files with 55 additions and 53 deletions

View File

@@ -1,6 +1,6 @@
import { Lang } from "@/constants/languages" import { Lang } from "@/constants/languages"
import { dt } from "@/lib/dt" import { dt } from "@/lib/dt"
import { getRoomAvailability } from "@/lib/trpc/memoizedRequests" import { getRoomsAvailability } from "@/lib/trpc/memoizedRequests"
import Alert from "@/components/TempDesignSystem/Alert" import Alert from "@/components/TempDesignSystem/Alert"
import { getIntl } from "@/i18n" import { getIntl } from "@/i18n"
@@ -31,7 +31,7 @@ export async function NoRoomsAlert({
lang, lang,
}: Props) { }: Props) {
const [availability, availabilityError] = await safeTry( const [availability, availabilityError] = await safeTry(
getRoomAvailability({ getRoomsAvailability({
hotelId: hotelId, hotelId: hotelId,
roomStayStartDate: dt(fromDate).format("YYYY-MM-DD"), roomStayStartDate: dt(fromDate).format("YYYY-MM-DD"),
roomStayEndDate: dt(toDate).format("YYYY-MM-DD"), roomStayEndDate: dt(toDate).format("YYYY-MM-DD"),

View File

@@ -4,7 +4,7 @@ import {
getHotelData, getHotelData,
getPackages, getPackages,
getProfileSafely, getProfileSafely,
getRoomAvailability, getRoomsAvailability,
} from "@/lib/trpc/memoizedRequests" } from "@/lib/trpc/memoizedRequests"
import { safeTry } from "@/utils/safeTry" import { safeTry } from "@/utils/safeTry"
@@ -57,7 +57,7 @@ export async function RoomsContainer({
) )
const roomsAvailabilityPromise = safeTry( const roomsAvailabilityPromise = safeTry(
getRoomAvailability({ getRoomsAvailability({
hotelId: hotelId, hotelId: hotelId,
roomStayStartDate: fromDateString, roomStayStartDate: fromDateString,
roomStayEndDate: toDateString, roomStayEndDate: toDateString,

View File

@@ -1,11 +1,12 @@
import { cache } from "react"
import { Lang } from "@/constants/languages" import { Lang } from "@/constants/languages"
import { import {
GetRoomsAvailabilityInput, GetRoomsAvailabilityInput,
GetSelectedRoomAvailabilityInput, GetSelectedRoomAvailabilityInput,
HotelDataInput,
} from "@/server/routers/hotels/input" } from "@/server/routers/hotels/input"
import { cache } from "@/utils/cache"
import { serverClient } from "../server" import { serverClient } from "../server"
import type { import type {
@@ -59,46 +60,20 @@ export const getUserTracking = cache(async function getMemoizedUserTracking() {
return serverClient().user.tracking() return serverClient().user.tracking()
}) })
export const getHotelData = cache(async function getMemoizedHotelData({ export const getHotelData = cache(function getMemoizedHotelData(
hotelId, props: HotelDataInput
language, ) {
isCardOnlyPayment, return serverClient().hotel.hotelData.get(props)
}: {
hotelId: string
language: string
isCardOnlyPayment?: boolean
}) {
return serverClient().hotel.hotelData.get({
hotelId,
language,
isCardOnlyPayment,
})
}) })
export const getRoomAvailability = cache( export const getRoomsAvailability = cache(function getMemoizedRoomAvailability(
async function getMemoizedRoomAvailability({ args: GetRoomsAvailabilityInput
hotelId, ) {
adults, return serverClient().hotel.availability.rooms(args)
roomStayStartDate,
roomStayEndDate,
children,
bookingCode,
rateCode,
}: GetRoomsAvailabilityInput) {
return serverClient().hotel.availability.rooms({
hotelId,
adults,
roomStayStartDate,
roomStayEndDate,
children,
bookingCode,
rateCode,
}) })
}
)
export const getSelectedRoomAvailability = cache( export const getSelectedRoomAvailability = cache(
async function getMemoizedRoomAvailability( function getMemoizedSelectedRoomAvailability(
args: GetSelectedRoomAvailabilityInput args: GetSelectedRoomAvailabilityInput
) { ) {
return serverClient().hotel.availability.room(args) return serverClient().hotel.availability.room(args)
@@ -141,13 +116,13 @@ export const getSiteConfig = cache(async function getMemoizedSiteConfig() {
return serverClient().contentstack.base.siteConfig() return serverClient().contentstack.base.siteConfig()
}) })
export const getBreakfastPackages = cache(async function getMemoizedPackages( export const getBreakfastPackages = cache(function getMemoizedBreakfastPackages(
input: BreackfastPackagesInput input: BreackfastPackagesInput
) { ) {
return serverClient().hotel.packages.breakfast(input) return serverClient().hotel.packages.breakfast(input)
}) })
export const getPackages = cache(async function getMemoizedPackages( export const getPackages = cache(function getMemoizedPackages(
input: PackagesInput input: PackagesInput
) { ) {
return serverClient().hotel.packages.get(input) return serverClient().hotel.packages.get(input)

11
package-lock.json generated
View File

@@ -41,6 +41,7 @@
"graphql-request": "^6.1.0", "graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"immer": "10.1.1", "immer": "10.1.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"libphonenumber-js": "^1.10.60", "libphonenumber-js": "^1.10.60",
"next": "^14.2.18", "next": "^14.2.18",
"next-auth": "^5.0.0-beta.19", "next-auth": "^5.0.0-beta.19",
@@ -64,6 +65,7 @@
"@testing-library/react": "^16.0.0", "@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2", "@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
"@types/json-stable-stringify-without-jsonify": "^1.0.2",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",
@@ -6850,6 +6852,12 @@
"parse5": "^7.0.0" "parse5": "^7.0.0"
} }
}, },
"node_modules/@types/json-stable-stringify-without-jsonify": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@types/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.2.tgz",
"integrity": "sha512-X/Kn5f5fv1KBGqGDaegrj72Dlh+qEKN3ELwMAB6RdVlVzkf6NTeEnJpgR/Hr0AlpgTlYq/Vd0U3f79lavn6aDA==",
"dev": true
},
"node_modules/@types/json5": { "node_modules/@types/json5": {
"version": "0.0.29", "version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -13939,8 +13947,7 @@
"node_modules/json-stable-stringify-without-jsonify": { "node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
"dev": true
}, },
"node_modules/json-stringify-safe": { "node_modules/json-stringify-safe": {
"version": "5.0.1", "version": "5.0.1",

View File

@@ -56,6 +56,7 @@
"graphql-request": "^6.1.0", "graphql-request": "^6.1.0",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"immer": "10.1.1", "immer": "10.1.1",
"json-stable-stringify-without-jsonify": "^1.0.1",
"libphonenumber-js": "^1.10.60", "libphonenumber-js": "^1.10.60",
"next": "^14.2.18", "next": "^14.2.18",
"next-auth": "^5.0.0-beta.19", "next-auth": "^5.0.0-beta.19",
@@ -79,6 +80,7 @@
"@testing-library/react": "^16.0.0", "@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2", "@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.12", "@types/jest": "^29.5.12",
"@types/json-stable-stringify-without-jsonify": "^1.0.2",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",

View File

@@ -1,16 +1,11 @@
import { metrics } from "@opentelemetry/api" import { metrics } from "@opentelemetry/api"
import { cache } from "react"
import { Lang } from "@/constants/languages" import { Lang } from "@/constants/languages"
import * as api from "@/lib/api" import * as api from "@/lib/api"
import { dt } from "@/lib/dt" import { dt } from "@/lib/dt"
import { GetHotelPage } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql" import { GetHotelPage } from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
import { request } from "@/lib/graphql/request" import { request } from "@/lib/graphql/request"
import { import { badRequestError, notFound } from "@/server/errors/trpc"
badRequestError,
notFound,
serverErrorByStatus,
} from "@/server/errors/trpc"
import { import {
contentStackUidWithServiceProcedure, contentStackUidWithServiceProcedure,
publicProcedure, publicProcedure,
@@ -20,6 +15,8 @@ import {
} from "@/server/trpc" } from "@/server/trpc"
import { toApiLang } from "@/server/utils" import { toApiLang } from "@/server/utils"
import { cache } from "@/utils/cache"
import { hotelPageSchema } from "../contentstack/hotelPage/output" import { hotelPageSchema } from "../contentstack/hotelPage/output"
import { import {
fetchHotelPageRefs, fetchHotelPageRefs,
@@ -57,7 +54,6 @@ import {
import { FacilityCardTypeEnum } from "@/types/components/hotelPage/facilities" import { FacilityCardTypeEnum } from "@/types/components/hotelPage/facilities"
import type { BedTypeSelection } from "@/types/components/hotelReservation/enterDetails/bedType" import type { BedTypeSelection } from "@/types/components/hotelReservation/enterDetails/bedType"
import { AvailabilityEnum } from "@/types/components/hotelReservation/selectHotel/selectHotel"
import { BreakfastPackageEnum } from "@/types/enums/breakfast" import { BreakfastPackageEnum } from "@/types/enums/breakfast"
import { HotelTypeEnum } from "@/types/enums/hotelType" import { HotelTypeEnum } from "@/types/enums/hotelType"
import type { RequestOptionsWithOutBody } from "@/types/fetch" import type { RequestOptionsWithOutBody } from "@/types/fetch"

22
utils/cache.ts Normal file
View File

@@ -0,0 +1,22 @@
import stringify from "json-stable-stringify-without-jsonify"
import { cache as reactCache } from "react"
/**
* Wrapper function to handle caching of memoized requests that recieve objects as args.
* React Cache will use shallow equality of the arguments to determine if there is a cache hit,
* therefore we need to stringify the arguments to ensure that the cache works as expected.
* This function will handle the stingification of the arguments, the caching of the function,
* and the parsing of the arguments back to their original form.
*
* @param fn - The function to memoize
*/
export function cache<T extends (...args: any[]) => any>(fn: T) {
const cachedFunction = reactCache((stringifiedParams: string) => {
return fn(...JSON.parse(stringifiedParams))
})
return (...args: Parameters<T>): ReturnType<T> => {
const stringifiedParams = stringify(args)
return cachedFunction(stringifiedParams)
}
}