Merge pull request #12468 from Budibase/fix/BUDI-7760
Fix relationship saving when both sides of relationship use same field name (internal)
This commit is contained in:
commit
591ad40c75
|
@ -24,7 +24,7 @@ import AWS from "aws-sdk"
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
import * as pro from "@budibase/pro"
|
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")
|
const send = require("koa-send")
|
||||||
|
|
||||||
|
@ -212,7 +212,9 @@ export const serveBuilderPreview = async function (ctx: Ctx) {
|
||||||
|
|
||||||
if (!env.isJest()) {
|
if (!env.isJest()) {
|
||||||
let appId = context.getAppId()
|
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, {
|
ctx.body = await processString(previewHbs, {
|
||||||
clientLibPath: objectStore.clientLibraryUrl(appId!, appInfo.version),
|
clientLibPath: objectStore.clientLibraryUrl(appId!, appInfo.version),
|
||||||
})
|
})
|
||||||
|
|
|
@ -517,9 +517,24 @@ describe.each([
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("patch", () => {
|
describe("patch", () => {
|
||||||
|
let otherTable: Table
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const tableConfig = generateTableConfig()
|
const tableConfig = generateTableConfig()
|
||||||
table = await createTable(tableConfig)
|
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 () => {
|
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.user1[0]._id).toEqual(user2._id)
|
||||||
expect(getResp.body.user2[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", () => {
|
describe("destroy", () => {
|
||||||
|
|
|
@ -251,9 +251,19 @@ class LinkController {
|
||||||
// find the docs that need to be deleted
|
// find the docs that need to be deleted
|
||||||
let toDeleteDocs = thisFieldLinkDocs
|
let toDeleteDocs = thisFieldLinkDocs
|
||||||
.filter(doc => {
|
.filter(doc => {
|
||||||
let correctDoc =
|
let correctDoc
|
||||||
doc.doc1.fieldName === fieldName ? doc.doc2 : doc.doc1
|
if (
|
||||||
return rowField.indexOf(correctDoc.rowId) === -1
|
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 => {
|
.map(doc => {
|
||||||
return { ...doc, _deleted: true }
|
return { ...doc, _deleted: true }
|
||||||
|
|
|
@ -934,25 +934,43 @@ describe("postgres integrations", () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
const m2oRel = {
|
||||||
|
[m2oFieldName]: [
|
||||||
|
{
|
||||||
|
_id: row._id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
expect(res.body[m2oFieldName]).toEqual([
|
expect(res.body[m2oFieldName]).toEqual([
|
||||||
{
|
{
|
||||||
|
...m2oRel,
|
||||||
...foreignRowsByType[RelationshipType.MANY_TO_ONE][0].row,
|
...foreignRowsByType[RelationshipType.MANY_TO_ONE][0].row,
|
||||||
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
|
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
|
||||||
row.id,
|
row.id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
...m2oRel,
|
||||||
...foreignRowsByType[RelationshipType.MANY_TO_ONE][1].row,
|
...foreignRowsByType[RelationshipType.MANY_TO_ONE][1].row,
|
||||||
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
|
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
|
||||||
row.id,
|
row.id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
...m2oRel,
|
||||||
...foreignRowsByType[RelationshipType.MANY_TO_ONE][2].row,
|
...foreignRowsByType[RelationshipType.MANY_TO_ONE][2].row,
|
||||||
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
|
[`fk_${manyToOneRelationshipInfo.table.name}_${manyToOneRelationshipInfo.fieldName}`]:
|
||||||
row.id,
|
row.id,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
const o2mRel = {
|
||||||
|
[o2mFieldName]: [
|
||||||
|
{
|
||||||
|
_id: row._id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
expect(res.body[o2mFieldName]).toEqual([
|
expect(res.body[o2mFieldName]).toEqual([
|
||||||
{
|
{
|
||||||
|
...o2mRel,
|
||||||
...foreignRowsByType[RelationshipType.ONE_TO_MANY][0].row,
|
...foreignRowsByType[RelationshipType.ONE_TO_MANY][0].row,
|
||||||
_id: expect.any(String),
|
_id: expect.any(String),
|
||||||
_rev: expect.any(String),
|
_rev: expect.any(String),
|
||||||
|
|
|
@ -136,6 +136,8 @@ export async function save(
|
||||||
schema.main = true
|
schema.main = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add in the new table for relationship purposes
|
||||||
|
tables[tableToSave.name] = tableToSave
|
||||||
cleanupRelationships(tableToSave, tables, oldTable)
|
cleanupRelationships(tableToSave, tables, oldTable)
|
||||||
|
|
||||||
const operation = tableId ? Operation.UPDATE_TABLE : Operation.CREATE_TABLE
|
const operation = tableId ? Operation.UPDATE_TABLE : Operation.CREATE_TABLE
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
Datasource,
|
Datasource,
|
||||||
|
FieldType,
|
||||||
ManyToManyRelationshipFieldMetadata,
|
ManyToManyRelationshipFieldMetadata,
|
||||||
ManyToOneRelationshipFieldMetadata,
|
ManyToOneRelationshipFieldMetadata,
|
||||||
OneToManyRelationshipFieldMetadata,
|
OneToManyRelationshipFieldMetadata,
|
||||||
|
@ -42,10 +43,13 @@ export function cleanupRelationships(
|
||||||
for (let [relatedKey, relatedSchema] of Object.entries(
|
for (let [relatedKey, relatedSchema] of Object.entries(
|
||||||
relatedTable.schema
|
relatedTable.schema
|
||||||
)) {
|
)) {
|
||||||
if (
|
if (relatedSchema.type !== FieldType.LINK) {
|
||||||
relatedSchema.type === FieldTypes.LINK &&
|
continue
|
||||||
relatedSchema.fieldName === foreignKey
|
}
|
||||||
) {
|
// 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]
|
delete relatedTable.schema[relatedKey]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue