Standardise fetching schema from client apps to fix issues with determing schema for certain data sources

This commit is contained in:
Andrew Kingston 2021-11-03 11:57:47 +00:00
parent 08de9c0b45
commit fcf87956de
4 changed files with 72 additions and 34 deletions

View File

@ -1,8 +1,8 @@
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import { fetchTableData } from "./tables" import { fetchTableData, fetchTableDefinition } from "./tables"
import { fetchViewData } from "./views" import { fetchViewData } from "./views"
import { fetchRelationshipData } from "./relationships" import { fetchRelationshipData } from "./relationships"
import { executeQuery } from "./queries" import { executeQuery, fetchQueryDefinition } from "./queries"
/** /**
* Fetches all rows for a particular Budibase data source. * Fetches all rows for a particular Budibase data source.
@ -39,3 +39,35 @@ export const fetchDatasource = async dataSource => {
// Enrich the result is always an array // Enrich the result is always an array
return Array.isArray(rows) ? rows : [] return Array.isArray(rows) ? rows : []
} }
/**
* Fetches the schema of any kind of datasource.
*/
export const fetchDatasourceSchema = async dataSource => {
if (!dataSource) {
return null
}
const { type } = dataSource
// Nested providers should already have exposed their own schema
if (type === "provider") {
return dataSource.value?.schema
}
// Tables, views and links can be fetched by table ID
if (
(type === "table" || type === "view" || type === "link") &&
dataSource.tableId
) {
const table = await fetchTableDefinition(dataSource.tableId)
return table?.schema
}
// Queries can be fetched by query ID
if (type === "query" && dataSource._id) {
const definition = await fetchQueryDefinition(dataSource._id)
return definition?.schema
}
return null
}

View File

@ -5,7 +5,7 @@ import API from "./api"
* Executes a query against an external data connector. * Executes a query against an external data connector.
*/ */
export const executeQuery = async ({ queryId, parameters }) => { export const executeQuery = async ({ queryId, parameters }) => {
const query = await API.get({ url: `/api/queries/${queryId}` }) const query = await fetchQueryDefinition(queryId)
if (query?.datasourceId == null) { if (query?.datasourceId == null) {
notificationStore.actions.error("That query couldn't be found") notificationStore.actions.error("That query couldn't be found")
return return
@ -24,3 +24,10 @@ export const executeQuery = async ({ queryId, parameters }) => {
} }
return res return res
} }
/**
* Fetches the definition of an external query.
*/
export const fetchQueryDefinition = async queryId => {
return await API.get({ url: `/api/queries/${queryId}`, cache: true })
}

View File

@ -156,34 +156,24 @@
} }
const getSchema = async dataSource => { const getSchema = async dataSource => {
if (dataSource?.schema) { let newSchema = (await API.fetchDatasourceSchema(dataSource)) || {}
schema = dataSource.schema
} else if (dataSource?.tableId) {
const definition = await API.fetchTableDefinition(dataSource.tableId)
schema = definition?.schema ?? {}
} else if (dataSource?.type === "provider") {
schema = dataSource.value?.schema ?? {}
} else {
schema = {}
}
// Ensure there are "name" properties for all fields and that field schema // Ensure there are "name" properties for all fields and that field schema
// are objects // are objects
let fixedSchema = {} Object.entries(newSchema).forEach(([fieldName, fieldSchema]) => {
Object.entries(schema || {}).forEach(([fieldName, fieldSchema]) => {
if (typeof fieldSchema === "string") { if (typeof fieldSchema === "string") {
fixedSchema[fieldName] = { newSchema[fieldName] = {
type: fieldSchema, type: fieldSchema,
name: fieldName, name: fieldName,
} }
} else { } else {
fixedSchema[fieldName] = { newSchema[fieldName] = {
...fieldSchema, ...fieldSchema,
name: fieldName, name: fieldName,
} }
} }
}) })
schema = fixedSchema schema = newSchema
schemaLoaded = true schemaLoaded = true
} }

View File

@ -34,25 +34,34 @@
return closestContext || {} return closestContext || {}
} }
// Fetches the form schema from this form's dataSource, if one exists // Fetches the form schema from this form's dataSource
const fetchSchema = async () => { const fetchSchema = async () => {
if (!dataSource?.tableId) { if (!dataSource) {
schema = {} schema = {}
table = null }
} else {
table = await API.fetchTableDefinition(dataSource?.tableId) // If the datasource is a query, then we instead use a schema of the query
if (table) { // parameters rather than the output schema
if (dataSource?.type === "query") { else if (
schema = {} dataSource.type === "query" &&
const params = table.parameters || [] dataSource._id &&
actionType === "Create"
) {
const query = await API.fetchQueryDefinition(dataSource._id)
let paramSchema = {}
const params = query.parameters || []
params.forEach(param => { params.forEach(param => {
schema[param.name] = { ...param, type: "string" } paramSchema[param.name] = { ...param, type: "string" }
}) })
} else { schema = paramSchema
schema = table.schema || {}
}
} }
// For all other cases, just grab the normal schema
else {
const dataSourceSchema = await API.fetchDatasourceSchema(dataSource)
schema = dataSourceSchema || {}
} }
loaded = true loaded = true
} }