First version of enrichment.

This commit is contained in:
mike12345567 2021-07-01 14:10:44 +01:00
parent 959c9f1e76
commit a13b5111bb
5 changed files with 56 additions and 22 deletions

View File

@ -1,5 +1,5 @@
const { makeExternalQuery } = require("./utils")
const { DataSourceOperation, SortDirection } = require("../../../constants")
const { DataSourceOperation, SortDirection, FieldTypes } = require("../../../constants")
const { getAllExternalTables } = require("../table/utils")
const {
breakExternalTableId,
@ -19,10 +19,12 @@ async function handleRequest(
appId,
operation,
tableId,
{ id, row, filters, sort, paginate, fullDocs } = {}
{ id, row, filters, sort, paginate, tables } = {}
) {
let { datasourceId, tableName } = breakExternalTableId(tableId)
const tables = await getAllExternalTables(appId, datasourceId)
if (!tables) {
tables = await getAllExternalTables(appId, datasourceId)
}
const table = tables[tableName]
if (!table) {
throw `Unable to process query, table "${tableName}" not defined.`
@ -83,8 +85,7 @@ async function handleRequest(
response,
table,
relationships,
tables,
fullDocs
tables
)
// if reading it'll just be an array of rows, return whole thing
return operation === DataSourceOperation.READ && Array.isArray(response)
@ -239,15 +240,43 @@ exports.fetchEnrichedRow = async ctx => {
const appId = ctx.appId
const id = ctx.params.rowId
const tableId = ctx.params.tableId
// TODO: this only enriches the full docs 1 layer deep, need to join those as well
const { datasourceId, tableName } = breakExternalTableId(tableId)
const tables = await getAllExternalTables(appId, datasourceId)
const response = await handleRequest(
appId,
DataSourceOperation.READ,
tableId,
{
id,
fullDocs: true,
tables,
}
)
return response ? response[0] : response
const table = tables[tableName]
const row = response[0]
// this seems like a lot of work, but basically we need to dig deeper for the enrich
// for a single row, there is probably a better way to do this with some smart multi-layer joins
for (let [fieldName, field] of Object.entries(table.schema)) {
if (field.type !== FieldTypes.LINK || !row[fieldName] || row[fieldName].length === 0) {
continue
}
const links = row[fieldName]
const linkedTableId = field.tableId
const linkedTable = tables[breakExternalTableId(linkedTableId).tableName]
// don't support composite keys right now
const linkedIds = links.map(link => breakRowIdField(link._id)[0])
row[fieldName] = await handleRequest(
appId,
DataSourceOperation.READ,
linkedTableId,
{
tables,
filters: {
oneOf: {
[linkedTable.primary]: linkedIds,
},
},
},
)
}
return row
}

View File

@ -80,8 +80,7 @@ exports.updateRelationshipColumns = (
row,
rows,
relationships,
allTables,
fullDocs
allTables
) => {
const columns = {}
for (let relationship of relationships) {
@ -91,13 +90,11 @@ exports.updateRelationshipColumns = (
}
let linked = basicProcessing(row, linkedTable)
// if not returning full docs then get the minimal links out
if (!fullDocs) {
const display = linkedTable.primaryDisplay
linked = {
primaryDisplay: display ? linked[display] : undefined,
_id: linked._id,
}
}
columns[relationship.column] = linked
}
for (let [column, related] of Object.entries(columns)) {
@ -116,8 +113,7 @@ exports.outputProcessing = (
rows,
table,
relationships,
allTables,
fullDocs
allTables
) => {
// if no rows this is what is returned? Might be PG only
if (rows[0].read === true) {
@ -132,8 +128,7 @@ exports.outputProcessing = (
row,
finalRows,
relationships,
allTables,
fullDocs
allTables
)
continue
}
@ -144,8 +139,7 @@ exports.outputProcessing = (
row,
finalRows,
relationships,
allTables,
fullDocs
allTables
)
}
return Object.values(finalRows)

View File

@ -1,3 +1,5 @@
import {breakExternalTableId} from "../../../integrations/utils"
const CouchDB = require("../../../db")
const csvParser = require("../../../utilities/csvParser")
const {

View File

@ -72,6 +72,9 @@ export interface SearchFilters {
notEmpty?: {
[key: string]: any
}
oneOf?: {
[key: string]: any[]
}
}
export interface RelationshipsJson {

View File

@ -30,6 +30,12 @@ function addFilters(
}
// if all or specified in filters, then everything is an or
const allOr = filters.allOr
if (filters.oneOf) {
iterate(filters.oneOf, (key, array) => {
const fnc = allOr ? "orWhereIn" : "whereIn"
query = query[fnc](key, array)
})
}
if (filters.string) {
iterate(filters.string, (key, value) => {
const fnc = allOr ? "orWhere" : "where"