From 7408eb945b407cf8215330689a204b20bb7f080d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 16 Jun 2021 18:38:00 +0100 Subject: [PATCH] Fixing automation integration and various components around forms. --- .../src/api/controllers/row/external.js | 48 ++++++++++++++----- .../server/src/automations/automationUtils.js | 10 +++- packages/server/src/integrations/postgres.js | 1 - packages/server/src/integrations/utils.js | 16 +++++++ 4 files changed, 60 insertions(+), 15 deletions(-) diff --git a/packages/server/src/api/controllers/row/external.js b/packages/server/src/api/controllers/row/external.js index f567a90678..3dd638d326 100644 --- a/packages/server/src/api/controllers/row/external.js +++ b/packages/server/src/api/controllers/row/external.js @@ -1,7 +1,11 @@ const { makeExternalQuery } = require("./utils") const { DataSourceOperation, SortDirection } = require("../../../constants") const { getExternalTable } = require("../table/utils") -const { breakExternalTableId } = require("../../../integrations/utils") +const { + breakExternalTableId, + generateRowIdField, + breakRowIdField +} = require("../../../integrations/utils") function inputProcessing(row, table) { if (!row) { @@ -29,20 +33,35 @@ function outputProcessing(rows, table) { for (let field of primary) { idParts.push(row[field]) } - row._id = idParts + row._id = generateRowIdField(idParts) + row.tableId = table._id } return rows } -function buildIDFilter(id, table) { +function buildFilters(id, filters, table) { + const primary = table.primary + 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 (!id || !table) { - return null + return filters } // if used as URL parameter it will have been joined if (typeof id === "string") { - id = id.split(",") + id = breakRowIdField(id) } - const primary = table.primary const equal = {} for (let field of primary) { // work through the ID and get the parts @@ -65,10 +84,9 @@ async function handleRequest( throw `Unable to process query, table "${tableName}" not defined.` } // clean up row on ingress using schema + filters = buildFilters(id, filters, table) row = inputProcessing(row, table) - // try and build an id filter if required - let idFilters = buildIDFilter(id, table) - if (operation === DataSourceOperation.DELETE && Object.keys(idFilters).length === 0) { + if (operation === DataSourceOperation.DELETE && Object.keys(filters).length === 0) { throw "Deletion must be filtered in someway" } let json = { @@ -81,7 +99,7 @@ async function handleRequest( // not specifying any fields means "*" fields: [], }, - filters: idFilters != null ? idFilters : filters, + filters, sort, paginate, body: row, @@ -103,7 +121,7 @@ exports.patch = async ctx => { const appId = ctx.appId const inputs = ctx.request.body const tableId = ctx.params.tableId - const id = inputs._id + const id = breakRowIdField(inputs._id) // don't save the ID to db delete inputs._id return handleRequest(appId, DataSourceOperation.UPDATE, tableId, { @@ -150,7 +168,7 @@ exports.destroy = async ctx => { const appId = ctx.appId const tableId = ctx.params.tableId return handleRequest(appId, DataSourceOperation.DELETE, tableId, { - id: ctx.request.body._id, + id: breakRowIdField(ctx.request.body._id), }) } @@ -163,7 +181,7 @@ exports.bulkDestroy = async ctx => { for (let row of rows) { promises.push( handleRequest(appId, DataSourceOperation.DELETE, tableId, { - id: row._id, + id: breakRowIdField(row._id), }) ) } @@ -182,6 +200,10 @@ exports.search = async ctx => { // todo: need to handle bookmarks page: params.bookmark, } + } else if (params && params.limit) { + paginateObj = { + limit: params.limit, + } } let sort if (params.sort) { diff --git a/packages/server/src/automations/automationUtils.js b/packages/server/src/automations/automationUtils.js index b86107f7e9..83c50eb71a 100644 --- a/packages/server/src/automations/automationUtils.js +++ b/packages/server/src/automations/automationUtils.js @@ -1,4 +1,6 @@ const CouchDB = require("../db") +const { isExternalTable, breakExternalTableId } = require("../integrations/utils") +const { getExternalTable } = require("../api/controllers/table/utils") /** * When values are input to the system generally they will be of type string as this is required for template strings. @@ -60,7 +62,13 @@ module.exports.cleanInputValues = (inputs, schema) => { */ module.exports.cleanUpRow = async (appId, tableId, row) => { const db = new CouchDB(appId) - const table = await db.get(tableId) + let table + if (isExternalTable(tableId)) { + const { datasourceId, tableName } = breakExternalTableId(tableId) + table = await getExternalTable(appId, datasourceId, tableName) + } else { + table = await db.get(tableId) + } return module.exports.cleanInputValues(row, { properties: table.schema }) } diff --git a/packages/server/src/integrations/postgres.js b/packages/server/src/integrations/postgres.js index 45c41d0d05..d40529defd 100644 --- a/packages/server/src/integrations/postgres.js +++ b/packages/server/src/integrations/postgres.js @@ -2,7 +2,6 @@ const { Pool } = require("pg") const { FIELD_TYPES } = require("./Integration") const Sql = require("./base/sql") const { FieldTypes } = require("../constants") -const { SEPARATOR } = require("@budibase/auth/db") const { buildExternalTableId } = require("./utils") const SCHEMA = { diff --git a/packages/server/src/integrations/utils.js b/packages/server/src/integrations/utils.js index 52fe04cfdc..efc0c359d3 100644 --- a/packages/server/src/integrations/utils.js +++ b/packages/server/src/integrations/utils.js @@ -16,3 +16,19 @@ exports.breakExternalTableId = tableId => { let datasourceId = parts.join(DOUBLE_SEPARATOR) return { datasourceId, tableName } } + +exports.generateRowIdField = (keyProps = []) => { + if (!Array.isArray(keyProps)) { + keyProps = [keyProps] + } + // this conserves order and types + return encodeURIComponent(JSON.stringify(keyProps)) +} + +// should always return an array +exports.breakRowIdField = _id => { + if (!_id) { + return null + } + return JSON.parse(decodeURIComponent(_id)) +}