merge Store into Point
This commit is contained in:
parent
9a9c41a2ba
commit
5032c7408c
10
app/Main.hs
10
app/Main.hs
@ -18,8 +18,8 @@ import Data.Time.Clock (nominalDiffTimeToSeconds)
|
|||||||
import Data.Time.Clock.POSIX (posixSecondsToUTCTime, utcTimeToPOSIXSeconds)
|
import Data.Time.Clock.POSIX (posixSecondsToUTCTime, utcTimeToPOSIXSeconds)
|
||||||
import Database.Persist.Postgresql (ConnectionPool, ConnectionString, SqlBackend, runMigration, runSqlPool, withPostgresqlPool)
|
import Database.Persist.Postgresql (ConnectionPool, ConnectionString, SqlBackend, runMigration, runSqlPool, withPostgresqlPool)
|
||||||
import Debug.Trace (traceShow)
|
import Debug.Trace (traceShow)
|
||||||
|
import Point qualified (fetch, migration, save)
|
||||||
import Session qualified
|
import Session qualified
|
||||||
import Store
|
|
||||||
import Track (parseBS)
|
import Track (parseBS)
|
||||||
import Yesod.Core
|
import Yesod.Core
|
||||||
import Yesod.Form.Fields
|
import Yesod.Form.Fields
|
||||||
@ -118,7 +118,7 @@ getPointsR = do
|
|||||||
<*> ireq intField "duration"
|
<*> ireq intField "duration"
|
||||||
let start' = posixSecondsToUTCTime $ fromInteger $ toInteger $ start tr
|
let start' = posixSecondsToUTCTime $ fromInteger $ toInteger $ start tr
|
||||||
duration' = fromInteger $ toInteger $ duration tr
|
duration' = fromInteger $ toInteger $ duration tr
|
||||||
points <- runDB $ Store.fetch start' duration'
|
points <- runDB $ Point.fetch start' duration'
|
||||||
returnJson (traceShow tr points)
|
returnJson (traceShow tr points)
|
||||||
|
|
||||||
data FileForm = FileForm
|
data FileForm = FileForm
|
||||||
@ -143,7 +143,7 @@ postUploadR = do
|
|||||||
bs <- fileSourceByteString $ fileInfo upload
|
bs <- fileSourceByteString $ fileInfo upload
|
||||||
case Track.parseBS (fromStrict bs) of
|
case Track.parseBS (fromStrict bs) of
|
||||||
Right points -> do
|
Right points -> do
|
||||||
eitherPoints <- runDB $ Store.save points
|
eitherPoints <- runDB $ Point.save points
|
||||||
case eitherPoints of
|
case eitherPoints of
|
||||||
Right points' ->
|
Right points' ->
|
||||||
defaultLayout [whamlet|<p>#{List.length points'} points - thanks!|]
|
defaultLayout [whamlet|<p>#{List.length points'} points - thanks!|]
|
||||||
@ -170,7 +170,7 @@ connStr = "host=127.0.0.1 port=5432 user=souplesse dbname=souplesse password=sec
|
|||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
|
main = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
|
||||||
runResourceT $ flip runSqlPool pool $ do
|
runResourceT $ flip runSqlPool pool $ do
|
||||||
runMigration Session.migrateSession
|
runMigration Session.migration
|
||||||
runMigration migrateTrkpt
|
runMigration Point.migration
|
||||||
static' <- static "frontend"
|
static' <- static "frontend"
|
||||||
warp 3000 $ Souplesse pool static'
|
warp 3000 $ Souplesse pool static'
|
||||||
|
106
lib/Point.hs
106
lib/Point.hs
@ -1,13 +1,31 @@
|
|||||||
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
{-# LANGUAGE DerivingStrategies #-}
|
||||||
|
{-# LANGUAGE EmptyDataDecls #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE GADTs #-}
|
||||||
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
|
{-# LANGUAGE StandaloneDeriving #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
|
||||||
module Point
|
module Point
|
||||||
( Pos (..),
|
( Pos (..),
|
||||||
Point (..),
|
Point (..),
|
||||||
|
save,
|
||||||
|
fetch,
|
||||||
|
migration,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Control.Exception
|
import Control.Exception
|
||||||
|
import Control.Monad.IO.Class (MonadIO, liftIO)
|
||||||
|
import Control.Monad.Trans.Reader (ReaderT)
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.ByteString.Lazy.Char8 qualified as L
|
import Data.ByteString.Lazy.Char8 qualified as L
|
||||||
import Data.Either
|
import Data.Either
|
||||||
@ -15,17 +33,35 @@ import Data.Functor ((<&>))
|
|||||||
import Data.List as List
|
import Data.List as List
|
||||||
import Data.List qualified
|
import Data.List qualified
|
||||||
import Data.Map as Map
|
import Data.Map as Map
|
||||||
import Data.Maybe
|
import Data.Maybe (isJust)
|
||||||
import Data.Text qualified
|
import Data.Text qualified
|
||||||
import Data.Text.Lazy as T
|
import Data.Text.Lazy as T
|
||||||
import Data.Time
|
import Data.Time
|
||||||
|
import Data.Time.Clock (DiffTime, NominalDiffTime, UTCTime, addUTCTime)
|
||||||
import Data.Time.Clock.POSIX (posixSecondsToUTCTime, utcTimeToPOSIXSeconds)
|
import Data.Time.Clock.POSIX (posixSecondsToUTCTime, utcTimeToPOSIXSeconds)
|
||||||
import Data.Time.ISO8601 qualified
|
import Data.Time.ISO8601 qualified
|
||||||
|
import Database.Persist
|
||||||
|
import Database.Persist.Class
|
||||||
|
import Database.Persist.Postgresql
|
||||||
|
( ConnectionString,
|
||||||
|
SqlBackend,
|
||||||
|
createPostgresqlPool,
|
||||||
|
pgConnStr,
|
||||||
|
pgPoolSize,
|
||||||
|
rawExecute,
|
||||||
|
runMigration,
|
||||||
|
runSqlPool,
|
||||||
|
)
|
||||||
|
import Database.Persist.TH
|
||||||
import Debug.Trace (trace, traceShow)
|
import Debug.Trace (trace, traceShow)
|
||||||
|
import Session qualified
|
||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
import Text.XML
|
import Text.XML
|
||||||
import Text.XML.Cursor as Cursor
|
import Text.XML.Cursor as Cursor
|
||||||
|
|
||||||
|
-- import Track (Point (..), Pos (..))
|
||||||
|
-- import Track as T
|
||||||
|
|
||||||
data Pos = Pos Double Double (Maybe Double) deriving (Show, Eq)
|
data Pos = Pos Double Double (Maybe Double) deriving (Show, Eq)
|
||||||
|
|
||||||
type Power = Maybe Int
|
type Power = Maybe Int
|
||||||
@ -58,3 +94,71 @@ instance ToJSON Point where
|
|||||||
"power" .= power,
|
"power" .= power,
|
||||||
"heartRate" .= heartRate
|
"heartRate" .= heartRate
|
||||||
]
|
]
|
||||||
|
|
||||||
|
share
|
||||||
|
[mkPersist sqlSettings, mkMigrate "migration"]
|
||||||
|
[persistLowerCase|
|
||||||
|
Trkpt
|
||||||
|
lat Double
|
||||||
|
lon Double
|
||||||
|
ele Double Maybe
|
||||||
|
time UTCTime
|
||||||
|
cadence Int Maybe
|
||||||
|
power Int Maybe
|
||||||
|
heartRate Int Maybe
|
||||||
|
|]
|
||||||
|
|
||||||
|
fromPoint :: Point -> Trkpt
|
||||||
|
fromPoint p =
|
||||||
|
let Pos lat lon ele = pos p
|
||||||
|
in Trkpt lat lon ele (time p) (cadence p) (power p) (heartRate p)
|
||||||
|
|
||||||
|
toPoint :: Entity Trkpt -> Point
|
||||||
|
toPoint entity =
|
||||||
|
let tkp = (\(Entity _ tkp) -> tkp) entity
|
||||||
|
pos = Pos (trkptLat tkp) (trkptLon tkp) (trkptEle tkp)
|
||||||
|
in Point
|
||||||
|
pos
|
||||||
|
(trkptTime tkp)
|
||||||
|
(trkptCadence tkp)
|
||||||
|
(trkptPower tkp)
|
||||||
|
(trkptHeartRate tkp)
|
||||||
|
|
||||||
|
data OverlapExists = OverlapExists String deriving (Show)
|
||||||
|
|
||||||
|
instance Exception OverlapExists
|
||||||
|
|
||||||
|
fetch :: (MonadIO m) => UTCTime -> NominalDiffTime -> ReaderT SqlBackend m [Point]
|
||||||
|
fetch start duration = do
|
||||||
|
let finish = addUTCTime duration start
|
||||||
|
trkpts <- selectList [TrkptTime >. start, TrkptTime <. finish] []
|
||||||
|
return $ List.map toPoint trkpts
|
||||||
|
|
||||||
|
-- any :: (MonadIO m) => UTCTime -> NominalDiffTime -> ReaderT SqlBackend m Bool
|
||||||
|
any start duration = do
|
||||||
|
let finish = addUTCTime duration start
|
||||||
|
exists <- selectFirst [TrkptTime >. start, TrkptTime <. finish] []
|
||||||
|
return $ isJust exists
|
||||||
|
|
||||||
|
startTime :: [Point] -> UTCTime
|
||||||
|
startTime (p : ps) = List.foldr (\a b -> min b (time a)) (time p) ps
|
||||||
|
|
||||||
|
duration :: [Point] -> NominalDiffTime
|
||||||
|
duration track =
|
||||||
|
case track of
|
||||||
|
[] -> 0
|
||||||
|
(p : ps) ->
|
||||||
|
let start = startTime track
|
||||||
|
finish = List.foldr (\a b -> max b (time a)) (time p) ps
|
||||||
|
in diffUTCTime finish start
|
||||||
|
|
||||||
|
save :: (MonadIO m) => [Point] -> ReaderT SqlBackend m (Either OverlapExists [Point])
|
||||||
|
save track = do
|
||||||
|
let start = startTime track
|
||||||
|
priors <- Point.any start (duration track)
|
||||||
|
if priors
|
||||||
|
then return $ Left (OverlapExists "track overlaps with existing data")
|
||||||
|
else do
|
||||||
|
mapM_ (Database.Persist.Class.insert . fromPoint) track
|
||||||
|
Session.refreshDrafts
|
||||||
|
return $ Right track
|
||||||
|
@ -17,7 +17,7 @@ module Session
|
|||||||
( Session (..),
|
( Session (..),
|
||||||
recents,
|
recents,
|
||||||
refreshDrafts,
|
refreshDrafts,
|
||||||
migrateSession,
|
migration,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ import Database.Persist.TH
|
|||||||
import Text.RawString.QQ (r)
|
import Text.RawString.QQ (r)
|
||||||
|
|
||||||
share
|
share
|
||||||
[mkPersist sqlSettings, mkMigrate "migrateSession"]
|
[mkPersist sqlSettings, mkMigrate "migration"]
|
||||||
[persistLowerCase|
|
[persistLowerCase|
|
||||||
SessionRow sql=session
|
SessionRow sql=session
|
||||||
startTime UTCTime
|
startTime UTCTime
|
||||||
|
99
lib/Store.hs
99
lib/Store.hs
@ -1,99 +0,0 @@
|
|||||||
{-# LANGUAGE DataKinds #-}
|
|
||||||
{-# LANGUAGE DerivingStrategies #-}
|
|
||||||
{-# LANGUAGE EmptyDataDecls #-}
|
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
|
||||||
{-# LANGUAGE GADTs #-}
|
|
||||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
|
||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
{-# LANGUAGE QuasiQuotes #-}
|
|
||||||
{-# LANGUAGE StandaloneDeriving #-}
|
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
|
||||||
{-# LANGUAGE UndecidableInstances #-}
|
|
||||||
|
|
||||||
module Store
|
|
||||||
( save,
|
|
||||||
fetch,
|
|
||||||
migrateTrkpt,
|
|
||||||
module Session,
|
|
||||||
)
|
|
||||||
where
|
|
||||||
|
|
||||||
import Control.Exception
|
|
||||||
import Control.Monad.IO.Class (MonadIO, liftIO)
|
|
||||||
import Control.Monad.Trans.Reader (ReaderT)
|
|
||||||
import Data.Maybe (isJust)
|
|
||||||
import Data.Time.Clock (DiffTime, NominalDiffTime, UTCTime, addUTCTime)
|
|
||||||
import Database.Persist
|
|
||||||
import Database.Persist.Class
|
|
||||||
import Database.Persist.Postgresql
|
|
||||||
( ConnectionString,
|
|
||||||
SqlBackend,
|
|
||||||
createPostgresqlPool,
|
|
||||||
pgConnStr,
|
|
||||||
pgPoolSize,
|
|
||||||
rawExecute,
|
|
||||||
runMigration,
|
|
||||||
runSqlPool,
|
|
||||||
)
|
|
||||||
import Database.Persist.TH
|
|
||||||
import Session qualified
|
|
||||||
import Text.Read (readMaybe)
|
|
||||||
import Track (Point (..), Pos (..))
|
|
||||||
import Track as T
|
|
||||||
|
|
||||||
connString :: ConnectionString
|
|
||||||
connString = "host=127.0.0.1 port=5432 user=souplesse dbname=souplesse password=secret"
|
|
||||||
|
|
||||||
share
|
|
||||||
[mkPersist sqlSettings, mkMigrate "migrateTrkpt"]
|
|
||||||
[persistLowerCase|
|
|
||||||
Trkpt
|
|
||||||
lat Double
|
|
||||||
lon Double
|
|
||||||
ele Double Maybe
|
|
||||||
time UTCTime
|
|
||||||
cadence Int Maybe
|
|
||||||
power Int Maybe
|
|
||||||
heartRate Int Maybe
|
|
||||||
|]
|
|
||||||
|
|
||||||
fromPoint :: Point -> Trkpt
|
|
||||||
fromPoint p =
|
|
||||||
let Pos lat lon ele = T.pos p
|
|
||||||
in Trkpt lat lon ele (T.time p) (T.cadence p) (T.power p) (T.heartRate p)
|
|
||||||
|
|
||||||
toPoint :: Entity Trkpt -> Point
|
|
||||||
toPoint entity =
|
|
||||||
let tkp = (\(Entity _ tkp) -> tkp) entity
|
|
||||||
pos = Pos (trkptLat tkp) (trkptLon tkp) (trkptEle tkp)
|
|
||||||
in Point
|
|
||||||
pos
|
|
||||||
(trkptTime tkp)
|
|
||||||
(trkptCadence tkp)
|
|
||||||
(trkptPower tkp)
|
|
||||||
(trkptHeartRate tkp)
|
|
||||||
|
|
||||||
data OverlapExists = OverlapExists String deriving (Show)
|
|
||||||
|
|
||||||
instance Exception OverlapExists
|
|
||||||
|
|
||||||
save :: (MonadIO m) => Track -> ReaderT SqlBackend m (Either OverlapExists Track)
|
|
||||||
save track = do
|
|
||||||
let start = T.startTime track
|
|
||||||
finish = addUTCTime (T.duration track) (T.startTime track)
|
|
||||||
priors <- selectFirst [TrkptTime >. start, TrkptTime <. finish] []
|
|
||||||
if isJust priors
|
|
||||||
then return $ Left (OverlapExists "track overlaps with existing data")
|
|
||||||
else do
|
|
||||||
mapM_ (insert . fromPoint) track
|
|
||||||
Session.refreshDrafts
|
|
||||||
return $ Right track
|
|
||||||
|
|
||||||
fetch :: (MonadIO m) => UTCTime -> NominalDiffTime -> ReaderT SqlBackend m [Point]
|
|
||||||
fetch start duration = do
|
|
||||||
let finish = addUTCTime duration start
|
|
||||||
trkpts <- selectList [TrkptTime >. start, TrkptTime <. finish] []
|
|
||||||
return $ map toPoint trkpts
|
|
14
lib/Track.hs
14
lib/Track.hs
@ -8,8 +8,6 @@ module Track
|
|||||||
parseFile,
|
parseFile,
|
||||||
parseBS,
|
parseBS,
|
||||||
Track.length,
|
Track.length,
|
||||||
startTime,
|
|
||||||
duration,
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@ -97,18 +95,6 @@ parse str = do
|
|||||||
length :: Track -> Int
|
length :: Track -> Int
|
||||||
length = Data.List.length
|
length = Data.List.length
|
||||||
|
|
||||||
startTime :: Track -> UTCTime
|
|
||||||
startTime (p : ps) = List.foldr (\a b -> min b (time a)) (time p) ps
|
|
||||||
|
|
||||||
duration :: Track -> NominalDiffTime
|
|
||||||
duration track =
|
|
||||||
case track of
|
|
||||||
[] -> 0
|
|
||||||
(p : ps) ->
|
|
||||||
let start = startTime track
|
|
||||||
finish = List.foldr (\a b -> max b (time a)) (time p) ps
|
|
||||||
in diffUTCTime finish start
|
|
||||||
|
|
||||||
-- parseFile :: FilePath -> IO [Point]
|
-- parseFile :: FilePath -> IO [Point]
|
||||||
parseFile name = do
|
parseFile name = do
|
||||||
gpx <- Text.XML.readFile def name
|
gpx <- Text.XML.readFile def name
|
||||||
|
@ -97,7 +97,6 @@ executable souplesse
|
|||||||
library souplesse-lib
|
library souplesse-lib
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
Track
|
Track
|
||||||
Store
|
|
||||||
Point
|
Point
|
||||||
Session
|
Session
|
||||||
hs-source-dirs:
|
hs-source-dirs:
|
||||||
|
Loading…
Reference in New Issue
Block a user