Improve custom datasource schema generation and error resistance
This commit is contained in:
parent
0e394f0259
commit
ecd2ed3d07
|
@ -1,6 +1,7 @@
|
||||||
import DataFetch from "./DataFetch.js"
|
import DataFetch from "./DataFetch.js"
|
||||||
|
|
||||||
export default class CustomFetch extends DataFetch {
|
export default class CustomFetch extends DataFetch {
|
||||||
|
// Gets the correct Budibase type for a JS value
|
||||||
getType(value) {
|
getType(value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return "string"
|
return "string"
|
||||||
|
@ -8,11 +9,15 @@ export default class CustomFetch extends DataFetch {
|
||||||
const type = typeof value
|
const type = typeof value
|
||||||
if (type === "object") {
|
if (type === "object") {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
|
// Use our custom array type to render badges
|
||||||
return "array"
|
return "array"
|
||||||
}
|
}
|
||||||
|
// Use JSON for objects to ensure they are stringified
|
||||||
return "json"
|
return "json"
|
||||||
|
} else if (!isNaN(value)) {
|
||||||
|
return "number"
|
||||||
} else {
|
} else {
|
||||||
return type
|
return "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,9 +32,8 @@ export default class CustomFetch extends DataFetch {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle string cases
|
// For strings, try JSON then fall back to attempting a CSV
|
||||||
if (typeof data === "string") {
|
if (typeof data === "string") {
|
||||||
// Try JSON parsing
|
|
||||||
try {
|
try {
|
||||||
const js = JSON.parse(data)
|
const js = JSON.parse(data)
|
||||||
if (Array.isArray(js)) {
|
if (Array.isArray(js)) {
|
||||||
|
@ -38,8 +42,6 @@ export default class CustomFetch extends DataFetch {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try a simple CSV
|
|
||||||
return data.split(",").map(x => x.trim())
|
return data.split(",").map(x => x.trim())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,12 +56,13 @@ export default class CustomFetch extends DataFetch {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out any invalid values
|
// Filter out any invalid values
|
||||||
data = data.filter(x => x != null && !Array.isArray(x))
|
data = data.filter(x => x != null && x !== "" && !Array.isArray(x))
|
||||||
|
|
||||||
// Ensure all values are packed into objects
|
// Ensure all values are packed into objects
|
||||||
return data.map(x => (typeof x === "object" ? x : { value: x }))
|
return data.map(x => (typeof x === "object" ? x : { value: x }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extracts and parses the custom data from the datasource definition
|
||||||
getCustomData(datasource) {
|
getCustomData(datasource) {
|
||||||
return this.enrichCustomData(this.parseCustomData(datasource?.data))
|
return this.enrichCustomData(this.parseCustomData(datasource?.data))
|
||||||
}
|
}
|
||||||
|
@ -68,6 +71,9 @@ export default class CustomFetch extends DataFetch {
|
||||||
// Try and work out the schema from the array provided
|
// Try and work out the schema from the array provided
|
||||||
let schema = {}
|
let schema = {}
|
||||||
const data = this.getCustomData(datasource)
|
const data = this.getCustomData(datasource)
|
||||||
|
if (!data?.length) {
|
||||||
|
return { schema }
|
||||||
|
}
|
||||||
|
|
||||||
// Go through every object and extract all valid keys
|
// Go through every object and extract all valid keys
|
||||||
for (let datum of data) {
|
for (let datum of data) {
|
||||||
|
@ -76,14 +82,32 @@ export default class CustomFetch extends DataFetch {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (!schema[key]) {
|
if (!schema[key]) {
|
||||||
schema[key] = { type: this.getType(datum[key]) }
|
let type = this.getType(datum[key])
|
||||||
|
let constraints = {}
|
||||||
|
|
||||||
|
// Determine whether we should render text columns as options instead
|
||||||
|
if (type === "string") {
|
||||||
|
const uniqueValues = [...new Set(data.map(x => x[key]))]
|
||||||
|
const uniqueness = uniqueValues.length / data.length
|
||||||
|
if (uniqueness <= 0.8) {
|
||||||
|
type = "options"
|
||||||
|
constraints.inclusion = uniqueValues
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate options for array columns
|
||||||
|
if (type === "array") {
|
||||||
|
constraints.inclusion = [...new Set(data.map(x => x[key]).flat())]
|
||||||
|
}
|
||||||
|
|
||||||
|
schema[key] = {
|
||||||
|
type,
|
||||||
|
constraints,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return { schema }
|
||||||
return {
|
|
||||||
schema,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getData() {
|
async getData() {
|
||||||
|
|
Loading…
Reference in New Issue