ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

194 lines
6.4 KiB

  1. import { QueryClient } from '@tanstack/react-query'
  2. import { match } from 'path-to-regexp'
  3. import { fetchPost, fetchPosts, fetchPostChanges } from '@/lib/posts'
  4. import { postsKeys, tagsKeys, wikiKeys } from '@/lib/queryKeys'
  5. import { fetchTagByName, fetchTag, fetchTags } from '@/lib/tags'
  6. import { fetchWikiPage,
  7. fetchWikiPageByTitle,
  8. fetchWikiPages } from '@/lib/wiki'
  9. import type { Category, FetchPostsOrder, FetchTagsOrder } from '@/types'
  10. type Prefetcher = (qc: QueryClient, url: URL) => Promise<void>
  11. const mPost = match<{ id: string }> ('/posts/:id')
  12. const mWiki = match<{ title: string }> ('/wiki/:title')
  13. const prefetchWikiPagesIndex: Prefetcher = async (qc, url) => {
  14. const title = url.searchParams.get ('title') ?? ''
  15. await qc.prefetchQuery ({
  16. queryKey: wikiKeys.index ({ title }),
  17. queryFn: () => fetchWikiPages ({ title }) })
  18. }
  19. const prefetchWikiPageShow: Prefetcher = async (qc, url) => {
  20. const m = mWiki (url.pathname)
  21. if (!(m))
  22. return
  23. const title = decodeURIComponent (m.params.title)
  24. const version = url.searchParams.get ('version') || undefined
  25. const wikiPage = await qc.fetchQuery ({
  26. queryKey: wikiKeys.show (title, { version }),
  27. queryFn: () => fetchWikiPageByTitle (title, { version }) })
  28. if (wikiPage)
  29. {
  30. const effectiveId = String (wikiPage.id ?? '')
  31. await qc.prefetchQuery ({
  32. queryKey: wikiKeys.show (effectiveId, { }),
  33. queryFn: () => fetchWikiPage (effectiveId, { } ) })
  34. if (wikiPage.body)
  35. {
  36. await qc.prefetchQuery ({
  37. queryKey: wikiKeys.index ({ }),
  38. queryFn: () => fetchWikiPages ({ }) })
  39. }
  40. }
  41. const effectiveTitle = wikiPage?.title ?? title
  42. await qc.prefetchQuery ({
  43. queryKey: tagsKeys.show (effectiveTitle),
  44. queryFn: () => fetchTagByName (effectiveTitle) })
  45. if (version)
  46. return
  47. const p = {
  48. tags: effectiveTitle,
  49. match: 'all',
  50. page: 1,
  51. limit: 8,
  52. url: '',
  53. title: '',
  54. originalCreatedFrom: '',
  55. originalCreatedTo: '',
  56. createdFrom: '',
  57. createdTo: '',
  58. updatedFrom: '',
  59. updatedTo: '',
  60. order: 'original_created_at:desc' } as const
  61. await qc.prefetchQuery ({
  62. queryKey: postsKeys.index (p),
  63. queryFn: () => fetchPosts (p) })
  64. }
  65. const prefetchPostsIndex: Prefetcher = async (qc, url) => {
  66. const tags = url.searchParams.get ('tags') ?? ''
  67. const qURL = url.searchParams.get ('url') ?? ''
  68. const title = url.searchParams.get ('title') ?? ''
  69. const originalCreatedFrom = url.searchParams.get ('original_created_from') ?? ''
  70. const originalCreatedTo = url.searchParams.get ('original_created_to') ?? ''
  71. const createdFrom = url.searchParams.get ('created_from') ?? ''
  72. const createdTo = url.searchParams.get ('created_to') ?? ''
  73. const updatedFrom = url.searchParams.get ('updated_from') ?? ''
  74. const updatedTo = url.searchParams.get ('updated_to') ?? ''
  75. const m: 'all' | 'any' = url.searchParams.get ('match') === 'any' ? 'any' : 'all'
  76. const page = Number (url.searchParams.get ('page') || 1)
  77. const limit = Number (url.searchParams.get ('limit') || 20)
  78. const order = (url.searchParams.get ('order') ?? 'original_created_at:desc') as FetchPostsOrder
  79. const keys = {
  80. tags, match: m, page, limit, url: qURL, title,
  81. originalCreatedFrom, originalCreatedTo, createdFrom, createdTo,
  82. updatedFrom, updatedTo, order }
  83. await qc.prefetchQuery ({
  84. queryKey: postsKeys.index (keys),
  85. queryFn: () => fetchPosts (keys) })
  86. }
  87. const prefetchPostShow: Prefetcher = async (qc, url) => {
  88. const m = mPost (url.pathname)
  89. if (!(m))
  90. return
  91. const { id } = m.params
  92. await qc.prefetchQuery ({
  93. queryKey: postsKeys.show (id),
  94. queryFn: () => fetchPost (id) })
  95. }
  96. const prefetchPostChanges: Prefetcher = async (qc, url) => {
  97. const id = url.searchParams.get ('id')
  98. const tag = url.searchParams.get ('tag')
  99. const page = Number (url.searchParams.get ('page') || 1)
  100. const limit = Number (url.searchParams.get ('limit') || 20)
  101. if (tag)
  102. {
  103. await qc.prefetchQuery ({
  104. queryKey: tagsKeys.show (tag),
  105. queryFn: () => fetchTag (tag) })
  106. }
  107. await qc.prefetchQuery ({
  108. queryKey: postsKeys.changes ({ ...(id && { id }),
  109. ...(tag && { tag }),
  110. page, limit }),
  111. queryFn: () => fetchPostChanges ({ ...(id && { id }),
  112. ...(tag && { tag }),
  113. page, limit }) })
  114. }
  115. const prefetchTagsIndex: Prefetcher = async (qc, url) => {
  116. const postRaw = url.searchParams.get ('post')
  117. const post = postRaw ? Number (postRaw) : null
  118. const name = url.searchParams.get ('name') ?? ''
  119. const category = (url.searchParams.get ('category') || null) as Category | null
  120. const postCountGTE = Number (url.searchParams.get ('post_count_gte') || 1)
  121. const postCountLTERaw = url.searchParams.get ('post_count_lte')
  122. const postCountLTE = postCountLTERaw ? Number (postCountLTERaw) : null
  123. const createdFrom = url.searchParams.get ('created_from') ?? ''
  124. const createdTo = url.searchParams.get ('created_to') ?? ''
  125. const updatedFrom = url.searchParams.get ('updated_from') ?? ''
  126. const updatedTo = url.searchParams.get ('updated_to') ?? ''
  127. const page = Number (url.searchParams.get ('page') || 1)
  128. const limit = Number (url.searchParams.get ('limit') || 20)
  129. const order = (url.searchParams.get ('order') ?? 'post_count:desc') as FetchTagsOrder
  130. const keys = {
  131. post, name, category, postCountGTE, postCountLTE, createdFrom, createdTo,
  132. updatedFrom, updatedTo, page, limit, order }
  133. await qc.prefetchQuery ({
  134. queryKey: tagsKeys.index (keys),
  135. queryFn: () => fetchTags (keys) })
  136. }
  137. export const routePrefetchers: { test: (u: URL) => boolean; run: Prefetcher }[] = [
  138. { test: u => ['/', '/posts', '/posts/search'].includes (u.pathname),
  139. run: prefetchPostsIndex },
  140. { test: u => (!(['/posts/new', '/posts/changes', '/posts/search'].includes (u.pathname))
  141. && Boolean (mPost (u.pathname))),
  142. run: prefetchPostShow },
  143. { test: u => u.pathname === '/posts/changes', run: prefetchPostChanges },
  144. { test: u => u.pathname === '/wiki', run: prefetchWikiPagesIndex },
  145. { test: u => (!(['/wiki/new', '/wiki/changes'].includes (u.pathname))
  146. && Boolean (mWiki (u.pathname))),
  147. run: prefetchWikiPageShow },
  148. { test: u => u.pathname === '/tags', run: prefetchTagsIndex }]
  149. export const prefetchForURL = async (qc: QueryClient, urlLike: string): Promise<void> => {
  150. const u = new URL (urlLike, location.origin)
  151. const r = routePrefetchers.find (x => x.test (u))
  152. if (!(r))
  153. return
  154. await r.run (qc, u)
  155. }