From 44e15e4e9b4c175514936e4d1011708130a8416b Mon Sep 17 00:00:00 2001 From: Wolfgang Walther Date: Sat, 11 Jul 2026 23:36:43 +0200 Subject: [PATCH] chore: run doctests in parallel Runs the doctests much faster, which is potentially useful in combination with postgrest-watch for local development. This implies that doctests run on compiled code, not in a GHCi session, which has some implications: - Only exported functions can be tested. - Imports need to be made explicit in doctests themselves. On the flipside, this would allow us to potentially include doctest results in code coverage, I believe. This change is a requirement to vendor hasql, which otherwise breaks the existing doctests: hasql contains a .hsc file, which *needs* to be compiled - not interpreted - to make the tests work. --- .github/workflows/test.yaml | 2 +- .gitignore | 1 + cabal.project | 3 +++ nix/tools/tests.nix | 2 -- postgrest.cabal | 5 +---- src/PostgREST/ApiRequest/Preferences.hs | 4 ++++ src/PostgREST/ApiRequest/QueryParams.hs | 15 +++++++++++++ src/PostgREST/Config.hs | 1 + src/PostgREST/Error.hs | 8 +++++++ src/PostgREST/MediaType.hs | 4 ++++ src/PostgREST/Plan.hs | 10 +++++++++ src/PostgREST/Response/Performance.hs | 3 +++ test/doc/Main.hs | 28 ++++--------------------- 13 files changed, 55 insertions(+), 31 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b94060545..4b4c9d04d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -63,7 +63,7 @@ jobs: - name: Run doctests if: always() - run: postgrest-test-doctests + run: nix-shell --run postgrest-test-doctests - name: Check the spec tests for idempotence if: always() diff --git a/.gitignore b/.gitignore index e1caf184f..9c62ebe84 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ gen_private.json .pytest_cache .ruff_cache postgrest-module-graph.png +.ghc.environment.* diff --git a/cabal.project b/cabal.project index 49c8932d1..f58873a98 100644 --- a/cabal.project +++ b/cabal.project @@ -2,3 +2,6 @@ packages: postgrest.cabal tests: true allow-newer: hasql:postgresql-libpq + +-- https://github.com/martijnbastiaan/doctest-parallel/blob/main/example/README.md#cabalproject +write-ghc-environment-files: always diff --git a/nix/tools/tests.nix b/nix/tools/tests.nix index 2bbac03d3..58c7052bf 100644 --- a/nix/tools/tests.nix +++ b/nix/tools/tests.nix @@ -55,8 +55,6 @@ let withEnv = postgrest.env; } '' - # This makes nix-env -iA tests.doctests.bin work. - export NIX_GHC=${postgrest.env.NIX_GHC} ${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:doctests ''; diff --git a/postgrest.cabal b/postgrest.cabal index 2974e1b84..a3b30d730 100644 --- a/postgrest.cabal +++ b/postgrest.cabal @@ -352,14 +352,11 @@ test-suite observability test-suite doctests type: exitcode-stdio-1.0 default-language: Haskell2010 - default-extensions: OverloadedStrings - NoImplicitPrelude hs-source-dirs: test/doc main-is: Main.hs build-depends: base >= 4.9 && < 4.22 - , doctest >= 0.8 + , doctest-parallel >= 0.4 , postgrest , pretty-simple - , protolude >= 0.3.1 && < 0.4 ghc-options: -threaded -O0 -Werror -Wall -fwarn-identities -fno-spec-constr -optP-Wno-nonportable-include-path diff --git a/src/PostgREST/ApiRequest/Preferences.hs b/src/PostgREST/ApiRequest/Preferences.hs index 55369efbb..572474ffb 100644 --- a/src/PostgREST/ApiRequest/Preferences.hs +++ b/src/PostgREST/ApiRequest/Preferences.hs @@ -21,6 +21,7 @@ module PostgREST.ApiRequest.Preferences , shouldCount , shouldExplainCount , prefAppliedHeader + , toHeaderValue ) where import qualified Data.ByteString.Char8 as BS @@ -34,7 +35,10 @@ import Protolude -- $setup -- Setup for doctests +-- >>> :set -XStandaloneDeriving -- >>> import Text.Pretty.Simple (pPrint) +-- >>> import qualified Data.Set as S +-- >>> import Protolude -- >>> deriving instance Show PreferResolution -- >>> deriving instance Show PreferRepresentation -- >>> deriving instance Show PreferCount diff --git a/src/PostgREST/ApiRequest/QueryParams.hs b/src/PostgREST/ApiRequest/QueryParams.hs index b8f21fd18..688e82a52 100644 --- a/src/PostgREST/ApiRequest/QueryParams.hs +++ b/src/PostgREST/ApiRequest/QueryParams.hs @@ -9,7 +9,18 @@ module PostgREST.ApiRequest.QueryParams ( parse , QueryParams(..) + , pFieldForest + , pFieldName + , pFieldSelect + , pJsonPath + , pLogicTree + , pOpExpr + , pOrder + , pRelationSelect + , pRequestFilter , pRequestRange + , pSingleVal + , pSpreadRelationSelect ) where import qualified Data.ByteString.Char8 as BS @@ -62,6 +73,10 @@ import PostgREST.Error (QPError (..)) import Protolude hiding (Sum, try) +-- $setup +-- >>> import qualified Text.ParserCombinators.Parsec as P +-- >>> import Protolude hiding (Sum, try) + data QueryParams = QueryParams { qsCanonical :: ByteString diff --git a/src/PostgREST/Config.hs b/src/PostgREST/Config.hs index c9828e75b..2824cd346 100644 --- a/src/PostgREST/Config.hs +++ b/src/PostgREST/Config.hs @@ -597,6 +597,7 @@ pgConnString conn | uriDesignator `T.isPrefixOf` conn || shortUriDesignator `T.i -- | Adds a `fallback_application_name` value to the connection string. This allows querying the PostgREST version on pg_stat_activity. -- +-- >>> import Protolude -- >>> let ver = "11.1.0 (5a04ec7)"::ByteString -- >>> let strangeVer = "11'1&0@#$%,.:\"[]{}?+^()=asdfqwer"::ByteString -- diff --git a/src/PostgREST/Error.hs b/src/PostgREST/Error.hs index 39df7982d..eb746156d 100644 --- a/src/PostgREST/Error.hs +++ b/src/PostgREST/Error.hs @@ -19,6 +19,8 @@ module PostgREST.Error , JwtClaimsError(..) , errorPayload , status + , noRelBetweenHint + , noRpcHint ) where import qualified Data.Aeson as JSON @@ -57,6 +59,12 @@ import PostgREST.Error.Types import Protolude +-- $setup +-- >>> import qualified Data.HashMap.Strict as HM +-- >>> import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..)) +-- >>> import PostgREST.SchemaCache.Relationship (Relationship (..)) +-- >>> import PostgREST.SchemaCache.Routine (Routine (..), RoutineParam (..)) + -- | Encode Error to ByteString errorPayload :: (ErrorBody a, ErrorHeaders a) => Verbosity -> a -> LByteString errorPayload verb = JSON.encode . toJsonPgrstError verb diff --git a/src/PostgREST/MediaType.hs b/src/PostgREST/MediaType.hs index d0055f3bb..25e04206d 100644 --- a/src/PostgREST/MediaType.hs +++ b/src/PostgREST/MediaType.hs @@ -9,6 +9,7 @@ module PostgREST.MediaType , toContentType , toMime , decodeMediaType + , tokenizeMediaType ) where import qualified Data.Aeson as JSON @@ -22,6 +23,9 @@ import Network.HTTP.Types.Header (Header, hContentType) import Protolude +-- $setup +-- >>> import qualified Text.ParserCombinators.Parsec as P + -- | Enumeration of currently supported media types data MediaType = MTApplicationJSON diff --git a/src/PostgREST/Plan.hs b/src/PostgREST/Plan.hs index 7fd157c19..8a91fa959 100644 --- a/src/PostgREST/Plan.hs +++ b/src/PostgREST/Plan.hs @@ -24,6 +24,7 @@ module PostgREST.Plan , InfoPlan(..) , CrudPlan(..) , legacyWarnings + , addNullEmbedFilters ) where import qualified Data.HashMap.Strict as HM @@ -87,7 +88,16 @@ import Protolude hiding (from) -- $setup -- Setup for doctests +-- >>> :set -XDuplicateRecordFields -- >>> import Data.Ranged.Ranges (fullRange) +-- >>> import Data.Tree (Tree (..)) +-- >>> import PostgREST.SchemaCache.Identifiers (QualifiedIdentifier (..)) +-- >>> import PostgREST.ApiRequest.Types +-- >>> import PostgREST.Plan.CallPlan +-- >>> import PostgREST.Plan.MutatePlan +-- >>> import PostgREST.Plan.ReadPlan as ReadPlan +-- >>> import PostgREST.Plan.Types +-- >>> import Protolude -- Plan for reading or writing to the db data CrudPlan diff --git a/src/PostgREST/Response/Performance.hs b/src/PostgREST/Response/Performance.hs index 17bfe894a..85c86ab85 100644 --- a/src/PostgREST/Response/Performance.hs +++ b/src/PostgREST/Response/Performance.hs @@ -8,6 +8,9 @@ import qualified Network.HTTP.Types as HTTP import Numeric (showFFloat) import Protolude +-- $setup +-- >>> import Protolude + -- | ServerTiming represents the timing data for a request, in seconds. data ServerTiming = ServerTiming diff --git a/test/doc/Main.hs b/test/doc/Main.hs index 2269d84df..c2f2efeaa 100644 --- a/test/doc/Main.hs +++ b/test/doc/Main.hs @@ -1,27 +1,7 @@ -module Main (main) where - -import Test.DocTest (doctest) - -import Protolude +module Main where +import System.Environment (getArgs) +import Test.DocTest (mainFromCabal) main :: IO () -main = - doctest - [ "-XOverloadedStrings" - , "-XNoImplicitPrelude" - , "-XStandaloneDeriving" - , "-XDuplicateRecordFields" - , "-isrc" - , "src/PostgREST/ApiRequest/Preferences.hs" - , "src/PostgREST/ApiRequest/QueryParams.hs" - , "src/PostgREST/Config.hs" - , "src/PostgREST/Error.hs" - , "src/PostgREST/MediaType.hs" - , "src/PostgREST/Network.hs" - , "src/PostgREST/Plan.hs" - , "src/PostgREST/Query/SqlFragment.hs" - , "src/PostgREST/Response.hs" - , "src/PostgREST/Response/Performance.hs" - , "src/PostgREST/SchemaCache/Identifiers.hs" - ] +main = mainFromCabal "postgrest" =<< getArgs