Merge pull request #3444 from Budibase/fix/sql-invalid-cols

Disallow _id, _rev and tableId fields for SQL tables
This commit is contained in:
Michael Drury 2021-11-22 11:03:59 +00:00 committed by GitHub
commit ddcc94c772
4 changed files with 53 additions and 9 deletions

View File

@ -8,6 +8,8 @@
export let onConfirm = undefined export let onConfirm = undefined
$: icon = selectIcon(type) $: icon = selectIcon(type)
// if newlines used, convert them to different elements
$: split = message.split("\n")
function selectIcon(alertType) { function selectIcon(alertType) {
switch (alertType) { switch (alertType) {
@ -33,7 +35,9 @@
<use xlink:href="#spectrum-icon-18-{icon}" /> <use xlink:href="#spectrum-icon-18-{icon}" />
</svg> </svg>
<div class="spectrum-InLineAlert-header">{header}</div> <div class="spectrum-InLineAlert-header">{header}</div>
<div class="spectrum-InLineAlert-content">{message}</div> {#each split as splitMsg}
<div class="spectrum-InLineAlert-content">{splitMsg}</div>
{/each}
{#if onConfirm} {#if onConfirm}
<div class="spectrum-InLineAlert-footer"> <div class="spectrum-InLineAlert-footer">
<Button secondary on:click={onConfirm}>OK</Button> <Button secondary on:click={onConfirm}>OK</Button>

View File

@ -7,7 +7,7 @@ const {
BudibaseInternalDB, BudibaseInternalDB,
getTableParams, getTableParams,
} = require("../../db/utils") } = require("../../db/utils")
const { BuildSchemaErrors } = require("../../constants") const { BuildSchemaErrors, InvalidColumns } = require("../../constants")
const { integrations } = require("../../integrations") const { integrations } = require("../../integrations")
const { getDatasourceAndQuery } = require("./row/utils") const { getDatasourceAndQuery } = require("./row/utils")
@ -152,6 +152,23 @@ exports.query = async function (ctx) {
} }
} }
function getErrorTables(errors, errorType) {
return Object.entries(errors)
.filter(entry => entry[1] === errorType)
.map(([name]) => name)
}
function updateError(error, newError, tables) {
if (!error) {
error = ""
}
if (error.length > 0) {
error += "\n"
}
error += `${newError} ${tables.join(", ")}`
return error
}
const buildSchemaHelper = async datasource => { const buildSchemaHelper = async datasource => {
const Connector = integrations[datasource.source] const Connector = integrations[datasource.source]
@ -176,12 +193,23 @@ const buildSchemaHelper = async datasource => {
const errors = connector.schemaErrors const errors = connector.schemaErrors
let error = null let error = null
if (errors && Object.keys(errors).length > 0) { if (errors && Object.keys(errors).length > 0) {
const noKeyTables = Object.entries(errors) const noKey = getErrorTables(errors, BuildSchemaErrors.NO_KEY)
.filter(entry => entry[1] === BuildSchemaErrors.NO_KEY) const invalidCol = getErrorTables(errors, BuildSchemaErrors.INVALID_COLUMN)
.map(([name]) => name) if (noKey.length) {
error = `No primary key constraint found for the following: ${noKeyTables.join( error = updateError(
", " error,
)}` "No primary key constraint found for the following:",
noKey
)
}
if (invalidCol.length) {
const invalidCols = Object.values(InvalidColumns).join(", ")
error = updateError(
error,
`Cannot use columns ${invalidCols} found in following:`,
invalidCol
)
}
} }
return { tables: connector.tables, error } return { tables: connector.tables, error }
} }

View File

@ -163,8 +163,15 @@ exports.MetadataTypes = {
AUTOMATION_TEST_HISTORY: "automationTestHistory", AUTOMATION_TEST_HISTORY: "automationTestHistory",
} }
exports.InvalidColumns = {
ID: "_id",
REV: "_rev",
TABLE_ID: "tableId",
}
exports.BuildSchemaErrors = { exports.BuildSchemaErrors = {
NO_KEY: "no_key", NO_KEY: "no_key",
INVALID_COLUMN: "invalid_column",
} }
// pass through the list from the auth/core lib // pass through the list from the auth/core lib

View File

@ -2,7 +2,7 @@ import { SqlQuery } from "../definitions/datasource"
import { Datasource, Table } from "../definitions/common" import { Datasource, Table } from "../definitions/common"
import { SourceNames } from "../definitions/datasource" import { SourceNames } from "../definitions/datasource"
const { DocumentTypes, SEPARATOR } = require("../db/utils") const { DocumentTypes, SEPARATOR } = require("../db/utils")
const { FieldTypes, BuildSchemaErrors } = require("../constants") const { FieldTypes, BuildSchemaErrors, InvalidColumns } = require("../constants")
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}` const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
const ROW_ID_REGEX = /^\[.*]$/g const ROW_ID_REGEX = /^\[.*]$/g
@ -161,13 +161,18 @@ export function finaliseExternalTables(
tables: { [key: string]: any }, tables: { [key: string]: any },
entities: { [key: string]: any } entities: { [key: string]: any }
) { ) {
const invalidColumns = Object.values(InvalidColumns)
const finalTables: { [key: string]: any } = {} const finalTables: { [key: string]: any } = {}
const errors: { [key: string]: string } = {} const errors: { [key: string]: string } = {}
for (let [name, table] of Object.entries(tables)) { for (let [name, table] of Object.entries(tables)) {
const schemaFields = Object.keys(table.schema)
// make sure every table has a key // make sure every table has a key
if (table.primary == null || table.primary.length === 0) { if (table.primary == null || table.primary.length === 0) {
errors[name] = BuildSchemaErrors.NO_KEY errors[name] = BuildSchemaErrors.NO_KEY
continue continue
} else if (schemaFields.find(field => invalidColumns.includes(field))) {
errors[name] = BuildSchemaErrors.INVALID_COLUMN
continue
} }
// make sure all previous props have been added back // make sure all previous props have been added back
finalTables[name] = copyExistingPropsOver(name, table, entities) finalTables[name] = copyExistingPropsOver(name, table, entities)