Skip to content

Commit ddae86b

Browse files
Refactor numeric tests
1 parent da8150e commit ddae86b

File tree

5 files changed

+47
-39
lines changed

5 files changed

+47
-39
lines changed

postgres-wire.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ test-suite postgres-wire-test
9999
, tasty-hunit
100100
, tasty-quickcheck
101101
, QuickCheck >= 2.9
102+
, scientific
103+
, time
104+
, uuid
102105
, tagged
103106
ghc-options: -threaded -rtsopts -with-rtsopts=-N
104107
default-language: Haskell2010

src/Database/PostgreSQL/Protocol/Codecs/Decoders.hs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import Database.PostgreSQL.Protocol.Codecs.Numeric
2424
-- 2 bytes - count of columns in the DataRow
2525
{-# INLINE dataRowHeader #-}
2626
dataRowHeader :: Decode ()
27-
dataRowHeader = skipBytes 7
27+
dataRowHeader = skipBytes 7
2828

2929
{-# INLINE fieldLength #-}
3030
fieldLength :: Decode Int
@@ -73,13 +73,13 @@ arrayDimensions dims = V.reverse <$> V.replicateM dims arrayDimSize
7373
arrayFieldDecoder :: Int -> (V.Vector Int -> Decode a) -> FieldDecoder a
7474
arrayFieldDecoder dims f _ = arrayHeader *> arrayDimensions dims >>= f
7575

76-
-- | Decodes only a content of the field.
77-
type FieldDecoder a = Int -> Decode a
78-
7976
--
8077
-- Primitives
8178
--
8279

80+
-- | Decodes only a content of the field.
81+
type FieldDecoder a = Int -> Decode a
82+
8383
{-# INLINE bool #-}
8484
bool :: FieldDecoder Bool
8585
bool _ = (== 1) <$> getWord8
@@ -134,9 +134,9 @@ bsJsonBytes len = getWord8 *> getByteString (len - 1)
134134
numeric :: FieldDecoder Scientific
135135
numeric _ = do
136136
ndigits <- getWord16BE
137-
weight <- getInt16BE
138-
sign <- getWord16BE >>= fromNumericSign
139-
_ <- getWord16BE
137+
weight <- getInt16BE
138+
sign <- fromNumericSign =<< getWord16BE
139+
_ <- getWord16BE
140140
numericToScientific sign weight <$>
141141
replicateM (fromIntegral ndigits) getWord16BE
142142

src/Database/PostgreSQL/Protocol/Codecs/Encoders.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Database.PostgreSQL.Protocol.Store.Encode
1616
import Database.PostgreSQL.Protocol.Types
1717
import Database.PostgreSQL.Protocol.Codecs.Time
1818
import Database.PostgreSQL.Protocol.Codecs.Numeric
19+
1920
--
2021
-- Primitives
2122
--
@@ -59,7 +60,7 @@ int8 = putInt64BE
5960

6061
{-# INLINE interval #-}
6162
interval :: DiffTime -> Encode
62-
interval v = let (mcs, days, months) = diffTimeToInterval v
63+
interval v = let (mcs, days, months) = diffTimeToInterval v
6364
in putInt64BE mcs <> putInt32BE days <> putInt32BE months
6465

6566
-- | Encodes representation of JSON as @ByteString@.
Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,14 @@
11
{-# language LambdaCase #-}
2-
module Database.PostgreSQL.Protocol.Codecs.Numeric where
3-
4-
-- TODO test it
5-
import Data.Tuple
6-
import Data.Word
7-
import Data.Int
8-
import Data.Foldable
9-
import Data.Scientific
10-
import Data.List (unfoldr)
112

12-
integerToDigits :: Integer -> [Word16]
13-
integerToDigits = (reverse.) . unfoldr $ \case
14-
0 -> Nothing
15-
n -> let (rest, rem) = n `divMod` nBase in Just (fromIntegral rem, rest)
3+
module Database.PostgreSQL.Protocol.Codecs.Numeric where
164

17-
toNumericSign :: Scientific -> Word16
18-
toNumericSign s | s >= 0 = 0x0000
19-
| otherwise = 0x4000
5+
import Data.Word (Word16)
6+
import Data.Int (Int16)
7+
import Data.Foldable (foldl')
8+
import Data.Scientific (Scientific, scientific, base10Exponent, coefficient)
9+
import Data.List (unfoldr)
2010

11+
{-# INLINE scientificToNumeric #-}
2112
scientificToNumeric :: Scientific -> (Int16, Word16, [Word16])
2213
scientificToNumeric number =
2314
let a = base10Exponent number `mod` nBaseDigits
@@ -28,24 +19,40 @@ scientificToNumeric number =
2819
scale = fromIntegral . negate $ min (base10Exponent number) 0
2920
in (weight, scale, digits)
3021

31-
digitsToInteger :: [Word16] -> Integer
32-
digitsToInteger = foldl' (\acc n -> acc * nBase + fromIntegral n) 0
22+
{-# INLINE numericToScientific #-}
23+
numericToScientific :: Integer -> Int16 -> [Word16] -> Scientific
24+
numericToScientific sign weight digits =
25+
let coef = digitsToInteger digits * sign
26+
exp' = (fromIntegral weight + 1 - length digits) * nBaseDigits
27+
in scientific coef exp'
3328

29+
{-# INLINE toNumericSign #-}
30+
toNumericSign :: Scientific -> Word16
31+
toNumericSign s | s >= 0 = 0x0000
32+
| otherwise = 0x4000
33+
34+
{-# INLINE fromNumericSign #-}
3435
fromNumericSign :: (Monad m, Num a) => Word16 -> m a
3536
fromNumericSign 0x0000 = pure 1
3637
fromNumericSign 0x4000 = pure $ -1
3738
-- NaN code is 0xC000, it is not supported.
3839
fromNumericSign _ = fail "Unknown numeric sign"
3940

40-
numericToScientific :: Integer -> Int16 -> [Word16] -> Scientific
41-
numericToScientific sign weight digits =
42-
let coef = digitsToInteger digits * sign
43-
exp' = (fromIntegral weight + 1 - length digits) * nBaseDigits
44-
in scientific coef exp'
41+
{-# INLINE integerToDigits #-}
42+
integerToDigits :: Integer -> [Word16]
43+
integerToDigits = (reverse.) . unfoldr $ \case
44+
0 -> Nothing
45+
n -> let (rest, rem) = n `divMod` nBase in Just (fromIntegral rem, rest)
46+
47+
{-# INLINE digitsToInteger #-}
48+
digitsToInteger :: [Word16] -> Integer
49+
digitsToInteger = foldl' (\acc n -> acc * nBase + fromIntegral n) 0
4550

51+
{-# INLINE nBase #-}
4652
nBase :: Num a => a
4753
nBase = 10000
4854

55+
{-# INLINE nBaseDigits #-}
4956
nBaseDigits :: Num a => a
5057
nBaseDigits = 4
5158

tests/Codecs/QuickCheck.hs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ makeCodecEncodeProperty c oid queryString encoder fPrint v = monadicIO $ do
6565
sendBatchAndSync c [q]
6666
dr <- readNextData c
6767
waitReadyForQuery c
68-
r <- either (error . show) (pure . BC.unpack . decodeOneRow decoder) dr
69-
-- print $ fPrint v <> " " <> r
70-
pure r
68+
either (error . show) (pure . BC.unpack . decodeOneRow decoder) dr
7169

7270
assertQCEqual (fPrint v) r
7371

@@ -96,7 +94,7 @@ mkCodecEncodeTest name oids queryString encoder fPrint =
9694

9795
testCodecsEncodeDecode :: TestTree
9896
testCodecsEncodeDecode = testGroup "Codecs property 'encode . decode = id'"
99-
[ {-mkCodecTest "bool" PGT.bool PE.bool PD.bool
97+
[ mkCodecTest "bool" PGT.bool PE.bool PD.bool
10098
, mkCodecTest "bytea" PGT.bytea PE.bytea PD.bytea
10199
, mkCodecTest "char" PGT.char PE.char PD.char
102100
, mkCodecTest "date" PGT.date PE.date PD.date
@@ -110,12 +108,11 @@ testCodecsEncodeDecode = testGroup "Codecs property 'encode . decode = id'"
110108
(fmap JsonString <$> PD.bsJsonText)
111109
, mkCodecTest "jsonb" PGT.jsonb (PE.bsJsonBytes .unJsonString)
112110
(fmap JsonString <$> PD.bsJsonBytes)
113-
-- TODO
114-
, -}mkCodecTest "numeric" PGT.numeric PE.numeric PD.numeric
115-
{-, mkCodecTest "text" PGT.text PE.bsText PD.bsText
111+
, mkCodecTest "numeric" PGT.numeric PE.numeric PD.numeric
112+
, mkCodecTest "text" PGT.text PE.bsText PD.bsText
116113
, mkCodecTest "timestamp" PGT.timestamp PE.timestamp PD.timestamp
117114
, mkCodecTest "timestamptz" PGT.timestamptz PE.timestamptz PD.timestamptz
118-
, mkCodecTest "uuid" PGT.uuid PE.uuid PD.uuid-}
115+
, mkCodecTest "uuid" PGT.uuid PE.uuid PD.uuid
119116
]
120117

121118
testCodecsEncodePrint :: TestTree

0 commit comments

Comments
 (0)