Skip to content

Commit

Permalink
Wire new 'order' query parameter through the API.
Browse files Browse the repository at this point in the history
  • Loading branch information
KtorZ committed Sep 29, 2022
1 parent 006c5fd commit 81d41e5
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 32 deletions.
25 changes: 17 additions & 8 deletions src/Kupo/App/Database.hs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import Kupo.Data.Database
, Checkpoint (..)
, Input (..)
, ScriptReference (..)
, SortDirection (..)
)
import Numeric
( Floating (..)
Expand Down Expand Up @@ -120,6 +121,7 @@ data Database (m :: Type -> Type) = Database

, foldInputs
:: Text -- An address-like query
-> SortDirection
-> (Input -> m ())
-> DBTransaction m ()

Expand Down Expand Up @@ -349,19 +351,26 @@ mkDatabase tr longestRollback bracketConnection = Database
]
changes conn

, foldInputs = \whereClause yield -> ReaderT $ \conn -> do
-- TODO: Move upward and make configurable by users.
let ordering = "DESC"
let qry = "SELECT output_reference, address, value, datum_hash, script_hash ,\
, foldInputs = \whereClause sortDirection yield -> ReaderT $ \conn -> do
let qry = "SELECT \
\output_reference, address, value, datum_hash, script_hash ,\
\created_at, createdAt.header_hash, \
\spent_at, spentAt.header_hash \
\FROM inputs \
\JOIN checkpoints AS createdAt ON createdAt.slot_no = created_at \
\LEFT OUTER JOIN checkpoints AS spentAt ON spentAt.slot_no = spent_at \
\WHERE " <> whereClause <> " \
\JOIN \
\checkpoints AS createdAt ON createdAt.slot_no = created_at \
\LEFT OUTER JOIN \
\checkpoints AS spentAt ON spentAt.slot_no = spent_at \
\WHERE "
<> whereClause <> " \
\ORDER BY \
\created_at " <> ordering <> ", \
\substr(output_reference, -2) " <> ordering
\substr(output_reference, -2) " <> ordering <> ", \
\substr(output_reference, -4, 2) " <> ordering
where
ordering = case sortDirection of
Asc -> "ASC"
Desc -> "DESC"

-- TODO: Allow resolving datums / scripts on demand through LEFT JOIN
--
Expand Down
13 changes: 10 additions & 3 deletions src/Kupo/App/Http.hs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import Kupo.Data.Database
( applyStatusFlag
, binaryDataFromRow
, datumHashToRow
, mkSortDirection
, patternToRow
, patternToSql
, pointFromRow
Expand All @@ -85,6 +86,9 @@ import Kupo.Data.Http.GetCheckpointMode
( GetCheckpointMode (..)
, getCheckpointModeFromQuery
)
import Kupo.Data.Http.OrderMatchesBy
( orderMatchesBy
)
import Kupo.Data.Http.Response
( responseJson
, responseJsonEncoding
Expand Down Expand Up @@ -410,13 +414,16 @@ handleGetMatches headers patternQuery queryParams Database{..} = either id id $
statusFlag <- statusFlagFromQueryParams queryParams
`orAbort` Errors.invalidStatusFlag

let query = applyStatusFlag statusFlag (patternToSql p)

yieldIf <- (mkYieldIf p <$> filterMatchesBy queryParams)
`orAbort` Errors.invalidMatchFilter

sortDirection <- mkSortDirection <$> orderMatchesBy queryParams
`orAbort` Errors.invalidSortDirection

let query = applyStatusFlag statusFlag (patternToSql p)

pure $ responseStreamJson headers resultToJson $ \yield done -> do
runReadOnlyTransaction $ foldInputs query (yieldIf yield . resultFromRow)
runReadOnlyTransaction $ foldInputs query sortDirection (yieldIf yield . resultFromRow)
done
where
-- NOTE: kupo does support two different ways for fetching results, via query parameters or via
Expand Down
16 changes: 16 additions & 0 deletions src/Kupo/Data/Database.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ module Kupo.Data.Database

-- * Filtering
, applyStatusFlag

-- * Sorting
, SortDirection (..)
, mkSortDirection
) where

import Kupo.Prelude
Expand Down Expand Up @@ -80,6 +84,9 @@ import Kupo.Data.Cardano
, transactionIdToBytes
, unsafeTransactionIdFromBytes
)
import Kupo.Data.Http.OrderMatchesBy
( OrderMatchesBy (..)
)
import Kupo.Data.Http.StatusFlag
( StatusFlag (..)
)
Expand Down Expand Up @@ -619,3 +626,12 @@ applyStatusFlag = \case
(<> " AND spent_at IS NULL")
OnlySpent ->
(<> " AND spent_at IS NOT NULL")

data SortDirection = Asc | Desc
deriving (Generic)

mkSortDirection :: OrderMatchesBy -> SortDirection
mkSortDirection = \case
MostRecentFirst -> Desc
NoExplicitOrder -> Desc
OldestFirst -> Asc
8 changes: 8 additions & 0 deletions src/Kupo/Data/Http/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ malformedPoint =
\a point). Please refer to the API reference for details <https://cardanosolutions.github.io/kupo>."
}

invalidSortDirection :: Response
invalidSortDirection =
responseJson status400 Default.headers $ HttpError
{ hint = "Invalid sort direction provided as query parameter. \
\You can specify either 'order=most_recent_first' or \
\'order=oldest_first'. Please refer to the API reference for details <https://cardanosolutions.github.io/kupo#operation/getAllMatches>."
}

unsafeRollbackBeyondSafeZone :: Response
unsafeRollbackBeyondSafeZone =
responseJson status400 Default.headers $ HttpError
Expand Down
16 changes: 8 additions & 8 deletions src/Kupo/Prelude.hs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ import Data.Generics.Internal.VL.Lens
import Data.List
( nubBy
)
import Data.Sequence.Strict
( StrictSeq
)
import GHC.Generics
( Rep
)
Expand Down Expand Up @@ -131,6 +134,11 @@ import Relude hiding
, tryTakeTMVar
, writeTVar
)
import Relude.Extra
( next
, prev
, safeToEnum
)
import System.Posix.Signals
( Handler (..)
, installHandler
Expand All @@ -146,14 +154,6 @@ import qualified Data.Aeson.Parser as Json
import qualified Data.Aeson.Parser.Internal as Json
import qualified Data.Aeson.Types as Json
import qualified Data.ByteString.Base58 as Base58
import Data.Sequence.Strict
( StrictSeq
)
import Relude.Extra
( next
, prev
, safeToEnum
)

data ConnectionStatusToggle m = ConnectionStatusToggle
{ toggleConnected :: !(m ())
Expand Down
10 changes: 9 additions & 1 deletion test/Test/Kupo/App/HttpSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,14 @@ spec = do
resBadRequest
& Wai.assertHeader Http.hContentType (renderHeader mediaTypeJson)

session' "🕱 GET /matches?order=foo" $ do
resBadRequest <- Wai.request $ Wai.defaultRequest
& flip Wai.setPath "/matches?order=foo"
resBadRequest
& Wai.assertStatus (Http.statusCode Http.status400)
resBadRequest
& Wai.assertHeader Http.hContentType (renderHeader mediaTypeJson)

session' "🕱 DELETE /matches/{pattern}" $ do
overlappingFragment <- liftIO $ generate (elements Fixture.overlappingUnaryFragments)
resBadRequest <- Wai.request $ Wai.defaultRequest
Expand Down Expand Up @@ -429,7 +437,7 @@ databaseStub = Database
10
, insertInputs =
\_ -> return ()
, foldInputs = \_ callback -> lift $ do
, foldInputs = \_ _ callback -> lift $ do
rows <- fmap resultToRow <$> generate (listOf1 genResult)
mapM_ callback rows
, deleteInputsByAddress =
Expand Down
Loading

0 comments on commit 81d41e5

Please sign in to comment.