-
Notifications
You must be signed in to change notification settings - Fork 2
feat: Support encoding and decoding of non-moment date objects #78
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
Conversation
706b3ac
to
69981a7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a first pass on the code
source/session.ts
Outdated
@@ -307,7 +306,8 @@ export class Session { | |||
return out; | |||
} | |||
|
|||
if (data && data._isAMomentObject) { | |||
const date = convertToISOString(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we try to convert all strings and numbers, or should we separate checking for date-like objects and encoding to iso string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean by this comment. currently we support converting all date objects, including moment and dayjs that have toISOString
method - as well as converting ISO 8601 compatible strings to UTC. Do you want to split strings and number cases from object cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, the question was if we should do:
if (isDateLike(data)) {
data = convertToISOString(data)
}
Rather than:
date = convertToISOString(data)
if (date) {
data = date;
}
I am not convinced that we should. I just thought it looked odd to try converting all types (except arrays and pojo:s already handled).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind either way, so let me know if you want me to change it
source/util/convert_to_iso_string.ts
Outdated
@@ -0,0 +1,20 @@ | |||
function isIsoDate(str: string) { | |||
if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also encode strings in a non-UTC timezone?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we're encoding strings in a non-utc timezone, e.g. 2023-01-01T01:00:00+01:00
, and converting to UTC. see tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous regex wasn't matching them - now it looks better.
// if this is a date object of type moment or dayjs, or regular date object (all of them has toISOString) | ||
((typeof data !== "string" && typeof data.toISOString === "function") || | ||
// if it's a ISO string already | ||
(typeof data == "string" && isIsoDate(data))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we encode already formatted strings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we support non-UTC timezones, while the server doesn't. this is to make sure they are in UTC format, since toISOString
always return UTC format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking, do we have a use case to supporting these? It seems like you have to jump through a few hoops to format dates like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing that I'm aware of, I thought it was better to support encoding all ISO8601 compatible strings than just a subset of them.
}; | ||
} | ||
|
||
// Ensure that the moment object is in local time zone and format | ||
// to timezone naive string. | ||
return { | ||
__type__: "datetime", | ||
value: data.local().format(ENCODE_DATETIME_FORMAT), | ||
value: moment(date).local().format(ENCODE_DATETIME_FORMAT), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we target the v2
for these changes as well? I am not really sure how to test this for regressions, so feels safer to do this while also removing this branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i have intentionally separated code for this PR to be backwards compatible by making sure all moment objects are passed in the same manner as before, so I hope we can target this for a minor release. we can add additional tests for this if there are certain use cases you are unsure about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to ensure that this path hasn't changed, without having to disable timezone support locally.
Can we add a test for:
const date = moment()
const convertedDate = convertToISOString(date)
const encodedDate = moment(date).local().format(ENCODE_DATETIME_FORMAT)
assert date.local().format(ENCODE_DATETIME_FORMAT) === encodedDate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please see new tests!
source/session.ts
Outdated
// need to strip from query. | ||
value = moment(value).utc().format(ENCODE_DATETIME_FORMAT); | ||
} else if (convertToISOString(value)) { | ||
value = convertToISOString(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the comment not true?
// Server does not store microsecond or timezone currently so
// need to strip from query.
These will be translated to a SQL comparison, so I think we need to strip to match how the dates are stored in the database.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's true that the server currently does not store microseconds, but I believe it's better to allow sending in all ISO8691 validated strings and convert them to whatever is supported in the server (as it currently works), than removing microseconds in the client.
server does store timezones in a way by only supporting UTC timezone, and we are thus converting to UTC dates always.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried testing this manually, and it does look like it works, though I am not sure why.. both of these return the expected Note.
select id from Note where thread_activity is "2023-02-20 09:58:01"
select id from Note where thread_activity is "2023-02-20T09:58:01.102Z"
Having a date-times as identifyingKey
doesn't make much sense, but I assume we should continue to support it. As long as it does, I am happy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the server encode all dates to a precision the database handles, which means that it strips the milliseconds (and timezone) from the string, which is why it is backwards compatible.
if the server API one day start supporting milliseconds granularity, this query will stop working yes, but that would be a breaking change from the server API anyway.
source/session.ts
Outdated
// need to strip from query. | ||
value = moment(value).utc().format(ENCODE_DATETIME_FORMAT); | ||
} else if (convertToISOString(value)) { | ||
value = convertToISOString(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried testing this manually, and it does look like it works, though I am not sure why.. both of these return the expected Note.
select id from Note where thread_activity is "2023-02-20 09:58:01"
select id from Note where thread_activity is "2023-02-20T09:58:01.102Z"
Having a date-times as identifyingKey
doesn't make much sense, but I assume we should continue to support it. As long as it does, I am happy.
source/session.ts
Outdated
@@ -307,7 +306,8 @@ export class Session { | |||
return out; | |||
} | |||
|
|||
if (data && data._isAMomentObject) { | |||
const date = convertToISOString(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, the question was if we should do:
if (isDateLike(data)) {
data = convertToISOString(data)
}
Rather than:
date = convertToISOString(data)
if (date) {
data = date;
}
I am not convinced that we should. I just thought it looked odd to try converting all types (except arrays and pojo:s already handled).
}; | ||
} | ||
|
||
// Ensure that the moment object is in local time zone and format | ||
// to timezone naive string. | ||
return { | ||
__type__: "datetime", | ||
value: data.local().format(ENCODE_DATETIME_FORMAT), | ||
value: moment(date).local().format(ENCODE_DATETIME_FORMAT), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to ensure that this path hasn't changed, without having to disable timezone support locally.
Can we add a test for:
const date = moment()
const convertedDate = convertToISOString(date)
const encodedDate = moment(date).local().format(ENCODE_DATETIME_FORMAT)
assert date.local().format(ENCODE_DATETIME_FORMAT) === encodedDate
069e987
to
e401e39
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good and working as intended. Consider if we should rename ISO
to Iso
for consistency.
@@ -96,18 +96,20 @@ export interface ResponseError { | |||
error?: Data; | |||
} | |||
|
|||
export interface MutatationOptions { | |||
export interface MutationOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤓 🏅
source/session.ts
Outdated
private decode( | ||
data: any, | ||
identityMap: Data = {}, | ||
decodeDatesAsISO: boolean = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was bout to comment that we could make the third argument a decodeOptions
to future-proof if we have a need for more options, but seeing as this is assumed to be private - I don't think it matters.
* feat: support encoding non-moment date objects * add tests for convert_to_iso_string * added docstring * add additional encoding tests * support non-moment decoding * non-UTC timezone for tests in CI * consistent camel casing
Resolves FT-bc5b3fba-b1ca-11ed-ba1e-a2da51ff8a88
Changes
As part of easing migration from moment, as described in #71 , we start by supporting encoding of non-moment date objects. This includes all date libraries that have
toISOString
as a method on their date objects, as well as nativeDate
library, and also an ISO6801 compatible string.Test
Make sure encoding all these date formats work as expected.