Lenses, sqlite-simple
[?]
Dec 15, 2014, 5:37 AM
TLQ72DSJD7GGPWN6HGBHAVPBRQFKEQ6KSK43U7JWWID4ZWAF47JACDependencies
- [2]
MXLZBRQNTrickle. - [3]
LUM4VQJIIncrement. - [4]
FRPWIKCNAdded log event parsing to Quixotic.Database.SQLite - [5]
A2J7B4SCInitial impl of depreciation function. - [6]
NVOCQVASInitial failing tests. - [7]
P6NR2CGXBeginning of implementation of depreciation. - [8]
64C6AWH6Rename Ananke -> Quixotic, project reboot. - [9]
2OIPAQCBMerge branch 'master' of github.com:nuttycom/ananke - [10]
7DBNV3GVInitial, stack-based impl of time log event reduction. - [11]
64VI73NPServer now compiles using abstracted SQLite - [12]
5W5M56VJMove library code to 'lib' - [13]
RSEB2NFGReplacing Snap with Scotty. - [14]
JUUMYIQEAdd groupBy utility function for use in TimeLog. - [15]
LAROLAYUWIP - [16]
WFZDMVUXRename ADB -> QDB - [17]
75N3UJ4JMore progression toward lenses. - [18]
MWUPXTBFA few steps down a road to be abandoned. - [19]
N4NDAZYTInitial implementation of payouts. - [20]
Y35QCWYWMinor improvement in WorkIndex type to eliminate duplicated information. - [21]
4QX5E5ACInitial compilation of payouts function succeeds. - [22]
2KZPOGRBOnce you get Haskell to compile, the tests pass! - [23]
GKGVYBZGAdded JSON serialization to TimeLog - [24]
TZQJVHBAAdd auction functions to ADB. - [25]
EMVTF2IWWIP moving back to snap. - [26]
WO2MINIFAuctions now compile! - [27]
NTPC7KJETrivial changes, feature scratchpad.
Change contents
- replacement in lib/Quixotic/Auction.hs at line 12
newtype AuctionId = AuctionId Int deriving (Show, Eq)newtype AuctionId = AuctionId Int64 deriving (Show, Eq) - replacement in lib/Quixotic/Auction.hs at line 16
, _endsAt :: UTCTime, _auctionEnd :: UTCTime - replacement in lib/Quixotic/Auction.hs at line 22
{ _userId :: UserId, _seconds :: Seconds, _btcAmount :: BTC{ _bidUser :: UserId, _bidSeconds :: Seconds, _bidAmount :: BTC, _bidTime :: UTCTime - replacement in lib/Quixotic/Auction.hs at line 34
bidSeconds bid = toRational $ bid ^. secondsbidAmount bid = toRational $ bid ^. (btcAmount . btc)costRatio bid = bidSeconds bid / bidAmount bidsecs bid = toRational $ bid ^. bidSecondsbtc bid = toRational $ bid ^. (bidAmount . satoshis)costRatio bid = secs bid / btc bid - replacement in lib/Quixotic/Auction.hs at line 44
| (total ++ x ^. btcAmount) < (auction ^. raiseAmount) =x : (takeWinningBids (total ++ x ^. btcAmount) xs)| (total ++ x ^. bidAmount) < (auction ^. raiseAmount) =x : (takeWinningBids (total ++ x ^. bidAmount) xs) - replacement in lib/Quixotic/Auction.hs at line 51
winFraction = (toRational $ remainder ^. btc) / (toRational $ x ^. (btcAmount . btc))remainderSeconds = Seconds . round $ winFraction * (toRational $ x ^. seconds)winFraction = (toRational $ remainder ^. satoshis) / (toRational $ x ^. (bidAmount . satoshis))remainderSeconds = Seconds . round $ winFraction * (toRational $ x ^. bidSeconds) - replacement in lib/Quixotic/Auction.hs at line 54
in [x & seconds .~ remainderSeconds & btcAmount .~ remainder]in [x & bidSeconds .~ remainderSeconds & bidAmount .~ remainder] - edit in lib/Quixotic/Database/SQLite.hs at line 2
{-# LANGUAGE TemplateHaskell #-} - edit in lib/Quixotic/Database/SQLite.hs at line 7
import Control.Error.Safe - replacement in lib/Quixotic/Database/SQLite.hs at line 11
import Database.SQLiteimport Database.SQLite.Simple - edit in lib/Quixotic/Database/SQLite.hs at line 18[4.1093]→[4.3922:3923](∅→∅),[4.1191]→[4.3922:3923](∅→∅),[4.3922]→[4.3922:3923](∅→∅),[4.3923]→[4.55:142](∅→∅),[4.142]→[4.1266:1307](∅→∅),[4.1266]→[4.1266:1307](∅→∅),[4.1307]→[4.60:103](∅→∅),[4.103]→[4.143:159](∅→∅),[4.1307]→[4.143:159](∅→∅),[4.159]→[4.116:187](∅→∅),[4.116]→[4.116:187](∅→∅),[4.187]→[4.1094:1245](∅→∅),[4.1245]→[4.330:336](∅→∅),[4.330]→[4.330:336](∅→∅),[4.336]→[4.4076:4077](∅→∅),[4.4076]→[4.4076:4077](∅→∅),[4.4077]→[4.337:505](∅→∅),[4.505]→[4.1246:1294](∅→∅),[4.1294]→[4.544:583](∅→∅),[4.544]→[4.544:583](∅→∅),[4.583]→[4.104:159](∅→∅),[4.159]→[4.4371:4372](∅→∅),[4.633]→[4.4371:4372](∅→∅),[4.4371]→[4.4371:4372](∅→∅),[4.4372]→[4.634:733](∅→∅),[4.733]→[3.4:217](∅→∅),[3.217]→[4.1295:1296](∅→∅),[4.96]→[4.1295:1296](∅→∅),[4.1296]→[3.218:293](∅→∅),[3.293]→[4.160:191](∅→∅),[4.1361]→[4.160:191](∅→∅),[4.191]→[2.4:106](∅→∅),[2.106]→[4.285:341](∅→∅),[4.285]→[4.285:341](∅→∅),[4.341]→[2.107:172](∅→∅)
sqliteQDB :: SQLiteHandle -> IO (QDB (EitherT Text IO) SQLiteHandle)sqliteQDB db = do_ <- defineTableOpt db True eventTable_ <- defineTableOpt db True auctionTablereturn $ QDB{ recordEvent = recordEvent', readWorkIndex = readWorkIndex', newAuction = newAuction', readAuction = readAuction', recordBid = recordBid', readBids = readBids', createUser = createUser'}recordEvent' :: LogEntry -> ReaderT SQLiteHandle (EitherT Text IO) ()recordEvent' (LogEntry ba ev) = dodb <- asklift . lift . void $ insertRow db "workEvents"[ ("btcAddr", ba ^. address ^. from packed), ("event", unpack (eventName ev)), ("eventTime", formatSqlTime (logTime ev))]readWorkIndex' :: ReaderT SQLiteHandle (EitherT Text IO) WorkIndexreadWorkIndex' = dodb <- asklet selection = execStatement db "SELECT btcAddr, event, eventTime from workEvents"rows <- lift . EitherT $ fmap (over _Left pack) selectionreturn . intervals . catMaybes $ fmap parseLogEntry (join rows)newAuction' :: Auction -> ReaderT SQLiteHandle (EitherT Text IO) AuctionIdnewAuction' a = dodb <- ask_ <- lift . lift $ insertRow db "auctions"[ ("raiseAmount", show $ a ^. (raiseAmount . btc)), ("eventTime", formatSqlTime $ a ^. endsAt)]lift . lift . fmap (AuctionId . fromInteger) $ getLastRowID db - replacement in lib/Quixotic/Database/SQLite.hs at line 19
readAuction' :: AuctionId -> ReaderT a (EitherT Text IO) AuctionreadAuction' (AuctionId aid) = dodb <- asklet selection = execParamStatement db"SELECT raiseAmount, endsAt FROM auctions WHERE ROWID = :aid"[("aid", Int aid)]rows <- lift . EitherT $ fmap (over _Left pack) selectionnewtype PLogEntry = PLogEntry LogEntrymakePrisms ''PLogEntry - edit in lib/Quixotic/Database/SQLite.hs at line 22
instance ToRow PLogEntry wheretoRow (PLogEntry (LogEntry a e)) =toRow (a ^. address, e ^. (eventType . to eventName), e ^. eventTime) - replacement in lib/Quixotic/Database/SQLite.hs at line 26
recordBid' :: UTCTime -> Bid -> ReaderT a (EitherT Text IO) ()recordBid' = undefinedreadBids' :: AuctionId -> ReaderT a (EitherT Text IO) [(UTCTime, Bid)]readBids' = undefinedinstance FromRow PLogEntry wherefromRow =let workEventParser = WorkEvent <$> (field >>= nameEvent) <*> fieldlogEntryParser = LogEntry <$> (fmap BtcAddr field) <*> workEventParserin fmap PLogEntry logEntryParser - replacement in lib/Quixotic/Database/SQLite.hs at line 32
createUser' :: User -> ReaderT a (EitherT Text IO) UserIdcreateUser' = undefinednewtype PAuction = PAuction AuctionmakePrisms ''PAuction - replacement in lib/Quixotic/Database/SQLite.hs at line 35[4.4556]→[3.561:629](∅→∅),[3.629]→[4.155:313](∅→∅),[4.155]→[4.155:313](∅→∅),[4.313]→[3.630:797](∅→∅)
parseLogEntry :: Row Value -> Maybe LogEntryparseLogEntry row = doa <- lookup "btcAddr" row >>= valueAddrt <- lookup "eventTime" row >>= valueTimeev <- lookup "event" row >>= (valueEvent t)return $ LogEntry a evparseAuction :: Row Value -> Maybe AuctionparseAuction row =Auction <$> (lookup "raiseAmount" row >>= valueBTC)<*> (lookup "endsAt" row >>= valueTime)instance FromRow PAuction wherefromRow =let auctionParser = Auction <$> (fmap BTC field) <*> fieldin fmap PAuction auctionParser - replacement in lib/Quixotic/Database/SQLite.hs at line 40
valueBTC :: Value -> Maybe BTCvalueBTC (Int i) _ = Just $ BTC ivalueBTC _ = NothingrecordEvent' :: LogEntry -> ReaderT Connection IO ()recordEvent' logEntry = doconn <- asklift $ execute conn"INSERT INTO work_events (btc_addr, event_type, event_time) VALUES (?, ?, ?)"(logEntry ^. (from _PLogEntry)) - replacement in lib/Quixotic/Database/SQLite.hs at line 47[3.885]→[4.313:349](∅→∅),[4.313]→[4.313:349](∅→∅),[4.349]→[4.346:389](∅→∅),[4.389]→[4.394:416](∅→∅),[4.394]→[4.394:416](∅→∅)
valueAddr :: Value -> Maybe BtcAddrvalueAddr (Text t) = parseBtcAddr $ pack tvalueAddr _ = NothingreadWorkIndex' :: ReaderT Connection IO WorkIndexreadWorkIndex' = doconn <- askrows <- lift $ query_ conn"SELECT btc_addr, event_type, event_time from workEvents"lift . return . workIndex $ fmap (^. _PLogEntry) rows - replacement in lib/Quixotic/Database/SQLite.hs at line 54
valueTime :: Value -> Maybe UTCTimevalueTime (Text t) = parseTime defaultTimeLocale "%c" tvalueTime _ = NothingnewAuction' :: Auction -> ReaderT Connection IO AuctionIdnewAuction' auc = doconn <- asklift $ execute conn"INSERT INTO auctions (raise_amount, end_time) VALUES (?, ?)"(auc ^. (raiseAmount . satoshis), auc ^. auctionEnd)lift . fmap AuctionId $ lastInsertRowId conn - replacement in lib/Quixotic/Database/SQLite.hs at line 62
valueEvent :: UTCTime -> Value -> Maybe WorkEventvalueEvent t (Text "start") = Just (StartWork t)valueEvent t (Text "stop") = Just (StopWork t)valueEvent _ _ = NothingreadAuction' :: AuctionId -> ReaderT Connection IO (Maybe Auction)readAuction' (AuctionId aid) = doconn <- askrows <- lift $ query conn"SELECT raise_amount, end_time FROM auctions WHERE ROWID = ?"(Only aid)lift . return . headMay $ fmap (^. _PAuction) rows - replacement in lib/Quixotic/Database/SQLite.hs at line 70
formatSqlTime :: UTCTime -> StringformatSqlTime t = formatTime defaultTimeLocale "%c" trecordBid' :: AuctionId -> Bid -> ReaderT Connection IO ()recordBid' (AuctionId aid) bid = doconn <- asklift $ execute conn"INSERT INTO bids (auction_id, user_id, bid_seconds, bid_amount, bid_time) values (?, ?, ?, ?, ?)"(aid, bid ^. bidUser, bid ^. bidSeconds, bid ^. bidAmount, bid ^. bidTime) - replacement in lib/Quixotic/Database/SQLite.hs at line 77
eventTable :: SQLTableeventTable = Table "workEvents"[ Column "btcAddr" (SQLVarChar 256) [], Column "event" (SQLVarChar 64) [], Column "eventTime" (SQLDateTime DATETIME) []] []readBids' :: AuctionId -> ReaderT Connection IO [(UTCTime, Bid)]readBids' = undefined - replacement in lib/Quixotic/Database/SQLite.hs at line 80
auctionTable :: SQLTableauctionTable = Table "auctions"[ Column "raiseAmouont" (SQLInt BIG False False) [], Column "endsAt" (SQLDateTime DATETIME) []] []createUser' :: User -> ReaderT Connection IO UserIdcreateUser' = undefined - edit in lib/Quixotic/Database/SQLite.hs at line 83[4.736]
sqliteQDB :: QDB IO ConnectionsqliteQDB = QDB{ recordEvent = recordEvent', readWorkIndex = readWorkIndex', newAuction = newAuction', readAuction = readAuction', recordBid = recordBid', readBids = readBids', createUser = createUser'} - replacement in lib/Quixotic/Database.hs at line 14
, readAuction :: AuctionId -> ReaderT a m Auction, recordBid :: UTCTime -> Bid -> ReaderT a m (), readAuction :: AuctionId -> ReaderT a m (Maybe Auction), recordBid :: AuctionId -> Bid -> ReaderT a m () - replacement in lib/Quixotic/TimeLog.hs at line 1
{-# LANGUAGE ScopedTypeVariables, OverloadedStrings, NoImplicitPrelude #-}{-# LANGUAGE ScopedTypeVariables #-}{-# LANGUAGE OverloadedStrings #-}{-# LANGUAGE NoImplicitPrelude #-}{-# LANGUAGE TemplateHaskell #-} - edit in lib/Quixotic/TimeLog.hs at line 8
, btcAddr, event - edit in lib/Quixotic/TimeLog.hs at line 10
, EventType(..), eventName, nameEvent - edit in lib/Quixotic/TimeLog.hs at line 13
, eventType, eventTime - edit in lib/Quixotic/TimeLog.hs at line 15
, workIndex - edit in lib/Quixotic/TimeLog.hs at line 19
, eventName - edit in lib/Quixotic/TimeLog.hs at line 20
, intervals - edit in lib/Quixotic/TimeLog.hs at line 25
import Control.Lens - edit in lib/Quixotic/TimeLog.hs at line 31
import qualified Data.Aeson.Types as A - replacement in lib/Quixotic/TimeLog.hs at line 35
data WorkEvent = StartWork { logTime :: UTCTime }| StopWork { logTime :: UTCTime } deriving (Show, Eq)data EventType = StartWork | StopWork deriving (Show, Eq) - replacement in lib/Quixotic/TimeLog.hs at line 37[4.5415]→[4.661:692](∅→∅),[4.692]→[4.5448:5515](∅→∅),[4.1760]→[4.5448:5515](∅→∅),[4.5448]→[4.5448:5515](∅→∅)
eventName :: WorkEvent -> TexteventName (StartWork _) = "start"eventName (StopWork _) = "stop"eventName :: EventType -> TexteventName StartWork = "start"eventName StopWork = "stop"nameEvent :: MonadPlus m => Text -> m EventTypenameEvent "start" = return StartWorknameEvent "stop" = return StopWorknameEvent _ = mzero - edit in lib/Quixotic/TimeLog.hs at line 46
data WorkEvent = WorkEvent{ _eventType :: EventType, _eventTime :: UTCTime} deriving (Show, Eq)makeLenses ''WorkEvent - replacement in lib/Quixotic/TimeLog.hs at line 53
parseJSON (Object jv) = dot <- jv .: "type" :: A.Parser Textcase t of"start" -> StartWork <$> jv .: "timestamp""stop" -> StopWork <$> jv .: "timestamp"_ -> mzeroparseJSON (Object jv) =WorkEvent <$> (jv .: "type" >>= nameEvent) <*> jv .: "timestamp" - replacement in lib/Quixotic/TimeLog.hs at line 59
{ btcAddr :: BtcAddr, event :: WorkEvent{ _btcAddr :: BtcAddr, _event :: WorkEvent - edit in lib/Quixotic/TimeLog.hs at line 62
makeLenses ''LogEntry - replacement in lib/Quixotic/TimeLog.hs at line 65
parseJSON (Object jv) = LogEntry <$>jv .: "btcAddr" <*>jv .: "workEvent"parseJSON (Object jv) =LogEntry <$> jv .: "btcAddr" <*> jv .: "workEvent" - replacement in lib/Quixotic/TimeLog.hs at line 114[4.600]→[4.352:403](∅→∅),[4.1582]→[4.352:403](∅→∅),[4.2354]→[4.352:403](∅→∅),[4.403]→[4.942:966](∅→∅),[4.966]→[4.885:1007](∅→∅)
intervals :: Foldable f => f LogEntry -> WorkIndexintervals logEntries =let logSum = F.foldl' appendLogEntry MS.empty logEntriesin MS.map (bimap (fmap event) (fmap workInterval)) $ logSumworkIndex :: Foldable f => f LogEntry -> WorkIndexworkIndex logEntries =let logSum :: RawIndexlogSum = F.foldl' appendLogEntry MS.empty logEntriesin MS.map (bimap (fmap (^. event)) (fmap workInterval)) $ logSum - replacement in lib/Quixotic/TimeLog.hs at line 123
appendLogEntry workIndex entry =let acc = reduceToIntervals $ pushEntry entry workIndexin insert (btcAddr entry) acc workIndexappendLogEntry idx entry =let acc = reduceToIntervals $ pushEntry entry idxin insert (entry ^. btcAddr) acc idx - replacement in lib/Quixotic/TimeLog.hs at line 128
pushEntry entry = first (entry :) . MS.findWithDefault ([], []) (btcAddr entry)pushEntry entry = first (entry :) . MS.findWithDefault ([], []) (entry ^. btcAddr) - replacement in lib/Quixotic/TimeLog.hs at line 131
reduceToIntervals ((LogEntry addr (StopWork end')) : (LogEntry _ (StartWork start')) : xs, acc) =reduceToIntervals ((LogEntry addr (WorkEvent StopWork end')) : (LogEntry _ (WorkEvent StartWork start')) : xs, acc) = - replacement in lib/Quixotic.hs at line 14
newtype BTC = BTC { _btc :: Int64 } deriving (Show, Eq, Ord)newtype BTC = BTC { _satoshis :: Int64 } deriving (Show, Eq, Ord) - replacement in lib/Quixotic.hs at line 18
(<>) b1 b2 = BTC $ _btc b1 + _btc b2(<>) (BTC b1) (BTC b2) = BTC $ b1 + b2 - replacement in lib/Quixotic.hs at line 25
invert b = BTC . negate . _btc $ binvert (BTC b) = BTC . negate $ b - edit in quixotic.cabal at line 32
, safe >= 0.3.8, errors >= 1.4.7 - replacement in quixotic.cabal at line 35
, sqlite == 0.5.2.2, sqlite-simple >= 0.4.8 && < 0.5