From 8a12523bcc59b66245ec2ce0e80d608ec7f87764 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 14:58:21 +0200 Subject: [PATCH 1/9] Add find by usermetadata test --- .../server/src/api/routes/tests/row.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 8cabdf5e0f..7ed4c7d640 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -36,6 +36,7 @@ import { generator, mocks } from "@budibase/backend-core/tests" import _, { merge } from "lodash" import * as uuid from "uuid" import { Knex } from "knex" +import { InternalTables } from "../../../db/utils" const timestamp = new Date("2023-01-26T11:48:57.597Z").toISOString() tk.freeze(timestamp) @@ -804,6 +805,23 @@ describe.each([ status: 404, }) }) + + isInternal && + it("can search row from user table", async () => { + const res = await config.api.row.get( + InternalTables.USER_METADATA, + config.userMetadataId! + ) + + expect(res).toEqual({ + ...config.getUser(), + _id: config.userMetadataId!, + _rev: expect.any(String), + roles: undefined, + roleId: "ADMIN", + tableId: InternalTables.USER_METADATA, + }) + }) }) describe("fetch", () => { From 89173be9f409e46d9a0de5b67195b1343c8acb91 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 15:03:44 +0200 Subject: [PATCH 2/9] Remove controller dependency --- packages/server/src/api/controllers/row/utils/utils.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/server/src/api/controllers/row/utils/utils.ts b/packages/server/src/api/controllers/row/utils/utils.ts index ae34034221..1a8b5c1041 100644 --- a/packages/server/src/api/controllers/row/utils/utils.ts +++ b/packages/server/src/api/controllers/row/utils/utils.ts @@ -1,5 +1,5 @@ import { InternalTables } from "../../../../db/utils" -import * as userController from "../../user" + import { context } from "@budibase/backend-core" import { Ctx, @@ -24,6 +24,7 @@ import { import sdk from "../../../../sdk" import { processStringSync } from "@budibase/string-templates" import validateJs from "validate.js" +import { getFullUser } from "../../../../utilities/users" validateJs.extend(validateJs.validators.datetime, { parse: function (value: string) { @@ -68,11 +69,7 @@ export async function findRow(ctx: UserCtx, tableId: string, rowId: string) { let row: Row // TODO remove special user case in future if (tableId === InternalTables.USER_METADATA) { - ctx.params = { - id: rowId, - } - await userController.findMetadata(ctx) - row = ctx.body + row = await getFullUser(rowId) } else { row = await db.get(rowId) } From 66a2b29ca27b91479be4bc22391c4136d54b29af Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 15:06:00 +0200 Subject: [PATCH 3/9] Clean unnecessary ctx --- packages/server/src/api/controllers/row/internal.ts | 6 +++--- packages/server/src/api/controllers/row/utils/utils.ts | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/server/src/api/controllers/row/internal.ts b/packages/server/src/api/controllers/row/internal.ts index 54d9b6a536..fe09526c33 100644 --- a/packages/server/src/api/controllers/row/internal.ts +++ b/packages/server/src/api/controllers/row/internal.ts @@ -32,7 +32,7 @@ export async function patch(ctx: UserCtx) { try { oldRow = await outputProcessing( dbTable, - await utils.findRow(ctx, tableId, inputs._id!) + await utils.findRow(tableId, inputs._id!) ) } catch (err) { if (isUserTable) { @@ -100,7 +100,7 @@ export async function find(ctx: UserCtx): Promise { const tableId = utils.getTableId(ctx), rowId = ctx.params.rowId const table = await sdk.tables.getTable(tableId) - let row = await utils.findRow(ctx, tableId, rowId) + let row = await utils.findRow(tableId, rowId) row = await outputProcessing(table, row) return row } @@ -195,7 +195,7 @@ export async function fetchEnrichedRow(ctx: UserCtx) { sdk.tables.getTable(tableId), linkRows.getLinkDocuments({ tableId, rowId, fieldName }), ]) - let row = await utils.findRow(ctx, tableId, rowId) + let row = await utils.findRow(tableId, rowId) row = await outputProcessing(table, row) const linkVals = links as LinkDocumentValue[] diff --git a/packages/server/src/api/controllers/row/utils/utils.ts b/packages/server/src/api/controllers/row/utils/utils.ts index 1a8b5c1041..911cfe8d5b 100644 --- a/packages/server/src/api/controllers/row/utils/utils.ts +++ b/packages/server/src/api/controllers/row/utils/utils.ts @@ -8,7 +8,6 @@ import { RelationshipsJson, Row, Table, - UserCtx, } from "@budibase/types" import { processDates, @@ -64,7 +63,7 @@ export async function processRelationshipFields( return row } -export async function findRow(ctx: UserCtx, tableId: string, rowId: string) { +export async function findRow(tableId: string, rowId: string) { const db = context.getAppDB() let row: Row // TODO remove special user case in future From 75609b2a9b4aa686e3542668ea8a332de37c12b8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 15:16:15 +0200 Subject: [PATCH 4/9] Move row.find to sdk --- .../src/api/controllers/row/external.ts | 27 ++-------------- .../server/src/api/controllers/row/index.ts | 7 ++-- .../src/api/controllers/row/internal.ts | 9 ------ packages/server/src/sdk/app/rows/external.ts | 17 ++++++++-- packages/server/src/sdk/app/rows/internal.ts | 32 +++++++++++++++++-- packages/server/src/sdk/app/rows/rows.ts | 4 +++ 6 files changed, 56 insertions(+), 40 deletions(-) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 601f47b511..18c88923e0 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -57,9 +57,7 @@ export async function patch(ctx: UserCtx) { throw { validation: validateResult.errors } } - const beforeRow = await sdk.rows.external.getRow(tableId, _id, { - relationships: true, - }) + const beforeRow = await sdk.rows.external.find(tableId, _id) const response = await handleRequest(Operation.UPDATE, tableId, { id: breakRowIdField(_id), @@ -69,9 +67,7 @@ export async function patch(ctx: UserCtx) { // The id might have been changed, so the refetching would fail. Recalculating the id just in case const updatedId = generateIdForRow({ ...beforeRow, ...dataToUpdate }, table) || _id - const row = await sdk.rows.external.getRow(tableId, updatedId, { - relationships: true, - }) + const row = await sdk.rows.external.find(tableId, updatedId) const [enrichedRow, oldRow] = await Promise.all([ outputProcessing(table, row, { @@ -92,25 +88,6 @@ export async function patch(ctx: UserCtx) { } } -export async function find(ctx: UserCtx): Promise { - const id = ctx.params.rowId - const tableId = utils.getTableId(ctx) - const row = await sdk.rows.external.getRow(tableId, id, { - relationships: true, - }) - - if (!row) { - ctx.throw(404) - } - - const table = await sdk.tables.getTable(tableId) - // Preserving links, as the outputProcessing does not support external rows yet and we don't need it in this use case - return await outputProcessing(table, row, { - squash: true, - preserveLinks: true, - }) -} - export async function destroy(ctx: UserCtx) { const tableId = utils.getTableId(ctx) const _id = ctx.request.body._id diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index 760b73f404..f3165f7f86 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -117,7 +117,9 @@ export async function fetch(ctx: any) { export async function find(ctx: UserCtx) { const tableId = utils.getTableId(ctx) - ctx.body = await pickApi(tableId).find(ctx) + const rowId = ctx.params.rowId + + ctx.body = await sdk.rows.find(tableId, rowId) } function isDeleteRows(input: any): input is DeleteRows { @@ -278,7 +280,8 @@ export async function downloadAttachment(ctx: UserCtx) { const { columnName } = ctx.params const tableId = utils.getTableId(ctx) - const row = await pickApi(tableId).find(ctx) + const rowId = ctx.params.rowId + const row = await sdk.rows.find(tableId, rowId) const table = await sdk.tables.getTable(tableId) const columnSchema = table.schema[columnName] diff --git a/packages/server/src/api/controllers/row/internal.ts b/packages/server/src/api/controllers/row/internal.ts index fe09526c33..b2982a3542 100644 --- a/packages/server/src/api/controllers/row/internal.ts +++ b/packages/server/src/api/controllers/row/internal.ts @@ -96,15 +96,6 @@ export async function patch(ctx: UserCtx) { return { ...result, oldRow } } -export async function find(ctx: UserCtx): Promise { - const tableId = utils.getTableId(ctx), - rowId = ctx.params.rowId - const table = await sdk.tables.getTable(tableId) - let row = await utils.findRow(tableId, rowId) - row = await outputProcessing(table, row) - return row -} - export async function destroy(ctx: UserCtx) { const db = context.getAppDB() const tableId = utils.getTableId(ctx) diff --git a/packages/server/src/sdk/app/rows/external.ts b/packages/server/src/sdk/app/rows/external.ts index 7ad5ea37ff..dc1e368f41 100644 --- a/packages/server/src/sdk/app/rows/external.ts +++ b/packages/server/src/sdk/app/rows/external.ts @@ -9,7 +9,7 @@ import { import cloneDeep from "lodash/fp/cloneDeep" import isEqual from "lodash/fp/isEqual" -export async function getRow( +async function getRow( tableId: string, rowId: string, opts?: { relationships?: boolean } @@ -53,7 +53,7 @@ export async function save( const rowId = response.row._id if (rowId) { - const row = await sdk.rows.external.getRow(tableId, rowId, { + const row = await getRow(tableId, rowId, { relationships: true, }) return { @@ -67,3 +67,16 @@ export async function save( return response } } + +export async function find(tableId: string, rowId: string): Promise { + const row = await getRow(tableId, rowId, { + relationships: true, + }) + + const table = await sdk.tables.getTable(tableId) + // Preserving links, as the outputProcessing does not support external rows yet and we don't need it in this use case + return await outputProcessing(table, row, { + squash: true, + preserveLinks: true, + }) +} diff --git a/packages/server/src/sdk/app/rows/internal.ts b/packages/server/src/sdk/app/rows/internal.ts index 14e771b36e..c21d3465a7 100644 --- a/packages/server/src/sdk/app/rows/internal.ts +++ b/packages/server/src/sdk/app/rows/internal.ts @@ -1,10 +1,15 @@ -import { db } from "@budibase/backend-core" +import { context, db } from "@budibase/backend-core" import { Row } from "@budibase/types" import sdk from "../../../sdk" import cloneDeep from "lodash/fp/cloneDeep" import { finaliseRow } from "../../../api/controllers/row/staticFormula" -import { inputProcessing } from "../../../utilities/rowProcessor" +import { + inputProcessing, + outputProcessing, +} from "../../../utilities/rowProcessor" import * as linkRows from "../../../db/linkedRows" +import { InternalTables } from "../../../db/utils" +import { getFullUser } from "../../../utilities/users" export async function save( tableId: string, @@ -47,3 +52,26 @@ export async function save( updateFormula: true, }) } + +export async function find(tableId: string, rowId: string): Promise { + const table = await sdk.tables.getTable(tableId) + let row = await findRow(tableId, rowId) + + row = await outputProcessing(table, row) + return row +} + +async function findRow(tableId: string, rowId: string) { + const db = context.getAppDB() + let row: Row + // TODO remove special user case in future + if (tableId === InternalTables.USER_METADATA) { + row = await getFullUser(rowId) + } else { + row = await db.get(rowId) + } + if (row.tableId !== tableId) { + throw "Supplied tableId does not match the rows tableId" + } + return row +} diff --git a/packages/server/src/sdk/app/rows/rows.ts b/packages/server/src/sdk/app/rows/rows.ts index bfd84a715c..ef03210800 100644 --- a/packages/server/src/sdk/app/rows/rows.ts +++ b/packages/server/src/sdk/app/rows/rows.ts @@ -34,3 +34,7 @@ export async function save( ) { return pickApi(tableId).save(tableId, row, userId) } + +export async function find(tableId: string, rowId: string) { + return pickApi(tableId).find(tableId, rowId) +} From 41698420180a0984e8c97622cb25b6db9be62d76 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 15:22:26 +0200 Subject: [PATCH 5/9] Fix get --- packages/server/src/api/controllers/row/external.ts | 8 ++++++-- packages/server/src/sdk/app/rows/external.ts | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 18c88923e0..06013d230c 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -57,7 +57,9 @@ export async function patch(ctx: UserCtx) { throw { validation: validateResult.errors } } - const beforeRow = await sdk.rows.external.find(tableId, _id) + const beforeRow = await sdk.rows.external.getRow(tableId, _id, { + relationships: true, + }) const response = await handleRequest(Operation.UPDATE, tableId, { id: breakRowIdField(_id), @@ -67,7 +69,9 @@ export async function patch(ctx: UserCtx) { // The id might have been changed, so the refetching would fail. Recalculating the id just in case const updatedId = generateIdForRow({ ...beforeRow, ...dataToUpdate }, table) || _id - const row = await sdk.rows.external.find(tableId, updatedId) + const row = await sdk.rows.external.getRow(tableId, updatedId, { + relationships: true, + }) const [enrichedRow, oldRow] = await Promise.all([ outputProcessing(table, row, { diff --git a/packages/server/src/sdk/app/rows/external.ts b/packages/server/src/sdk/app/rows/external.ts index dc1e368f41..7cf28300ed 100644 --- a/packages/server/src/sdk/app/rows/external.ts +++ b/packages/server/src/sdk/app/rows/external.ts @@ -9,7 +9,7 @@ import { import cloneDeep from "lodash/fp/cloneDeep" import isEqual from "lodash/fp/isEqual" -async function getRow( +export async function getRow( tableId: string, rowId: string, opts?: { relationships?: boolean } From 8a8633b43b981d54b904990c2de34eeeb687c435 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 23 Jul 2024 15:27:35 +0200 Subject: [PATCH 6/9] Fix throwing 404 --- packages/server/src/sdk/app/rows/external.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/server/src/sdk/app/rows/external.ts b/packages/server/src/sdk/app/rows/external.ts index 7cf28300ed..9ab1362606 100644 --- a/packages/server/src/sdk/app/rows/external.ts +++ b/packages/server/src/sdk/app/rows/external.ts @@ -1,4 +1,5 @@ import { IncludeRelationship, Operation, Row } from "@budibase/types" +import { HTTPError } from "@budibase/backend-core" import { handleRequest } from "../../../api/controllers/row/external" import { breakRowIdField } from "../../../integrations/utils" import sdk from "../../../sdk" @@ -73,6 +74,10 @@ export async function find(tableId: string, rowId: string): Promise { relationships: true, }) + if (!row) { + throw new HTTPError("Row not found", 404) + } + const table = await sdk.tables.getTable(tableId) // Preserving links, as the outputProcessing does not support external rows yet and we don't need it in this use case return await outputProcessing(table, row, { From 932c331076a5d0d0fbe3a32e66433f5b493c01dc Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 24 Jul 2024 13:21:22 +0200 Subject: [PATCH 7/9] NX affected config --- nx.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/nx.json b/nx.json index 54db3a24a3..fb05ea94d0 100644 --- a/nx.json +++ b/nx.json @@ -10,7 +10,18 @@ }, "targetDefaults": { "build": { - "inputs": ["{workspaceRoot}/scripts/*", "{workspaceRoot}/lerna.json"] + "inputs": [ + "{workspaceRoot}/scripts/*", + "{workspaceRoot}/lerna.json", + "{workspaceRoot}/.github/workflows/*" + ] + }, + "test": { + "inputs": [ + "{workspaceRoot}/scripts/*", + "{workspaceRoot}/lerna.json", + "{workspaceRoot}/.github/workflows/*" + ] } }, "namedInputs": { From 82c8be5f55eed0ebdb1fb5d07781564835949cdf Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 24 Jul 2024 14:49:23 +0200 Subject: [PATCH 8/9] Fix mssql testcontaint wait strategy --- packages/server/src/integrations/tests/utils/mssql.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/integrations/tests/utils/mssql.ts b/packages/server/src/integrations/tests/utils/mssql.ts index a4bd5448f4..2a4af48725 100644 --- a/packages/server/src/integrations/tests/utils/mssql.ts +++ b/packages/server/src/integrations/tests/utils/mssql.ts @@ -22,7 +22,7 @@ export async function getDatasource(): Promise { }) .withWaitStrategy( Wait.forSuccessfulCommand( - "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" + "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" ) ) ) From 89b57701557bc9bcc8d4c6e07e3cc3aee0c576eb Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 24 Jul 2024 15:22:37 +0200 Subject: [PATCH 9/9] Change image --- .github/workflows/budibase_ci.yml | 2 +- packages/server/src/integrations/tests/utils/mssql.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index d63596f08f..1bc1915a71 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -164,7 +164,7 @@ jobs: - name: Pull testcontainers images run: | - docker pull mcr.microsoft.com/mssql/server:2022-latest & + docker pull mcr.microsoft.com/mssql/server:2022-CU13-ubuntu-22.04 & docker pull mysql:8.3 & docker pull postgres:16.1-bullseye & docker pull mongo:7.0-jammy & diff --git a/packages/server/src/integrations/tests/utils/mssql.ts b/packages/server/src/integrations/tests/utils/mssql.ts index 2a4af48725..ed94477814 100644 --- a/packages/server/src/integrations/tests/utils/mssql.ts +++ b/packages/server/src/integrations/tests/utils/mssql.ts @@ -9,7 +9,9 @@ let ports: Promise export async function getDatasource(): Promise { if (!ports) { ports = startContainer( - new GenericContainer("mcr.microsoft.com/mssql/server:2022-latest") + new GenericContainer( + "mcr.microsoft.com/mssql/server:2022-CU13-ubuntu-22.04" + ) .withExposedPorts(1433) .withEnvironment({ ACCEPT_EULA: "Y", @@ -22,7 +24,7 @@ export async function getDatasource(): Promise { }) .withWaitStrategy( Wait.forSuccessfulCommand( - "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" + "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Password_123 -q 'SELECT 1'" ) ) )