Handling invalid time values when ISO strings are input as filter options.
This commit is contained in:
parent
8118a55f1b
commit
77abe6da83
|
@ -13,6 +13,7 @@ import {
|
|||
isDocument,
|
||||
RowResponse,
|
||||
RowValue,
|
||||
SqlClient,
|
||||
SQLiteDefinition,
|
||||
SqlQueryBinding,
|
||||
} from "@budibase/types"
|
||||
|
@ -25,6 +26,7 @@ import { SQLITE_DESIGN_DOC_ID } from "../../constants"
|
|||
import { DDInstrumentedDatabase } from "../instrumentation"
|
||||
import { checkSlashesInUrl } from "../../helpers"
|
||||
import env from "../../environment"
|
||||
import { sqlLog } from "../../sql/utils"
|
||||
|
||||
const DATABASE_NOT_FOUND = "Database does not exist."
|
||||
|
||||
|
@ -322,6 +324,7 @@ export class DatabaseImpl implements Database {
|
|||
): Promise<T[]> {
|
||||
const dbName = this.name
|
||||
const url = `/${dbName}/${SQLITE_DESIGN_DOC_ID}`
|
||||
sqlLog(SqlClient.SQL_LITE, sql, parameters)
|
||||
return await this._sqlQuery<T[]>(url, "POST", {
|
||||
query: sql,
|
||||
args: parameters,
|
||||
|
|
|
@ -3,8 +3,10 @@ import * as dbCore from "../db"
|
|||
import {
|
||||
getNativeSql,
|
||||
isExternalTable,
|
||||
isIsoDateString,
|
||||
isValidISODateString,
|
||||
isValidFilter,
|
||||
sqlLog,
|
||||
isInvalidISODateString,
|
||||
} from "./utils"
|
||||
import { SqlStatements } from "./sqlStatements"
|
||||
import SqlTableQueryBuilder from "./sqlTable"
|
||||
|
@ -38,10 +40,6 @@ const envLimit = environment.SQL_MAX_ROWS
|
|||
: null
|
||||
const BASE_LIMIT = envLimit || 5000
|
||||
|
||||
// these are invalid dates sent by the client, need to convert them to a real max date
|
||||
const MIN_ISO_DATE = "0000-00-00T00:00:00.000Z"
|
||||
const MAX_ISO_DATE = "9999-00-00T00:00:00.000Z"
|
||||
|
||||
function likeKey(client: string, key: string): string {
|
||||
let start: string, end: string
|
||||
switch (client) {
|
||||
|
@ -75,10 +73,10 @@ function parse(input: any) {
|
|||
if (typeof input !== "string") {
|
||||
return input
|
||||
}
|
||||
if (input === MAX_ISO_DATE || input === MIN_ISO_DATE) {
|
||||
if (isInvalidISODateString(input)) {
|
||||
return null
|
||||
}
|
||||
if (isIsoDateString(input)) {
|
||||
if (isValidISODateString(input)) {
|
||||
return new Date(input.trim())
|
||||
}
|
||||
return input
|
||||
|
@ -938,15 +936,7 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
|
|||
}
|
||||
|
||||
log(query: string, values?: SqlQueryBinding) {
|
||||
if (!environment.SQL_LOGGING_ENABLE) {
|
||||
return
|
||||
}
|
||||
const sqlClient = this.getSqlClient()
|
||||
let string = `[SQL] [${sqlClient.toUpperCase()}] query="${query}"`
|
||||
if (values) {
|
||||
string += ` values="${values.join(", ")}"`
|
||||
}
|
||||
console.log(string)
|
||||
sqlLog(this.getSqlClient(), query, values)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,12 @@ import { DocumentType, SqlQuery, Table, TableSourceType } from "@budibase/types"
|
|||
import { DEFAULT_BB_DATASOURCE_ID } from "../constants"
|
||||
import { Knex } from "knex"
|
||||
import { SEPARATOR } from "../db"
|
||||
import environment from "../environment"
|
||||
|
||||
const DOUBLE_SEPARATOR = `${SEPARATOR}${SEPARATOR}`
|
||||
const ROW_ID_REGEX = /^\[.*]$/g
|
||||
const ENCODED_SPACE = encodeURIComponent(" ")
|
||||
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/
|
||||
|
||||
export function isExternalTableID(tableId: string) {
|
||||
return tableId.startsWith(DocumentType.DATASOURCE + SEPARATOR)
|
||||
|
@ -120,15 +122,38 @@ export function breakRowIdField(_id: string | { _id: string }): any[] {
|
|||
}
|
||||
}
|
||||
|
||||
export function isIsoDateString(str: string) {
|
||||
export function isInvalidISODateString(str: string) {
|
||||
const trimmedValue = str.trim()
|
||||
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(trimmedValue)) {
|
||||
if (!ISO_DATE_REGEX.test(trimmedValue)) {
|
||||
return false
|
||||
}
|
||||
let d = new Date(trimmedValue)
|
||||
return isNaN(d.getTime())
|
||||
}
|
||||
|
||||
export function isValidISODateString(str: string) {
|
||||
const trimmedValue = str.trim()
|
||||
if (!ISO_DATE_REGEX.test(trimmedValue)) {
|
||||
return false
|
||||
}
|
||||
let d = new Date(trimmedValue)
|
||||
if (isNaN(d.getTime())) {
|
||||
return false
|
||||
}
|
||||
return d.toISOString() === trimmedValue
|
||||
}
|
||||
|
||||
export function isValidFilter(value: any) {
|
||||
return value != null && value !== ""
|
||||
}
|
||||
|
||||
export function sqlLog(client: string, query: string, values?: any[]) {
|
||||
if (!environment.SQL_LOGGING_ENABLE) {
|
||||
return
|
||||
}
|
||||
let string = `[SQL] [${client.toUpperCase()}] query="${query}"`
|
||||
if (values) {
|
||||
string += ` values="${values.join(", ")}"`
|
||||
}
|
||||
console.log(string)
|
||||
}
|
||||
|
|
|
@ -2167,6 +2167,35 @@ describe.each([
|
|||
}
|
||||
)
|
||||
|
||||
describe.each([
|
||||
{ low: "2024-07-03T00:00:00.000Z", high: "9999-00-00T00:00:00.000Z" },
|
||||
{ low: "2024-07-03T00:00:00.000Z", high: "9998-00-00T00:00:00.000Z" },
|
||||
{ low: "0000-00-00T00:00:00.000Z", high: "2024-07-04T00:00:00.000Z" },
|
||||
{ low: "0001-00-00T00:00:00.000Z", high: "2024-07-04T00:00:00.000Z" },
|
||||
])("date special cases", ({ low, high }) => {
|
||||
const earlyDate = "2024-07-03T10:00:00.000Z",
|
||||
laterDate = "2024-07-03T11:00:00.000Z"
|
||||
beforeAll(async () => {
|
||||
table = await createTable({
|
||||
date: {
|
||||
name: "date",
|
||||
type: FieldType.DATETIME,
|
||||
},
|
||||
})
|
||||
await createRows([{ date: earlyDate }, { date: laterDate }])
|
||||
})
|
||||
|
||||
it("should be able to handle a date search", async () => {
|
||||
await expectSearch({
|
||||
query: {
|
||||
range: {
|
||||
"1:date": { low, high },
|
||||
},
|
||||
},
|
||||
}).toContainExactly([{ date: earlyDate }, { date: laterDate }])
|
||||
})
|
||||
})
|
||||
|
||||
describe.each([
|
||||
"名前", // Japanese for "name"
|
||||
"Benutzer-ID", // German for "user ID", includes a hyphen
|
||||
|
|
Loading…
Reference in New Issue