Fixes issue #2417 in the backend, looks for fields which could contain a key value and if they do it will resolve them down to the ID field value.
This commit is contained in:
parent
0b2bdf4d47
commit
dd75d236c0
|
@ -15,8 +15,9 @@ import {
|
||||||
import {
|
import {
|
||||||
breakRowIdField,
|
breakRowIdField,
|
||||||
generateRowIdField,
|
generateRowIdField,
|
||||||
|
isRowId,
|
||||||
|
convertRowId,
|
||||||
} from "../../../integrations/utils"
|
} from "../../../integrations/utils"
|
||||||
import { RelationshipTypes } from "../../../constants"
|
|
||||||
|
|
||||||
interface ManyRelationship {
|
interface ManyRelationship {
|
||||||
tableId?: string
|
tableId?: string
|
||||||
|
@ -36,7 +37,7 @@ interface RunConfig {
|
||||||
|
|
||||||
module External {
|
module External {
|
||||||
const { makeExternalQuery } = require("./utils")
|
const { makeExternalQuery } = require("./utils")
|
||||||
const { DataSourceOperation, FieldTypes } = require("../../../constants")
|
const { DataSourceOperation, FieldTypes, RelationshipTypes } = require("../../../constants")
|
||||||
const { breakExternalTableId, isSQL } = require("../../../integrations/utils")
|
const { breakExternalTableId, isSQL } = require("../../../integrations/utils")
|
||||||
const { processObjectSync } = require("@budibase/string-templates")
|
const { processObjectSync } = require("@budibase/string-templates")
|
||||||
const { cloneDeep } = require("lodash/fp")
|
const { cloneDeep } = require("lodash/fp")
|
||||||
|
@ -83,6 +84,48 @@ module External {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function checks the incoming parameters to make sure all the inputs are
|
||||||
|
* valid based on on the table schema. The main thing this is looking for is when a
|
||||||
|
* user has made use of the _id field of a row for a foreign key or a search parameter.
|
||||||
|
* In these cases the key will be sent up as [1], rather than 1. In these cases we will
|
||||||
|
* simplify it down to the requirements. This function is quite complex as we try to be
|
||||||
|
* relatively restrictive over what types of columns we will perform this action for.
|
||||||
|
*/
|
||||||
|
function cleanupConfig(config: RunConfig, table: Table): RunConfig {
|
||||||
|
const primaryOptions = [
|
||||||
|
FieldTypes.STRING,
|
||||||
|
FieldTypes.LONGFORM,
|
||||||
|
FieldTypes.OPTIONS,
|
||||||
|
FieldTypes.NUMBER,
|
||||||
|
]
|
||||||
|
// filter out fields which cannot be keys
|
||||||
|
const fieldNames = Object.entries(table.schema)
|
||||||
|
.filter(schema => primaryOptions.find(val => val === schema[1].type))
|
||||||
|
.map(([fieldName]) => fieldName)
|
||||||
|
const iterateObject = (obj: { [key: string]: any }) => {
|
||||||
|
for (let [field, value] of Object.entries(obj)) {
|
||||||
|
if (fieldNames.find(name => name === field) && isRowId(value)) {
|
||||||
|
obj[field] = convertRowId(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check the row and filters to make sure they aren't a key of some sort
|
||||||
|
if (config.filters) {
|
||||||
|
for (let filter of Object.values(config.filters)) {
|
||||||
|
if (typeof filter !== "object" || Object.keys(filter).length === 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
iterateObject(filter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.row) {
|
||||||
|
iterateObject(config.row)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
function generateIdForRow(row: Row | undefined, table: Table): string {
|
function generateIdForRow(row: Row | undefined, table: Table): string {
|
||||||
const primary = table.primary
|
const primary = table.primary
|
||||||
if (!row || !primary) {
|
if (!row || !primary) {
|
||||||
|
@ -509,7 +552,7 @@ module External {
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
async run({ id, row, filters, sort, paginate }: RunConfig) {
|
async run(config: RunConfig) {
|
||||||
const { appId, operation, tableId } = this
|
const { appId, operation, tableId } = this
|
||||||
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
let { datasourceId, tableName } = breakExternalTableId(tableId)
|
||||||
if (!this.datasource) {
|
if (!this.datasource) {
|
||||||
|
@ -525,9 +568,11 @@ module External {
|
||||||
if (!table) {
|
if (!table) {
|
||||||
throw `Unable to process query, table "${tableName}" not defined.`
|
throw `Unable to process query, table "${tableName}" not defined.`
|
||||||
}
|
}
|
||||||
// clean up row on ingress using schema
|
// look for specific components of config which may not be considered acceptable
|
||||||
|
let { id, row, filters, sort, paginate } = cleanupConfig(config, table)
|
||||||
filters = buildFilters(id, filters || {}, table)
|
filters = buildFilters(id, filters || {}, table)
|
||||||
const relationships = this.buildRelationships(table)
|
const relationships = this.buildRelationships(table)
|
||||||
|
// clean up row on ingress using schema
|
||||||
const processed = this.inputProcessing(row, table)
|
const processed = this.inputProcessing(row, table)
|
||||||
row = processed.row
|
row = processed.row
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -5,6 +5,7 @@ const { DocumentTypes, SEPARATOR } = require("../db/utils")
|
||||||
const { FieldTypes } = require("../constants")
|
const { FieldTypes } = require("../constants")
|
||||||
|
|
||||||
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
||||||
|
const ROW_ID_REGEX = /^\[.*]$/g
|
||||||
|
|
||||||
export function isExternalTable(tableId: string) {
|
export function isExternalTable(tableId: string) {
|
||||||
return tableId.includes(DocumentTypes.DATASOURCE)
|
return tableId.includes(DocumentTypes.DATASOURCE)
|
||||||
|
@ -32,6 +33,20 @@ export function generateRowIdField(keyProps: any[] = []) {
|
||||||
return encodeURIComponent(JSON.stringify(keyProps).replace(/"/g, "'"))
|
return encodeURIComponent(JSON.stringify(keyProps).replace(/"/g, "'"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isRowId(field: any) {
|
||||||
|
return Array.isArray(field) || (typeof field === "string" && field.match(ROW_ID_REGEX) != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertRowId(field: any) {
|
||||||
|
if (Array.isArray(field)) {
|
||||||
|
return field[0]
|
||||||
|
}
|
||||||
|
if (typeof field === "string" && field.match(ROW_ID_REGEX) != null) {
|
||||||
|
return field.substring(1, field.length - 1)
|
||||||
|
}
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
|
||||||
// should always return an array
|
// should always return an array
|
||||||
export function breakRowIdField(_id: string | { _id: string }): any[] {
|
export function breakRowIdField(_id: string | { _id: string }): any[] {
|
||||||
if (!_id) {
|
if (!_id) {
|
||||||
|
|
Loading…
Reference in New Issue