From de0b23dd9f931a87379f5bba7c85439a83ab61c2 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 29 Nov 2021 17:11:08 +0000 Subject: [PATCH] Moving generation to builder because it reduces API calls and has no reason to be carried out server-side, handling array/object schema generation correctly. --- .../src/builderStore/schemaGenerator.js | 56 +++++++++++++++++++ .../DataTable/modals/CreateEditColumn.svelte | 11 +++- .../DataTable/modals/JSONSchemaModal.svelte | 40 ++++++------- .../server/src/api/controllers/table/index.js | 33 ----------- packages/server/src/api/routes/table.js | 18 ------ 5 files changed, 86 insertions(+), 72 deletions(-) create mode 100644 packages/builder/src/builderStore/schemaGenerator.js diff --git a/packages/builder/src/builderStore/schemaGenerator.js b/packages/builder/src/builderStore/schemaGenerator.js new file mode 100644 index 0000000000..33115fc997 --- /dev/null +++ b/packages/builder/src/builderStore/schemaGenerator.js @@ -0,0 +1,56 @@ +import { FIELDS } from "constants/backend" + +function baseConversion(type) { + if (type === "string") { + return { + type: FIELDS.STRING.type, + } + } else if (type === "boolean") { + return { + type: FIELDS.BOOLEAN.type, + } + } else if (type === "number") { + return { + type: FIELDS.NUMBER.type, + } + } +} + +function recurse(schemaLevel = {}, objectLevel) { + if (!objectLevel) { + return null + } + const baseType = typeof objectLevel + if (baseType !== "object") { + return baseConversion(baseType) + } + for (let [key, value] of Object.entries(objectLevel)) { + const type = typeof value + // check array first, since arrays are objects + if (Array.isArray(value)) { + const schema = recurse(schemaLevel[key], value[0]) + if (schema) { + schemaLevel[key] = { + type: FIELDS.ARRAY.type, + schema, + } + } + } else if (type === "object") { + const schema = recurse(schemaLevel[key], objectLevel[key]) + if (schema) { + schemaLevel[key] = schema + } + } else { + schemaLevel[key] = baseConversion(type) + } + } + if (!schemaLevel.type) { + return { type: FIELDS.JSON.type, schema: schemaLevel } + } else { + return schemaLevel + } +} + +export function generate(object) { + return recurse({}, object).schema +} diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index f4c0422304..752f291019 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -87,7 +87,10 @@ field.subtype !== AUTO_COLUMN_SUB_TYPES.CREATED_BY && field.subtype !== AUTO_COLUMN_SUB_TYPES.UPDATED_BY && field.type !== FORMULA_TYPE - $: canBeDisplay = field.type !== LINK_TYPE && field.type !== AUTO_TYPE + $: canBeDisplay = + field.type !== LINK_TYPE && + field.type !== AUTO_TYPE && + field.type !== JSON_TYPE $: canBeRequired = field.type !== LINK_TYPE && !uneditable && field.type !== AUTO_TYPE $: relationshipOptions = getRelationshipOptions(field) @@ -454,7 +457,11 @@ (field.schema = detail)} + json={field.json} + on:save={({ detail }) => { + field.schema = detail.schema + field.json = detail.json + }} /> { @@ -90,7 +91,8 @@ label="Type" options={keyValueOptions} bind:value={fieldTypes[i]} - getOptionValue={field => field.toLowerCase()} + getOptionValue={field => field.value} + getOptionLabel={field => field.label} /> {/each} diff --git a/packages/server/src/api/controllers/table/index.js b/packages/server/src/api/controllers/table/index.js index bd404f3da8..abbb4d6ff9 100644 --- a/packages/server/src/api/controllers/table/index.js +++ b/packages/server/src/api/controllers/table/index.js @@ -9,7 +9,6 @@ const { BudibaseInternalDB, } = require("../../../db/utils") const { getTable } = require("./utils") -const { FieldTypes } = require("../../../constants") function pickApi({ tableId, table }) { if (table && !tableId) { @@ -82,38 +81,6 @@ exports.destroy = async function (ctx) { ctx.body = { message: `Table ${tableId} deleted.` } } -exports.schemaGenerate = function (ctx) { - const { json } = ctx.request.body - function recurse(schemaLevel, objectLevel) { - for (let [key, value] of Object.entries(objectLevel)) { - const type = typeof value - // check array first, since arrays are objects - if (Array.isArray(value)) { - schemaLevel[key] = { - type: FieldTypes.ARRAY, - } - } else if (type === "object") { - schemaLevel[key] = recurse(schemaLevel[key], objectLevel) - } else if (type === "string") { - schemaLevel[key] = { - type: FieldTypes.STRING, - } - } else if (type === "boolean") { - schemaLevel[key] = { - type: FieldTypes.BOOLEAN, - } - } else if (type === "number") { - schemaLevel[key] = { - type: FieldTypes.NUMBER, - } - } - } - return schemaLevel - } - - ctx.body = recurse({}, json) || {} -} - exports.bulkImport = async function (ctx) { const tableId = ctx.params.tableId await pickApi({ tableId }).bulkImport(ctx) diff --git a/packages/server/src/api/routes/table.js b/packages/server/src/api/routes/table.js index a4575b3572..d8ddbe8133 100644 --- a/packages/server/src/api/routes/table.js +++ b/packages/server/src/api/routes/table.js @@ -139,24 +139,6 @@ router generateSaveValidator(), tableController.save ) - /** - * @api {post} /api/tables/schema/generate Generate schema from JSON - * @apiName Generate schema from JSON - * @apiGroup tables - * @apiPermission builder - * @apiDescription Given a JSON structure this will generate a nested schema that can be used for a key/value data - * type in a table. - * - * @apiParam (Body) {object} json The JSON structure from which a nest schema should be generated. - * - * @apiSuccess {object} schema The response body will contain the schema, which can now be used for a key/value - * data type. - */ - .post( - "/api/tables/schema/generate", - authorized(BUILDER), - tableController.schemaGenerate - ) /** * @api {post} /api/tables/csv/validate Validate a CSV for a table * @apiName Validate a CSV for a table