yesodweb / yesodweb/persistent

Nano does not roundtrip as part of entity

Open
#1,304 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Haskell
Stars
486
Forks
306
PR merge metrics
No merged PRs in 30d

Description

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
  }

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the supplied Stack reproduction with LTS 16.12 and SQLite, then trace the conversion between the Nano value, SQLite's NUMERIC(19,9) column, and Persistent's retrieved value. Compare the insert and get paths and add a regression test showing that the latitude and longitude roundtrip unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell, sqlite
Domain
database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.