fix: handle caching of card grids on content page blocks

This commit is contained in:
Christel Westerberg
2024-11-01 09:30:04 +01:00
parent a76857a62b
commit 036bb8351a
3 changed files with 79 additions and 97 deletions

View File

@@ -1,11 +1,31 @@
import "server-only"
import deepmerge from "deepmerge"
import { request } from "./request"
import type { BatchRequestDocument } from "graphql-request"
import type { Data } from "@/types/request"
function arrayMerge(
target: any[],
source: any[],
options: deepmerge.ArrayMergeOptions | undefined
) {
const destination = target.slice()
source.forEach((item, index) => {
if (typeof destination[index] === "undefined") {
destination[index] = options?.cloneUnlessOtherwiseSpecified(item, options)
} else if (options?.isMergeableObject(item)) {
destination[index] = deepmerge(target[index], item, options)
} else if (target.indexOf(item) === -1) {
destination.push(item)
}
})
return destination
}
export async function batchRequest<T>(
queries: (BatchRequestDocument & { options?: RequestInit })[]
): Promise<Data<T>> {
@@ -17,15 +37,21 @@ export async function batchRequest<T>(
)
let data = {} as T
const reasons = []
const reasons: PromiseRejectedResult["reason"][] = []
response.forEach((res) => {
if (res.status === "fulfilled") {
data = Object.assign({}, data, res.value.data)
data = deepmerge(data, res.value.data, { arrayMerge })
} else {
reasons.push(res.reason)
}
})
if (reasons.length) {
reasons.forEach((reason) => {
console.error(`Batch request failed`, reason)
})
}
return { data }
} catch (error) {
console.error("Error in batched graphql request")

View File

@@ -1,10 +1,10 @@
import { Lang } from "@/constants/languages"
import { batchRequest } from "@/lib/graphql/batchRequest"
import {
GetContentPage,
GetContentPageBlocksBatch1,
GetContentPageBlocksBatch2,
} from "@/lib/graphql/Query/ContentPage/ContentPage.graphql"
import { request } from "@/lib/graphql/request"
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"
import { contentPageSchema } from "./output"
@@ -12,30 +12,20 @@ import {
fetchContentPageRefs,
generatePageTags,
getContentPageCounter,
validateContentPageRefs,
} from "./utils"
import {
TrackingChannelEnum,
type TrackingSDKPageData,
} from "@/types/components/tracking"
import { ContentPageEnum } from "@/types/enums/contentPage"
import type {
GetBlock,
GetContentPageSchema,
} from "@/types/trpc/routers/contentstack/contentPage"
import type { GetContentPageSchema } from "@/types/trpc/routers/contentstack/contentPage"
export const contentPageQueryRouter = router({
get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
const { lang, uid } = ctx
const contentPageRefsData = await fetchContentPageRefs(lang, uid)
const contentPageRefs = await fetchContentPageRefs(lang, uid)
const contentPageRefs = validateContentPageRefs(
contentPageRefsData,
lang,
uid
)
if (!contentPageRefs) {
return null
}
@@ -50,69 +40,42 @@ export const contentPageQueryRouter = router({
})
)
const [mainResponse, blocksResponse1, blocksResponse2] = await Promise.all([
request<GetContentPageSchema>(
GetContentPage,
{ locale: lang, uid },
{
const contentPageRequest = await batchRequest<GetContentPageSchema>([
{
document: GetContentPage,
variables: { locale: lang, uid },
options: {
cache: "force-cache",
next: {
tags,
},
}
),
request<GetContentPageSchema>(
GetContentPageBlocksBatch1,
{ locale: lang, uid },
{
},
},
{
document: GetContentPageBlocksBatch1,
variables: { locale: lang, uid },
options: {
cache: "force-cache",
next: {
tags,
},
}
),
request<GetContentPageSchema>(
GetContentPageBlocksBatch2,
{ locale: lang, uid },
{
},
},
{
document: GetContentPageBlocksBatch2,
variables: { locale: lang, uid },
options: {
cache: "force-cache",
next: {
tags,
},
}
),
},
},
])
const blocksOrder = mainResponse.data.content_page.blocks?.map(
(block) => block.__typename
)
let sortedBlocks
if (blocksOrder) {
const blocks = [
blocksResponse1.data.content_page.blocks,
blocksResponse2.data.content_page.blocks,
]
.flat(2)
.filter((obj) => !(obj && Object.keys(obj).length < 2))
// Remove empty objects and objects with only typename
sortedBlocks = blocksOrder
.map((typename: ContentPageEnum.ContentStack.blocks) =>
blocks.find((block) => block?.__typename === typename)
)
.filter((block): block is GetBlock => !!block)
}
const responseData = {
...mainResponse.data,
content_page: {
...mainResponse.data.content_page,
blocks: sortedBlocks,
},
}
const contentPage = contentPageSchema.safeParse(responseData)
const contentPage = contentPageSchema.safeParse(contentPageRequest.data)
if (!contentPage.success) {
console.error(
`Failed to validate Contentpage Data - (lang: ${lang}, uid: ${uid})`

View File

@@ -1,11 +1,11 @@
import { metrics } from "@opentelemetry/api"
import { Lang } from "@/constants/languages"
import { batchRequest } from "@/lib/graphql/batchRequest"
import {
GetContentPageBlocksRefs,
GetContentPageRefs,
} from "@/lib/graphql/Query/ContentPage/ContentPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { generateTag, generateTagsFromSystem } from "@/utils/generateTag"
@@ -44,30 +44,30 @@ export async function fetchContentPageRefs(lang: Lang, uid: string) {
query: { lang, uid },
})
)
const [mainRefsResponse, blockRefsResponse] = await Promise.all([
request<GetContentPageRefsSchema>(
GetContentPageRefs,
{ locale: lang, uid },
{
const res = await batchRequest<GetContentPageRefsSchema>([
{
document: GetContentPageRefs,
variables: { locale: lang, uid },
options: {
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
},
}
),
request<GetContentPageRefsSchema>(
GetContentPageBlocksRefs,
{ locale: lang, uid },
{
},
},
{
document: GetContentPageBlocksRefs,
variables: { locale: lang, uid },
options: {
cache: "force-cache",
next: {
tags: [generateTag(lang, uid)],
tags: [generateTag(lang, uid + 1)],
},
}
),
},
},
])
if (!mainRefsResponse.data) {
const notFoundError = notFound(mainRefsResponse)
if (!res.data) {
const notFoundError = notFound(res)
getContentPageRefsFailCounter.add(1, {
lang,
uid,
@@ -88,22 +88,7 @@ export async function fetchContentPageRefs(lang: Lang, uid: string) {
)
throw notFoundError
}
const responseData = {
...mainRefsResponse.data,
content_page: {
...mainRefsResponse.data.content_page,
blocks: blockRefsResponse.data.content_page.blocks,
},
}
return responseData
}
export function validateContentPageRefs(
data: GetContentPageRefsSchema,
lang: Lang,
uid: string
) {
const validatedData = contentPageRefsSchema.safeParse(data)
const validatedData = contentPageRefsSchema.safeParse(res.data)
if (!validatedData.success) {
getContentPageRefsFailCounter.add(1, {
lang,
@@ -192,6 +177,14 @@ export function getConnections({ content_page }: ContentPageRefs) {
}
break
}
case ContentPageEnum.ContentStack.blocks.CardsGrid: {
if (block.cards_grid.length) {
block.cards_grid.forEach((card) => {
connections.push(card)
})
}
break
}
}
})
}