Add optional enrichment of relationship fields when determining datasource schema and update block filters to properly reference relationship fields

This commit is contained in:
Andrew Kingston 2022-01-17 14:03:47 +00:00
parent aae2dc86d3
commit 0502e62e1c
5 changed files with 51 additions and 49 deletions

View File

@ -2958,7 +2958,7 @@
"key": "dataSource" "key": "dataSource"
}, },
{ {
"type": "multifield", "type": "searchfield",
"label": "Search Columns", "label": "Search Columns",
"key": "searchColumns", "key": "searchColumns",
"placeholder": "Choose search columns" "placeholder": "Choose search columns"

View File

@ -71,12 +71,13 @@
const enrichFilter = (filter, columns, formId) => { const enrichFilter = (filter, columns, formId) => {
let enrichedFilter = [...(filter || [])] let enrichedFilter = [...(filter || [])]
columns?.forEach(column => { columns?.forEach(column => {
const safePath = column.name.split(".").map(safe).join(".")
enrichedFilter.push({ enrichedFilter.push({
field: column.name, field: column.name,
operator: column.type === "string" ? "string" : "equal", operator: column.type === "string" ? "string" : "equal",
type: column.type === "string" ? "string" : "number", type: column.type === "string" ? "string" : "number",
valueType: "Binding", valueType: "Binding",
value: `{{ [${formId}].[${column.name}] }}`, value: `{{ ${safe(formId)}.${safePath} }}`,
}) })
}) })
return enrichedFilter return enrichedFilter
@ -112,7 +113,9 @@
// Load the datasource schema so we can determine column types // Load the datasource schema so we can determine column types
const fetchSchema = async dataSource => { const fetchSchema = async dataSource => {
if (dataSource) { if (dataSource) {
schema = await fetchDatasourceSchema(dataSource) schema = await fetchDatasourceSchema(dataSource, {
enrichRelationships: true,
})
} }
schemaLoaded = true schemaLoaded = true
} }

View File

@ -41,11 +41,9 @@
let dataProviderId let dataProviderId
let schema let schema
let schemaLoaded = false let schemaLoaded = false
let enrichedSearchColumns
let enrichedSearchColumnsLoaded = false
$: fetchSchema(dataSource) $: fetchSchema(dataSource)
$: enrichSearchColumns(searchColumns, schema) $: enrichedSearchColumns = enrichSearchColumns(searchColumns, schema)
$: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId) $: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId)
$: titleButtonAction = [ $: titleButtonAction = [
{ {
@ -61,21 +59,22 @@
const enrichFilter = (filter, columns, formId) => { const enrichFilter = (filter, columns, formId) => {
let enrichedFilter = [...(filter || [])] let enrichedFilter = [...(filter || [])]
columns?.forEach(column => { columns?.forEach(column => {
const safePath = column.name.split(".").map(safe).join(".")
enrichedFilter.push({ enrichedFilter.push({
field: column.name, field: column.name,
operator: column.type === "string" ? "string" : "equal", operator: column.type === "string" ? "string" : "equal",
type: column.type === "string" ? "string" : "number", type: column.type === "string" ? "string" : "number",
valueType: "Binding", valueType: "Binding",
value: `{{ ${safe(formId)}.${safe(column.name)} }}`, value: `{{ ${safe(formId)}.${safePath} }}`,
}) })
}) })
return enrichedFilter return enrichedFilter
} }
// Determine data types for search fields and only use those that are valid // Determine data types for search fields and only use those that are valid
const enrichSearchColumns = async (searchColumns, schema) => { const enrichSearchColumns = (searchColumns, schema) => {
let enrichedColumns = [] let enrichedColumns = []
const addType = column => { searchColumns?.forEach(column => {
const schemaType = schema?.[column]?.type const schemaType = schema?.[column]?.type
const componentType = schemaComponentMap[schemaType] const componentType = schemaComponentMap[schemaType]
if (componentType) { if (componentType) {
@ -84,51 +83,23 @@
componentType, componentType,
type: schemaType, type: schemaType,
}) })
return true
} }
return false })
} return enrichedColumns.slice(0, 3)
for (let column of searchColumns || []) {
// if addType returns false, it didn't find one, look for SQL relationships
if (!addType(column) && column.includes(".")) {
const [tableName, linkColumn] = column.split(".")
for (let colSchema of Object.values(schema || {})) {
// found the related table
if (
colSchema.type === "link" &&
colSchema.tableId &&
colSchema.tableId.endsWith(tableName)
) {
try {
const linkSchema = await fetchDatasourceSchema({
...dataSource,
tableId: colSchema.tableId,
})
if (linkSchema) {
schema[column] = linkSchema[linkColumn]
addType(column)
}
} catch (err) {
// ignore the error, couldn't get table
}
}
}
}
}
enrichedSearchColumns = enrichedColumns.slice(0, 3)
enrichedSearchColumnsLoaded = true
} }
// Load the datasource schema so we can determine column types // Load the datasource schema so we can determine column types
const fetchSchema = async dataSource => { const fetchSchema = async dataSource => {
if (dataSource) { if (dataSource) {
schema = await fetchDatasourceSchema(dataSource) schema = await fetchDatasourceSchema(dataSource, {
enrichRelationships: true,
})
} }
schemaLoaded = true schemaLoaded = true
} }
</script> </script>
{#if schemaLoaded && enrichedSearchColumnsLoaded} {#if schemaLoaded}
<Block> <Block>
<div class={size} use:styleable={$component.styles}> <div class={size} use:styleable={$component.styles}>
<BlockComponent type="form" bind:id={formId} props={{ dataSource }}> <BlockComponent type="form" bind:id={formId} props={{ dataSource }}>

View File

@ -67,7 +67,6 @@ export default class DataFetch {
this.getPage = this.getPage.bind(this) this.getPage = this.getPage.bind(this)
this.getInitialData = this.getInitialData.bind(this) this.getInitialData = this.getInitialData.bind(this)
this.determineFeatureFlags = this.determineFeatureFlags.bind(this) this.determineFeatureFlags = this.determineFeatureFlags.bind(this)
this.enrichSchema = this.enrichSchema.bind(this)
this.refresh = this.refresh.bind(this) this.refresh = this.refresh.bind(this)
this.update = this.update.bind(this) this.update = this.update.bind(this)
this.hasNextPage = this.hasNextPage.bind(this) this.hasNextPage = this.hasNextPage.bind(this)
@ -129,7 +128,7 @@ export default class DataFetch {
// Fetch and enrich schema // Fetch and enrich schema
let schema = this.constructor.getSchema(datasource, definition) let schema = this.constructor.getSchema(datasource, definition)
schema = this.enrichSchema(schema) schema = DataFetch.enrichSchema(schema)
if (!schema) { if (!schema) {
return return
} }
@ -248,7 +247,7 @@ export default class DataFetch {
* @param schema the datasource schema * @param schema the datasource schema
* @return {object} the enriched datasource schema * @return {object} the enriched datasource schema
*/ */
enrichSchema(schema) { static enrichSchema(schema) {
if (schema == null) { if (schema == null) {
return null return null
} }

View File

@ -6,13 +6,19 @@ import RelationshipFetch from "./fetch/RelationshipFetch.js"
import NestedProviderFetch from "./fetch/NestedProviderFetch.js" import NestedProviderFetch from "./fetch/NestedProviderFetch.js"
import FieldFetch from "./fetch/FieldFetch.js" import FieldFetch from "./fetch/FieldFetch.js"
import JSONArrayFetch from "./fetch/JSONArrayFetch.js" import JSONArrayFetch from "./fetch/JSONArrayFetch.js"
import DataFetch from "./fetch/DataFetch.js"
/** /**
* Fetches the schema of any kind of datasource. * Fetches the schema of any kind of datasource.
* All datasource fetch classes implement their own functionality to get the * All datasource fetch classes implement their own functionality to get the
* schema of a datasource of their respective types. * schema of a datasource of their respective types.
* @param datasource the datasource to fetch the schema for
* @param options options for enriching the schema
*/ */
export const fetchDatasourceSchema = async datasource => { export const fetchDatasourceSchema = async (
datasource,
options = { enrichRelationships: false }
) => {
const handler = { const handler = {
table: TableFetch, table: TableFetch,
view: ViewFetch, view: ViewFetch,
@ -28,7 +34,7 @@ export const fetchDatasourceSchema = async datasource => {
// Get the datasource definition and then schema // Get the datasource definition and then schema
const definition = await handler.getDefinition(datasource) const definition = await handler.getDefinition(datasource)
const schema = handler.getSchema(datasource, definition) let schema = handler.getSchema(datasource, definition)
if (!schema) { if (!schema) {
return null return null
} }
@ -49,5 +55,28 @@ export const fetchDatasourceSchema = async datasource => {
}) })
} }
}) })
return { ...schema, ...jsonAdditions } schema = { ...schema, ...jsonAdditions }
// Check for any relationship fields if required
if (options?.enrichRelationships) {
let relationshipAdditions = {}
for (let fieldKey of Object.keys(schema)) {
const fieldSchema = schema[fieldKey]
if (fieldSchema?.type === "link") {
const linkSchema = await fetchDatasourceSchema({
type: "table",
tableId: fieldSchema?.tableId,
})
Object.keys(linkSchema || {}).forEach(linkKey => {
relationshipAdditions[`${fieldKey}.${linkKey}`] = {
type: linkSchema[linkKey].type,
}
})
}
}
schema = { ...schema, ...relationshipAdditions }
}
// Ensure schema structure is correct
return DataFetch.enrichSchema(schema)
} }