diff --git a/packages/server/src/db/linkedRows/index.js b/packages/server/src/db/linkedRows/index.js index 8e4c64af14..aa795284cb 100644 --- a/packages/server/src/db/linkedRows/index.js +++ b/packages/server/src/db/linkedRows/index.js @@ -4,11 +4,13 @@ const { getLinkDocuments, createLinkView, getUniqueByProp, + getRelatedTableForField, + getLinkedTableIDs, + getLinkedTable, } = require("./linkUtils") const { flatten } = require("lodash") const CouchDB = require("../../db") const { getMultiIDParams } = require("../../db/utils") -const { FieldTypes } = require("../../constants") /** * This functionality makes sure that when rows with links are created, updated or deleted they are processed @@ -30,26 +32,6 @@ exports.IncludeDocs = IncludeDocs exports.getLinkDocuments = getLinkDocuments exports.createLinkView = createLinkView -function getLinkedTableIDs(table) { - return Object.values(table.schema) - .filter(column => column.type === FieldTypes.LINK) - .map(column => column.tableId) -} - -function getRelatedTableForField(table, fieldName) { - // look to see if its on the table, straight in the schema - const field = table.schema[fieldName] - if (field != null) { - return field.tableId - } - for (let column of Object.values(table.schema)) { - if (column.type === FieldTypes.LINK && column.fieldName === fieldName) { - return column.tableId - } - } - return null -} - async function getLinksForRows(appId, rows) { const tableIds = [...new Set(rows.map(el => el.tableId))] // start by getting all the link values for performance reasons @@ -172,7 +154,6 @@ exports.attachLinkedPrimaryDisplay = async (appId, table, rows) => { return rows } const db = new CouchDB(appId) - const linkedTables = await Promise.all(linkedTableIds.map(id => db.get(id))) const links = (await getLinksForRows(appId, rows)).filter(link => rows.some(row => row._id === link.thisId) ) @@ -180,27 +161,26 @@ exports.attachLinkedPrimaryDisplay = async (appId, table, rows) => { const linked = (await db.allDocs(getMultiIDParams(linkedRowIds))).rows.map( row => row.doc ) + // will populate this as we find them + const linkedTables = [] for (let row of rows) { - links - .filter(link => link.thisId === row._id) - .forEach(link => { - if (row[link.fieldName] == null) { - row[link.fieldName] = [] - } - const linkedTableId = getRelatedTableForField(table, link.fieldName) - const linkedRow = linked.find(row => row._id === link.id) - const linkedTable = linkedTables.find( - table => table._id === linkedTableId - ) - if (!linkedRow || !linkedTable) { - return - } - // need to handle an edge case where relationship just wasn't found - const value = linkedRow[linkedTable.primaryDisplay] || linkedRow._id - if (value) { - row[link.fieldName].push(value) - } - }) + for (let link of links.filter(link => link.thisId === row._id)) { + if (row[link.fieldName] == null) { + row[link.fieldName] = [] + } + const linkedRow = linked.find(row => row._id === link.id) + const linkedTableId = + linkedRow.tableId || getRelatedTableForField(table, link.fieldName) + const linkedTable = await getLinkedTable(db, linkedTableId, linkedTables) + if (!linkedRow || !linkedTable) { + continue + } + // need to handle an edge case where relationship just wasn't found + const value = linkedRow[linkedTable.primaryDisplay] || linkedRow._id + if (value) { + row[link.fieldName].push(value) + } + } } return rows } diff --git a/packages/server/src/db/linkedRows/linkUtils.js b/packages/server/src/db/linkedRows/linkUtils.js index fba12aec0b..157f9e4e63 100644 --- a/packages/server/src/db/linkedRows/linkUtils.js +++ b/packages/server/src/db/linkedRows/linkUtils.js @@ -1,6 +1,7 @@ const CouchDB = require("../index") const Sentry = require("@sentry/node") const { ViewNames, getQueryIndex } = require("../utils") +const { FieldTypes } = require("../../constants") /** * Only needed so that boolean parameters are being used for includeDocs @@ -120,3 +121,35 @@ exports.getUniqueByProp = (array, prop) => { return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos }) } + +exports.getLinkedTableIDs = table => { + return Object.values(table.schema) + .filter(column => column.type === FieldTypes.LINK) + .map(column => column.tableId) +} + +exports.getLinkedTable = async (db, id, tables) => { + let linkedTable = tables.find(table => table._id === id) + if (linkedTable) { + return linkedTable + } + linkedTable = await db.get(id) + if (linkedTable) { + tables.push(linkedTable) + } + return linkedTable +} + +exports.getRelatedTableForField = (table, fieldName) => { + // look to see if its on the table, straight in the schema + const field = table.schema[fieldName] + if (field != null) { + return field.tableId + } + for (let column of Object.values(table.schema)) { + if (column.type === FieldTypes.LINK && column.fieldName === fieldName) { + return column.tableId + } + } + return null +}