Browse Source

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.

master
mike12345567 5 years ago
parent
commit
ed28bf664d
  1. 5
      packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte
  2. 52
      packages/builder/src/components/backend/DataTable/modals/JSONSchemaModal.svelte
  3. 33
      packages/server/src/api/controllers/table/index.js
  4. 18
      packages/server/src/api/routes/table.js

5
packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte

@ -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}

52
packages/builder/src/components/backend/DataTable/modals/JSONSchemaModal.svelte

@ -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,26 +21,32 @@
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
function saveSchema() { let inputJson = JSON.parse(input)
for (let i of Object.keys(fieldKeys)) { const response = await post("/api/tables/schema/generate", {
const key = fieldKeys[i] json: inputJson,
schema[key] = { })
type: fieldTypes[i], 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
} }
dispatcher("save", schema)
} }
onMount(() => { function updateCounts() {
if (!schema) { if (!schema) {
schema = {} schema = {}
} }
@ -49,6 +57,20 @@
i++ i++
} }
fieldCount = i fieldCount = i
}
function saveSchema() {
for (let i of Object.keys(fieldKeys)) {
const key = fieldKeys[i]
schema[key] = {
type: fieldTypes[i],
}
}
dispatcher("save", schema)
}
onMount(() => {
updateCounts()
}) })
</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>

33
packages/server/src/api/controllers/table/index.js

@ -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)

18
packages/server/src/api/routes/table.js

@ -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

Loading…
Cancel
Save