From 1eac218d6e523b33699a0c5117a780b3af9839e8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 4 Jan 2022 15:02:43 +0000 Subject: [PATCH] Add support for nested provider, field and jsonarray datasource types in new data fetch model --- packages/client/src/utils/fetch/FieldFetch.js | 44 ++++++++ .../client/src/utils/fetch/JSONArrayFetch.js | 13 +++ .../src/utils/fetch/NestedProviderFetch.js | 20 ++++ packages/client/src/utils/fetch/fetchData.js | 6 + packages/client/src/utils/schema.js | 104 +++++++----------- 5 files changed, 120 insertions(+), 67 deletions(-) create mode 100644 packages/client/src/utils/fetch/FieldFetch.js create mode 100644 packages/client/src/utils/fetch/JSONArrayFetch.js create mode 100644 packages/client/src/utils/fetch/NestedProviderFetch.js diff --git a/packages/client/src/utils/fetch/FieldFetch.js b/packages/client/src/utils/fetch/FieldFetch.js new file mode 100644 index 0000000000..ef9902ed27 --- /dev/null +++ b/packages/client/src/utils/fetch/FieldFetch.js @@ -0,0 +1,44 @@ +import DataFetch from "./DataFetch.js" + +export default class FieldFetch extends DataFetch { + static async getDefinition(datasource) { + // Field sources have their schema statically defined + let schema + if (datasource.fieldType === "attachment") { + schema = { + url: { + type: "string", + }, + name: { + type: "string", + }, + } + } else if (datasource.fieldType === "array") { + schema = { + value: { + type: "string", + }, + } + } + return { schema } + } + + async getData() { + const { datasource } = this.options + + // These sources will be available directly from context + const data = datasource?.value || [] + let rows = [] + if (Array.isArray(data) && data[0] && typeof data[0] !== "object") { + rows = data.map(value => ({ value })) + } else { + rows = data + } + + return { + rows: rows || [], + hasNextPage: false, + cursor: null, + } + } +} diff --git a/packages/client/src/utils/fetch/JSONArrayFetch.js b/packages/client/src/utils/fetch/JSONArrayFetch.js new file mode 100644 index 0000000000..8beb555ef9 --- /dev/null +++ b/packages/client/src/utils/fetch/JSONArrayFetch.js @@ -0,0 +1,13 @@ +import FieldFetch from "./FieldFetch.js" +import { fetchTableDefinition } from "api" +import { getJSONArrayDatasourceSchema } from "builder/src/builderStore/jsonUtils" + +export default class JSONArrayFetch extends FieldFetch { + static async getDefinition(datasource) { + // JSON arrays need their table definitions fetched. + // We can then extract their schema as a subset of the table schema. + const table = await fetchTableDefinition(datasource.tableId) + const schema = getJSONArrayDatasourceSchema(table?.schema, datasource) + return { schema } + } +} diff --git a/packages/client/src/utils/fetch/NestedProviderFetch.js b/packages/client/src/utils/fetch/NestedProviderFetch.js new file mode 100644 index 0000000000..163d7e9930 --- /dev/null +++ b/packages/client/src/utils/fetch/NestedProviderFetch.js @@ -0,0 +1,20 @@ +import DataFetch from "./DataFetch.js" + +export default class NestedProviderFetch extends DataFetch { + static async getDefinition(datasource) { + // Nested providers should already have exposed their own schema + return { + schema: datasource?.value?.schema, + } + } + + async getData() { + const { datasource } = this.options + // Pull the rows from the existing data provider + return { + rows: datasource?.value?.rows || [], + hasNextPage: false, + cursor: null, + } + } +} diff --git a/packages/client/src/utils/fetch/fetchData.js b/packages/client/src/utils/fetch/fetchData.js index bd14e849dc..f93e037b44 100644 --- a/packages/client/src/utils/fetch/fetchData.js +++ b/packages/client/src/utils/fetch/fetchData.js @@ -2,12 +2,18 @@ import TableFetch from "./TableFetch.js" import ViewFetch from "./ViewFetch.js" import QueryFetch from "./QueryFetch.js" import RelationshipFetch from "./RelationshipFetch.js" +import NestedProviderFetch from "./NestedProviderFetch.js" +import FieldFetch from "./FieldFetch.js" +import JSONArrayFetch from "./JSONArrayFetch.js" const DataFetchMap = { table: TableFetch, view: ViewFetch, query: QueryFetch, link: RelationshipFetch, + provider: NestedProviderFetch, + field: FieldFetch, + jsonarray: JSONArrayFetch, } export const fetchData = (datasource, options) => { diff --git a/packages/client/src/utils/schema.js b/packages/client/src/utils/schema.js index 7122140744..e333bb616e 100644 --- a/packages/client/src/utils/schema.js +++ b/packages/client/src/utils/schema.js @@ -1,83 +1,53 @@ -import { - convertJSONSchemaToTableSchema, - getJSONArrayDatasourceSchema, -} from "builder/src/builderStore/jsonUtils" -import { fetchTableDefinition } from "api" +import { convertJSONSchemaToTableSchema } from "builder/src/builderStore/jsonUtils" import TableFetch from "./fetch/TableFetch.js" import ViewFetch from "./fetch/ViewFetch.js" import QueryFetch from "./fetch/QueryFetch.js" +import RelationshipFetch from "./fetch/RelationshipFetch.js" +import NestedProviderFetch from "./fetch/NestedProviderFetch.js" +import FieldFetch from "./fetch/FieldFetch.js" +import JSONArrayFetch from "./fetch/JSONArrayFetch.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. */ export const fetchDatasourceSchema = async datasource => { - const type = datasource?.type - let schema - - // Nested providers should already have exposed their own schema - if (type === "provider") { - schema = datasource.value?.schema - } - - // Field sources have their schema statically defined - if (type === "field") { - if (datasource.fieldType === "attachment") { - schema = { - url: { - type: "string", - }, - name: { - type: "string", - }, - } - } else if (datasource.fieldType === "array") { - schema = { - value: { - type: "string", - }, - } - } - } - - // JSON arrays need their table definitions fetched. - // We can then extract their schema as a subset of the table schema. - if (type === "jsonarray") { - const table = await fetchTableDefinition(datasource.tableId) - schema = getJSONArrayDatasourceSchema(table?.schema, datasource) - } - - // All normal datasource schema can use their corresponding implementations - // in the data fetch classes const handler = { table: TableFetch, - link: TableFetch, view: ViewFetch, query: QueryFetch, - }[type] - if (handler) { - const definition = await handler.getDefinition(datasource) - schema = handler.getSchema(datasource, definition) + link: RelationshipFetch, + provider: NestedProviderFetch, + field: FieldFetch, + jsonarray: JSONArrayFetch, + }[datasource?.type] + if (!handler) { + return null + } + + // Get the datasource definition and then schema + const definition = await handler.getDefinition(datasource) + const schema = handler.getSchema(datasource, definition) + if (!schema) { + return null } // Check for any JSON fields so we can add any top level properties - if (schema) { - let jsonAdditions = {} - Object.keys(schema).forEach(fieldKey => { - const fieldSchema = schema[fieldKey] - if (fieldSchema?.type === "json") { - const jsonSchema = convertJSONSchemaToTableSchema(fieldSchema, { - squashObjects: true, - }) - Object.keys(jsonSchema).forEach(jsonKey => { - jsonAdditions[`${fieldKey}.${jsonKey}`] = { - type: jsonSchema[jsonKey].type, - nestedJSON: true, - } - }) - } - }) - return { ...schema, ...jsonAdditions } - } - - return null + let jsonAdditions = {} + Object.keys(schema).forEach(fieldKey => { + const fieldSchema = schema[fieldKey] + if (fieldSchema?.type === "json") { + const jsonSchema = convertJSONSchemaToTableSchema(fieldSchema, { + squashObjects: true, + }) + Object.keys(jsonSchema).forEach(jsonKey => { + jsonAdditions[`${fieldKey}.${jsonKey}`] = { + type: jsonSchema[jsonKey].type, + nestedJSON: true, + } + }) + } + }) + return { ...schema, ...jsonAdditions } }