Adding a mapping layer to search queries so that we can map search inputs based on the table schema if desired - primarily for the user column.

This commit is contained in:
mike12345567 2023-10-06 11:57:11 +01:00
parent 4bbd575cb0
commit 3de8c53166
6 changed files with 110 additions and 6 deletions

View File

@ -191,7 +191,7 @@
} }
const getValidOperatorsForType = filter => { const getValidOperatorsForType = filter => {
if (!filter) { if (!filter.field) {
return [] return []
} }

View File

@ -16,6 +16,7 @@ import { cleanExportRows } from "../utils"
import { utils } from "@budibase/shared-core" import { utils } from "@budibase/shared-core"
import { ExportRowsParams, ExportRowsResult } from "../search" import { ExportRowsParams, ExportRowsResult } from "../search"
import { HTTPError, db } from "@budibase/backend-core" import { HTTPError, db } from "@budibase/backend-core"
import { searchInputMapping } from "./utils"
import pick from "lodash/pick" import pick from "lodash/pick"
import { outputProcessing } from "../../../../utilities/rowProcessor" import { outputProcessing } from "../../../../utilities/rowProcessor"
@ -50,7 +51,10 @@ export async function search(options: SearchParams) {
[params.sort]: { direction }, [params.sort]: { direction },
} }
} }
try { try {
const table = await sdk.tables.getTable(tableId)
options = searchInputMapping(table, options)
let rows = (await handleRequest(Operation.READ, tableId, { let rows = (await handleRequest(Operation.READ, tableId, {
filters: query, filters: query,
sort, sort,
@ -76,7 +80,6 @@ export async function search(options: SearchParams) {
rows = rows.map((r: any) => pick(r, fields)) rows = rows.map((r: any) => pick(r, fields))
} }
const table = await sdk.tables.getTable(tableId)
rows = await outputProcessing(table, rows, { preserveLinks: true }) rows = await outputProcessing(table, rows, { preserveLinks: true })
// need wrapper object for bookmarks etc when paginating // need wrapper object for bookmarks etc when paginating

View File

@ -29,6 +29,7 @@ import {
} from "../../../../api/controllers/view/utils" } from "../../../../api/controllers/view/utils"
import sdk from "../../../../sdk" import sdk from "../../../../sdk"
import { ExportRowsParams, ExportRowsResult } from "../search" import { ExportRowsParams, ExportRowsResult } from "../search"
import { searchInputMapping } from "./utils"
import pick from "lodash/pick" import pick from "lodash/pick"
export async function search(options: SearchParams) { export async function search(options: SearchParams) {
@ -47,9 +48,9 @@ export async function search(options: SearchParams) {
disableEscaping: options.disableEscaping, disableEscaping: options.disableEscaping,
} }
let table let table = await sdk.tables.getTable(tableId)
options = searchInputMapping(table, options)
if (params.sort && !params.sortType) { if (params.sort && !params.sortType) {
table = await sdk.tables.getTable(tableId)
const schema = table.schema const schema = table.schema
const sortField = schema[params.sort] const sortField = schema[params.sort]
params.sortType = sortField.type === "number" ? "number" : "string" params.sortType = sortField.type === "number" ? "number" : "string"
@ -68,7 +69,6 @@ export async function search(options: SearchParams) {
if (tableId === InternalTables.USER_METADATA) { if (tableId === InternalTables.USER_METADATA) {
response.rows = await getGlobalUsersFromMetadata(response.rows) response.rows = await getGlobalUsersFromMetadata(response.rows)
} }
table = table || (await sdk.tables.getTable(tableId))
if (options.fields) { if (options.fields) {
const fields = [...options.fields, ...db.CONSTANT_INTERNAL_ROW_COLS] const fields = [...options.fields, ...db.CONSTANT_INTERNAL_ROW_COLS]

View File

@ -0,0 +1,49 @@
import { searchInputMapping } from "../utils"
import { db as dbCore } from "@budibase/backend-core"
import {
FieldType,
FieldTypeSubtypes,
Table,
SearchParams,
} from "@budibase/types"
const tableId = "ta_a"
const tableWithUserCol: Table = {
_id: tableId,
name: "table",
schema: {
user: {
name: "user",
type: FieldType.BB_REFERENCE,
subtype: FieldTypeSubtypes.BB_REFERENCE.USER,
},
},
}
describe("searchInputMapping", () => {
it("should be able to map ro_ to global user IDs", () => {
const globalUserId = dbCore.generateGlobalUserID()
const userMedataId = dbCore.generateUserMetadataID(globalUserId)
const params: SearchParams = {
tableId,
query: {
equal: {
"1:user": userMedataId,
},
},
}
const output = searchInputMapping(tableWithUserCol, params)
expect(output.query.equal!["1:user"]).toBe(globalUserId)
})
it("shouldn't change any other input", () => {
const params: SearchParams = {
tableId,
query: {
equal: {
"1:user": "test@test.com",
},
},
}
})
})

View File

@ -0,0 +1,53 @@
import {
FieldType,
FieldTypeSubtypes,
SearchParams,
Table,
DocumentType,
SEPARATOR,
} from "@budibase/types"
import { db as dbCore } from "@budibase/backend-core"
function findColumnInQueries(
column: string,
options: SearchParams,
callback: <T>(filter: T) => T
) {
for (let filterBlock of Object.values(options.query)) {
if (typeof filterBlock !== "object") {
continue
}
for (let [key, filter] of Object.entries(filterBlock)) {
if (key.endsWith(column)) {
filterBlock[key] = callback(filter)
}
}
}
}
function userColumnMapping(column: string, options: SearchParams) {
findColumnInQueries(column, options, (filterValue: any): string => {
if (typeof filterValue !== "string") {
return filterValue
}
const rowPrefix = DocumentType.ROW + SEPARATOR
// TODO: at some point in future might want to handle mapping emails to IDs
if (filterValue.startsWith(rowPrefix)) {
return dbCore.getGlobalIDFromUserMetadataID(filterValue)
}
return filterValue
})
}
export function searchInputMapping(table: Table, options: SearchParams) {
for (let [key, column] of Object.entries(table.schema)) {
switch (column.type) {
case FieldType.BB_REFERENCE:
if (column.subtype === FieldTypeSubtypes.BB_REFERENCE.USER) {
userColumnMapping(key, options)
}
break
}
}
return options
}

View File

@ -14,7 +14,6 @@ const HBS_REGEX = /{{([^{].*?)}}/g
/** /**
* Returns the valid operator options for a certain data type * Returns the valid operator options for a certain data type
* @param type the data type
*/ */
export const getValidOperatorsForType = ( export const getValidOperatorsForType = (
type: FieldType, type: FieldType,