From 3fc170c16bd1a99848cc260c94440f381497e4e2 Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Tue, 15 Oct 2024 17:33:32 +0100 Subject: [PATCH 01/16] Add settings to automation context. --- .../src/api/routes/tests/automation.spec.ts | 66 +++++++++++++++++-- .../tests/utilities/AutomationTestBuilder.ts | 7 +- .../server/src/definitions/automations.ts | 5 ++ packages/server/src/threads/automation.ts | 9 ++- 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/packages/server/src/api/routes/tests/automation.spec.ts b/packages/server/src/api/routes/tests/automation.spec.ts index b6233b24ad..a517346c82 100644 --- a/packages/server/src/api/routes/tests/automation.spec.ts +++ b/packages/server/src/api/routes/tests/automation.spec.ts @@ -9,9 +9,15 @@ import { TRIGGER_DEFINITIONS, BUILTIN_ACTION_DEFINITIONS, } from "../../../automations" -import { events } from "@budibase/backend-core" +import { configs, context, events } from "@budibase/backend-core" import sdk from "../../../sdk" -import { Automation, FieldType, Table } from "@budibase/types" +import { + Automation, + ConfigType, + FieldType, + SettingsConfig, + Table, +} from "@budibase/types" import { mocks } from "@budibase/backend-core/tests" import { FilterConditions } from "../../../automations/steps/filter" import { removeDeprecated } from "../../../automations/utils" @@ -39,8 +45,7 @@ describe("/automations", () => { }) beforeEach(() => { - // @ts-ignore - events.automation.deleted.mockClear() + jest.clearAllMocks() }) describe("get definitions", () => { @@ -244,6 +249,59 @@ describe("/automations", () => { }) }) + describe("run", () => { + let oldConfig: SettingsConfig + beforeAll(async () => { + await context.doInTenant(config.getTenantId(), async () => { + oldConfig = await configs.getSettingsConfigDoc() + + const settings: SettingsConfig = { + _id: oldConfig._id, + _rev: oldConfig._rev, + type: ConfigType.SETTINGS, + config: { + platformUrl: "https://example.com", + logoUrl: "https://example.com/logo.png", + company: "Test Company", + }, + } + const saved = await configs.save(settings) + oldConfig._rev = saved.rev + }) + }) + + afterAll(async () => { + await context.doInTenant(config.getTenantId(), async () => { + await configs.save(oldConfig) + }) + }) + + it("should be able to access platformUrl, logoUrl and company in the automation", async () => { + const result = await createAutomationBuilder({ + name: "Test Automation", + appId: config.getAppId(), + config, + }) + .appAction({ fields: {} }) + .serverLog({ + text: "{{ settings.url }}", + }) + .serverLog({ + text: "{{ settings.logo }}", + }) + .serverLog({ + text: "{{ settings.company }}", + }) + .run() + + expect(result.steps[0].outputs.message).toEndWith("https://example.com") + expect(result.steps[1].outputs.message).toEndWith( + "https://example.com/logo.png" + ) + expect(result.steps[2].outputs.message).toEndWith("Test Company") + }) + }) + describe("test", () => { it("tests the automation successfully", async () => { let table = await config.createTable() diff --git a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts index 6aaf22cd6a..fa8061edce 100644 --- a/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts +++ b/packages/server/src/automations/tests/utilities/AutomationTestBuilder.ts @@ -225,7 +225,9 @@ class AutomationBuilder extends BaseStepBuilder { private triggerOutputs: any private triggerSet: boolean = false - constructor(options: { name?: string; appId?: string } = {}) { + constructor( + options: { name?: string; appId?: string; config?: TestConfiguration } = {} + ) { super() this.automationConfig = { name: options.name || `Test Automation ${uuidv4()}`, @@ -237,7 +239,7 @@ class AutomationBuilder extends BaseStepBuilder { type: "automation", appId: options.appId ?? setup.getConfig().getAppId(), } - this.config = setup.getConfig() + this.config = options.config || setup.getConfig() } // TRIGGERS @@ -347,6 +349,7 @@ class AutomationBuilder extends BaseStepBuilder { export function createAutomationBuilder(options?: { name?: string appId?: string + config?: TestConfiguration }) { return new AutomationBuilder(options) } diff --git a/packages/server/src/definitions/automations.ts b/packages/server/src/definitions/automations.ts index 9433075da7..afee81ee0a 100644 --- a/packages/server/src/definitions/automations.ts +++ b/packages/server/src/definitions/automations.ts @@ -19,4 +19,9 @@ export interface AutomationContext extends AutomationResults { stepsByName: Record env?: Record trigger: any + settings?: { + url?: string + logo?: string + company?: string + } } diff --git a/packages/server/src/threads/automation.ts b/packages/server/src/threads/automation.ts index 3b47634663..f7db52ec1a 100644 --- a/packages/server/src/threads/automation.ts +++ b/packages/server/src/threads/automation.ts @@ -29,7 +29,7 @@ import { } from "@budibase/types" import { AutomationContext, TriggerOutput } from "../definitions/automations" import { WorkerCallback } from "./definitions" -import { context, logging } from "@budibase/backend-core" +import { context, logging, configs } from "@budibase/backend-core" import { processObject, processStringSync } from "@budibase/string-templates" import { cloneDeep } from "lodash/fp" import { performance } from "perf_hooks" @@ -259,6 +259,13 @@ class Orchestrator { }) this.context.env = await sdkUtils.getEnvironmentVariables() + const { config } = await configs.getSettingsConfigDoc() + this.context.settings = { + url: config.platformUrl, + logo: config.logoUrl, + company: config.company, + } + let metadata // check if this is a recurring automation, From e53ec31305741a9d1b8201296cab25ab0d1f49c1 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 25 Oct 2024 13:20:15 +0200 Subject: [PATCH 02/16] Add row create test --- .../server/src/api/routes/tests/row.spec.ts | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 31067ab40f..d79a8a7379 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -939,6 +939,74 @@ describe.each([ }) }) }) + + describe("relations to same table", () => { + let relatedRows: Row[] + + beforeAll(async () => { + const relatedTable = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + }, + }) + ) + const relatedTableId = relatedTable._id! + table = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + related1: { + type: FieldType.LINK, + name: "related1", + fieldName: "main1", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + related2: { + type: FieldType.LINK, + name: "related2", + fieldName: "main2", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + }, + }) + ) + relatedRows = await Promise.all([ + config.api.row.save(relatedTableId, { name: "foo" }), + config.api.row.save(relatedTableId, { name: "bar" }), + config.api.row.save(relatedTableId, { name: "baz" }), + config.api.row.save(relatedTableId, { name: "boo" }), + ]) + }) + + it("can create rows with both relationships", async () => { + const row = await config.api.row.save(table._id!, { + name: "test", + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + related1: [ + { + _id: relatedRows[0]._id, + primaryDisplay: relatedRows[0].name, + }, + ], + related2: [ + { + _id: relatedRows[1]._id, + primaryDisplay: relatedRows[1].name, + }, + ], + }) + ) + }) + }) }) describe("get", () => { From d044d56801fc0f53184388da21ecee9f88e2c124 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 25 Oct 2024 13:25:28 +0200 Subject: [PATCH 03/16] Add more tests --- .../server/src/api/routes/tests/row.spec.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index d79a8a7379..4bfd612775 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1006,6 +1006,36 @@ describe.each([ }) ) }) + + it("can create rows with no relationships", async () => { + const row = await config.api.row.save(table._id!, { + name: "test", + }) + + expect(row.related1).toBeUndefined() + expect(row.related2).toBeUndefined() + }) + + it("can create rows with only one relationships field", async () => { + const row = await config.api.row.save(table._id!, { + name: "test", + related1: [], + related2: [relatedRows[1]._id!], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + related2: [ + { + _id: relatedRows[1]._id, + primaryDisplay: relatedRows[1].name, + }, + ], + }) + ) + expect(row.related1).toBeUndefined() + }) }) }) From 5efcf97c0d6815d8cc80fe06216b8c5d160602b3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 25 Oct 2024 15:16:54 +0200 Subject: [PATCH 04/16] Add more tests --- .../server/src/api/routes/tests/row.spec.ts | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 4bfd612775..32788d2783 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1139,6 +1139,133 @@ describe.each([ const rows = await config.api.row.fetch(table._id!) expect(rows).toHaveLength(1) }) + + describe("relations to same table", () => { + let relatedRows: Row[] + + beforeAll(async () => { + const relatedTable = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + }, + }) + ) + const relatedTableId = relatedTable._id! + table = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + related1: { + type: FieldType.LINK, + name: "related1", + fieldName: "main1", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + related2: { + type: FieldType.LINK, + name: "related2", + fieldName: "main2", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + }, + }) + ) + relatedRows = await Promise.all([ + config.api.row.save(relatedTableId, { name: "foo" }), + config.api.row.save(relatedTableId, { name: "bar" }), + config.api.row.save(relatedTableId, { name: "baz" }), + config.api.row.save(relatedTableId, { name: "boo" }), + ]) + }) + + it("can edit rows with both relationships", async () => { + let row = await config.api.row.save(table._id!, { + name: "test", + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], + }) + + row = await config.api.row.save(table._id!, { + ...row, + related1: [relatedRows[0]._id!, relatedRows[1]._id!], + related2: [relatedRows[2]._id!], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + related1: [ + { + _id: relatedRows[1]._id, + primaryDisplay: relatedRows[1].name, + }, + { + _id: relatedRows[0]._id, + primaryDisplay: relatedRows[0].name, + }, + ], + related2: [ + { + _id: relatedRows[2]._id, + primaryDisplay: relatedRows[2].name, + }, + ], + }) + ) + }) + + it("can drop existing relationship", async () => { + let row = await config.api.row.save(table._id!, { + name: "test", + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], + }) + + row = await config.api.row.save(table._id!, { + ...row, + related1: [], + related2: [relatedRows[2]._id!], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + related2: [ + { + _id: relatedRows[2]._id, + primaryDisplay: relatedRows[2].name, + }, + ], + }) + ) + expect(row.related1).toBeUndefined() + }) + + it("can drop both relationships", async () => { + let row = await config.api.row.save(table._id!, { + name: "test", + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], + }) + + row = await config.api.row.save(table._id!, { + ...row, + related1: [], + related2: [], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + }) + ) + expect(row.related1).toBeUndefined() + expect(row.related2).toBeUndefined() + }) + }) }) describe("patch", () => { From 96be44781779b981de7b3350ff21004e449e3e36 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 25 Oct 2024 15:22:57 +0200 Subject: [PATCH 05/16] Fix many to many --- .../api/controllers/row/ExternalRequest.ts | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 5ceed002de..527bc4b3ef 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -425,8 +425,12 @@ export class ExternalRequest { */ async lookupRelations(tableId: string, row: Row) { const related: { - [key: string]: { rows: Row[]; isMany: boolean; tableId: string } - } = {} + rows: Row[] + isMany: boolean + tableId: string + field: string + }[] = [] + const { tableName } = breakExternalTableId(tableId) const table = this.tables[tableName] // @ts-ignore @@ -489,11 +493,13 @@ export class ExternalRequest { const storeTo = isManyToMany(field) ? field.throughFrom || linkPrimaryKey : fieldName - related[storeTo] = { + + related.push({ rows, isMany: isManyToMany(field), tableId: relatedTableId, - } + field: storeTo, + }) } return related } @@ -528,7 +534,9 @@ export class ExternalRequest { const linkSecondary = relationshipPrimary[1] - const rows = related[key]?.rows || [] + const rows = + related.find(r => r.tableId === relationship.tableId && r.field === key) + ?.rows || [] const relationshipMatchPredicate = ({ row, @@ -573,12 +581,12 @@ export class ExternalRequest { } } // finally cleanup anything that needs to be removed - for (let [colName, { isMany, rows, tableId }] of Object.entries(related)) { + for (let { isMany, rows, tableId, field } of related) { const table: Table | undefined = this.getTable(tableId) // if it's not the foreign key skip it, nothing to do if ( !table || - (!isMany && table.primary && table.primary.indexOf(colName) !== -1) + (!isMany && table.primary && table.primary.indexOf(field) !== -1) ) { continue } @@ -586,7 +594,7 @@ export class ExternalRequest { const rowId = generateIdForRow(row, table) const promise: Promise = isMany ? this.removeManyToManyRelationships(rowId, table) - : this.removeOneToManyRelationships(rowId, table, colName) + : this.removeOneToManyRelationships(rowId, table, field) if (promise) { promises.push(promise) } @@ -603,7 +611,9 @@ export class ExternalRequest { if (!isManyToOne(relationshipColumn)) { continue } - const { rows, isMany, tableId } = related[relationshipColumn.fieldName] + const { rows, isMany, tableId } = related.find( + r => r.field === relationshipColumn.fieldName + )! const table = this.getTable(tableId)! await Promise.all( rows.map(row => { From 00eedbf72685d6a8a24f3b9a946f054d9a0de8e3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 25 Oct 2024 16:57:50 +0200 Subject: [PATCH 06/16] Fix deletions --- .../api/controllers/row/ExternalRequest.ts | 27 ++++---- .../server/src/api/routes/tests/row.spec.ts | 66 +++++++++++++++++++ 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 527bc4b3ef..1fb8ce0423 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -11,6 +11,7 @@ import { IncludeRelationship, InternalSearchFilterOperator, isManyToOne, + isOneToMany, OneToManyRelationshipFieldMetadata, Operation, PaginationJson, @@ -50,6 +51,7 @@ import sdk from "../../../sdk" import env from "../../../environment" import { makeExternalQuery } from "../../../integrations/base/query" import { dataFilters, helpers } from "@budibase/shared-core" +import { isRelationshipColumn } from "../../../db/utils" export interface ManyRelationship { tableId?: string @@ -606,25 +608,28 @@ export class ExternalRequest { async removeRelationshipsToRow(table: Table, rowId: string) { const row = await this.getRow(table, rowId) const related = await this.lookupRelations(table._id!, row) - for (let column of Object.values(table.schema)) { - const relationshipColumn = column as RelationshipFieldMetadata - if (!isManyToOne(relationshipColumn)) { + for (const column of Object.values(table.schema)) { + if (!isRelationshipColumn(column) || isOneToMany(column)) { continue } - const { rows, isMany, tableId } = related.find( - r => r.field === relationshipColumn.fieldName - )! + + const relatedByTable = isManyToMany(column) + ? related.find( + r => r.tableId === column.through && r.field === column.fieldName + ) + : related.find(r => r.field === column.fieldName) + if (!relatedByTable) { + continue + } + + const { rows, isMany, tableId } = relatedByTable const table = this.getTable(tableId)! await Promise.all( rows.map(row => { const rowId = generateIdForRow(row, table) return isMany ? this.removeManyToManyRelationships(rowId, table) - : this.removeOneToManyRelationships( - rowId, - table, - relationshipColumn.fieldName - ) + : this.removeOneToManyRelationships(rowId, table, column.fieldName) }) ) } diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 32788d2783..19d6595619 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1542,6 +1542,72 @@ describe.each([ ) expect(res.length).toEqual(2) }) + + describe("relations to same table", () => { + let relatedRows: Row[] + + beforeAll(async () => { + const relatedTable = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + }, + }) + ) + const relatedTableId = relatedTable._id! + table = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + related1: { + type: FieldType.LINK, + name: "related1", + fieldName: "main1", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + related2: { + type: FieldType.LINK, + name: "related2", + fieldName: "main2", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + }, + }) + ) + relatedRows = await Promise.all([ + config.api.row.save(relatedTableId, { name: "foo" }), + config.api.row.save(relatedTableId, { name: "bar" }), + config.api.row.save(relatedTableId, { name: "baz" }), + config.api.row.save(relatedTableId, { name: "boo" }), + ]) + }) + + it("can delete rows with both relationships", async () => { + const row = await config.api.row.save(table._id!, { + name: "test", + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], + }) + + await config.api.row.delete(table._id!, { _id: row._id! }) + + await config.api.row.get(table._id!, row._id!, { status: 404 }) + }) + + it("can delete rows with empty relationships", async () => { + const row = await config.api.row.save(table._id!, { + name: "test", + related1: [], + related2: [], + }) + + await config.api.row.delete(table._id!, { _id: row._id! }) + + await config.api.row.get(table._id!, row._id!, { status: 404 }) + }) + }) }) describe("validate", () => { From a01c5ed654dbc3100522bc5267269b406a317e97 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Fri, 25 Oct 2024 17:01:25 +0200 Subject: [PATCH 07/16] Don't run tests for lucene --- .../server/src/api/routes/tests/row.spec.ts | 495 +++++++++--------- 1 file changed, 249 insertions(+), 246 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 19d6595619..19f11a044a 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -940,103 +940,104 @@ describe.each([ }) }) - describe("relations to same table", () => { - let relatedRows: Row[] + !isLucene && + describe("relations to same table", () => { + let relatedRows: Row[] - beforeAll(async () => { - const relatedTable = await config.api.table.save( - defaultTable({ - schema: { - name: { name: "name", type: FieldType.STRING }, - }, - }) - ) - const relatedTableId = relatedTable._id! - table = await config.api.table.save( - defaultTable({ - schema: { - name: { name: "name", type: FieldType.STRING }, - related1: { - type: FieldType.LINK, - name: "related1", - fieldName: "main1", - tableId: relatedTableId, - relationshipType: RelationshipType.MANY_TO_MANY, + beforeAll(async () => { + const relatedTable = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, }, - related2: { - type: FieldType.LINK, - name: "related2", - fieldName: "main2", - tableId: relatedTableId, - relationshipType: RelationshipType.MANY_TO_MANY, + }) + ) + const relatedTableId = relatedTable._id! + table = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + related1: { + type: FieldType.LINK, + name: "related1", + fieldName: "main1", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + related2: { + type: FieldType.LINK, + name: "related2", + fieldName: "main2", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, }, - }, - }) - ) - relatedRows = await Promise.all([ - config.api.row.save(relatedTableId, { name: "foo" }), - config.api.row.save(relatedTableId, { name: "bar" }), - config.api.row.save(relatedTableId, { name: "baz" }), - config.api.row.save(relatedTableId, { name: "boo" }), - ]) - }) - - it("can create rows with both relationships", async () => { - const row = await config.api.row.save(table._id!, { - name: "test", - related1: [relatedRows[0]._id!], - related2: [relatedRows[1]._id!], + }) + ) + relatedRows = await Promise.all([ + config.api.row.save(relatedTableId, { name: "foo" }), + config.api.row.save(relatedTableId, { name: "bar" }), + config.api.row.save(relatedTableId, { name: "baz" }), + config.api.row.save(relatedTableId, { name: "boo" }), + ]) }) - expect(row).toEqual( - expect.objectContaining({ + it("can create rows with both relationships", async () => { + const row = await config.api.row.save(table._id!, { name: "test", - related1: [ - { - _id: relatedRows[0]._id, - primaryDisplay: relatedRows[0].name, - }, - ], - related2: [ - { - _id: relatedRows[1]._id, - primaryDisplay: relatedRows[1].name, - }, - ], + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], }) - ) - }) - it("can create rows with no relationships", async () => { - const row = await config.api.row.save(table._id!, { - name: "test", + expect(row).toEqual( + expect.objectContaining({ + name: "test", + related1: [ + { + _id: relatedRows[0]._id, + primaryDisplay: relatedRows[0].name, + }, + ], + related2: [ + { + _id: relatedRows[1]._id, + primaryDisplay: relatedRows[1].name, + }, + ], + }) + ) }) - expect(row.related1).toBeUndefined() - expect(row.related2).toBeUndefined() - }) - - it("can create rows with only one relationships field", async () => { - const row = await config.api.row.save(table._id!, { - name: "test", - related1: [], - related2: [relatedRows[1]._id!], - }) - - expect(row).toEqual( - expect.objectContaining({ + it("can create rows with no relationships", async () => { + const row = await config.api.row.save(table._id!, { name: "test", - related2: [ - { - _id: relatedRows[1]._id, - primaryDisplay: relatedRows[1].name, - }, - ], }) - ) - expect(row.related1).toBeUndefined() + + expect(row.related1).toBeUndefined() + expect(row.related2).toBeUndefined() + }) + + it("can create rows with only one relationships field", async () => { + const row = await config.api.row.save(table._id!, { + name: "test", + related1: [], + related2: [relatedRows[1]._id!], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + related2: [ + { + _id: relatedRows[1]._id, + primaryDisplay: relatedRows[1].name, + }, + ], + }) + ) + expect(row.related1).toBeUndefined() + }) }) - }) }) describe("get", () => { @@ -1140,132 +1141,133 @@ describe.each([ expect(rows).toHaveLength(1) }) - describe("relations to same table", () => { - let relatedRows: Row[] + !isLucene && + describe("relations to same table", () => { + let relatedRows: Row[] - beforeAll(async () => { - const relatedTable = await config.api.table.save( - defaultTable({ - schema: { - name: { name: "name", type: FieldType.STRING }, - }, - }) - ) - const relatedTableId = relatedTable._id! - table = await config.api.table.save( - defaultTable({ - schema: { - name: { name: "name", type: FieldType.STRING }, - related1: { - type: FieldType.LINK, - name: "related1", - fieldName: "main1", - tableId: relatedTableId, - relationshipType: RelationshipType.MANY_TO_MANY, + beforeAll(async () => { + const relatedTable = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, }, - related2: { - type: FieldType.LINK, - name: "related2", - fieldName: "main2", - tableId: relatedTableId, - relationshipType: RelationshipType.MANY_TO_MANY, + }) + ) + const relatedTableId = relatedTable._id! + table = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + related1: { + type: FieldType.LINK, + name: "related1", + fieldName: "main1", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + related2: { + type: FieldType.LINK, + name: "related2", + fieldName: "main2", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, }, - }, - }) - ) - relatedRows = await Promise.all([ - config.api.row.save(relatedTableId, { name: "foo" }), - config.api.row.save(relatedTableId, { name: "bar" }), - config.api.row.save(relatedTableId, { name: "baz" }), - config.api.row.save(relatedTableId, { name: "boo" }), - ]) - }) - - it("can edit rows with both relationships", async () => { - let row = await config.api.row.save(table._id!, { - name: "test", - related1: [relatedRows[0]._id!], - related2: [relatedRows[1]._id!], + }) + ) + relatedRows = await Promise.all([ + config.api.row.save(relatedTableId, { name: "foo" }), + config.api.row.save(relatedTableId, { name: "bar" }), + config.api.row.save(relatedTableId, { name: "baz" }), + config.api.row.save(relatedTableId, { name: "boo" }), + ]) }) - row = await config.api.row.save(table._id!, { - ...row, - related1: [relatedRows[0]._id!, relatedRows[1]._id!], - related2: [relatedRows[2]._id!], - }) - - expect(row).toEqual( - expect.objectContaining({ + it("can edit rows with both relationships", async () => { + let row = await config.api.row.save(table._id!, { name: "test", - related1: [ - { - _id: relatedRows[1]._id, - primaryDisplay: relatedRows[1].name, - }, - { - _id: relatedRows[0]._id, - primaryDisplay: relatedRows[0].name, - }, - ], - related2: [ - { - _id: relatedRows[2]._id, - primaryDisplay: relatedRows[2].name, - }, - ], + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], }) - ) - }) - it("can drop existing relationship", async () => { - let row = await config.api.row.save(table._id!, { - name: "test", - related1: [relatedRows[0]._id!], - related2: [relatedRows[1]._id!], + row = await config.api.row.save(table._id!, { + ...row, + related1: [relatedRows[0]._id!, relatedRows[1]._id!], + related2: [relatedRows[2]._id!], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + related1: [ + { + _id: relatedRows[1]._id, + primaryDisplay: relatedRows[1].name, + }, + { + _id: relatedRows[0]._id, + primaryDisplay: relatedRows[0].name, + }, + ], + related2: [ + { + _id: relatedRows[2]._id, + primaryDisplay: relatedRows[2].name, + }, + ], + }) + ) }) - row = await config.api.row.save(table._id!, { - ...row, - related1: [], - related2: [relatedRows[2]._id!], - }) - - expect(row).toEqual( - expect.objectContaining({ + it("can drop existing relationship", async () => { + let row = await config.api.row.save(table._id!, { name: "test", - related2: [ - { - _id: relatedRows[2]._id, - primaryDisplay: relatedRows[2].name, - }, - ], + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], }) - ) - expect(row.related1).toBeUndefined() - }) - it("can drop both relationships", async () => { - let row = await config.api.row.save(table._id!, { - name: "test", - related1: [relatedRows[0]._id!], - related2: [relatedRows[1]._id!], + row = await config.api.row.save(table._id!, { + ...row, + related1: [], + related2: [relatedRows[2]._id!], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + related2: [ + { + _id: relatedRows[2]._id, + primaryDisplay: relatedRows[2].name, + }, + ], + }) + ) + expect(row.related1).toBeUndefined() }) - row = await config.api.row.save(table._id!, { - ...row, - related1: [], - related2: [], - }) - - expect(row).toEqual( - expect.objectContaining({ + it("can drop both relationships", async () => { + let row = await config.api.row.save(table._id!, { name: "test", + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], }) - ) - expect(row.related1).toBeUndefined() - expect(row.related2).toBeUndefined() + + row = await config.api.row.save(table._id!, { + ...row, + related1: [], + related2: [], + }) + + expect(row).toEqual( + expect.objectContaining({ + name: "test", + }) + ) + expect(row.related1).toBeUndefined() + expect(row.related2).toBeUndefined() + }) }) - }) }) describe("patch", () => { @@ -1543,71 +1545,72 @@ describe.each([ expect(res.length).toEqual(2) }) - describe("relations to same table", () => { - let relatedRows: Row[] + !isLucene && + describe("relations to same table", () => { + let relatedRows: Row[] - beforeAll(async () => { - const relatedTable = await config.api.table.save( - defaultTable({ - schema: { - name: { name: "name", type: FieldType.STRING }, - }, - }) - ) - const relatedTableId = relatedTable._id! - table = await config.api.table.save( - defaultTable({ - schema: { - name: { name: "name", type: FieldType.STRING }, - related1: { - type: FieldType.LINK, - name: "related1", - fieldName: "main1", - tableId: relatedTableId, - relationshipType: RelationshipType.MANY_TO_MANY, + beforeAll(async () => { + const relatedTable = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, }, - related2: { - type: FieldType.LINK, - name: "related2", - fieldName: "main2", - tableId: relatedTableId, - relationshipType: RelationshipType.MANY_TO_MANY, + }) + ) + const relatedTableId = relatedTable._id! + table = await config.api.table.save( + defaultTable({ + schema: { + name: { name: "name", type: FieldType.STRING }, + related1: { + type: FieldType.LINK, + name: "related1", + fieldName: "main1", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, + related2: { + type: FieldType.LINK, + name: "related2", + fieldName: "main2", + tableId: relatedTableId, + relationshipType: RelationshipType.MANY_TO_MANY, + }, }, - }, - }) - ) - relatedRows = await Promise.all([ - config.api.row.save(relatedTableId, { name: "foo" }), - config.api.row.save(relatedTableId, { name: "bar" }), - config.api.row.save(relatedTableId, { name: "baz" }), - config.api.row.save(relatedTableId, { name: "boo" }), - ]) - }) - - it("can delete rows with both relationships", async () => { - const row = await config.api.row.save(table._id!, { - name: "test", - related1: [relatedRows[0]._id!], - related2: [relatedRows[1]._id!], + }) + ) + relatedRows = await Promise.all([ + config.api.row.save(relatedTableId, { name: "foo" }), + config.api.row.save(relatedTableId, { name: "bar" }), + config.api.row.save(relatedTableId, { name: "baz" }), + config.api.row.save(relatedTableId, { name: "boo" }), + ]) }) - await config.api.row.delete(table._id!, { _id: row._id! }) + it("can delete rows with both relationships", async () => { + const row = await config.api.row.save(table._id!, { + name: "test", + related1: [relatedRows[0]._id!], + related2: [relatedRows[1]._id!], + }) - await config.api.row.get(table._id!, row._id!, { status: 404 }) - }) + await config.api.row.delete(table._id!, { _id: row._id! }) - it("can delete rows with empty relationships", async () => { - const row = await config.api.row.save(table._id!, { - name: "test", - related1: [], - related2: [], + await config.api.row.get(table._id!, row._id!, { status: 404 }) }) - await config.api.row.delete(table._id!, { _id: row._id! }) + it("can delete rows with empty relationships", async () => { + const row = await config.api.row.save(table._id!, { + name: "test", + related1: [], + related2: [], + }) - await config.api.row.get(table._id!, row._id!, { status: 404 }) + await config.api.row.delete(table._id!, { _id: row._id! }) + + await config.api.row.get(table._id!, row._id!, { status: 404 }) + }) }) - }) }) describe("validate", () => { From 407484bbe53e7ed05e3a2381b1fdd98547a21def Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Fri, 25 Oct 2024 16:21:10 +0100 Subject: [PATCH 08/16] Respond to PR comments. --- packages/server/src/threads/automation.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/server/src/threads/automation.ts b/packages/server/src/threads/automation.ts index 7083562006..1af8646cf4 100644 --- a/packages/server/src/threads/automation.ts +++ b/packages/server/src/threads/automation.ts @@ -263,11 +263,16 @@ class Orchestrator { this.context.env = await sdkUtils.getEnvironmentVariables() this.context.user = this.currentUser - const { config } = await configs.getSettingsConfigDoc() - this.context.settings = { - url: config.platformUrl, - logo: config.logoUrl, - company: config.company, + try { + const { config } = await configs.getSettingsConfigDoc() + this.context.settings = { + url: config.platformUrl, + logo: config.logoUrl, + company: config.company, + } + } catch (e) { + // if settings doc doesn't exist, make the settings blank + this.context.settings = {} } let metadata From 708b1d652739691466be8c311ba18b3e19f9b13d Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 28 Oct 2024 10:37:25 +0100 Subject: [PATCH 09/16] Update yarn.lock --- yarn.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1198e98ad6..9810b76ef3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2051,7 +2051,7 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.32.11": +"@budibase/backend-core@2.33.2": version "0.0.0" dependencies: "@budibase/nano" "10.1.5" @@ -2132,15 +2132,15 @@ through2 "^2.0.0" "@budibase/pro@npm:@budibase/pro@latest": - version "2.32.11" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.32.11.tgz#c94d534f829ca0ef252677757e157a7e58b87b4d" - integrity sha512-mOkqJpqHKWsfTWZwWcvBCYFUIluSUHltQNinc1ZRsg9rC3OKoHSDop6gzm744++H/GzGRN8V86kLhCgtNIlkpA== + version "2.33.2" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.33.2.tgz#5c2012f7b2bf0fd871cda1ad37ad7a0442c84658" + integrity sha512-lBB6Wfp6OIOHRlGq82WS9KxvEXRs/P2QlwJT0Aj9PhmkQFsnXm2r8d18f0xTGvcflD+iR7XGP/k56JlCanmhQg== dependencies: "@anthropic-ai/sdk" "^0.27.3" - "@budibase/backend-core" "2.32.11" - "@budibase/shared-core" "2.32.11" - "@budibase/string-templates" "2.32.11" - "@budibase/types" "2.32.11" + "@budibase/backend-core" "2.33.2" + "@budibase/shared-core" "2.33.2" + "@budibase/string-templates" "2.33.2" + "@budibase/types" "2.33.2" "@koa/router" "8.0.8" bull "4.10.1" dd-trace "5.2.0" @@ -2153,13 +2153,13 @@ scim-patch "^0.8.1" scim2-parse-filter "^0.2.8" -"@budibase/shared-core@2.32.11": +"@budibase/shared-core@2.33.2": version "0.0.0" dependencies: "@budibase/types" "0.0.0" cron-validate "1.4.5" -"@budibase/string-templates@2.32.11": +"@budibase/string-templates@2.33.2": version "0.0.0" dependencies: "@budibase/handlebars-helpers" "^0.13.2" @@ -2167,7 +2167,7 @@ handlebars "^4.7.8" lodash.clonedeep "^4.5.0" -"@budibase/types@2.32.11": +"@budibase/types@2.33.2": version "0.0.0" dependencies: scim-patch "^0.8.1" From 8aeb19aabe0058e7ab895528198c582ae4f101d5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 28 Oct 2024 10:54:00 +0100 Subject: [PATCH 10/16] Fix flakiness --- packages/server/src/api/routes/tests/row.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index 19f11a044a..72ade0a69a 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -1199,16 +1199,16 @@ describe.each([ expect(row).toEqual( expect.objectContaining({ name: "test", - related1: [ - { - _id: relatedRows[1]._id, - primaryDisplay: relatedRows[1].name, - }, + related1: expect.arrayContaining([ { _id: relatedRows[0]._id, primaryDisplay: relatedRows[0].name, }, - ], + { + _id: relatedRows[1]._id, + primaryDisplay: relatedRows[1].name, + }, + ]), related2: [ { _id: relatedRows[2]._id, From 95de01c86c8971a745eaf0f2107ed17e5213da30 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 28 Oct 2024 13:17:07 +0100 Subject: [PATCH 11/16] Simplifying lookups --- .../api/controllers/row/ExternalRequest.ts | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 1fb8ce0423..c5ebe69aea 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -17,6 +17,7 @@ import { PaginationJson, QueryJson, RelationshipFieldMetadata, + RelationshipType, Row, SearchFilters, SortJson, @@ -421,17 +422,30 @@ export class ExternalRequest { return { row: newRow as T, manyRelationships } } + private getLookupRelationsKey(relationship: { + relationshipType: RelationshipType + fieldName: string + through?: string + }) { + if (relationship.relationshipType === RelationshipType.MANY_TO_MANY) { + return `${relationship.through}_${relationship.fieldName}` + } + return relationship.fieldName + } /** * This is a cached lookup, of relationship records, this is mainly for creating/deleting junction * information. */ - async lookupRelations(tableId: string, row: Row) { - const related: { - rows: Row[] - isMany: boolean - tableId: string - field: string - }[] = [] + private async lookupRelations(tableId: string, row: Row) { + const related: Record< + string, + { + rows: Row[] + isMany: boolean + tableId: string + field: string + } + > = {} const { tableName } = breakExternalTableId(tableId) const table = this.tables[tableName] @@ -496,12 +510,12 @@ export class ExternalRequest { ? field.throughFrom || linkPrimaryKey : fieldName - related.push({ + related[this.getLookupRelationsKey(field)] = { rows, isMany: isManyToMany(field), tableId: relatedTableId, field: storeTo, - }) + } } return related } @@ -537,8 +551,13 @@ export class ExternalRequest { const linkSecondary = relationshipPrimary[1] const rows = - related.find(r => r.tableId === relationship.tableId && r.field === key) - ?.rows || [] + related[ + this.getLookupRelationsKey({ + relationshipType: RelationshipType.MANY_TO_MANY, + fieldName: key, + through: relationship.tableId, + }) + ]?.rows || [] const relationshipMatchPredicate = ({ row, @@ -583,7 +602,7 @@ export class ExternalRequest { } } // finally cleanup anything that needs to be removed - for (let { isMany, rows, tableId, field } of related) { + for (let { isMany, rows, tableId, field } of Object.values(related)) { const table: Table | undefined = this.getTable(tableId) // if it's not the foreign key skip it, nothing to do if ( @@ -613,11 +632,7 @@ export class ExternalRequest { continue } - const relatedByTable = isManyToMany(column) - ? related.find( - r => r.tableId === column.through && r.field === column.fieldName - ) - : related.find(r => r.field === column.fieldName) + const relatedByTable = related[this.getLookupRelationsKey(column)] if (!relatedByTable) { continue } From d944e3a8f9c3a73c2b23c75b7a69b191ab955cb2 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 28 Oct 2024 13:53:44 +0100 Subject: [PATCH 12/16] Cleanup --- .../src/api/controllers/row/ExternalRequest.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index c5ebe69aea..49f2f02ebe 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -443,7 +443,6 @@ export class ExternalRequest { rows: Row[] isMany: boolean tableId: string - field: string } > = {} @@ -478,10 +477,7 @@ export class ExternalRequest { "Unable to lookup relationships - undefined column properties." ) } - const { tableName: relatedTableName } = - breakExternalTableId(relatedTableId) - // @ts-ignore - const linkPrimaryKey = this.tables[relatedTableName].primary[0] + if (!lookupField || !row?.[lookupField] == null) { continue } @@ -506,15 +502,11 @@ export class ExternalRequest { !Array.isArray(response) || isKnexEmptyReadResponse(response) ? [] : response - const storeTo = isManyToMany(field) - ? field.throughFrom || linkPrimaryKey - : fieldName related[this.getLookupRelationsKey(field)] = { rows, isMany: isManyToMany(field), tableId: relatedTableId, - field: storeTo, } } return related @@ -602,7 +594,7 @@ export class ExternalRequest { } } // finally cleanup anything that needs to be removed - for (let { isMany, rows, tableId, field } of Object.values(related)) { + for (const [field, { isMany, rows, tableId }] of Object.entries(related)) { const table: Table | undefined = this.getTable(tableId) // if it's not the foreign key skip it, nothing to do if ( From b92427015b1ae0634e56763605a18d286545bc10 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 28 Oct 2024 13:55:08 +0100 Subject: [PATCH 13/16] Cleanup test --- packages/server/src/api/routes/tests/row.spec.ts | 2 +- 1 file changed, 1 insertion(+), 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 72ade0a69a..a11f1d758a 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -3076,7 +3076,7 @@ describe.each([ }, ], ["from original saved row", (row: Row) => row], - ["from updated row", (row: Row) => config.api.row.save(viewId, row)], + ["from updated row", (row: Row) => config.api.row.save(viewId, row)], ] it.each(testScenarios)( From 641ceea92e1baf5f1279e5f67b2273cd58849da4 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 28 Oct 2024 13:57:53 +0100 Subject: [PATCH 14/16] Fix checks --- packages/server/src/api/controllers/row/ExternalRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 49f2f02ebe..07331bd701 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -478,7 +478,7 @@ export class ExternalRequest { ) } - if (!lookupField || !row?.[lookupField] == null) { + if (!lookupField || !row?.[lookupField]) { continue } const endpoint = getEndpoint(relatedTableId, Operation.READ) From d36b810efcbbd6fe1c1df253d6859f8c1ee26fb3 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Mon, 28 Oct 2024 14:28:53 +0100 Subject: [PATCH 15/16] Fix flakiness --- .../server/src/api/controllers/row/ExternalRequest.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 07331bd701..b884683197 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -54,12 +54,13 @@ import { makeExternalQuery } from "../../../integrations/base/query" import { dataFilters, helpers } from "@budibase/shared-core" import { isRelationshipColumn } from "../../../db/utils" -export interface ManyRelationship { +interface ManyRelationship { tableId?: string id?: string isUpdate?: boolean key: string [key: string]: any + relationshipType: RelationshipType } export interface RunConfig { @@ -386,6 +387,7 @@ export class ExternalRequest { [otherKey]: breakRowIdField(relationship)[0], // leave the ID for enrichment later [thisKey]: `{{ literal ${tablePrimary} }}`, + relationshipType: RelationshipType.MANY_TO_MANY, }) } } @@ -402,6 +404,7 @@ export class ExternalRequest { [thisKey]: breakRowIdField(relationship)[0], // leave the ID for enrichment later [otherKey]: `{{ literal ${tablePrimary} }}`, + relationshipType: RelationshipType.MANY_TO_ONE, }) } } @@ -531,7 +534,8 @@ export class ExternalRequest { const promises = [] const related = await this.lookupRelations(mainTableId, row) for (let relationship of relationships) { - const { key, tableId, isUpdate, id, ...rest } = relationship + const { key, tableId, isUpdate, id, relationshipType, ...rest } = + relationship const body: { [key: string]: any } = processObjectSync(rest, row, {}) const linkTable = this.getTable(tableId) const relationshipPrimary = linkTable?.primary || [] @@ -545,7 +549,7 @@ export class ExternalRequest { const rows = related[ this.getLookupRelationsKey({ - relationshipType: RelationshipType.MANY_TO_MANY, + relationshipType, fieldName: key, through: relationship.tableId, }) From 184df942791d9aa0dac781353f97788a1945793e Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 28 Oct 2024 13:35:25 +0000 Subject: [PATCH 16/16] Bump version to 2.33.3 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index df50828b30..8235ee9b60 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "2.33.2", + "version": "2.33.3", "npmClient": "yarn", "packages": [ "packages/*",