diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index 4c5415a6c6..2963546e7f 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -24,7 +24,7 @@ import AWS from "aws-sdk" import fs from "fs" import sdk from "../../../sdk" import * as pro from "@budibase/pro" -import { App, Ctx, ProcessAttachmentResponse, Upload } from "@budibase/types" +import { App, Ctx, ProcessAttachmentResponse } from "@budibase/types" const send = require("koa-send") @@ -212,7 +212,9 @@ export const serveBuilderPreview = async function (ctx: Ctx) { if (!env.isJest()) { let appId = context.getAppId() - const previewHbs = loadHandlebarsFile(`${__dirname}/preview.hbs`) + const templateLoc = join(__dirname, "templates") + const previewLoc = fs.existsSync(templateLoc) ? templateLoc : __dirname + const previewHbs = loadHandlebarsFile(join(previewLoc, "preview.hbs")) ctx.body = await processString(previewHbs, { clientLibPath: objectStore.clientLibraryUrl(appId!, appInfo.version), }) diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index de49441f3a..5b3c69b87a 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -517,9 +517,24 @@ describe.each([ }) describe("patch", () => { + let otherTable: Table + beforeAll(async () => { const tableConfig = generateTableConfig() table = await createTable(tableConfig) + const otherTableConfig = generateTableConfig() + // need a short name of table here - for relationship tests + otherTableConfig.name = "a" + otherTableConfig.schema.relationship = { + name: "relationship", + relationshipType: RelationshipType.ONE_TO_MANY, + type: FieldType.LINK, + tableId: table._id!, + fieldName: "relationship", + } + otherTable = await createTable(otherTableConfig) + // need to set the config back to the original table + config.table = table }) it("should update only the fields that are supplied", async () => { @@ -615,6 +630,28 @@ describe.each([ expect(getResp.body.user1[0]._id).toEqual(user2._id) expect(getResp.body.user2[0]._id).toEqual(user2._id) }) + + it("should be able to update relationships when both columns are same name", async () => { + let row = await config.api.row.save(table._id!, { + name: "test", + description: "test", + }) + let row2 = await config.api.row.save(otherTable._id!, { + name: "test", + description: "test", + relationship: [row._id], + }) + row = (await config.api.row.get(table._id!, row._id!)).body + expect(row.relationship.length).toBe(1) + const resp = await config.api.row.patch(table._id!, { + _id: row._id!, + _rev: row._rev!, + tableId: row.tableId!, + name: "test2", + relationship: [row2._id], + }) + expect(resp.relationship.length).toBe(1) + }) }) describe("destroy", () => { diff --git a/packages/server/src/db/linkedRows/LinkController.ts b/packages/server/src/db/linkedRows/LinkController.ts index c4eed1169a..f52694465f 100644 --- a/packages/server/src/db/linkedRows/LinkController.ts +++ b/packages/server/src/db/linkedRows/LinkController.ts @@ -251,9 +251,19 @@ class LinkController { // find the docs that need to be deleted let toDeleteDocs = thisFieldLinkDocs .filter(doc => { - let correctDoc = - doc.doc1.fieldName === fieldName ? doc.doc2 : doc.doc1 - return rowField.indexOf(correctDoc.rowId) === -1 + let correctDoc + if ( + doc.doc1.tableId === table._id! && + doc.doc1.fieldName === fieldName + ) { + correctDoc = doc.doc2 + } else if ( + doc.doc2.tableId === table._id! && + doc.doc2.fieldName === fieldName + ) { + correctDoc = doc.doc1 + } + return correctDoc && rowField.indexOf(correctDoc.rowId) === -1 }) .map(doc => { return { ...doc, _deleted: true } diff --git a/packages/server/src/integration-test/postgres.spec.ts b/packages/server/src/integration-test/postgres.spec.ts index 8dc49a9489..67e4fee81c 100644 --- a/packages/server/src/integration-test/postgres.spec.ts +++ b/packages/server/src/integration-test/postgres.spec.ts @@ -934,25 +934,43 @@ describe("postgres integrations", () => { }, ], }) + const m2oRel = { + [m2oFieldName]: [ + { + _id: row._id, + }, + ], + } expect(res.body[m2oFieldName]).toEqual([ { + ...m2oRel, ...foreignRowsByType[RelationshipType.MANY_TO_ONE][0].row, [`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]: row.id, }, { + ...m2oRel, ...foreignRowsByType[RelationshipType.MANY_TO_ONE][1].row, [`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]: row.id, }, { + ...m2oRel, ...foreignRowsByType[RelationshipType.MANY_TO_ONE][2].row, [`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]: row.id, }, ]) + const o2mRel = { + [o2mFieldName]: [ + { + _id: row._id, + }, + ], + } expect(res.body[o2mFieldName]).toEqual([ { + ...o2mRel, ...foreignRowsByType[RelationshipType.ONE_TO_MANY][0].row, _id: expect.any(String), _rev: expect.any(String), diff --git a/packages/server/src/sdk/app/tables/external/index.ts b/packages/server/src/sdk/app/tables/external/index.ts index f445fcaf08..157a683ad0 100644 --- a/packages/server/src/sdk/app/tables/external/index.ts +++ b/packages/server/src/sdk/app/tables/external/index.ts @@ -136,6 +136,8 @@ export async function save( schema.main = true } + // add in the new table for relationship purposes + tables[tableToSave.name] = tableToSave cleanupRelationships(tableToSave, tables, oldTable) const operation = tableId ? Operation.UPDATE_TABLE : Operation.CREATE_TABLE diff --git a/packages/server/src/sdk/app/tables/external/utils.ts b/packages/server/src/sdk/app/tables/external/utils.ts index bde812dd3d..50ea98eb39 100644 --- a/packages/server/src/sdk/app/tables/external/utils.ts +++ b/packages/server/src/sdk/app/tables/external/utils.ts @@ -1,5 +1,6 @@ import { Datasource, + FieldType, ManyToManyRelationshipFieldMetadata, ManyToOneRelationshipFieldMetadata, OneToManyRelationshipFieldMetadata, @@ -42,10 +43,13 @@ export function cleanupRelationships( for (let [relatedKey, relatedSchema] of Object.entries( relatedTable.schema )) { - if ( - relatedSchema.type === FieldTypes.LINK && - relatedSchema.fieldName === foreignKey - ) { + if (relatedSchema.type !== FieldType.LINK) { + continue + } + // if they both have the same field name it will appear as if it needs to be removed, + // don't cleanup in this scenario + const sameFieldNameForBoth = relatedSchema.name === schema.name + if (relatedSchema.fieldName === foreignKey && !sameFieldNameForBoth) { delete relatedTable.schema[relatedKey] } }