Adding server functionality to determine schema for JSON data type, some basic UI around an editor for getting JSON to determine schema from and the key/value mechanism for flat structures.

This commit is contained in:
mike12345567 2021-11-26 17:39:18 +00:00
parent 0be0cc9a55
commit ed28bf664d
4 changed files with 93 additions and 17 deletions

View File

@ -452,7 +452,10 @@
</div> </div>
</ModalContent> </ModalContent>
<Modal bind:this={jsonSchemaModal}> <Modal bind:this={jsonSchemaModal}>
<JSONSchemaModal on:save={({ detail }) => console.log(detail)} /> <JSONSchemaModal
schema={field.schema}
on:save={({ detail }) => (field.schema = detail)}
/>
</Modal> </Modal>
<ConfirmDialog <ConfirmDialog
bind:this={confirmDeleteDialog} bind:this={confirmDeleteDialog}

View File

@ -7,8 +7,10 @@
Button, Button,
Input, Input,
Select, Select,
notifications,
} from "@budibase/bbui" } from "@budibase/bbui"
import { onMount, createEventDispatcher } from "svelte" import { onMount, createEventDispatcher } from "svelte"
import { post } from "builderStore/api"
export let schema = {} export let schema = {}
@ -19,13 +21,42 @@
let fieldKeys = {}, let fieldKeys = {},
fieldTypes = {} fieldTypes = {}
let keyValueOptions = ["String", "Number", "Boolean", "Object", "Array"] let keyValueOptions = ["String", "Number", "Boolean", "Object", "Array"]
let invalid = false
$: invalid = false async function onJsonUpdate({ detail }) {
function onJsonUpdate({ detail }) {
// TODO: make request
const input = detail.value const input = detail.value
console.log(input) json = input
try {
// check json valid first
let inputJson = JSON.parse(input)
const response = await post("/api/tables/schema/generate", {
json: inputJson,
})
if (response.status !== 200) {
const error = (await response.text()).message
notifications.error(error)
} else {
schema = await response.json()
updateCounts()
invalid = false
}
} catch (err) {
// json not currently valid
invalid = true
}
}
function updateCounts() {
if (!schema) {
schema = {}
}
let i = 0
for (let [key, value] of Object.entries(schema)) {
fieldKeys[i] = key
fieldTypes[i] = value.type
i++
}
fieldCount = i
} }
function saveSchema() { function saveSchema() {
@ -39,16 +70,7 @@
} }
onMount(() => { onMount(() => {
if (!schema) { updateCounts()
schema = {}
}
let i = 0
for (let [key, value] of Object.entries(schema)) {
fieldKeys[i] = key
fieldTypes[i] = value.type
i++
}
fieldCount = i
}) })
</script> </script>
@ -56,7 +78,7 @@
title={"Key/Value Schema Editor"} title={"Key/Value Schema Editor"}
confirmText="Save Column" confirmText="Save Column"
onConfirm={saveSchema} onConfirm={saveSchema}
disabled={invalid} bind:disabled={invalid}
size="L" size="L"
> >
<Tabs selected={mode} noPadding> <Tabs selected={mode} noPadding>

View File

@ -9,6 +9,7 @@ const {
BudibaseInternalDB, BudibaseInternalDB,
} = require("../../../db/utils") } = require("../../../db/utils")
const { getTable } = require("./utils") const { getTable } = require("./utils")
const { FieldTypes } = require("../../../constants")
function pickApi({ tableId, table }) { function pickApi({ tableId, table }) {
if (table && !tableId) { if (table && !tableId) {
@ -81,6 +82,38 @@ exports.destroy = async function (ctx) {
ctx.body = { message: `Table ${tableId} deleted.` } 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) { exports.bulkImport = async function (ctx) {
const tableId = ctx.params.tableId const tableId = ctx.params.tableId
await pickApi({ tableId }).bulkImport(ctx) await pickApi({ tableId }).bulkImport(ctx)

View File

@ -139,6 +139,24 @@ router
generateSaveValidator(), generateSaveValidator(),
tableController.save 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 * @api {post} /api/tables/csv/validate Validate a CSV for a table
* @apiName Validate a CSV for a table * @apiName Validate a CSV for a table