On Sat, Aug 01, 2015 at 03:08:47AM +0300, Nikita Karetnikov wrote:
> > Oh, wow. Thanks for the tip. I will probably do that. Even after
> > spending a few hours on this esqueleto, it will still save me time to
> > switch.
> >
> > Just gotta figure out how to share database connection information...
> 
> Is it really that bad?  If it's a major slowdown, just go ahead, but
> paste what you've tried.  Also, I'd suggest moving a subselect into a
> separate Haskell function, even with strings.

Here's what is happening so far:

    -- | Find underfunded patrons.
    -- This function is used after something may have broken the invariant that
    -- all funded pledges are covered by the patron's account balance. It 
returns
    -- pertinent information about each underfunded pledge.
    --
    underfundedUsers :: (MonadIO m, Functor m)
                     => ProjectId
                     -> SqlPersistT m [Underfunded]
    underfundedUsers projId = do
        -- the inner query
        totalOutlays <- fmap processOutlayRows $
            select $
            from $ \(pl `InnerJoin` pr `InnerJoin` u `InnerJoin` ac) -> do
            on_ $ ac ^. AccountId ==. u ^. UserAccount
            on_ $ u ^. UserId ==. pl ^. PledgeUser
            on_ $ pr ^. ProjectId ==. pl ^. PledgeProject
            where_ $ pl ^. PledgeFundedShares >. val 0
            groupBy $ (u ^. UserId)
            return (u ^. UserId
                   ,sum_ (($*.) (pr ^. ProjectShareValue)
                                (pl ^. PledgeFundedShares))
                   )
        let process' = processIntermediateRows totalOutlays
        intemediate <- fmap process' $
            select $
            from $ \(pl `InnerJoin` u `InnerJoin` ac `InnerJoin` pr) -> do
            on_ $ pr ^. ProjectId ==. pl ^. PledgeProject
            on_ $ ac ^. AccountId ==. u ^. UserAccount
            on_ $ u ^. UserId ==. pl ^. PledgeUser
            return (u ^. UserId
                   ,ac ^. AccountBalance
                   ,pl ^. PledgeFundedShares
                   ,pr ^. ProjectId
                   ,pr ^. ProjectShareValue
                   ,ac ^. AccountId)
      where
        -- | Just cleans up types and removes rows that returned Nothing
        -- for the sum. (There actually shouldn't be any because of the inner
        -- join, but whatevs.)
        processOutlayRows :: [(Value UserId, Value (Maybe Milray))]
                          -> Map UserId Milray
        processOutlayRows = M.fromList
                          . catMaybes
                          . map sequence -- 'lift' the Maybe
                          . unwrapValues

        -- | Primarily calculates the "available balance" for each pledge.
        -- That is defined, for each pledge, as the difference between the
        -- patron's total balance and the sum of the outlay going to the
        -- patron's *other* pledges.
        processIntermediateRows :: Map UserId Milray
                                -> [(Value UserId
                                    ,Value Milray
                                    ,Value Int64
                                    ,Value ProjectId
                                    ,Value Milray
                                    ,Value AccountId)]
                                -> [Underfunded]
        processIntermediateRows totalOutlays =
            map ( (\(u, a, p, v) -> Underfunded u a p v))
                . map getAvailable
                . unwrapValues
                )
          where
            getAvailable (UserId, Milray, Int64, ProjectId, Milray, AccountId) =
                -- XXX TODO
                undefined

> Note that with esqueleto, if you change the schema, you'll get a compile
> time warning.  While with strings, it'll happen at runtime.

True, but I have to accept that risk right now. Tests will help.

Attachment: signature.asc
Description: Digital signature

_______________________________________________
Dev mailing list
[email protected]
https://lists.snowdrift.coop/mailman/listinfo/dev

Reply via email to