From 5365de6a8dd080f0da256862c5665be942624aba Mon Sep 17 00:00:00 2001 From: Dean Date: Tue, 29 Aug 2023 09:19:11 +0100 Subject: [PATCH 001/128] POC --- .../Component/ComponentSettingsPanel.svelte | 34 ++++++++++++++++--- .../context/DeviceBindingsProvider.svelte | 6 ++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte index 2ff605cc77..4d87619013 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte @@ -1,6 +1,11 @@ @@ -192,6 +221,13 @@ > Edit column + + Duplicate column + { + console.log("start", $focusedCellAPI, $focusedCellAPI.isReadonly()) if ($focusedCellAPI && !$focusedCellAPI.isReadonly()) { const type = $focusedCellAPI.getType() + console.log(type) if (type === "number" && keyCodeIsNumber(keyCode)) { // Update the value locally but don't save it yet $focusedCellAPI.setValue(parseInt(key), { save: false }) From 32108abbc0e6064176d7e3798a93041370f159a2 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 6 Sep 2023 16:59:30 +0100 Subject: [PATCH 018/128] Remove logs --- .../frontend-core/src/components/grid/cells/DataCell.svelte | 5 +---- .../src/components/grid/overlays/KeyboardManager.svelte | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/frontend-core/src/components/grid/cells/DataCell.svelte b/packages/frontend-core/src/components/grid/cells/DataCell.svelte index daf0a03276..19bdf1bd74 100644 --- a/packages/frontend-core/src/components/grid/cells/DataCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/DataCell.svelte @@ -56,10 +56,7 @@ isActive: () => api?.isActive?.() ?? false, onKeyDown: (...params) => api?.onKeyDown(...params), isReadonly: () => readonly, - getType: () => { - console.log("getType", column) - return column.schema.type - }, + getType: () => column.schema.type, getValue: () => row[column.name], setValue: (value, options = { save: true }) => { validation.actions.setError(cellId, null) diff --git a/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte b/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte index 3232f23e76..cd23f154b5 100644 --- a/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte +++ b/packages/frontend-core/src/components/grid/overlays/KeyboardManager.svelte @@ -212,10 +212,8 @@ // Focuses the cell and starts entering a new value const startEnteringValue = (key, keyCode) => { - console.log("start", $focusedCellAPI, $focusedCellAPI.isReadonly()) if ($focusedCellAPI && !$focusedCellAPI.isReadonly()) { const type = $focusedCellAPI.getType() - console.log(type) if (type === "number" && keyCodeIsNumber(keyCode)) { // Update the value locally but don't save it yet $focusedCellAPI.setValue(parseInt(key), { save: false }) From 3fb67ffe4feda02b1e45d655f61388ed487367c4 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 7 Sep 2023 10:42:07 +0100 Subject: [PATCH 019/128] Updating pro reference checking to work for master branch. --- .github/workflows/budibase_ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 3e4b2221d2..66fbd7abb2 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -225,10 +225,12 @@ jobs: echo "Running on branch '$branch' (base_ref=${{ github.base_ref }}, ref_name=${{ github.head_ref }})" if [[ $branch == "master" ]]; then - base_commit=$(git rev-parse origin/master) + base_branch=master else - base_commit=$(git rev-parse origin/develop) + base_branch=develop fi + git fetch origin $base_branch + base_commit=$(git rev-parse $base_branch) echo "target_branch=$branch" echo "target_branch=$branch" >> "$GITHUB_OUTPUT" From ef9c0f7f042876ffed772008830f3c287a1d4ca0 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 7 Sep 2023 10:46:02 +0100 Subject: [PATCH 020/128] Pure git fetch for checking pro ref. --- .github/workflows/budibase_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 66fbd7abb2..579f656301 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -229,7 +229,7 @@ jobs: else base_branch=develop fi - git fetch origin $base_branch + git fetch base_commit=$(git rev-parse $base_branch) echo "target_branch=$branch" From f17a0acb17c335bda163748339b5c02fb6f7797c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 7 Sep 2023 10:48:08 +0100 Subject: [PATCH 021/128] Better logging. --- .github/workflows/budibase_ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 579f656301..4db4b3064c 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -229,7 +229,9 @@ jobs: else base_branch=develop fi + echo "Running git fetch" git fetch + echo "Running git rev-parse $base_branch" base_commit=$(git rev-parse $base_branch) echo "target_branch=$branch" From 25287173e25b0715215132c7b5774b38a50ebf18 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 7 Sep 2023 10:59:29 +0100 Subject: [PATCH 022/128] Switching to fetch-depth 0. --- .github/workflows/budibase_ci.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 4db4b3064c..d670e222d3 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -214,6 +214,7 @@ jobs: with: submodules: true token: ${{ secrets.PERSONAL_ACCESS_TOKEN || github.token }} + fetch-depth: 0 - name: Check pro commit id: get_pro_commits @@ -225,14 +226,10 @@ jobs: echo "Running on branch '$branch' (base_ref=${{ github.base_ref }}, ref_name=${{ github.head_ref }})" if [[ $branch == "master" ]]; then - base_branch=master + base_commit=$(git rev-parse origin/master) else - base_branch=develop + base_commit=$(git rev-parse origin/develop) fi - echo "Running git fetch" - git fetch - echo "Running git rev-parse $base_branch" - base_commit=$(git rev-parse $base_branch) echo "target_branch=$branch" echo "target_branch=$branch" >> "$GITHUB_OUTPUT" @@ -255,4 +252,4 @@ jobs: process.exit(1); } else { console.log('All good, the submodule had been merged and setup correctly!') - } + } \ No newline at end of file From ee396b983b3637d1cf21d8a29e1d8ebd183e9cd8 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 7 Sep 2023 11:29:18 +0000 Subject: [PATCH 023/128] Bump version to 2.9.39 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index a662b691ed..9c5cd65aa0 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.9.39-alpha.14", + "version": "2.9.39", "npmClient": "yarn", "packages": [ "packages/*" From 10e3cccb9f2bb004840f5c60f8bd111338d6609e Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 7 Sep 2023 13:33:53 +0000 Subject: [PATCH 024/128] Bump version to 2.10.0 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 9c5cd65aa0..fd2bdb2f65 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.9.39", + "version": "2.10.0", "npmClient": "yarn", "packages": [ "packages/*" From 662e8d9c31c168bb7ea3953c90c870d901490e76 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 7 Sep 2023 17:02:11 +0100 Subject: [PATCH 025/128] Quick fix for disabling formula changing, swapping between static and dynamic can cause problems. --- .../backend/DataTable/modals/CreateEditColumn.svelte | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index fdfbff7b14..fd13767a63 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -55,7 +55,7 @@ let linkEditDisabled let primaryDisplay let indexes = [...($tables.selected.indexes || [])] - let isCreating + let isCreating = undefined let table = $tables.selected let confirmDeleteDialog @@ -75,11 +75,11 @@ } const initialiseField = (field, savingColumn) => { + isCreating = !field if (field && !savingColumn) { editableColumn = cloneDeep(field) originalName = editableColumn.name ? editableColumn.name + "" : null linkEditDisabled = originalName != null - isCreating = originalName == null primaryDisplay = $tables.selected.primaryDisplay == null || $tables.selected.primaryDisplay === editableColumn.name @@ -584,6 +584,7 @@ { label: "Dynamic", value: "dynamic" }, { label: "Static", value: "static" }, ]} + disabled={!isCreating} getOptionLabel={option => option.label} getOptionValue={option => option.value} tooltip="Dynamic formula are calculated when retrieved, but cannot be filtered or sorted by, From ab5753273ddebb9f7f68b538e517162f26bb88ef Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 7 Sep 2023 18:50:07 +0100 Subject: [PATCH 026/128] fix for legacy custom roles --- packages/server/src/sdk/app/permissions/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/sdk/app/permissions/index.ts b/packages/server/src/sdk/app/permissions/index.ts index b79bfeeb31..b2661b0f7e 100644 --- a/packages/server/src/sdk/app/permissions/index.ts +++ b/packages/server/src/sdk/app/permissions/index.ts @@ -92,7 +92,7 @@ export async function getResourcePerms( // update the various roleIds in the resource permissions for (let role of rolesList) { const rolePerms = allowsExplicitPerm - ? roles.checkForRoleResourceArray(role.permissions, resourceId) + ? roles.checkForRoleResourceArray(role.permissions || {}, resourceId) : {} if (rolePerms[resourceId]?.indexOf(level) > -1) { permissions[level] = { From b74814906851bed6853ccccf438a0c5e65bb91e1 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 7 Sep 2023 19:06:58 +0100 Subject: [PATCH 027/128] fix for app backups not being shown --- packages/builder/src/stores/portal/licensing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/stores/portal/licensing.js b/packages/builder/src/stores/portal/licensing.js index 795616add1..3197822e53 100644 --- a/packages/builder/src/stores/portal/licensing.js +++ b/packages/builder/src/stores/portal/licensing.js @@ -107,7 +107,7 @@ export const createLicensingStore = () => { Constants.Features.USER_GROUPS ) const backupsEnabled = license.features.includes( - Constants.Features.BACKUPS + Constants.Features.APP_BACKUPS ) const scimEnabled = license.features.includes(Constants.Features.SCIM) const environmentVariablesEnabled = license.features.includes( From 3cec62b0c7672392a00f1ef4a014329cf03dad4f Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 7 Sep 2023 18:21:05 +0000 Subject: [PATCH 028/128] Bump version to 2.10.1 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index fd2bdb2f65..a346d18213 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.0", + "version": "2.10.1", "npmClient": "yarn", "packages": [ "packages/*" From 3c46d66333713671c0d144b92ba908deb1bb3077 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 09:25:19 +0200 Subject: [PATCH 029/128] yarn.lock --- yarn.lock | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/yarn.lock b/yarn.lock index ab86a87560..8c93661665 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6269,6 +6269,14 @@ "@types/tedious" "*" tarn "^3.0.1" +"@types/node-fetch@2.6.1": + version "2.6.1" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975" + integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node-fetch@2.6.4": version "2.6.4" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" @@ -6290,6 +6298,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== +"@types/node@14.18.20": + version "14.18.20" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.20.tgz#268f028b36eaf51181c3300252f605488c4f0650" + integrity sha512-Q8KKwm9YqEmUBRsqJ2GWJDtXltBDxTdC4m5vTdXBolu2PeQh8LX+f6BTwU+OuXPu37fLxoN6gidqBmnky36FXA== + "@types/node@16.9.1": version "16.9.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" From c6621e8c495d518a1d3825ec302b62441c88d202 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 10:04:35 +0200 Subject: [PATCH 030/128] Type response --- packages/server/src/api/controllers/row/external.ts | 2 +- packages/server/src/api/controllers/row/index.ts | 3 ++- packages/server/src/api/controllers/row/internal.ts | 2 +- packages/server/src/api/controllers/row/utils.ts | 2 +- packages/types/src/api/web/app/row.ts | 2 ++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 491cbfa8f9..5a78b55ca7 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -106,7 +106,7 @@ export async function save(ctx: UserCtx) { } } -export async function find(ctx: UserCtx) { +export async function find(ctx: UserCtx): Promise { const id = ctx.params.rowId const tableId = utils.getTableId(ctx) return sdk.rows.external.getRow(tableId, id) diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index 88d3f50dbe..0bc3c4d3c7 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -14,6 +14,7 @@ import { SearchRowResponse, SearchRowRequest, SearchParams, + GetRowResponse, } from "@budibase/types" import * as utils from "./utils" import { gridSocket } from "../../../websockets" @@ -111,7 +112,7 @@ export async function fetch(ctx: any) { }) } -export async function find(ctx: any) { +export async function find(ctx: UserCtx) { const tableId = utils.getTableId(ctx) ctx.body = await quotas.addQuery(() => pickApi(tableId).find(ctx), { datasourceId: tableId, diff --git a/packages/server/src/api/controllers/row/internal.ts b/packages/server/src/api/controllers/row/internal.ts index 4a412c42eb..b80bd339e6 100644 --- a/packages/server/src/api/controllers/row/internal.ts +++ b/packages/server/src/api/controllers/row/internal.ts @@ -131,7 +131,7 @@ export async function save(ctx: UserCtx) { }) } -export async function find(ctx: UserCtx) { +export async function find(ctx: UserCtx): Promise { const tableId = utils.getTableId(ctx), rowId = ctx.params.rowId const table = await sdk.tables.getTable(tableId) diff --git a/packages/server/src/api/controllers/row/utils.ts b/packages/server/src/api/controllers/row/utils.ts index e85ec4553c..c1df80600c 100644 --- a/packages/server/src/api/controllers/row/utils.ts +++ b/packages/server/src/api/controllers/row/utils.ts @@ -27,7 +27,7 @@ validateJs.extend(validateJs.validators.datetime, { export async function findRow(ctx: UserCtx, tableId: string, rowId: string) { const db = context.getAppDB() - let row + let row: Row // TODO remove special user case in future if (tableId === InternalTables.USER_METADATA) { ctx.params = { diff --git a/packages/types/src/api/web/app/row.ts b/packages/types/src/api/web/app/row.ts index f9623a3daf..6e051facae 100644 --- a/packages/types/src/api/web/app/row.ts +++ b/packages/types/src/api/web/app/row.ts @@ -1,5 +1,7 @@ import { Row } from "../../../documents/app/row" +export interface GetRowResponse extends Row {} + export interface DeleteRows { rows: (Row | string)[] } From f8adbb86a0e19d228629d4e1ce231a15412e51e7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 10:04:49 +0200 Subject: [PATCH 031/128] Fix tests --- .../src/api/controllers/row/external.ts | 8 +++- .../server/src/api/routes/tests/row.spec.ts | 37 ++++++++++++------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 5a78b55ca7..5a1c7e04ff 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -109,7 +109,13 @@ export async function save(ctx: UserCtx) { export async function find(ctx: UserCtx): Promise { const id = ctx.params.rowId const tableId = utils.getTableId(ctx) - return sdk.rows.external.getRow(tableId, id) + const row = await sdk.rows.external.getRow(tableId, id) + + if (!row) { + ctx.throw(404) + } + + return row } export async function destroy(ctx: UserCtx) { diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 9c150d8968..821842e1b4 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -12,6 +12,7 @@ import { PermissionLevel, QuotaUsageType, Row, + SaveRowRequest, SaveTableRequest, SortOrder, SortType, @@ -34,6 +35,8 @@ describe.each([ ["internal", undefined], ["postgres", databaseTestProviders.postgres], ])("/rows (%s)", (_, dsProvider) => { + const isInternal = !dsProvider + let request = setup.getRequest() let config = setup.getConfig() let table: Table @@ -127,9 +130,20 @@ describe.each([ expect(usage).toBe(expected) } - const createRow = () => config.api.row.save(table._id!, basicRow(table._id!)) + const createRow = (row?: SaveRowRequest) => + config.api.row.save(table._id!, row || basicRow(table._id!)) describe("save, load, update", () => { + function getDefaultFields() { + if (isInternal) { + return { + type: "row", + createdAt: timestamp, + updatedAt: timestamp, + } + } + } + it("returns a success message when the row is created", async () => { const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -230,7 +244,7 @@ describe.each([ }) it("should load a row", async () => { - const existing = await config.createRow() + const existing = await createRow() const queryUsage = await getQueryUsage() const res = await request @@ -243,9 +257,8 @@ describe.each([ ...row, _id: existing._id, _rev: existing._rev, - type: "row", - createdAt: timestamp, - updatedAt: timestamp, + id: existing.id, + ...getDefaultFields(), }) await assertQueryUsage(queryUsage + 1) }) @@ -256,8 +269,8 @@ describe.each([ name: "Second Contact", status: "new", } - await config.createRow() - await config.createRow(newRow) + await createRow() + await createRow(newRow) const queryUsage = await getQueryUsage() const res = await request @@ -273,14 +286,12 @@ describe.each([ }) it("load should return 404 when row does not exist", async () => { - await config.createRow() + await createRow() const queryUsage = await getQueryUsage() - await request - .get(`/api/${table._id}/rows/not-a-valid-id`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(404) + await config.api.row.get(table._id!, "1234567", { + expectStatus: 404, + }) await assertQueryUsage(queryUsage) // no change }) From 2c6df7475547a33677554dc93ab6e7de28c0a877 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 10:12:46 +0200 Subject: [PATCH 032/128] Fix more tests --- packages/server/src/api/routes/tests/row.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 821842e1b4..14b59e24c1 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -503,7 +503,7 @@ describe.each([ describe("patch", () => { it("should update only the fields that are supplied", async () => { - const existing = await config.createRow() + const existing = await createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -530,7 +530,7 @@ describe.each([ }) it("should throw an error when given improper types", async () => { - const existing = await config.createRow() + const existing = await createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -552,7 +552,7 @@ describe.each([ describe("destroy", () => { it("should be able to delete a row", async () => { - const createdRow = await config.createRow(row) + const createdRow = await createRow(row) const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() From 93124d804bed15b313a6c4563dda9c11f9348e8c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 10:17:22 +0200 Subject: [PATCH 033/128] Fix validate test --- packages/server/src/api/controllers/row/index.ts | 5 +++-- packages/types/src/api/web/app/row.ts | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index 0bc3c4d3c7..e86b466601 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -15,6 +15,7 @@ import { SearchRowRequest, SearchParams, GetRowResponse, + ValidateResponse, } from "@budibase/types" import * as utils from "./utils" import { gridSocket } from "../../../websockets" @@ -215,11 +216,11 @@ export async function search(ctx: Ctx) { }) } -export async function validate(ctx: Ctx) { +export async function validate(ctx: Ctx) { const tableId = utils.getTableId(ctx) // external tables are hard to validate currently if (isExternalTable(tableId)) { - ctx.body = { valid: true } + ctx.body = { valid: true, errors: {} } } else { ctx.body = await sdk.rows.utils.validate({ row: ctx.request.body, diff --git a/packages/types/src/api/web/app/row.ts b/packages/types/src/api/web/app/row.ts index 6e051facae..4ab4090461 100644 --- a/packages/types/src/api/web/app/row.ts +++ b/packages/types/src/api/web/app/row.ts @@ -11,3 +11,8 @@ export interface DeleteRow { } export type DeleteRowRequest = DeleteRows | DeleteRow + +export interface ValidateResponse { + valid: boolean + errors: Record +} From 3912517f6733e27ba293a695b83f785c6caa411a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 10:22:24 +0200 Subject: [PATCH 034/128] Do not validate external --- packages/server/src/api/routes/tests/row.spec.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 14b59e24c1..ab61a480f3 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -599,8 +599,14 @@ describe.each([ .expect("Content-Type", /json/) .expect(200) - expect(res.body.valid).toBe(false) - expect(Object.keys(res.body.errors)).toEqual(["name"]) + if (isInternal) { + expect(res.body.valid).toBe(false) + expect(Object.keys(res.body.errors)).toEqual(["name"]) + } else { + // Validation for external is not implemented, so it will always return valid + expect(res.body.valid).toBe(true) + expect(Object.keys(res.body.errors)).toEqual([]) + } await assertRowUsage(rowUsage) await assertQueryUsage(queryUsage) }) From 93e9b1b8b4d7f4e24df169b8ab33c2929dcfde52 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 10:34:45 +0200 Subject: [PATCH 035/128] Fix tests --- packages/server/src/api/controllers/row/external.ts | 2 +- packages/server/src/api/routes/tests/row.spec.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 5a1c7e04ff..44d50886d3 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -125,7 +125,7 @@ export async function destroy(ctx: UserCtx) { id: breakRowIdField(_id), includeSqlRelationships: IncludeRelationship.EXCLUDE, })) as { row: Row } - return { response: { ok: true }, row } + return { response: { ok: true, id: _id }, row } } export async function bulkDestroy(ctx: UserCtx) { diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index ab61a480f3..ae28c14279 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -614,8 +614,8 @@ describe.each([ describe("bulkDelete", () => { it("should be able to delete a bulk set of rows", async () => { - const row1 = await config.createRow() - const row2 = await config.createRow() + const row1 = await createRow() + const row2 = await createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -635,9 +635,9 @@ describe.each([ }) it("should be able to delete a variety of row set types", async () => { - const row1 = await config.createRow() - const row2 = await config.createRow() - const row3 = await config.createRow() + const row1 = await createRow() + const row2 = await createRow() + const row3 = await createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -657,7 +657,7 @@ describe.each([ }) it("should accept a valid row object and delete the row", async () => { - const row1 = await config.createRow() + const row1 = await createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() From 9e799c6b933eb6e582a53b5e021498cf8c83f6ae Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 10:43:19 +0200 Subject: [PATCH 036/128] Legacy views tests --- .../server/src/api/routes/tests/row.spec.ts | 99 ++++++++++--------- .../src/tests/utilities/TestConfiguration.ts | 7 +- 2 files changed, 57 insertions(+), 49 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index ae28c14279..0fab8eb426 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -710,55 +710,62 @@ describe.each([ }) }) - describe("fetchView", () => { - it("should be able to fetch tables contents via 'view'", async () => { - const row = await config.createRow() - const rowUsage = await getRowUsage() - const queryUsage = await getQueryUsage() + // Legacy views are not available for external + isInternal && + describe("fetchView", () => { + it("should be able to fetch tables contents via 'view'", async () => { + const row = await createRow() + const rowUsage = await getRowUsage() + const queryUsage = await getQueryUsage() - const res = await request - .get(`/api/views/${table._id}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body.length).toEqual(1) - expect(res.body[0]._id).toEqual(row._id) - await assertRowUsage(rowUsage) - await assertQueryUsage(queryUsage + 1) + const res = await request + .get(`/api/views/${table._id}`) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(res.body.length).toEqual(1) + expect(res.body[0]._id).toEqual(row._id) + await assertRowUsage(rowUsage) + await assertQueryUsage(queryUsage + 1) + }) + + it("should throw an error if view doesn't exist", async () => { + const rowUsage = await getRowUsage() + const queryUsage = await getQueryUsage() + + await request + .get(`/api/views/derp`) + .set(config.defaultHeaders()) + .expect(404) + + await assertRowUsage(rowUsage) + await assertQueryUsage(queryUsage) + }) + + it("should be able to run on a view", async () => { + const view = await config.createLegacyView({ + tableId: table._id!, + name: "ViewTest", + filters: [], + schema: {}, + }) + const row = await createRow() + const rowUsage = await getRowUsage() + const queryUsage = await getQueryUsage() + + const res = await request + .get(`/api/views/${view.name}`) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(res.body.length).toEqual(1) + expect(res.body[0]._id).toEqual(row._id) + + await assertRowUsage(rowUsage) + await assertQueryUsage(queryUsage + 1) + }) }) - it("should throw an error if view doesn't exist", async () => { - const rowUsage = await getRowUsage() - const queryUsage = await getQueryUsage() - - await request - .get(`/api/views/derp`) - .set(config.defaultHeaders()) - .expect(404) - - await assertRowUsage(rowUsage) - await assertQueryUsage(queryUsage) - }) - - it("should be able to run on a view", async () => { - const view = await config.createLegacyView() - const row = await config.createRow() - const rowUsage = await getRowUsage() - const queryUsage = await getQueryUsage() - - const res = await request - .get(`/api/views/${view.name}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect(res.body.length).toEqual(1) - expect(res.body[0]._id).toEqual(row._id) - - await assertRowUsage(rowUsage) - await assertQueryUsage(queryUsage + 1) - }) - }) - describe("fetchEnrichedRows", () => { it("should allow enriching some linked rows", async () => { const { table, firstRow, secondRow } = await tenancy.doInTenant( diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index e835779f93..72a8b9a146 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -50,6 +50,7 @@ import { SearchFilters, UserRoles, Automation, + View, } from "@budibase/types" import API from "./api" @@ -629,12 +630,12 @@ class TestConfiguration { // VIEW - async createLegacyView(config?: any) { - if (!this.table) { + async createLegacyView(config?: View) { + if (!this.table && !config) { throw "Test requires table to be configured." } const view = config || { - tableId: this.table._id, + tableId: this.table!._id, name: "ViewTest", } return this._req(view, null, controllers.view.v1.save) From 5e2e43a7d7e342014d97010ee723d6b23848f6f7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 13:52:17 +0200 Subject: [PATCH 037/128] Clean configs --- .../server/src/api/routes/tests/row.spec.ts | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 0fab8eb426..d572097469 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -49,37 +49,39 @@ describe.each([ await config.init() }) - beforeEach(async () => { - mocks.licenses.useCloudFree() - let tableConfig: SaveTableRequest = { - name: generator.guid(), - type: "table", - primary: ["id"], - schema: { - id: { - type: FieldType.AUTO, - name: "id", - autocolumn: true, - constraints: { - presence: true, - }, - }, - name: { - type: FieldType.STRING, - name: "name", - constraints: { - type: "string", - }, - }, - description: { - type: FieldType.STRING, - name: "description", - constraints: { - type: "string", - }, + const generateTableConfig: () => SaveTableRequest = () => ({ + name: generator.guid(), + type: "table", + primary: ["id"], + schema: { + id: { + type: FieldType.AUTO, + name: "id", + autocolumn: true, + constraints: { + presence: true, }, }, - } + name: { + type: FieldType.STRING, + name: "name", + constraints: { + type: "string", + }, + }, + description: { + type: FieldType.STRING, + name: "description", + constraints: { + type: "string", + }, + }, + }, + }) + + beforeEach(async () => { + mocks.licenses.useCloudFree() + const tableConfig = generateTableConfig() if (dsProvider) { datasource = await config.api.datasource.create( @@ -93,6 +95,8 @@ describe.each([ } table = await config.api.table.create(tableConfig) + config.table = table + config.datasource = datasource row = basicRow(table._id!) }) @@ -130,8 +134,8 @@ describe.each([ expect(usage).toBe(expected) } - const createRow = (row?: SaveRowRequest) => - config.api.row.save(table._id!, row || basicRow(table._id!)) + const createRow = (tableId = table._id!, row?: SaveRowRequest) => + config.api.row.save(tableId, row || basicRow(table._id!)) describe("save, load, update", () => { function getDefaultFields() { @@ -270,7 +274,7 @@ describe.each([ status: "new", } await createRow() - await createRow(newRow) + await createRow(table._id, newRow) const queryUsage = await getQueryUsage() const res = await request @@ -552,7 +556,7 @@ describe.each([ describe("destroy", () => { it("should be able to delete a row", async () => { - const createdRow = await createRow(row) + const createdRow = await createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() From a780f85cacab6ef2dfd0612dd298093b5b431b90 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 8 Sep 2023 12:37:28 +0000 Subject: [PATCH 038/128] Bump version to 2.9.40-alpha.8 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 1725c59154..96ada475a3 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.9.40-alpha.7", + "version": "2.9.40-alpha.8", "npmClient": "yarn", "packages": [ "packages/*" From 9b783e0804763554f949da4ed4dac85a804395a5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 15:08:49 +0200 Subject: [PATCH 039/128] Fix cleanup relationships --- .../server/src/api/controllers/table/external.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/server/src/api/controllers/table/external.ts b/packages/server/src/api/controllers/table/external.ts index 327904666d..513b989a3a 100644 --- a/packages/server/src/api/controllers/table/external.ts +++ b/packages/server/src/api/controllers/table/external.ts @@ -67,13 +67,15 @@ function cleanupRelationships( tables: Record, oldTable?: Table ) { - const tableToIterate = oldTable ? oldTable : table - // clean up relationships in couch table schemas - for (let [key, schema] of Object.entries(tableToIterate.schema)) { - if ( - schema.type === FieldTypes.LINK && - (!oldTable || table.schema[key] == null) - ) { + const isUpdate = !!oldTable + if (!isUpdate) { + return + } + + // When updating a table, we want to detect if some relationships were removed. + // If so, we want to remove the relationship from the other end + for (let [key, schema] of Object.entries(oldTable.schema)) { + if (schema.type === FieldTypes.LINK && !table.schema[key]) { const relatedTable = Object.values(tables).find( table => table._id === schema.tableId ) From a5142088d9f0c25b08a7e09e656a238290dd4948 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 15:09:50 +0200 Subject: [PATCH 040/128] Clean tests --- .../server/src/api/routes/tests/row.spec.ts | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index d572097469..01a6175249 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -772,22 +772,36 @@ describe.each([ describe("fetchEnrichedRows", () => { it("should allow enriching some linked rows", async () => { - const { table, firstRow, secondRow } = await tenancy.doInTenant( + const { linkedTable, firstRow, secondRow } = await tenancy.doInTenant( config.getTenantId(), async () => { - const table = await config.createLinkedTable() - const firstRow = await config.createRow({ + const linkedTable = await config.createLinkedTable({ + name: generator.guid(), + type: "table", + primary: ["id"], + schema: { + id: { + type: FieldType.AUTO, + name: "id", + autocolumn: true, + constraints: { + presence: true, + }, + }, + }, + }) + const firstRow = await createRow(table._id, { name: "Test Contact", description: "original description", tableId: table._id, }) - const secondRow = await config.createRow({ + const secondRow = await createRow(linkedTable._id, { name: "Test 2", description: "og desc", link: [{ _id: firstRow._id }], - tableId: table._id, + tableId: linkedTable._id, }) - return { table, firstRow, secondRow } + return { linkedTable, firstRow, secondRow } } ) const rowUsage = await getRowUsage() @@ -795,16 +809,16 @@ describe.each([ // test basic enrichment const resBasic = await request - .get(`/api/${table._id}/rows/${secondRow._id}`) + .get(`/api/${linkedTable._id}/rows/${secondRow._id}`) .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) - expect(resBasic.body.link[0]._id).toBe(firstRow._id) - expect(resBasic.body.link[0].primaryDisplay).toBe("Test Contact") + expect(resBasic.body.link.length).toBe(1) + expect(resBasic.body.link[0]).toEqual({ _id: firstRow._id }) // test full enrichment const resEnriched = await request - .get(`/api/${table._id}/${secondRow._id}/enrich`) + .get(`/api/${linkedTable._id}/${secondRow._id}/enrich`) .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) From 45ddd46f4cb79ff71a76a1ce1c45e887115a8073 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 15:29:05 +0200 Subject: [PATCH 041/128] Fix tests --- .../server/src/api/routes/tests/row.spec.ts | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 01a6175249..9d9bcb302c 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -137,17 +137,15 @@ describe.each([ const createRow = (tableId = table._id!, row?: SaveRowRequest) => config.api.row.save(tableId, row || basicRow(table._id!)) - describe("save, load, update", () => { - function getDefaultFields() { - if (isInternal) { - return { - type: "row", - createdAt: timestamp, - updatedAt: timestamp, - } + const defaultRowFields = isInternal + ? { + type: "row", + createdAt: timestamp, + updatedAt: timestamp, } - } + : undefined + describe("save, load, update", () => { it("returns a success message when the row is created", async () => { const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -262,7 +260,7 @@ describe.each([ _id: existing._id, _rev: existing._rev, id: existing.id, - ...getDefaultFields(), + ...defaultRowFields, }) await assertQueryUsage(queryUsage + 1) }) @@ -835,7 +833,7 @@ describe.each([ it("should allow enriching attachment rows", async () => { const table = await config.createAttachmentTable() const attachmentId = `${structures.uuid()}.csv` - const row = await config.createRow({ + const row = await createRow(table._id, { name: "test", description: "test", attachment: [ @@ -906,15 +904,24 @@ describe.each([ function userTable(): Table { return { name: "user", - type: "user", + type: "table", + primary: ["id"], schema: { + id: { + type: FieldType.AUTO, + name: "id", + autocolumn: true, + constraints: { + presence: true, + }, + }, name: { type: FieldType.STRING, name: "name", }, surname: { type: FieldType.STRING, - name: "name", + name: "surname", }, age: { type: FieldType.NUMBER, @@ -965,11 +972,10 @@ describe.each([ surname: data.surname, address: data.address, tableId: config.table!._id, - type: "row", - _id: expect.any(String), - _rev: expect.any(String), - createdAt: expect.any(String), - updatedAt: expect.any(String), + _id: newRow._id, + _rev: newRow._rev, + id: newRow.id, + ...defaultRowFields, }) expect(row.body._viewId).toBeUndefined() expect(row.body.age).toBeUndefined() @@ -1006,13 +1012,12 @@ describe.each([ const row = await config.api.row.get(tableId, newRow._id!) expect(row.body).toEqual({ ...newRow, - type: "row", name: newData.name, address: newData.address, - _id: expect.any(String), + _id: newRow._id, _rev: expect.any(String), - createdAt: expect.any(String), - updatedAt: expect.any(String), + id: newRow.id, + ...defaultRowFields, }) expect(row.body._viewId).toBeUndefined() expect(row.body.age).toBeUndefined() From c26a4c3a1135e42d321f88edb596db1a84293630 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 15:46:10 +0200 Subject: [PATCH 042/128] Fixes --- .../server/src/api/routes/tests/row.spec.ts | 99 ++++++++++--------- 1 file changed, 53 insertions(+), 46 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 9d9bcb302c..fa72776f30 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -49,51 +49,57 @@ describe.each([ await config.init() }) - const generateTableConfig: () => SaveTableRequest = () => ({ - name: generator.guid(), - type: "table", - primary: ["id"], - schema: { - id: { - type: FieldType.AUTO, - name: "id", - autocolumn: true, - constraints: { - presence: true, - }, - }, - name: { - type: FieldType.STRING, - name: "name", - constraints: { - type: "string", - }, - }, - description: { - type: FieldType.STRING, - name: "description", - constraints: { - type: "string", - }, - }, - }, - }) - - beforeEach(async () => { - mocks.licenses.useCloudFree() - const tableConfig = generateTableConfig() - + const tableDatasourceConfig = async () => { + const result: Partial = {} if (dsProvider) { datasource = await config.api.datasource.create( await dsProvider.getDsConfig() ) - tableConfig.sourceId = datasource._id + result.sourceId = datasource._id if (datasource.plus) { - tableConfig.type = "external" + result.type = "external" } } + return result + } + const generateTableConfig: () => Promise = async () => { + return { + name: generator.guid(), + type: "table", + primary: ["id"], + schema: { + id: { + type: FieldType.AUTO, + name: "id", + autocolumn: true, + constraints: { + presence: true, + }, + }, + name: { + type: FieldType.STRING, + name: "name", + constraints: { + type: "string", + }, + }, + description: { + type: FieldType.STRING, + name: "description", + constraints: { + type: "string", + }, + }, + }, + ...(await tableDatasourceConfig()), + } + } + + beforeEach(async () => { + mocks.licenses.useCloudFree() + const tableConfig = await generateTableConfig() table = await config.api.table.create(tableConfig) config.table = table config.datasource = datasource @@ -901,9 +907,9 @@ describe.each([ }) describe("view 2.0", () => { - function userTable(): Table { + async function userTable(): Promise { return { - name: "user", + name: `users_${generator.guid()}`, type: "table", primary: ["id"], schema: { @@ -936,6 +942,7 @@ describe.each([ name: "jobTitle", }, }, + ...(await tableDatasourceConfig()), } } @@ -949,7 +956,7 @@ describe.each([ describe("create", () => { it("should persist a new row with only the provided view fields", async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const view = await config.api.viewV2.create({ tableId: table._id!, schema: { @@ -985,7 +992,7 @@ describe.each([ describe("patch", () => { it("should update only the view fields for a row", async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1027,7 +1034,7 @@ describe.each([ describe("destroy", () => { it("should be able to delete a row", async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1037,7 +1044,7 @@ describe.each([ }, }) - const createdRow = await config.createRow() + const createdRow = await createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -1052,7 +1059,7 @@ describe.each([ }) it("should be able to delete multiple rows", async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1063,9 +1070,9 @@ describe.each([ }) const rows = [ - await config.createRow(), - await config.createRow(), - await config.createRow(), + await createRow(tableId), + await createRow(tableId), + await createRow(tableId), ] const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() From b63b61655b3b4e25e4466f0516f6dbfa9a1ab411 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 15:54:27 +0200 Subject: [PATCH 043/128] Fixes --- .../server/src/api/routes/tests/row.spec.ts | 36 ++++++++++++------- .../src/tests/utilities/TestConfiguration.ts | 28 ++++++++++----- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index fa72776f30..0193ff095d 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1094,11 +1094,20 @@ describe.each([ describe("view search", () => { const viewSchema = { age: { visible: true }, name: { visible: true } } - function userTable(): Table { + async function userTable(): Promise
{ return { - name: "user", - type: "user", + name: `users_${generator.guid()}`, + type: "table", + primary: ["id"], schema: { + id: { + type: FieldType.AUTO, + name: "id", + autocolumn: true, + constraints: { + presence: true, + }, + }, name: { type: FieldType.STRING, name: "name", @@ -1110,11 +1119,12 @@ describe.each([ constraints: {}, }, }, + ...(await tableDatasourceConfig()), } } - it("returns table rows from view", async () => { - const table = await config.createTable(userTable()) + it.only("returns table rows from view", async () => { + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push(await config.createRow({ tableId: table._id })) @@ -1130,7 +1140,7 @@ describe.each([ }) it("searching respects the view filters", async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const expectedRows = [] for (let i = 0; i < 10; i++) await config.createRow({ @@ -1235,7 +1245,7 @@ describe.each([ it.each(sortTestOptions)( "allow sorting (%s)", async (sortParams, expected) => { - await config.createTable(userTable()) + await config.createTable(await userTable()) const users = [ { name: "Alice", age: 25 }, { name: "Bob", age: 30 }, @@ -1266,7 +1276,7 @@ describe.each([ it.each(sortTestOptions)( "allow override the default view sorting (%s)", async (sortParams, expected) => { - await config.createTable(userTable()) + await config.createTable(await userTable()) const users = [ { name: "Alice", age: 25 }, { name: "Bob", age: 30 }, @@ -1307,7 +1317,7 @@ describe.each([ ) it("when schema is defined, defined columns and row attributes are returned", async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push( @@ -1337,7 +1347,7 @@ describe.each([ }) it("views without data can be returned", async () => { - await config.createTable(userTable()) + await config.createTable(await userTable()) const createViewResponse = await config.api.viewV2.create() const response = await config.api.viewV2.search(createViewResponse.id) @@ -1346,7 +1356,7 @@ describe.each([ }) it("respects the limit parameter", async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push(await config.createRow({ tableId: table._id })) @@ -1363,7 +1373,7 @@ describe.each([ }) it("can handle pagination", async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push(await config.createRow({ tableId: table._id })) @@ -1428,7 +1438,7 @@ describe.each([ let tableId: string beforeAll(async () => { - const table = await config.createTable(userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push(await config.createRow({ tableId: table._id })) diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 72a8b9a146..030a08cee7 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -51,6 +51,8 @@ import { UserRoles, Automation, View, + FieldType, + RelationshipType, } from "@budibase/types" import API from "./api" @@ -76,7 +78,6 @@ class TestConfiguration { globalUserId: any userMetadataId: any table?: Table - linkedTable: any automation: any datasource?: Datasource tenantId?: string @@ -559,25 +560,34 @@ class TestConfiguration { return this._req(null, { tableId }, controllers.table.find) } - async createLinkedTable(relationshipType?: string, links: any = ["link"]) { + async createLinkedTable( + config?: Table, + relationshipType = RelationshipType.ONE_TO_MANY, + links: any = ["link"] + ) { if (!this.table) { throw "Must have created a table first." } - const tableConfig: any = basicTable() + const tableConfig = config || basicTable() tableConfig.primaryDisplay = "name" for (let link of links) { tableConfig.schema[link] = { - type: "link", + type: FieldType.LINK, fieldName: link, tableId: this.table._id, name: link, - } - if (relationshipType) { - tableConfig.schema[link].relationshipType = relationshipType + relationshipType, } } - const linkedTable = await this.createTable(tableConfig) - this.linkedTable = linkedTable + + if (this.datasource && !tableConfig.sourceId) { + tableConfig.sourceId = this.datasource._id + if (this.datasource.plus) { + tableConfig.type = "external" + } + } + + const linkedTable = await this.api.table.create(tableConfig) return linkedTable } From fd023cf291e1dba7abb5643c15de5b52d318f150 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 15:56:31 +0200 Subject: [PATCH 044/128] Add dist/plugins.js back --- packages/backend-core/scripts/build.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend-core/scripts/build.js b/packages/backend-core/scripts/build.js index 9cc33d7b75..f84f22bf8d 100644 --- a/packages/backend-core/scripts/build.js +++ b/packages/backend-core/scripts/build.js @@ -1,4 +1,5 @@ #!/usr/bin/node const coreBuild = require("../../../scripts/build") +coreBuild("./src/plugin/index.ts", "./dist/plugins.js") coreBuild("./src/index.ts", "./dist/index.js") From 1a7a1cdd1bbcbe473987e17d14a0e53d9287b2e7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 16:23:34 +0200 Subject: [PATCH 045/128] Fix view test --- packages/server/src/api/routes/tests/row.spec.ts | 14 ++++++++++++-- packages/server/src/sdk/app/rows/search.ts | 2 +- .../server/src/sdk/app/rows/search/internal.ts | 6 +++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 0193ff095d..905304356c 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1123,7 +1123,7 @@ describe.each([ } } - it.only("returns table rows from view", async () => { + it("returns empty rows from view when no schema is passed", async () => { const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { @@ -1135,7 +1135,17 @@ describe.each([ expect(response.body.rows).toHaveLength(10) expect(response.body).toEqual({ - rows: expect.arrayContaining(rows.map(expect.objectContaining)), + rows: expect.arrayContaining( + rows.map(r => ({ + _viewId: createViewResponse.id, + tableId: table._id, + _id: r._id, + _rev: r._rev, + ...defaultRowFields, + })) + ), + hasNextPage: false, + bookmark: null, }) }) diff --git a/packages/server/src/sdk/app/rows/search.ts b/packages/server/src/sdk/app/rows/search.ts index 4861f473ea..afee18b57c 100644 --- a/packages/server/src/sdk/app/rows/search.ts +++ b/packages/server/src/sdk/app/rows/search.ts @@ -20,7 +20,7 @@ function pickApi(tableId: any) { export async function search(options: SearchParams): Promise<{ rows: any[] hasNextPage?: boolean - bookmark?: number | null + bookmark?: number | string | null }> { return pickApi(options.tableId).search(options) } diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index 4cdeca87f6..0a6fd69ff6 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -59,7 +59,11 @@ export async function search(options: SearchParams) { if (paginate) { response = await paginatedSearch(query, params) } else { - response = await fullSearch(query, params) + response = { + ...(await fullSearch(query, params)), + hasNextPage: false, + bookmark: null, + } } // Enrich search results with relationships From b4e82289691ec92cb36df9a428bfdf89352d58e0 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 8 Sep 2023 14:26:28 +0000 Subject: [PATCH 046/128] Bump version to 2.9.40-alpha.9 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 96ada475a3..65d0082142 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.9.40-alpha.8", + "version": "2.9.40-alpha.9", "npmClient": "yarn", "packages": [ "packages/*" From 8858fe38873d1b9d4c128cfa4d8f8b2b537d4d5f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 16:31:47 +0200 Subject: [PATCH 047/128] Fixes --- .../server/src/api/routes/tests/row.spec.ts | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 905304356c..94014d458d 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -20,6 +20,7 @@ import { Table, } from "@budibase/types" import { + expectAnyExternalColsAttributes, expectAnyInternalColsAttributes, generator, mocks, @@ -1178,8 +1179,18 @@ describe.each([ expect(response.body.rows).toHaveLength(5) expect(response.body).toEqual({ rows: expect.arrayContaining( - expectedRows.map(expect.objectContaining) + expectedRows.map(r => ({ + _viewId: createViewResponse.id, + tableId: table._id, + name: r.name, + age: r.age, + _id: r._id, + _rev: r._rev, + ...defaultRowFields, + })) ), + hasNextPage: false, + bookmark: null, }) }) @@ -1277,9 +1288,9 @@ describe.each([ const response = await config.api.viewV2.search(createViewResponse.id) expect(response.body.rows).toHaveLength(4) - expect(response.body).toEqual({ - rows: expected.map(name => expect.objectContaining({ name })), - }) + expect(response.body.rows).toEqual( + expected.map(name => expect.objectContaining({ name })) + ) } ) @@ -1320,9 +1331,9 @@ describe.each([ ) expect(response.body.rows).toHaveLength(4) - expect(response.body).toEqual({ - rows: expected.map(name => expect.objectContaining({ name })), - }) + expect(response.body.rows).toEqual( + expected.map(name => expect.objectContaining({ name })) + ) } ) @@ -1348,7 +1359,9 @@ describe.each([ expect(response.body.rows).toEqual( expect.arrayContaining( rows.map(r => ({ - ...expectAnyInternalColsAttributes, + ...(isInternal + ? expectAnyInternalColsAttributes + : expectAnyExternalColsAttributes), _viewId: view.id, name: r.name, })) From 2f5aadec4bdc09b71dc16f34e4c9b2339d27dad8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 16:39:13 +0200 Subject: [PATCH 048/128] More fixes --- packages/server/src/api/routes/tests/row.spec.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 94014d458d..2373b8f9cc 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1401,7 +1401,6 @@ describe.each([ for (let i = 0; i < 10; i++) { rows.push(await config.createRow({ tableId: table._id })) } - // rows.sort((a, b) => (a._id! > b._id! ? 1 : -1)) const createViewResponse = await config.api.viewV2.create() const allRows = (await config.api.viewV2.search(createViewResponse.id)) @@ -1417,9 +1416,9 @@ describe.each([ ) expect(firstPageResponse.body).toEqual({ rows: expect.arrayContaining(allRows.slice(0, 4)), - totalRows: 10, + totalRows: isInternal ? 10 : undefined, hasNextPage: true, - bookmark: expect.any(String), + bookmark: expect.anything(), }) const secondPageResponse = await config.api.viewV2.search( @@ -1434,9 +1433,9 @@ describe.each([ ) expect(secondPageResponse.body).toEqual({ rows: expect.arrayContaining(allRows.slice(4, 8)), - totalRows: 10, + totalRows: isInternal ? 10 : undefined, hasNextPage: true, - bookmark: expect.any(String), + bookmark: expect.anything(), }) const lastPageResponse = await config.api.viewV2.search( @@ -1450,9 +1449,9 @@ describe.each([ ) expect(lastPageResponse.body).toEqual({ rows: expect.arrayContaining(allRows.slice(8)), - totalRows: 10, + totalRows: isInternal ? 10 : undefined, hasNextPage: false, - bookmark: expect.any(String), + bookmark: expect.anything(), }) }) From d1d3dd3c378e055f180517b851c1bfd72f1b701b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Fri, 8 Sep 2023 14:51:34 +0000 Subject: [PATCH 049/128] Bump version to 2.10.2 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index a346d18213..34dca0cd41 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.1", + "version": "2.10.2", "npmClient": "yarn", "packages": [ "packages/*" From 4e69e51ccad85c9663f13d411ea6fd6f265cd1d8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 8 Sep 2023 17:42:54 +0200 Subject: [PATCH 050/128] Fix autocolumns --- .../src/api/controllers/row/ExternalRequest.ts | 18 ++++++++++++------ .../server/src/api/controllers/row/external.ts | 18 +++++++++++++++++- .../server/src/api/routes/tests/row.spec.ts | 4 ++-- packages/server/src/sdk/app/tables/index.ts | 15 +++++++++++++-- .../server/src/sdk/app/tables/validation.ts | 7 ------- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index b24b642035..2c4428599b 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -1,4 +1,5 @@ import { + AutoReason, Datasource, FieldSchema, FieldType, @@ -24,7 +25,7 @@ import { isSQL, } from "../../../integrations/utils" import { getDatasourceAndQuery } from "../../../sdk/app/rows/utils" -import { FieldTypes } from "../../../constants" +import { AutoFieldSubTypes, FieldTypes } from "../../../constants" import { processObjectSync } from "@budibase/string-templates" import { cloneDeep } from "lodash/fp" import { processDates, processFormulas } from "../../../utilities/rowProcessor" @@ -259,6 +260,15 @@ function isOneSide(field: FieldSchema) { ) } +function isEditableColumn(column: FieldSchema) { + const isExternalAutoColumn = + column.autocolumn && + column.autoReason !== AutoReason.FOREIGN_KEY && + column.subtype !== AutoFieldSubTypes.AUTO_ID + const isFormula = column.type === FieldTypes.FORMULA + return !(isExternalAutoColumn || isFormula) +} + export class ExternalRequest { private operation: Operation private tableId: string @@ -295,11 +305,7 @@ export class ExternalRequest { manyRelationships: ManyRelationship[] = [] for (let [key, field] of Object.entries(table.schema)) { // if set already, or not set just skip it - if ( - row[key] == null || - newRow[key] || - !sdk.tables.isEditableColumn(field) - ) { + if (row[key] == null || newRow[key] || !isEditableColumn(field)) { continue } // if its an empty string then it means return the column to null (if possible) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 44d50886d3..acae075165 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -18,6 +18,8 @@ import { import sdk from "../../../sdk" import * as utils from "./utils" import { dataFilters } from "@budibase/shared-core" +import { inputProcessing } from "../../../utilities/rowProcessor" +import { cloneDeep, isEqual } from "lodash" export async function handleRequest( operation: Operation, @@ -88,10 +90,24 @@ export async function save(ctx: UserCtx) { if (!validateResult.valid) { throw { validation: validateResult.errors } } + + const table = await sdk.tables.getTable(tableId) + const { table: updatedTable, row } = inputProcessing( + ctx.user, + cloneDeep(table), + inputs + ) + const response = await handleRequest(Operation.CREATE, tableId, { - row: inputs, + row, }) + const responseRow = response as { row: Row } + + if (!isEqual(table, updatedTable)) { + await sdk.tables.saveTable(updatedTable) + } + const rowId = responseRow.row._id if (rowId) { const row = await sdk.rows.external.getRow(tableId, rowId, { diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 2373b8f9cc..63850602ba 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -177,8 +177,8 @@ describe.each([ const queryUsage = await getQueryUsage() const newTable = await config.createTable({ + ...table, name: "TestTableAuto", - type: "table", schema: { ...table.schema, "Row ID": { @@ -189,7 +189,7 @@ describe.each([ autocolumn: true, constraints: { type: "number", - presence: false, + presence: true, numericality: { greaterThanOrEqualTo: "", lessThanOrEqualTo: "", diff --git a/packages/server/src/sdk/app/tables/index.ts b/packages/server/src/sdk/app/tables/index.ts index 1bf9117837..64fcde4bff 100644 --- a/packages/server/src/sdk/app/tables/index.ts +++ b/packages/server/src/sdk/app/tables/index.ts @@ -12,7 +12,7 @@ import { TableViewsResponse, } from "@budibase/types" import datasources from "../datasources" -import { isEditableColumn, populateExternalTableSchemas } from "./validation" +import { populateExternalTableSchemas } from "./validation" import sdk from "../../../sdk" async function getAllInternalTables(db?: Database): Promise { @@ -73,12 +73,23 @@ function enrichViewSchemas(table: Table): TableResponse { } } +async function saveTable(table: Table) { + const db = context.getAppDB() + if (isExternalTable(table._id!)) { + const datasource = await sdk.datasources.get(table.sourceId!) + datasource.entities![table.name] = table + await db.put(datasource) + } else { + await db.put(table) + } +} + export default { getAllInternalTables, getAllExternalTables, getExternalTable, getTable, populateExternalTableSchemas, - isEditableColumn, enrichViewSchemas, + saveTable, } diff --git a/packages/server/src/sdk/app/tables/validation.ts b/packages/server/src/sdk/app/tables/validation.ts index 8dc41107d3..56f3e84c7a 100644 --- a/packages/server/src/sdk/app/tables/validation.ts +++ b/packages/server/src/sdk/app/tables/validation.ts @@ -55,13 +55,6 @@ function checkForeignKeysAreAutoColumns(datasource: Datasource) { return datasource } -export function isEditableColumn(column: FieldSchema) { - const isAutoColumn = - column.autocolumn && column.autoReason !== AutoReason.FOREIGN_KEY - const isFormula = column.type === FieldTypes.FORMULA - return !(isAutoColumn || isFormula) -} - export function populateExternalTableSchemas(datasource: Datasource) { return checkForeignKeysAreAutoColumns(datasource) } From 33be2d6c969c52be48f833c4f8eadb9b6c1b7e2a Mon Sep 17 00:00:00 2001 From: FlaminWrap <97764630+FlaminWrap@users.noreply.github.com> Date: Fri, 8 Sep 2023 21:28:25 +0100 Subject: [PATCH 051/128] Fix #11353 Removes the slice as the v prefix has been removed Addresses: #11353 --- .../builder/src/pages/builder/portal/settings/version.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/builder/src/pages/builder/portal/settings/version.svelte b/packages/builder/src/pages/builder/portal/settings/version.svelte index fb9144c730..c3898b7861 100644 --- a/packages/builder/src/pages/builder/portal/settings/version.svelte +++ b/packages/builder/src/pages/builder/portal/settings/version.svelte @@ -63,8 +63,7 @@ ) const githubResponse = await githubCheck.json() - //Get tag and remove the v infront of the tage name e.g. v1.0.0 is 1.0.0 - githubVersion = githubResponse.tag_name.slice(1) + githubVersion = githubResponse.tag_name //Get the release date and output it in the local time format githubPublishedDate = new Date(githubResponse.published_at) From 139c642199b77b7d723a842832619c6f1043bc8a Mon Sep 17 00:00:00 2001 From: Mel O'Hagan Date: Fri, 8 Sep 2023 23:53:15 +0100 Subject: [PATCH 052/128] Don't send S3 image data url to rows endpoint --- .../src/components/app/forms/S3Upload.svelte | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/client/src/components/app/forms/S3Upload.svelte b/packages/client/src/components/app/forms/S3Upload.svelte index 795e2e4332..dfc5032de9 100644 --- a/packages/client/src/components/app/forms/S3Upload.svelte +++ b/packages/client/src/components/app/forms/S3Upload.svelte @@ -2,6 +2,7 @@ import Field from "./Field.svelte" import { CoreDropzone, ProgressCircle } from "@budibase/bbui" import { getContext, onMount, onDestroy } from "svelte" + import { cloneDeep } from "../../../../../bbui/src/helpers" export let datasourceId export let bucket @@ -14,6 +15,7 @@ let fieldState let fieldApi + let localFiles = [] const { API, notificationStore, uploadStore } = getContext("sdk") const component = getContext("component") @@ -90,9 +92,17 @@ } const handleChange = e => { - const changed = fieldApi.setValue(e.detail) + localFiles = e.detail + let files = cloneDeep(e.detail) || [] + // remove URL as it contains the full base64 image data + files.forEach(file => { + if (file.type?.startsWith("image")) { + delete file.url + } + }) + const changed = fieldApi.setValue(files) if (onChange && changed) { - onChange({ value: e.detail }) + onChange({ value: files }) } } @@ -118,7 +128,7 @@
{#if fieldState} Date: Fri, 8 Sep 2023 23:59:25 +0100 Subject: [PATCH 053/128] S3 upload field is now simple input --- .../src/components/design/settings/componentSettings.js | 3 ++- packages/client/manifest.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/components/design/settings/componentSettings.js b/packages/builder/src/components/design/settings/componentSettings.js index 8b151564a1..6d673cbd3d 100644 --- a/packages/builder/src/components/design/settings/componentSettings.js +++ b/packages/builder/src/components/design/settings/componentSettings.js @@ -1,4 +1,4 @@ -import { Checkbox, Select, RadioGroup, Stepper } from "@budibase/bbui" +import { Checkbox, Select, RadioGroup, Stepper, Input } from "@budibase/bbui" import DataSourceSelect from "./controls/DataSourceSelect.svelte" import S3DataSourceSelect from "./controls/S3DataSourceSelect.svelte" import DataProviderSelect from "./controls/DataProviderSelect.svelte" @@ -60,6 +60,7 @@ const componentMap = { "field/longform": FormFieldSelect, "field/datetime": FormFieldSelect, "field/attachment": FormFieldSelect, + "field/s3": Input, "field/link": FormFieldSelect, "field/array": FormFieldSelect, "field/json": FormFieldSelect, diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 229d344d55..75fe287b2a 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -3721,7 +3721,7 @@ }, "settings": [ { - "type": "field/attachment", + "type": "field/s3", "label": "Field", "key": "field", "required": true From c860a7597815e609b5a7fb0067ad936657a1498d Mon Sep 17 00:00:00 2001 From: Mel O'Hagan Date: Sat, 9 Sep 2023 00:04:42 +0100 Subject: [PATCH 054/128] Use asterisk instead of null --- .../_components/EditDatasourceConfigButton.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/EditDatasourceConfigButton.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/EditDatasourceConfigButton.svelte index 9e50ab8da3..54937f9415 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/EditDatasourceConfigButton.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/EditDatasourceConfigButton.svelte @@ -31,7 +31,7 @@ datasource.source === IntegrationTypes.DYNAMODB || datasource.source === IntegrationTypes.S3 ) { - return `${datasource.config.endpoint}:${datasource.config.region}` + return `${datasource.config.endpoint || "*"}:${datasource.config.region}` } if (datasource.source === IntegrationTypes.ELASTICSEARCH) { return datasource.config.url From ca743e77fbfc00a8c21003ad4cb8db0e3e3978f4 Mon Sep 17 00:00:00 2001 From: Conor Webb Date: Mon, 11 Sep 2023 07:52:43 +0100 Subject: [PATCH 055/128] Fixed typo of label for number type column. --- .../components/backend/DataTable/modals/CreateEditColumn.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index fd13767a63..44c37813d6 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -523,7 +523,7 @@ {:else if editableColumn.type === "number" && !editableColumn.autocolumn}
- +
Date: Wed, 6 Sep 2023 18:17:44 +0100 Subject: [PATCH 056/128] Updating the yarn dev process to not include a removal of the dist directory as part of the streamed watchers - this seems to create a problem for shared core and moving this up a level to a parallel run before the watchers massively improves stability. --- package.json | 2 +- packages/server/package.json | 2 +- packages/shared-core/package.json | 2 +- packages/types/package.json | 2 +- packages/worker/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b0c428fe70..b263fb6585 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "kill-builder": "kill-port 3000", "kill-server": "kill-port 4001 4002", "kill-all": "yarn run kill-builder && yarn run kill-server", - "dev": "yarn run kill-all && lerna run --stream dev:builder", + "dev": "yarn run kill-all && lerna run --parallel prebuild && lerna run --stream dev:builder", "dev:noserver": "yarn run kill-builder && lerna run --stream dev:stack:up && lerna run --stream dev:builder --ignore @budibase/backend-core --ignore @budibase/server --ignore @budibase/worker", "dev:server": "yarn run kill-server && lerna run --stream dev:builder --scope @budibase/worker --scope @budibase/server", "dev:built": "yarn run kill-all && cd packages/server && yarn dev:stack:up && cd ../../ && lerna run --stream dev:built", diff --git a/packages/server/package.json b/packages/server/package.json index ecf31175dc..39f52342a4 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -26,7 +26,7 @@ "dev:stack:up": "node scripts/dev/manage.js up", "dev:stack:down": "node scripts/dev/manage.js down", "dev:stack:nuke": "node scripts/dev/manage.js nuke", - "dev:builder": "yarn run dev:stack:up && rimraf dist/ && nodemon", + "dev:builder": "yarn run dev:stack:up && nodemon", "dev:built": "yarn run dev:stack:up && yarn run run:docker", "specs": "ts-node specs/generate.ts && openapi-typescript specs/openapi.yaml --output src/definitions/openapi.ts", "initialise": "node scripts/initialise.js", diff --git a/packages/shared-core/package.json b/packages/shared-core/package.json index 8edea4870a..160a42f086 100644 --- a/packages/shared-core/package.json +++ b/packages/shared-core/package.json @@ -10,7 +10,7 @@ "prebuild": "rimraf dist/", "build": "node ../../scripts/build.js && tsc -p tsconfig.build.json --emitDeclarationOnly --paths null", "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", - "dev:builder": "yarn prebuild && tsc -p tsconfig.json --watch --preserveWatchOutput", + "dev:builder": "tsc -p tsconfig.json --watch --preserveWatchOutput", "check:types": "tsc -p tsconfig.json --noEmit --paths null" }, "dependencies": { diff --git a/packages/types/package.json b/packages/types/package.json index bb0163ae13..919cc736fc 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -10,7 +10,7 @@ "prebuild": "rimraf dist/", "build": "node ../../scripts/build.js && tsc -p tsconfig.build.json --emitDeclarationOnly", "build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput", - "dev:builder": "yarn prebuild && tsc -p tsconfig.json --watch --preserveWatchOutput", + "dev:builder": "tsc -p tsconfig.json --watch --preserveWatchOutput", "check:types": "tsc -p tsconfig.json --noEmit --paths null" }, "jest": {}, diff --git a/packages/worker/package.json b/packages/worker/package.json index 3b66df264e..15ab1c1ff9 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -22,7 +22,7 @@ "predocker": "yarn build && cp ../../yarn.lock ./dist/", "build:docker": "yarn predocker && docker build . -t worker-service --label version=$BUDIBASE_RELEASE_VERSION", "dev:stack:init": "node ./scripts/dev/manage.js init", - "dev:builder": "npm run dev:stack:init && rimraf dist/ && nodemon", + "dev:builder": "npm run dev:stack:init && nodemon", "dev:built": "yarn run dev:stack:init && yarn run run:docker", "test": "bash scripts/test.sh", "test:watch": "jest --watch", From 8ecc9c2d53e9f62e44c66ef218bd2f0090778937 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 11 Sep 2023 10:57:39 +0000 Subject: [PATCH 057/128] Bump version to 2.10.3-alpha.0 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 34dca0cd41..1669e15246 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.2", + "version": "2.10.3-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" From cb115f4f11a2dcdad669ac1ed027562344ad7762 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 11 Sep 2023 11:15:51 +0000 Subject: [PATCH 058/128] Bump version to 2.10.3 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 1669e15246..efc51f353a 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.3-alpha.0", + "version": "2.10.3", "npmClient": "yarn", "packages": [ "packages/*" From 491d5b2de74adfc0048998b4ba1985e4340d564c Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Mon, 11 Sep 2023 16:01:47 +0100 Subject: [PATCH 059/128] Remove missed reference to developer in user import modal --- packages/frontend-core/src/constants.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/frontend-core/src/constants.js b/packages/frontend-core/src/constants.js index cfaaaea81b..344326065a 100644 --- a/packages/frontend-core/src/constants.js +++ b/packages/frontend-core/src/constants.js @@ -52,11 +52,6 @@ export const BuilderRoleDescriptions = [ icon: "User", label: "App user - Only has access to published apps", }, - { - value: BudibaseRoles.Developer, - icon: "Hammer", - label: "Developer - Access to the app builder", - }, { value: BudibaseRoles.Admin, icon: "Draw", From 7147752b9c5c33e4741e1c3ceaf643888ca36256 Mon Sep 17 00:00:00 2001 From: Mel O'Hagan Date: Mon, 11 Sep 2023 21:26:05 +0100 Subject: [PATCH 060/128] Fix date validation regex --- packages/server/src/integrations/tests/sql.spec.ts | 12 ++++++++++++ packages/server/src/integrations/utils.ts | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts index 0bf1498f5f..5bbdbff006 100644 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ b/packages/server/src/integrations/tests/sql.spec.ts @@ -657,4 +657,16 @@ describe("SQL query builder", () => { sql: `select * from (select top (@p0) * from [test] order by [test].[id] asc) as [test]`, }) }) + + it("should not parse JSON string as Date", () => { + let query = new Sql(SqlClient.POSTGRES, limit)._query( + generateCreateJson(TABLE_NAME, { + name: '{ "created_at":"2023-09-09T03:21:06.024Z" }', + }) + ) + expect(query).toEqual({ + bindings: ['{ "created_at":"2023-09-09T03:21:06.024Z" }'], + sql: `insert into \"test\" (\"name\") values ($1) returning *`, + }) + }) }) diff --git a/packages/server/src/integrations/utils.ts b/packages/server/src/integrations/utils.ts index 3f598ce986..02041c9d4b 100644 --- a/packages/server/src/integrations/utils.ts +++ b/packages/server/src/integrations/utils.ts @@ -182,7 +182,7 @@ export function getSqlQuery(query: SqlQuery | string): SqlQuery { export const isSQL = helpers.isSQL export function isIsoDateString(str: string) { - if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) { + if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(str.trim())) { return false } let d = new Date(str) From 17dc01808c384e5d703b14e8ce90bb0b363f3739 Mon Sep 17 00:00:00 2001 From: Mel O'Hagan Date: Mon, 11 Sep 2023 21:35:51 +0100 Subject: [PATCH 061/128] Additional unit test --- packages/server/src/integrations/base/sql.ts | 2 +- packages/server/src/integrations/tests/sql.spec.ts | 13 +++++++++++++ packages/server/src/integrations/utils.ts | 7 ++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 2cdae682b0..bf19ec9afe 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -58,7 +58,7 @@ function parse(input: any) { return null } if (isIsoDateString(input)) { - return new Date(input) + return new Date(input.trim()) } return input } diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts index 5bbdbff006..5cc4849d03 100644 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ b/packages/server/src/integrations/tests/sql.spec.ts @@ -669,4 +669,17 @@ describe("SQL query builder", () => { sql: `insert into \"test\" (\"name\") values ($1) returning *`, }) }) + + it("should parse and trim valid string as Date", () => { + const dateObj = new Date("2023-09-09T03:21:06.024Z") + let query = new Sql(SqlClient.POSTGRES, limit)._query( + generateCreateJson(TABLE_NAME, { + name: " 2023-09-09T03:21:06.024Z ", + }) + ) + expect(query).toEqual({ + bindings: [dateObj], + sql: `insert into \"test\" (\"name\") values ($1) returning *`, + }) + }) }) diff --git a/packages/server/src/integrations/utils.ts b/packages/server/src/integrations/utils.ts index 02041c9d4b..2883e4471c 100644 --- a/packages/server/src/integrations/utils.ts +++ b/packages/server/src/integrations/utils.ts @@ -182,11 +182,12 @@ export function getSqlQuery(query: SqlQuery | string): SqlQuery { export const isSQL = helpers.isSQL export function isIsoDateString(str: string) { - if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(str.trim())) { + const trimmedValue = str.trim() + if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(trimmedValue)) { return false } - let d = new Date(str) - return d.toISOString() === str + let d = new Date(trimmedValue) + return d.toISOString() === trimmedValue } /** From 55514653c34d3cada6009ccf2d88b92fb72e8991 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 09:25:40 +0200 Subject: [PATCH 062/128] yarn.lock --- yarn.lock | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8c93661665..ab86a87560 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6269,14 +6269,6 @@ "@types/tedious" "*" tarn "^3.0.1" -"@types/node-fetch@2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975" - integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - "@types/node-fetch@2.6.4": version "2.6.4" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" @@ -6298,11 +6290,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== -"@types/node@14.18.20": - version "14.18.20" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.20.tgz#268f028b36eaf51181c3300252f605488c4f0650" - integrity sha512-Q8KKwm9YqEmUBRsqJ2GWJDtXltBDxTdC4m5vTdXBolu2PeQh8LX+f6BTwU+OuXPu37fLxoN6gidqBmnky36FXA== - "@types/node@16.9.1": version "16.9.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" From c70c627fc9f0ae12ca8f047e24cc08e44126e391 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 09:52:46 +0200 Subject: [PATCH 063/128] Fix view test --- .../server/src/api/routes/tests/row.spec.ts | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 63850602ba..d66a30684e 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -471,7 +471,12 @@ describe.each([ function orderTable(): Table { return { name: "orders", + primary: ["id"], schema: { + id: { + type: FieldType.AUTO, + name: "id", + }, Country: { type: FieldType.STRING, name: "Country", @@ -494,19 +499,35 @@ describe.each([ const createViewResponse = await config.api.viewV2.create({ tableId: table._id, schema: { - Country: {}, - OrderID: {}, + Country: { + visible: true, + }, + OrderID: { + visible: true, + }, }, }) - const response = await config.api.row.save(createViewResponse.id, { - Country: "Aussy", - OrderID: "1111", - Story: "aaaaa", - }) + const createRowResponse = await config.api.row.save( + createViewResponse.id, + { + OrderID: "1111", + Country: "Aussy", + Story: "aaaaa", + } + ) - const row = await config.api.row.get(table._id!, response._id!) + const row = await config.api.row.get(table._id!, createRowResponse._id!) expect(row.body.Story).toBeUndefined() + expect(row.body).toEqual({ + ...defaultRowFields, + OrderID: "1111", + Country: "Aussy", + id: 1, + _id: "%5B1%5D", + _rev: createRowResponse._rev, + tableId: table._id, + }) }) }) From 8ee23e6168f16456bafc06f464a8790dc3c4c212 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 09:57:47 +0200 Subject: [PATCH 064/128] Fix --- packages/server/src/api/routes/tests/row.spec.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index d66a30684e..bbf5a13574 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -471,18 +471,14 @@ describe.each([ function orderTable(): Table { return { name: "orders", - primary: ["id"], + primary: ["OrderID"], schema: { - id: { - type: FieldType.AUTO, - name: "id", - }, Country: { type: FieldType.STRING, name: "Country", }, OrderID: { - type: FieldType.STRING, + type: FieldType.NUMBER, name: "OrderID", }, Story: { @@ -521,10 +517,9 @@ describe.each([ expect(row.body.Story).toBeUndefined() expect(row.body).toEqual({ ...defaultRowFields, - OrderID: "1111", + OrderID: 1111, Country: "Aussy", - id: 1, - _id: "%5B1%5D", + _id: createRowResponse._id, _rev: createRowResponse._rev, tableId: table._id, }) From cee89b95b1c0ec332522d3f59b53406b4099b58d Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 12 Sep 2023 09:34:11 +0100 Subject: [PATCH 065/128] remove reference to premium plan --- packages/server/src/sdk/app/permissions/index.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/server/src/sdk/app/permissions/index.ts b/packages/server/src/sdk/app/permissions/index.ts index b2661b0f7e..b62a7fb459 100644 --- a/packages/server/src/sdk/app/permissions/index.ts +++ b/packages/server/src/sdk/app/permissions/index.ts @@ -61,11 +61,7 @@ export async function getInheritablePermissions( export async function allowsExplicitPermissions(resourceId: string) { if (isViewID(resourceId)) { const allowed = await features.isViewPermissionEnabled() - const minPlan = !allowed - ? env.SELF_HOSTED - ? PlanType.BUSINESS - : PlanType.PREMIUM - : undefined + const minPlan = !allowed ? PlanType.BUSINESS : undefined return { allowed, From 377fc7fc10e4176b4385f8e1a97dd0ee7321c6fc Mon Sep 17 00:00:00 2001 From: Mel O'Hagan Date: Tue, 12 Sep 2023 09:38:33 +0100 Subject: [PATCH 066/128] Updating pro reference to master --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 4638ae916e..961d683794 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 4638ae916e55ce89166095578cbd01745d0ee9ee +Subproject commit 961d683794442f615468d44b684e5a94633109eb From d294b171c0f5c0d131a75a3622324bb37d59061c Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 12 Sep 2023 09:40:29 +0100 Subject: [PATCH 067/128] pro update --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index 4638ae916e..961d683794 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 4638ae916e55ce89166095578cbd01745d0ee9ee +Subproject commit 961d683794442f615468d44b684e5a94633109eb From 66524d998b746b1ad92e265bb5eb9436aee8446c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 11:02:44 +0200 Subject: [PATCH 068/128] Run coerced only for internal --- .../server/src/api/routes/tests/row.spec.ts | 305 +++++++++--------- 1 file changed, 153 insertions(+), 152 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index bbf5a13574..5fa3745987 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -304,167 +304,168 @@ describe.each([ await assertQueryUsage(queryUsage) // no change }) - it("row values are coerced", async () => { - const str = { - type: FieldType.STRING, - name: "str", - constraints: { type: "string", presence: false }, - } - const attachment = { - type: FieldType.ATTACHMENT, - name: "attachment", - constraints: { type: "array", presence: false }, - } - const bool = { - type: FieldType.BOOLEAN, - name: "boolean", - constraints: { type: "boolean", presence: false }, - } - const number = { - type: FieldType.NUMBER, - name: "str", - constraints: { type: "number", presence: false }, - } - const datetime = { - type: FieldType.DATETIME, - name: "datetime", - constraints: { - type: "string", - presence: false, - datetime: { earliest: "", latest: "" }, - }, - } - const arrayField = { - type: FieldType.ARRAY, - constraints: { - type: "array", - presence: false, - inclusion: ["One", "Two", "Three"], - }, - name: "Sample Tags", - sortable: false, - } - const optsField = { - fieldName: "Sample Opts", - name: "Sample Opts", - type: FieldType.OPTIONS, + isInternal && + it("row values are coerced", async () => { + const str = { + type: FieldType.STRING, + name: "str", + constraints: { type: "string", presence: false }, + } + const attachment = { + type: FieldType.ATTACHMENT, + name: "attachment", + constraints: { type: "array", presence: false }, + } + const bool = { + type: FieldType.BOOLEAN, + name: "boolean", + constraints: { type: "boolean", presence: false }, + } + const number = { + type: FieldType.NUMBER, + name: "str", + constraints: { type: "number", presence: false }, + } + const datetime = { + type: FieldType.DATETIME, + name: "datetime", constraints: { type: "string", presence: false, - inclusion: ["Alpha", "Beta", "Gamma"], + datetime: { earliest: "", latest: "" }, }, - }, - table = await config.createTable({ - name: "TestTable2", - type: "table", - schema: { - name: str, - stringUndefined: str, - stringNull: str, - stringString: str, - numberEmptyString: number, - numberNull: number, - numberUndefined: number, - numberString: number, - numberNumber: number, - datetimeEmptyString: datetime, - datetimeNull: datetime, - datetimeUndefined: datetime, - datetimeString: datetime, - datetimeDate: datetime, - boolNull: bool, - boolEmpty: bool, - boolUndefined: bool, - boolString: bool, - boolBool: bool, - attachmentNull: attachment, - attachmentUndefined: attachment, - attachmentEmpty: attachment, - attachmentEmptyArrayStr: attachment, - arrayFieldEmptyArrayStr: arrayField, - arrayFieldArrayStrKnown: arrayField, - arrayFieldNull: arrayField, - arrayFieldUndefined: arrayField, - optsFieldEmptyStr: optsField, - optsFieldUndefined: optsField, - optsFieldNull: optsField, - optsFieldStrKnown: optsField, + } + const arrayField = { + type: FieldType.ARRAY, + constraints: { + type: "array", + presence: false, + inclusion: ["One", "Two", "Three"], }, - }) + name: "Sample Tags", + sortable: false, + } + const optsField = { + fieldName: "Sample Opts", + name: "Sample Opts", + type: FieldType.OPTIONS, + constraints: { + type: "string", + presence: false, + inclusion: ["Alpha", "Beta", "Gamma"], + }, + }, + table = await config.createTable({ + name: "TestTable2", + type: "table", + schema: { + name: str, + stringUndefined: str, + stringNull: str, + stringString: str, + numberEmptyString: number, + numberNull: number, + numberUndefined: number, + numberString: number, + numberNumber: number, + datetimeEmptyString: datetime, + datetimeNull: datetime, + datetimeUndefined: datetime, + datetimeString: datetime, + datetimeDate: datetime, + boolNull: bool, + boolEmpty: bool, + boolUndefined: bool, + boolString: bool, + boolBool: bool, + attachmentNull: attachment, + attachmentUndefined: attachment, + attachmentEmpty: attachment, + attachmentEmptyArrayStr: attachment, + arrayFieldEmptyArrayStr: arrayField, + arrayFieldArrayStrKnown: arrayField, + arrayFieldNull: arrayField, + arrayFieldUndefined: arrayField, + optsFieldEmptyStr: optsField, + optsFieldUndefined: optsField, + optsFieldNull: optsField, + optsFieldStrKnown: optsField, + }, + }) - row = { - name: "Test Row", - stringUndefined: undefined, - stringNull: null, - stringString: "i am a string", - numberEmptyString: "", - numberNull: null, - numberUndefined: undefined, - numberString: "123", - numberNumber: 123, - datetimeEmptyString: "", - datetimeNull: null, - datetimeUndefined: undefined, - datetimeString: "1984-04-20T00:00:00.000Z", - datetimeDate: new Date("1984-04-20"), - boolNull: null, - boolEmpty: "", - boolUndefined: undefined, - boolString: "true", - boolBool: true, - tableId: table._id, - attachmentNull: null, - attachmentUndefined: undefined, - attachmentEmpty: "", - attachmentEmptyArrayStr: "[]", - arrayFieldEmptyArrayStr: "[]", - arrayFieldUndefined: undefined, - arrayFieldNull: null, - arrayFieldArrayStrKnown: "['One']", - optsFieldEmptyStr: "", - optsFieldUndefined: undefined, - optsFieldNull: null, - optsFieldStrKnown: "Alpha", - } + row = { + name: "Test Row", + stringUndefined: undefined, + stringNull: null, + stringString: "i am a string", + numberEmptyString: "", + numberNull: null, + numberUndefined: undefined, + numberString: "123", + numberNumber: 123, + datetimeEmptyString: "", + datetimeNull: null, + datetimeUndefined: undefined, + datetimeString: "1984-04-20T00:00:00.000Z", + datetimeDate: new Date("1984-04-20"), + boolNull: null, + boolEmpty: "", + boolUndefined: undefined, + boolString: "true", + boolBool: true, + tableId: table._id, + attachmentNull: null, + attachmentUndefined: undefined, + attachmentEmpty: "", + attachmentEmptyArrayStr: "[]", + arrayFieldEmptyArrayStr: "[]", + arrayFieldUndefined: undefined, + arrayFieldNull: null, + arrayFieldArrayStrKnown: "['One']", + optsFieldEmptyStr: "", + optsFieldUndefined: undefined, + optsFieldNull: null, + optsFieldStrKnown: "Alpha", + } - const createdRow = await config.createRow(row) - const id = createdRow._id! + const createdRow = await config.createRow(row) + const id = createdRow._id! - const saved = (await loadRow(id, table._id!)).body + const saved = (await loadRow(id, table._id!)).body - expect(saved.stringUndefined).toBe(undefined) - expect(saved.stringNull).toBe("") - expect(saved.stringString).toBe("i am a string") - expect(saved.numberEmptyString).toBe(null) - expect(saved.numberNull).toBe(null) - expect(saved.numberUndefined).toBe(undefined) - expect(saved.numberString).toBe(123) - expect(saved.numberNumber).toBe(123) - expect(saved.datetimeEmptyString).toBe(null) - expect(saved.datetimeNull).toBe(null) - expect(saved.datetimeUndefined).toBe(undefined) - expect(saved.datetimeString).toBe( - new Date(row.datetimeString).toISOString() - ) - expect(saved.datetimeDate).toBe(row.datetimeDate.toISOString()) - expect(saved.boolNull).toBe(null) - expect(saved.boolEmpty).toBe(null) - expect(saved.boolUndefined).toBe(undefined) - expect(saved.boolString).toBe(true) - expect(saved.boolBool).toBe(true) - expect(saved.attachmentNull).toEqual([]) - expect(saved.attachmentUndefined).toBe(undefined) - expect(saved.attachmentEmpty).toEqual([]) - expect(saved.attachmentEmptyArrayStr).toEqual([]) - expect(saved.arrayFieldEmptyArrayStr).toEqual([]) - expect(saved.arrayFieldNull).toEqual([]) - expect(saved.arrayFieldUndefined).toEqual(undefined) - expect(saved.optsFieldEmptyStr).toEqual(null) - expect(saved.optsFieldUndefined).toEqual(undefined) - expect(saved.optsFieldNull).toEqual(null) - expect(saved.arrayFieldArrayStrKnown).toEqual(["One"]) - expect(saved.optsFieldStrKnown).toEqual("Alpha") - }) + expect(saved.stringUndefined).toBe(undefined) + expect(saved.stringNull).toBe("") + expect(saved.stringString).toBe("i am a string") + expect(saved.numberEmptyString).toBe(null) + expect(saved.numberNull).toBe(null) + expect(saved.numberUndefined).toBe(undefined) + expect(saved.numberString).toBe(123) + expect(saved.numberNumber).toBe(123) + expect(saved.datetimeEmptyString).toBe(null) + expect(saved.datetimeNull).toBe(null) + expect(saved.datetimeUndefined).toBe(undefined) + expect(saved.datetimeString).toBe( + new Date(row.datetimeString).toISOString() + ) + expect(saved.datetimeDate).toBe(row.datetimeDate.toISOString()) + expect(saved.boolNull).toBe(null) + expect(saved.boolEmpty).toBe(null) + expect(saved.boolUndefined).toBe(undefined) + expect(saved.boolString).toBe(true) + expect(saved.boolBool).toBe(true) + expect(saved.attachmentNull).toEqual([]) + expect(saved.attachmentUndefined).toBe(undefined) + expect(saved.attachmentEmpty).toEqual([]) + expect(saved.attachmentEmptyArrayStr).toEqual([]) + expect(saved.arrayFieldEmptyArrayStr).toEqual([]) + expect(saved.arrayFieldNull).toEqual([]) + expect(saved.arrayFieldUndefined).toEqual(undefined) + expect(saved.optsFieldEmptyStr).toEqual(null) + expect(saved.optsFieldUndefined).toEqual(undefined) + expect(saved.optsFieldNull).toEqual(null) + expect(saved.arrayFieldArrayStrKnown).toEqual(["One"]) + expect(saved.optsFieldStrKnown).toEqual("Alpha") + }) }) describe("view save", () => { From 260e0b6f99616ce81d06e25ecdb49977ff061e5f Mon Sep 17 00:00:00 2001 From: Mel O'Hagan Date: Tue, 12 Sep 2023 10:25:10 +0100 Subject: [PATCH 069/128] Improve default S3 subtitle --- .../_components/EditDatasourceConfigButton.svelte | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/EditDatasourceConfigButton.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/EditDatasourceConfigButton.svelte index 54937f9415..9654b27b50 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/EditDatasourceConfigButton.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[datasourceId]/_components/EditDatasourceConfigButton.svelte @@ -27,11 +27,13 @@ if (datasource.source === IntegrationTypes.COUCHDB) { return datasource.config.database } - if ( - datasource.source === IntegrationTypes.DYNAMODB || - datasource.source === IntegrationTypes.S3 - ) { - return `${datasource.config.endpoint || "*"}:${datasource.config.region}` + if (datasource.source === IntegrationTypes.DYNAMODB) { + return `${datasource.config.endpoint}:${datasource.config.region}` + } + if (datasource.source === IntegrationTypes.S3) { + return datasource.config.endpoint + ? `${datasource.config.endpoint}:${datasource.config.region}` + : `s3.${datasource.config.region}.amazonaws.com` } if (datasource.source === IntegrationTypes.ELASTICSEARCH) { return datasource.config.url From 948e5184c181264f22c1ce6936ee0e55608b1af0 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 12 Sep 2023 09:28:46 +0000 Subject: [PATCH 070/128] Bump version to 2.10.4 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index efc51f353a..5b5e98d0ea 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.3", + "version": "2.10.4", "npmClient": "yarn", "packages": [ "packages/*" From b289253b0e0a6e2553ec7a71d8688b8d441ec62b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 12 Sep 2023 10:18:09 +0000 Subject: [PATCH 071/128] Bump version to 2.10.5 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 5b5e98d0ea..23a10992cb 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.4", + "version": "2.10.5", "npmClient": "yarn", "packages": [ "packages/*" From d92811f909d5915c71232c6e5fa85b922fbc6bb9 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 12 Sep 2023 10:18:42 +0000 Subject: [PATCH 072/128] Bump version to 2.10.6 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 23a10992cb..63466ceedb 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.5", + "version": "2.10.6", "npmClient": "yarn", "packages": [ "packages/*" From 1d0a42b59fb2c1482e55c466703e6470028f75b7 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 12 Sep 2023 11:26:26 +0100 Subject: [PATCH 073/128] pin version of postgres in QA core tests so it works with pg dump --- .../integrations/external-schema/postgres.integration.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa-core/src/integrations/external-schema/postgres.integration.spec.ts b/qa-core/src/integrations/external-schema/postgres.integration.spec.ts index 762a16b221..bb7c8de932 100644 --- a/qa-core/src/integrations/external-schema/postgres.integration.spec.ts +++ b/qa-core/src/integrations/external-schema/postgres.integration.spec.ts @@ -18,7 +18,7 @@ describe("getExternalSchema", () => { beforeAll(async () => { // This is left on propose without a tag, so if a new version introduces a breaking change we will be notified - const container = await new GenericContainer("postgres") + const container = await new GenericContainer("postgres:13.12") .withExposedPorts(5432) .withEnv("POSTGRES_PASSWORD", "password") .start() From 9fc1811b0c2b7a72c8e6ae5e575c922efaff6085 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 12 Sep 2023 11:26:38 +0100 Subject: [PATCH 074/128] remove comment --- .../integrations/external-schema/postgres.integration.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/qa-core/src/integrations/external-schema/postgres.integration.spec.ts b/qa-core/src/integrations/external-schema/postgres.integration.spec.ts index bb7c8de932..a0812c9677 100644 --- a/qa-core/src/integrations/external-schema/postgres.integration.spec.ts +++ b/qa-core/src/integrations/external-schema/postgres.integration.spec.ts @@ -17,7 +17,6 @@ describe("getExternalSchema", () => { } beforeAll(async () => { - // This is left on propose without a tag, so if a new version introduces a breaking change we will be notified const container = await new GenericContainer("postgres:13.12") .withExposedPorts(5432) .withEnv("POSTGRES_PASSWORD", "password") From 45605100697e6f0b9a3df63a357661261e546c9d Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Tue, 12 Sep 2023 12:16:13 +0100 Subject: [PATCH 075/128] Customize signup flow BB changes (#11706) * wip * wip * wip * wip --- packages/bbui/src/Banner/Banner.svelte | 4 +++ .../bbui/src/Notification/Notification.svelte | 6 ++++- .../Notification/NotificationDisplay.svelte | 3 ++- packages/bbui/src/Stores/banner.js | 1 + packages/bbui/src/Stores/notifications.js | 6 ++++- .../builder/src/pages/builder/_layout.svelte | 27 +++++++++++++++++++ 6 files changed, 44 insertions(+), 3 deletions(-) diff --git a/packages/bbui/src/Banner/Banner.svelte b/packages/bbui/src/Banner/Banner.svelte index 3810021a61..a04d469cc7 100644 --- a/packages/bbui/src/Banner/Banner.svelte +++ b/packages/bbui/src/Banner/Banner.svelte @@ -66,6 +66,10 @@ pointer-events: all; width: 100%; } + + .spectrum-Toast--neutral { + background-color: var(--grey-2); + } .spectrum-Button { border: 1px solid rgba(255, 255, 255, 0.2); } diff --git a/packages/bbui/src/Notification/Notification.svelte b/packages/bbui/src/Notification/Notification.svelte index eb2922a5de..26e60ed366 100644 --- a/packages/bbui/src/Notification/Notification.svelte +++ b/packages/bbui/src/Notification/Notification.svelte @@ -27,7 +27,11 @@
{message || ""}
{#if action} - + action(() => dispatch("dismiss"))} + >
{actionMessage}
{/if} diff --git a/packages/bbui/src/Notification/NotificationDisplay.svelte b/packages/bbui/src/Notification/NotificationDisplay.svelte index 0f7e93eb23..6b7e68cece 100644 --- a/packages/bbui/src/Notification/NotificationDisplay.svelte +++ b/packages/bbui/src/Notification/NotificationDisplay.svelte @@ -8,7 +8,7 @@
- {#each $notifications as { type, icon, message, id, dismissable, action, wide } (id)} + {#each $notifications as { type, icon, message, id, dismissable, action, actionMessage, wide } (id)}
notifications.dismiss(id)} /> diff --git a/packages/bbui/src/Stores/banner.js b/packages/bbui/src/Stores/banner.js index 1a0b2d9ecc..fc93e7be99 100644 --- a/packages/bbui/src/Stores/banner.js +++ b/packages/bbui/src/Stores/banner.js @@ -1,6 +1,7 @@ import { writable } from "svelte/store" export const BANNER_TYPES = { + NEUTRAL: "neutral", INFO: "info", NEGATIVE: "negative", WARNING: "warning", diff --git a/packages/bbui/src/Stores/notifications.js b/packages/bbui/src/Stores/notifications.js index 449d282f24..28331fffd8 100644 --- a/packages/bbui/src/Stores/notifications.js +++ b/packages/bbui/src/Stores/notifications.js @@ -27,7 +27,9 @@ export const createNotificationStore = () => { icon = "", autoDismiss = true, action = null, + actionMessage = null, wide = false, + dismissTimeout = NOTIFICATION_TIMEOUT, } ) => { if (block) { @@ -44,14 +46,16 @@ export const createNotificationStore = () => { icon, dismissable: !autoDismiss, action, + actionMessage, wide, + dismissTimeout, }, ] }) if (autoDismiss) { const timeoutId = setTimeout(() => { dismissNotification(_id) - }, NOTIFICATION_TIMEOUT) + }, dismissTimeout) timeoutIds.add(timeoutId) } } diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index b216958045..960822a39f 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -3,6 +3,7 @@ import { admin, auth, licensing } from "stores/portal" import { onMount } from "svelte" import { CookieUtils, Constants } from "@budibase/frontend-core" + import { banner, BANNER_TYPES } from "@budibase/bbui" import { API } from "api" import Branding from "./Branding.svelte" @@ -16,6 +17,32 @@ $: user = $auth.user $: useAccountPortal = cloud && !$admin.disableAccountPortal + let showVerificationPrompt = false + + const checkVerification = user => { + if (!showVerificationPrompt && user?.account?.verified === false) { + showVerificationPrompt = true + banner.queue([ + { + message: `Please verify your account. We've sent the verification link to ${user.email}`, + type: BANNER_TYPES.NEUTRAL, + showCloseButton: false, + extraButtonAction: () => { + fetch(`${$admin.accountPortalUrl}/api/auth/reset`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email: user.email }), + }) + }, + extraButtonText: "Resend email", + }, + ]) + } + } + + $: checkVerification(user) const validateTenantId = async () => { const host = window.location.host From 6e23d746117ce6b760a0c338ab79de85fd5a5da7 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 12 Sep 2023 11:16:28 +0000 Subject: [PATCH 076/128] Bump version to 2.10.3-alpha.1 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 1669e15246..ebdf2a4466 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.3-alpha.0", + "version": "2.10.3-alpha.1", "npmClient": "yarn", "packages": [ "packages/*" From aeac7aaa0c0f8845bbfd187e207795c25af7237d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 12 Sep 2023 13:54:39 +0100 Subject: [PATCH 077/128] Making sure that not all falsy values are considered invalid filter inputs. --- .../server/scripts/integrations/postgres/init.sql | 3 ++- packages/server/src/api/controllers/row/external.ts | 4 ++-- packages/server/src/api/controllers/row/utils.ts | 6 ++++++ yarn.lock | 13 +++++++++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/server/scripts/integrations/postgres/init.sql b/packages/server/scripts/integrations/postgres/init.sql index 6cb3f51269..f89ad2812d 100644 --- a/packages/server/scripts/integrations/postgres/init.sql +++ b/packages/server/scripts/integrations/postgres/init.sql @@ -1,7 +1,7 @@ SELECT 'CREATE DATABASE main' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'main')\gexec CREATE SCHEMA "test-1"; -CREATE TYPE person_job AS ENUM ('qa', 'programmer', 'designer'); +CREATE TYPE person_job AS ENUM ('qa', 'programmer', 'designer', 'support'); CREATE TABLE Persons ( PersonID SERIAL PRIMARY KEY, LastName varchar(255), @@ -51,6 +51,7 @@ CREATE TABLE CompositeTable ( ); INSERT INTO Persons (FirstName, LastName, Address, City, Type) VALUES ('Mike', 'Hughes', '123 Fake Street', 'Belfast', 'qa'); INSERT INTO Persons (FirstName, LastName, Address, City, Type) VALUES ('John', 'Smith', '64 Updown Road', 'Dublin', 'programmer'); +INSERT INTO Persons (FirstName, LastName, Address, City, Type, Age) VALUES ('Foo', 'Bar', 'Foo Street', 'Bartown', 'support', 0); INSERT INTO Tasks (ExecutorID, QaID, TaskName, Completed) VALUES (1, 2, 'assembling', TRUE); INSERT INTO Tasks (ExecutorID, QaID, TaskName, Completed) VALUES (2, 1, 'processing', FALSE); INSERT INTO Products (ProductName) VALUES ('Computers'); diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 491cbfa8f9..44921a5114 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -32,12 +32,12 @@ export async function handleRequest( } // @ts-ignore for (let [key, value] of Object.entries(opts.filters[filterField])) { - if (!value || value === "") { + if (utils.invalidFilter(value)) { // @ts-ignore delete opts.filters[filterField][key] } } - } + } if ( diff --git a/packages/server/src/api/controllers/row/utils.ts b/packages/server/src/api/controllers/row/utils.ts index e85ec4553c..12c84bfb7b 100644 --- a/packages/server/src/api/controllers/row/utils.ts +++ b/packages/server/src/api/controllers/row/utils.ts @@ -139,3 +139,9 @@ export async function validate({ } return { valid: Object.keys(errors).length === 0, errors } } + +// don't do a pure falsy check, as 0 is included +// https://github.com/Budibase/budibase/issues/10118 +export function invalidFilter(value: any) { + return value == null || value === "" +} diff --git a/yarn.lock b/yarn.lock index ab86a87560..8c93661665 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6269,6 +6269,14 @@ "@types/tedious" "*" tarn "^3.0.1" +"@types/node-fetch@2.6.1": + version "2.6.1" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.1.tgz#8f127c50481db65886800ef496f20bbf15518975" + integrity sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node-fetch@2.6.4": version "2.6.4" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" @@ -6290,6 +6298,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== +"@types/node@14.18.20": + version "14.18.20" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.20.tgz#268f028b36eaf51181c3300252f605488c4f0650" + integrity sha512-Q8KKwm9YqEmUBRsqJ2GWJDtXltBDxTdC4m5vTdXBolu2PeQh8LX+f6BTwU+OuXPu37fLxoN6gidqBmnky36FXA== + "@types/node@16.9.1": version "16.9.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" From aed5694ac2715dae82e5f43f314d16b5647806a7 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 12 Sep 2023 14:06:20 +0100 Subject: [PATCH 078/128] Adding dedicated function for removing empty filters. --- .../src/api/controllers/row/external.ts | 15 +------- .../server/src/api/controllers/row/utils.ts | 38 +++++++++++++++++-- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index 44921a5114..a04584e6bd 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -18,6 +18,7 @@ import { import sdk from "../../../sdk" import * as utils from "./utils" import { dataFilters } from "@budibase/shared-core" +import { removeEmptyFilters } from "./utils" export async function handleRequest( operation: Operation, @@ -26,20 +27,8 @@ export async function handleRequest( ) { // make sure the filters are cleaned up, no empty strings for equals, fuzzy or string if (opts && opts.filters) { - for (let filterField of NoEmptyFilterStrings) { - if (!opts.filters[filterField]) { - continue - } - // @ts-ignore - for (let [key, value] of Object.entries(opts.filters[filterField])) { - if (utils.invalidFilter(value)) { - // @ts-ignore - delete opts.filters[filterField][key] - } - } - + opts.filters = utils.removeEmptyFilters(opts.filters) } - if ( !dataFilters.hasFilters(opts?.filters) && opts?.filters?.onEmptyFilter === EmptyFilterOption.RETURN_NONE diff --git a/packages/server/src/api/controllers/row/utils.ts b/packages/server/src/api/controllers/row/utils.ts index 12c84bfb7b..cc27f4c2a3 100644 --- a/packages/server/src/api/controllers/row/utils.ts +++ b/packages/server/src/api/controllers/row/utils.ts @@ -1,8 +1,15 @@ import { InternalTables } from "../../../db/utils" import * as userController from "../user" import { context } from "@budibase/backend-core" -import { Ctx, FieldType, Row, Table, UserCtx } from "@budibase/types" -import { FieldTypes } from "../../../constants" +import { + Ctx, + FieldType, + Row, + SearchFilters, + Table, + UserCtx, +} from "@budibase/types" +import { FieldTypes, NoEmptyFilterStrings } from "../../../constants" import sdk from "../../../sdk" import validateJs from "validate.js" @@ -142,6 +149,29 @@ export async function validate({ // don't do a pure falsy check, as 0 is included // https://github.com/Budibase/budibase/issues/10118 -export function invalidFilter(value: any) { - return value == null || value === "" +export function removeEmptyFilters(filters: SearchFilters) { + for (let filterField of NoEmptyFilterStrings) { + if (!filters[filterField]) { + continue + } + + for (let filterType of Object.keys(filters)) { + if (filterType !== filterField) { + continue + } + // don't know which one we're checking, type could be anything + const value = filters[filterType] as unknown + if (typeof value === "object") { + for (let [key, value] of Object.entries( + filters[filterType] as object + )) { + if (value == null || value === "") { + // @ts-ignore + delete filters[filterField][key] + } + } + } + } + } + return filters } From 80e217afda1325ccf8b23f8650eead02a26fb0d0 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 12 Sep 2023 14:23:08 +0100 Subject: [PATCH 079/128] Quick test to avoid scenario in future. --- .../api/controllers/row/tests/utils.spec.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 packages/server/src/api/controllers/row/tests/utils.spec.ts diff --git a/packages/server/src/api/controllers/row/tests/utils.spec.ts b/packages/server/src/api/controllers/row/tests/utils.spec.ts new file mode 100644 index 0000000000..e0ad637e9d --- /dev/null +++ b/packages/server/src/api/controllers/row/tests/utils.spec.ts @@ -0,0 +1,21 @@ +import * as utils from "../utils" + +describe("removeEmptyFilters", () => { + it("0 should not be removed", () => { + const filters = utils.removeEmptyFilters({ + equal: { + column: 0, + }, + }) + expect((filters.equal as any).column).toBe(0) + }) + + it("empty string should be removed", () => { + const filters = utils.removeEmptyFilters({ + equal: { + column: "", + }, + }) + expect(Object.values(filters.equal as any).length).toBe(0) + }) +}) From 9a8b43b218ce7274c0d5b96d45e79da8dc7aab2b Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Tue, 12 Sep 2023 15:39:25 +0000 Subject: [PATCH 080/128] Bump version to 2.10.3-alpha.2 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index ebdf2a4466..e070f6579c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.3-alpha.1", + "version": "2.10.3-alpha.2", "npmClient": "yarn", "packages": [ "packages/*" From 88c68cfe5858e758d80fbeac2df3eb3dd14901bf Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 18:07:20 +0200 Subject: [PATCH 081/128] Fetch relationships on external row find --- packages/server/src/api/controllers/row/external.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index acae075165..3881d1dd08 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -125,7 +125,9 @@ export async function save(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) + const row = await sdk.rows.external.getRow(tableId, id, { + relationships: true, + }) if (!row) { ctx.throw(404) From a537b17b239d8c8b166ba0e1e0cbb898a044f870 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 18:07:50 +0200 Subject: [PATCH 082/128] Run attachments only on internal --- .../server/src/api/routes/tests/row.spec.ts | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 5fa3745987..90eb4820b8 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -853,31 +853,32 @@ describe.each([ }) }) - describe("attachments", () => { - it("should allow enriching attachment rows", async () => { - const table = await config.createAttachmentTable() - const attachmentId = `${structures.uuid()}.csv` - const row = await createRow(table._id, { - name: "test", - description: "test", - attachment: [ - { - key: `${config.getAppId()}/attachments/${attachmentId}`, - }, - ], - tableId: table._id, - }) - // the environment needs configured for this - await setup.switchToSelfHosted(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}` - ) + isInternal && + describe("attachments", () => { + it("should allow enriching attachment rows", async () => { + const table = await config.createAttachmentTable() + const attachmentId = `${structures.uuid()}.csv` + const row = await createRow(table._id, { + name: "test", + description: "test", + attachment: [ + { + key: `${config.getAppId()}/attachments/${attachmentId}`, + }, + ], + tableId: table._id, + }) + // the environment needs configured for this + await setup.switchToSelfHosted(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}` + ) + }) }) }) }) - }) describe("exportData", () => { it("should allow exporting all columns", async () => { From 8b644555e3e108bebdfa7f5bbcac835c0f1705a5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 18:09:09 +0200 Subject: [PATCH 083/128] Fetch primaryDisplay --- packages/server/src/api/routes/tests/row.spec.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 90eb4820b8..0bf678ef93 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -70,6 +70,7 @@ describe.each([ name: generator.guid(), type: "table", primary: ["id"], + primaryDisplay: "name", schema: { id: { type: FieldType.AUTO, @@ -801,6 +802,7 @@ describe.each([ name: generator.guid(), type: "table", primary: ["id"], + primaryDisplay: "id", schema: { id: { type: FieldType.AUTO, @@ -836,7 +838,10 @@ describe.each([ .expect("Content-Type", /json/) .expect(200) expect(resBasic.body.link.length).toBe(1) - expect(resBasic.body.link[0]).toEqual({ _id: firstRow._id }) + expect(resBasic.body.link[0]).toEqual({ + _id: firstRow._id, + primaryDisplay: firstRow.name, + }) // test full enrichment const resEnriched = await request From dd47c79ef92921c560dcd8949f0cdc26be73402d Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 18:09:42 +0200 Subject: [PATCH 084/128] Replace guids by words --- packages/server/src/api/routes/tests/row.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 0bf678ef93..fdf1a861db 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -67,7 +67,7 @@ describe.each([ const generateTableConfig: () => Promise = async () => { return { - name: generator.guid(), + name: generator.word(), type: "table", primary: ["id"], primaryDisplay: "name", @@ -799,7 +799,7 @@ describe.each([ config.getTenantId(), async () => { const linkedTable = await config.createLinkedTable({ - name: generator.guid(), + name: generator.word(), type: "table", primary: ["id"], primaryDisplay: "id", @@ -933,7 +933,7 @@ describe.each([ describe("view 2.0", () => { async function userTable(): Promise
{ return { - name: `users_${generator.guid()}`, + name: `users_${generator.word()}`, type: "table", primary: ["id"], schema: { @@ -1120,7 +1120,7 @@ describe.each([ const viewSchema = { age: { visible: true }, name: { visible: true } } async function userTable(): Promise
{ return { - name: `users_${generator.guid()}`, + name: `users_${generator.word()}`, type: "table", primary: ["id"], schema: { From 2dd2dcc2cb0dabb3416157ef6d9c665943b7383c Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Tue, 12 Sep 2023 17:26:41 +0100 Subject: [PATCH 085/128] Role fixes --- .../app/[application]/_components/BuilderSidePanel.svelte | 2 +- .../src/pages/builder/portal/users/users/[userId].svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 7c4d3db7ce..c93a41f541 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -126,7 +126,7 @@ user, prodAppId ) - const isAppBuilder = sdk.users.hasAppBuilderPermissions(user, prodAppId) + const isAppBuilder = user.builder?.apps?.includes(prodAppId) let role if (isAdminOrGlobalBuilder) { role = Constants.Roles.ADMIN diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index 2a74cd9de5..ec10ec8316 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -111,7 +111,7 @@ }) } return availableApps.map(app => { - const prodAppId = apps.getProdAppID(app.appId) + const prodAppId = apps.getProdAppID(app.devId) return { name: app.name, devId: app.devId, From cb762cc336237e87a695700c4cecba8c83655ebe Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 19:03:24 +0200 Subject: [PATCH 086/128] Use api for testing --- .../server/src/api/routes/tests/row.spec.ts | 95 +++++++++++-------- .../server/src/tests/utilities/api/viewV2.ts | 4 +- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index fdf1a861db..2f1647b994 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -177,11 +177,12 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() + const tableConfig = await generateTableConfig() const newTable = await config.createTable({ - ...table, + ...tableConfig, name: "TestTableAuto", schema: { - ...table.schema, + ...tableConfig.schema, "Row ID": { name: "Row ID", type: FieldType.NUMBER, @@ -356,7 +357,7 @@ describe.each([ inclusion: ["Alpha", "Beta", "Gamma"], }, }, - table = await config.createTable({ + table = await config.api.table.create({ name: "TestTable2", type: "table", schema: { @@ -392,6 +393,7 @@ describe.each([ optsFieldNull: optsField, optsFieldStrKnown: optsField, }, + ...(await tableDatasourceConfig()), }) row = { @@ -470,7 +472,7 @@ describe.each([ }) describe("view save", () => { - function orderTable(): Table { + async function orderTable(): Promise
{ return { name: "orders", primary: ["OrderID"], @@ -488,11 +490,12 @@ describe.each([ name: "Story", }, }, + ...(await tableDatasourceConfig()), } } it("views have extra data trimmed", async () => { - const table = await config.createTable(orderTable()) + const table = await config.api.table.create(await orderTable()) const createViewResponse = await config.api.viewV2.create({ tableId: table._id, @@ -887,7 +890,7 @@ describe.each([ describe("exportData", () => { it("should allow exporting all columns", async () => { - const existing = await config.createRow() + const existing = await createRow() const res = await request .post(`/api/${table._id}/rows/exportRows?format=json`) .set(config.defaultHeaders()) @@ -910,7 +913,7 @@ describe.each([ }) it("should allow exporting only certain columns", async () => { - const existing = await config.createRow() + const existing = await createRow() const res = await request .post(`/api/${table._id}/rows/exportRows?format=json`) .set(config.defaultHeaders()) @@ -980,7 +983,7 @@ describe.each([ describe("create", () => { it("should persist a new row with only the provided view fields", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const view = await config.api.viewV2.create({ tableId: table._id!, schema: { @@ -992,7 +995,7 @@ describe.each([ const data = randomRowData() const newRow = await config.api.row.save(view.id, { - tableId: config.table!._id, + tableId: table!._id, _viewId: view.id, ...data, }) @@ -1002,7 +1005,7 @@ describe.each([ name: data.name, surname: data.surname, address: data.address, - tableId: config.table!._id, + tableId: table!._id, _id: newRow._id, _rev: newRow._rev, id: newRow.id, @@ -1016,7 +1019,7 @@ describe.each([ describe("patch", () => { it("should update only the view fields for a row", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1058,7 +1061,7 @@ describe.each([ describe("destroy", () => { it("should be able to delete a row", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1083,7 +1086,7 @@ describe.each([ }) it("should be able to delete multiple rows", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1148,13 +1151,17 @@ describe.each([ } it("returns empty rows from view when no schema is passed", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { - rows.push(await config.createRow({ tableId: table._id })) + rows.push( + await config.api.row.save(table._id!, { tableId: table._id }) + ) } - const createViewResponse = await config.api.viewV2.create() + const createViewResponse = await config.api.viewV2.create({ + tableId: table._id, + }) const response = await config.api.viewV2.search(createViewResponse.id) expect(response.body.rows).toHaveLength(10) @@ -1174,10 +1181,10 @@ describe.each([ }) it("searching respects the view filters", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const expectedRows = [] for (let i = 0; i < 10; i++) - await config.createRow({ + await config.api.row.save(table._id!, { tableId: table._id, name: generator.name(), age: generator.integer({ min: 10, max: 30 }), @@ -1185,7 +1192,7 @@ describe.each([ for (let i = 0; i < 5; i++) expectedRows.push( - await config.createRow({ + await config.api.row.save(table._id!, { tableId: table._id, name: generator.name(), age: 40, @@ -1193,6 +1200,7 @@ describe.each([ ) const createViewResponse = await config.api.viewV2.create({ + tableId: table._id!, query: [{ operator: "equal", field: "age", value: 40 }], schema: viewSchema, }) @@ -1289,7 +1297,7 @@ describe.each([ it.each(sortTestOptions)( "allow sorting (%s)", async (sortParams, expected) => { - await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const users = [ { name: "Alice", age: 25 }, { name: "Bob", age: 30 }, @@ -1297,13 +1305,14 @@ describe.each([ { name: "Danny", age: 15 }, ] for (const user of users) { - await config.createRow({ - tableId: config.table!._id, + await config.api.row.save(table._id!, { + tableId: table._id, ...user, }) } const createViewResponse = await config.api.viewV2.create({ + tableId: table._id, sort: sortParams, schema: viewSchema, }) @@ -1320,7 +1329,7 @@ describe.each([ it.each(sortTestOptions)( "allow override the default view sorting (%s)", async (sortParams, expected) => { - await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const users = [ { name: "Alice", age: 25 }, { name: "Bob", age: 30 }, @@ -1328,13 +1337,14 @@ describe.each([ { name: "Danny", age: 15 }, ] for (const user of users) { - await config.createRow({ - tableId: config.table!._id, + await config.api.row.save(table._id!, { + tableId: table._id, ...user, }) } const createViewResponse = await config.api.viewV2.create({ + tableId: table._id, sort: { field: "name", order: SortOrder.ASCENDING, @@ -1361,11 +1371,11 @@ describe.each([ ) it("when schema is defined, defined columns and row attributes are returned", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push( - await config.createRow({ + await config.api.row.save(table._id!, { tableId: table._id, name: generator.name(), age: generator.age(), @@ -1374,6 +1384,7 @@ describe.each([ } const view = await config.api.viewV2.create({ + tableId: table._id, schema: { name: { visible: true } }, }) const response = await config.api.viewV2.search(view.id) @@ -1393,23 +1404,27 @@ describe.each([ }) it("views without data can be returned", async () => { - await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) - const createViewResponse = await config.api.viewV2.create() + const createViewResponse = await config.api.viewV2.create({ + tableId: table._id, + }) const response = await config.api.viewV2.search(createViewResponse.id) expect(response.body.rows).toHaveLength(0) }) it("respects the limit parameter", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { - rows.push(await config.createRow({ tableId: table._id })) + rows.push(await createRow(table._id, { tableId: table._id })) } const limit = generator.integer({ min: 1, max: 8 }) - const createViewResponse = await config.api.viewV2.create() + const createViewResponse = await config.api.viewV2.create({ + tableId: table._id, + }) const response = await config.api.viewV2.search(createViewResponse.id, { limit, query: {}, @@ -1419,13 +1434,15 @@ describe.each([ }) it("can handle pagination", async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { - rows.push(await config.createRow({ tableId: table._id })) + rows.push(await createRow(table._id, { tableId: table._id })) } - const createViewResponse = await config.api.viewV2.create() + const createViewResponse = await config.api.viewV2.create({ + tableId: table._id, + }) const allRows = (await config.api.viewV2.search(createViewResponse.id)) .body.rows @@ -1483,13 +1500,15 @@ describe.each([ let tableId: string beforeAll(async () => { - const table = await config.createTable(await userTable()) + const table = await config.api.table.create(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { - rows.push(await config.createRow({ tableId: table._id })) + rows.push(await createRow(table._id, { tableId: table._id })) } - const createViewResponse = await config.api.viewV2.create() + const createViewResponse = await config.api.viewV2.create({ + tableId: table._id, + }) tableId = table._id! viewId = createViewResponse.id diff --git a/packages/server/src/tests/utilities/api/viewV2.ts b/packages/server/src/tests/utilities/api/viewV2.ts index 0682361e16..92a6d394bf 100644 --- a/packages/server/src/tests/utilities/api/viewV2.ts +++ b/packages/server/src/tests/utilities/api/viewV2.ts @@ -23,8 +23,8 @@ export class ViewV2API extends TestAPI { if (!tableId && !this.config.table) { throw "Test requires table to be configured." } - const table = this.config.table - tableId = table!._id! + + tableId = tableId || this.config.table!._id! const view = { tableId, name: generator.guid(), From 9c37f2f05690e7d145ed6f475c0ce9a3b2f0f45a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 19:18:19 +0200 Subject: [PATCH 087/128] Use configs --- .../server/src/api/routes/tests/row.spec.ts | 84 +++++++------------ 1 file changed, 31 insertions(+), 53 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 2f1647b994..9282d5c83b 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -41,31 +41,20 @@ describe.each([ let request = setup.getRequest() let config = setup.getConfig() let table: Table - let row: Row - let datasource: Datasource | undefined afterAll(setup.afterAll) beforeAll(async () => { await config.init() + + if (dsProvider) { + await config.createDatasource({ + datasource: await dsProvider.getDsConfig(), + }) + } }) - const tableDatasourceConfig = async () => { - const result: Partial = {} - if (dsProvider) { - datasource = await config.api.datasource.create( - await dsProvider.getDsConfig() - ) - - result.sourceId = datasource._id - if (datasource.plus) { - result.type = "external" - } - } - return result - } - - const generateTableConfig: () => Promise = async () => { + const generateTableConfig: () => SaveTableRequest = () => { return { name: generator.word(), type: "table", @@ -95,17 +84,13 @@ describe.each([ }, }, }, - ...(await tableDatasourceConfig()), } } beforeEach(async () => { mocks.licenses.useCloudFree() - const tableConfig = await generateTableConfig() - table = await config.api.table.create(tableConfig) - config.table = table - config.datasource = datasource - row = basicRow(table._id!) + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) }) const loadRow = async (id: string, tbl_Id: string, status = 200) => @@ -159,8 +144,8 @@ describe.each([ const queryUsage = await getQueryUsage() const res = await request - .post(`/api/${row.tableId}/rows`) - .send(row) + .post(`/api/${config.table!._id}/rows`) + .send(basicRow(config.table!._id!)) .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) @@ -177,7 +162,7 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const tableConfig = await generateTableConfig() + const tableConfig = generateTableConfig() const newTable = await config.createTable({ ...tableConfig, name: "TestTableAuto", @@ -265,10 +250,7 @@ describe.each([ .expect(200) expect(res.body).toEqual({ - ...row, - _id: existing._id, - _rev: existing._rev, - id: existing.id, + ...existing, ...defaultRowFields, }) await assertQueryUsage(queryUsage + 1) @@ -280,7 +262,7 @@ describe.each([ name: "Second Contact", status: "new", } - await createRow() + const firstRow = await createRow() await createRow(table._id, newRow) const queryUsage = await getQueryUsage() @@ -292,7 +274,7 @@ describe.each([ expect(res.body.length).toBe(2) expect(res.body.find((r: Row) => r.name === newRow.name)).toBeDefined() - expect(res.body.find((r: Row) => r.name === row.name)).toBeDefined() + expect(res.body.find((r: Row) => r.name === firstRow.name)).toBeDefined() await assertQueryUsage(queryUsage + 1) }) @@ -357,7 +339,7 @@ describe.each([ inclusion: ["Alpha", "Beta", "Gamma"], }, }, - table = await config.api.table.create({ + table = await config.createTable({ name: "TestTable2", type: "table", schema: { @@ -393,10 +375,9 @@ describe.each([ optsFieldNull: optsField, optsFieldStrKnown: optsField, }, - ...(await tableDatasourceConfig()), }) - row = { + const row = { name: "Test Row", stringUndefined: undefined, stringNull: null, @@ -490,12 +471,11 @@ describe.each([ name: "Story", }, }, - ...(await tableDatasourceConfig()), } } it("views have extra data trimmed", async () => { - const table = await config.api.table.create(await orderTable()) + const table = await config.createTable(await orderTable()) const createViewResponse = await config.api.viewV2.create({ tableId: table._id, @@ -969,7 +949,6 @@ describe.each([ name: "jobTitle", }, }, - ...(await tableDatasourceConfig()), } } @@ -983,7 +962,7 @@ describe.each([ describe("create", () => { it("should persist a new row with only the provided view fields", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const view = await config.api.viewV2.create({ tableId: table._id!, schema: { @@ -1019,7 +998,7 @@ describe.each([ describe("patch", () => { it("should update only the view fields for a row", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1061,7 +1040,7 @@ describe.each([ describe("destroy", () => { it("should be able to delete a row", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1086,7 +1065,7 @@ describe.each([ }) it("should be able to delete multiple rows", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const tableId = table._id! const view = await config.api.viewV2.create({ tableId, @@ -1146,12 +1125,11 @@ describe.each([ constraints: {}, }, }, - ...(await tableDatasourceConfig()), } } it("returns empty rows from view when no schema is passed", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push( @@ -1181,7 +1159,7 @@ describe.each([ }) it("searching respects the view filters", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const expectedRows = [] for (let i = 0; i < 10; i++) await config.api.row.save(table._id!, { @@ -1297,7 +1275,7 @@ describe.each([ it.each(sortTestOptions)( "allow sorting (%s)", async (sortParams, expected) => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const users = [ { name: "Alice", age: 25 }, { name: "Bob", age: 30 }, @@ -1329,7 +1307,7 @@ describe.each([ it.each(sortTestOptions)( "allow override the default view sorting (%s)", async (sortParams, expected) => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const users = [ { name: "Alice", age: 25 }, { name: "Bob", age: 30 }, @@ -1371,7 +1349,7 @@ describe.each([ ) it("when schema is defined, defined columns and row attributes are returned", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push( @@ -1404,7 +1382,7 @@ describe.each([ }) it("views without data can be returned", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const createViewResponse = await config.api.viewV2.create({ tableId: table._id, @@ -1415,7 +1393,7 @@ describe.each([ }) it("respects the limit parameter", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push(await createRow(table._id, { tableId: table._id })) @@ -1434,7 +1412,7 @@ describe.each([ }) it("can handle pagination", async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push(await createRow(table._id, { tableId: table._id })) @@ -1500,7 +1478,7 @@ describe.each([ let tableId: string beforeAll(async () => { - const table = await config.api.table.create(await userTable()) + const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { rows.push(await createRow(table._id, { tableId: table._id })) From 3843581e56d7e71eeafb80c6ebf2e5b68ffcea76 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 19:31:58 +0200 Subject: [PATCH 088/128] Unify --- .../server/src/api/routes/tests/row.spec.ts | 63 +++++++++---------- .../src/tests/utilities/TestConfiguration.ts | 10 +-- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 9282d5c83b..7488056bc3 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -127,9 +127,6 @@ describe.each([ expect(usage).toBe(expected) } - const createRow = (tableId = table._id!, row?: SaveRowRequest) => - config.api.row.save(tableId, row || basicRow(table._id!)) - const defaultRowFields = isInternal ? { type: "row", @@ -215,7 +212,7 @@ describe.each([ }) it("updates a row successfully", async () => { - const existing = await createRow() + const existing = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -240,7 +237,7 @@ describe.each([ }) it("should load a row", async () => { - const existing = await createRow() + const existing = await config.createRow() const queryUsage = await getQueryUsage() const res = await request @@ -262,8 +259,8 @@ describe.each([ name: "Second Contact", status: "new", } - const firstRow = await createRow() - await createRow(table._id, newRow) + const firstRow = await config.createRow() + await config.createRow(newRow) const queryUsage = await getQueryUsage() const res = await request @@ -279,7 +276,7 @@ describe.each([ }) it("load should return 404 when row does not exist", async () => { - await createRow() + await config.createRow() const queryUsage = await getQueryUsage() await config.api.row.get(table._id!, "1234567", { @@ -513,7 +510,7 @@ describe.each([ describe("patch", () => { it("should update only the fields that are supplied", async () => { - const existing = await createRow() + const existing = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -540,7 +537,7 @@ describe.each([ }) it("should throw an error when given improper types", async () => { - const existing = await createRow() + const existing = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -562,7 +559,7 @@ describe.each([ describe("destroy", () => { it("should be able to delete a row", async () => { - const createdRow = await createRow() + const createdRow = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -624,8 +621,8 @@ describe.each([ describe("bulkDelete", () => { it("should be able to delete a bulk set of rows", async () => { - const row1 = await createRow() - const row2 = await createRow() + const row1 = await config.createRow() + const row2 = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -645,9 +642,9 @@ describe.each([ }) it("should be able to delete a variety of row set types", async () => { - const row1 = await createRow() - const row2 = await createRow() - const row3 = await createRow() + const row1 = await config.createRow() + const row2 = await config.createRow() + const row3 = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -667,7 +664,7 @@ describe.each([ }) it("should accept a valid row object and delete the row", async () => { - const row1 = await createRow() + const row1 = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -724,7 +721,7 @@ describe.each([ isInternal && describe("fetchView", () => { it("should be able to fetch tables contents via 'view'", async () => { - const row = await createRow() + const row = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -759,7 +756,7 @@ describe.each([ filters: [], schema: {}, }) - const row = await createRow() + const row = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -797,12 +794,12 @@ describe.each([ }, }, }) - const firstRow = await createRow(table._id, { + const firstRow = await config.createRow({ name: "Test Contact", description: "original description", tableId: table._id, }) - const secondRow = await createRow(linkedTable._id, { + const secondRow = await config.createRow({ name: "Test 2", description: "og desc", link: [{ _id: firstRow._id }], @@ -846,7 +843,7 @@ describe.each([ it("should allow enriching attachment rows", async () => { const table = await config.createAttachmentTable() const attachmentId = `${structures.uuid()}.csv` - const row = await createRow(table._id, { + const row = await config.createRow({ name: "test", description: "test", attachment: [ @@ -870,7 +867,7 @@ describe.each([ describe("exportData", () => { it("should allow exporting all columns", async () => { - const existing = await createRow() + const existing = await config.createRow() const res = await request .post(`/api/${table._id}/rows/exportRows?format=json`) .set(config.defaultHeaders()) @@ -893,7 +890,7 @@ describe.each([ }) it("should allow exporting only certain columns", async () => { - const existing = await createRow() + const existing = await config.createRow() const res = await request .post(`/api/${table._id}/rows/exportRows?format=json`) .set(config.defaultHeaders()) @@ -1050,7 +1047,7 @@ describe.each([ }, }) - const createdRow = await createRow() + const createdRow = await config.createRow() const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -1075,11 +1072,11 @@ describe.each([ }, }) - const rows = [ - await createRow(tableId), - await createRow(tableId), - await createRow(tableId), - ] + const rows = await Promise.all([ + config.createRow(), + config.createRow(), + config.createRow(), + ]) const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -1396,7 +1393,7 @@ describe.each([ const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { - rows.push(await createRow(table._id, { tableId: table._id })) + rows.push(await config.createRow()) } const limit = generator.integer({ min: 1, max: 8 }) @@ -1415,7 +1412,7 @@ describe.each([ const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { - rows.push(await createRow(table._id, { tableId: table._id })) + rows.push(await config.createRow()) } const createViewResponse = await config.api.viewV2.create({ @@ -1481,7 +1478,7 @@ describe.each([ const table = await config.createTable(await userTable()) const rows = [] for (let i = 0; i < 10; i++) { - rows.push(await createRow(table._id, { tableId: table._id })) + rows.push(await config.createRow()) } const createViewResponse = await config.api.viewV2.create({ diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 030a08cee7..119a926085 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -533,7 +533,7 @@ class TestConfiguration { { skipReassigning } = { skipReassigning: false } ): Promise
{ config = config || basicTable() - const response = await this._req(config, null, controllers.table.save) + const response = await this.api.table.create(config) if (!skipReassigning) { this.table = response } @@ -694,12 +694,8 @@ class TestConfiguration { datasource: Datasource }): Promise { config = config || basicDatasource() - const response = await this._req( - { ...config }, - null, - controllers.datasource.save - ) - this.datasource = response.datasource + const response = await this.api.datasource.create({ ...config.datasource }) + this.datasource = response return this.datasource! } From fccb2f625c902b5699d1f815a15c1fc517b988ad Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 19:39:40 +0200 Subject: [PATCH 089/128] Use configs --- .../server/src/api/routes/tests/row.spec.ts | 48 ++++++------------- .../src/tests/utilities/TestConfiguration.ts | 21 ++++++++ 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 7488056bc3..ee3f12b449 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -474,8 +474,8 @@ describe.each([ it("views have extra data trimmed", async () => { const table = await config.createTable(await orderTable()) - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id, + const createViewResponse = await config.createView({ + name: generator.word(), schema: { Country: { visible: true, @@ -960,8 +960,7 @@ describe.each([ describe("create", () => { it("should persist a new row with only the provided view fields", async () => { const table = await config.createTable(await userTable()) - const view = await config.api.viewV2.create({ - tableId: table._id!, + const view = await config.createView({ schema: { name: { visible: true }, surname: { visible: true }, @@ -997,8 +996,7 @@ describe.each([ it("should update only the view fields for a row", async () => { const table = await config.createTable(await userTable()) const tableId = table._id! - const view = await config.api.viewV2.create({ - tableId, + const view = await config.createView({ schema: { name: { visible: true }, address: { visible: true }, @@ -1039,8 +1037,7 @@ describe.each([ it("should be able to delete a row", async () => { const table = await config.createTable(await userTable()) const tableId = table._id! - const view = await config.api.viewV2.create({ - tableId, + const view = await config.createView({ schema: { name: { visible: true }, address: { visible: true }, @@ -1064,8 +1061,7 @@ describe.each([ it("should be able to delete multiple rows", async () => { const table = await config.createTable(await userTable()) const tableId = table._id! - const view = await config.api.viewV2.create({ - tableId, + const view = await config.createView({ schema: { name: { visible: true }, address: { visible: true }, @@ -1134,9 +1130,7 @@ describe.each([ ) } - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id, - }) + const createViewResponse = await config.createView() const response = await config.api.viewV2.search(createViewResponse.id) expect(response.body.rows).toHaveLength(10) @@ -1174,8 +1168,7 @@ describe.each([ }) ) - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id!, + const createViewResponse = await config.createView({ query: [{ operator: "equal", field: "age", value: 40 }], schema: viewSchema, }) @@ -1286,8 +1279,7 @@ describe.each([ }) } - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id, + const createViewResponse = await config.createView({ sort: sortParams, schema: viewSchema, }) @@ -1318,8 +1310,7 @@ describe.each([ }) } - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id, + const createViewResponse = await config.createView({ sort: { field: "name", order: SortOrder.ASCENDING, @@ -1358,8 +1349,7 @@ describe.each([ ) } - const view = await config.api.viewV2.create({ - tableId: table._id, + const view = await config.createView({ schema: { name: { visible: true } }, }) const response = await config.api.viewV2.search(view.id) @@ -1381,9 +1371,7 @@ describe.each([ it("views without data can be returned", async () => { const table = await config.createTable(await userTable()) - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id, - }) + const createViewResponse = await config.createView() const response = await config.api.viewV2.search(createViewResponse.id) expect(response.body.rows).toHaveLength(0) @@ -1397,9 +1385,7 @@ describe.each([ } const limit = generator.integer({ min: 1, max: 8 }) - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id, - }) + const createViewResponse = await config.createView() const response = await config.api.viewV2.search(createViewResponse.id, { limit, query: {}, @@ -1415,9 +1401,7 @@ describe.each([ rows.push(await config.createRow()) } - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id, - }) + const createViewResponse = await config.createView() const allRows = (await config.api.viewV2.search(createViewResponse.id)) .body.rows @@ -1481,9 +1465,7 @@ describe.each([ rows.push(await config.createRow()) } - const createViewResponse = await config.api.viewV2.create({ - tableId: table._id, - }) + const createViewResponse = await config.createView() tableId = table._id! viewId = createViewResponse.id diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 119a926085..fbb6e05c57 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -53,6 +53,8 @@ import { View, FieldType, RelationshipType, + ViewV2, + CreateViewRequest, } from "@budibase/types" import API from "./api" @@ -651,6 +653,25 @@ class TestConfiguration { return this._req(view, null, controllers.view.v1.save) } + async createView( + config?: Omit & { + name?: string + tableId?: string + } + ) { + if (!this.table && !config?.tableId) { + throw "Test requires table to be configured." + } + + const view: CreateViewRequest = { + ...config, + tableId: config?.tableId || this.table!._id!, + name: config?.name || generator.word(), + } + + return await this.api.viewV2.create(view) + } + // AUTOMATION async createAutomation(config?: any) { From f0872c1fa3135bd6b1cd6e976d8c0c9a1ec75790 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 19:59:37 +0200 Subject: [PATCH 090/128] Improve api --- packages/server/src/tests/utilities/api/row.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/server/src/tests/utilities/api/row.ts b/packages/server/src/tests/utilities/api/row.ts index c6ef4606d2..2f6760ebeb 100644 --- a/packages/server/src/tests/utilities/api/row.ts +++ b/packages/server/src/tests/utilities/api/row.ts @@ -22,6 +22,21 @@ export class RowAPI extends TestAPI { return request } + getEnriched = async ( + sourceId: string, + rowId: string, + { expectStatus } = { expectStatus: 200 } + ) => { + const request = this.request + .get(`/api/${sourceId}/rows/${rowId}/enrich`) + .set(this.config.defaultHeaders()) + .expect(expectStatus) + if (expectStatus !== 404) { + request.expect("Content-Type", /json/) + } + return request + } + save = async ( sourceId: string, row: SaveRowRequest, @@ -51,7 +66,7 @@ export class RowAPI extends TestAPI { delete = async ( sourceId: string, - rows: Row[], + rows: Row | string | (Row | string)[], { expectStatus } = { expectStatus: 200 } ) => { return this.request From 458de1282ec1ab6cf4b93f5269464013529fd2df Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 20:17:21 +0200 Subject: [PATCH 091/128] Use api for testing --- .../server/src/api/routes/tests/row.spec.ts | 2 -- .../server/src/api/routes/tests/table.spec.ts | 12 ++++++----- .../src/api/routes/tests/viewV2.spec.ts | 10 ++++++--- .../src/integration-test/postgres.spec.ts | 2 +- .../src/tests/utilities/TestConfiguration.ts | 21 ++++--------------- .../src/tests/utilities/api/datasource.ts | 17 +++++++++++++++ 6 files changed, 36 insertions(+), 28 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index ee3f12b449..7ec2ef8ef9 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -6,13 +6,11 @@ import * as setup from "./utilities" import { context, roles, tenancy } from "@budibase/backend-core" import { quotas } from "@budibase/pro" import { - Datasource, FieldType, MonthlyQuotaName, PermissionLevel, QuotaUsageType, Row, - SaveRowRequest, SaveTableRequest, SortOrder, SortType, diff --git a/packages/server/src/api/routes/tests/table.spec.ts b/packages/server/src/api/routes/tests/table.spec.ts index 9914e6d66f..f56c6e4e44 100644 --- a/packages/server/src/api/routes/tests/table.spec.ts +++ b/packages/server/src/api/routes/tests/table.spec.ts @@ -1,6 +1,6 @@ import { generator } from "@budibase/backend-core/tests" import { events, context } from "@budibase/backend-core" -import { FieldType, Table } from "@budibase/types" +import { FieldType, Table, ViewCalculation } from "@budibase/types" import { checkBuilderEndpoint } from "./utilities/TestFunctions" import * as setup from "./utilities" const { basicTable } = setup.structures @@ -90,8 +90,10 @@ describe("/tables", () => { await config.createLegacyView({ name: "TestView", field: "Price", - calculation: "stats", - tableId: testTable._id, + calculation: ViewCalculation.STATISTICS, + tableId: testTable._id!, + schema: {}, + filters: [], }) const testRow = await request @@ -254,7 +256,7 @@ describe("/tables", () => { })) await config.api.viewV2.create({ tableId }) - await config.createLegacyView({ tableId, name: generator.guid() }) + await config.createLegacyView() const res = await config.api.table.fetch() @@ -366,7 +368,7 @@ describe("/tables", () => { .expect("Content-Type", /json/) .expect(200) expect(res.body.message).toEqual(`Table ${testTable._id} deleted.`) - const dependentTable = await config.getTable(linkedTable._id) + const dependentTable = await config.api.table.get(linkedTable._id!) expect(dependentTable.schema.TestTable).not.toBeDefined() }) diff --git a/packages/server/src/api/routes/tests/viewV2.spec.ts b/packages/server/src/api/routes/tests/viewV2.spec.ts index 5e8ae09e55..6d893c1c7f 100644 --- a/packages/server/src/api/routes/tests/viewV2.spec.ts +++ b/packages/server/src/api/routes/tests/viewV2.spec.ts @@ -6,6 +6,7 @@ import { SortOrder, SortType, Table, + UIFieldMetadata, UpdateViewRequest, ViewV2, } from "@budibase/types" @@ -418,9 +419,12 @@ describe.each([ const res = await config.api.viewV2.create(newView) const view = await config.api.viewV2.get(res.id) expect(view!.schema?.Price).toBeUndefined() - const updatedTable = await config.getTable(table._id!) - const viewSchema = updatedTable.views[view!.name!].schema - expect(viewSchema.Price.visible).toEqual(false) + const updatedTable = await config.api.table.get(table._id!) + const viewSchema = updatedTable.views![view!.name!].schema as Record< + string, + UIFieldMetadata + > + expect(viewSchema.Price?.visible).toEqual(false) }) }) }) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 0a53326cf4..b0f6f5bb04 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -397,7 +397,7 @@ describe("postgres integrations", () => { expect(res.status).toBe(200) expect(res.body).toEqual(updatedRow) - const persistedRow = await config.getRow( + const persistedRow = await config.api.row.get( primaryPostgresTable._id!, row.id ) diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index fbb6e05c57..44867e6b01 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -557,11 +557,6 @@ class TestConfiguration { return this.updateTable(config, options) } - async getTable(tableId?: string) { - tableId = tableId || this.table?._id - return this._req(null, { tableId }, controllers.table.find) - } - async createLinkedTable( config?: Table, relationshipType = RelationshipType.ONE_TO_MANY, @@ -609,11 +604,7 @@ class TestConfiguration { } const tableId = (config && config.tableId) || this.table._id config = config || basicRow(tableId!) - return this._req(config, { tableId }, controllers.row.save) - } - - async getRow(tableId: string, rowId: string): Promise { - return this._req(null, { tableId, rowId }, controllers.row.find) + return this.api.row.save(tableId!, config) } async getRows(tableId: string) { @@ -648,7 +639,7 @@ class TestConfiguration { } const view = config || { tableId: this.table!._id, - name: "ViewTest", + name: generator.guid(), } return this._req(view, null, controllers.view.v1.save) } @@ -721,12 +712,8 @@ class TestConfiguration { } async updateDatasource(datasource: Datasource): Promise { - const response = await this._req( - datasource, - { datasourceId: datasource._id }, - controllers.datasource.update - ) - this.datasource = response.datasource + const response = await this.api.datasource.update(datasource) + this.datasource = response return this.datasource! } diff --git a/packages/server/src/tests/utilities/api/datasource.ts b/packages/server/src/tests/utilities/api/datasource.ts index 3c85a1c332..2ce09959fc 100644 --- a/packages/server/src/tests/utilities/api/datasource.ts +++ b/packages/server/src/tests/utilities/api/datasource.ts @@ -29,6 +29,23 @@ export class DatasourceAPI extends TestAPI { return result.body.datasource as Datasource } + update = async ( + config: Datasource, + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const body: CreateDatasourceRequest = { + datasource: config, + tablesFilter: [], + } + const result = await this.request + .put(`/api/datasources/${config._id}`) + .send(body) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(expectStatus) + return result.body.datasource as Datasource + } + verify = async ( data: VerifyDatasourceRequest, { expectStatus } = { expectStatus: 200 } From b5e6b42db20dca220fc46ebd534377ec5852dab3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 20:40:00 +0200 Subject: [PATCH 092/128] Reuse tables --- .../server/src/api/routes/tests/row.spec.ts | 196 +++++++++--------- .../server/src/tests/utilities/api/row.ts | 12 ++ 2 files changed, 109 insertions(+), 99 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 7ec2ef8ef9..b610e9689e 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -133,19 +133,26 @@ describe.each([ } : undefined - describe("save, load, update", () => { + let tableId: string + + beforeAll(async () => { + const tableConfig = generateTableConfig() + const table = await config.createTable(tableConfig) + tableId = table._id! + }) + it("returns a success message when the row is created", async () => { const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() const res = await request - .post(`/api/${config.table!._id}/rows`) - .send(basicRow(config.table!._id!)) + .post(`/api/${tableId}/rows`) + .send(basicRow(tableId)) .set(config.defaultHeaders()) .expect("Content-Type", /json/) .expect(200) expect((res as any).res.statusMessage).toEqual( - `${table.name} saved successfully` + `${config.table!.name} saved successfully` ) expect(res.body.name).toEqual("Test Contact") expect(res.body._rev).toBeDefined() @@ -158,28 +165,31 @@ describe.each([ const queryUsage = await getQueryUsage() const tableConfig = generateTableConfig() - const newTable = await config.createTable({ - ...tableConfig, - name: "TestTableAuto", - schema: { - ...tableConfig.schema, - "Row ID": { - name: "Row ID", - type: FieldType.NUMBER, - subtype: "autoID", - icon: "ri-magic-line", - autocolumn: true, - constraints: { - type: "number", - presence: true, - numericality: { - greaterThanOrEqualTo: "", - lessThanOrEqualTo: "", + const newTable = await config.createTable( + { + ...tableConfig, + name: "TestTableAuto", + schema: { + ...tableConfig.schema, + "Row ID": { + name: "Row ID", + type: FieldType.NUMBER, + subtype: "autoID", + icon: "ri-magic-line", + autocolumn: true, + constraints: { + type: "number", + presence: true, + numericality: { + greaterThanOrEqualTo: "", + lessThanOrEqualTo: "", + }, }, }, }, }, - }) + { skipReassigning: true } + ) const ids = [1, 2, 3] @@ -214,22 +224,14 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .post(`/api/${table._id}/rows`) - .send({ - _id: existing._id, - _rev: existing._rev, - tableId: table._id, - name: "Updated Name", - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.save(tableId, { + _id: existing._id, + _rev: existing._rev, + tableId, + name: "Updated Name", + }) - expect((res as any).res.statusMessage).toEqual( - `${table.name} updated successfully.` - ) - expect(res.body.name).toEqual("Updated Name") + expect(res.name).toEqual("Updated Name") await assertRowUsage(rowUsage) await assertQueryUsage(queryUsage + 1) }) @@ -238,11 +240,7 @@ describe.each([ const existing = await config.createRow() const queryUsage = await getQueryUsage() - const res = await request - .get(`/api/${table._id}/rows/${existing._id}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.get(tableId, existing._id!) expect(res.body).toEqual({ ...existing, @@ -252,24 +250,24 @@ describe.each([ }) it("should list all rows for given tableId", async () => { + const table = await config.createTable(generateTableConfig(), { + skipReassigning: true, + }) + const tableId = table._id! const newRow = { - tableId: table._id, + tableId, name: "Second Contact", - status: "new", + description: "new", } - const firstRow = await config.createRow() + const firstRow = await config.createRow({ tableId }) await config.createRow(newRow) const queryUsage = await getQueryUsage() - const res = await request - .get(`/api/${table._id}/rows`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.fetch(tableId) - expect(res.body.length).toBe(2) - expect(res.body.find((r: Row) => r.name === newRow.name)).toBeDefined() - expect(res.body.find((r: Row) => r.name === firstRow.name)).toBeDefined() + expect(res.length).toBe(2) + expect(res.find((r: Row) => r.name === newRow.name)).toBeDefined() + expect(res.find((r: Row) => r.name === firstRow.name)).toBeDefined() await assertQueryUsage(queryUsage + 1) }) @@ -277,7 +275,7 @@ describe.each([ await config.createRow() const queryUsage = await getQueryUsage() - await config.api.row.get(table._id!, "1234567", { + await config.api.row.get(tableId, "1234567", { expectStatus: 404, }) await assertQueryUsage(queryUsage) // no change @@ -325,52 +323,52 @@ describe.each([ sortable: false, } const optsField = { - fieldName: "Sample Opts", - name: "Sample Opts", - type: FieldType.OPTIONS, - constraints: { - type: "string", - presence: false, - inclusion: ["Alpha", "Beta", "Gamma"], - }, + fieldName: "Sample Opts", + name: "Sample Opts", + type: FieldType.OPTIONS, + constraints: { + type: "string", + presence: false, + inclusion: ["Alpha", "Beta", "Gamma"], }, - table = await config.createTable({ - name: "TestTable2", - type: "table", - schema: { - name: str, - stringUndefined: str, - stringNull: str, - stringString: str, - numberEmptyString: number, - numberNull: number, - numberUndefined: number, - numberString: number, - numberNumber: number, - datetimeEmptyString: datetime, - datetimeNull: datetime, - datetimeUndefined: datetime, - datetimeString: datetime, - datetimeDate: datetime, - boolNull: bool, - boolEmpty: bool, - boolUndefined: bool, - boolString: bool, - boolBool: bool, - attachmentNull: attachment, - attachmentUndefined: attachment, - attachmentEmpty: attachment, - attachmentEmptyArrayStr: attachment, - arrayFieldEmptyArrayStr: arrayField, - arrayFieldArrayStrKnown: arrayField, - arrayFieldNull: arrayField, - arrayFieldUndefined: arrayField, - optsFieldEmptyStr: optsField, - optsFieldUndefined: optsField, - optsFieldNull: optsField, - optsFieldStrKnown: optsField, - }, - }) + } + const table = await config.createTable({ + name: "TestTable2", + type: "table", + schema: { + name: str, + stringUndefined: str, + stringNull: str, + stringString: str, + numberEmptyString: number, + numberNull: number, + numberUndefined: number, + numberString: number, + numberNumber: number, + datetimeEmptyString: datetime, + datetimeNull: datetime, + datetimeUndefined: datetime, + datetimeString: datetime, + datetimeDate: datetime, + boolNull: bool, + boolEmpty: bool, + boolUndefined: bool, + boolString: bool, + boolBool: bool, + attachmentNull: attachment, + attachmentUndefined: attachment, + attachmentEmpty: attachment, + attachmentEmptyArrayStr: attachment, + arrayFieldEmptyArrayStr: arrayField, + arrayFieldArrayStrKnown: arrayField, + arrayFieldNull: arrayField, + arrayFieldUndefined: arrayField, + optsFieldEmptyStr: optsField, + optsFieldUndefined: optsField, + optsFieldNull: optsField, + optsFieldStrKnown: optsField, + }, + }) const row = { name: "Test Row", diff --git a/packages/server/src/tests/utilities/api/row.ts b/packages/server/src/tests/utilities/api/row.ts index 2f6760ebeb..3c266f07b5 100644 --- a/packages/server/src/tests/utilities/api/row.ts +++ b/packages/server/src/tests/utilities/api/row.ts @@ -76,4 +76,16 @@ export class RowAPI extends TestAPI { .expect("Content-Type", /json/) .expect(expectStatus) } + + fetch = async ( + sourceId: string, + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const request = this.request + .get(`/api/${sourceId}/rows`) + .set(this.config.defaultHeaders()) + .expect(expectStatus) + + return (await request).body + } } From d522ff70b4eb6ec77eb30a842945c303e48c22c7 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 20:47:06 +0200 Subject: [PATCH 093/128] Don't create tables for each test --- .../server/src/api/routes/tests/row.spec.ts | 53 +++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index b610e9689e..dfb43779a8 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -87,8 +87,6 @@ describe.each([ beforeEach(async () => { mocks.licenses.useCloudFree() - const tableConfig = generateTableConfig() - table = await config.createTable(tableConfig) }) const loadRow = async (id: string, tbl_Id: string, status = 200) => @@ -133,6 +131,7 @@ describe.each([ } : undefined + describe("save, load, update", () => { let tableId: string beforeAll(async () => { @@ -446,8 +445,8 @@ describe.each([ }) describe("view save", () => { - async function orderTable(): Promise
{ - return { + it("views have extra data trimmed", async () => { + const table = await config.createTable({ name: "orders", primary: ["OrderID"], schema: { @@ -464,11 +463,7 @@ describe.each([ name: "Story", }, }, - } - } - - it("views have extra data trimmed", async () => { - const table = await config.createTable(await orderTable()) + }) const createViewResponse = await config.createView({ name: generator.word(), @@ -505,6 +500,11 @@ describe.each([ }) describe("patch", () => { + beforeEach(async () => { + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) + }) + it("should update only the fields that are supplied", async () => { const existing = await config.createRow() @@ -554,6 +554,11 @@ describe.each([ }) describe("destroy", () => { + beforeEach(async () => { + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) + }) + it("should be able to delete a row", async () => { const createdRow = await config.createRow() const rowUsage = await getRowUsage() @@ -574,6 +579,11 @@ describe.each([ }) describe("validate", () => { + beforeEach(async () => { + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) + }) + it("should return no errors on valid row", async () => { const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -616,6 +626,11 @@ describe.each([ }) describe("bulkDelete", () => { + beforeEach(async () => { + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) + }) + it("should be able to delete a bulk set of rows", async () => { const row1 = await config.createRow() const row2 = await config.createRow() @@ -716,6 +731,11 @@ describe.each([ // Legacy views are not available for external isInternal && describe("fetchView", () => { + beforeEach(async () => { + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) + }) + it("should be able to fetch tables contents via 'view'", async () => { const row = await config.createRow() const rowUsage = await getRowUsage() @@ -770,6 +790,11 @@ describe.each([ }) describe("fetchEnrichedRows", () => { + beforeEach(async () => { + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) + }) + it("should allow enriching some linked rows", async () => { const { linkedTable, firstRow, secondRow } = await tenancy.doInTenant( config.getTenantId(), @@ -836,6 +861,11 @@ describe.each([ isInternal && describe("attachments", () => { + beforeEach(async () => { + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) + }) + it("should allow enriching attachment rows", async () => { const table = await config.createAttachmentTable() const attachmentId = `${structures.uuid()}.csv` @@ -862,6 +892,11 @@ describe.each([ }) describe("exportData", () => { + beforeEach(async () => { + const tableConfig = generateTableConfig() + table = await config.createTable(tableConfig) + }) + it("should allow exporting all columns", async () => { const existing = await config.createRow() const res = await request From eee8a2e5f95fd27b1b6f0082df24bf32b713d803 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 20:49:47 +0200 Subject: [PATCH 094/128] Run before alls --- packages/server/src/api/routes/tests/row.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index dfb43779a8..b4e257dc1c 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -500,7 +500,7 @@ describe.each([ }) describe("patch", () => { - beforeEach(async () => { + beforeAll(async () => { const tableConfig = generateTableConfig() table = await config.createTable(tableConfig) }) @@ -554,7 +554,7 @@ describe.each([ }) describe("destroy", () => { - beforeEach(async () => { + beforeAll(async () => { const tableConfig = generateTableConfig() table = await config.createTable(tableConfig) }) @@ -579,7 +579,7 @@ describe.each([ }) describe("validate", () => { - beforeEach(async () => { + beforeAll(async () => { const tableConfig = generateTableConfig() table = await config.createTable(tableConfig) }) From 0c8a8e1b26fd1cd16585cfd84632b5359e4db414 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 12 Sep 2023 21:09:25 +0200 Subject: [PATCH 095/128] Unify --- .../server/src/api/routes/tests/row.spec.ts | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index b4e257dc1c..a4fe43ea1a 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -39,6 +39,7 @@ describe.each([ let request = setup.getRequest() let config = setup.getConfig() let table: Table + let tableId: string afterAll(setup.afterAll) @@ -131,15 +132,13 @@ describe.each([ } : undefined + beforeAll(async () => { + const tableConfig = generateTableConfig() + const table = await config.createTable(tableConfig) + tableId = table._id! + }) + describe("save, load, update", () => { - let tableId: string - - beforeAll(async () => { - const tableConfig = generateTableConfig() - const table = await config.createTable(tableConfig) - tableId = table._id! - }) - it("returns a success message when the row is created", async () => { const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -626,7 +625,7 @@ describe.each([ }) describe("bulkDelete", () => { - beforeEach(async () => { + beforeAll(async () => { const tableConfig = generateTableConfig() table = await config.createTable(tableConfig) }) @@ -790,7 +789,7 @@ describe.each([ }) describe("fetchEnrichedRows", () => { - beforeEach(async () => { + beforeAll(async () => { const tableConfig = generateTableConfig() table = await config.createTable(tableConfig) }) @@ -861,7 +860,7 @@ describe.each([ isInternal && describe("attachments", () => { - beforeEach(async () => { + beforeAll(async () => { const tableConfig = generateTableConfig() table = await config.createTable(tableConfig) }) @@ -892,7 +891,7 @@ describe.each([ }) describe("exportData", () => { - beforeEach(async () => { + beforeAll(async () => { const tableConfig = generateTableConfig() table = await config.createTable(tableConfig) }) From 986decb1034a0ad1589e26d394fa7614b7bab160 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 09:37:11 +0200 Subject: [PATCH 096/128] Reduce timings --- .../server/src/api/routes/tests/row.spec.ts | 190 +++++++++--------- 1 file changed, 91 insertions(+), 99 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index a4fe43ea1a..fbf6651186 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -652,9 +652,11 @@ describe.each([ }) it("should be able to delete a variety of row set types", async () => { - const row1 = await config.createRow() - const row2 = await config.createRow() - const row3 = await config.createRow() + const [row1, row2, row3] = await Promise.all([ + config.createRow(), + config.createRow(), + config.createRow(), + ]) const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() @@ -1153,12 +1155,11 @@ describe.each([ it("returns empty rows from view when no schema is passed", async () => { const table = await config.createTable(await userTable()) - const rows = [] - for (let i = 0; i < 10; i++) { - rows.push( - await config.api.row.save(table._id!, { tableId: table._id }) + const rows = await Promise.all( + Array.from({ length: 10 }, () => + config.api.row.save(table._id!, { tableId: table._id }) ) - } + ) const createViewResponse = await config.createView() const response = await config.api.viewV2.search(createViewResponse.id) @@ -1181,22 +1182,26 @@ describe.each([ it("searching respects the view filters", async () => { const table = await config.createTable(await userTable()) - const expectedRows = [] - for (let i = 0; i < 10; i++) - await config.api.row.save(table._id!, { - tableId: table._id, - name: generator.name(), - age: generator.integer({ min: 10, max: 30 }), - }) - for (let i = 0; i < 5; i++) - expectedRows.push( - await config.api.row.save(table._id!, { + await Promise.all( + Array.from({ length: 10 }, () => + config.api.row.save(table._id!, { + tableId: table._id, + name: generator.name(), + age: generator.integer({ min: 10, max: 30 }), + }) + ) + ) + + const expectedRows = await Promise.all( + Array.from({ length: 5 }, () => + config.api.row.save(table._id!, { tableId: table._id, name: generator.name(), age: 40, }) ) + ) const createViewResponse = await config.createView({ query: [{ operator: "equal", field: "age", value: 40 }], @@ -1292,9 +1297,8 @@ describe.each([ ], ] - it.each(sortTestOptions)( - "allow sorting (%s)", - async (sortParams, expected) => { + describe("sorting", () => { + beforeAll(async () => { const table = await config.createTable(await userTable()) const users = [ { name: "Alice", age: 25 }, @@ -1302,82 +1306,76 @@ describe.each([ { name: "Charly", age: 27 }, { name: "Danny", age: 15 }, ] - for (const user of users) { - await config.api.row.save(table._id!, { - tableId: table._id, - ...user, + await Promise.all( + users.map(u => + config.api.row.save(table._id!, { + tableId: table._id, + ...u, + }) + ) + ) + }) + + it.each(sortTestOptions)( + "allow sorting (%s)", + async (sortParams, expected) => { + const createViewResponse = await config.createView({ + sort: sortParams, + schema: viewSchema, }) + + const response = await config.api.viewV2.search( + createViewResponse.id + ) + + expect(response.body.rows).toHaveLength(4) + expect(response.body.rows).toEqual( + expected.map(name => expect.objectContaining({ name })) + ) } + ) - const createViewResponse = await config.createView({ - sort: sortParams, - schema: viewSchema, - }) - - const response = await config.api.viewV2.search(createViewResponse.id) - - expect(response.body.rows).toHaveLength(4) - expect(response.body.rows).toEqual( - expected.map(name => expect.objectContaining({ name })) - ) - } - ) - - it.each(sortTestOptions)( - "allow override the default view sorting (%s)", - async (sortParams, expected) => { - const table = await config.createTable(await userTable()) - const users = [ - { name: "Alice", age: 25 }, - { name: "Bob", age: 30 }, - { name: "Charly", age: 27 }, - { name: "Danny", age: 15 }, - ] - for (const user of users) { - await config.api.row.save(table._id!, { - tableId: table._id, - ...user, + it.each(sortTestOptions)( + "allow override the default view sorting (%s)", + async (sortParams, expected) => { + const createViewResponse = await config.createView({ + sort: { + field: "name", + order: SortOrder.ASCENDING, + type: SortType.STRING, + }, + schema: viewSchema, }) + + const response = await config.api.viewV2.search( + createViewResponse.id, + { + sort: sortParams.field, + sortOrder: sortParams.order, + sortType: sortParams.type, + query: {}, + } + ) + + expect(response.body.rows).toHaveLength(4) + expect(response.body.rows).toEqual( + expected.map(name => expect.objectContaining({ name })) + ) } - - const createViewResponse = await config.createView({ - sort: { - field: "name", - order: SortOrder.ASCENDING, - type: SortType.STRING, - }, - schema: viewSchema, - }) - - const response = await config.api.viewV2.search( - createViewResponse.id, - { - sort: sortParams.field, - sortOrder: sortParams.order, - sortType: sortParams.type, - query: {}, - } - ) - - expect(response.body.rows).toHaveLength(4) - expect(response.body.rows).toEqual( - expected.map(name => expect.objectContaining({ name })) - ) - } - ) + ) + }) it("when schema is defined, defined columns and row attributes are returned", async () => { const table = await config.createTable(await userTable()) - const rows = [] - for (let i = 0; i < 10; i++) { - rows.push( - await config.api.row.save(table._id!, { + const rows = await Promise.all( + Array.from({ length: 10 }, () => + config.api.row.save(table._id!, { tableId: table._id, name: generator.name(), age: generator.age(), }) ) - } + ) const view = await config.createView({ schema: { name: { visible: true } }, @@ -1408,11 +1406,9 @@ describe.each([ }) it("respects the limit parameter", async () => { - const table = await config.createTable(await userTable()) - const rows = [] - for (let i = 0; i < 10; i++) { - rows.push(await config.createRow()) - } + await config.createTable(await userTable()) + await Promise.all(Array.from({ length: 10 }, () => config.createRow())) + const limit = generator.integer({ min: 1, max: 8 }) const createViewResponse = await config.createView() @@ -1425,11 +1421,8 @@ describe.each([ }) it("can handle pagination", async () => { - const table = await config.createTable(await userTable()) - const rows = [] - for (let i = 0; i < 10; i++) { - rows.push(await config.createRow()) - } + await config.createTable(await userTable()) + await Promise.all(Array.from({ length: 10 }, () => config.createRow())) const createViewResponse = await config.createView() const allRows = (await config.api.viewV2.search(createViewResponse.id)) @@ -1489,11 +1482,10 @@ describe.each([ let tableId: string beforeAll(async () => { - const table = await config.createTable(await userTable()) - const rows = [] - for (let i = 0; i < 10; i++) { - rows.push(await config.createRow()) - } + await config.createTable(await userTable()) + await Promise.all( + Array.from({ length: 10 }, () => config.createRow()) + ) const createViewResponse = await config.createView() From 14259c82f343933cf325e690f1fd5b6a9da5d1df Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 09:57:41 +0200 Subject: [PATCH 097/128] Use test api --- .../server/src/api/routes/tests/row.spec.ts | 130 ++++++------------ .../server/src/tests/utilities/api/row.ts | 23 +++- 2 files changed, 60 insertions(+), 93 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index fbf6651186..c9d78cd404 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -36,8 +36,8 @@ describe.each([ ])("/rows (%s)", (_, dsProvider) => { const isInternal = !dsProvider - let request = setup.getRequest() - let config = setup.getConfig() + const request = setup.getRequest() + const config = setup.getConfig() let table: Table let tableId: string @@ -90,12 +90,8 @@ describe.each([ mocks.licenses.useCloudFree() }) - const loadRow = async (id: string, tbl_Id: string, status = 200) => - await request - .get(`/api/${tbl_Id}/rows/${id}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(status) + const loadRow = (id: string, tbl_Id: string, status = 200) => + config.api.row.get(tbl_Id, id, { expectStatus: status }) const getRowUsage = async () => { const { total } = await config.doInContext(null, () => @@ -193,20 +189,12 @@ describe.each([ // Performing several create row requests should increment the autoID fields accordingly const createRow = async (id: number) => { - const res = await request - .post(`/api/${newTable._id}/rows`) - .send({ - name: "row_" + id, - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) - expect((res as any).res.statusMessage).toEqual( - `${newTable.name} saved successfully` - ) - expect(res.body.name).toEqual("row_" + id) - expect(res.body._rev).toBeDefined() - expect(res.body["Row ID"]).toEqual(id) + const res = await config.api.row.save(newTable._id!, { + name: "row_" + id, + }) + expect(res.name).toEqual("row_" + id) + expect(res._rev).toBeDefined() + expect(res["Row ID"]).toEqual(id) } for (let i = 0; i < ids.length; i++) { @@ -563,14 +551,7 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .delete(`/api/${table._id}/rows`) - .send({ - rows: [createdRow], - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.delete(table._id!, [createdRow]) expect(res.body[0]._id).toEqual(createdRow._id) await assertRowUsage(rowUsage - 1) await assertQueryUsage(queryUsage + 1) @@ -587,15 +568,10 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .post(`/api/${table._id}/rows/validate`) - .send({ name: "ivan" }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.validate(table._id!, { name: "ivan" }) - expect(res.body.valid).toBe(true) - expect(Object.keys(res.body.errors)).toEqual([]) + expect(res.valid).toBe(true) + expect(Object.keys(res.errors)).toEqual([]) await assertRowUsage(rowUsage) await assertQueryUsage(queryUsage) }) @@ -604,20 +580,15 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .post(`/api/${table._id}/rows/validate`) - .send({ name: 1 }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.validate(table._id!, { name: 1 }) if (isInternal) { - expect(res.body.valid).toBe(false) - expect(Object.keys(res.body.errors)).toEqual(["name"]) + expect(res.valid).toBe(false) + expect(Object.keys(res.errors)).toEqual(["name"]) } else { // Validation for external is not implemented, so it will always return valid - expect(res.body.valid).toBe(true) - expect(Object.keys(res.body.errors)).toEqual([]) + expect(res.valid).toBe(true) + expect(Object.keys(res.errors)).toEqual([]) } await assertRowUsage(rowUsage) await assertQueryUsage(queryUsage) @@ -636,14 +607,7 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .delete(`/api/${table._id}/rows`) - .send({ - rows: [row1, row2], - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.delete(table._id!, [row1, row2]) expect(res.body.length).toEqual(2) await loadRow(row1._id!, table._id!, 404) @@ -660,14 +624,11 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .delete(`/api/${table._id}/rows`) - .send({ - rows: [row1, row2._id, { _id: row3._id }], - }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.delete(table._id!, [ + row1, + row2._id, + { _id: row3._id }, + ]) expect(res.body.length).toEqual(3) await loadRow(row1._id!, table._id!, 404) @@ -680,12 +641,7 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .delete(`/api/${table._id}/rows`) - .send(row1) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.delete(table._id!, row1) expect(res.body.id).toEqual(row1._id) await loadRow(row1._id!, table._id!, 404) @@ -697,31 +653,23 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .delete(`/api/${table._id}/rows`) - .send({ not: "valid" }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - + const res = await config.api.row.delete( + table._id!, + { not: "valid" }, + { expectStatus: 400 } + ) expect(res.body.message).toEqual("Invalid delete rows request") - const res2 = await request - .delete(`/api/${table._id}/rows`) - .send({ rows: 123 }) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - + const res2 = await config.api.row.delete( + table._id!, + { rows: 123 }, + { expectStatus: 400 } + ) expect(res2.body.message).toEqual("Invalid delete rows request") - const res3 = await request - .delete(`/api/${table._id}/rows`) - .send("invalid") - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(400) - + const res3 = await config.api.row.delete(table._id!, "invalid", { + expectStatus: 400, + }) expect(res3.body.message).toEqual("Invalid delete rows request") await assertRowUsage(rowUsage) diff --git a/packages/server/src/tests/utilities/api/row.ts b/packages/server/src/tests/utilities/api/row.ts index 3c266f07b5..2338285ed4 100644 --- a/packages/server/src/tests/utilities/api/row.ts +++ b/packages/server/src/tests/utilities/api/row.ts @@ -1,4 +1,9 @@ -import { PatchRowRequest, SaveRowRequest, Row } from "@budibase/types" +import { + PatchRowRequest, + SaveRowRequest, + Row, + ValidateResponse, +} from "@budibase/types" import TestConfiguration from "../TestConfiguration" import { TestAPI } from "./base" @@ -51,6 +56,20 @@ export class RowAPI extends TestAPI { return resp.body as Row } + validate = async ( + sourceId: string, + row: SaveRowRequest, + { expectStatus } = { expectStatus: 200 } + ): Promise => { + const resp = await this.request + .post(`/api/${sourceId}/rows/validate`) + .send(row) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(expectStatus) + return resp.body as ValidateResponse + } + patch = async ( sourceId: string, row: PatchRowRequest, @@ -71,7 +90,7 @@ export class RowAPI extends TestAPI { ) => { return this.request .delete(`/api/${sourceId}/rows`) - .send({ rows }) + .send(Array.isArray(rows) ? { rows } : rows) .set(this.config.defaultHeaders()) .expect("Content-Type", /json/) .expect(expectStatus) From 4d12ee53dae26cf078e8f38f997b5fa384782517 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 09:59:17 +0200 Subject: [PATCH 098/128] LegacyView test api --- .../server/src/api/routes/tests/row.spec.ts | 17 +++-------------- .../server/src/tests/utilities/api/index.ts | 3 +++ .../src/tests/utilities/api/legacyView.ts | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 packages/server/src/tests/utilities/api/legacyView.ts diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index c9d78cd404..6a7a0210ef 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -690,11 +690,7 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .get(`/api/views/${table._id}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.legacyView.get(table._id!) expect(res.body.length).toEqual(1) expect(res.body[0]._id).toEqual(row._id) await assertRowUsage(rowUsage) @@ -705,10 +701,7 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - await request - .get(`/api/views/derp`) - .set(config.defaultHeaders()) - .expect(404) + await config.api.legacyView.get("derp", { expectStatus: 404 }) await assertRowUsage(rowUsage) await assertQueryUsage(queryUsage) @@ -725,11 +718,7 @@ describe.each([ const rowUsage = await getRowUsage() const queryUsage = await getQueryUsage() - const res = await request - .get(`/api/views/${view.name}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.legacyView.get(view.name) expect(res.body.length).toEqual(1) expect(res.body[0]._id).toEqual(row._id) diff --git a/packages/server/src/tests/utilities/api/index.ts b/packages/server/src/tests/utilities/api/index.ts index 0521f9b19f..31c74a0e78 100644 --- a/packages/server/src/tests/utilities/api/index.ts +++ b/packages/server/src/tests/utilities/api/index.ts @@ -4,9 +4,11 @@ import { RowAPI } from "./row" import { TableAPI } from "./table" import { ViewV2API } from "./viewV2" import { DatasourceAPI } from "./datasource" +import { LegacyViewAPI } from "./legacyView" export default class API { table: TableAPI + legacyView: LegacyViewAPI viewV2: ViewV2API row: RowAPI permission: PermissionAPI @@ -14,6 +16,7 @@ export default class API { constructor(config: TestConfiguration) { this.table = new TableAPI(config) + this.legacyView = new LegacyViewAPI(config) this.viewV2 = new ViewV2API(config) this.row = new RowAPI(config) this.permission = new PermissionAPI(config) diff --git a/packages/server/src/tests/utilities/api/legacyView.ts b/packages/server/src/tests/utilities/api/legacyView.ts new file mode 100644 index 0000000000..63981cec5e --- /dev/null +++ b/packages/server/src/tests/utilities/api/legacyView.ts @@ -0,0 +1,16 @@ +import TestConfiguration from "../TestConfiguration" +import { TestAPI } from "./base" + +export class LegacyViewAPI extends TestAPI { + constructor(config: TestConfiguration) { + super(config) + } + + get = async (id: string, { expectStatus } = { expectStatus: 200 }) => { + return await this.request + .get(`/api/views/${id}`) + .set(this.config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(expectStatus) + } +} From cf74f19381d8341c6fe4658658b0ac82c3072b46 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 10:13:54 +0200 Subject: [PATCH 099/128] Use test api --- .../server/src/api/controllers/row/index.ts | 6 ++- .../server/src/api/routes/tests/row.spec.ts | 42 +++++++------------ .../server/src/tests/utilities/api/row.ts | 17 +++++++- packages/types/src/api/web/app/rows.ts | 11 ++++- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index e86b466601..f0f2462019 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -16,6 +16,8 @@ import { SearchParams, GetRowResponse, ValidateResponse, + ExportRowsRequest, + ExportRowsResponse, } from "@budibase/types" import * as utils from "./utils" import { gridSocket } from "../../../websockets" @@ -239,7 +241,9 @@ export async function fetchEnrichedRow(ctx: any) { ) } -export const exportRows = async (ctx: any) => { +export const exportRows = async ( + ctx: Ctx +) => { const tableId = utils.getTableId(ctx) const format = ctx.query.format diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 6a7a0210ef..09cc2d1888 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -771,11 +771,10 @@ describe.each([ const queryUsage = await getQueryUsage() // test basic enrichment - const resBasic = await request - .get(`/api/${linkedTable._id}/rows/${secondRow._id}`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const resBasic = await config.api.row.get( + linkedTable._id!, + secondRow._id! + ) expect(resBasic.body.link.length).toBe(1) expect(resBasic.body.link[0]).toEqual({ _id: firstRow._id, @@ -783,11 +782,10 @@ describe.each([ }) // test full enrichment - const resEnriched = await request - .get(`/api/${linkedTable._id}/${secondRow._id}/enrich`) - .set(config.defaultHeaders()) - .expect("Content-Type", /json/) - .expect(200) + const resEnriched = await config.api.row.getEnriched( + linkedTable._id!, + secondRow._id! + ) expect(resEnriched.body.link.length).toBe(1) expect(resEnriched.body.link[0]._id).toBe(firstRow._id) expect(resEnriched.body.link[0].name).toBe("Test Contact") @@ -837,14 +835,9 @@ describe.each([ it("should allow exporting all columns", async () => { const existing = await config.createRow() - const res = await request - .post(`/api/${table._id}/rows/exportRows?format=json`) - .set(config.defaultHeaders()) - .send({ - rows: [existing._id], - }) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.exportRows(table._id!, { + rows: [existing._id!], + }) const results = JSON.parse(res.text) expect(results.length).toEqual(1) const row = results[0] @@ -860,15 +853,10 @@ describe.each([ it("should allow exporting only certain columns", async () => { const existing = await config.createRow() - const res = await request - .post(`/api/${table._id}/rows/exportRows?format=json`) - .set(config.defaultHeaders()) - .send({ - rows: [existing._id], - columns: ["_id"], - }) - .expect("Content-Type", /json/) - .expect(200) + const res = await config.api.row.exportRows(table._id!, { + rows: [existing._id!], + columns: ["_id"], + }) const results = JSON.parse(res.text) expect(results.length).toEqual(1) const row = results[0] diff --git a/packages/server/src/tests/utilities/api/row.ts b/packages/server/src/tests/utilities/api/row.ts index 2338285ed4..686c8c031b 100644 --- a/packages/server/src/tests/utilities/api/row.ts +++ b/packages/server/src/tests/utilities/api/row.ts @@ -3,6 +3,7 @@ import { SaveRowRequest, Row, ValidateResponse, + ExportRowsRequest, } from "@budibase/types" import TestConfiguration from "../TestConfiguration" import { TestAPI } from "./base" @@ -33,7 +34,7 @@ export class RowAPI extends TestAPI { { expectStatus } = { expectStatus: 200 } ) => { const request = this.request - .get(`/api/${sourceId}/rows/${rowId}/enrich`) + .get(`/api/${sourceId}/${rowId}/enrich`) .set(this.config.defaultHeaders()) .expect(expectStatus) if (expectStatus !== 404) { @@ -107,4 +108,18 @@ export class RowAPI extends TestAPI { return (await request).body } + + exportRows = async ( + tableId: string, + body: ExportRowsRequest, + { expectStatus } = { expectStatus: 200 } + ) => { + const request = this.request + .post(`/api/${tableId}/rows/exportRows?format=json`) + .set(this.config.defaultHeaders()) + .send(body) + .expect("Content-Type", /json/) + .expect(expectStatus) + return request + } } diff --git a/packages/types/src/api/web/app/rows.ts b/packages/types/src/api/web/app/rows.ts index a99ef0e837..62ea90a6a4 100644 --- a/packages/types/src/api/web/app/rows.ts +++ b/packages/types/src/api/web/app/rows.ts @@ -1,5 +1,6 @@ -import { SearchParams } from "../../../sdk" +import { SearchFilters, SearchParams } from "../../../sdk" import { Row } from "../../../documents" +import { ReadStream } from "fs" export interface SaveRowRequest extends Row {} @@ -28,3 +29,11 @@ export interface SearchViewRowRequest export interface SearchRowResponse { rows: any[] } + +export interface ExportRowsRequest { + rows: string[] + columns?: string[] + query?: SearchFilters +} + +export type ExportRowsResponse = ReadStream From 069b0d6161945288d5c937516cc9d5ca447b053e Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 10:31:39 +0200 Subject: [PATCH 100/128] Fix types --- packages/server/src/migrations/tests/index.spec.ts | 5 ++++- packages/server/src/sdk/app/rows/search.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/server/src/migrations/tests/index.spec.ts b/packages/server/src/migrations/tests/index.spec.ts index b64cad26c1..d83e3cf31e 100644 --- a/packages/server/src/migrations/tests/index.spec.ts +++ b/packages/server/src/migrations/tests/index.spec.ts @@ -11,6 +11,7 @@ import { MIGRATIONS } from "../" import * as helpers from "./helpers" import tk from "timekeeper" +import { View } from "@budibase/types" const timestamp = new Date().toISOString() tk.freeze(timestamp) @@ -52,7 +53,9 @@ describe("migrations", () => { await config.createTable() await config.createLegacyView() await config.createTable() - await config.createLegacyView(structures.view(config.table!._id!)) + await config.createLegacyView( + structures.view(config.table!._id!) as View + ) await config.createScreen() await config.createScreen() diff --git a/packages/server/src/sdk/app/rows/search.ts b/packages/server/src/sdk/app/rows/search.ts index afee18b57c..b3bc220124 100644 --- a/packages/server/src/sdk/app/rows/search.ts +++ b/packages/server/src/sdk/app/rows/search.ts @@ -30,7 +30,7 @@ export interface ExportRowsParams { format: Format rowIds?: string[] columns?: string[] - query: SearchFilters + query?: SearchFilters } export interface ExportRowsResult { From 47899c669dee55588353242d7cb4d56bf8f16ac8 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 10:39:22 +0200 Subject: [PATCH 101/128] Use api --- packages/server/src/integration-test/postgres.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index b0f6f5bb04..0e2560b7df 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -47,7 +47,7 @@ describe("postgres integrations", () => { ) async function createAuxTable(prefix: string) { - return await config.createTable({ + return await config.api.table.create({ name: `${prefix}_${generator.word({ length: 6 })}`, type: "external", primary: ["id"], @@ -83,7 +83,7 @@ describe("postgres integrations", () => { relationshipType: RelationshipType.MANY_TO_MANY, } - primaryPostgresTable = await config.createTable({ + primaryPostgresTable = await config.api.table.create({ name: `p_${generator.word({ length: 6 })}`, type: "external", primary: ["id"], @@ -263,7 +263,7 @@ describe("postgres integrations", () => { } async function createDefaultPgTable() { - return await config.createTable({ + return await config.api.table.create({ name: generator.word({ length: 10 }), type: "external", primary: ["id"], @@ -301,7 +301,7 @@ describe("postgres integrations", () => { ) } - it("validate table schema", async () => { + it.only("validate table schema", async () => { const res = await makeRequest( "get", `/api/datasources/${postgresDatasource._id}` From c7e41eacc77383918e82f2c23041935aab04aad2 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 11:00:53 +0200 Subject: [PATCH 102/128] Cleanup test --- .../src/integration-test/postgres.spec.ts | 74 ++++++++----------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 0e2560b7df..2dc84a98da 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -181,32 +181,16 @@ describe("postgres integrations", () => { let { rowData } = opts as any let foreignRows: ForeignRowsInfo[] = [] - async function createForeignRow(tableInfo: ForeignTableInfo) { - const foreignKey = `fk_${tableInfo.table.name}_${tableInfo.fieldName}` - - const foreignRow = await config.createRow({ - tableId: tableInfo.table._id, - title: generator.name(), - }) - - rowData = { - ...rowData, - [foreignKey]: foreignRow.id, - } - foreignRows.push({ - row: foreignRow, - - relationshipType: tableInfo.relationshipType, - }) - } - if (opts?.createForeignRows?.createOneToMany) { const foreignKey = `fk_${oneToManyRelationshipInfo.table.name}_${oneToManyRelationshipInfo.fieldName}` - const foreignRow = await config.createRow({ - tableId: oneToManyRelationshipInfo.table._id, - title: generator.name(), - }) + const foreignRow = await config.api.row.save( + oneToManyRelationshipInfo.table._id!, + { + tableId: oneToManyRelationshipInfo.table._id, + title: generator.name(), + } + ) rowData = { ...rowData, @@ -219,10 +203,13 @@ describe("postgres integrations", () => { } for (let i = 0; i < (opts?.createForeignRows?.createManyToOne || 0); i++) { - const foreignRow = await config.createRow({ - tableId: manyToOneRelationshipInfo.table._id, - title: generator.name(), - }) + const foreignRow = await config.api.row.save( + manyToOneRelationshipInfo.table._id!, + { + tableId: manyToOneRelationshipInfo.table._id, + title: generator.name(), + } + ) rowData = { ...rowData, @@ -237,10 +224,13 @@ describe("postgres integrations", () => { } for (let i = 0; i < (opts?.createForeignRows?.createManyToMany || 0); i++) { - const foreignRow = await config.createRow({ - tableId: manyToManyRelationshipInfo.table._id, - title: generator.name(), - }) + const foreignRow = await config.api.row.save( + manyToManyRelationshipInfo.table._id!, + { + tableId: manyToManyRelationshipInfo.table._id, + title: generator.name(), + } + ) rowData = { ...rowData, @@ -254,7 +244,7 @@ describe("postgres integrations", () => { }) } - const row = await config.createRow({ + const row = await config.api.row.save(primaryPostgresTable._id!, { tableId: primaryPostgresTable._id, ...rowData, }) @@ -277,6 +267,14 @@ describe("postgres integrations", () => { }) } + const createRandomTableWithRows = async () => { + const tableId = (await createDefaultPgTable())._id! + return await config.api.row.save(tableId, { + tableId, + title: generator.name(), + }) + } + async function populatePrimaryRows( count: number, opts?: { @@ -685,12 +683,6 @@ describe("postgres integrations", () => { describe("given than multiple tables have multiple rows", () => { const rowsCount = 6 beforeEach(async () => { - const createRandomTableWithRows = async () => - await config.createRow({ - tableId: (await createDefaultPgTable())._id, - title: generator.name(), - }) - await createRandomTableWithRows() await createRandomTableWithRows() @@ -978,12 +970,6 @@ describe("postgres integrations", () => { const rowsCount = 6 beforeEach(async () => { - const createRandomTableWithRows = async () => - await config.createRow({ - tableId: (await createDefaultPgTable())._id, - title: generator.name(), - }) - await createRandomTableWithRows() await populatePrimaryRows(rowsCount) await createRandomTableWithRows() From 823afa1f553116526ed1c3f150570ec4848b89ee Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 11:59:34 +0200 Subject: [PATCH 103/128] Run all tests --- packages/server/src/integration-test/postgres.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 2dc84a98da..27e9fa7206 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -299,7 +299,7 @@ describe("postgres integrations", () => { ) } - it.only("validate table schema", async () => { + it("validate table schema", async () => { const res = await makeRequest( "get", `/api/datasources/${postgresDatasource._id}` From ceb3129e221c4871c6c48dc0d14f62ff11fd8c5a Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 12:02:13 +0200 Subject: [PATCH 104/128] Revert relationship changes --- .../server/src/api/controllers/table/external.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/controllers/table/external.ts b/packages/server/src/api/controllers/table/external.ts index 513b989a3a..327904666d 100644 --- a/packages/server/src/api/controllers/table/external.ts +++ b/packages/server/src/api/controllers/table/external.ts @@ -67,15 +67,13 @@ function cleanupRelationships( tables: Record, oldTable?: Table ) { - const isUpdate = !!oldTable - if (!isUpdate) { - return - } - - // When updating a table, we want to detect if some relationships were removed. - // If so, we want to remove the relationship from the other end - for (let [key, schema] of Object.entries(oldTable.schema)) { - if (schema.type === FieldTypes.LINK && !table.schema[key]) { + const tableToIterate = oldTable ? oldTable : table + // clean up relationships in couch table schemas + for (let [key, schema] of Object.entries(tableToIterate.schema)) { + if ( + schema.type === FieldTypes.LINK && + (!oldTable || table.schema[key] == null) + ) { const relatedTable = Object.values(tables).find( table => table._id === schema.tableId ) From 6bae382d81e118c12c047b19674d27d5ae5d4f09 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 12:23:59 +0200 Subject: [PATCH 105/128] Fix tests --- packages/server/src/api/controllers/table/index.ts | 4 ++-- packages/server/src/tests/utilities/TestConfiguration.ts | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/table/index.ts b/packages/server/src/api/controllers/table/index.ts index 759974d6a7..29c41ad985 100644 --- a/packages/server/src/api/controllers/table/index.ts +++ b/packages/server/src/api/controllers/table/index.ts @@ -78,9 +78,9 @@ export async function save(ctx: UserCtx) { ctx.status = 200 ctx.message = `Table ${table.name} saved successfully.` ctx.eventEmitter && - ctx.eventEmitter.emitTable(`table:save`, appId, savedTable) + ctx.eventEmitter.emitTable(`table:save`, appId, { ...savedTable }) ctx.body = savedTable - builderSocket?.emitTableUpdate(ctx, savedTable) + builderSocket?.emitTableUpdate(ctx, { ...savedTable }) } export async function destroy(ctx: UserCtx) { diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 44867e6b01..e521a5a6a6 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -557,6 +557,11 @@ class TestConfiguration { return this.updateTable(config, options) } + async getTable(tableId?: string) { + tableId = tableId || this.table!._id! + return this._req(null, { tableId }, controllers.table.find) + } + async createLinkedTable( config?: Table, relationshipType = RelationshipType.ONE_TO_MANY, @@ -607,6 +612,10 @@ class TestConfiguration { return this.api.row.save(tableId!, config) } + async getRow(tableId: string, rowId: string): Promise { + return this._req(null, { tableId, rowId }, controllers.row.find) + } + async getRows(tableId: string) { if (!tableId && this.table) { tableId = this.table._id! From dc5cd7cf76cf7132f742b68032f04f2119b4f7d2 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 12:53:47 +0200 Subject: [PATCH 106/128] Fix --- .../src/integration-test/postgres.spec.ts | 95 ++++++++++++------- 1 file changed, 60 insertions(+), 35 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 27e9fa7206..8ce1530ec2 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -47,7 +47,7 @@ describe("postgres integrations", () => { ) async function createAuxTable(prefix: string) { - return await config.api.table.create({ + return await config.createTable({ name: `${prefix}_${generator.word({ length: 6 })}`, type: "external", primary: ["id"], @@ -83,7 +83,7 @@ describe("postgres integrations", () => { relationshipType: RelationshipType.MANY_TO_MANY, } - primaryPostgresTable = await config.api.table.create({ + primaryPostgresTable = await config.createTable({ name: `p_${generator.word({ length: 6 })}`, type: "external", primary: ["id"], @@ -184,13 +184,10 @@ describe("postgres integrations", () => { if (opts?.createForeignRows?.createOneToMany) { const foreignKey = `fk_${oneToManyRelationshipInfo.table.name}_${oneToManyRelationshipInfo.fieldName}` - const foreignRow = await config.api.row.save( - oneToManyRelationshipInfo.table._id!, - { - tableId: oneToManyRelationshipInfo.table._id, - title: generator.name(), - } - ) + const foreignRow = await config.createRow({ + tableId: oneToManyRelationshipInfo.table._id, + title: generator.name(), + }) rowData = { ...rowData, @@ -203,13 +200,10 @@ describe("postgres integrations", () => { } for (let i = 0; i < (opts?.createForeignRows?.createManyToOne || 0); i++) { - const foreignRow = await config.api.row.save( - manyToOneRelationshipInfo.table._id!, - { - tableId: manyToOneRelationshipInfo.table._id, - title: generator.name(), - } - ) + const foreignRow = await config.createRow({ + tableId: manyToOneRelationshipInfo.table._id, + title: generator.name(), + }) rowData = { ...rowData, @@ -224,13 +218,10 @@ describe("postgres integrations", () => { } for (let i = 0; i < (opts?.createForeignRows?.createManyToMany || 0); i++) { - const foreignRow = await config.api.row.save( - manyToManyRelationshipInfo.table._id!, - { - tableId: manyToManyRelationshipInfo.table._id, - title: generator.name(), - } - ) + const foreignRow = await config.createRow({ + tableId: manyToManyRelationshipInfo.table._id, + title: generator.name(), + }) rowData = { ...rowData, @@ -244,7 +235,7 @@ describe("postgres integrations", () => { }) } - const row = await config.api.row.save(primaryPostgresTable._id!, { + const row = await config.createRow({ tableId: primaryPostgresTable._id, ...rowData, }) @@ -253,7 +244,7 @@ describe("postgres integrations", () => { } async function createDefaultPgTable() { - return await config.api.table.create({ + return await config.createTable({ name: generator.word({ length: 10 }), type: "external", primary: ["id"], @@ -395,7 +386,7 @@ describe("postgres integrations", () => { expect(res.status).toBe(200) expect(res.body).toEqual(updatedRow) - const persistedRow = await config.api.row.get( + const persistedRow = await config.getRow( primaryPostgresTable._id!, row.id ) @@ -520,7 +511,7 @@ describe("postgres integrations", () => { foreignRows = createdRow.foreignRows }) - it("only one to many foreign keys are retrieved", async () => { + it("only one to primary keys are retrieved", async () => { const res = await getRow(primaryPostgresTable._id, row.id) expect(res.status).toBe(200) @@ -528,6 +519,12 @@ describe("postgres integrations", () => { const one2ManyForeignRows = foreignRows.filter( x => x.relationshipType === RelationshipType.ONE_TO_MANY ) + const many2OneForeignRows = foreignRows.filter( + x => x.relationshipType === RelationshipType.MANY_TO_ONE + ) + const many2ManyForeignRows = foreignRows.filter( + x => x.relationshipType === RelationshipType.MANY_TO_MANY + ) expect(one2ManyForeignRows).toHaveLength(1) expect(res.body).toEqual({ @@ -538,9 +535,25 @@ describe("postgres integrations", () => { _rev: expect.any(String), [`fk_${oneToManyRelationshipInfo.table.name}_${oneToManyRelationshipInfo.fieldName}`]: one2ManyForeignRows[0].row.id, + [oneToManyRelationshipInfo.fieldName]: expect.arrayContaining( + one2ManyForeignRows.map(r => ({ + _id: r.row._id, + primaryDisplay: r.row.title, + })) + ), + [manyToOneRelationshipInfo.fieldName]: expect.arrayContaining( + many2OneForeignRows.map(r => ({ + _id: r.row._id, + primaryDisplay: r.row.title, + })) + ), + [manyToManyRelationshipInfo.fieldName]: expect.arrayContaining( + many2ManyForeignRows.map(r => ({ + _id: r.row._id, + primaryDisplay: r.row.title, + })) + ), }) - - expect(res.body[oneToManyRelationshipInfo.fieldName]).toBeUndefined() }) }) @@ -569,9 +582,13 @@ describe("postgres integrations", () => { _rev: expect.any(String), [`fk_${oneToManyRelationshipInfo.table.name}_${oneToManyRelationshipInfo.fieldName}`]: foreignRows[0].row.id, + [oneToManyRelationshipInfo.fieldName]: expect.arrayContaining( + foreignRows.map(r => ({ + _id: r.row._id, + primaryDisplay: r.row.title, + })) + ), }) - - expect(res.body[oneToManyRelationshipInfo.fieldName]).toBeUndefined() }) }) @@ -598,9 +615,13 @@ describe("postgres integrations", () => { tableId: row.tableId, _id: expect.any(String), _rev: expect.any(String), + [manyToOneRelationshipInfo.fieldName]: expect.arrayContaining( + foreignRows.map(r => ({ + _id: r.row._id, + primaryDisplay: r.row.title, + })) + ), }) - - expect(res.body[oneToManyRelationshipInfo.fieldName]).toBeUndefined() }) }) @@ -627,9 +648,13 @@ describe("postgres integrations", () => { tableId: row.tableId, _id: expect.any(String), _rev: expect.any(String), + [manyToManyRelationshipInfo.fieldName]: expect.arrayContaining( + foreignRows.map(r => ({ + _id: r.row._id, + primaryDisplay: r.row.title, + })) + ), }) - - expect(res.body[oneToManyRelationshipInfo.fieldName]).toBeUndefined() }) }) }) From c530d5fa348105ead7cab139655b8444dde7424b Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 13:17:51 +0200 Subject: [PATCH 107/128] Timeout issues --- .../src/integration-test/postgres.spec.ts | 20 ++++++++++--------- .../src/integrations/tests/utils/index.ts | 2 ++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 8ce1530ec2..86a43c8c42 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -21,8 +21,6 @@ import { databaseTestProviders } from "../integrations/tests/utils" const config = setup.getConfig()! -jest.setTimeout(30000) - jest.unmock("pg") jest.mock("../websockets") @@ -39,13 +37,13 @@ describe("postgres integrations", () => { const apiKey = await config.generateApiKey() makeRequest = generateMakeRequest(apiKey, true) - }) - beforeEach(async () => { postgresDatasource = await config.api.datasource.create( await databaseTestProviders.postgres.getDsConfig() ) + }) + beforeEach(async () => { async function createAuxTable(prefix: string) { return await config.createTable({ name: `${prefix}_${generator.word({ length: 6 })}`, @@ -345,12 +343,16 @@ describe("postgres integrations", () => { it("multiple rows can be persisted", async () => { const numberOfRows = 10 - const newRows = Array(numberOfRows).fill(generateRandomPrimaryRowData()) + const newRows: Row[] = Array(numberOfRows).fill( + generateRandomPrimaryRowData() + ) - for (const newRow of newRows) { - const res = await createRow(primaryPostgresTable._id, newRow) - expect(res.status).toBe(200) - } + await Promise.all( + newRows.map(async newRow => { + const res = await createRow(primaryPostgresTable._id, newRow) + expect(res.status).toBe(200) + }) + ) const persistedRows = await config.getRows(primaryPostgresTable._id!) expect(persistedRows).toHaveLength(numberOfRows) diff --git a/packages/server/src/integrations/tests/utils/index.ts b/packages/server/src/integrations/tests/utils/index.ts index c145a9c809..a28141db08 100644 --- a/packages/server/src/integrations/tests/utils/index.ts +++ b/packages/server/src/integrations/tests/utils/index.ts @@ -3,6 +3,8 @@ jest.unmock("pg") import { Datasource } from "@budibase/types" import * as pg from "./postgres" +jest.setTimeout(30000) + export interface DatabasePlusTestProvider { getDsConfig(): Promise } From 142fb18c177b1063076c98852643094299cb1137 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 14:09:48 +0200 Subject: [PATCH 108/128] Fix tests --- .../server/src/api/routes/tests/row.spec.ts | 33 +++++++++++-------- .../src/db/tests/linkController.spec.js | 2 +- .../src/tests/utilities/TestConfiguration.ts | 4 +-- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 09cc2d1888..e3bfc32320 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -10,6 +10,7 @@ import { MonthlyQuotaName, PermissionLevel, QuotaUsageType, + RelationshipType, Row, SaveTableRequest, SortOrder, @@ -737,22 +738,26 @@ describe.each([ const { linkedTable, firstRow, secondRow } = await tenancy.doInTenant( config.getTenantId(), async () => { - const linkedTable = await config.createLinkedTable({ - name: generator.word(), - type: "table", - primary: ["id"], - primaryDisplay: "id", - schema: { - id: { - type: FieldType.AUTO, - name: "id", - autocolumn: true, - constraints: { - presence: true, + const linkedTable = await config.createLinkedTable( + RelationshipType.ONE_TO_MANY, + ["link"], + { + name: generator.word(), + type: "table", + primary: ["id"], + primaryDisplay: "id", + schema: { + id: { + type: FieldType.AUTO, + name: "id", + autocolumn: true, + constraints: { + presence: true, + }, }, }, - }, - }) + } + ) const firstRow = await config.createRow({ name: "Test Contact", description: "original description", diff --git a/packages/server/src/db/tests/linkController.spec.js b/packages/server/src/db/tests/linkController.spec.js index 1c50142871..59d0f3f983 100644 --- a/packages/server/src/db/tests/linkController.spec.js +++ b/packages/server/src/db/tests/linkController.spec.js @@ -6,7 +6,7 @@ const { RelationshipType } = require("../../constants") const { cloneDeep } = require("lodash/fp") describe("test the link controller", () => { - let config = new TestConfig(false) + let config = new TestConfig() let table1, table2, appId beforeAll(async () => { diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index e521a5a6a6..94896932ad 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -563,9 +563,9 @@ class TestConfiguration { } async createLinkedTable( - config?: Table, relationshipType = RelationshipType.ONE_TO_MANY, - links: any = ["link"] + links: any = ["link"], + config?: Table ) { if (!this.table) { throw "Must have created a table first." From 21e5219bde49817b78d8dcf217784586550e277f Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 13 Sep 2023 12:10:55 +0000 Subject: [PATCH 109/128] Bump version to 2.10.7-alpha.0 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 63466ceedb..88bde5827a 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.6", + "version": "2.10.7-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" From 9c6e880479a059c099a1c17f884a9dbc4dd48a2c Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 15:03:21 +0200 Subject: [PATCH 110/128] Fix update datasource test helper --- packages/server/src/tests/utilities/api/datasource.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/server/src/tests/utilities/api/datasource.ts b/packages/server/src/tests/utilities/api/datasource.ts index 2ce09959fc..ee698334f2 100644 --- a/packages/server/src/tests/utilities/api/datasource.ts +++ b/packages/server/src/tests/utilities/api/datasource.ts @@ -30,16 +30,12 @@ export class DatasourceAPI extends TestAPI { } update = async ( - config: Datasource, + datasource: Datasource, { expectStatus } = { expectStatus: 200 } ): Promise => { - const body: CreateDatasourceRequest = { - datasource: config, - tablesFilter: [], - } const result = await this.request - .put(`/api/datasources/${config._id}`) - .send(body) + .put(`/api/datasources/${datasource._id}`) + .send(datasource) .set(this.config.defaultHeaders()) .expect("Content-Type", /json/) .expect(expectStatus) From d248c7b6b8357a3bc3f1a52e7e7bce6b62c7924f Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 15:26:29 +0200 Subject: [PATCH 111/128] Fix types --- packages/server/src/sdk/app/rows/search.ts | 2 +- packages/server/src/sdk/app/rows/search/internal.ts | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/server/src/sdk/app/rows/search.ts b/packages/server/src/sdk/app/rows/search.ts index b3bc220124..380521a05a 100644 --- a/packages/server/src/sdk/app/rows/search.ts +++ b/packages/server/src/sdk/app/rows/search.ts @@ -20,7 +20,7 @@ function pickApi(tableId: any) { export async function search(options: SearchParams): Promise<{ rows: any[] hasNextPage?: boolean - bookmark?: number | string | null + bookmark?: number | null }> { return pickApi(options.tableId).search(options) } diff --git a/packages/server/src/sdk/app/rows/search/internal.ts b/packages/server/src/sdk/app/rows/search/internal.ts index 0a6fd69ff6..4cdeca87f6 100644 --- a/packages/server/src/sdk/app/rows/search/internal.ts +++ b/packages/server/src/sdk/app/rows/search/internal.ts @@ -59,11 +59,7 @@ export async function search(options: SearchParams) { if (paginate) { response = await paginatedSearch(query, params) } else { - response = { - ...(await fullSearch(query, params)), - hasNextPage: false, - bookmark: null, - } + response = await fullSearch(query, params) } // Enrich search results with relationships From 891e77e2bfdc0e68fba12d4f44b4f5a48fbe4c04 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 15:28:38 +0200 Subject: [PATCH 112/128] Remove coverage from prettier --- .prettierignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index a73fed4890..64607d74ab 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,4 +9,5 @@ packages/backend-core/coverage packages/server/client packages/server/src/definitions/openapi.ts packages/builder/.routify -packages/sdk/sdk \ No newline at end of file +packages/sdk/sdk +packages/pro/coverage \ No newline at end of file From 17c365d398ce0e6cb4102fb79a4d5af7840d9026 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 15:39:59 +0200 Subject: [PATCH 113/128] Fix tests --- packages/server/src/api/routes/tests/row.spec.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index e3bfc32320..a74a9f7960 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1105,8 +1105,12 @@ describe.each([ ...defaultRowFields, })) ), - hasNextPage: false, - bookmark: null, + ...(isInternal + ? {} + : { + hasNextPage: false, + bookmark: null, + }), }) }) @@ -1153,8 +1157,12 @@ describe.each([ ...defaultRowFields, })) ), - hasNextPage: false, - bookmark: null, + ...(isInternal + ? {} + : { + hasNextPage: false, + bookmark: null, + }), }) }) From dc29ebfe273fac6cc8c195e91b705bd1b1e29fa0 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 15:54:44 +0200 Subject: [PATCH 114/128] Fix tests --- .../server/src/api/controllers/query/import/tests/index.spec.js | 2 +- packages/server/src/db/tests/linkTests.spec.js | 2 +- .../src/migrations/functions/usageQuotas/tests/syncRows.spec.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/query/import/tests/index.spec.js b/packages/server/src/api/controllers/query/import/tests/index.spec.js index 60030ae7f3..3aa9e7f916 100644 --- a/packages/server/src/api/controllers/query/import/tests/index.spec.js +++ b/packages/server/src/api/controllers/query/import/tests/index.spec.js @@ -39,7 +39,7 @@ const datasets = { } describe("Rest Importer", () => { - const config = new TestConfig(false) + const config = new TestConfig() beforeAll(async () => { await config.init() diff --git a/packages/server/src/db/tests/linkTests.spec.js b/packages/server/src/db/tests/linkTests.spec.js index b7764dacb7..19a0eb88d3 100644 --- a/packages/server/src/db/tests/linkTests.spec.js +++ b/packages/server/src/db/tests/linkTests.spec.js @@ -4,7 +4,7 @@ const linkUtils = require("../linkedRows/linkUtils") const { context } = require("@budibase/backend-core") describe("test link functionality", () => { - const config = new TestConfig(false) + const config = new TestConfig() let appId describe("getLinkedTable", () => { diff --git a/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts b/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts index fc0f9e1aa9..5257ffc042 100644 --- a/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +++ b/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts @@ -5,7 +5,7 @@ import { QuotaUsageType, StaticQuotaName } from "@budibase/types" import { db as dbCore, context } from "@budibase/backend-core" describe("syncRows", () => { - let config = new TestConfig(false) + let config = new TestConfig() beforeEach(async () => { await config.init() From be5e8005b2d6b2a2c0e5a8339d25e034914e506a Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 13 Sep 2023 14:06:52 +0000 Subject: [PATCH 115/128] Bump version to 2.10.7 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 63466ceedb..77f38e67ed 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.6", + "version": "2.10.7", "npmClient": "yarn", "packages": [ "packages/*" From 8af3e4bf6b5d6930126cb4302e0df67a5db2f6d8 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 13 Sep 2023 15:23:30 +0100 Subject: [PATCH 116/128] Found some discussion of testcontainers being problematic when nearly out of disk space, we have seen issues with the default Github runners as they have extremely limited disk space, this should help a bit removing android and dotnet, two pieces of functionality we will never need. --- .github/workflows/budibase_ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index d670e222d3..fc35575ec6 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -25,6 +25,13 @@ jobs: lint: runs-on: ubuntu-latest steps: + - name: Maximize build space + uses: easimon/maximize-build-space@master + with: + root-reserve-mb: 35000 + swap-size-mb: 1024 + remove-android: 'true' + remove-dotnet: 'true' - name: Checkout repo and submodules uses: actions/checkout@v3 if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'Budibase/budibase' From d1e1ad4930ae91ab595485d4f4a3696aee6567aa Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 16:33:04 +0200 Subject: [PATCH 117/128] Revert TestConfiguration changes --- .../src/tests/utilities/TestConfiguration.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index 94896932ad..da7af8acd7 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -535,7 +535,7 @@ class TestConfiguration { { skipReassigning } = { skipReassigning: false } ): Promise
{ config = config || basicTable() - const response = await this.api.table.create(config) + const response = await this._req(config, null, controllers.table.save) if (!skipReassigning) { this.table = response } @@ -589,7 +589,7 @@ class TestConfiguration { } } - const linkedTable = await this.api.table.create(tableConfig) + const linkedTable = await this.createTable(tableConfig) return linkedTable } @@ -609,7 +609,7 @@ class TestConfiguration { } const tableId = (config && config.tableId) || this.table._id config = config || basicRow(tableId!) - return this.api.row.save(tableId!, config) + return this._req(config, { tableId }, controllers.row.save) } async getRow(tableId: string, rowId: string): Promise { @@ -715,14 +715,18 @@ class TestConfiguration { datasource: Datasource }): Promise { config = config || basicDatasource() - const response = await this.api.datasource.create({ ...config.datasource }) - this.datasource = response + const response = await this._req(config, null, controllers.datasource.save) + this.datasource = response.datasource return this.datasource! } async updateDatasource(datasource: Datasource): Promise { - const response = await this.api.datasource.update(datasource) - this.datasource = response + const response = await this._req( + datasource, + { datasourceId: datasource._id }, + controllers.datasource.update + ) + this.datasource = response.datasource return this.datasource! } From 405ea4e37b9eff0d9c0eaec1b721a9382bc2af38 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Wed, 13 Sep 2023 16:39:23 +0200 Subject: [PATCH 118/128] Reverts --- .../server/src/api/controllers/query/import/tests/index.spec.js | 2 +- .../src/migrations/functions/usageQuotas/tests/syncRows.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/server/src/api/controllers/query/import/tests/index.spec.js b/packages/server/src/api/controllers/query/import/tests/index.spec.js index 3aa9e7f916..60030ae7f3 100644 --- a/packages/server/src/api/controllers/query/import/tests/index.spec.js +++ b/packages/server/src/api/controllers/query/import/tests/index.spec.js @@ -39,7 +39,7 @@ const datasets = { } describe("Rest Importer", () => { - const config = new TestConfig() + const config = new TestConfig(false) beforeAll(async () => { await config.init() diff --git a/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts b/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts index 5257ffc042..fc0f9e1aa9 100644 --- a/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts +++ b/packages/server/src/migrations/functions/usageQuotas/tests/syncRows.spec.ts @@ -5,7 +5,7 @@ import { QuotaUsageType, StaticQuotaName } from "@budibase/types" import { db as dbCore, context } from "@budibase/backend-core" describe("syncRows", () => { - let config = new TestConfig() + let config = new TestConfig(false) beforeEach(async () => { await config.init() From f70531d34322ce64ed6bc2f3e20df5e489e9e809 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 13 Sep 2023 15:00:27 +0000 Subject: [PATCH 119/128] Bump version to 2.10.7-alpha.1 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 88bde5827a..054621b521 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.7-alpha.0", + "version": "2.10.7-alpha.1", "npmClient": "yarn", "packages": [ "packages/*" From 78d0398315ec4f9e1edf47b7ec94480c0b887f61 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Wed, 13 Sep 2023 16:18:33 +0100 Subject: [PATCH 120/128] Update stale_bot.yml --- .github/workflows/stale_bot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale_bot.yml b/.github/workflows/stale_bot.yml index 8cda3a9342..f87d561db9 100644 --- a/.github/workflows/stale_bot.yml +++ b/.github/workflows/stale_bot.yml @@ -2,7 +2,7 @@ name: Close stale issues and PRs # https://github.com/actions/stale on: workflow_dispatch: schedule: - - cron: '30 1 * * *' # 1:30 every morning + - cron: '*/30 * * * *' # Every 30 mins jobs: stale: From 29358cec5f070840ef6ea4a836065c9f7755d5e8 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 13 Sep 2023 15:18:50 +0000 Subject: [PATCH 121/128] Bump version to 2.10.7-alpha.2 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 054621b521..a3a8bda618 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.7-alpha.1", + "version": "2.10.7-alpha.2", "npmClient": "yarn", "packages": [ "packages/*" From 6d74bb4063bc7580bad2c822a325f291d638aa7d Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 13 Sep 2023 18:01:20 +0000 Subject: [PATCH 122/128] Bump version to 2.10.8 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 77f38e67ed..30aa2afa3c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.7", + "version": "2.10.8", "npmClient": "yarn", "packages": [ "packages/*" From 37cb9261e8028bd62d21f0499d7b20aeba6ddd64 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 14 Sep 2023 09:28:43 +0000 Subject: [PATCH 123/128] Bump version to 2.10.9-alpha.0 --- lerna.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lerna.json b/lerna.json index d267691a6e..2394c5aa57 100644 --- a/lerna.json +++ b/lerna.json @@ -1,7 +1,9 @@ { - "version": "2.10.8", + "version": "2.10.9-alpha.0", "npmClient": "yarn", - "packages": ["packages/*"], + "packages": [ + "packages/*" + ], "useNx": true, "command": { "publish": { @@ -17,4 +19,4 @@ "loadEnvFiles": false } } -} +} \ No newline at end of file From 4daa996044837eaf344a60f1edb7ca53e1984700 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 14 Sep 2023 10:38:14 +0100 Subject: [PATCH 124/128] Adding console log to trigger cache bust and run tests. --- packages/backend-core/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index ffffd8240a..c540b717da 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -50,5 +50,6 @@ export * from "./constants" // expose package init function import * as db from "./db" export const init = (opts: any = {}) => { + console.log("test") db.init(opts.db) } From 4ca9ea97b66c0e96b4949b01566326594714de31 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 14 Sep 2023 10:55:41 +0100 Subject: [PATCH 125/128] Get server/worker tests to run. --- packages/server/src/index.ts | 1 + packages/worker/src/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index b3fbb22bde..46ec2035a7 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -11,6 +11,7 @@ function runServer() { process.env.GLOBAL_AGENT_FORCE_GLOBAL_AGENT = "false" bootstrap() require("./app") + console.log("test") } runServer() diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 30596d1d76..7212e8207c 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -109,6 +109,7 @@ export default server.listen(parseInt(env.PORT || "4002"), async () => { console.log(`Worker running on ${JSON.stringify(server.address())}`) await initPro() await redis.init() + console.log("test") }) process.on("uncaughtException", err => { From 26c6393f06c102379f3f4a0a2886272b3cda71a8 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 14 Sep 2023 11:11:05 +0100 Subject: [PATCH 126/128] Adding retries to 409 test. --- packages/worker/src/api/routes/global/tests/scim.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/worker/src/api/routes/global/tests/scim.spec.ts b/packages/worker/src/api/routes/global/tests/scim.spec.ts index 5686e39fa8..fba1523cd4 100644 --- a/packages/worker/src/api/routes/global/tests/scim.spec.ts +++ b/packages/worker/src/api/routes/global/tests/scim.spec.ts @@ -10,6 +10,8 @@ import { import { TestConfiguration } from "../../../../tests" import { events } from "@budibase/backend-core" +// this test can 409 - retries reduce issues with this +jest.retryTimes(2) jest.setTimeout(30000) mocks.licenses.useScimIntegration() From 5f82b79d40d37f66a132a7f12bd43ed281444e90 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 14 Sep 2023 11:42:04 +0100 Subject: [PATCH 127/128] Removing test logs. --- packages/backend-core/src/index.ts | 1 - packages/server/src/index.ts | 1 - packages/worker/src/index.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index c540b717da..ffffd8240a 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -50,6 +50,5 @@ export * from "./constants" // expose package init function import * as db from "./db" export const init = (opts: any = {}) => { - console.log("test") db.init(opts.db) } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 46ec2035a7..b3fbb22bde 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -11,7 +11,6 @@ function runServer() { process.env.GLOBAL_AGENT_FORCE_GLOBAL_AGENT = "false" bootstrap() require("./app") - console.log("test") } runServer() diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 7212e8207c..30596d1d76 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -109,7 +109,6 @@ export default server.listen(parseInt(env.PORT || "4002"), async () => { console.log(`Worker running on ${JSON.stringify(server.address())}`) await initPro() await redis.init() - console.log("test") }) process.on("uncaughtException", err => { From f15ca351cd00ddc525055c65c2138a0c92ce3960 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 14 Sep 2023 11:03:14 +0000 Subject: [PATCH 128/128] Bump version to 2.10.9-alpha.1 --- lerna.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 68cc011c5b..a428ef9af6 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.10.9-alpha.0", + "version": "2.10.9-alpha.1", "npmClient": "yarn", "packages": [ "packages/*" @@ -19,4 +19,4 @@ "loadEnvFiles": false } } -} +} \ No newline at end of file