mirror of https://github.com/Budibase/budibase.git
6 changed files with 277 additions and 213 deletions
@ -0,0 +1,189 @@ |
|||
const { |
|||
breakExternalTableId, |
|||
generateRowIdField, |
|||
breakRowIdField, |
|||
} = require("../../../integrations/utils") |
|||
const { FieldTypes } = require("../../../constants") |
|||
const { cloneDeep } = require("lodash/fp") |
|||
|
|||
exports.inputProcessing = (row, table, allTables) => { |
|||
if (!row) { |
|||
return { row, manyRelationships: [] } |
|||
} |
|||
let newRow = {}, manyRelationships = [] |
|||
for (let [key, field] of Object.entries(table.schema)) { |
|||
// currently excludes empty strings
|
|||
if (!row[key]) { |
|||
continue |
|||
} |
|||
const isLink = field.type === FieldTypes.LINK |
|||
if (isLink && !field.through) { |
|||
// we don't really support composite keys for relationships, this is why [0] is used
|
|||
newRow[key] = breakRowIdField(row[key][0])[0] |
|||
} else if (isLink && field.through) { |
|||
const linkTable = allTables.find(table => table._id === field.tableId) |
|||
// table has to exist for many to many
|
|||
if (!linkTable) { |
|||
continue |
|||
} |
|||
row[key].map(relationship => { |
|||
// we don't really support composite keys for relationships, this is why [0] is used
|
|||
manyRelationships.push({ |
|||
tableId: field.through, |
|||
[linkTable.primary]: breakRowIdField(relationship)[0], |
|||
// leave the ID for enrichment later
|
|||
[table.primary]: `{{ id }}`, |
|||
}) |
|||
}) |
|||
} else { |
|||
newRow[key] = row[key] |
|||
} |
|||
} |
|||
return { row: newRow, manyRelationships } |
|||
} |
|||
|
|||
exports.generateIdForRow = (row, table) => { |
|||
if (!row) { |
|||
return |
|||
} |
|||
const primary = table.primary |
|||
// build id array
|
|||
let idParts = [] |
|||
for (let field of primary) { |
|||
idParts.push(row[field]) |
|||
} |
|||
return generateRowIdField(idParts) |
|||
} |
|||
|
|||
exports.updateRelationshipColumns = (rows, row, relationships, allTables) => { |
|||
const columns = {} |
|||
for (let relationship of relationships) { |
|||
const linkedTable = allTables[relationship.tableName] |
|||
if (!linkedTable) { |
|||
continue |
|||
} |
|||
const display = linkedTable.primaryDisplay |
|||
const related = {} |
|||
if (display && row[display]) { |
|||
related.primaryDisplay = row[display] |
|||
} |
|||
related._id = row[relationship.to] |
|||
columns[relationship.column] = related |
|||
} |
|||
for (let [column, related] of Object.entries(columns)) { |
|||
if (!Array.isArray(rows[row._id][column])) { |
|||
rows[row._id][column] = [] |
|||
} |
|||
// make sure relationship hasn't been found already
|
|||
if (!rows[row._id][column].find(relation => relation._id === related._id)) { |
|||
rows[row._id][column].push(related) |
|||
} |
|||
} |
|||
return rows |
|||
} |
|||
|
|||
exports.outputProcessing = (rows, table, relationships, allTables) => { |
|||
// if no rows this is what is returned? Might be PG only
|
|||
if (rows[0].read === true) { |
|||
return [] |
|||
} |
|||
let finalRows = {} |
|||
for (let row of rows) { |
|||
row._id = exports.generateIdForRow(row, table) |
|||
// this is a relationship of some sort
|
|||
if (finalRows[row._id]) { |
|||
finalRows = exports.updateRelationshipColumns( |
|||
finalRows, |
|||
row, |
|||
relationships, |
|||
allTables |
|||
) |
|||
continue |
|||
} |
|||
const thisRow = {} |
|||
// filter the row down to what is actually the row (not joined)
|
|||
for (let fieldName of Object.keys(table.schema)) { |
|||
thisRow[fieldName] = row[fieldName] |
|||
} |
|||
thisRow._id = row._id |
|||
thisRow.tableId = table._id |
|||
thisRow._rev = "rev" |
|||
finalRows[thisRow._id] = thisRow |
|||
// do this at end once its been added to the final rows
|
|||
finalRows = exports.updateRelationshipColumns( |
|||
finalRows, |
|||
row, |
|||
relationships, |
|||
allTables |
|||
) |
|||
} |
|||
return Object.values(finalRows) |
|||
} |
|||
|
|||
exports.buildFilters = (id, filters, table) => { |
|||
const primary = table.primary |
|||
// if passed in array need to copy for shifting etc
|
|||
let idCopy = cloneDeep(id) |
|||
if (filters) { |
|||
// need to map over the filters and make sure the _id field isn't present
|
|||
for (let filter of Object.values(filters)) { |
|||
if (filter._id) { |
|||
const parts = breakRowIdField(filter._id) |
|||
for (let field of primary) { |
|||
filter[field] = parts.shift() |
|||
} |
|||
} |
|||
// make sure this field doesn't exist on any filter
|
|||
delete filter._id |
|||
} |
|||
} |
|||
// there is no id, just use the user provided filters
|
|||
if (!idCopy || !table) { |
|||
return filters |
|||
} |
|||
// if used as URL parameter it will have been joined
|
|||
if (typeof idCopy === "string") { |
|||
idCopy = breakRowIdField(idCopy) |
|||
} |
|||
const equal = {} |
|||
for (let field of primary) { |
|||
// work through the ID and get the parts
|
|||
equal[field] = idCopy.shift() |
|||
} |
|||
return { |
|||
equal, |
|||
} |
|||
} |
|||
|
|||
exports.buildRelationships = (table, allTables) => { |
|||
const relationships = [] |
|||
for (let [fieldName, field] of Object.entries(table.schema)) { |
|||
if (field.type !== FieldTypes.LINK) { |
|||
continue |
|||
} |
|||
const { tableName: linkTableName } = breakExternalTableId(field.tableId) |
|||
// no table to link to, this is not a valid relationships
|
|||
if (!allTables[linkTableName]) { |
|||
continue |
|||
} |
|||
const linkTable = allTables[linkTableName] |
|||
const definition = { |
|||
// if no foreign key specified then use the name of the field in other table
|
|||
from: field.foreignKey || table.primary[0], |
|||
to: field.fieldName, |
|||
tableName: linkTableName, |
|||
through: undefined, |
|||
// need to specify where to put this back into
|
|||
column: fieldName, |
|||
} |
|||
if (field.through) { |
|||
const { tableName: throughTableName } = breakExternalTableId(field.through) |
|||
definition.through = throughTableName |
|||
// don't support composite keys for relationships
|
|||
definition.from = table.primary[0] |
|||
definition.to = linkTable.primary[0] |
|||
} |
|||
relationships.push(definition) |
|||
} |
|||
return relationships |
|||
} |
|||
Loading…
Reference in new issue