Don't allow a column to be both required and have a default value.
This commit is contained in:
parent
c64d76eb84
commit
ca31add039
|
@ -10,7 +10,7 @@ import {
|
||||||
isExternalTableID,
|
isExternalTableID,
|
||||||
isSQL,
|
isSQL,
|
||||||
} from "../../../integrations/utils"
|
} from "../../../integrations/utils"
|
||||||
import { events } from "@budibase/backend-core"
|
import { events, HTTPError } from "@budibase/backend-core"
|
||||||
import {
|
import {
|
||||||
BulkImportRequest,
|
BulkImportRequest,
|
||||||
BulkImportResponse,
|
BulkImportResponse,
|
||||||
|
@ -40,6 +40,20 @@ function pickApi({ tableId, table }: { tableId?: string; table?: Table }) {
|
||||||
return internal
|
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
|
// covers both internal and external
|
||||||
export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
|
export async function fetch(ctx: UserCtx<void, FetchTablesResponse>) {
|
||||||
const internal = await sdk.tables.getAllInternalTables()
|
const internal = await sdk.tables.getAllInternalTables()
|
||||||
|
@ -76,6 +90,8 @@ export async function save(ctx: UserCtx<SaveTableRequest, SaveTableResponse>) {
|
||||||
const isImport = table.rows
|
const isImport = table.rows
|
||||||
const renaming = ctx.request.body._rename
|
const renaming = ctx.request.body._rename
|
||||||
|
|
||||||
|
checkDefaultFields(table)
|
||||||
|
|
||||||
const api = pickApi({ table })
|
const api = pickApi({ table })
|
||||||
let savedTable = await api.save(ctx, renaming)
|
let savedTable = await api.save(ctx, renaming)
|
||||||
if (!table._id) {
|
if (!table._id) {
|
||||||
|
|
|
@ -86,6 +86,30 @@ describe.each([
|
||||||
expect(events.rows.imported).toHaveBeenCalledWith(res, 1)
|
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 () => {
|
it("should apply authorization to endpoint", async () => {
|
||||||
await checkBuilderEndpoint({
|
await checkBuilderEndpoint({
|
||||||
config,
|
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", () => {
|
describe("external table validation", () => {
|
||||||
!isInternal &&
|
!isInternal &&
|
||||||
it("should error if column is of type auto", async () => {
|
it("should error if column is of type auto", async () => {
|
||||||
|
|
Loading…
Reference in New Issue