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

Fix date-only searching. #15337

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

samwho
Copy link
Collaborator

@samwho samwho commented Jan 9, 2025

Description

Bit of a thorny one, this. Mostly affected SQS.

The problem boils down to how we store dates as strings in SQS. The problem is that we haven't been consistent in how we do it: it's possible to save a date as either 2020-01-01 or 2020-01-01T00:00:00Z. It's also possible to search for a date with either format. Because they're strings, despite being semantically identical (if you assume UTC both sides), they do not match.

What I've done is make sure that regardless of whether you search or save the date in either format, you can always find them.

Addresses

Launchcontrol

  • Fixes a problem that caused no rows to be returned when applying filters to date-only fields.

Copy link

linear bot commented Jan 9, 2025

Copy link

qa-wolf bot commented Jan 9, 2025

QA Wolf here! As you write new code it's important that your test coverage is keeping up.
Click here to request test coverage for this PR!

@github-actions github-actions bot added firestorm Data/Infra/Revenue Team size/m labels Jan 9, 2025
Comment on lines +35 to +40
let rootErr = err
while (rootErr.cause) {
rootErr = rootErr.cause
}
// @ts-ignore
error.stack = err.stack
error.stack = rootErr.stack
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was bothering me when tests failed. I only got shown the outermost error, which was never where the real problem was. This makes the error stack traces substantially more useful.

Comment on lines +832 to +838
for (const value of values) {
if (value != null) {
q = q.or.whereLike(key, `${value.toISOString().slice(0, 10)}%`)
} else {
q = q.or.whereNull(key)
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a shame we can't easily use whereIn here. We could, I suppose, if we expanded out, say, 2020-01-01 to ["2020-01-01", "2020-01-01T00:00:00Z"] but that felt more fraught than a bunch of LIKE queries.

return false
}
return d.toISOString() === trimmedValue
return ISO_DATE_REGEX.test(str.trim())
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is used in a single place, and it's where we parse incoming data to be searched on. I want both dates and date time to get parsed into Date objects, so I've modified this function to include anything that looks like 2020-01-01 or 2020-01-01T00:00:00Z.

It stood out to me that the regex we use does not consider any other timezones, not sure how big a deal that is in practice.

@@ -2341,7 +2341,7 @@ if (descriptions.length) {
[FieldType.ARRAY]: ["options 2", "options 4"],
[FieldType.NUMBER]: generator.natural(),
[FieldType.BOOLEAN]: generator.bool(),
[FieldType.DATETIME]: generator.date().toISOString(),
[FieldType.DATETIME]: generator.date().toISOString().slice(0, 10),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For whatever reason in this test we use a datetime field but set dateOnly=true.

Comment on lines +1686 to +1692
describe("datetime - date only", () => {
describe.each([true, false])(
"saved with timestamp: %s",
saveWithTimestamp => {
describe.each([true, false])(
"search with timestamp: %s",
searchWithTimestamp => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep I hate it too, but we're in a position where dates could have been saved into SQS with or without time components, and you can also search with or without a time component. For dateOnly fields, I think the best trade-off is to handle the cross product of all eventualities in the same way: ignore time.

Comment on lines +414 to +422
} else if (column.type === FieldType.DATETIME && column.dateOnly) {
for (const row of rows) {
if (typeof row[property] === "string") {
row[property] = new Date(row[property])
}
if (row[property] instanceof Date) {
row[property] = row[property].toISOString().slice(0, 10)
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used to return date only fields with a timestamp sometimes, in a format that wasn't consistent (depended how each database returned the data, e.g. postgres would do 2020-01-01 +00:00:00). This unifies them all to return 2020-01-01.

Comment on lines +714 to +720
const leftDate = dayjs(docValue)
if (leftDate.isValid()) {
const rightDate = dayjs(testValue)
if (rightDate.isValid()) {
return leftDate.isSame(rightDate)
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to help in-memory search match date-only fields correctly when either side is a date/datetime.

@samwho samwho marked this pull request as ready for review January 9, 2025 17:43
@samwho samwho requested a review from a team as a code owner January 9, 2025 17:43
@samwho samwho requested review from adrinr and removed request for a team January 9, 2025 17:43
Copy link
Collaborator

@mike12345567 mike12345567 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
firestorm Data/Infra/Revenue Team size/m
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants