Fix multiple relations to same table for external

This commit is contained in:
Adria Navarro 2024-10-16 10:21:17 +02:00
parent f5fe3c0bdf
commit b01564c934
4 changed files with 3 additions and 87 deletions

View File

@ -412,7 +412,8 @@ class InternalBuilder {
const { relationships, endpoint, tableAliases: aliases } = this.query const { relationships, endpoint, tableAliases: aliases } = this.query
const tableName = endpoint.entityId const tableName = endpoint.entityId
const fromAlias = aliases?.[tableName] || tableName const fromAlias = aliases?.[tableName] || tableName
const matches = (value: string) => filterKey.startsWith(`${value}`) const matches = (value: string) =>
filterKey.match(new RegExp(`^${value}\\.`))
if (!relationships) { if (!relationships) {
return query return query
} }
@ -435,7 +436,7 @@ class InternalBuilder {
const manyToMany = validateManyToMany(relationship) const manyToMany = validateManyToMany(relationship)
let updatedKey let updatedKey
if (matchesRelationName) { if (!matchesTableName) {
updatedKey = filterKey.replace( updatedKey = filterKey.replace(
new RegExp(`^${relationship.column}.`), new RegExp(`^${relationship.column}.`),
`${aliases![relationship.tableName]}.` `${aliases![relationship.tableName]}.`
@ -485,7 +486,6 @@ class InternalBuilder {
) )
} }
query = query.whereExists(whereCb(updatedKey, subQuery)) query = query.whereExists(whereCb(updatedKey, subQuery))
break
} }
} }
return query return query

View File

@ -204,18 +204,6 @@ export class ExternalRequest<T extends Operation> {
filters: SearchFilters, filters: SearchFilters,
table: Table table: Table
): SearchFilters { ): SearchFilters {
// replace any relationship columns initially, table names and relationship column names are acceptable
const relationshipColumns = sdk.rows.filters.getRelationshipColumns(table)
filters = sdk.rows.filters.updateFilterKeys(
filters,
relationshipColumns.map(({ name, definition }) => {
const { tableName } = breakExternalTableId(definition.tableId)
return {
original: name,
updated: tableName,
}
})
)
const primary = table.primary const primary = table.primary
// if passed in array need to copy for shifting etc // if passed in array need to copy for shifting etc
let idCopy: undefined | string | any[] = cloneDeep(id) let idCopy: undefined | string | any[] = cloneDeep(id)

View File

@ -3,14 +3,12 @@ import * as rows from "./rows"
import * as search from "./search" import * as search from "./search"
import * as utils from "./utils" import * as utils from "./utils"
import * as external from "./external" import * as external from "./external"
import * as filters from "./search/filters"
import AliasTables from "./sqlAlias" import AliasTables from "./sqlAlias"
export default { export default {
...attachments, ...attachments,
...rows, ...rows,
...search, ...search,
filters,
utils, utils,
external, external,
AliasTables, AliasTables,

View File

@ -1,70 +0,0 @@
import {
FieldType,
RelationshipFieldMetadata,
SearchFilters,
Table,
} from "@budibase/types"
import { isPlainObject } from "lodash"
import { dataFilters } from "@budibase/shared-core"
export function getRelationshipColumns(table: Table): {
name: string
definition: RelationshipFieldMetadata
}[] {
// performing this with a for loop rather than an array filter improves
// type guarding, as no casts are required
const linkEntries: [string, RelationshipFieldMetadata][] = []
for (let entry of Object.entries(table.schema)) {
if (entry[1].type === FieldType.LINK) {
const linkColumn: RelationshipFieldMetadata = entry[1]
linkEntries.push([entry[0], linkColumn])
}
}
return linkEntries.map(entry => ({
name: entry[0],
definition: entry[1],
}))
}
export function getTableIDList(
tables: Table[]
): { name: string; id: string }[] {
return tables
.filter(table => table.originalName && table._id)
.map(table => ({ id: table._id!, name: table.originalName! }))
}
export function updateFilterKeys(
filters: SearchFilters,
updates: { original: string; updated: string }[]
): SearchFilters {
const makeFilterKeyRegex = (str: string) =>
new RegExp(`^${str}\\.|:${str}\\.`)
for (let filter of Object.values(filters)) {
if (!isPlainObject(filter)) {
continue
}
for (const [key, keyFilter] of Object.entries(filter)) {
if (keyFilter === "") {
delete filter[key]
}
const possibleKey = updates.find(({ original }) =>
key.match(makeFilterKeyRegex(original))
)
if (possibleKey && possibleKey.original !== possibleKey.updated) {
// only replace the first, not replaceAll
filter[
key.replace(
new RegExp(`^(\\d+:)?${possibleKey.original}\\.`),
`$1${possibleKey.updated}.`
)
] = filter[key]
delete filter[key]
}
}
}
return dataFilters.recurseLogicalOperators(filters, (f: SearchFilters) => {
return updateFilterKeys(f, updates)
})
}