From 90bf4655eaa924408cf095b6fa0dff4d1de3e136 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 17 Jul 2023 15:57:12 +0200 Subject: [PATCH] Remove ctx from export rows (search not implemented) --- .../server/src/api/controllers/row/index.ts | 34 +++++++++++-- packages/server/src/sdk/app/rows/search.ts | 20 +++++++- .../src/sdk/app/rows/search/external.ts | 50 +++++++++---------- .../src/sdk/app/rows/search/internal.ts | 32 ++++++------ packages/server/src/sdk/app/rows/utils.ts | 3 +- 5 files changed, 92 insertions(+), 47 deletions(-) diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index ed441f7784..78d64610b0 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -6,6 +6,8 @@ import { Ctx } from "@budibase/types" import * as utils from "./utils" import { gridSocket } from "../../../websockets" import sdk from "../../../sdk" +import * as exporters from "../view/exporters" +import { apiFileReturn } from "../../../utilities/fileSystem" function pickApi(tableId: any) { if (isExternalTable(tableId)) { @@ -164,7 +166,33 @@ export async function fetchEnrichedRow(ctx: any) { export const exportRows = async (ctx: any) => { const tableId = utils.getTableId(ctx) - ctx.body = await quotas.addQuery(() => sdk.rows.exportRows(tableId, ctx), { - datasourceId: tableId, - }) + + const format = ctx.query.format + + const { rows, columns, query } = ctx.request.body + if (typeof format !== "string" || !exporters.isFormat(format)) { + ctx.throw( + 400, + `Format ${format} not valid. Valid values: ${Object.values( + exporters.Format + )}` + ) + } + + ctx.body = await quotas.addQuery( + async () => { + const { fileName, content } = await sdk.rows.exportRows({ + tableId, + format, + rowIds: rows, + columns, + query, + }) + ctx.attachment(fileName) + return apiFileReturn(content) + }, + { + datasourceId: tableId, + } + ) } diff --git a/packages/server/src/sdk/app/rows/search.ts b/packages/server/src/sdk/app/rows/search.ts index f8f50df2e6..b3b01d5d6c 100644 --- a/packages/server/src/sdk/app/rows/search.ts +++ b/packages/server/src/sdk/app/rows/search.ts @@ -2,6 +2,7 @@ import { Ctx, SearchFilters } from "@budibase/types" import { isExternalTable } from "../../../integrations/utils" import * as internal from "./search/internal" import * as external from "./search/external" +import { Format } from "../../../api/controllers/view/exporters" export interface SearchParams { tableId: string @@ -31,8 +32,23 @@ export async function search(tableId: string, ctx: Ctx) { return pickApi(tableId).search(ctx) } -export async function exportRows(tableId: string, ctx: Ctx) { - return pickApi(tableId).exportRows(ctx) +export interface ExportRowsParams { + tableId: string + format: Format + rowIds: string[] + columns: string[] + query: string +} + +export interface ExportRowsResult { + fileName: string + content: string +} + +export async function exportRows( + options: ExportRowsParams +): Promise { + return pickApi(options.tableId).exportRows(options) } export async function fetch(tableId: string) { diff --git a/packages/server/src/sdk/app/rows/search/external.ts b/packages/server/src/sdk/app/rows/search/external.ts index e6d910b1c9..fe175d9d53 100644 --- a/packages/server/src/sdk/app/rows/search/external.ts +++ b/packages/server/src/sdk/app/rows/search/external.ts @@ -14,6 +14,7 @@ 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" export async function search(ctx: Ctx) { const tableId = ctx.params.tableId @@ -78,34 +79,30 @@ export async function search(ctx: Ctx) { } } -export async function exportRows(ctx: Ctx) { - const { datasourceId, tableName } = breakExternalTableId(ctx.params.tableId) - const format = ctx.query.format as string - const { columns } = ctx.request.body +export async function exportRows( + options: ExportRowsParams +): Promise { + const { tableId, format, columns, rowIds } = options + const { datasourceId, tableName } = breakExternalTableId(tableId) + const datasource = await sdk.datasources.get(datasourceId!) if (!datasource || !datasource.entities) { - ctx.throw(400, "Datasource has not been configured for plus API.") + throw ctx.throw(400, "Datasource has not been configured for plus API.") } - if (!exporters.isFormat(format)) { - ctx.throw( - 400, - `Format ${format} not valid. Valid values: ${Object.values( - exporters.Format - )}` - ) - } - - if (ctx.request.body.rows) { + if (rowIds?.length) { ctx.request.body = { query: { oneOf: { - _id: ctx.request.body.rows.map((row: string) => { + _id: rowIds.map((row: string) => { const ids = JSON.parse( decodeURI(row).replace(/'/g, `"`).replace(/%2C/g, ",") ) if (ids.length > 1) { - ctx.throw(400, "Export data does not support composite keys.") + throw ctx.throw( + 400, + "Export data does not support composite keys." + ) } return ids[0] }), @@ -131,14 +128,14 @@ export async function exportRows(ctx: Ctx) { } if (!tableName) { - ctx.throw(400, "Could not find table name.") + throw ctx.throw(400, "Could not find table name.") } - let schema = datasource.entities[tableName].schema + const schema = datasource.entities[tableName].schema let exportRows = cleanExportRows(rows, schema, format, columns) let headers = Object.keys(schema) - let content + let content: string switch (format) { case exporters.Format.CSV: content = exporters.csv(headers, exportRows) @@ -150,15 +147,14 @@ export async function exportRows(ctx: Ctx) { content = exporters.jsonWithSchema(schema, exportRows) break default: - utils.unreachable(format) - break + throw utils.unreachable(format) } - const filename = `export.${format}` - - // send down the file - ctx.attachment(filename) - return apiFileReturn(content) + const fileName = `export.${format}` + return { + fileName, + content, + } } export async function fetch(tableId: string) { diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index 7caa5083c9..0407d1b630 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -25,6 +25,7 @@ import { getFromMemoryDoc, } from "../../../../api/controllers/view/utils" import sdk from "../../../../sdk" +import { ExportRowsParams, ExportRowsResult } from "../search" export async function search(ctx: Ctx) { const { tableId } = ctx.params @@ -67,15 +68,12 @@ export async function search(ctx: Ctx) { return response } -export async function exportRows(ctx: Ctx) { +export async function exportRows( + options: ExportRowsParams +): Promise { + const { tableId, format, rowIds, columns, query } = options const db = context.getAppDB() - const table = await db.get(ctx.params.tableId) - const rowIds = ctx.request.body.rows - let format = ctx.query.format - if (typeof format !== "string") { - ctx.throw(400, "Format parameter is not valid") - } - const { columns, query } = ctx.request.body + const table = await db.get(tableId) let result if (rowIds) { @@ -109,14 +107,20 @@ export async function exportRows(ctx: Ctx) { let exportRows = cleanExportRows(rows, schema, format, columns) if (format === Format.CSV) { - ctx.attachment("export.csv") - return apiFileReturn(csv(Object.keys(rows[0]), exportRows)) + return { + fileName: "export.csv", + content: csv(Object.keys(rows[0]), exportRows), + } } else if (format === Format.JSON) { - ctx.attachment("export.json") - return apiFileReturn(json(exportRows)) + return { + fileName: "export.json", + content: json(exportRows), + } } else if (format === Format.JSON_WITH_SCHEMA) { - ctx.attachment("export.json") - return apiFileReturn(jsonWithSchema(schema, exportRows)) + return { + fileName: "export.json", + content: jsonWithSchema(schema, exportRows), + } } else { throw "Format not recognised" } diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index 1f5be1479b..d9f64af163 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -1,3 +1,4 @@ +import { TableSchema } from "@budibase/types" import { FieldTypes } from "../../../constants" import { makeExternalQuery } from "../../../integrations/base/query" import { Format } from "../../../api/controllers/view/exporters" @@ -11,7 +12,7 @@ export async function getDatasourceAndQuery(json: any) { export function cleanExportRows( rows: any[], - schema: any, + schema: TableSchema, format: string, columns: string[] ) {