From 0502e62e1caf68873759dc3d23e71d5c428c2d5d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 17 Jan 2022 14:03:47 +0000 Subject: [PATCH] Add optional enrichment of relationship fields when determining datasource schema and update block filters to properly reference relationship fields --- packages/client/manifest.json | 2 +- .../components/app/blocks/CardsBlock.svelte | 7 ++- .../components/app/blocks/TableBlock.svelte | 51 ++++--------------- packages/client/src/utils/fetch/DataFetch.js | 5 +- packages/client/src/utils/schema.js | 35 +++++++++++-- 5 files changed, 51 insertions(+), 49 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 310cec7f4b..9431129fa0 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2958,7 +2958,7 @@ "key": "dataSource" }, { - "type": "multifield", + "type": "searchfield", "label": "Search Columns", "key": "searchColumns", "placeholder": "Choose search columns" diff --git a/packages/client/src/components/app/blocks/CardsBlock.svelte b/packages/client/src/components/app/blocks/CardsBlock.svelte index 301b440ab3..f0892ca447 100644 --- a/packages/client/src/components/app/blocks/CardsBlock.svelte +++ b/packages/client/src/components/app/blocks/CardsBlock.svelte @@ -71,12 +71,13 @@ const enrichFilter = (filter, columns, formId) => { let enrichedFilter = [...(filter || [])] columns?.forEach(column => { + const safePath = column.name.split(".").map(safe).join(".") enrichedFilter.push({ field: column.name, operator: column.type === "string" ? "string" : "equal", type: column.type === "string" ? "string" : "number", valueType: "Binding", - value: `{{ [${formId}].[${column.name}] }}`, + value: `{{ ${safe(formId)}.${safePath} }}`, }) }) return enrichedFilter @@ -112,7 +113,9 @@ // Load the datasource schema so we can determine column types const fetchSchema = async dataSource => { if (dataSource) { - schema = await fetchDatasourceSchema(dataSource) + schema = await fetchDatasourceSchema(dataSource, { + enrichRelationships: true, + }) } schemaLoaded = true } diff --git a/packages/client/src/components/app/blocks/TableBlock.svelte b/packages/client/src/components/app/blocks/TableBlock.svelte index fef6be5c50..3de4497731 100644 --- a/packages/client/src/components/app/blocks/TableBlock.svelte +++ b/packages/client/src/components/app/blocks/TableBlock.svelte @@ -41,11 +41,9 @@ let dataProviderId let schema let schemaLoaded = false - let enrichedSearchColumns - let enrichedSearchColumnsLoaded = false $: fetchSchema(dataSource) - $: enrichSearchColumns(searchColumns, schema) + $: enrichedSearchColumns = enrichSearchColumns(searchColumns, schema) $: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId) $: titleButtonAction = [ { @@ -61,21 +59,22 @@ const enrichFilter = (filter, columns, formId) => { let enrichedFilter = [...(filter || [])] columns?.forEach(column => { + const safePath = column.name.split(".").map(safe).join(".") enrichedFilter.push({ field: column.name, operator: column.type === "string" ? "string" : "equal", type: column.type === "string" ? "string" : "number", valueType: "Binding", - value: `{{ ${safe(formId)}.${safe(column.name)} }}`, + value: `{{ ${safe(formId)}.${safePath} }}`, }) }) return enrichedFilter } // Determine data types for search fields and only use those that are valid - const enrichSearchColumns = async (searchColumns, schema) => { + const enrichSearchColumns = (searchColumns, schema) => { let enrichedColumns = [] - const addType = column => { + searchColumns?.forEach(column => { const schemaType = schema?.[column]?.type const componentType = schemaComponentMap[schemaType] if (componentType) { @@ -84,51 +83,23 @@ componentType, type: schemaType, }) - return true } - return false - } - 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 + }) + return enrichedColumns.slice(0, 3) } // Load the datasource schema so we can determine column types const fetchSchema = async dataSource => { if (dataSource) { - schema = await fetchDatasourceSchema(dataSource) + schema = await fetchDatasourceSchema(dataSource, { + enrichRelationships: true, + }) } schemaLoaded = true } -{#if schemaLoaded && enrichedSearchColumnsLoaded} +{#if schemaLoaded}
diff --git a/packages/client/src/utils/fetch/DataFetch.js b/packages/client/src/utils/fetch/DataFetch.js index 2333991ac9..884e12feb1 100644 --- a/packages/client/src/utils/fetch/DataFetch.js +++ b/packages/client/src/utils/fetch/DataFetch.js @@ -67,7 +67,6 @@ export default class DataFetch { this.getPage = this.getPage.bind(this) this.getInitialData = this.getInitialData.bind(this) this.determineFeatureFlags = this.determineFeatureFlags.bind(this) - this.enrichSchema = this.enrichSchema.bind(this) this.refresh = this.refresh.bind(this) this.update = this.update.bind(this) this.hasNextPage = this.hasNextPage.bind(this) @@ -129,7 +128,7 @@ export default class DataFetch { // Fetch and enrich schema let schema = this.constructor.getSchema(datasource, definition) - schema = this.enrichSchema(schema) + schema = DataFetch.enrichSchema(schema) if (!schema) { return } @@ -248,7 +247,7 @@ export default class DataFetch { * @param schema the datasource schema * @return {object} the enriched datasource schema */ - enrichSchema(schema) { + static enrichSchema(schema) { if (schema == null) { return null } diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index e333bb616e..dc00430fcd 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -6,13 +6,19 @@ import RelationshipFetch from "./fetch/RelationshipFetch.js" import NestedProviderFetch from "./fetch/NestedProviderFetch.js" import FieldFetch from "./fetch/FieldFetch.js" import JSONArrayFetch from "./fetch/JSONArrayFetch.js" +import DataFetch from "./fetch/DataFetch.js" /** * Fetches the schema of any kind of datasource. * All datasource fetch classes implement their own functionality to get the * 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 = { table: TableFetch, view: ViewFetch, @@ -28,7 +34,7 @@ export const fetchDatasourceSchema = async datasource => { // Get the datasource definition and then schema const definition = await handler.getDefinition(datasource) - const schema = handler.getSchema(datasource, definition) + let schema = handler.getSchema(datasource, definition) if (!schema) { 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) }