Skip to content

Commit

Permalink
adding default and FromField instance for interval.
Browse files Browse the repository at this point in the history
  • Loading branch information
Montmorency committed Feb 10, 2023
1 parent 12b45ce commit 4c082f5
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 5 deletions.
3 changes: 2 additions & 1 deletion IHP/IDE/SchemaDesigner/Compiler.hs
Expand Up @@ -184,7 +184,8 @@ compilePostgresType PPolygon = "POLYGON"
compilePostgresType PDate = "DATE"
compilePostgresType PBinary = "BYTEA"
compilePostgresType PTime = "TIME"
compilePostgresType PInterval = "INTERVAL"
compilePostgresType (PInterval Nothing) = "INTERVAL"
compilePostgresType (PInterval (Just fields)) = "INTERVAL" <> " " <> fields
compilePostgresType (PNumeric (Just precision) (Just scale)) = "NUMERIC(" <> show precision <> "," <> show scale <> ")"
compilePostgresType (PNumeric (Just precision) Nothing) = "NUMERIC(" <> show precision <> ")"
compilePostgresType (PNumeric Nothing _) = "NUMERIC"
Expand Down
6 changes: 3 additions & 3 deletions IHP/IDE/SchemaDesigner/Parser.hs
Expand Up @@ -350,9 +350,9 @@ sqlType = choice $ map optionalArray

interval = do
try (symbol' "INTERVAL")
optional do
choice $ map symbol' intervalFields
pure PInterval
fields <- optional do
choice $ map symbol' intervalFields
pure (PInterval fields)

numericPS = do
try (symbol' "NUMERIC(")
Expand Down
2 changes: 1 addition & 1 deletion IHP/IDE/SchemaDesigner/Types.hs
Expand Up @@ -211,7 +211,7 @@ data PostgresType
| PDate
| PBinary
| PTime
| PInterval
| PInterval {fields :: Maybe Text}
| PNumeric { precision :: Maybe Int, scale :: Maybe Int }
| PVaryingN (Maybe Int)
| PCharacterN Int
Expand Down
44 changes: 44 additions & 0 deletions IHP/ModelSupport.hs
Expand Up @@ -664,6 +664,9 @@ type family Include' (name :: [GHC.Types.Symbol]) model where
Include' '[] model = model
Include' (x:xs) model = Include' xs (Include x model)

instance Default NominalDiffTime where
def = 0

instance Default TimeOfDay where
def = TimeOfDay 0 0 0

Expand Down Expand Up @@ -883,6 +886,47 @@ instance Exception EnhancedSqlError
instance Default Aeson.Value where
def = Aeson.Null

-- | See https://stackoverflow.com/questions/32398878/converting-postgres-interval-to-haskell-nominaltimediff-with-postgresql-simple
-- To support NominalDiffTime we parse Y year[s] M mon[s] D day[s] [-]HHH:MM:SS.[SSSs]
-- The default is the postgres format.
-- Corresponds to the postgresql interval 6 months see the documentation (https://www.postgresql.org/docs/current/datatype-datetime.html).
instance FromField NominalDiffTime where
fromField f mdat =
if typeOid f /= typoid interval
then returnError Incompatible f ""
else case mdat of
Nothing -> returnError UnexpectedNull f ""
Just dat -> case parseOnly (pNominalDiffTime <* endOfInput) dat of
Left msg -> returnError ConversionFailed f msg
Right t -> return t

pNominalDiffTime :: Parser NominalDiffTime
pNominalDiffTime = do
(years, mons, days) <- pCalTime
(h, m, s) <- pClockTime

let calTime = fromRational . toRational $ (\[y,m,d] -> (365*nominalDay*y 30*nominalDay*m + nominalDay*d) $ map (fromMaybe 0) [years, mons, days]
let clockTime = fromRational . toRational $ s + 60*(fromIntegral m) + 60*60*(fromIntegral h)

pure (calTime + clockTime)

-- | Parse a limited postgres interval of the form [-]HHH:MM:SS.[SSSS] (no larger units than hours).
pCalTime :: Parser (Maybe Int, Maybe Int, Maybe Int)
pCalTime = do
years <- try $ signed decimal <* choice $ map symbol' ["years", "year"]
mons <- try $ signed decimal <* choice $ map symbol' ["mons", "mon"]
days <- try $ signed decimal <* choice $ map symbol' ["days", "day"]
pure (years, mons, days)

-- | Parse a limited postgres interval of the form [-]HHH:MM:SS.[SSSS] (no larger units than hours).
pClockTime :: Parser (Int, Int, Pico)
pClockTime = do
h <- try $ signed decimal <* char ':'
m <- try $ twoDigits <* char ':'
s <- try seconds
if m < 60 && s <= 60
then return (h, m, s)
else fail "invalid interval"

-- | This instancs allows us to avoid wrapping lists with PGArray when
-- using sql types such as @INT[]@
Expand Down
1 change: 1 addition & 0 deletions IHP/SchemaCompiler.hs
Expand Up @@ -68,6 +68,7 @@ atomicType = \case
PDate -> "Data.Time.Calendar.Day"
PBinary -> "(Binary ByteString)"
PTime -> "TimeOfDay"
(PInterval _) -> "NominalDiffTime"
PCustomType theType -> tableNameToModelName theType
PTimestamp -> "LocalTime"
(PNumeric _ _) -> "Scientific"
Expand Down

0 comments on commit 4c082f5

Please sign in to comment.