Merge branch 'master' into ts/type-fetchData-usages
This commit is contained in:
commit
40196c6c01
|
@ -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
|
|
||||||
|
|
|
@ -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", () => {
|
||||||
|
|
|
@ -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 },
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue