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:
parent
0be0cc9a55
commit
ed28bf664d
|
@ -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}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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…
Reference in New Issue