Further enhancement, client library sends up the column it wants enriched and then we can ignore everything else, makes a big difference for enriching users (with a lot of relationships).
This commit is contained in:
parent
069fd33964
commit
3e2f9dfc4e
|
@ -9,7 +9,9 @@ export const buildRelationshipEndpoints = API => ({
|
||||||
if (!tableId || !rowId) {
|
if (!tableId || !rowId) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const response = await API.get({ url: `/api/${tableId}/${rowId}/enrich` })
|
const response = await API.get({
|
||||||
|
url: `/api/${tableId}/${rowId}/enrich?field=${fieldName}`,
|
||||||
|
})
|
||||||
if (!fieldName) {
|
if (!fieldName) {
|
||||||
return response || []
|
return response || []
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -224,14 +224,15 @@ export async function bulkDestroy(ctx: UserCtx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchEnrichedRow(ctx: UserCtx) {
|
export async function fetchEnrichedRow(ctx: UserCtx) {
|
||||||
|
const fieldName = ctx.request.query.field as string | undefined
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
const tableId = utils.getTableId(ctx)
|
const tableId = utils.getTableId(ctx)
|
||||||
const rowId = ctx.params.rowId
|
const rowId = ctx.params.rowId as string
|
||||||
// need table to work out where links go in row, as well as the link docs
|
// need table to work out where links go in row, as well as the link docs
|
||||||
let response = await Promise.all([
|
let response = await Promise.all([
|
||||||
sdk.tables.getTable(tableId),
|
sdk.tables.getTable(tableId),
|
||||||
utils.findRow(ctx, tableId, rowId),
|
utils.findRow(ctx, tableId, rowId),
|
||||||
linkRows.getLinkDocuments({ tableId, rowId }),
|
linkRows.getLinkDocuments({ tableId, rowId, fieldName }),
|
||||||
])
|
])
|
||||||
const table = response[0] as Table
|
const table = response[0] as Table
|
||||||
const row = response[1] as Row
|
const row = response[1] as Row
|
||||||
|
@ -248,8 +249,13 @@ export async function fetchEnrichedRow(ctx: UserCtx) {
|
||||||
let final = []
|
let final = []
|
||||||
for (let linkTable of linkTables) {
|
for (let linkTable of linkTables) {
|
||||||
const relatedRows = linkedRows.filter(row => row.tableId === linkTable._id)
|
const relatedRows = linkedRows.filter(row => row.tableId === linkTable._id)
|
||||||
|
// include the row being enriched for performance reasons, don't need to fetch it to include
|
||||||
final = final.concat(
|
final = final.concat(
|
||||||
outputProcessing(linkTable, relatedRows, { preserveLinks: true })
|
outputProcessing(linkTable, relatedRows, {
|
||||||
|
// have to clone to avoid JSON cycle
|
||||||
|
fromRow: cloneDeep(row),
|
||||||
|
squash: true,
|
||||||
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// finalise the promises
|
// finalise the promises
|
||||||
|
|
|
@ -146,9 +146,14 @@ export async function updateLinks(args: {
|
||||||
* This is required for formula fields, this may only be utilised internally (for now).
|
* This is required for formula fields, this may only be utilised internally (for now).
|
||||||
* @param {object} table The table from which the rows originated.
|
* @param {object} table The table from which the rows originated.
|
||||||
* @param {array<object>} rows The rows which are to be enriched.
|
* @param {array<object>} rows The rows which are to be enriched.
|
||||||
|
* @param {object} opts optional - options like passing in a base row to use for enrichment.
|
||||||
* @return {Promise<*>} returns the rows with all of the enriched relationships on it.
|
* @return {Promise<*>} returns the rows with all of the enriched relationships on it.
|
||||||
*/
|
*/
|
||||||
export async function attachFullLinkedDocs(table: Table, rows: Row[]) {
|
export async function attachFullLinkedDocs(
|
||||||
|
table: Table,
|
||||||
|
rows: Row[],
|
||||||
|
opts?: { fromRow?: Row }
|
||||||
|
) {
|
||||||
const linkedTableIds = getLinkedTableIDs(table)
|
const linkedTableIds = getLinkedTableIDs(table)
|
||||||
if (linkedTableIds.length === 0) {
|
if (linkedTableIds.length === 0) {
|
||||||
return rows
|
return rows
|
||||||
|
@ -158,20 +163,34 @@ export async function attachFullLinkedDocs(table: Table, rows: Row[]) {
|
||||||
getLinksForRows(rows),
|
getLinksForRows(rows),
|
||||||
sdk.tables.getTables(linkedTableIds),
|
sdk.tables.getTables(linkedTableIds),
|
||||||
])
|
])
|
||||||
|
// find the links that pertain to one of the rows that is being enriched
|
||||||
const links = (response[0] as LinkDocumentValue[]).filter(link =>
|
const links = (response[0] as LinkDocumentValue[]).filter(link =>
|
||||||
rows.some(row => row._id === link.thisId)
|
rows.some(row => row._id === link.thisId)
|
||||||
)
|
)
|
||||||
|
// if fromRow has been passed in, then we don't need to fetch it (optimisation)
|
||||||
|
let linksWithoutFromRow = links
|
||||||
|
if (opts?.fromRow) {
|
||||||
|
linksWithoutFromRow = links.filter(link => link.id !== opts?.fromRow?._id)
|
||||||
|
}
|
||||||
const linkedTables = response[1] as Table[]
|
const linkedTables = response[1] as Table[]
|
||||||
// clear any existing links that could be dupe'd
|
// clear any existing links that could be dupe'd
|
||||||
rows = clearRelationshipFields(table, rows)
|
rows = clearRelationshipFields(table, rows)
|
||||||
// now get the docs and combine into the rows
|
// now get the docs and combine into the rows
|
||||||
let linked = await getFullLinkedDocs(links)
|
let linked = []
|
||||||
|
if (linksWithoutFromRow.length > 0) {
|
||||||
|
linked = await getFullLinkedDocs(linksWithoutFromRow)
|
||||||
|
}
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
for (let link of links.filter(link => link.thisId === row._id)) {
|
for (let link of links.filter(link => link.thisId === row._id)) {
|
||||||
if (row[link.fieldName] == null) {
|
if (row[link.fieldName] == null) {
|
||||||
row[link.fieldName] = []
|
row[link.fieldName] = []
|
||||||
}
|
}
|
||||||
const linkedRow = linked.find(row => row._id === link.id)
|
let linkedRow: Row
|
||||||
|
if (opts?.fromRow && opts?.fromRow?._id === link.id) {
|
||||||
|
linkedRow = opts.fromRow!
|
||||||
|
} else {
|
||||||
|
linkedRow = linked.find(row => row._id === link.id)
|
||||||
|
}
|
||||||
if (linkedRow) {
|
if (linkedRow) {
|
||||||
const linkedTableId =
|
const linkedTableId =
|
||||||
linkedRow.tableId || getRelatedTableForField(table, link.fieldName)
|
linkedRow.tableId || getRelatedTableForField(table, link.fieldName)
|
||||||
|
|
|
@ -35,19 +35,22 @@ export const IncludeDocs = {
|
||||||
export async function getLinkDocuments(args: {
|
export async function getLinkDocuments(args: {
|
||||||
tableId?: string
|
tableId?: string
|
||||||
rowId?: string
|
rowId?: string
|
||||||
includeDocs?: any
|
fieldName?: string
|
||||||
|
includeDocs?: boolean
|
||||||
}): Promise<LinkDocumentValue[] | LinkDocument[]> {
|
}): Promise<LinkDocumentValue[] | LinkDocument[]> {
|
||||||
const { tableId, rowId, includeDocs } = args
|
const { tableId, rowId, fieldName, includeDocs } = args
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
let params: any
|
let params: any
|
||||||
if (rowId != null) {
|
if (rowId) {
|
||||||
params = { key: [tableId, rowId] }
|
params = { key: [tableId, rowId] }
|
||||||
}
|
}
|
||||||
// only table is known
|
// only table is known
|
||||||
else {
|
else {
|
||||||
params = { startKey: [tableId], endKey: [tableId, {}] }
|
params = { startKey: [tableId], endKey: [tableId, {}] }
|
||||||
}
|
}
|
||||||
params.include_docs = !!includeDocs
|
if (includeDocs) {
|
||||||
|
params.include_docs = true
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
let linkRows = (await db.query(getQueryIndex(ViewName.LINK), params)).rows
|
let linkRows = (await db.query(getQueryIndex(ViewName.LINK), params)).rows
|
||||||
// filter to get unique entries
|
// filter to get unique entries
|
||||||
|
@ -67,6 +70,11 @@ export async function getLinkDocuments(args: {
|
||||||
return unique
|
return unique
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// filter down to just the required field name
|
||||||
|
if (fieldName) {
|
||||||
|
linkRows = linkRows.filter(link => link.value.fieldName === fieldName)
|
||||||
|
}
|
||||||
|
// return docs if docs requested, otherwise just the value information
|
||||||
if (includeDocs) {
|
if (includeDocs) {
|
||||||
return linkRows.map(row => row.doc) as LinkDocument[]
|
return linkRows.map(row => row.doc) as LinkDocument[]
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -104,7 +104,7 @@ async function getTable(tableId: string): Promise<Table> {
|
||||||
const table = await getExternalTable(datasourceId, tableName)
|
const table = await getExternalTable(datasourceId, tableName)
|
||||||
return { ...table, sql: isSQL(datasource) }
|
return { ...table, sql: isSQL(datasource) }
|
||||||
} else {
|
} else {
|
||||||
return db.get(tableId)
|
return db.get<Table>(tableId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,7 +201,7 @@ export async function inputProcessing(
|
||||||
export async function outputProcessing<T extends Row[] | Row>(
|
export async function outputProcessing<T extends Row[] | Row>(
|
||||||
table: Table,
|
table: Table,
|
||||||
rows: T,
|
rows: T,
|
||||||
opts: { squash?: boolean; preserveLinks?: boolean } = {
|
opts: { squash?: boolean; preserveLinks?: boolean; fromRow?: Row } = {
|
||||||
squash: true,
|
squash: true,
|
||||||
preserveLinks: false,
|
preserveLinks: false,
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,9 @@ export async function outputProcessing<T extends Row[] | Row>(
|
||||||
}
|
}
|
||||||
// attach any linked row information
|
// attach any linked row information
|
||||||
let enriched = !opts.preserveLinks
|
let enriched = !opts.preserveLinks
|
||||||
? await linkRows.attachFullLinkedDocs(table, safeRows)
|
? await linkRows.attachFullLinkedDocs(table, safeRows, {
|
||||||
|
fromRow: opts?.fromRow,
|
||||||
|
})
|
||||||
: safeRows
|
: safeRows
|
||||||
|
|
||||||
// process formulas
|
// process formulas
|
||||||
|
|
Loading…
Reference in New Issue