Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests to ensure date sorting works, and you can't bulk import dates in an invalid format. #15358

Merged
merged 6 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions packages/server/src/api/routes/tests/row.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2043,6 +2043,101 @@ if (descriptions.length) {
expect(rows[0].name).toEqual("Clare updated")
expect(rows[1].name).toEqual("Jeff updated")
})

it("should reject bulkImport date only fields with wrong format", async () => {
const table = await config.api.table.save(
saveTableRequest({
schema: {
date: {
type: FieldType.DATETIME,
dateOnly: true,
name: "date",
},
},
})
)

await config.api.row.bulkImport(
table._id!,
{
rows: [
{
date: "01.02.2024",
},
],
},
{
status: 400,
body: {
message:
'Invalid format for field "date": "01.02.2024". Date-only fields must be in the format "YYYY-MM-DD".',
},
}
)
})

it("should reject bulkImport date time fields with wrong format", async () => {
const table = await config.api.table.save(
saveTableRequest({
schema: {
date: {
type: FieldType.DATETIME,
name: "date",
},
},
})
)

await config.api.row.bulkImport(
table._id!,
{
rows: [
{
date: "01.02.2024",
},
],
},
{
status: 400,
body: {
message:
'Invalid format for field "date": "01.02.2024". Datetime fields must be in ISO format, e.g. "YYYY-MM-DDTHH:MM:SSZ".',
},
}
)
})

it("should reject bulkImport time fields with wrong format", async () => {
const table = await config.api.table.save(
saveTableRequest({
schema: {
time: {
type: FieldType.DATETIME,
timeOnly: true,
name: "time",
},
},
})
)

await config.api.row.bulkImport(
table._id!,
{
rows: [
{
time: "3pm",
},
],
},
{
status: 400,
body: {
message:
'Invalid format for field "time": "3pm". Time-only fields must be in the format "HH:MM:SS".',
},
}
)
})
})

describe("enrich", () => {
Expand Down
67 changes: 64 additions & 3 deletions packages/server/src/api/routes/tests/search.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1705,7 +1705,10 @@ if (descriptions.length) {

beforeAll(async () => {
tableOrViewId = await createTableOrView({
dateid: { name: "dateid", type: FieldType.STRING },
dateid: {
name: "dateid",
type: FieldType.STRING,
},
date: {
name: "date",
type: FieldType.DATETIME,
Expand Down Expand Up @@ -1751,7 +1754,9 @@ if (descriptions.length) {
describe("notEqual", () => {
it("successfully finds a row", async () => {
await expectQuery({
notEqual: { date: `${JAN_1ST}${SEARCH_SUFFIX}` },
notEqual: {
date: `${JAN_1ST}${SEARCH_SUFFIX}`,
},
}).toContainExactly([
{ date: JAN_10TH },
{ dateid: NULL_DATE__ID },
Expand All @@ -1760,7 +1765,9 @@ if (descriptions.length) {

it("fails to find nonexistent row", async () => {
await expectQuery({
notEqual: { date: `${JAN_30TH}${SEARCH_SUFFIX}` },
notEqual: {
date: `${JAN_30TH}${SEARCH_SUFFIX}`,
},
}).toContainExactly([
{ date: JAN_1ST },
{ date: JAN_10TH },
Expand Down Expand Up @@ -1822,6 +1829,60 @@ if (descriptions.length) {
}).toFindNothing()
})
})

describe("sort", () => {
it("sorts ascending", async () => {
await expectSearch({
query: {},
sort: "date",
sortOrder: SortOrder.ASCENDING,
}).toMatchExactly([
{ dateid: NULL_DATE__ID },
{ date: JAN_1ST },
{ date: JAN_10TH },
])
})

it("sorts descending", async () => {
await expectSearch({
query: {},
sort: "date",
sortOrder: SortOrder.DESCENDING,
}).toMatchExactly([
{ date: JAN_10TH },
{ date: JAN_1ST },
{ dateid: NULL_DATE__ID },
])
})

describe("sortType STRING", () => {
it("sorts ascending", async () => {
await expectSearch({
query: {},
sort: "date",
sortType: SortType.STRING,
sortOrder: SortOrder.ASCENDING,
}).toMatchExactly([
{ dateid: NULL_DATE__ID },
{ date: JAN_1ST },
{ date: JAN_10TH },
])
})

it("sorts descending", async () => {
await expectSearch({
query: {},
sort: "date",
sortType: SortType.STRING,
sortOrder: SortOrder.DESCENDING,
}).toMatchExactly([
{ date: JAN_10TH },
{ date: JAN_1ST },
{ dateid: NULL_DATE__ID },
])
})
})
})
}
)
}
Expand Down
30 changes: 21 additions & 9 deletions packages/server/src/utilities/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Table,
} from "@budibase/types"
import { ValidColumnNameRegex, helpers, utils } from "@budibase/shared-core"
import { db } from "@budibase/backend-core"
import { db, HTTPError, sql } from "@budibase/backend-core"

type Rows = Array<Row>

Expand Down Expand Up @@ -175,15 +175,27 @@ export function parse(rows: Rows, table: Table): Rows {
if ([FieldType.NUMBER].includes(columnType)) {
// If provided must be a valid number
parsedRow[columnName] = columnData ? Number(columnData) : columnData
} else if (
columnType === FieldType.DATETIME &&
!columnSchema.timeOnly &&
!columnSchema.dateOnly
) {
// If provided must be a valid date
} else if (columnType === FieldType.DATETIME) {
if (columnData && !columnSchema.timeOnly) {
if (!sql.utils.isValidISODateString(columnData)) {
let message = `Invalid format for field "${columnName}": "${columnData}".`
if (columnSchema.dateOnly) {
message += ` Date-only fields must be in the format "YYYY-MM-DD".`
} else {
message += ` Datetime fields must be in ISO format, e.g. "YYYY-MM-DDTHH:MM:SSZ".`
}
throw new HTTPError(message, 400)
}
}
if (columnData && columnSchema.timeOnly) {
if (!sql.utils.isValidTime(columnData)) {
throw new HTTPError(
`Invalid format for field "${columnName}": "${columnData}". Time-only fields must be in the format "HH:MM:SS".`,
400
)
}
}
parsedRow[columnName] = columnData
? new Date(columnData).toISOString()
: columnData
} else if (
columnType === FieldType.JSON &&
typeof columnData === "string"
Expand Down
Loading