Fixing issue #2412 - making sure full enriched records are passed along to automations.
This commit is contained in:
parent
3eeb7c27b8
commit
a92530f170
|
@ -23,6 +23,19 @@ const CALCULATION_TYPES = {
|
||||||
STATS: "stats",
|
STATS: "stats",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function storeResponse(ctx, db, row, oldTable, table) {
|
||||||
|
row.type = "row"
|
||||||
|
const response = await db.put(row)
|
||||||
|
// don't worry about rev, tables handle rev/lastID updates
|
||||||
|
if (!isEqual(oldTable, table)) {
|
||||||
|
await db.put(table)
|
||||||
|
}
|
||||||
|
row._rev = response.rev
|
||||||
|
// process the row before return, to include relationships
|
||||||
|
row = await outputProcessing(ctx, table, row, { squash: false })
|
||||||
|
return { row, table }
|
||||||
|
}
|
||||||
|
|
||||||
exports.patch = async ctx => {
|
exports.patch = async ctx => {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
|
@ -77,14 +90,7 @@ exports.patch = async ctx => {
|
||||||
return { row: ctx.body, table }
|
return { row: ctx.body, table }
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await db.put(row)
|
return storeResponse(ctx, db, row, dbTable, table)
|
||||||
// don't worry about rev, tables handle rev/lastID updates
|
|
||||||
if (!isEqual(dbTable, table)) {
|
|
||||||
await db.put(table)
|
|
||||||
}
|
|
||||||
row._rev = response.rev
|
|
||||||
row.type = "row"
|
|
||||||
return { row, table }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.save = async function (ctx) {
|
exports.save = async function (ctx) {
|
||||||
|
@ -118,14 +124,7 @@ exports.save = async function (ctx) {
|
||||||
table,
|
table,
|
||||||
})
|
})
|
||||||
|
|
||||||
row.type = "row"
|
return storeResponse(ctx, db, row, dbTable, table)
|
||||||
const response = await db.put(row)
|
|
||||||
// don't worry about rev, tables handle rev/lastID updates
|
|
||||||
if (!isEqual(dbTable, table)) {
|
|
||||||
await db.put(table)
|
|
||||||
}
|
|
||||||
row._rev = response.rev
|
|
||||||
return { row, table }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fetchView = async ctx => {
|
exports.fetchView = async ctx => {
|
||||||
|
@ -221,34 +220,47 @@ exports.destroy = async function (ctx) {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
const { _id, _rev } = ctx.request.body
|
const { _id, _rev } = ctx.request.body
|
||||||
const row = await db.get(_id)
|
let row = await db.get(_id)
|
||||||
|
|
||||||
if (row.tableId !== ctx.params.tableId) {
|
if (row.tableId !== ctx.params.tableId) {
|
||||||
throw "Supplied tableId doesn't match the row's tableId"
|
throw "Supplied tableId doesn't match the row's tableId"
|
||||||
}
|
}
|
||||||
|
const table = await db.get(row.tableId)
|
||||||
|
// update the row to include full relationships before deleting them
|
||||||
|
row = await outputProcessing(ctx, table, row, { squash: false })
|
||||||
|
// now remove the relationships
|
||||||
await linkRows.updateLinks({
|
await linkRows.updateLinks({
|
||||||
appId,
|
appId,
|
||||||
eventType: linkRows.EventType.ROW_DELETE,
|
eventType: linkRows.EventType.ROW_DELETE,
|
||||||
row,
|
row,
|
||||||
tableId: row.tableId,
|
tableId: row.tableId,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let response
|
||||||
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
||||||
ctx.params = {
|
ctx.params = {
|
||||||
id: _id,
|
id: _id,
|
||||||
}
|
}
|
||||||
await userController.destroyMetadata(ctx)
|
await userController.destroyMetadata(ctx)
|
||||||
return { response: ctx.body, row }
|
response = ctx.body
|
||||||
} else {
|
} else {
|
||||||
const response = await db.remove(_id, _rev)
|
response = await db.remove(_id, _rev)
|
||||||
return { response, row }
|
|
||||||
}
|
}
|
||||||
|
return { response, row }
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.bulkDestroy = async ctx => {
|
exports.bulkDestroy = async ctx => {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
const { rows } = ctx.request.body
|
|
||||||
const db = new CouchDB(appId)
|
const db = new CouchDB(appId)
|
||||||
|
const tableId = ctx.params.tableId
|
||||||
|
const table = await db.get(tableId)
|
||||||
|
let { rows } = ctx.request.body
|
||||||
|
|
||||||
|
// before carrying out any updates, make sure the rows are ready to be returned
|
||||||
|
// they need to be the full rows (including previous relationships) for automations
|
||||||
|
rows = await outputProcessing(ctx, table, rows, { squash: false })
|
||||||
|
|
||||||
|
// remove the relationships first
|
||||||
let updates = rows.map(row =>
|
let updates = rows.map(row =>
|
||||||
linkRows.updateLinks({
|
linkRows.updateLinks({
|
||||||
appId,
|
appId,
|
||||||
|
@ -257,8 +269,7 @@ exports.bulkDestroy = async ctx => {
|
||||||
tableId: row.tableId,
|
tableId: row.tableId,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
// TODO remove special user case in future
|
if (tableId === InternalTables.USER_METADATA) {
|
||||||
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
|
||||||
updates = updates.concat(
|
updates = updates.concat(
|
||||||
rows.map(row => {
|
rows.map(row => {
|
||||||
ctx.params = {
|
ctx.params = {
|
||||||
|
|
|
@ -36,6 +36,18 @@ exports.IncludeDocs = IncludeDocs
|
||||||
exports.getLinkDocuments = getLinkDocuments
|
exports.getLinkDocuments = getLinkDocuments
|
||||||
exports.createLinkView = createLinkView
|
exports.createLinkView = createLinkView
|
||||||
|
|
||||||
|
function clearRelationshipFields(table, rows) {
|
||||||
|
for (let [key, field] of Object.entries(table.schema)) {
|
||||||
|
if (field.type === FieldTypes.LINK) {
|
||||||
|
rows = rows.map(row => {
|
||||||
|
delete row[key]
|
||||||
|
return row
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -126,33 +138,6 @@ exports.updateLinks = async function (args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a row with information about the links that pertain to it.
|
|
||||||
* @param {string} appId The instance in which this row has been created.
|
|
||||||
* @param {object} rows The row(s) themselves which is to be updated with info (if applicable). This can be
|
|
||||||
* a single row object or an array of rows - both will be handled.
|
|
||||||
* @returns {Promise<object>} The updated row (this may be the same if no links were found). If an array was input
|
|
||||||
* then an array will be output, object input -> object output.
|
|
||||||
*/
|
|
||||||
exports.attachLinkIDs = async (appId, rows) => {
|
|
||||||
const links = await getLinksForRows(appId, rows)
|
|
||||||
// now iterate through the rows and all field information
|
|
||||||
for (let row of rows) {
|
|
||||||
// find anything that matches the row's ID we are searching for and join it
|
|
||||||
links
|
|
||||||
.filter(el => el.thisId === row._id)
|
|
||||||
.forEach(link => {
|
|
||||||
if (row[link.fieldName] == null) {
|
|
||||||
row[link.fieldName] = []
|
|
||||||
}
|
|
||||||
row[link.fieldName].push(link.id)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// if it was an array when it came in then handle it as an array in response
|
|
||||||
// otherwise return the first element as there was only one input
|
|
||||||
return rows
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a table and a list of rows this will retrieve all of the attached docs and enrich them into the row.
|
* Given a table and a list of rows this will retrieve all of the attached docs and enrich them into the row.
|
||||||
* 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).
|
||||||
|
@ -173,6 +158,9 @@ exports.attachFullLinkedDocs = async (ctx, table, rows) => {
|
||||||
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)
|
||||||
)
|
)
|
||||||
|
// clear any existing links that could be dupe'd
|
||||||
|
rows = clearRelationshipFields(table, rows)
|
||||||
|
// now get the docs and combine into the rows
|
||||||
let linked = await getFullLinkedDocs(ctx, appId, links)
|
let linked = await getFullLinkedDocs(ctx, appId, links)
|
||||||
const linkedTables = []
|
const linkedTables = []
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
|
|
|
@ -59,16 +59,4 @@ describe("test link functionality", () => {
|
||||||
expect(Array.isArray(output)).toBe(true)
|
expect(Array.isArray(output)).toBe(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("attachLinkIDs", () => {
|
|
||||||
it("should be able to attach linkIDs", async () => {
|
|
||||||
await config.init()
|
|
||||||
await config.createTable()
|
|
||||||
const table = await config.createLinkedTable()
|
|
||||||
const row = await config.createRow()
|
|
||||||
const linkRow = await config.createRow(basicLinkedRow(table._id, row._id))
|
|
||||||
const attached = await links.attachLinkIDs(config.getAppId(), [linkRow])
|
|
||||||
expect(attached[0].link[0]).toBe(row._id)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
|
@ -185,10 +185,16 @@ exports.inputProcessing = (user = {}, table, row) => {
|
||||||
* @param {object} ctx the request which is looking for enriched rows.
|
* @param {object} ctx the request which is looking for enriched rows.
|
||||||
* @param {object} table the table from which these rows came from originally, this is used to determine
|
* @param {object} table the table from which these rows came from originally, this is used to determine
|
||||||
* the schema of the rows and then enrich.
|
* the schema of the rows and then enrich.
|
||||||
* @param {object[]} rows the rows which are to be enriched.
|
* @param {object[]|object} rows the rows which are to be enriched.
|
||||||
* @returns {object[]} the enriched rows will be returned.
|
* @param {object} opts used to set some options for the output, such as disabling relationship squashing.
|
||||||
|
* @returns {object[]|object} the enriched rows will be returned.
|
||||||
*/
|
*/
|
||||||
exports.outputProcessing = async (ctx, table, rows) => {
|
exports.outputProcessing = async (
|
||||||
|
ctx,
|
||||||
|
table,
|
||||||
|
rows,
|
||||||
|
opts = { squash: true }
|
||||||
|
) => {
|
||||||
const appId = ctx.appId
|
const appId = ctx.appId
|
||||||
let wasArray = true
|
let wasArray = true
|
||||||
if (!(rows instanceof Array)) {
|
if (!(rows instanceof Array)) {
|
||||||
|
@ -214,6 +220,12 @@ exports.outputProcessing = async (ctx, table, rows) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enriched = await linkRows.squashLinksToPrimaryDisplay(appId, table, enriched)
|
if (opts.squash) {
|
||||||
|
enriched = await linkRows.squashLinksToPrimaryDisplay(
|
||||||
|
appId,
|
||||||
|
table,
|
||||||
|
enriched
|
||||||
|
)
|
||||||
|
}
|
||||||
return wasArray ? enriched : enriched[0]
|
return wasArray ? enriched : enriched[0]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue