Merge branch 'master' into ts/type-fetchData-usages

This commit is contained in:
Adria Navarro 2025-01-16 10:58:26 +01:00 committed by GitHub
commit 40196c6c01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 192 additions and 50 deletions

View File

@ -8,41 +8,15 @@ jobs:
stale: stale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/stale@v8 - uses: actions/stale@v8
with: with:
days-before-stale: 330 # Issues
operations-per-run: 1 days-before-stale: 180
# stale rules for PRs stale-issue-label: stale
days-before-pr-stale: 7 days-before-close: 30
stale-issue-label: stale stale-issue-message: "This issue has been automatically marked as stale as there has been no activity for 6 months."
exempt-pr-labels: pinned,security,roadmap # Pull requests
days-before-pr-close: 7 days-before-pr-stale: 7
days-before-issue-close: 30 days-before-pr-close: 14
exempt-pr-labels: pinned,security,roadmap
- uses: actions/stale@v8 operations-per-run: 100
with:
operations-per-run: 3
# stale rules for high priority bugs
days-before-stale: 30
only-issue-labels: bug,High priority
stale-issue-label: warn
days-before-close: 30
- uses: actions/stale@v8
with:
operations-per-run: 3
# stale rules for medium priority bugs
days-before-stale: 90
only-issue-labels: bug,Medium priority
stale-issue-label: warn
days-before-close: 30
- uses: actions/stale@v8
with:
operations-per-run: 3
# stale rules for all bugs
days-before-stale: 180
stale-issue-label: stale
only-issue-labels: bug
stale-issue-message: "This issue has been automatically marked as stale because it has not had any activity for six months."
days-before-close: 30

View File

@ -2043,6 +2043,101 @@ if (descriptions.length) {
expect(rows[0].name).toEqual("Clare updated") expect(rows[0].name).toEqual("Clare updated")
expect(rows[1].name).toEqual("Jeff 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", () => { describe("enrich", () => {

View File

@ -1705,7 +1705,10 @@ if (descriptions.length) {
beforeAll(async () => { beforeAll(async () => {
tableOrViewId = await createTableOrView({ tableOrViewId = await createTableOrView({
dateid: { name: "dateid", type: FieldType.STRING }, dateid: {
name: "dateid",
type: FieldType.STRING,
},
date: { date: {
name: "date", name: "date",
type: FieldType.DATETIME, type: FieldType.DATETIME,
@ -1751,7 +1754,9 @@ if (descriptions.length) {
describe("notEqual", () => { describe("notEqual", () => {
it("successfully finds a row", async () => { it("successfully finds a row", async () => {
await expectQuery({ await expectQuery({
notEqual: { date: `${JAN_1ST}${SEARCH_SUFFIX}` }, notEqual: {
date: `${JAN_1ST}${SEARCH_SUFFIX}`,
},
}).toContainExactly([ }).toContainExactly([
{ date: JAN_10TH }, { date: JAN_10TH },
{ dateid: NULL_DATE__ID }, { dateid: NULL_DATE__ID },
@ -1760,7 +1765,9 @@ if (descriptions.length) {
it("fails to find nonexistent row", async () => { it("fails to find nonexistent row", async () => {
await expectQuery({ await expectQuery({
notEqual: { date: `${JAN_30TH}${SEARCH_SUFFIX}` }, notEqual: {
date: `${JAN_30TH}${SEARCH_SUFFIX}`,
},
}).toContainExactly([ }).toContainExactly([
{ date: JAN_1ST }, { date: JAN_1ST },
{ date: JAN_10TH }, { date: JAN_10TH },
@ -1822,6 +1829,60 @@ if (descriptions.length) {
}).toFindNothing() }).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 },
])
})
})
})
} }
) )
} }

View File

@ -7,7 +7,7 @@ import {
Table, Table,
} from "@budibase/types" } from "@budibase/types"
import { ValidColumnNameRegex, helpers, utils } from "@budibase/shared-core" 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> type Rows = Array<Row>
@ -175,15 +175,27 @@ export function parse(rows: Rows, table: Table): Rows {
if ([FieldType.NUMBER].includes(columnType)) { if ([FieldType.NUMBER].includes(columnType)) {
// If provided must be a valid number // If provided must be a valid number
parsedRow[columnName] = columnData ? Number(columnData) : columnData parsedRow[columnName] = columnData ? Number(columnData) : columnData
} else if ( } else if (columnType === FieldType.DATETIME) {
columnType === FieldType.DATETIME && if (columnData && !columnSchema.timeOnly) {
!columnSchema.timeOnly && if (!sql.utils.isValidISODateString(columnData)) {
!columnSchema.dateOnly let message = `Invalid format for field "${columnName}": "${columnData}".`
) { if (columnSchema.dateOnly) {
// If provided must be a valid date 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 parsedRow[columnName] = columnData
? new Date(columnData).toISOString()
: columnData
} else if ( } else if (
columnType === FieldType.JSON && columnType === FieldType.JSON &&
typeof columnData === "string" typeof columnData === "string"