import DataFetch from "./DataFetch" import { Helpers } from "@budibase/bbui" import { Query } from "@budibase/types" import { get } from "svelte/store" interface QueryDatasource { _id: string fields: any queryParams: any parameters: any } export default class QueryFetch extends DataFetch { determineFeatureFlags(definition: Query) { const supportsPagination = !!definition?.fields?.pagination?.type && !!definition?.fields?.pagination?.location && !!definition?.fields?.pagination?.pageParam return { supportsPagination } } async getDefinition(datasource: QueryDatasource) { if (!datasource?._id) { return null } try { const definition = await this.API.fetchQueryDefinition(datasource._id) // After getting the definition of query, it loses "fields" attribute // because of security reason from the server. However, this attribute // needs to be inside the definition for pagination. if (!definition.fields) { definition.fields = datasource.fields } return definition } catch (error) { return null } } getDefaultSortColumn() { return null } async getData() { const { datasource, limit, paginate } = this.options const { supportsPagination } = this.features const { cursor, definition } = get(this.store) const type = definition?.fields?.pagination?.type // Set the default query params let parameters = Helpers.cloneDeep(datasource?.queryParams || {}) for (let param of datasource?.parameters || {}) { if (!parameters[param.name]) { parameters[param.name] = param.default } } // Add pagination to query if supported const queryPayload: { parameters: any pagination?: { page: number | null limit: number } } = { parameters } if (paginate && supportsPagination) { const requestCursor = type === "page" ? parseInt(cursor || "1") : cursor queryPayload.pagination = { page: requestCursor, limit } } // Execute query try { const res = await this.API.executeQuery(datasource?._id, queryPayload) const { data, pagination, ...rest } = res // Derive pagination info from response let nextCursor = null let hasNextPage = false if (paginate && supportsPagination) { if (type === "page") { // For "page number" pagination, increment the existing page number nextCursor = queryPayload.pagination!.page! + 1 hasNextPage = data?.length === limit && limit > 0 } else { // For "cursor" pagination, the cursor should be in the response nextCursor = pagination?.cursor hasNextPage = nextCursor != null } } return { rows: data || [], info: rest, cursor: nextCursor, hasNextPage, } } catch (error) { return { rows: [], hasNextPage: false, } } } }