diff --git a/src/runtime/app.ts b/src/runtime/app.ts index d6af97e4c..3a921e6f5 100644 --- a/src/runtime/app.ts +++ b/src/runtime/app.ts @@ -1,4 +1,4 @@ -import type { Collections, PageCollections, CollectionQueryBuilder, SurroundOptions } from '@nuxt/content' +import type { Collections, PageCollections, CollectionQueryBuilder, SurroundOptions, SQLOperator } from '@nuxt/content' import { collectionQureyBuilder } from './internal/query' import { measurePerformance } from './internal/performance' import { generateNavigationTree } from './internal/navigation' @@ -7,16 +7,21 @@ import { generateSearchSections } from './internal/search' import { fetchQuery } from './internal/api' import { tryUseNuxtApp } from '#imports' +interface ChainablePromise extends Promise { + where(field: keyof PageCollections[T] | string, operator: SQLOperator, value?: unknown): ChainablePromise + order(field: keyof PageCollections[T], direction: 'ASC' | 'DESC'): ChainablePromise +} + export const queryCollection = (collection: T): CollectionQueryBuilder => { return collectionQureyBuilder(collection, (collection, sql) => executeContentQuery(collection, sql)) } -export async function queryCollectionNavigation(collection: T, fields?: Array) { - return generateNavigationTree(queryCollection(collection), fields) +export function queryCollectionNavigation(collection: T, fields?: Array) { + return chainablePromise(collection, qb => generateNavigationTree(qb, fields)) } -export async function queryCollectionItemSurroundings(collection: T, path: string, opts?: SurroundOptions) { - return generateItemSurround(queryCollection(collection), path, opts) +export function queryCollectionItemSurroundings(collection: T, path: string, opts?: SurroundOptions) { + return chainablePromise(collection, qb => generateItemSurround(qb, path, opts)) } export async function queryCollectionSearchSections(collection: keyof Collections, opts?: { ignoredTags: string[] }) { @@ -45,3 +50,32 @@ async function queryContentSqlClientWasm(collection: T, fn: (qb: CollectionQueryBuilder) => Promise) { + const queryBuilder = queryCollection(collection) + + const chainable: ChainablePromise = { + where(field, operator, value) { + queryBuilder.where(String(field), operator, value) + 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 +} diff --git a/src/runtime/nitro.ts b/src/runtime/nitro.ts index 0a1795e9c..1b95ddc21 100644 --- a/src/runtime/nitro.ts +++ b/src/runtime/nitro.ts @@ -1,4 +1,4 @@ -import type { Collections, CollectionQueryBuilder, PageCollections, SurroundOptions } from '@nuxt/content' +import type { Collections, CollectionQueryBuilder, PageCollections, SurroundOptions, SQLOperator } from '@nuxt/content' import type { H3Event } from 'h3' import { collectionQureyBuilder } from './internal/query' import { generateNavigationTree } from './internal/navigation' @@ -6,18 +6,52 @@ import { generateItemSurround } from './internal/surround' import { generateSearchSections } from './internal/search' import { fetchQuery } from './internal/api' +interface ChainablePromise extends Promise { + where(field: keyof PageCollections[T] | string, operator: SQLOperator, value?: unknown): ChainablePromise + order(field: keyof PageCollections[T], direction: 'ASC' | 'DESC'): ChainablePromise +} + export const queryCollectionWithEvent = (event: H3Event, collection: T): CollectionQueryBuilder => { return collectionQureyBuilder(collection, (collection, sql) => fetchQuery(event, collection, sql)) } export async function queryCollectionNavigationWithEvent(event: H3Event, collection: T, fields?: Array) { - return generateNavigationTree(queryCollectionWithEvent(event, collection), fields) + return chainablePromise(event, collection, qb => generateNavigationTree(qb, fields)) } export async function queryCollectionItemSurroundingsWithEvent(event: H3Event, collection: T, path: string, opts?: SurroundOptions) { - return generateItemSurround(queryCollectionWithEvent(event, collection), path, opts) + return chainablePromise(event, collection, qb => generateItemSurround(qb, path, opts)) } export async function queryCollectionSearchSections(event: H3Event, collection: keyof Collections, opts?: { ignoredTags: string[] }) { return generateSearchSections(queryCollectionWithEvent(event, collection), opts) } + +function chainablePromise(event: H3Event, collection: T, fn: (qb: CollectionQueryBuilder) => Promise) { + const queryBuilder = queryCollectionWithEvent(event, collection) + + const chainable: ChainablePromise = { + where(field, operator, value) { + queryBuilder.where(String(field), operator, value) + 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 +}