Skip to content

Nano does not roundtrip as part of entity  #1304

@NorfairKing

Description

@NorfairKing

Bug Reports

I'm using persistent as part of LTS 16.12 with sqlite.

I have this database definition:

Place sql=place
    query Text -- Address
    lat Nano
    lon Nano

    UniquePlaceQuery query

    deriving Show
    deriving Eq
    deriving Generic

I noticed something really weird when running this in a property test:

                liftIO $ pPrint place
                mPlace <- DB.get placeId
                liftIO $ pPrint mPlace

output

Place
  { placeQuery =
      "\119188\844395\748003\773996\537954\635786\579726\1085648\596327\160180\526694\824331\996801\669722\926453\142441\1050632\260094\410357\477790\829171\521373"
  , placeLat = 6778287944.859847017
  , placeLon = -3037898653.585851994
  }
Just
  Place
    { placeQuery =
        "\119188\844395\748003\773996\537954\635786\579726\1085648\596327\160180\526694\824331\996801\669722\926453\142441\1050632\260094\410357\477790\829171\521373"
    , placeLat = 6778287944.859847068
    , placeLon = -3037898653.585852147
    }

As you can see, the latitude and logitude are different.

I did some digging already. (If you do so, watch out for this issue.)

> 6778287944.859847017 :: Nano
6778287944.859847017 
> fromPersistValue (toPersistValue (6778287944.859847017 :: Nano)) :: Either Text Nano
Right 6778287944.859847017

So far so good, so it looks like the problem is between sqlite and persistent.

Repro script:

#!/usr/bin/env stack
-- stack --resolver lts-16.12 script

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

import Control.Monad
import Control.Monad.IO.Class (liftIO)
import Data.Fixed
import Data.Text (Text)
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import System.Exit
import Text.Show.Pretty (ppShow)

share
  [mkPersist sqlSettings, mkMigrate "migrateAll"]
  [persistLowerCase|

Place sql=place
    lat Nano
    lon Nano

    deriving Show
    deriving Eq
|]

main :: IO ()
main = runSqlite ":memory:" $ do
  runMigration migrateAll

  let expected =
        Place
          { placeLat = 6778287944.859847017,
            placeLon = -3037898653.585851994
          }
  placeId <- insert expected
  mActual <- get placeId
  liftIO $
    forM_ mActual $ \actual ->
      if expected == actual
        then putStrLn "Done!"
        else
          die $
            unlines
              [ "Roundtrip failed.",
                unwords ["expected:", ppShow expected],
                unwords ["actual:  ", ppShow actual]
              ]

Output:

Migrating: CREATE TABLE "place"("id" INTEGER PRIMARY KEY,"lat" NUMERIC(19,9) NOT NULL,"lon" NUMERIC(19,9) NOT NULL)
Roundtrip failed.
expected: Place
  { placeLat = 6778287944.859847017
  , placeLon = -3037898653.585851994
  }
actual:   Place
  { placeLat = 6778287944.859847068
  , placeLon = -3037898653.585852147
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions