Initial implementation - needs testing.
This commit is contained in:
parent
37d53cff20
commit
c0b85c6379
|
@ -22,6 +22,18 @@ export function isManyToMany(
|
|||
return !!(field as ManyToManyRelationshipFieldMetadata).through
|
||||
}
|
||||
|
||||
function isCorrectRelationship(
|
||||
relationship: RelationshipsJson,
|
||||
row: Row
|
||||
): boolean {
|
||||
const junctionTableId = relationship.through!
|
||||
const possibleColumns = [
|
||||
`${junctionTableId}.doc1.fieldName`,
|
||||
`${junctionTableId}.doc2.fieldName`,
|
||||
]
|
||||
return !!possibleColumns.find(col => row[col] === relationship.column)
|
||||
}
|
||||
|
||||
/**
|
||||
* This iterates through the returned rows and works out what elements of the rows
|
||||
* actually match up to another row (based on primary keys) - this is pretty specific
|
||||
|
@ -64,7 +76,9 @@ export async function updateRelationshipColumns(
|
|||
if (!linked._id) {
|
||||
continue
|
||||
}
|
||||
columns[relationship.column] = linked
|
||||
if (opts?.sqs && isCorrectRelationship(relationship, row)) {
|
||||
columns[relationship.column] = linked
|
||||
}
|
||||
}
|
||||
for (let [column, related] of Object.entries(columns)) {
|
||||
if (!row._id) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
Operation,
|
||||
QueryJson,
|
||||
RelationshipFieldMetadata,
|
||||
RelationshipsJson,
|
||||
Row,
|
||||
RowSearchParams,
|
||||
SearchFilters,
|
||||
|
@ -30,7 +31,10 @@ import {
|
|||
SQLITE_DESIGN_DOC_ID,
|
||||
SQS_DATASOURCE_INTERNAL,
|
||||
} from "@budibase/backend-core"
|
||||
import { CONSTANT_INTERNAL_ROW_COLS } from "../../../../db/utils"
|
||||
import {
|
||||
CONSTANT_INTERNAL_ROW_COLS,
|
||||
generateJunctionTableID,
|
||||
} from "../../../../db/utils"
|
||||
import AliasTables from "../sqlAlias"
|
||||
import { outputProcessing } from "../../../../utilities/rowProcessor"
|
||||
import pick from "lodash/pick"
|
||||
|
@ -52,7 +56,7 @@ const USER_COLUMN_PREFIX_REGEX = new RegExp(
|
|||
function buildInternalFieldList(
|
||||
table: Table,
|
||||
tables: Table[],
|
||||
opts: { relationships: boolean } = { relationships: true }
|
||||
opts?: { relationships?: RelationshipsJson[] }
|
||||
) {
|
||||
let fieldList: string[] = []
|
||||
fieldList = fieldList.concat(
|
||||
|
@ -60,20 +64,31 @@ function buildInternalFieldList(
|
|||
)
|
||||
for (let col of Object.values(table.schema)) {
|
||||
const isRelationship = col.type === FieldType.LINK
|
||||
if (!opts.relationships && isRelationship) {
|
||||
if (!opts?.relationships && isRelationship) {
|
||||
continue
|
||||
}
|
||||
if (isRelationship) {
|
||||
const linkCol = col as RelationshipFieldMetadata
|
||||
const relatedTable = tables.find(table => table._id === linkCol.tableId)!
|
||||
fieldList = fieldList.concat(
|
||||
buildInternalFieldList(relatedTable, tables, { relationships: false })
|
||||
// no relationships provided, don't go more than a layer deep
|
||||
fieldList = fieldList.concat(buildInternalFieldList(relatedTable, tables))
|
||||
fieldList.push(
|
||||
`${generateJunctionTableID(
|
||||
table._id!,
|
||||
relatedTable._id!
|
||||
)}.doc1.fieldName`
|
||||
)
|
||||
fieldList.push(
|
||||
`${generateJunctionTableID(
|
||||
table._id!,
|
||||
relatedTable._id!
|
||||
)}.doc2.fieldName`
|
||||
)
|
||||
} else {
|
||||
fieldList.push(`${table._id}.${mapToUserColumn(col.name)}`)
|
||||
}
|
||||
}
|
||||
return fieldList
|
||||
return [...new Set(fieldList)]
|
||||
}
|
||||
|
||||
function cleanupFilters(
|
||||
|
@ -165,18 +180,27 @@ function reverseUserColumnMapping(rows: Row[]) {
|
|||
})
|
||||
}
|
||||
|
||||
function runSqlQuery(json: QueryJson, tables: Table[]): Promise<Row[]>
|
||||
function runSqlQuery(
|
||||
json: QueryJson,
|
||||
tables: Table[],
|
||||
relationships: RelationshipsJson[]
|
||||
): Promise<Row[]>
|
||||
function runSqlQuery(
|
||||
json: QueryJson,
|
||||
tables: Table[],
|
||||
relationships: RelationshipsJson[],
|
||||
opts: { countTotalRows: true }
|
||||
): Promise<number>
|
||||
async function runSqlQuery(
|
||||
json: QueryJson,
|
||||
tables: Table[],
|
||||
relationships: RelationshipsJson[],
|
||||
opts?: { countTotalRows?: boolean }
|
||||
) {
|
||||
const alias = new AliasTables(tables.map(table => table.name))
|
||||
const relationshipJunctionTableIds = relationships.map(rel => rel.through!)
|
||||
const alias = new AliasTables(
|
||||
tables.map(table => table.name).concat(relationshipJunctionTableIds)
|
||||
)
|
||||
if (opts?.countTotalRows) {
|
||||
json.endpoint.operation = Operation.COUNT
|
||||
}
|
||||
|
@ -193,8 +217,13 @@ async function runSqlQuery(
|
|||
let bindings = query.bindings
|
||||
|
||||
// quick hack for docIds
|
||||
sql = sql.replace(/`doc1`.`rowId`/g, "`doc1.rowId`")
|
||||
sql = sql.replace(/`doc2`.`rowId`/g, "`doc2.rowId`")
|
||||
|
||||
const fixJunctionDocs = (field: string) =>
|
||||
["doc1", "doc2"].forEach(doc => {
|
||||
sql = sql.replaceAll(`\`${doc}\`.\`${field}\``, `\`${doc}.${field}\``)
|
||||
})
|
||||
fixJunctionDocs("rowId")
|
||||
fixJunctionDocs("fieldName")
|
||||
|
||||
if (Array.isArray(query)) {
|
||||
throw new Error("SQS cannot currently handle multiple queries")
|
||||
|
@ -260,7 +289,7 @@ export async function search(
|
|||
columnPrefix: USER_COLUMN_PREFIX,
|
||||
},
|
||||
resource: {
|
||||
fields: buildInternalFieldList(table, allTables),
|
||||
fields: buildInternalFieldList(table, allTables, { relationships }),
|
||||
},
|
||||
relationships,
|
||||
}
|
||||
|
@ -292,11 +321,11 @@ export async function search(
|
|||
|
||||
try {
|
||||
const queries: Promise<Row[] | number>[] = []
|
||||
queries.push(runSqlQuery(request, allTables))
|
||||
queries.push(runSqlQuery(request, allTables, relationships))
|
||||
if (options.countRows) {
|
||||
// get the total count of rows
|
||||
queries.push(
|
||||
runSqlQuery(request, allTables, {
|
||||
runSqlQuery(request, allTables, relationships, {
|
||||
countTotalRows: true,
|
||||
})
|
||||
)
|
||||
|
|
|
@ -111,7 +111,8 @@ export default class AliasTables {
|
|||
aliasField(field: string) {
|
||||
const tableNames = this.tableNames
|
||||
if (field.includes(".")) {
|
||||
const [tableName, column] = field.split(".")
|
||||
const [tableName, ...rest] = field.split(".")
|
||||
const column = rest.join(".")
|
||||
const foundTableName = tableNames.find(name => {
|
||||
const idx = tableName.indexOf(name)
|
||||
if (idx === -1 || idx > 1) {
|
||||
|
|
Loading…
Reference in New Issue