Skip to content

Commit 555cfa1

Browse files
committed
feat: create index for path base search (#1401)
1 parent 59f46ee commit 555cfa1

File tree

7 files changed

+66
-8
lines changed

7 files changed

+66
-8
lines changed

src/module.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,12 +533,16 @@ export default defineNuxtModule<ModuleOptions>({
533533
nitro.options.runtimeConfig.public.content.wsUrl = url.replace('http', 'ws')
534534

535535
// Watch contents
536-
await nitro.storage.watch((event: WatchEvent, key: string) => {
536+
await nitro.storage.watch(async (event: WatchEvent, key: string) => {
537537
// Ignore events that are not related to content
538538
if (!key.startsWith(MOUNT_PREFIX)) {
539539
return
540540
}
541541
key = key.substring(MOUNT_PREFIX.length)
542+
543+
// Remove content Index
544+
await nitro.storage.removeItem('cache:content:content-index.json')
545+
542546
// Broadcast a message to the server to refresh the page
543547
ws.broadcast({ event, key })
544548
})

src/runtime/composables/query.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const createQueryFetch = <T = ParsedContent>(path?: string) => (query: Qu
3535
})
3636
}
3737

38-
return $fetch<T | T[]>(apiPath as any, {
38+
return $fetch(apiPath as any, {
3939
method: 'GET',
4040
responseType: 'json',
4141
params: {

src/runtime/server/api/cache.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { defineEventHandler } from 'h3'
2-
import { serverQueryContent } from '../storage'
2+
import { getContentIndex } from '../content-index'
3+
import { cacheStorage, serverQueryContent } from '../storage'
34

45
// This route is used to cache all the parsed content
56
export default defineEventHandler(async (event) => {
67
const now = Date.now()
78
// Fetch all content
89
await serverQueryContent(event).find()
910

11+
// Generate Index
12+
await getContentIndex(event)
13+
14+
const navigation = await $fetch('/api/_content/navigation')
15+
await cacheStorage.setItem('content-navigation.json', navigation)
16+
1017
return {
1118
generatedAt: now,
1219
generateTime: Date.now() - now

src/runtime/server/api/navigation.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
import { defineEventHandler } from 'h3'
2-
import { serverQueryContent } from '../storage'
2+
import { cacheStorage, serverQueryContent } from '../storage'
33
import { createNav } from '../navigation'
44
import { ParsedContentMeta } from '../../types'
55
import { getContentQuery } from '../../utils/query'
6+
import { isPreview } from '../preview'
67

78
export default defineEventHandler(async (event) => {
89
const query = getContentQuery(event)
910

11+
// Read from cache if not preview and there is no query
12+
if (!isPreview(event) && Object.keys(query).length === 0) {
13+
const cache = cacheStorage.getItem('content-navigation.json')
14+
if (cache) {
15+
return cache
16+
}
17+
}
18+
1019
const contents = await serverQueryContent(event, query)
1120
.where({
1221
/**

src/runtime/server/content-index.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { CompatibilityEvent } from 'h3'
2+
import type { ParsedContent, QueryBuilder } from '../types'
3+
import { isPreview } from './preview'
4+
import { cacheStorage, getContent, getContentsList, serverQueryContent } from './storage'
5+
6+
export async function getContentIndex (event: CompatibilityEvent) {
7+
let contentIndex = await cacheStorage.getItem('content-index.json') as Record<string, string>
8+
if (!contentIndex) {
9+
// Fetch all content
10+
const data = await serverQueryContent(event).find()
11+
12+
contentIndex = data.reduce((acc, item) => {
13+
acc[item._path!] = item._id
14+
return acc
15+
}, {} as Record<string, string>)
16+
17+
await cacheStorage.setItem('content-index.json', contentIndex)
18+
}
19+
20+
return contentIndex
21+
}
22+
23+
export async function getIndexedContentsList<T = ParsedContent> (event: CompatibilityEvent, query: QueryBuilder<T>): Promise<T[]> {
24+
const params = query.params()
25+
const path = params?.where?.find(wh => wh._path)?._path
26+
27+
// Read from Index is not preview and path is string or RegExp
28+
if (!isPreview(event) && (typeof path === 'string' || path instanceof RegExp)) {
29+
const index = await getContentIndex(event)
30+
const keys = Object.keys(index)
31+
.filter(key => (path as any).test ? (path as any).test(key) : key === String(path))
32+
.map(key => index[key])
33+
34+
const contents = await Promise.all(keys.map(key => getContent(event, key)))
35+
return contents as unknown as Promise<T[]>
36+
}
37+
38+
return getContentsList(event) as unknown as Promise<T[]>
39+
}

src/runtime/server/storage.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { createPipelineFetcher } from '../query/match/pipeline'
1010
import { transformContent } from '../transformers'
1111
import type { ModuleOptions } from '../../module'
1212
import { getPreview, isPreview } from './preview'
13+
import { getIndexedContentsList } from './content-index'
1314
// eslint-disable-next-line import/named
1415
// @ts-ignore
1516
import { useNitroApp, useRuntimeConfig, useStorage } from '#imports'
@@ -200,9 +201,7 @@ export const createServerQueryFetch = <T = ParsedContent>(event: CompatibilityEv
200201
query.sort({ _file: 1, $numeric: true })
201202
}
202203

203-
return createPipelineFetcher<T>(
204-
() => getContentsList(event) as unknown as Promise<T[]>
205-
)(query)
204+
return createPipelineFetcher<T>(() => getIndexedContentsList<T>(event, query))(query)
206205
}
207206

208207
/**

src/runtime/types.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ export interface QueryBuilder<T = ParsedContentMeta> {
471471
/**
472472
* Fetch sorround contents
473473
*/
474-
findSurround(query: string | object, options?: Partial<{ before: number; after: number }>): Promise<Array<T>>
474+
findSurround(query: string | QueryBuilderWhere, options?: Partial<{ before: number; after: number }>): Promise<Array<T>>
475475

476476
/**
477477
* Filter contents based on locale

0 commit comments

Comments
 (0)