beam icon indicating copy to clipboard operation
beam copied to clipboard

beam-sqlite fails to encode/decode some UTCTime values

Open thomasjm opened this issue 4 years ago • 3 comments

When I try to store and retrieve a UTCTime representing the year 1, I get a decoding error.

time = UTCTime (fromGregorian 1 0 0) (secondsToDiffTime 0)

The error is BeamRowReadError {brreColumn = Just 5, brreError = ColumnTypeMismatch {ctmHaskellType = "UTCTime", ctmSQLType = "TEXT", ctmMessage = "conversion failed: couldn't parse UTCTime field: Failed reading: year must consist of at least 4 digits"}}.

I think this is because the time is getting encoded like this: 1-01-01T00:00:00.

I've added a failing test to beam-sqlite, I'll open a separate PR with it.

thomasjm avatar Mar 05 '21 12:03 thomasjm

beam-sqlite re-uses the parsers from sqlite-simple. My suggestion for this particular use case, since this is ultimately a non-standard format for dates, is to define

newtype MyTime = MyTime UTCTime
  deriving (Generic)
deriving newtype instance HasSqlValueSyntax syntax UTCTime => HasSqlValueSyntax syntax MyTime
instance FromBackendRow be Text => FromBackendRow be MyTime where
   fromBackendRow = mySpecialFunctionToParseTimes =<< fromBackendRow
mySpecialFunctionToParseTimes :: MonadFail m => Text -> m MyTime

As it is, I don't want to special-case parsing in Beam over whatever sqlite-simple does. IMO, this follows the principle of least surprise for users coming to beam from these libraries. Especially with dates, 01 could mean 2001 or 1901.

tathougies avatar Mar 08 '21 21:03 tathougies

beam-sqlite re-uses the parsers from sqlite-simple

I just dug into this a little more, I think the issue is that the encoding part is done by beam-sqlite in a weird way:

https://github.com/haskell-beam/beam/blob/master/beam-sqlite/Database/Beam/Sqlite/Syntax.hs#L951-L953

In the HasSqlValueSyntax instance, beam-sqlite is using its own date format string rather that sqlite-simple's ToField instance.

I updated my PR to use the toField function and it fixes the failing test: https://github.com/haskell-beam/beam/pull/554/commits/877a1b51846609b9b7a4509a7a55ba2b2ae069ce. What do you think? I think a couple other types like Day would also benefit from the same change.

thomasjm avatar Apr 16 '21 16:04 thomasjm

@tathougies Was there some reason originally not to use the sqlite-simple serializations? Wondering if there's some implication I'm missing, otherwise I think we should change this.

kmicklas avatar Jun 18 '21 00:06 kmicklas

Hey @tathougies or @kmicklas, could we merge my fix for this? I'd love to stop maintaining my own fork of Beam that I have to use due to this. AFAIK it's a straightforward bug and the PR (#554) fixes it nicely.

thomasjm avatar Nov 05 '22 05:11 thomasjm

@kmicklas I recall at some point I switched from the sqlite-simple serializations, because there were some cases it did not cover. As for PR 554... I can merge it, unless there are any objections.

tathougies avatar Nov 06 '22 03:11 tathougies

FWIW I dug through git history and I don't see it ever being switched -- it seems it was added here.

I'd be interested in what cases sqlite-simple doesn't cover -- it looks to me like the code over there is more careful to be compliant with SQLite's requirements. For example, it is careful to pad the year to 4 digits which the current code doesn't do and which causes this issue.

For the same reason, I think beam should really make the same change for the Day type, which sqlite-simple also handles more carefully. I think LocalTime has the same problem too, although sqlite-simple doesn't have an instance for that type yet.

thomasjm avatar Nov 06 '22 07:11 thomasjm

@kmicklas could you chime in? This seems like a clear win and I've love to get it merged :)

thomasjm avatar Nov 14 '22 21:11 thomasjm

I think we can merge this PR. Maybe Ken has thoughts.

tathougies avatar Nov 15 '22 03:11 tathougies

Ken already indicated support above in June 2021. Let's merge!

I just rebased on master and the tests pass, so it should be ready to go.

thomasjm avatar Nov 16 '22 23:11 thomasjm

Thanks for the contribution @thomasjm!

kmicklas avatar Nov 20 '22 18:11 kmicklas