From 0abd1deb3492f80b98b0d34a6709254f393020a6 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 8 Aug 2023 13:19:22 +0100 Subject: [PATCH] Updating test cases, fixes based on running through view/row API. --- .../src/api/controllers/row/external.ts | 13 ++-- .../src/api/controllers/row/internal.ts | 23 +++--- .../server/src/api/controllers/row/utils.ts | 10 ++- .../server/src/api/routes/tests/row.spec.ts | 71 ++----------------- .../server/src/middleware/trimViewRowInfo.ts | 31 +++++--- .../server/src/tests/utilities/api/row.ts | 37 ++++++++-- .../server/src/tests/utilities/api/viewV2.ts | 46 ------------ packages/types/src/api/web/app/rows.ts | 2 + 8 files changed, 87 insertions(+), 146 deletions(-) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 3ee4ca6edd..bc4edbd661 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -15,6 +15,7 @@ import { UserCtx, } from "@budibase/types" import sdk from "../../../sdk" +import * as utils from "./utils" export async function handleRequest( operation: Operation, @@ -43,7 +44,7 @@ export async function handleRequest( } export async function patch(ctx: UserCtx) { - const tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) const { _id, ...rowData } = ctx.request.body const validateResult = await sdk.rows.utils.validate({ @@ -70,7 +71,7 @@ export async function patch(ctx: UserCtx) { export async function save(ctx: UserCtx) { const inputs = ctx.request.body - const tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) const validateResult = await sdk.rows.utils.validate({ row: inputs, tableId, @@ -98,12 +99,12 @@ export async function save(ctx: UserCtx) { export async function find(ctx: UserCtx) { const id = ctx.params.rowId - const tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) return sdk.rows.external.getRow(tableId, id) } export async function destroy(ctx: UserCtx) { - const tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) const _id = ctx.request.body._id const { row } = (await handleRequest(Operation.DELETE, tableId, { id: breakRowIdField(_id), @@ -114,7 +115,7 @@ export async function destroy(ctx: UserCtx) { export async function bulkDestroy(ctx: UserCtx) { const { rows } = ctx.request.body - const tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) let promises: Promise[] = [] for (let row of rows) { promises.push( @@ -130,7 +131,7 @@ export async function bulkDestroy(ctx: UserCtx) { export async function fetchEnrichedRow(ctx: UserCtx) { const id = ctx.params.rowId - const tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) const { datasourceId, tableName } = breakExternalTableId(tableId) const datasource: Datasource = await sdk.datasources.get(datasourceId!) if (!tableName) { diff --git a/packages/server/src/api/controllers/row/internal.ts b/packages/server/src/api/controllers/row/internal.ts index 2ff1df0933..3432ec80f3 100644 --- a/packages/server/src/api/controllers/row/internal.ts +++ b/packages/server/src/api/controllers/row/internal.ts @@ -13,7 +13,7 @@ import { import { FieldTypes } from "../../../constants" import * as utils from "./utils" import { cloneDeep } from "lodash/fp" -import { context, db as dbCore } from "@budibase/backend-core" +import { context } from "@budibase/backend-core" import { finaliseRow, updateRelatedFormula } from "./staticFormula" import { UserCtx, @@ -26,8 +26,8 @@ import { import sdk from "../../../sdk" export async function patch(ctx: UserCtx) { + const tableId = utils.getTableId(ctx) const inputs = ctx.request.body - const tableId = inputs.tableId const isUserTable = tableId === InternalTables.USER_METADATA let oldRow const dbTable = await sdk.tables.getTable(tableId) @@ -94,7 +94,8 @@ export async function patch(ctx: UserCtx) { export async function save(ctx: UserCtx) { let inputs = ctx.request.body - inputs.tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) + inputs.tableId = tableId if (!inputs._rev && !inputs._id) { inputs._id = generateRowID(inputs.tableId) @@ -132,20 +133,22 @@ export async function save(ctx: UserCtx) { } export async function find(ctx: UserCtx) { - const db = dbCore.getDB(ctx.appId) - const table = await sdk.tables.getTable(ctx.params.tableId) - let row = await utils.findRow(ctx, ctx.params.tableId, ctx.params.rowId) + const tableId = utils.getTableId(ctx), + rowId = ctx.params.rowId + const table = await sdk.tables.getTable(tableId) + let row = await utils.findRow(ctx, tableId, rowId) row = await outputProcessing(table, row) return row } export async function destroy(ctx: UserCtx) { const db = context.getAppDB() + const tableId = utils.getTableId(ctx) const { _id } = ctx.request.body let row = await db.get(_id) let _rev = ctx.request.body._rev || row._rev - if (row.tableId !== ctx.params.tableId) { + if (row.tableId !== tableId) { throw "Supplied tableId doesn't match the row's tableId" } const table = await sdk.tables.getTable(row.tableId) @@ -163,7 +166,7 @@ export async function destroy(ctx: UserCtx) { await updateRelatedFormula(table, row) let response - if (ctx.params.tableId === InternalTables.USER_METADATA) { + if (tableId === InternalTables.USER_METADATA) { ctx.params = { id: _id, } @@ -176,7 +179,7 @@ export async function destroy(ctx: UserCtx) { } export async function bulkDestroy(ctx: UserCtx) { - const tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) const table = await sdk.tables.getTable(tableId) let { rows } = ctx.request.body @@ -216,7 +219,7 @@ export async function bulkDestroy(ctx: UserCtx) { export async function fetchEnrichedRow(ctx: UserCtx) { const db = context.getAppDB() - const tableId = ctx.params.tableId + const tableId = utils.getTableId(ctx) const rowId = ctx.params.rowId // need table to work out where links go in row let [table, row] = await Promise.all([ diff --git a/packages/server/src/api/controllers/row/utils.ts b/packages/server/src/api/controllers/row/utils.ts index 6cc342b8a0..157f18e231 100644 --- a/packages/server/src/api/controllers/row/utils.ts +++ b/packages/server/src/api/controllers/row/utils.ts @@ -45,15 +45,19 @@ export async function findRow(ctx: UserCtx, tableId: string, rowId: string) { } export function getTableId(ctx: Ctx) { - if (ctx.request.body?.tableId) { - return ctx.request.body.tableId - } + // top priority, use the URL first if (ctx.params?.sourceId) { return ctx.params.sourceId } + // check body for a table ID + if (ctx.request.body?.tableId) { + return ctx.request.body.tableId + } + // now check for old way of specifying table ID if (ctx.params?.tableId) { return ctx.params.tableId } + // now check if a specific view name if (ctx.params?.viewName) { return ctx.params.viewName } diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 5e1616340f..8d4c9a91fd 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -16,15 +16,12 @@ import { FieldType, SortType, SortOrder, - DeleteRow, } from "@budibase/types" import { expectAnyInternalColsAttributes, generator, structures, } from "@budibase/backend-core/tests" -import trimViewRowInfoMiddleware from "../../../middleware/trimViewRowInfo" -import router from "../row" describe("/rows", () => { let request = setup.getRequest() @@ -393,18 +390,6 @@ describe("/rows", () => { expect(saved.arrayFieldArrayStrKnown).toEqual(["One"]) expect(saved.optsFieldStrKnown).toEqual("Alpha") }) - - it("should throw an error when creating a table row with view id data", async () => { - const res = await request - .post(`/api/${row.tableId}/rows`) - .send({ ...row, _viewId: generator.guid() }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - expect(res.body.message).toEqual( - "Table row endpoints cannot contain view info" - ) - }) }) describe("patch", () => { @@ -454,25 +439,6 @@ describe("/rows", () => { await assertRowUsage(rowUsage) await assertQueryUsage(queryUsage) }) - - it("should throw an error when creating a table row with view id data", async () => { - const existing = await config.createRow() - - const res = await config.api.row.patch( - table._id!, - { - ...existing, - _id: existing._id!, - _rev: existing._rev!, - tableId: table._id!, - _viewId: generator.guid(), - }, - { expectStatus: 400 } - ) - expect(res.body.message).toEqual( - "Table row endpoints cannot contain view info" - ) - }) }) describe("destroy", () => { @@ -741,7 +707,7 @@ describe("/rows", () => { }) // the environment needs configured for this await setup.switchToSelfHosted(async () => { - context.doInAppContext(config.getAppId(), async () => { + return context.doInAppContext(config.getAppId(), async () => { const enriched = await outputProcessing(table, [row]) expect((enriched as Row[])[0].attachment[0].url).toBe( `/files/signed/prod-budi-app-assets/${config.getProdAppId()}/attachments/${attachmentId}` @@ -847,7 +813,7 @@ describe("/rows", () => { }) const data = randomRowData() - const newRow = await config.api.viewV2.row.create(view.id, { + const newRow = await config.api.row.save(view.id, { tableId: config.table!._id, _viewId: view.id, ...data, @@ -869,16 +835,6 @@ describe("/rows", () => { expect(row.body.age).toBeUndefined() expect(row.body.jobTitle).toBeUndefined() }) - - it("should setup the trimViewRowInfo middleware", async () => { - const route = router.stack.find( - r => - r.methods.includes("POST") && - r.path === "/api/v2/views/:viewId/rows" - ) - expect(route).toBeDefined() - expect(route?.stack).toContainEqual(trimViewRowInfoMiddleware) - }) }) describe("patch", () => { @@ -893,13 +849,13 @@ describe("/rows", () => { }, }) - const newRow = await config.api.viewV2.row.create(view.id, { + const newRow = await config.api.row.save(view.id, { tableId, _viewId: view.id, ...randomRowData(), }) const newData = randomRowData() - await config.api.viewV2.row.update(view.id, newRow._id!, { + await config.api.row.patch(view.id, { tableId, _viewId: view.id, _id: newRow._id!, @@ -922,16 +878,6 @@ describe("/rows", () => { expect(row.body.age).toBeUndefined() expect(row.body.jobTitle).toBeUndefined() }) - - it("should setup the trimViewRowInfo middleware", async () => { - const route = router.stack.find( - r => - r.methods.includes("PATCH") && - r.path === "/api/v2/views/:viewId/rows/:rowId" - ) - expect(route).toBeDefined() - expect(route?.stack).toContainEqual(trimViewRowInfoMiddleware) - }) }) describe("destroy", () => { @@ -950,10 +896,7 @@ describe("/rows", () => { const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const body: DeleteRow = { - _id: createdRow._id!, - } - await config.api.viewV2.row.delete(view.id, body) + await config.api.row.delete(view.id, [createdRow]) await assertRowUsage(rowUsage - 1) await assertQueryUsage(queryUsage + 1) @@ -982,9 +925,7 @@ describe("/rows", () => { const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - await config.api.viewV2.row.delete(view.id, { - rows: [rows[0], rows[2]], - }) + await config.api.row.delete(view.id, [rows[0], rows[2]]) await assertRowUsage(rowUsage - 2) await assertQueryUsage(queryUsage + 1) diff --git a/packages/server/src/middleware/trimViewRowInfo.ts b/packages/server/src/middleware/trimViewRowInfo.ts index 763552c3d7..5a207936b2 100644 --- a/packages/server/src/middleware/trimViewRowInfo.ts +++ b/packages/server/src/middleware/trimViewRowInfo.ts @@ -3,26 +3,35 @@ import * as utils from "../db/utils" import sdk from "../sdk" import { db } from "@budibase/backend-core" import { Next } from "koa" +import { getTableId } from "../api/controllers/row/utils" export default async (ctx: Ctx, next: Next) => { const { body } = ctx.request - const { _viewId: viewId } = body + let { _viewId: viewId } = body - const possibleViewId = ctx.params.tableId + const possibleViewId = getTableId(ctx) + if (utils.isViewID(possibleViewId)) { + viewId = possibleViewId + } // nothing to do, it is not a view (just a table ID) - if (!viewId || !utils.isViewID(possibleViewId)) { + if (!viewId) { return next() } - const { tableId } = utils.extractViewInfoFromID(possibleViewId) - const { _viewId, ...trimmedView } = await trimViewFields( - viewId, - tableId, - body - ) - ctx.request.body = trimmedView - ctx.params.tableId = tableId + const { tableId } = utils.extractViewInfoFromID(viewId) + + // don't need to trim delete requests + if (ctx.method.toLowerCase() !== "delete") { + const { _viewId, ...trimmedView } = await trimViewFields( + viewId, + tableId, + body + ) + ctx.request.body = trimmedView + } + + ctx.params.sourceId = tableId return next() } diff --git a/packages/server/src/tests/utilities/api/row.ts b/packages/server/src/tests/utilities/api/row.ts index c7c72368f5..c6ef4606d2 100644 --- a/packages/server/src/tests/utilities/api/row.ts +++ b/packages/server/src/tests/utilities/api/row.ts @@ -1,4 +1,4 @@ -import { PatchRowRequest } from "@budibase/types" +import { PatchRowRequest, SaveRowRequest, Row } from "@budibase/types" import TestConfiguration from "../TestConfiguration" import { TestAPI } from "./base" @@ -8,12 +8,12 @@ export class RowAPI extends TestAPI { } get = async ( - tableId: string, + sourceId: string, rowId: string, { expectStatus } = { expectStatus: 200 } ) => { const request = this.request - .get(`/api/${tableId}/rows/${rowId}`) + .get(`/api/${sourceId}/rows/${rowId}`) .set(this.config.defaultHeaders()) .expect(expectStatus) if (expectStatus !== 404) { @@ -22,16 +22,43 @@ export class RowAPI extends TestAPI { return request } + save = async ( + sourceId: string, + row: SaveRowRequest, + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const resp = await this.request + .post(`/api/${sourceId}/rows`) + .send(row) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(expectStatus) + return resp.body as Row + } + patch = async ( - tableId: string, + sourceId: string, row: PatchRowRequest, { expectStatus } = { expectStatus: 200 } ) => { return this.request - .patch(`/api/${tableId}/rows`) + .patch(`/api/${sourceId}/rows`) .send(row) .set(this.config.defaultHeaders()) .expect("Content-Type", /json/) .expect(expectStatus) } + + delete = async ( + sourceId: string, + rows: Row[], + { expectStatus } = { expectStatus: 200 } + ) => { + return this.request + .delete(`/api/${sourceId}/rows`) + .send({ rows }) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(expectStatus) + } } diff --git a/packages/server/src/tests/utilities/api/viewV2.ts b/packages/server/src/tests/utilities/api/viewV2.ts index 813d2ebfd1..1520154641 100644 --- a/packages/server/src/tests/utilities/api/viewV2.ts +++ b/packages/server/src/tests/utilities/api/viewV2.ts @@ -1,10 +1,6 @@ import { CreateViewRequest, UpdateViewRequest, - DeleteRowRequest, - PatchRowRequest, - PatchRowResponse, - Row, ViewV2, SearchViewRowRequest, } from "@budibase/types" @@ -90,46 +86,4 @@ export class ViewV2API extends TestAPI { .expect("Content-Type", /json/) .expect(expectStatus) } - - row = { - create: async ( - viewId: string, - row: Row, - { expectStatus } = { expectStatus: 200 } - ): Promise => { - const result = await this.request - .post(`/api/v2/views/${viewId}/rows`) - .send(row) - .set(this.config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(expectStatus) - return result.body as Row - }, - update: async ( - viewId: string, - rowId: string, - row: PatchRowRequest, - { expectStatus } = { expectStatus: 200 } - ): Promise => { - const result = await this.request - .patch(`/api/v2/views/${viewId}/rows/${rowId}`) - .send(row) - .set(this.config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(expectStatus) - return result.body as PatchRowResponse - }, - delete: async ( - viewId: string, - body: DeleteRowRequest, - { expectStatus } = { expectStatus: 200 } - ): Promise => { - const result = await this.request - .delete(`/api/v2/views/${viewId}/rows`) - .send(body) - .set(this.config.defaultHeaders()) - .expect(expectStatus) - return result.body - }, - } } diff --git a/packages/types/src/api/web/app/rows.ts b/packages/types/src/api/web/app/rows.ts index f1890ef777..2b51c7b203 100644 --- a/packages/types/src/api/web/app/rows.ts +++ b/packages/types/src/api/web/app/rows.ts @@ -1,6 +1,8 @@ import { SearchParams } from "../../../sdk" import { Row } from "../../../documents" +export interface SaveRowRequest extends Row {} + export interface PatchRowRequest extends Row { _id: string _rev: string