Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into hkm/ghcjs-cross
Browse files Browse the repository at this point in the history
# Conflicts:
#	marlowe/marlowe.cabal
#	nix/pkgs/haskell/materialized-darwin/.plan.nix/marlowe.nix
#	nix/pkgs/haskell/materialized-darwin/.plan.nix/plutus-contract.nix
#	nix/pkgs/haskell/materialized-linux/.plan.nix/marlowe.nix
#	nix/pkgs/haskell/materialized-linux/.plan.nix/plutus-contract.nix
#	nix/pkgs/haskell/materialized-windows/.plan.nix/marlowe.nix
#	nix/pkgs/haskell/materialized-windows/.plan.nix/plutus-contract.nix
#	plutus-contract/plutus-contract.cabal
  • Loading branch information
hamishmack committed Oct 11, 2021
2 parents a0258b9 + 5ffcfa6 commit 0928bd6
Show file tree
Hide file tree
Showing 331 changed files with 13,551 additions and 6,376 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,6 @@ secrets/*/.gpg-id
ghcid.txt
plutus-pab/test-node/testnet/db
plutus-pab/test-node/alonzo-purple/db
# profiling output files
*.timelog
*.stacks
4 changes: 2 additions & 2 deletions deployment/morph/machines/marlowe-dash.nix
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
nodePort = 8082;
chainIndexPort = 8083;
signingProcessPort = 8084;
slotZeroTime = 1591566291000; # POSIX time of 2020-06-07T21:44:51Z (Sunday, June 7, 2020 21:44:51)
slotZeroTime = 1596059091000; # In milliseconds. See note [Datetime to slot] in Marlowe.Slot
slotLength = 1000; # In milliseconds
constantFee = 10; # Constant fee per transaction in lovelace
scriptsFeeFactor = 1.0; # Factor by which to multiply the size-dependent scripts fee in lovelace
scriptsFeeFactor = 0.0; # Factor by which to multiply the size-dependent scripts fee in lovelace
};

}
2 changes: 1 addition & 1 deletion fake-pab/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ let
'';
name = "marlowe-dashboard-client-fake-pab";
extraSrcs = {
web-common = webCommon;
web-common = webCommon.cleanSrc;
web-common-marlowe = webCommonMarlowe;
generated = marlowe-dashboard.generated-purescript;
fake-pab-generated = fake-pab-generated-purescript;
Expand Down
42 changes: 38 additions & 4 deletions freer-extras/freer-extras.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,50 @@ library
hs-source-dirs: src
exposed-modules:
Control.Monad.Freer.Extras
Control.Monad.Freer.Extras.Modify
Control.Monad.Freer.Extras.Beam
Control.Monad.Freer.Extras.Log
Control.Monad.Freer.Extras.Stream
Control.Monad.Freer.Extras.Modify
Control.Monad.Freer.Extras.Pagination
Control.Monad.Freer.Extras.State
Control.Monad.Freer.Extras.Stream
build-depends:
aeson -any,
base >=4.7 && <5,
lens -any,
beam-core -any,
beam-sqlite -any,
containers -any,
data-default -any,
freer-simple -any,
iohk-monitoring -any,
lens -any,
mtl -any,
openapi3 -any,
prettyprinter -any,
sqlite-simple -any,
streaming -any,
text -any
text -any,

test-suite freer-extras-test
import: lang
type: exitcode-stdio-1.0
main-is: Spec.hs
hs-source-dirs: test
other-modules:
Control.Monad.Freer.Extras.BeamSpec
Control.Monad.Freer.Extras.PaginationSpec
build-depends:
hedgehog -any,
tasty -any,
tasty-hedgehog -any,
build-depends:
base >=4.7 && <5,
beam-core -any,
beam-migrate -any,
beam-sqlite -any,
containers -any,
contra-tracer -any,
freer-extras -any,
freer-simple -any,
lens -any,
semigroups -any,
sqlite-simple -any,
2 changes: 2 additions & 0 deletions freer-extras/src/Control/Monad/Freer/Extras.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ module Control.Monad.Freer.Extras (
, module Control.Monad.Freer.Extras.Modify
, module Control.Monad.Freer.Extras.Stream
, module Control.Monad.Freer.Extras.State
, module Control.Monad.Freer.Extras.Beam
) where

import Control.Monad.Freer.Extras.Beam
import Control.Monad.Freer.Extras.Log
import Control.Monad.Freer.Extras.Modify
import Control.Monad.Freer.Extras.State
Expand Down
200 changes: 200 additions & 0 deletions freer-extras/src/Control/Monad/Freer/Extras/Beam.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StrictData #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ViewPatterns #-}

module Control.Monad.Freer.Extras.Beam where

import Cardano.BM.Data.Tracer (ToObject (..))
import Cardano.BM.Trace (Trace, logDebug)
import Control.Concurrent (threadDelay)
import Control.Exception (try)
import Control.Monad (guard)
import Control.Monad.Freer (Eff, LastMember, Member, type (~>))
import Control.Monad.Freer.Error (Error, throwError)
import Control.Monad.Freer.Extras.Pagination (Page (..), PageQuery (..), PageSize (..))
import Control.Monad.Freer.Reader (Reader, ask)
import Control.Monad.Freer.TH (makeEffect)
import Data.Aeson (FromJSON, ToJSON)
import Data.Foldable (traverse_)
import qualified Data.List.NonEmpty as L
import Data.Maybe (isJust, listToMaybe)
import Data.Text (Text)
import qualified Data.Text as Text
import Database.Beam (Beamable, DatabaseEntity, FromBackendRow, Identity,
MonadIO (liftIO), Q, QBaseScope, QExpr, SqlDelete, SqlInsert,
SqlSelect, SqlUpdate, TableEntity, asc_, filter_,
insertValues, limit_, orderBy_, runDelete, runInsert,
runSelectReturningList, runSelectReturningOne, runUpdate,
select, val_, (>.))
import Database.Beam.Backend.SQL (BeamSqlBackendCanSerialize, HasSqlValueSyntax)
import Database.Beam.Backend.SQL.BeamExtensions (BeamHasInsertOnConflict (anyConflict, insertOnConflict, onConflictDoNothing))
import Database.Beam.Query.Internal (QNested)
import Database.Beam.Schema.Tables (FieldsFulfillConstraint)
import Database.Beam.Sqlite (Sqlite, SqliteM, runBeamSqliteDebug)
import Database.Beam.Sqlite.Syntax (SqliteValueSyntax)
import qualified Database.SQLite.Simple as Sqlite
import GHC.Generics (Generic)
import Prettyprinter (Pretty (..), colon, (<+>))

type BeamableSqlite table = (Beamable table, FieldsFulfillConstraint (BeamSqlBackendCanSerialize Sqlite) table)

type BeamThreadingArg = QNested (QNested QBaseScope)

newtype BeamError =
SqlError Text
deriving stock (Eq, Show, Generic)
deriving anyclass (FromJSON, ToJSON, ToObject)

instance Pretty BeamError where
pretty = \case
SqlError s -> "SqlError (via Beam)" <> colon <+> pretty s

newtype BeamLog =
SqlLog String
deriving stock (Eq, Show, Generic)
deriving anyclass (FromJSON, ToJSON, ToObject)

instance Pretty BeamLog where
pretty = \case
SqlLog s -> "SqlLog" <> colon <+> pretty s

data BeamEffect r where
-- Workaround for "too many SQL variables" sqlite error. Provide a
-- batch size so that we avoid the error. The maximum is 999.
AddRowsInBatches
:: BeamableSqlite table
=> Int
-> DatabaseEntity Sqlite db (TableEntity table)
-> [table Identity]
-> BeamEffect ()

AddRows
:: BeamableSqlite table
=> SqlInsert Sqlite table
-> BeamEffect ()

UpdateRows
:: Beamable table
=> SqlUpdate Sqlite table
-> BeamEffect ()

DeleteRows
:: Beamable table
=> SqlDelete Sqlite table
-> BeamEffect ()

SelectList
:: FromBackendRow Sqlite a
=> SqlSelect Sqlite a
-> BeamEffect [a]

-- | Select using Seek Pagination.
SelectPage
:: (FromBackendRow Sqlite a, HasSqlValueSyntax SqliteValueSyntax a)
=> PageQuery a
-> Q Sqlite db BeamThreadingArg (QExpr Sqlite BeamThreadingArg a)
-> BeamEffect (Page a)

SelectOne
:: FromBackendRow Sqlite a
=> SqlSelect Sqlite a
-> BeamEffect (Maybe a)

Combined
:: [BeamEffect ()]
-> BeamEffect ()

handleBeam ::
forall effs.
( LastMember IO effs
, Member (Error BeamError) effs
, Member (Reader Sqlite.Connection) effs
)
=> Trace IO BeamLog
-> BeamEffect
~> Eff effs
handleBeam trace eff = runBeam trace $ execute eff
where
execute :: BeamEffect ~> SqliteM
execute = \case
AddRowsInBatches _ _ [] -> pure ()
AddRowsInBatches n table (splitAt n -> (batch, rest)) -> do
runInsert $ insertOnConflict table (insertValues batch) anyConflict onConflictDoNothing
execute $ AddRowsInBatches n table rest
AddRows q -> runInsert q
UpdateRows q -> runUpdate q
DeleteRows q -> runDelete q
SelectList q -> runSelectReturningList q
SelectPage pageQuery@PageQuery { pageQuerySize = PageSize ps, pageQueryLastItem } q -> do
let ps' = fromIntegral ps

-- Fetch the first @PageSize + 1@ elements after the last query
-- element. The @+1@ allows to us to know if there is a next page
-- or not.
items <- runSelectReturningList
$ select
$ limit_ (ps' + 1)
$ orderBy_ asc_
$ filter_ (\qExpr -> maybe (val_ True)
(\lastItem -> qExpr >. val_ lastItem)
pageQueryLastItem
) q

let lastItemM = guard (length items > fromIntegral ps)
>> L.nonEmpty items
>>= listToMaybe . L.tail . L.reverse
let newPageQuery = fmap (PageQuery (PageSize ps) . Just) lastItemM

pure $
Page
{ currentPageQuery = pageQuery
, nextPageQuery = newPageQuery
, pageItems = if isJust lastItemM then init items else items
}
SelectOne q -> runSelectReturningOne q
Combined effs -> traverse_ execute effs

runBeam ::
forall effs.
( LastMember IO effs
, Member (Error BeamError) effs
, Member (Reader Sqlite.Connection) effs
)
=> Trace IO BeamLog
-> SqliteM
~> Eff effs
runBeam trace action = do
conn <- ask @Sqlite.Connection
loop conn ( 5 :: Int )
where
loop conn retries = do
let traceSql = logDebug trace . SqlLog
resultEither <- liftIO $ try $ Sqlite.withTransaction conn $ runBeamSqliteDebug traceSql conn action
case resultEither of
-- 'Database.SQLite.Simple.ErrorError' corresponds to an SQL error or
-- missing database. When this exception is raised, we suppose it's
-- because the another transaction was already running.
Left (Sqlite.SQLError Sqlite.ErrorError _ _) | retries > 0 -> do
liftIO $ threadDelay 100_000
loop conn (retries - 1)
-- We handle and rethrow errors other than
-- 'Database.SQLite.Simple.ErrorError'.
Left e -> do
throwError $ SqlError $ Text.pack $ show e
Right v -> return v

makeEffect ''BeamEffect

0 comments on commit 0928bd6

Please sign in to comment.