-
-
Notifications
You must be signed in to change notification settings - Fork 747
Expand file tree
/
Copy pathclient.ts
More file actions
98 lines (87 loc) · 4.17 KB
/
Copy pathclient.ts
File metadata and controls
98 lines (87 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import type { H3Event } from 'h3'
import { collectionQueryBuilder } from './internal/query'
import { generateNavigationTree } from './internal/navigation'
import { generateItemSurround } from './internal/surround'
import { type GenerateSearchSectionsOptions, generateSearchSections } from './internal/search'
import { fetchQuery } from './internal/api'
import type { Collections, PageCollections, CollectionQueryBuilder, SurroundOptions, SQLOperator, QueryGroupFunction, ContentNavigationItem } from '@nuxt/content'
import { tryUseNuxtApp } from '#imports'
interface ChainablePromise<T extends keyof PageCollections, R> extends Promise<R> {
where(field: keyof PageCollections[T] | string, operator: SQLOperator, value?: unknown): ChainablePromise<T, R>
andWhere(groupFactory: QueryGroupFunction<PageCollections[T]>): ChainablePromise<T, R>
orWhere(groupFactory: QueryGroupFunction<PageCollections[T]>): ChainablePromise<T, R>
order(field: keyof PageCollections[T], direction: 'ASC' | 'DESC'): ChainablePromise<T, R>
}
export const queryCollection = <T extends keyof Collections>(collection: T): CollectionQueryBuilder<Collections[T]> => {
const event = tryUseNuxtApp()?.ssrContext?.event
return collectionQueryBuilder<T>(collection, (collection, sql) => executeContentQuery(event, collection, sql))
}
export function queryCollectionNavigation<T extends keyof PageCollections>(collection: T, fields?: Array<keyof PageCollections[T]>): ChainablePromise<T, ContentNavigationItem[]> {
return chainablePromise(collection, qb => generateNavigationTree(qb, fields))
}
export function queryCollectionItemSurroundings<T extends keyof PageCollections>(collection: T, path: string, opts?: SurroundOptions<keyof PageCollections[T]>): ChainablePromise<T, ContentNavigationItem[]> {
return chainablePromise(collection, qb => generateItemSurround(qb, path, opts))
}
export function queryCollectionSearchSections<T extends keyof PageCollections>(collection: T, opts?: GenerateSearchSectionsOptions) {
return chainablePromise(collection, qb => generateSearchSections(qb, opts))
}
async function executeContentQuery<T extends keyof Collections, Result = Collections[T]>(event: H3Event | undefined, collection: T, sql: string) {
if (import.meta.client && window.WebAssembly) {
if (window.sessionStorage?.getItem('previewToken')) {
try {
const result = await queryContentSqlClientWasm<T, Result>(collection, sql)
if (result && (Array.isArray(result) ? result.length > 0 : true)) {
return result as Result[]
}
}
catch {
// WASM query failed — fall through to server fetch
}
return fetchQuery(event, String(collection), sql) as Promise<Result[]>
}
return queryContentSqlClientWasm<T, Result>(collection, sql) as Promise<Result[]>
}
else {
return fetchQuery(event, String(collection), sql) as Promise<Result[]>
}
}
async function queryContentSqlClientWasm<T extends keyof Collections, Result = Collections[T]>(collection: T, sql: string) {
const rows = await import('./internal/database.client')
.then(m => m.loadDatabaseAdapter(collection))
.then(db => db.all<Result>(sql))
return rows as Result[]
}
function chainablePromise<T extends keyof PageCollections, Result>(collection: T, fn: (qb: CollectionQueryBuilder<PageCollections[T]>) => Promise<Result>) {
const queryBuilder = queryCollection(collection)
const chainable: ChainablePromise<T, Result> = {
where(field, operator, value) {
queryBuilder.where(String(field), operator, value)
return chainable
},
andWhere(groupFactory) {
queryBuilder.andWhere(groupFactory)
return chainable
},
orWhere(groupFactory) {
queryBuilder.orWhere(groupFactory)
return chainable
},
order(field, direction) {
queryBuilder.order(String(field), direction)
return chainable
},
then(onfulfilled, onrejected) {
return fn(queryBuilder).then(onfulfilled, onrejected)
},
catch(onrejected) {
return this.then(undefined, onrejected)
},
finally(onfinally) {
return this.then(undefined, undefined).finally(onfinally)
},
get [Symbol.toStringTag]() {
return 'Promise'
},
}
return chainable
}