From a6f6942288f674a902de77220d030e8cb4d81f6a Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 3 Oct 2024 16:10:07 +0100 Subject: [PATCH 1/4] Fixing an issue with corrupt relationship records referencing rows which don't exist, this is a temporary measure as these relationships should be cleaned up correctly but for now ignore any which reference rows which no longer exist. --- .../backend-core/src/db/couch/DatabaseImpl.ts | 12 +++++++---- .../src/db/linkedRows/LinkController.ts | 20 ++++++++++--------- packages/types/src/sdk/db.ts | 2 +- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/backend-core/src/db/couch/DatabaseImpl.ts b/packages/backend-core/src/db/couch/DatabaseImpl.ts index 274c1b9e93..472e0f44ad 100644 --- a/packages/backend-core/src/db/couch/DatabaseImpl.ts +++ b/packages/backend-core/src/db/couch/DatabaseImpl.ts @@ -213,17 +213,21 @@ export class DatabaseImpl implements Database { async getMultiple( ids: string[], - opts?: { allowMissing?: boolean } + opts?: { allowMissing?: boolean; excludeDocs?: boolean } ): Promise { // get unique ids = [...new Set(ids)] + const includeDocs = !opts?.excludeDocs const response = await this.allDocs({ keys: ids, - include_docs: true, + include_docs: includeDocs, }) const rowUnavailable = (row: RowResponse) => { // row is deleted - key lookup can return this - if (row.doc == null || ("deleted" in row.value && row.value.deleted)) { + if ( + (includeDocs && row.doc == null) || + (row.value && "deleted" in row.value && row.value.deleted) + ) { return true } return row.error === "not_found" @@ -237,7 +241,7 @@ export class DatabaseImpl implements Database { const missingIds = missing.map(row => row.key).join(", ") throw new Error(`Unable to get documents: ${missingIds}`) } - return rows.map(row => row.doc!) + return rows.map(row => (includeDocs ? row.doc! : row.value)) } async remove(idOrDoc: string | Document, rev?: string) { diff --git a/packages/server/src/db/linkedRows/LinkController.ts b/packages/server/src/db/linkedRows/LinkController.ts index 85a160713b..3c0601c9ee 100644 --- a/packages/server/src/db/linkedRows/LinkController.ts +++ b/packages/server/src/db/linkedRows/LinkController.ts @@ -211,19 +211,21 @@ class LinkController { linkedSchema?.type === FieldType.LINK && linkedSchema?.relationshipType === RelationshipType.ONE_TO_MANY ) { - let links = ( - await getLinkDocuments({ - tableId: field.tableId, - rowId: linkId, - }) - ).filter( - link => - link.id !== row._id && link.fieldName === linkedSchema.name + let links = await getLinkDocuments({ + tableId: field.tableId, + rowId: linkId, + fieldName: linkedSchema.name, + }) + + // check all the related rows exist + const foundRecords = await this._db.getMultiple( + links.map(l => l.id), + { allowMissing: true, excludeDocs: true } ) // The 1 side of 1:N is already related to something else // You must remove the existing relationship - if (links.length > 0) { + if (foundRecords.length > 0) { throw new Error( `1:N Relationship Error: Record already linked to another.` ) diff --git a/packages/types/src/sdk/db.ts b/packages/types/src/sdk/db.ts index a081f4f1a2..49baaa5bb1 100644 --- a/packages/types/src/sdk/db.ts +++ b/packages/types/src/sdk/db.ts @@ -133,7 +133,7 @@ export interface Database { exists(docId: string): Promise getMultiple( ids: string[], - opts?: { allowMissing?: boolean } + opts?: { allowMissing?: boolean; excludeDocs?: boolean } ): Promise remove(idOrDoc: Document): Promise remove(idOrDoc: string, rev?: string): Promise From 86846eff3f79192385f420b200b1a58b59a0042f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 3 Oct 2024 16:22:32 +0100 Subject: [PATCH 2/4] Small fix. --- packages/server/src/db/linkedRows/LinkController.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/server/src/db/linkedRows/LinkController.ts b/packages/server/src/db/linkedRows/LinkController.ts index 3c0601c9ee..944542e73f 100644 --- a/packages/server/src/db/linkedRows/LinkController.ts +++ b/packages/server/src/db/linkedRows/LinkController.ts @@ -214,8 +214,10 @@ class LinkController { let links = await getLinkDocuments({ tableId: field.tableId, rowId: linkId, - fieldName: linkedSchema.name, - }) + }).filter( + link => + link.id !== row._id && link.fieldName === linkedSchema.name + ) // check all the related rows exist const foundRecords = await this._db.getMultiple( From 6fb844753b4ffcc7b3af857c723a0f193b2bc1f5 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 3 Oct 2024 16:24:54 +0100 Subject: [PATCH 3/4] Another small fix. --- packages/server/src/db/linkedRows/LinkController.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/server/src/db/linkedRows/LinkController.ts b/packages/server/src/db/linkedRows/LinkController.ts index 944542e73f..1cd4240d4b 100644 --- a/packages/server/src/db/linkedRows/LinkController.ts +++ b/packages/server/src/db/linkedRows/LinkController.ts @@ -211,10 +211,12 @@ class LinkController { linkedSchema?.type === FieldType.LINK && linkedSchema?.relationshipType === RelationshipType.ONE_TO_MANY ) { - let links = await getLinkDocuments({ - tableId: field.tableId, - rowId: linkId, - }).filter( + let links = ( + await getLinkDocuments({ + tableId: field.tableId, + rowId: linkId, + }) + ).filter( link => link.id !== row._id && link.fieldName === linkedSchema.name ) From abd7b3b84e5e1fda05e4987e34cc66072d33e347 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 9 Oct 2024 09:12:59 +0000 Subject: [PATCH 4/4] Bump version to 2.32.13 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index 55721b6b2d..faed02052e 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "2.32.12", + "version": "2.32.13", "npmClient": "yarn", "packages": [ "packages/*",