diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index 78d64610b0..673f2adb53 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -134,9 +134,14 @@ export async function destroy(ctx: any) { export async function search(ctx: any) { const tableId = utils.getTableId(ctx) - ctx.status = 200 - ctx.body = await quotas.addQuery(() => sdk.rows.search(tableId, ctx), { + const searchParams = { + ...ctx.request.body, + tableId, + } + + ctx.status = 200 + ctx.body = await quotas.addQuery(() => sdk.rows.search(searchParams), { datasourceId: tableId, }) } diff --git a/packages/server/src/sdk/app/rows/search.ts b/packages/server/src/sdk/app/rows/search.ts index b3b01d5d6c..b43af78740 100644 --- a/packages/server/src/sdk/app/rows/search.ts +++ b/packages/server/src/sdk/app/rows/search.ts @@ -1,4 +1,4 @@ -import { Ctx, SearchFilters } from "@budibase/types" +import { SearchFilters } from "@budibase/types" import { isExternalTable } from "../../../integrations/utils" import * as internal from "./search/internal" import * as external from "./search/external" @@ -6,13 +6,15 @@ import { Format } from "../../../api/controllers/view/exporters" export interface SearchParams { tableId: string - paginate: boolean - query?: SearchFilters - bookmark?: number - limit: number + paginate?: boolean + query: SearchFilters + bookmark?: string + limit?: number sort?: string sortOrder?: string sortType?: string + version?: string + disableEscaping?: boolean } export interface ViewParams { @@ -28,8 +30,8 @@ function pickApi(tableId: any) { return internal } -export async function search(tableId: string, ctx: Ctx) { - return pickApi(tableId).search(ctx) +export async function search(options: SearchParams) { + return pickApi(options.tableId).search(options) } export interface ExportRowsParams { @@ -37,7 +39,7 @@ export interface ExportRowsParams { format: Format rowIds: string[] columns: string[] - query: string + query: SearchFilters } export interface ExportRowsResult { diff --git a/packages/server/src/sdk/app/rows/search/external.ts b/packages/server/src/sdk/app/rows/search/external.ts index fe175d9d53..3317b0e398 100644 --- a/packages/server/src/sdk/app/rows/search/external.ts +++ b/packages/server/src/sdk/app/rows/search/external.ts @@ -5,22 +5,23 @@ import { PaginationJson, IncludeRelationship, Row, - Ctx, + SearchFilters, } from "@budibase/types" import * as exporters from "../../../../api/controllers/view/exporters" import sdk from "../../../../sdk" import { handleRequest } from "../../../../api/controllers/row/external" import { breakExternalTableId } from "../../../../integrations/utils" import { cleanExportRows } from "../utils" -import { apiFileReturn } from "../../../../utilities/fileSystem" import { utils } from "@budibase/shared-core" -import { ExportRowsParams, ExportRowsResult } from "../search" +import { ExportRowsParams, ExportRowsResult, SearchParams } from "../search" +import { HTTPError } from "@budibase/backend-core" -export async function search(ctx: Ctx) { - const tableId = ctx.params.tableId - const { paginate, query, ...params } = ctx.request.body - let { bookmark, limit } = params - if (!bookmark && paginate) { +export async function search(options: SearchParams) { + const { tableId } = options + const { paginate, query, ...params } = options + const { limit } = params + let bookmark = (params.bookmark && parseInt(params.bookmark)) || undefined + if (paginate && bookmark) { bookmark = 1 } let paginateObj = {} @@ -60,14 +61,14 @@ export async function search(ctx: Ctx) { sort, paginate: { limit: 1, - page: bookmark * limit + 1, + page: bookmark! * limit + 1, }, includeSqlRelationships: IncludeRelationship.INCLUDE, })) as Row[] hasNextPage = nextRows.length > 0 } // need wrapper object for bookmarks etc when paginating - return { rows, hasNextPage, bookmark: bookmark + 1 } + return { rows, hasNextPage, bookmark: (bookmark || 0) + 1 } } catch (err: any) { if (err.message && err.message.includes("does not exist")) { throw new Error( @@ -87,31 +88,30 @@ export async function exportRows( const datasource = await sdk.datasources.get(datasourceId!) if (!datasource || !datasource.entities) { - throw ctx.throw(400, "Datasource has not been configured for plus API.") + throw new HTTPError("Datasource has not been configured for plus API.", 400) } + let query: SearchFilters = {} if (rowIds?.length) { - ctx.request.body = { - query: { - oneOf: { - _id: rowIds.map((row: string) => { - const ids = JSON.parse( - decodeURI(row).replace(/'/g, `"`).replace(/%2C/g, ",") + query = { + oneOf: { + _id: rowIds.map((row: string) => { + const ids = JSON.parse( + decodeURI(row).replace(/'/g, `"`).replace(/%2C/g, ",") + ) + if (ids.length > 1) { + throw new HTTPError( + "Export data does not support composite keys.", + 400 ) - if (ids.length > 1) { - throw ctx.throw( - 400, - "Export data does not support composite keys." - ) - } - return ids[0] - }), - }, + } + return ids[0] + }), }, } } - let result = await search(ctx) + let result = await search({ tableId, query }) let rows: Row[] = [] // Filter data to only specified columns if required @@ -128,7 +128,7 @@ export async function exportRows( } if (!tableName) { - throw ctx.throw(400, "Could not find table name.") + throw new HTTPError("Could not find table name.", 400) } const schema = datasource.entities[tableName].schema let exportRows = cleanExportRows(rows, schema, format, columns) diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index 0407d1b630..70274de34a 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -1,4 +1,7 @@ -import { context } from "@budibase/backend-core" +import { + context, + SearchParams as InternalSearchParams, +} from "@budibase/backend-core" import env from "../../../../environment" import { fullSearch, paginatedSearch } from "./internalSearch" import { @@ -8,7 +11,7 @@ import { } from "../../../../db/utils" import { getGlobalUsersFromMetadata } from "../../../../utilities/global" import { outputProcessing } from "../../../../utilities/rowProcessor" -import { Ctx, Database, Row } from "@budibase/types" +import { Database, Row } from "@budibase/types" import { cleanExportRows } from "../utils" import { Format, @@ -16,7 +19,6 @@ import { json, jsonWithSchema, } from "../../../../api/controllers/view/exporters" -import { apiFileReturn } from "../../../../utilities/fileSystem" import * as inMemoryViews from "../../../../db/inMemoryView" import { migrateToInMemoryView, @@ -25,10 +27,10 @@ import { getFromMemoryDoc, } from "../../../../api/controllers/view/utils" import sdk from "../../../../sdk" -import { ExportRowsParams, ExportRowsResult } from "../search" +import { ExportRowsParams, ExportRowsResult, SearchParams } from "../search" -export async function search(ctx: Ctx) { - const { tableId } = ctx.params +export async function search(options: SearchParams) { + const { tableId } = options // Fetch the whole table when running in cypress, as search doesn't work if (!env.COUCH_DB_URL && env.isCypress()) { @@ -36,16 +38,25 @@ export async function search(ctx: Ctx) { } const db = context.getAppDB() - const { paginate, query, ...params } = ctx.request.body - params.version = ctx.version - params.tableId = tableId + const { paginate, query } = options + + const params: InternalSearchParams = { + tableId: options.tableId, + sort: options.sort, + sortOrder: options.sortOrder, + sortType: options.sortType, + limit: options.limit, + bookmark: options.bookmark, + version: options.version, + disableEscaping: options.disableEscaping, + } let table if (params.sort && !params.sortType) { table = await db.get(tableId) const schema = table.schema const sortField = schema[params.sort] - params.sortType = sortField.type == "number" ? "number" : "string" + params.sortType = sortField.type === "number" ? "number" : "string" } let response @@ -86,7 +97,7 @@ export async function exportRows( result = await outputProcessing(table, response) } else if (query) { - let searchResponse = await search(ctx) + let searchResponse = await search({ tableId, query }) result = searchResponse.rows }