diff --git a/packages/server/src/sdk/app/rows/tests/utils.spec.ts b/packages/server/src/sdk/app/rows/tests/utils.spec.ts index 7361f7b13c..acd4281256 100644 --- a/packages/server/src/sdk/app/rows/tests/utils.spec.ts +++ b/packages/server/src/sdk/app/rows/tests/utils.spec.ts @@ -183,6 +183,26 @@ describe("validate", () => { time: ["must be no later than 15:00"], }) }) + + describe("range crossing midnight", () => { + const table = getTable() + table.schema.time.constraints = { + presence: true, + datetime: { + earliest: "15:00", + latest: "10:00", + }, + } + + it.each(["10:00", "15:00", `9:${minute()}`, "16:34"])( + "should accept values in range (%s)", + async time => { + const row = { time } + const output = await validate({ table, tableId: table._id!, row }) + expect(output.valid).toBe(true) + } + ) + }) }) }) diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts index 708bd6f503..19e8869494 100644 --- a/packages/server/src/sdk/app/rows/utils.ts +++ b/packages/server/src/sdk/app/rows/utils.ts @@ -227,31 +227,46 @@ function validateTimeOnlyField( res = [`"${fieldName}" is not a valid time`] } else if (constraints) { let castedValue = value - const stringTimeToDateISOString = (value: string) => { + const stringTimeToDate = (value: string) => { const [hour, minute, second] = value.split(":").map((x: string) => +x) let date = dayjs("2000-01-01T00:00:00.000Z").hour(hour).minute(minute) if (!isNaN(second)) { date = date.second(second) } - return date.toISOString() + return date } if (castedValue) { - castedValue = stringTimeToDateISOString(castedValue) + castedValue = stringTimeToDate(castedValue) } let castedConstraints = cloneDeep(constraints) + + let earliest, latest if (castedConstraints.datetime?.earliest) { - castedConstraints.datetime.earliest = stringTimeToDateISOString( - castedConstraints.datetime?.earliest - ) + earliest = stringTimeToDate(castedConstraints.datetime?.earliest) } if (castedConstraints.datetime?.latest) { - castedConstraints.datetime.latest = stringTimeToDateISOString( - castedConstraints.datetime?.latest - ) + latest = stringTimeToDate(castedConstraints.datetime?.latest) } - let jsValidation = validateJs.single(castedValue, castedConstraints) + if (earliest && latest && earliest.isAfter(latest)) { + latest = latest.add(1, "day") + if (earliest.isAfter(castedValue)) { + castedValue = castedValue.add(1, "day") + } + } + + if (earliest || latest) { + castedConstraints.datetime = { + earliest: earliest?.toISOString() || "", + latest: latest?.toISOString() || "", + } + } + + let jsValidation = validateJs.single( + castedValue?.toISOString(), + castedConstraints + ) jsValidation = jsValidation?.map((m: string) => m ?.replace(