Merge branch 'feature/relationship-enrichment' of github.com:Budibase/budibase into feature/relationship-enrichment

This commit is contained in:
Andrew Kingston 2021-02-19 14:31:29 +00:00
commit 3bedcf1e62
2 changed files with 55 additions and 42 deletions

View File

@ -4,11 +4,13 @@ const {
getLinkDocuments, getLinkDocuments,
createLinkView, createLinkView,
getUniqueByProp, getUniqueByProp,
getRelatedTableForField,
getLinkedTableIDs,
getLinkedTable,
} = require("./linkUtils") } = require("./linkUtils")
const { flatten } = require("lodash") const { flatten } = require("lodash")
const CouchDB = require("../../db") const CouchDB = require("../../db")
const { getMultiIDParams } = require("../../db/utils") 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 * 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.getLinkDocuments = getLinkDocuments
exports.createLinkView = createLinkView 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) { async function getLinksForRows(appId, rows) {
const tableIds = [...new Set(rows.map(el => el.tableId))] const tableIds = [...new Set(rows.map(el => el.tableId))]
// start by getting all the link values for performance reasons // start by getting all the link values for performance reasons
@ -172,7 +154,6 @@ exports.attachLinkedPrimaryDisplay = async (appId, table, rows) => {
return rows return rows
} }
const db = new CouchDB(appId) const db = new CouchDB(appId)
const linkedTables = await Promise.all(linkedTableIds.map(id => db.get(id)))
const links = (await getLinksForRows(appId, rows)).filter(link => const links = (await getLinksForRows(appId, rows)).filter(link =>
rows.some(row => row._id === link.thisId) 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( const linked = (await db.allDocs(getMultiIDParams(linkedRowIds))).rows.map(
row => row.doc row => row.doc
) )
// will populate this as we find them
const linkedTables = []
for (let row of rows) { for (let row of rows) {
links for (let link of links.filter(link => link.thisId === row._id)) {
.filter(link => link.thisId === row._id) if (row[link.fieldName] == null) {
.forEach(link => { row[link.fieldName] = []
if (row[link.fieldName] == null) { }
row[link.fieldName] = [] const linkedRow = linked.find(row => row._id === link.id)
} const linkedTableId =
const linkedTableId = getRelatedTableForField(table, link.fieldName) linkedRow.tableId || getRelatedTableForField(table, link.fieldName)
const linkedRow = linked.find(row => row._id === link.id) const linkedTable = await getLinkedTable(db, linkedTableId, linkedTables)
const linkedTable = linkedTables.find( if (!linkedRow || !linkedTable) {
table => table._id === linkedTableId continue
) }
if (!linkedRow || !linkedTable) { // need to handle an edge case where relationship just wasn't found
return const value = linkedRow[linkedTable.primaryDisplay] || linkedRow._id
} if (value) {
// need to handle an edge case where relationship just wasn't found row[link.fieldName].push(value)
const value = linkedRow[linkedTable.primaryDisplay] || linkedRow._id }
if (value) { }
row[link.fieldName].push(value)
}
})
} }
return rows return rows
} }

View File

@ -1,6 +1,7 @@
const CouchDB = require("../index") const CouchDB = require("../index")
const Sentry = require("@sentry/node") const Sentry = require("@sentry/node")
const { ViewNames, getQueryIndex } = require("../utils") const { ViewNames, getQueryIndex } = require("../utils")
const { FieldTypes } = require("../../constants")
/** /**
* Only needed so that boolean parameters are being used for includeDocs * 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 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
}