1
0
Fork 0
mirror of synced 2024-09-20 11:27:56 +12:00

Don't allow a column to be both required and have a default value.

This commit is contained in:
Sam Rose 2024-07-16 16:54:34 +01:00
parent c64d76eb84
commit ca31add039
No known key found for this signature in database
2 changed files with 177 additions and 1 deletions

View file

@ -10,7 +10,7 @@ import {
isExternalTableID,
isSQL,
} from "../../../integrations/utils"
import { events } from "@budibase/backend-core"
import { events, HTTPError } from "@budibase/backend-core"
import {
BulkImportRequest,
BulkImportResponse,
@ -40,6 +40,20 @@ function pickApi({ tableId, table }: { tableId?: string; table?: Table }) {
return internal
}
function checkDefaultFields(table: Table) {
for (const [key, field] of Object.entries(table.schema)) {
if (!("default" in field) || field.default == null) {
continue
}
if (field.constraints?.presence) {
throw new HTTPError(
`Cannot make field "${key}" required, it has a default value.`,
400
)
}
}
}
// covers both internal and external
export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
const internal = await sdk.tables.getAllInternalTables()
@ -76,6 +90,8 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
const isImport = table.rows
const renaming = ctx.request.body._rename
checkDefaultFields(table)
const api = pickApi({ table })
let savedTable = await api.save(ctx, renaming)
if (!table._id) {

View file

@ -86,6 +86,30 @@ describe.each([
expect(events.rows.imported).toHaveBeenCalledWith(res, 1)
})
it("should not allow a column to have a default value and be required", async () => {
await config.api.table.save(
tableForDatasource(datasource, {
schema: {
name: {
name: "name",
type: FieldType.STRING,
default: "default",
constraints: {
presence: true,
},
},
},
}),
{
status: 400,
body: {
message:
'Cannot make field "name" required, it has a default value.',
},
}
)
})
it("should apply authorization to endpoint", async () => {
await checkBuilderEndpoint({
config,
@ -225,6 +249,142 @@ describe.each([
})
})
describe("default field validation", () => {
it("should error if an existing column is set to required and has a default value", async () => {
const table = await config.api.table.save(
tableForDatasource(datasource, {
schema: {
name: {
name: "name",
type: FieldType.STRING,
default: "default",
},
},
})
)
await config.api.table.save(
{
...table,
schema: {
...table.schema,
name: {
name: "name",
type: FieldType.STRING,
default: "default",
constraints: {
presence: true,
},
},
},
},
{
status: 400,
body: {
message:
'Cannot make field "name" required, it has a default value.',
},
}
)
})
it("should error if an existing column is given a default value and is required", async () => {
const table = await config.api.table.save(
tableForDatasource(datasource, {
schema: {
name: {
name: "name",
type: FieldType.STRING,
constraints: {
presence: true,
},
},
},
})
)
await config.api.table.save(
{
...table,
schema: {
...table.schema,
name: {
name: "name",
type: FieldType.STRING,
default: "default",
constraints: {
presence: true,
},
},
},
},
{
status: 400,
body: {
message:
'Cannot make field "name" required, it has a default value.',
},
}
)
})
it("should be able to set an existing column to have a default value if it's not required", async () => {
const table = await config.api.table.save(
tableForDatasource(datasource, {
schema: {
name: {
name: "name",
type: FieldType.STRING,
},
},
})
)
await config.api.table.save(
{
...table,
schema: {
...table.schema,
name: {
name: "name",
type: FieldType.STRING,
default: "default",
},
},
},
{ status: 200 }
)
})
it("should be able to remove a default value if the column is not required", async () => {
const table = await config.api.table.save(
tableForDatasource(datasource, {
schema: {
name: {
name: "name",
type: FieldType.STRING,
default: "default",
},
},
})
)
await config.api.table.save(
{
...table,
schema: {
...table.schema,
name: {
name: "name",
type: FieldType.STRING,
},
},
},
{ status: 200 }
)
})
})
describe("external table validation", () => {
!isInternal &&
it("should error if column is of type auto", async () => {