budibase/packages/client/src/utils/blocks.js

104 lines
3.3 KiB
JavaScript

import { makePropSafe as safe } from "@budibase/string-templates"
import { API } from "../api/index.js"
// Map of data types to component types for search fields inside blocks
const schemaComponentMap = {
string: "stringfield",
options: "optionsfield",
number: "numberfield",
bigint: "bigintfield",
datetime: "datetimefield",
boolean: "booleanfield",
formula: "stringfield",
}
/**
* Determine data types for search fields and only use those that are valid
* @param searchColumns the search columns to use
* @param schema the datasource schema
*/
export const enrichSearchColumns = async (searchColumns, schema) => {
if (!searchColumns?.length || !schema) {
return []
}
let enrichedColumns = []
for (let column of searchColumns) {
let schemaType = schema[column]?.type
// Check if this is a field in another related table. The only way we can
// check this is checking for a "." inside the column, then checking if we
// have a link field named the same as that field prefix.
if (column.includes(".")) {
const split = column.split(".")
const sourceField = split[0]
const linkField = split.slice(1).join(".")
const linkSchema = schema[sourceField]
if (linkSchema?.type === "link") {
const linkedDef = await API.fetchTableDefinition(linkSchema.tableId)
schemaType = linkedDef?.schema?.[linkField]?.type
}
}
const componentType = schemaComponentMap[schemaType]
if (componentType) {
enrichedColumns.push({
name: column,
componentType,
type: schemaType,
})
}
}
return enrichedColumns.slice(0, 5)
}
/**
* Enriches a normal datasource filter with bindings representing the additional
* search fields configured as part of a searchable block. These bindings are
* fields inside a form used as part of the block.
* @param filter the normal data provider filter
* @param columns the enriched search column structure
* @param formId the ID of the form containing the search fields
*/
export const enrichFilter = (filter, columns, formId) => {
let enrichedFilter = [...(filter || [])]
columns?.forEach(column => {
const safePath = column.name.split(".").map(safe).join(".")
const stringType = column.type === "string" || column.type === "formula"
const dateType = column.type === "datetime"
const binding = `${safe(formId)}.${safePath}`
// For dates, use a range of the entire day selected
if (dateType) {
enrichedFilter.push({
field: column.name,
type: column.type,
operator: "rangeLow",
valueType: "Binding",
value: `{{ ${binding} }}`,
})
const format = "YYYY-MM-DDTHH:mm:ss.SSSZ"
let hbs = `{{ date (add (date ${binding} "x") 86399999) "${format}" }}`
hbs = `{{#if ${binding} }}${hbs}{{/if}}`
enrichedFilter.push({
field: column.name,
type: column.type,
operator: "rangeHigh",
valueType: "Binding",
value: hbs,
})
}
// For other fields, do an exact match
else {
enrichedFilter.push({
field: column.name,
type: column.type,
operator: stringType ? "string" : "equal",
valueType: "Binding",
value: `{{ ${binding} }}`,
})
}
})
return enrichedFilter
}