Compare commits

...
Author SHA1 Message Date
Taimoor Zaeem a46ac79ea8 nix: exclude protolude from style checks
Currently, our vendored protolude has many failing checks for
style, lint and hsie. Temporarily excluding it. We should
reinstate these checks later.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-30 20:33:32 +05:00
Taimoor Zaeem a2faa667f3 chore: build postgrest with vendored protolude
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-30 19:56:33 +05:00
Taimoor Zaeem 366502729d chore: remove unneeded files and directories from src/protolude
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-30 15:38:39 +05:00
Taimoor Zaeem 7c8f79d86f chore: add .git-blame-ignore-revs
Ignore blame for commit that moved protolude files under src/protolude.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-30 14:24:21 +05:00
Taimoor Zaeem 827121b72f chore: merge protolude as subdirectory src/protolude 2026-04-30 14:17:07 +05:00
Taimoor Zaeem d4949c633e chore: move protolude files to src/protolude
Later we merge the src/protolude directory with src/PostgREST.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-30 14:16:23 +05:00
Laurence IslaandWolfgang Walther 5f6f7dca44 fix: unexpected results when embedding the same table twice 2026-04-29 09:10:48 +00:00
Wolfgang Walther ea08a4d767 ci: test build of dev shell on darwin 2026-04-28 12:56:53 +00:00
Wolfgang Walther 822f8ef802 nix: remove unused tools from dev shell
I doubt that anyone would use cabal2nix or update-nix-fetchgit manually
- and at the same time everyone surely has git installed through their
OS anyway, otherwise they can't even get that far.
2026-04-28 12:56:53 +00:00
Wolfgang Walther c8439e437c ci: use nix-build-uncached to save useless downloads
There is no point to actually realize the derivations to disk, when they
are in cache. `nix-build-uncached` checks the cache and stops before
downloading dependencies if they are available. It will however build as
normal on a cache-miss. Should speed up CI when no Nix dependencies
change a fair bit.

We can only do this for the MacOS job, which only tests the builds. We
can not do this for other jobs which require the build results to be
present before uploading parts of them as artifacts.
2026-04-28 12:56:53 +00:00
Laurence Isla dc179665dc chore: fix incorrect username in changelog entry 2026-04-27 18:22:58 -05:00
Wolfgang Walther 3ec9b94c79 ci: avoid useless download of GHC during stack builds
Forgot to adjust when updating stackage.
2026-04-27 19:52:57 +00:00
renovate[bot]andWolfgang Walther 9b9521b75a chore(deps): update korthout/backport-action action to v4.5 2026-04-27 19:51:37 +00:00
Laurence Isla 41b86fffa5 fix: no longer retries the transaction on 40001 errors 2026-04-27 14:30:10 -05:00
Taimoor ZaeemandWolfgang Walther bf758698b3 fix: login with uppercase and mixed case role names
PostgREST failed when querying role settings where current
role name contained uppercase letters. This commit resolves
it by quoting the CURRENT_USER.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-27 09:19:26 +00:00
Wolfgang WaltherandMichal Kleczek a5cc457875 chore(deps): update hasql to 1.9.3.1
Michael and I arrived at mostly the same things independently. Took some
of his, some of mine.

Co-authored-by: Michal Kleczek <michal@kleczek.org>
2026-04-27 09:12:31 +00:00
Wolfgang Walther f80122e12b ci: trigger workflows when nixpkgs pin is updated
Otherwise we might break things...
2026-04-27 08:29:41 +00:00
Wolfgang Walther 2e5baaf296 chore(deps): update nixpkgs pin 2026-04-27 08:29:41 +00:00
Wolfgang Walther 0e0bc6a2c1 chore(deps): fix docs deps
These should have been updated by postgrest-nixpkgs-upgrade, when I
upgraded the Nixpkgs pin, but I did not follow my own readme, and just
ran nix flake update...
2026-04-27 08:29:41 +00:00
Taimoor ZaeemandSteve Chavez 38829191a7 test(load): reduce num of tables in errors loadtest
The table not found error only generates hint when the total number of
tables in a schema are less than 500.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-26 12:32:47 -05:00
Taimoor ZaeemandWolfgang Walther c9253ed056 test(load): update error loadtest endpoint to generate hint
This endpoint didn't generate error hint which is not desired
for loadtest.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-24 10:30:30 +00:00
Taimoor ZaeemandWolfgang Walther a1ab388ab6 test(doctests): remove redundant doctests in Error.hs
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-23 08:23:28 +00:00
renovate[bot]andWolfgang Walther de4ad62562 chore(deps): update korthout/backport-action action to v4.4.0 2026-04-21 09:05:36 +00:00
Wolfgang Walther e2a677e21d chore: try to re-enable codecov annotations
Not sure whether this works, but it likely can't hurt.
2026-04-20 23:24:49 +02:00
Michał KłeczekandSteve Chavez baebacf3db fix: shutdown should wait for in flight requests
Upgraded warp to 3.4.13 which fixed https://github.com/yesodweb/wai/issues/853
Changed interrupt handling so that instead of killing the main thread, listening sockets are closed which triggers warp graceful shutdown.
2026-04-20 16:19:13 -05:00
Wolfgang Walther 3b1373ec02 chore: update the nix upgrade docs
These have been outdated for a while, not only because we're now using
flake.nix, but also in various other places.

Resolves #4816
2026-04-20 19:29:26 +00:00
Wolfgang Walther 695678ad40 chore: add changelog for static aarch64 builds and remove left-overs
I guess I forgot to update a few places when doing this.
2026-04-20 19:29:26 +00:00
Wolfgang Walther 92ba6d5caa ci: fix actions/cache-on-main
My recent commit to fix the stack cache on macOS only changed the
restore keys, but no cache would ever be saved that way. I effectively
disabled all caching...
2026-04-19 23:03:07 +02:00
Wolfgang Walther 6b4022b0c1 ci: fix docker push for release job
Unfortunately, `docker manifest create` does not support image digests,
so we need to push a tag for each version of the image. Furthermore, the
docker CLI does not provide a way to delete that tag afterwards, so we
will end up with those temporary tags.
2026-04-19 22:20:46 +02:00
Wolfgang Walther 0cb354be7a ci: fix stack cache for macOS
We now have two stack jobs for macOS, but they use the same cache, which
is very inefficient. Adding the architecture to the cache key will give
each of these jobs a separate cache.
2026-04-19 21:48:06 +02:00
Wolfgang Walther 1c869bf3a6 ci: remove builds for GHC 9.6.7 and 9.8.4
Now that we can build with at least GHC 9.10 on all platforms, there is
no need to keep testing these older versions anymore.
2026-04-19 20:17:48 +02:00
Wolfgang Walther fee820bac2 chore: release static executable for aarch64-linux
Also makes the aarch64 variant of the docker image consist of a single
static executable, similar to the x86_64 variant.
2026-04-19 17:53:48 +00:00
Wolfgang WaltherandMichal Kleczek 1676314fc3 nix: build with GHC 9.12.3
Jumping past GHC 9.6, 9.8 and 9.10 immediately, because these versions
do not successfully build the static binary with TemplateHaskell and
iserv-proxy, yet.

Michal wrote the changes to hsie.

Co-authored-by: Michal Kleczek <michal@kleczek.org>
2026-04-19 17:53:48 +00:00
Wolfgang Walther 49a16fe505 ci: build with cabal and GHC 9.12.3 2026-04-19 17:50:23 +00:00
Wolfgang Walther 43447ed711 test: fix two doctests
Spotted them randomly while debugging something else.
2026-04-19 19:10:56 +02:00
Wolfgang Walther edbd2a3dca chore: remove renovate haskell updates
These don't really make sense, because it's non-trivial to construct a
build plan that *ensures* the dependency that renovate creates a PR for
is tested with the latest version. Cabal might just select a build plan,
that doesn't include the dependency, in which case we could just as well
have no upper bounds at all.

Since there is no good way to test these changes (I tried, a while
ago!), let's just disable these PRs. They are more annoying than
anything else.
2026-04-19 18:38:51 +02:00
Wolfgang Walther 03f7234360 ci: test against PostgreSQL 18 2026-04-19 13:16:55 +00:00
Wolfgang Walther d79f28fd75 chore: fix stack.yml's nix integration once more
We don't need an impure environment anymore, because we can't run the
test suite via stack anyway.
2026-04-19 13:16:55 +00:00
Wolfgang Walther 051b4799de chore(deps): update nixpkgs to latest nixpkgs-unstable
This allows building TemplateHaskell with GHC 9.6+ via iserv-proxy.
2026-04-19 13:16:55 +00:00
Wolfgang Walther 1b74b93466 remove: drop support for PostgreSQL 13
PostgreSQL 13 has been EOL since November 2025 and will not be available
in the next Nixpkgs bump anymore.
2026-04-19 13:16:55 +00:00
Wolfgang Walther 4ccb125e85 chore: remove outdated comment
We started actually depending on postgresql-libpq in
5356f4e973.
2026-04-19 13:52:19 +02:00
steve-chavezandWolfgang Walther b6c6bb27a8 ci: reinstate macos x86 releases
Closes https://github.com/PostgREST/postgrest/issues/4755
2026-04-19 11:26:06 +00:00
Wolfgang Walther 1f70e42d3b ci: build with cabal and GHC 9.10.3 2026-04-19 10:07:14 +00:00
Wolfgang Walther be7a42ff30 chore: stackage 23.28 -> 24.37
This updates stack builds to GHC 9.10.3.
2026-04-19 10:07:14 +00:00
Wolfgang Walther 9ed7f52685 nix: put tmpdirs directly into /tmp to fix long unix socket paths
I'm not sure whether that's Lix specific, but when I enter nix-shell, I
get quite a long TMPDIR, which results in all postgrest-with-pg-XX
scripts failing, because the unix socket path is too long. If TMPDIR was
not set, mktemp would fall back to /tmp, so we can just do that in any
case, which guarantees a short path in every case.
2026-04-18 20:53:21 +02:00
Wolfgang Walther dfb3602318 nix: remove left-over comment 2026-04-18 20:53:20 +02:00
Wolfgang Walther f1cd9a2136 chore: stackage 22.44 -> 23.28
This updates stackage builds to GHC 9.8.4.
2026-04-18 18:38:32 +00:00
Taimoor ZaeemandWolfgang Walther 759917772c chore: add changelog entry for v14.10
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-17 10:20:30 +00:00
steve-chavez bcc8998e5e add: log schema cache queries' timings
This adds a new log line that shows each schema cache query time individually, only on
`log-level=debug`. Like so:

```
$ PGRST_LOG_LEVEL=debug postgrest-with-pg-17 -f test/spec/fixtures/load.sql postgrest-run

....
10/Apr/2026:21:48:45 -0500: Schema cache queried in 192.2 milliseconds
10/Apr/2026:21:48:45 -0500: tables: 72.027 ms, keydeps: 20.118 ms, rels: 6.189 ms, funcs: 35.010 ms, comprels: 4.319 ms, dreps: 1.614 ms, mhandlers: 7.419 ms, tzones: 43.025 ms
```

This helps debug specific schema cache queries being slow like on
https://github.com/PostgREST/postgrest/issues/4613#issuecomment-4210191065 and
https://github.com/PostgREST/postgrest/issues/3046#issuecomment-3469059948.
It also closes https://github.com/PostgREST/postgrest/issues/3215,
which main motivation was to find out which query is slow.

Implementation details
---------------------

To time each query inside a transaction in pure SQL, we do:

```sql
-- start timer
select set_config('pgrst.tmp_x', clock_timestamp()::text, false);
-- run the query
select <query>
-- end timer
select set_config('pgrst.tmp_x', (clock_timestamp() - current_setting('pgrst.tmp_x', false)::timestamptz)::text, false);

-- .... repeated for every query

-- at the end we capture all the timings with
select extract('milliseconds' from current_setting('pgrst.tmp_x', false)::interval), extract(..;
```

Considerations
--------------

Only added this on `log-level=debug` because while the queries are fast
and the data is valuable, it triples the amount of queries we run during schema cache refresh,
which could be troublesome on slow networks. It's possible to reduce the
amount of queries by starting and stopping timers in one statement, but
this would still double the amount of queries and makes the code messy,
doesn't seem worth it.

Also it would pollute pg_stat_statements, it's only required to debug certain
extreme cases anyway.
2026-04-16 13:10:24 -05:00
steve-chavez 6af77360d3 docs: add note about schema cache queries 2026-04-16 13:10:24 -05:00
renovate[bot]andWolfgang Walther f939a81ad6 chore(deps): update ubuntu:noble docker digest to c4a8d55 2026-04-16 10:44:13 +00:00
renovate[bot]andWolfgang Walther bf8a52694a chore(deps): update haskell-actions/setup action to v2.11.0 2026-04-15 18:05:32 +00:00
Wolfgang Walther 4fbde347f8 docs: fix broken link 2026-04-15 09:29:35 +02:00
Michal KleczekandGitHub aca58c8571 fix: Flush pool as late as possible during schema cache reloading (#4645)
retryingSchemaCacheLoad flushes the pool upon every retry before it starts reloading the schema. This is too early as schema reloading might take some time during which new connections might be acquired. The consequence is that:
* upon successful schema cache reload we might have some connections created with the old schema cache
* we close connections upon each retry and under load we will keep closing and re-opening connections until schema cache load succeeds

This change is to make sure we flush the pool only after successful schema cache querying but before loading (so that connections acquired during loading wait for it and do not interfere with timing the loading process).
2026-04-14 17:09:25 -05:00
Taimoor ZaeemandSteve Chavez 4ca34c0695 chore: update cabal spec version in postgrest.cabal
The current version is too old and it prevented using latest features
like common stanzas and visibility fields.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-14 12:16:48 -05:00
renovate[bot]andWolfgang Walther 26ce39bb46 chore(deps): update actions/cache action to v5.0.5 2026-04-13 21:04:11 +00:00
Taimoor ZaeemandSteve Chavez 4e8c4f218f chore: add changelog entry for v14.9
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-13 11:15:18 -05:00
renovate[bot]andWolfgang Walther 070eb2fc3a chore(deps): update actions/create-github-app-token action to v3.1.1 2026-04-12 15:51:35 +00:00
renovate[bot]andWolfgang Walther 431f8586f5 chore(deps): update actions/upload-artifact action to v7.0.1 2026-04-12 15:25:15 +00:00
steve-chavez c9adaed79d docs: target_session_attrs=read-only in libpq>=14 2026-04-10 15:14:41 -05:00
Michał KłeczekandSteve Chavez 381e12efa2 refactor: remove usage of Control.Debounce
This change replaces usage of Control.Debounce in Logger with makeDebouncer function extracted from AppState to a new module PostgREST.Debounce.
2026-04-10 12:22:08 -05:00
Michał KłeczekandSteve Chavez f4fc29855e refactor: remove leftover comment in AppState 2026-04-10 12:22:08 -05:00
steve-chavez 2fb2e86473 fix: remove red herring warp logs on default log-level
The logs added on e95e815483 are red
herrings under normal operation.

This moves them to `log-level=debug` and removes "error" from the
message prefix.

Fixes https://github.com/PostgREST/postgrest/issues/4799
2026-04-09 16:44:25 -05:00
Michał KłeczekandSteve Chavez c31aeecdcf test: add test_pool_acquisition_timeout_logs_are_debounced to io tests 2026-04-09 13:59:17 -05:00
Michał KłeczekandSteve Chavez 5d4f82d70f add: log pool flushes
Emit a dedicated PoolFlushed observation when the DB pool is released during schema cache reload.
2026-04-09 10:41:29 -05:00
Michał KłeczekandSteve Chavez ad907219be test(refactor): make debug output testing more robust
This change introduces a match_log function, that implements lenient matching of log output lines. Tests of log output are retrofited to use the function.
2026-04-09 10:41:29 -05:00
renovate[bot]andWolfgang Walther 463b701e9f chore(deps): update haskell-actions/setup action to v2.10.4 2026-04-09 08:48:59 +00:00
Steve Chavez 3d98f8d65b refactor: clarify debouncer function 2026-04-07 13:44:03 -05:00
Michał KłeczekandSteve Chavez a4c1d945ee refactor: Simplify schema cache loading triggering logic
DISCLAIMER:
This commit was authored entirely by a human without the assistance of LLMs.

Using debouncer to trigger schema cache loading makes it difficult to understand when exactly it is triggered.
2026-04-07 13:44:03 -05:00
renovate[bot]andWolfgang Walther ff068aa1b7 chore(deps): update ubuntu:noble docker digest to 84e77de 2026-04-07 08:10:36 +00:00
Taimoor ZaeemandSteve Chavez 9e48a338c3 chore: add changelog entry for v14.8
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-06 10:50:16 -05:00
steve-chavez b610b1ea51 docs: clarify set operators need views/functions
Closes https://github.com/PostgREST/postgrest/issues/4780.
2026-04-03 17:02:21 -05:00
Artur Bento de CarvalhoandGitHub 69c6a0aa36 fix: use int32/int64 formats for integer types
Fixed integer type mapping in OpenAPI 2.0: replaced the invalid integer format with int32/int64 and added the toSwaggerFormat function to map PostgreSQL types to valid OpenAPI 2.0 formats:

smallint -> int32
integer -> int32
bigint -> int64
2026-04-03 14:21:32 -05:00
renovate[bot]andWolfgang Walther a5e66a4448 chore(deps): update docker/login-action action to v4.1.0 2026-04-02 20:07:13 +00:00
Michał KłeczekandSteve Chavez 328598eaed test: Schema cache load debouncing
test: adjust replicateM to 100
2026-04-02 09:02:18 -05:00
Taimoor ZaeemandSteve Chavez d6c338d588 add: config db-timezone-enabled for optional querying of timezones
To avoid repeated querying of `pg_timezone_names` every time schema
cache is reset, `Prefer: timezone` can be disabled by setting
`db-timezone-enabled = false`.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-04-01 12:48:38 -05:00
Michał KłeczekandSteve Chavez bd5de884fa test(io): add test_so_reuseport_zero_downtime_handover 2026-03-31 13:33:33 -05:00
Michal KleczekandGitHub 8d5b1018d3 refactor(test): provide means to validate metrics and observations
Some helpers are provided for introspecting metrics already (used in JWT cache tests). This change provides facilities to additionally validate emited Observation events.
A new Spec module is also implemented, adding basic tests of schema cache reloading - their main goal is to excercise the new infrastructure.
2026-03-31 13:15:56 -05:00
renovate[bot]andWolfgang Walther ae7d4d2553 chore(deps): update codecov/codecov-action action to v6 2026-03-27 10:34:37 +00:00
renovate[bot]andWolfgang Walther 88afa05cf8 chore(deps): update korthout/backport-action action to v4.3.0 2026-03-27 08:45:54 +00:00
Taimoor ZaeemandWolfgang Walther 748ba7f02b chore: remove blank line in CHANGELOG.md
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-27 08:44:09 +00:00
Taimoor ZaeemandWolfgang Walther 0b665ecd10 chore: correct config name in CHANGELOG.md
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-27 08:44:09 +00:00
Taimoor ZaeemandSteve Chavez 1b402d16ad test(spec): move preference tests into separate modules
Towards #4751.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-26 12:36:47 -05:00
Taimoor ZaeemandSteve Chavez 135b77d12b test(io): rename jwt-role-claim-key*.config dump files
These files were added to cover the config dumping of
string comparison operators in `JSPath`. Renaming and
adding a comment in these to make it clear.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-24 11:11:43 -05:00
steve-chavez effcc080e5 chore: put ai policy first in CONTRIBUTING
Otherwise it's not that visible.
2026-03-23 10:10:58 -05:00
arturbent0andWolfgang Walther 5e504a77fa docs: clarify debounce time window in schema cache reloads 2026-03-23 12:04:01 +00:00
arturbent0andWolfgang Walther c9c6ebb53a docs: add new terms to spellcheck dictionary 2026-03-23 12:04:01 +00:00
Artur Bento de CarvalhoandWolfgang Walther 941c2f2d17 docs: explain schema cache reload behavior with NOTIFY debouncing
Add a "debouncing" section to explain how PostgREST handles multiple NOTIFY events.
2026-03-23 12:04:01 +00:00
Taimoor ZaeemandWolfgang Walther bf7dc485b3 chore: add changelog entry for v14.7
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-23 11:22:29 +00:00
steve-chavez 622c6d3f19 fix: not logging termination unix signals
Under container environments like ECS, it's hard to know when PostgREST
is being terminated.
2026-03-20 13:09:10 -05:00
Taimoor ZaeemandSteve Chavez 12ef63370b nix(test): add test suite for observability tests
- Create separate test suite for observability tests

- Create wrapper script `postgrest-test-observability`

- Add to CI and `postgrest-check`

- Move JWT cache tests under observability tests

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-19 10:38:42 -05:00
renovate[bot]andWolfgang Walther 796339172c chore(deps): update ubuntu:noble docker digest to 186072b 2026-03-19 09:16:11 +00:00
renovate[bot]andWolfgang Walther 238e9078bf chore(deps): update cachix/cachix-action action to v17 2026-03-18 21:19:20 +00:00
renovate[bot]andWolfgang Walther 1934179c64 chore(deps): update codecov/codecov-action action to v5.5.3 2026-03-18 20:02:06 +00:00
renovate[bot]andWolfgang Walther 88c365fb52 chore(deps): update actions/cache action to v5.0.4 2026-03-18 19:08:42 +00:00
Taimoor ZaeemandSteve Chavez 0ff8a1a37a refactor(auth): use wildcard type constructor import
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-18 13:09:27 -05:00
renovate[bot]andWolfgang Walther c448712e88 chore(deps): update ubuntu:noble docker digest to 0d39fcc 2026-03-17 10:19:37 +00:00
Taimoor ZaeemandSteve Chavez d4ba41bd43 nix(shell): bypass proxy variables using NO_PROXY=*
Tested using:

```sh
export HTTP_PROXY=http://localhost:7890
nix-shell
postgrest-test-io
```

Closes #4633.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-16 10:53:10 -05:00
Taimoor ZaeemandSteve Chavez 40a1fea916 refactor: move role insertion in claims to PreQuery.hs
Also add a comment on `AuthResult` type to explain that
we can also access the claims in the db using GUCs.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-16 10:24:24 -05:00
Andrei DziahelandSteve Chavez 1f54e2accc add: add "Vary" header to responses
Co-authored-by: Steve Chavez <stevechavezast@gmail.com>
2026-03-16 09:55:20 -05:00
renovate[bot]andWolfgang Walther d5df12c9c2 chore(deps): update actions/create-github-app-token action to v3 2026-03-14 18:04:36 +00:00
steve-chavezandWolfgang Walther af4c4157f5 nix: remove uneeded slocat
slocat was introduced to test pipeline mode (see https://github.com/PostgREST/postgrest/pull/2682),
but pipeline mode was not merged https://github.com/PostgREST/postgrest/pull/2707.

So it's really not needed on the loadtests.
2026-03-13 18:56:31 +00:00
renovate[bot]andWolfgang Walther 5ff271592c chore(deps): update ubuntu:noble docker digest to d1e2e92 2026-03-13 14:06:41 +00:00
renovate[bot]andWolfgang Walther bb4358c8bb chore(deps): update cachix/cachix-action digest to 3ba601f 2026-03-13 14:06:12 +00:00
renovate[bot]andWolfgang Walther 2ab2706c8e chore(deps): update actions/cache action to v5.0.3 2026-03-13 14:05:23 +00:00
renovate[bot]andWolfgang Walther b83fbb76a9 chore(deps): update haskell-actions/setup action to v2.10.3 2026-03-13 14:04:41 +00:00
renovate[bot]andWolfgang Walther fb54db143d chore(deps): update actions/checkout action to v6.0.2 2026-03-13 14:03:45 +00:00
renovate[bot]andWolfgang Walther 8ee8cdd7f8 chore(deps): update github artifact actions 2026-03-12 21:08:47 +00:00
Michał KłeczekandSteve Chavez bee2ea6fa6 test(io): add test_graceful_shutdown_waits_for_in_flight_request 2026-03-12 15:24:46 -05:00
Michał KłeczekandSteve Chavez a4aa58b4de refactor: move socket creation and management to App module
Right now listening sockets initialization, management and usage is split between App, AppState and Admin modules: they are created in AppState.init and remembered in AppState but used only in App and Admin.

It has several negative consequences:
- sockets are initialized even if not needed (eg. command line invocations like dump-config or dump-schema)
- it is impossible to start listening on a socket after initial schema cache load because it requires AppState

This change decouples listen socket management from AppState. Sockets are created only when needed (ie. not in command line tools invocation) and passed to admin application and to Warp by the App module.
2026-03-12 10:03:47 -05:00
Michał KłeczekandSteve Chavez e741c1bca7 refactor: provide AppState infrastructure to wait for schema cache load
This commit replaces ioRef based implementation of schema cache status tracking to MVar based, so that it is possible to wait for schema cache loading.

Waiting for schema cache loading is necessary to implement zero-downtime upgrades  with SO_REUSEPORT, where listening on a socket must wait for schema cache loading.
2026-03-12 09:04:56 -05:00
Wolfgang WaltherandAndrei Dziahel d5694672a4 nix(flake): add devShell
Adds a devShell to the flake for use with `nix develop`.

Co-authored-by: Andrei Dziahel <develop7@develop7.info>
2026-03-11 19:50:01 +00:00
Wolfgang Walther ca858f7544 docs: fix prometheus text format link
Reported by linkcheck.
2026-03-11 08:48:49 +01:00
renovate[bot]andWolfgang Walther cab60b9ee8 chore(deps): update docker/setup-buildx-action action to v4 2026-03-10 18:40:00 +00:00
steve-chavezandWolfgang Walther 0b7f0197fc chore: update license 2026-03-10 16:41:42 +00:00
Taimoor ZaeemandSteve Chavez 93db1a5a47 refactor: remove redundant parameters from actionResponse
Towards #4608.

We already have access to these parameters via `ApiRequest` type,
hence no need to pass them separately.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-10 09:55:42 -05:00
renovate[bot]andWolfgang Walther f657ac4e0b chore(deps): update docker/login-action action to v4 2026-03-10 14:15:16 +00:00
Taimoor ZaeemandSteve Chavez f5b9ed28db nix(chore): remove defunct config in loadtest.nix
`PGRST_JWT_CACHE_MAX_LIFETIME` is defunct since #4084 is merged.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-09 15:46:23 -05:00
renovate[bot]andWolfgang Walther 0eb2bdd8e1 chore(deps): update korthout/backport-action action to v4.2.0 2026-03-09 13:13:13 +00:00
Taimoor ZaeemandSteve Chavez 58368513ab chore: add changelog entry for v14.6
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-08 21:01:30 -05:00
Taimoor ZaeemandSteve Chavez 5abacba0d8 fix(error): leaking table and function names when calculating hint
Increase similarity score to 0.75 from 0.33 for table and functions
error hint.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-06 16:03:21 -05:00
Laurence Isla 2861b35f41 chore: update sponsors
* The list of sponsors is now ordered by total contribution value (highest first)
* Removed former backers from sponsor pages
2026-03-03 22:02:18 -05:00
steve-chavez 4e4ae3c7a2 chore: add AI policy in CONTRIBUTING
To preserve our scarce review capacity, we reserve the right to reject
seemingly AI generated low-value contributions.

---

Also delete the first paragraph since now it can be interpreted as
low-effort contributions.
2026-03-03 19:56:08 -05:00
steve-chavez 1c6d0816a5 chore: mention tests are required in CONTRIBUTING
Also remove the Haskell conventions subtitle since these are general
recommendations.
2026-03-02 17:57:01 -05:00
Laurence Isla 341e40196d chore: update sponsor 2026-03-02 17:36:04 -05:00
Michał KłeczekandSteve Chavez 8e1f0a0471 refactor: standardize query logging to follow code logging other observations
This commit addresses the following TODO in observationMessage function:
"TODO pending refactor: The logic for printing the query cannot be done here. Join the observationMessages function into observationLogger to avoid this mempty."

Changing observationMessage to observationMessages (that returns [Text] instead of Text) made it possible to address issue documented as TODO and harmonize query logging with other observations.
2026-03-02 15:46:17 -05:00
Michał KłeczekandSteve Chavez 2408cd332d refactor: get rid of redundant SchemaCacheSummaryObs
There is unnecessary coupling between observation messages and emited log entries. This causes schema loading logic to emit redundant events: SchemaCacheSummaryObs and SchemaCacheLoadedObs.

Logically - we want to emit a single event containing both summary and timing information. How it is logged is a different matter and should be decoupled.

This commit
* changes observationMessage function returning Text to observationMessages returning [Text] so that it is possible to return multiple (or zero) messages to log based on an observation event
* Removes SchemaCacheSummaryObs constructor from Observation type and adds summary text to SchemaCacheLoadedObs
2026-03-02 14:45:31 -05:00
Michał KłeczekandSteve Chavez 58a973e664 refactor: make Observation Logger and Listener modules more cohesive
Observation module exports observationMessage and isDbListenerBug functions. The first one is used only in Logger module and the second one - only in Listener.

This change moves observationMessage function to Logger module and isDbListenerBug function to Listener module, making all three modules more cohesive and lessening dependencies.
It also gives the compiler more opportunities for intra-module inlining and optimization.
2026-03-02 12:26:22 -05:00
Taimoor ZaeemandSteve Chavez a36963026e docs: add client error verbosity section to errors page
Add a new section "Client Error Verbosity". Move the details from
the config page to this section and link it.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-03-02 12:07:55 -05:00
Michał KłeczekandSteve Chavez 78f231c87a refactor: failure in schema cache load should not set listener delay
Listener has its own backoff logic independent of schema cache loading. It also uses listener delay value to identify its retries and to trigger schema cache reloads upon failures.
If schema cache reloading sets listener delay it might lead to some unexpected reloading loops.
That's especially important in set ups where listener connection points to master and the pool to replica(s).
2026-02-25 17:34:38 -05:00
Taimoor ZaeemandSteve Chavez 5992430e9f chore: update CHANGELOG.md
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-25 15:24:27 -05:00
Taimoor ZaeemandSteve Chavez 83dc082acf add: config client-error-verbosity to set error verbosity
Set error verbosity using this config. The verbosity can
be set to `verbose` or `minimal` for client error responses.

This only affects client side HTTP responses, server side logs
are not affected by this config.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-25 15:24:27 -05:00
Taimoor ZaeemandSteve Chavez 2edc44c352 refactor: remove ToJSON instance definition on error types
Towards #4088.

- Some of these instances are not used. Reduces number of lines
  significantly.

- Removing this gives us more flexibility for cases like conditional
  encoding based on some outside parameter, without needing to
  add the conditional at type level.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-23 12:10:51 -05:00
Taimoor ZaeemandSteve Chavez 02feaf087e refactor: remove commented out code from Auth/Jwt.hs
Some commented out code got left in the codebase in
5196823365.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-20 11:07:30 -05:00
Taimoor ZaeemandSteve Chavez c52fd3fd2b refactor: rename ApiRequestError type constructor to ApiRequestErr
Rename to keep the naming convention consistent with other
type constructor names.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-19 11:29:51 -05:00
Taimoor ZaeemandSteve Chavez 248b777117 refactor: move error data types to Error/Types.hs
The `Error.hs` module is getting bloated. This moves types
to another module for better separation of concerns.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-19 11:29:51 -05:00
steve-chavez 66fda76644 docs: missing link to prefer:tx in config page 2026-02-19 10:23:22 -05:00
dshukertjrandWolfgang Walther 23692ab8e7 docs: Update the Supabase logo to a correct one 2026-02-19 09:52:46 +00:00
Taimoor ZaeemandWolfgang Walther b977ffbb90 test(io): reset statement_timeout of anon role to correct value
Forgot to do this in bfb4f900e7.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-18 12:46:30 +00:00
Michał KłeczekandSteve Chavez 85a313a8cc test(spec): Move metrics state helpers from JwtCacheSpec to SpecHelpers
Refactoring: State validation helpers used in JwtCacheSpec moved to SpecHelper
to make them available in other Spec modules.
2026-02-17 17:55:16 -05:00
Taimoor ZaeemandSteve Chavez bfb4f900e7 test(io): increase statement_timeout value of anonymous role
It is too low which leaves a small window of values to
use when testing other features.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-17 11:35:12 -05:00
Taimoor ZaeemandSteve Chavez 055efe7abd refactor: move Proxy-Status header to error type class
Headers that apply to all errors should all be in one place.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-16 13:09:01 -05:00
Michał KłeczekandSteve Chavez ca96328142 refactor: Remove unnecessary lazy initialization of stateLogDebouncePoolTimeout
stateLogDebouncePoolTimeout is an MVar initialized on the first logging of PoolAcqTimeoutObs. The code in logWithDebounce has race condition that could lead to creation of multiple debouncers.

This change simplifies logic by getting rid of lazy initialization of debouncer.
2026-02-15 13:14:10 -05:00
Michał KłeczekandSteve Chavez d6816d8d2a refactor: Remove unnecessary SQL.UsageError parameter from PoolAcqTimeoutObs
PoolAcqTimeoutObs is always created with SQL.AcquisitionTimeoutUsageError so the parameter does not provide any useful information.
On the other hand, it complicates debouncing logic in Logger as logWithDebounce has to lazily create the debouncer (which is error prone and hence the logic has a race condition).

This change removes the parameter from PoolAcqTimeoutObs. It is a prerequisite to simplifying logWithDebounce.
2026-02-15 13:14:10 -05:00
Taimoor ZaeemandSteve Chavez c5d495006a chore: add changelog entry for v14.5
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-13 08:58:57 -05:00
steve-chavez abe414ad88 nix: print how to tail the server logs
For easier debugging during loadtests.

Also prefix the echo traces for the postgrest-with-pgrst command.
2026-02-12 20:18:08 -05:00
steve-chavez e95e815483 fix: don't hide async exceptions in logs
Fixes #4646. Using the repro on #4646, this now produces the log:

```
11/Feb/2026:09:40:08 -0500: Warp server error: stack overflow
```

When:
```
$ curl localhost:3000/
curl: (52) Empty reply from server
```
2026-02-12 19:43:50 -05:00
Taimoor ZaeemandWolfgang Walther c3500bd3af docs(install): update postgresql minimum supported version
PostgREST dropped support for PostgreSQL version 12 however,
it was not reflected in the docs.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-12 09:22:01 +00:00
Taimoor ZaeemandSteve Chavez 99984d328e docs: add section on docker resource constraints
Closes #4623.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-06 16:30:47 -05:00
Taimoor ZaeemandSteve Chavez aaaf7e96bd test(io): set client_min_messages to warning in SQL fixtures
To suppress unwanted "NOTICE: ..." messages which pollute the log.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-04 09:20:03 -05:00
Taimoor ZaeemandSteve Chavez 37fc0a211b test(io): refactor SQL fixtures
- Move privileges and grants to privileges.sql
- Move schema, tables and functions to schema.sql
- Move global database settings to database.sql

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-04 09:20:03 -05:00
Taimoor ZaeemandSteve Chavez c35eb7a6c2 test(io): move role fixtures to roles.sql
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-02 17:38:32 -05:00
Taimoor ZaeemandSteve Chavez 2bd4b07418 chore: add entry for a feature which was a breaking change
Adds the associated breaking change entry in CHANGELOG.md
for #4517.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-02-02 09:14:58 -05:00
steve-chavez 55cd5a23ff chore: move fixed entry to feature in changelog 2026-01-30 16:23:30 -05:00
Taimoor ZaeemandSteve Chavez 72a9d70f09 chore: add changelog entry for v14.4
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-01-30 08:46:47 -05:00
Laurence Isla d10c779fc6 perf: optimize count=exact when there's no limits, offsets or db-max-rows 2026-01-28 18:43:44 -05:00
Laurence Isla d031bb2df5 refactor: use a single function to get the page_total count 2026-01-28 18:43:44 -05:00
Michal KleczekandGitHub 73a465501e fix: listener running with exception masked after first failure 2026-01-28 17:13:59 -05:00
Wolfgang Walther 6f1fe69433 docs: add Wolfgang Walther as author
This was done in other places in
ffa393850a, but missed in the docs.
2026-01-28 09:59:42 +01:00
Wolfgang Walther 246239f42a docs: fix links
datrium.com doesn't exist anymore, while euronodes.com seems to only
fail SSL in CI.
2026-01-28 09:57:09 +01:00
Laurence Isla 1682677297 fix: filtering the returned representation whenn using or/and filters on mutations 2026-01-27 21:24:19 +00:00
Michał KłeczekandSteve Chavez 21b8c3458a add: Log pg version details of listener connection
Follow-up to #4617 adding more information to log entry produced upon successful listener connection establishement.
2026-01-27 15:44:05 -05:00
Michał KłeczekandSteve Chavez 5356f4e973 add: Log actual host and port of listener connection
Diagnosing problems with listener channel notifications not being handled properly by PostgREST connected to read replicas is difficult. Issues might be related to lost connections and listener not being connected to the right host after failover or database server restarts.
This patch adds logging of actual host:port used by libpq connection opened by the listener. It should make it easier to find out if PostgREST is connected to the right host.
2026-01-27 11:00:30 -05:00
Michal KleczekandGitHub 00c7cb1a22 fix: ensure Listener connections are released
retryingListen function potentially leaks database connections. This patch ensures the connections are released in case of listen/notify errors.
2026-01-26 16:26:24 -05:00
Taimoor ZaeemandSteve Chavez d75b1a7e96 docs: using default parameters on RPC with GET request
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-01-26 08:06:48 -05:00
Taimoor ZaeemandGitHub fe0386e9c4 add: string slicing operator for jwt-role-claim-key (#4603) 2026-01-24 05:40:21 -05:00
Taimoor ZaeemandWolfgang Walther 5a4c11c72a chore(ci): correct slightly misleading name of coverage workflow
The coverage workflow mentions that we run the tests against PG 15,
however that is incorrect and misleading. We actually run it against the
latest supported PostgreSQL version according to the nix scripts.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-01-18 14:53:52 +00:00
Laurence IslaandGitHub c15e908266 add(logs): Include a HINT when the LISTEN channel breaks due to a Postgres bug
The HINT shows a SQL command that solves the issue.
2026-01-18 18:47:53 +07:00
Taimoor ZaeemandSteve Chavez c18727ff43 refactor: move walkJSPath to Config/JSPath.hs module
The logic to evaluate `JSPath` belongs to `JSPath.hs` module.
Hence, moving this logic from `Auth/Jwt.hs` to here.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-01-14 22:34:08 +07:00
Michał KłeczekandSteve Chavez 886df84e87 test: Fix flakiness of test_second_request_for_non_existent_table_should_be_quick
Changed divider in assertion (response.elapsed.total_seconds() < first_duration / divider) to 2 (from 10).
2026-01-13 11:37:50 +07:00
renovate[bot]andWolfgang Walther 8f5fe3f46b chore(deps): update haskell-actions/setup action to v2.10.2 2026-01-11 17:31:31 +00:00
steve-chavez ffa393850a chore: update LICENSE 2026-01-11 11:59:31 +08:00
Kian-Meng AngandSteve Chavez f5c7cde9b7 docs: fix typos
Found via `codespell -S test -L notin,nam,plantext,cryto,corelation,inout,ot`
2026-01-06 05:24:51 +08:00
renovate[bot]andWolfgang Walther 0018c38f79 chore(deps): update haskell-actions/setup action to v2.10.1 2026-01-05 19:02:21 +00:00
Taimoor ZaeemandSteve Chavez 9042457326 chore: add changelog entry for v14.3
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-01-04 13:13:00 +08:00
Taimoor ZaeemandSteve Chavez e988fe49ed chore: move changelog entry to unreleased section
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-01-03 15:18:51 +08:00
Michał KłeczekandSteve Chavez e592d568c6 fix: Performance and high memory usage of relation hint calculation
* Calculation of hint message when requested relation is not present in schema cache requires creation of a FuzzySet (to use fuzzy search to find candidate tables). For schemas with many tables it is costly.
This patch introduces dbTablesFuzzyIndex in SchemaCache to memoize the FuzzySet creation.

* Additionally, because of FuzzySet large memory requirements, this patch introduces a limit of 500 relations per schema, above which FuzzySet is not created and hint calculation disabled.
2026-01-03 07:56:12 +08:00
Taimoor ZaeemandSteve Chavez 9ec5b030ce refactor: move content negotiation logic to Negotiate.hs
Moves the `negotiateContent` function to `Plan/Negotiate.hs`
module. This also adds comments to describe the current approach
we have for negotiation.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-01-02 06:32:17 +08:00
steve-chavez 76e0e1fbff nix: fix sleep default on postgrest-with-pgrst
The sleep was always applying since it had a default.
2026-01-02 06:11:07 +08:00
steve-chavez b8ca1bb04c nix: add new loadtest for errors
Also included it in CI.
2025-12-23 15:00:24 -05:00
steve-chavez 57c5ff5db3 nix: show wait time for fixture loading 2025-12-23 15:00:24 -05:00
steve-chavez 2b83dcc794 nix: sleep param for withPgrst 2025-12-23 15:00:24 -05:00
steve-chavez 7c3bccf4ba nix: show wait time on withPgrst 2025-12-23 15:00:24 -05:00
steve-chavez d2aa6c1b8a nix: timeout param for withPgrst 2025-12-23 15:00:24 -05:00
Taimoor ZaeemandSteve Chavez a329bca16b nix: add config file for hlint
Adds a config file for hlint containing arguments and
custom warnings.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-12-22 14:19:46 -05:00
388930336d refactor: fix definition of Ord instance for Routine type (#4577)
The `Ord` instance definition for type `Routine` had a logical
error when comparing two routines. The error did not affect any
end users. However, for correctness and completeness reasons, this
commit fixes the error.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
Co-authored-by: Joel Jacobson <joel@compiler.org>
2025-12-22 08:34:29 +00:00
renovate[bot]andWolfgang Walther d06377a37b chore(deps): update docker/setup-buildx-action action to v3.12.0 2025-12-20 20:25:19 +00:00
Taimoor ZaeemandSteve Chavez eed018fe1d chore: add changelog entry for v14.2
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-12-19 12:29:57 -05:00
steve-chavez 013f078bc4 fix: inaccurate Server-Timing durations
The transaction duration was notably off, doing:

```
curl localhost:3000/rpc/sleep?seconds=5 -i
```

Shows `46.1` for the `transaction;dur`, with this fix we obtain
`5007.3`.

Fixes https://github.com/PostgREST/postgrest/issues/4522

This also fixes inaccurate "schema cache queried" logs,
see https://github.com/PostgREST/postgrest/issues/4551.
2025-12-18 17:35:18 -05:00
renovate[bot]andWolfgang Walther 2bcd336400 chore(deps): update haskell-actions/setup action to v2.9.1 2025-12-17 18:01:04 +00:00
steve-chavez 8f34afd66e nix: jwt loadtest chain commands and split rsa gen
Chaining the target generation command after the build is done ensures
that if a build takes too long, the dynamic target generation for vegeta
won't cause 401 Unauthorized errors due to already expired JWTs.

Also split the rsa materials writing to another python program for
easier maintenance.
2025-12-16 21:15:28 -05:00
steve-chavez 4cdc4c4861 nix: show build time on postgrest-with-pgrst 2025-12-16 21:15:28 -05:00
steve-chavez 050554e2bb nix: fail jwt loadtest in case of 401
Also print last unauthorized body
2025-12-16 21:15:28 -05:00
Taimoor ZaeemandSteve Chavez b3b7bd9327 docs: add link on how to start docker service
Closes #4552.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-12-16 11:34:04 -05:00
renovate[bot]andWolfgang Walther dac8a5fb86 chore(deps): update haskell-actions/setup action to v2.9.0 2025-12-15 21:01:22 +00:00
Joel JakobssonandGitHub fd6a3bdccf fix: hasSingleUnnamedParam incorrectly matching named parameters
The hasSingleUnnamedParam function was only checking the parameter type
but not whether the parameter actually had no name. This caused functions
with a single NAMED parameter (e.g., `foo(data json)`) to incorrectly
match the single-param fallback mode.

The result was a confusing PostgreSQL error 42883 "function does not exist"
instead of a clean PGRST202 error explaining that no matching function
was found.

Added ppName == mempty check so functions with named parameters don't
incorrectly match the single-param fallback.
2025-12-15 15:34:48 -05:00
renovate[bot]andWolfgang Walther 60c70c5b37 chore(deps): update korthout/backport-action action to v4.0.1 2025-12-15 20:18:02 +00:00
renovate[bot]andWolfgang Walther c9f9b93ad7 chore(deps): update github artifact actions 2025-12-13 14:36:30 +00:00
renovate[bot]andWolfgang Walther e39b91c27b chore(deps): update korthout/backport-action action to v4 2025-12-13 14:36:12 +00:00
renovate[bot]andWolfgang Walther d694ad90e0 chore(deps): update actions/cache action to v5.0.1 2025-12-13 11:31:32 +00:00
steve-chavez 99b8246d6e nix: add --method for postgrest-loadtest
Currently the `postgrest-loadtest -k jwt-*` loadtests use the OPTIONS method,
which is good for isolating the perf changes for JWT auth.

But using GET is more accurate for actual perf improvements,
since it actually hits the database.

This adds a method argument for postgrest-loadtest, so GET can be used like:

```
postgrest-loadtest -k jwt-hs --method GET
```

CI is not changed, this is mostly useful for manually checking variance.
2025-12-12 14:46:46 -05:00
steve-chavez 90bf1762ae nix: rename genTargetsHs to genTargets
Previous name wasn't accurate as RSA is used as well.
2025-12-12 14:46:46 -05:00
renovate[bot]andWolfgang Walther c9c975ce49 chore(deps): update actions/cache action to v5 2025-12-12 08:29:32 +00:00
Taimoor ZaeemandSteve Chavez 29c2aa015f refactor: create function to handle response preferences
Centralizes handling of preferences that are used to
create `Preference-Applied` header which is returned on
responses.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-12-11 17:55:45 -05:00
Taimoor ZaeemandSteve Chavez abad47ff1b add: log error when db-schemas config contain restricted schemas
We don't allow accessing schemas "pg_catalog" and "information_schema".
Instead of silently failing requests on these schemas, this now adds
logging an error on startup when these schemas are found in `db-schemas`
config.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-12-11 14:28:08 -05:00
Laurence IslaandSteve Chavez c232e97f80 chore(changelog): move incorrectly placed fixes 2025-12-10 20:00:31 -05:00
Laurence Isla ab9b00ce88 refactor: use only Lazy.ByteString to calculate the response body length 2025-12-10 14:18:19 +00:00
Laurence Isla 9200a98087 fix: add missing Content-Length to empty HTTP 201 responses
For when a preference other than return=representation is requested.
2025-12-10 14:18:19 +00:00
Laurence Isla 3b27b2220d fix: regression that truncates error message when offset is out of bounds
- Happens when offset > the number of rows and when "Prefer: count=exact" header is sent
- Regression introduced in commit 57ef998
2025-12-10 14:18:19 +00:00
renovate[bot]andWolfgang Walther 6573953ebd chore(deps): update codecov/codecov-action action to v5.5.2 2025-12-10 12:24:43 +00:00
Taimoor ZaeemandSteve Chavez 0fa2f569a7 fix: misleading logs on unsupported postgresql versions
Postgrest fails on unsupported pg versions. However before killing
the thread, it continues to print a few more log messages which
were misleading. This commit fixes this by making sure that the
no log message should be printed after the unsupported pg version
observation and kill the thread immediately.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-12-09 13:46:34 -05:00
renovate[bot]andWolfgang Walther 24a27d17d0 chore(deps): update actions/create-github-app-token action to v2.2.1 2025-12-06 11:00:06 +00:00
renovate[bot]andGitHub 1724e4551d chore(deps): update actions/checkout digest to 8e8c483 (main) (#4511) 2025-12-03 19:32:01 +00:00
renovate[bot]andWolfgang Walther 457f20f962 chore(deps): update actions/checkout action to v6.0.1 2025-12-03 19:30:42 +00:00
renovate[bot]andWolfgang Walther 70240b0d08 chore(deps): update actions/create-github-app-token action to v2.2.0 2025-12-03 19:29:54 +00:00
Taimoor ZaeemandSteve Chavez 50eec773bf test(io): fix freeport function to prevent failures
Sometimes, a healthcheck related test fails as occurred in
https://github.com/PostgREST/postgrest/actions/runs/19771357953/job/56655949002.
This happens due to freeport function accidently picking up a used port.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-29 18:17:00 -05:00
Taimoor ZaeemandSteve Chavez 35de13eebd test(io): move fixtures to fixtures/ directory
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-27 17:08:03 -05:00
Taimoor ZaeemandSteve Chavez 3baa6b0063 test(io): rename fixtures.sql to load.sql
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-27 17:08:03 -05:00
Andrei DziahelandGitHub 6d462f762e nix: override PGRST_CMD for postgrest-loadtest from env
Enables `PGRST_CMD=postgrest-profiled-run postgrest-loadtest` running
loadtest against profiled executable, which wasn't available before
2025-11-25 19:46:23 +00:00
Taimoor ZaeemandGitHub 802cce9a28 nix(shell): remove postgrest/ directory prefix when running pg (#4502)
When running postgres from nix-shell, nix creates a directory
structure like `postgrest/postgrest-with-pg-17-XXX` in the `/tmp`
directory. This commit removes the extra `postgrest/` prefix to
shorten length of absolute path length of filenames.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-25 15:54:25 +00:00
Marek BriegerandGitHub ee334cbcf8 chore: improve grammar in README.md 2025-11-25 12:20:26 +00:00
Taimoor ZaeemandSteve Chavez c561a3749c test(io): move authentication related tests to test_auth.py
The `test_io.py` module is too bloated (2100+ lines). To
logically group related tests, as a first step, this commit
separates authentication related IO tests into `test_auth.py`
module.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-21 13:21:15 -05:00
renovate[bot]andWolfgang Walther f8b56736d7 chore(deps): update actions/checkout digest to 1af3b93 2025-11-21 17:29:18 +00:00
renovate[bot]andWolfgang Walther 7bcd46b145 chore(deps): update actions/checkout action to v6 2025-11-21 17:29:09 +00:00
Taimoor ZaeemandSteve Chavez d905592115 docs: add asterisk character to reserved characters list
The `*` character is a reserved character in the postgrest
url grammar but we didn't mention it in the docs. Now added.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-20 16:20:28 -05:00
Taimoor ZaeemandSteve Chavez 4b8dec8901 docs: clarify postgrest reserved characters in url grammar
Fixes a typo in the documentation where it said that `()`
is a reserved character, when we actually meant to say that
`(` and `)` are reserved characters.

Related discussion in #4254.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-20 16:20:28 -05:00
Taimoor ZaeemandSteve Chavez 379eaec8e0 test(io): remove stale jwt cache test
Removes a test related to jwt cache which is stale
since #4084.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-19 11:17:18 -05:00
Andrei DziahelandWolfgang Walther ae2d650516 fix: hashtables <1.4.1 fail to build with GCC 15
Introduces hashtables >= 1.4.1 requirement
2025-11-18 19:26:16 +00:00
Wolfgang Walther 4a83e79923 ci/test: remove macos x86 flake check
See previous commit.
2025-11-18 11:05:23 +01:00
Wolfgang Walther eb00c1991c ci: remove macos x86 builds
The x86 GitHub runner will not be available anymore, soon.

We might be able to re-introduce this, once we can build a static
executable via Nix on darwin, too.
2025-11-18 11:01:05 +01:00
Taimoor ZaeemandWolfgang Walther 462798dc2d nix: shorten postgrest-with-postgresql-xx scripts
Renames these scripts to `postgrest-with-pg-xx`. The renaming
helps reduce the length of temporary filenames. This is needed
to ensure that socket file names remain under the maximum
allowed length of 107 chars.

Closes #4461.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-18 09:40:16 +00:00
renovate[bot]andWolfgang Walther 1efd5781f8 chore(deps): update actions/checkout action to v5.0.1 2025-11-18 09:38:41 +00:00
Taimoor ZaeemandWolfgang Walther 08c6deba12 docs: update server-host config in docker-compose example
The docker-compose example did not work with multiple containers
when PGRST_SERVER_HOST is set to `localhost`. This updates the
value to `0.0.0.0` allowing other containers to connect.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-18 09:36:37 +00:00
renovate[bot]andWolfgang Walther 531848366d chore(deps): update ubuntu:noble docker digest to c35e29c 2025-11-15 13:52:00 +00:00
Taimoor ZaeemandSteve Chavez 91abcd49e1 test(io): move resource embedding tests to test_io.py
- Adds fixtures to `test/io/fixtures.sql` to test resource
  embedding related queries.

- Moves the resource embedding related tests that no longer
  require big schema from `test_big_schema.py` to `test_io.py`.

Closes #4417.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-11 13:43:10 -05:00
Jens TroegerandSteve Chavez 770c404ebe docs: add another project to the list of Example Apps 2025-11-11 13:25:55 -05:00
Taimoor ZaeemandSteve Chavez 99217433b1 chore(cabal): remove unused haskell dependencies
This should reduce setup time for build process.

- cache: introduced in #2928, defunct since #4084
- clock: introduced in #2928, defunct since #4084
- heredoc: introduced in #714, defunct since #4390
- iproute: introduced in #3560, defunct since #4288

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-09 13:49:18 -05:00
Taimoor ZaeemandWolfgang Walther bccf7ac97a Revert "chore: remove unused haskell dependencies"
This reverts commit b6bb8382e7.
2025-11-06 08:11:44 +00:00
Taimoor ZaeemandWolfgang Walther ed8be34b20 chore: add changelog entry for v14.1
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-06 08:11:32 +00:00
Taimoor ZaeemandSteve Chavez b6bb8382e7 chore: remove unused haskell dependencies
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-04 14:12:08 -05:00
renovate[bot]andWolfgang Walther 893e0061a3 chore(deps): update actions/checkout digest to 71cf226 2025-11-03 20:47:50 +00:00
Taimoor ZaeemandSteve Chavez 58efc2680e fix: server-host !6 incorrectly binds to IPv4 address
Updates streaming-commons to version 0.2.3.1. This resolves #3202.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-02 12:24:14 -05:00
Taimoor ZaeemandWolfgang Walther 8180905890 chore(changelog): fix typo in changelog entry
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-11-01 09:00:31 +00:00
Taimoor ZaeemandSteve Chavez db2be093b5 refactor: move dumpQi to Config.hs and clarify quoteQi
The `dumpQi` function is only used in the `Config.hs` module, so
it is moved there. This also adds a doctest for `quoteQi` and
clarifies its usage.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-30 12:26:29 -05:00
Taimoor ZaeemandSteve Chavez a688878236 fix: db-pre-config function failing with pg reserved words
When db-pre-config is accidentally set to a pg reserved word
like "true", it fails with a confusing error. The function
names should be properly quoted to avoid such errors. This commit
resolves this by quoting the pre-config function name.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-29 16:54:24 -05:00
Michał KłeczekandSteve Chavez 75d4131aa6 chore: Add commit structuring guidelines to CONTRIBUTING.md 2025-10-28 10:02:56 -05:00
Taimoor ZaeemandSteve Chavez 66f84c5903 refactor: move escapeIdent function to Identifiers.hs
Moves the functions `escapeIdent` and `trimNullChars` to
SchemaCache/Identifiers.hs module.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-28 09:47:37 -05:00
Taimoor ZaeemandSteve Chavez 5d9b169380 refactor: sort exports of Identifiers.hs and SqlFragments.hs
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-28 09:47:37 -05:00
Taimoor ZaeemandSteve Chavez eb908c696f chore(changelog): update versioning scheme description
The changelog description mentioned that we follow semantic
versioning but from now on we don't. Hence updated the description
to reflect new versioning policy.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-27 10:00:40 -05:00
renovate[bot]andWolfgang Walther 21edcc86ce chore(deps): update github artifact actions 2025-10-25 08:23:40 +00:00
Wolfgang Walther 6f46233ad7 ci: fix tag job with new release workflow
A single component version is the development version, everything with
more components is not. Thus, we only need to check for a single dot.
2025-10-25 10:20:32 +02:00
steve-chavez 018803473c bump version to 15 2025-10-24 17:39:04 -05:00
steve-chavez 23750e644f bump version to 14.0 2025-10-24 17:39:04 -05:00
steve-chavez 4dff3550b3 docs: new two-part versioning in releases section
Also add entry to the changelog
2025-10-24 17:23:57 -05:00
steve-chavez 3085cc81ec docs: link external auth on architecture page
Partly addresses https://github.com/PostgREST/postgrest/issues/4110
2025-10-24 14:56:24 -05:00
steve-chavez 4ea983163a chore: add changelog for v13.0.8 2025-10-24 14:12:02 -05:00
steve-chavez 1d2350188c chore(changelog): put additions at the top 2025-10-24 13:19:21 -05:00
steve-chavez b20d369176 docs: elaborate on Docker tag
Also link to installation from README.md

Closes https://github.com/PostgREST/postgrest/issues/4385.
2025-10-23 18:57:41 -05:00
steve-chavez 7968b918ec nix: fix postgrest-loadtest command
Uses python for sending SIGNIT cross-platform
2025-10-23 16:05:15 -05:00
renovate[bot]andWolfgang Walther 82981a1a29 chore(deps): update actions/checkout digest to ff7abcd 2025-10-23 10:57:37 +00:00
Wolfgang Walther 41def2f0eb ci: fix vars reference 2025-10-23 12:56:28 +02:00
Taimoor ZaeemandWolfgang Walther 6aa5a09c18 ci: automate backports using backport action
Creates a workflow using https://github.com/korthout/backport-action.
This allows creating a backport PR by labeling the merged PR with a
`backport <version>` label.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-23 10:54:03 +00:00
Michał KłeczekandLaurence Isla 66161104bf refactor: Remove redundant VANull constructor in Auth.JWT module 2025-10-22 00:40:30 +00:00
Michał KłeczekandLaurence Isla 5a4e2e4dec refactor: Encapsulate aud config
This change is an initial step to change JWT aud configuration to regular expression.
Exporting function
audMatchesCfg :: AppConfig -> Text -> Bool
from Config module allows changing the way how JWT aud is configured to be isolated and not affect code in Auth.JWT
2025-10-22 00:40:30 +00:00
steve-chavez 0f7ac1bc39 test: schema cache load max duration
Test to ensure no regression happens after https://github.com/PostgREST/postgrest/pull/4396
2025-10-21 14:10:14 -05:00
Laurence Isla 1ada6e6f84 chore(changelog): add missing devs from changelog entries 2025-10-21 16:16:42 +00:00
Michal KleczekandGitHub be9a0ab467 perf: Index various lists in SchemaCache to change complexity from O(n*n) to O(n) (#4396) 2025-10-20 21:17:50 -05:00
Laurence Isla ea5db2a09a fix: reloading the Schema Cache unnecessarily on a PGRST002 error
When 503 errors happen if the Schema Cache is empty,
it should not retrigger the connection worker since
there's no Schema Cache loaded yet.
2025-10-20 18:42:56 +00:00
Laurence Isla c88ddfe18d fix: not logging the JSON message on a PGRST002 error
It happens right after the configuration is loaded and before
the schema cache is queried.
2025-10-20 18:42:56 +00:00
Andrei DziahelandSteve Chavez b7ad217cd3 fix: unbreaks postgrest-profiled-run
* replaces v2-build -> v2-run (which should be v2-exec)
  with one-shot v2-run
* fixes empty postgrest.prof file by sending SIGINT to the profiled
  postgrest process to trigger writing it explicitly
2025-10-17 15:43:41 -05:00
Michał KłeczekandSteve Chavez c08b87749b test: Separated query and loading internal sleep configs
To make schema cache loading wait tests robust it is necessary to provide three separate internal config variables:
* "internal-schema-cache-query-sleep" - introduces delay in schema queries execution
* "internal-schema-cache-load-sleep" - introduces delay between schema queries execution and processing their results
* "internal-schema-cache-relationship-load-sleep" - introduces delay in processing relationship query results

Thanks to these changes it is now possible to test various schema loading scenarios with the right granularity robustly (eg. make sure requests wait for schema loading but not for relationship loading).
2025-10-17 13:42:35 -05:00
Taimoor ZaeemandSteve Chavez 07681d1b5b fix: loading utf-8 config files with ascii locale set
Updates configurator-pg to version 0.2.11. This resolves #4386.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-14 09:05:34 -05:00
Taimoor ZaeemandWolfgang Walther 7ba5e32bcc chore: update pull request template according to commitlint
Updates pull request template to avoid inconsistencies.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-14 09:28:53 +00:00
renovate[bot]andWolfgang Walther 3885c643ec chore(deps): update ubuntu:noble docker digest to 66460d5 2025-10-13 10:21:47 +00:00
Taimoor ZaeemandSteve Chavez 66a8d04610 nix: setup linter to lint python files
This sets up the `ruff` linter for python code linting.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-11 23:38:00 -05:00
Wolfgang WaltherandSteve Chavez 8e35d543bd nix: adjust release tool to new versioning scheme
Resolves #4166
2025-10-10 18:19:33 -05:00
Jens TroegerandSteve Chavez 041d4f8ed2 test(pytest): remove unused variables and clean other minor lint to please ruff 2025-10-10 13:23:05 -05:00
renovate[bot]andWolfgang Walther 4d764500b1 chore(deps): update ubuntu:noble docker digest to 59a458b 2025-10-10 07:33:58 +00:00
Taimoor ZaeemandSteve Chavez 7b85333b88 chore: correct value of log-query in example config file
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-09 12:17:07 -05:00
Taimoor ZaeemandSteve Chavez af6edc575d refactor: move example config file to Config.hs
We usually miss adding or changing the example config
file when we do changes to our configurations. Moving
the example config file from CLI module to Config module
would make it less easy to miss doing the associated
changes to the example config file.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-09 12:17:07 -05:00
Jens TroegerandWolfgang Walther 4ce859bf46 test(pytest): remove star imports to please ruff linter 2025-10-09 10:10:40 +00:00
Wolfgang Walther 32eb6ebf19 nix: revert to build shared libs in development mode
This was disabled to reduce rebuilds for local development slightly.
However it caused random other errors, so reverting.
2025-10-09 11:59:49 +02:00
Wolfgang Walther e4bdc3bc4c chore: fix repo warning on build 2025-10-09 11:57:16 +02:00
c1d9728dc8 test(pytest): move pytest fixtures to conftest.py
There are a few benefits for this:

  - All fixtures in one module, so single source of truth.

  - The fixtures are automatically imported and injected by pytest
    so no explicit imports needed for these.

  - Linters won't complain about redefinition of outer scope objects.

Co-authored-by: Jens Troeger <jens.troeger@light-speed.de>
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-10-08 13:54:32 -05:00
steve-chavezandWolfgang Walther 322216c810 chore: remove split-sections
It's a problem for macos on x86_64 and it's no longer needed as mentioned on
https://github.com/PostgREST/postgrest/discussions/4384#discussioncomment-14614110
2025-10-08 06:29:12 +00:00
Laurence Isla 6d8a95f607 chore: fix broken logo URL in Docker Hub README 2025-10-08 02:40:58 +00:00
renovate[bot]andWolfgang Walther ea2c64da54 chore(deps): update ubuntu:noble docker digest to 728785b 2025-10-05 08:36:50 +00:00
steve-chavez 09b088d8ff change: change log-query string value to bool
BREAKING CHANGE

As discussed on https://github.com/PostgREST/postgrest/issues/3934#issuecomment-3362806777,
this changes log-query to use a bool value, this:

- Simplifies config for users.
- Reduces effort in testing the different combinations.

Closes #3934
2025-10-03 12:17:12 -05:00
steve-chavez e4458abd33 chore(changelog): adjust jwt sieve change 2025-10-03 12:17:12 -05:00
renovate[bot]andWolfgang Walther 8abc1559c7 chore(deps): update peter-evans/dockerhub-description action to v5 2025-10-02 10:03:53 +00:00
renovate[bot]andWolfgang Walther b6ac0279a5 chore(deps): update ubuntu:noble docker digest to fdb6c9c 2025-10-02 10:03:22 +00:00
renovate[bot]andWolfgang Walther 36ac916c72 chore(deps): update dependency macos to v15 2025-10-02 09:25:21 +00:00
renovate[bot]andWolfgang Walther 253453d8a6 chore(deps): update docker/login-action action to v3.6.0 2025-10-02 09:25:07 +00:00
Taimoor ZaeemandSteve Chavez a9a1763328 add: --ready flag for postgrest healthcheck
The `--ready` flag is a wrapper around the admin server
`/ready` request. This is done through using an http client
library in postgrest.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-28 18:01:10 -05:00
Taimoor ZaeemandSteve Chavez ab2cd766c2 docs: document config file parameter on CLI page
The CLI page had the config file parameter missing. This commit
adds that. Also adds the CLI usage output which shows all
available options. Closes #4300.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-26 19:26:47 -05:00
Wolfgang Walther 0478e6bbfe ci: allow manually running linkcheck workflow 2025-09-25 10:28:37 +02:00
Wolfgang Walther f2d13c242e chore: ignore failing linkcheck 2025-09-25 10:27:13 +02:00
renovate[bot]andWolfgang Walther bc01687d7c chore(deps): update actions/cache action to v4.3.0 2025-09-25 08:22:10 +00:00
renovate[bot]andWolfgang Walther f894901ad1 chore(deps): update nixbuild/nix-quick-install-action action to v34 2025-09-25 08:18:28 +00:00
Taimoor ZaeemandSteve Chavez d064faebb9 test(io): remove unused module imports
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-22 12:38:47 -05:00
Steve ChavezandGitHub bcf3457c28 docs: note index on automatic tsvector (#4344) 2025-09-19 13:49:30 -05:00
Steve ChavezandGitHub 9f056ac756 fix: not logging tx variables and pre-request (#4341)
Addresses the first item on https://github.com/PostgREST/postgrest/issues/3934
2025-09-19 12:16:10 -05:00
Taimoor ZaeemandWolfgang Walther 98de226dfd test(io): move reusable functions to postgrest.py
Moves the `set_statement_timeout` and `reset_statement_timeout`
function to postgrest.py. This cleans up test_io.py so it only
contains tests. Also makes these functions reusable in other
other tests like test_cli.py.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-18 16:51:00 +00:00
steve-chavez 4a81f6b1a6 test: refactor test_log_query
It's easier to maintain without using explicit array indexes for
matching the logs
2025-09-17 19:08:10 -05:00
Taimoor ZaeemandWolfgang Walther ef3a25a626 test(io): remove unused duplicate freeport() function
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-17 14:41:03 +00:00
renovate[bot]andWolfgang Walther 2b8f8c4c47 chore(deps): update ubuntu:noble docker digest to 353675e 2025-09-17 10:32:38 +00:00
renovate[bot]andWolfgang Walther 6019e4890d chore(deps): update haskell-actions/setup action to v2.8.2 2025-09-16 19:13:16 +00:00
Taimoor ZaeemandWolfgang Walther 089ffae94c chore: add changelog for v13.0.7
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-16 09:02:13 +00:00
renovate[bot]andWolfgang Walther 52c346f952 chore(deps): update ubuntu:noble docker digest to 590e57a 2025-09-16 09:01:55 +00:00
steve-chavez baea47bc85 refactor: make Query module pure
This splits off the transaction concerns into a MainTx module

It's just moving some functions inside the Query module to the MainTx module.
Some types names were also changed so they don't have the "Query" prefix, to avoid confusion.
2025-09-15 23:43:26 -05:00
steve-chavez 15e04903b1 fix: not logging explain query for estimated count
Fixes https://github.com/PostgREST/postgrest/issues/4319
2025-09-15 17:07:12 -05:00
steve-chavez a75ec75fff refactor: put CallReadPlan into CrudPlan 2025-09-15 17:07:12 -05:00
Taimoor ZaeemandWolfgang Walther 2d3d6256ab test(coverage): set hpctixfile to a unique name
Sets hpctixfile to be unique for every postgrest process that
is run.

Previously, this was based on the test name, but issues arise
when two postgrest processes are run under the same test, which
generates two files where one gets overwritten by the other.

Consequently, coverage data used to get lost, which is now fixed
with this commit.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-15 10:39:13 +00:00
steve-chavez 0acf5a30e6 refactor: remove unnecessary RSPlan constructor
This also removes some unreachable paths in Query module logic.
2025-09-11 20:51:51 -05:00
steve-chavez 4650e7299f chore(changelog): add breaking change for JWT kid 2025-09-11 14:50:21 -05:00
steve-chavez 0bb127057f docs: clarify wording on kid validation 2025-09-11 14:50:21 -05:00
Taimoor ZaeemandSteve Chavez 59ca9e7f0d test(io): move jwt secret length test to test_cli.py
Closes #4316.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-11 12:01:21 -05:00
steve-chavez cddfb6cf5e fix: not logging OpenAPI queries
Closes https://github.com/PostgREST/postgrest/issues/4226.

This requires moving query generation to the top App.hs module.

At this point is also simple to log the transaction variables + the
pre-request function call but this is not done here to reduce scope.
2025-09-10 09:04:12 -05:00
steve-chavez 1d2a3e8501 refactor: pass AuthResult to txVarQuery
Saves one parameter to the function.
2025-09-10 09:04:12 -05:00
steve-chavez 966a611d7f refactor: inline txVarQuery and preReqQuery
This way it's easier to see which queries are being executed.

Also use whenJust instead of traverse_.
2025-09-10 09:04:12 -05:00
Taimoor ZaeemandWolfgang Walther 19ac284f25 test(io): correct config error tests in test_cli.py
Towards fixing #4316. The config error tests were not
correctly tested. This commit allows capturing stderr
output and then checks the error messages properly.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-10 10:05:10 +00:00
Taimoor ZaeemandSteve Chavez d512d5c105 refactor: move escapeHostName to Network.hs
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-05 08:51:33 -05:00
renovate[bot]andWolfgang Walther b265f7bf7e chore(deps): update codecov/codecov-action action to v5.5.1 2025-09-04 19:25:46 +00:00
steve-chavez 1dca23e7af refactor: move accessibleFuncs to SqlFragment 2025-09-04 09:35:33 -05:00
steve-chavez 9c07070263 refactor: move accessibleTables to SqlFragment 2025-09-04 09:35:33 -05:00
steve-chavez 1ace298a1a refactor: move schemaCacheDescription to SqlFragment
This doesn't belong in the schema cache module, as
it's unused there. It's only used on Query.hs.
2025-09-04 09:35:33 -05:00
renovate[bot]andWolfgang Walther 96d2b69af4 chore(deps): update ubuntu:noble docker digest to 9cbed75 2025-09-03 13:53:55 +00:00
steve-chavez b2ce322d56 refactor: move snippet logic inside Statements.hs
Some snippet logic was unnecessarily at the Query.hs level.

This is better as we can see what inputs we need to form the main
queries.
2025-09-02 16:26:15 -05:00
steve-chavez 0844743c30 refactor: clarify Plan module and comment 2025-09-02 16:26:15 -05:00
steve-chavez 3e776213b7 refactor: move decoding to Query.hs
Towards solving https://github.com/PostgREST/postgrest/issues/3934.

This makes the Statements internal module pure now it only returns
Hasql.Snippet.
2025-09-02 16:26:15 -05:00
renovate[bot]andWolfgang Walther 00d92aa474 chore(deps): update ubuntu:noble docker digest to f3b7f1b 2025-09-02 08:17:07 +00:00
Taimoor ZaeemandWolfgang Walther 0d7986bd71 chore: add changelog for v13.0.6
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-02 08:16:28 +00:00
Taimoor ZaeemandSteve Chavez 41b6ebea58 refactor: deduplicate host resolution logic and observations
Replaces the "API server listening on unix socket" with simpler
"API server listening on " observation. This allows refactoring
redundant code.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-09-01 15:00:20 -05:00
Taimoor ZaeemandSteve Chavez ef9ac61d9e test(log): postgrest listening on unix socket observation
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-08-30 13:43:18 -05:00
Laurence Isla 043b1f97ee fix: empty enum in 'preferParams' openAPI parameter 2025-08-29 22:57:56 +00:00
Taimoor ZaeemandSteve Chavez 7a2840fba6 fix: format of IPv6 address logged at PostgREST startup
The IPv6 address logged at the startup like `::1:80` was
wrong because the port isn't clearly separated. This commit
corrects it, now logging as `[::1]:80`.

This is done in accordance to RFC 3986. In short, we did this
have a clear separation between the port and host because
the components of an IPv6 are separated with the ':' character.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-08-29 13:02:20 -05:00
renovate[bot]andWolfgang Walther 08a6a9d9be chore(deps): update nixbuild/nix-quick-install-action action to v33 2025-08-25 13:55:55 +00:00
Taimoor ZaeemandWolfgang Walther 09c1e2b24c chore: add changelog for v13.0.5
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-08-25 06:51:51 +00:00
Laurence Isla bf90f95443 fix: logging the Haskell type instead of the listener error message directly
Previously: Just "connection error..."
Now: connection error...
2025-08-22 19:27:38 +00:00
Taimoor ZaeemandSteve Chavez dfe5ba3863 fix(admin): metrics endpoint not responding with Content-Type header
The prometheus metrics text format requires `Content-Type` header
for correct scraping which fails otherwise. Closes #4271.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-08-20 16:13:55 -05:00
renovate[bot]andWolfgang Walther 7657607ca5 chore(deps): update codecov/codecov-action action to v5.5.0 2025-08-20 18:11:02 +00:00
steve-chavez f01d5bfeb3 docs: reorder computed relationships for clarity
Ensure the function inlining is mentioned first
2025-08-19 12:24:47 -05:00
Taimoor ZaeemandSteve Chavez 0ae1cdfc66 refactor(query): make fromJsonBodyF function more readable
The `fromJsonBodyF` function was very unreadable and making
changes were difficult. This commit improves the readability
for easier future changes and improvements.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-08-19 11:58:19 -05:00
steve-chavez 1dce4a9321 Revert "fix: geojson invalid query on unavailable PostGIS"
This reverts commit 0f1ca8faac.

Reverting for now as it adds one more query to the schema cache and
there's no clear way forward on how to integrate the fix with the
current schema cache queries.

See discussion on
https://github.com/PostgREST/postgrest/pull/4246#pullrequestreview-3093174224.
2025-08-13 14:54:53 -05:00
renovate[bot]andWolfgang Walther c9272b0088 chore(deps): update ubuntu:noble docker digest to 7c06e91 2025-08-13 07:19:30 +00:00
renovate[bot]andWolfgang Walther 1cd8934bb7 chore(deps): update actions/checkout action to v5 2025-08-11 15:15:57 +00:00
renovate[bot]andWolfgang Walther b915968f30 chore(deps): update actions/cache action to v4.2.4 2025-08-07 14:24:41 +00:00
steve-chavez 0f1ca8faac fix: geojson invalid query on unavailable PostGIS
Closes https://github.com/PostgREST/postgrest/issues/4245.

It adds a query on schema cache construction, but doesn't add a new
attribute to the SchemaCache type. We only need the information to be
passed to the `initialMediaHandlers` function to build the builtin media
handlers.
2025-08-06 10:20:01 -05:00
renovate[bot]andWolfgang Walther 7870add603 chore(deps): update actions/download-artifact action to v5 2025-08-06 07:45:01 +00:00
renovate[bot]andWolfgang Walther a2da255931 chore(deps): update docker/login-action action to v3.5.0 2025-08-04 17:05:52 +00:00
renovate[bot]andWolfgang Walther 26bc13b57f chore(deps): update haskell-actions/setup action to v2.8.1 2025-08-03 16:27:13 +00:00
steve-chavez fa09e4af0d docs: add redirects for broken hashes on auth.rst 2025-07-30 05:28:00 -05:00
steve-chavez fd127f449c docs: correct order of jwt claims sections 2025-07-30 05:14:43 -05:00
steve-chavez ad25479185 chore: put bounded jwt cache as addition 2025-07-30 04:53:22 -05:00
Taimoor ZaeemandSteve Chavez 6a37e1c37b chore: correct recent change log entry
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2025-07-30 02:46:01 -05:00
Michal KleczekandGitHub 77ff11de95 feat: JWT cache implementation based on sieve algorithm (#4084)
Changes:

1. Refactoring and some cleanup of JWT handling code:
* Instead of caching AuthResult cache decoded claims (which signature was verified). Validating claims and determining role is done after cache lookup
* Cleaned up API so that usage of it is simplified: lookupJwtCache cache key >>= parseClaims configJwtAud time
* Handling of JwtCacheState initialization and updates of configuration is encapsulated in Auth.JwtCache module

2. Generic high performance (hopefully) scalable, dynamically resizeable cache implementation based on stm, stm-hamt and sieve algorithm. It also integrates with PostgREST measurements infrastructure providing usage stats (ie. hit ratio, evictions count)
2025-07-29 18:51:41 -05:00
steve-chavez ac155a9391 docs: clarify auth page
Reorganizes the auth page and clarifies some links
2025-07-28 15:43:38 -05:00
Taimoor ZaeemandSteve Chavez 96571aa0f4 refactor: move request body to a Payload.hs module 2025-07-26 08:50:56 +02:00
steve-chavez aa58e37f03 refactor: add PreQuery module
Small step towards solving #3934.

Adds a module that builds SQL snippets for the transaction variables
and the pre-request function.
2025-07-23 10:06:32 +02:00
Taimoor ZaeemandGitHub 5e0da40ac4 chore: update README.md and CONTRIBUTING.md (#4218)
- Moved the CONTRIBUTING.md file to project root.
- Fixed broken nightly release link.
- Update README.md
2025-07-22 13:50:00 +00:00
renovate[bot]andWolfgang Walther 2b065553a0 chore(config): migrate config .github/renovate.json 2025-07-21 20:04:54 +00:00
renovate[bot]andWolfgang Walther cd04360a43 chore(deps): update ubuntu:noble docker digest to a08e551 2025-07-19 12:16:42 +00:00
Taimoor ZaeemandWolfgang Walther 96bbbe35e1 test: adjust jwt claims error test to avoid failure
The JWT claims IO test fails too often. This breaks our
workflows. This commit adjusts the edge cases in test to
prevent flakiness.
2025-07-19 12:16:29 +00:00
steve-chavez 161f37f1f1 test: remove jwt decoding from mixed loadtest
We now have dedicated JWT loadtests, so it's no longer necessary
to conflate JWT here.
2025-07-18 07:25:53 -05:00
Wolfgang WaltherandSteve Chavez 25e56f32e4 nix: avoid updating cabal on every run
Resolves #4206
2025-07-17 11:47:44 -05:00
Laurence Isla 66caaffbe3 chore: update sponsor 2025-07-16 19:54:53 -05:00
steve-chavez 2d4967c4b4 nix: reduce loadtest result verbosity 2025-07-16 17:38:33 -05:00
Wolfgang Walther d013a1fd77 docs: adjust some redirects
Those were reported in the weekly linkcheck.
2025-07-16 11:03:50 +02:00
renovate[bot]andWolfgang Walther b91e241b9a chore(deps): update ubuntu:noble docker digest to c4570d2 2025-07-16 09:00:23 +00:00
renovate[bot]andWolfgang Walther 84564b9e3e chore(deps): update ubuntu:noble docker digest to a328b84 2025-07-16 08:51:25 +00:00
Taimoor ZaeemandSteve Chavez d4caa0f5f5 fix: empty spread embeddings return unexpected SQL error
Fixes the SQL error from postgres when an empty spread embeddings
like `...table()` is requested.
2025-07-13 14:16:27 -05:00
Wolfgang Walther d31c873cd5 chore(changelog): add removal of PostgreSQL 12 2025-07-11 19:21:40 +02:00
Wolfgang Walther f32a8861c5 nix: add system argument to postgrest-push-cachix
This allows building aarch64-darwin derivations on a remote builder and
then pushing them to cachix before triggering CI.
2025-07-11 15:53:06 +00:00
Wolfgang Walther 18932b7a4a nix: use upstream GHC for static build
This way we benefit from NixOS' binary cache to deliver GHC for us and
don't need to cache it ourselves.

This will become relevant once we do that for more platforms.
2025-07-11 15:53:06 +00:00
Wolfgang Walther 067c181bb8 nix: remove libpq overlay
We have fixed the static build of PostgreSQL upstream, so we don't need
our separate overlay anymore. One more step towards building a static
executable on other platforms.
2025-07-11 15:53:06 +00:00
Wolfgang Walther 83c533e557 nix: refactor derivation tests for static package
Instead of rolling our own, we can use some tooling from nix / nixpkgs.

We drop the "statically linked" check, because our goal is to compile
mostly-static executables to darwin, too. However, those will never be
fully static, because they always link to the platform's libc.
2025-07-11 15:53:06 +00:00
Wolfgang Walther 55eafdf352 chore(deps): update nixpkgs to 25.05 2025-07-11 15:53:06 +00:00
Wolfgang Walther 70f449654f nix: fix some darwin sandbox issues 2025-07-11 15:53:06 +00:00
Wolfgang Walther bd61cf9b60 nix: re-introduce postgrest-nixpkgs-upgrade
Resolves #4161
2025-07-11 15:53:06 +00:00
Wolfgang Walther 6bf2cb09a6 remove: drop support for PostgreSQL 12
This has been EOL since November and has been dropped from nixpkgs.
2025-07-11 15:53:06 +00:00
renovate[bot]andWolfgang Walther fbb243ee0c chore(deps): update docker/setup-buildx-action action to v3.11.1 2025-07-08 20:06:24 +00:00
renovate[bot]andWolfgang Walther 7ce2b3c4e9 chore(deps): update ubuntu:noble docker digest to 440dcf6 2025-07-08 20:05:31 +00:00
Wolfgang Walther 7e2f06d217 chore: bump some hackage dependencies
All of these were tested via stackage 23.27 which required allow-newer
for them.
2025-07-08 20:01:40 +00:00
Wolfgang Walther cedb8d9cd9 chore: fix stack's nix integration
The pkgconfig package has been renamed to pkg-config in... February
2019. So this has not been working for quite some time.
2025-07-08 20:28:47 +02:00
Wolfgang Walther 39e2a154f0 chore: remove left-over comment for Ubuntu (arm)
We have been building with GHC 9.6 on that platform for a while.
2025-07-08 17:55:24 +00:00
Wolfgang Walther a4ab4ce2f3 chore: build with GHC 9.8.4 for cabal 2025-07-08 17:55:24 +00:00
Wolfgang Walther cfabbe67b8 chore: update hackage index-state 2025-07-08 17:55:24 +00:00
Wolfgang Walther a91a222613 chore: stackage 22.41 -> 22.44
Updates stackage to 22.44, which is also supported on FreeBSD, where GHC
9.6.7 is available again.
2025-07-08 17:55:24 +00:00
steve-chavez a183dea9e4 docs: clarify health checks empty response body 2025-07-08 12:45:15 -05:00
Wolfgang Walther b28df988ef chore: remove Paths_postgrest module
The dependency on it was removed in #3608 already, but we forgot to
remove it from postgrest.cabal, which caused it to still be built.

We didn't realize because all references of it were stripped away by
dead code elimination anyway.
2025-07-08 16:36:42 +00:00
Joel JakobssonandGitHub 01c23a8124 fix(openapi): respect function volatility for GET methods
The OpenAPI specification was incorrectly exposing GET methods for
VOLATILE functions, even though such functions properly reject GET
requests at runtime with "405 Method Not Allowed".  This created
a mismatch between the advertised API specification and the actual
runtime behavior.

VOLATILE functions should only be callable via POST since they may
have side effects, while STABLE and IMMUTABLE functions can safely
be called via GET since they don't modify database state.

Fix by checking the pdVolatility field in makeProcPathItem() and
only including GET methods in the OpenAPI PathItem for non-volatile
functions.

The runtime behavior was already correct; this fixes only the
OpenAPI documentation generation.
2025-07-07 15:26:51 +00:00
steve-chavez e3f8a95b72 nix: complete jwt loadtests
Completes the jwt loadtests, now we have non-cached, cached + worst case
for the cache.

- jwt-hs (edited): now has the cache disabled
- jwt-hs-cache: cache enabled for jwt-hs
- jwt-hs-cache-worst: worst case of the jwt-hs cache
- jwt-rsa (edited): now has the cache disabled
- jwt-rsa-cache: cache enabled for jwt-rsa
- jwt-rsa-cache-worst: worst case of the jwt-rsa cache

Also deletes `nix/tools/generate_targets_rsa.py` and uses a single
python script.

Should prove what's mentioned on
https://github.com/PostgREST/postgrest/pull/4084#issuecomment-2998170423
2025-07-06 19:14:17 -05:00
steve-chavez a87e31b767 nix: shorten loadtest script 2025-07-06 19:14:17 -05:00
Taimoor ZaeemandSteve Chavez 4daa4533d3 docs: horizontal filtering on table-valued functions 2025-07-02 14:28:49 -05:00
Taimoor ZaeemandSteve Chavez e37385c893 nix: run hlint on multiple threads 2025-06-30 12:14:06 -05:00
Taimoor ZaeemandGitHub 4a0eb7febe fix: OpenAPI broken docs link (#4169) 2025-06-27 15:14:34 -05:00
Taimoor ZaeemandSteve Chavez f295130544 chore: update postgrest scripts in nix README.md
Adds `postgrest-commitlint` and removes `postgrest-nixpkgs-upgrade`.
2025-06-26 12:16:49 -05:00
Wolfgang Walther 9d5968a45a ci: fix loadtest job on stable branches
Previously, the loadtest would always compare against main and the
latest tag. This meant a loadtest running on the v13 release branch,
would compare to a *future* version of both. This is not useful, and
also not supported by `postgrest-loadtest-against`, which recently
introduced a change on `main`, that now breaks the tests on the back
branches.

With this change, the loadtest will always run against the current
target branch of a PR, so against the v13 branch for a PR against v13,
for example. Also, it will compare against the latest released tag *for
that branch*.

Thus, when running this for v12, it will test against the v12 branch and
the v12.2.12 tag.
2025-06-26 09:44:08 +00:00
Wolfgang Walther 9519278c5e nix: remove mem_pct from loadtest monitor 2025-06-25 15:05:33 +00:00
Wolfgang Walther a91ce4a159 ci: update Nix to 2.29.1
Related:
https://discourse.nixos.org/t/security-advisory-privilege-escalations-in-nix-lix-and-guix/66017
2025-06-25 06:34:09 +00:00
Wolfgang WaltherandLaurence Isla 969e4afb26 nix: provide shell completions via flake packages 2025-06-24 01:44:44 +00:00
Wolfgang WaltherandLaurence Isla de25b26f3e nix: reduce closure size of default package in flake.nix
Splitting the executable in a separate output avoids distributing all of
the libraries and documentation, which are not needed when just running
PostgREST.

Reduces closure size from 4.3G to 73.9M for the flake exported packages.

Resolves #4149
2025-06-24 01:44:44 +00:00
steve-chavez 67bd3526c2 nix: use json file for generated jwk on loadtest
Having the JWK as .http file was confusing.

Also split genTargets into two to avoid confusion.
2025-06-20 11:27:44 -05:00
Taimoor ZaeemandSteve Chavez c7e5db34e4 chore: add changelog for v13.0.3 and v13.0.4 2025-06-20 09:45:04 -05:00
steve-chavez c8adfebb1f nix: fix postgrest-loadtest-to-markdown on NAs
The python script failed when presenting NAs with:

TypeError: boolean value of NA is ambiguous
2025-06-19 16:48:44 -05:00
steve-chavez 49de3c1ab8 nix: adjacent process monitoring report columns 2025-06-19 16:36:25 -05:00
steve-chavez e1c71c92d6 nix: add traces to loadtest commands 2025-06-19 15:04:16 -05:00
Taimoor ZaeemandWolfgang Walther 330df05891 ci: only run commitlint on github PRs
The `commitlint` script disrupts our release workflow if failed
on push event. We also don't need it on push because once pushed,
git commit history can't be amended.
2025-06-18 17:03:04 +00:00
Taimoor ZaeemandSteve Chavez 63a492291a nix: allow mixed casing in commitlint subject message 2025-06-17 18:10:37 -05:00
Taimoor ZaeemandSteve Chavez 0b69ad0e65 ci: fix commitlint CI failure 2025-06-17 18:10:37 -05:00
steve-chavez bc99ec8285 nix: add group to postgrest-loadtest-report
This is so the results are easier to skim
2025-06-17 17:58:49 -05:00
steve-chavez 7dbb8cd987 nix: better monitoring loadtest report readability 2025-06-17 16:38:06 -05:00
Taimoor ZaeemandGitHub 38332d9462 nix: add commitlint to lint commit messages (#4128)
Adds a new script `postgrest-commitlint` to lint commit messages.
2025-06-17 16:15:14 -05:00
renovate[bot]andWolfgang Walther cba7fc950b chore(deps): update ubuntu:noble docker digest to b59d215 2025-06-17 20:37:37 +00:00
renovate[bot]andWolfgang Walther 143d23f1b8 chore(deps): update docker/setup-buildx-action action to v3.11.0 2025-06-17 20:36:39 +00:00
steve-chavez 47763df590 nix: add process monitoring for loadtests
Closes https://github.com/PostgREST/postgrest/issues/4107.

Adds two python scripts:

- monitor_pid.py: monitors the postgrest process each second
  until it exits, then outputs a csv with the results. The nix wrappers
  use the `loadtest` dir for the output.
- merge_monitor_result.py: receives a list of csvs and merges them into
  a single markdown table. The nix wrappers use the `loadtest/*.csv`
  files for the input.

The nix `postgrest-with-pgrst` and `postgrest-loadtest-report` commands
use these scripts to add monitoring for `postgrest-loadtest` and
`postgrest-loadtest-against`.
2025-06-17 00:10:58 -05:00
steve-chavez 53604c9db2 nix: increase jwt-hs loadtest TOTAL_TARGETS
This is so the process monitoring results are more meaningful.

* remove the amount of total targets from the loadtest kind name
  since the targets can change.

* clarifies the top comment on the generate_targets python script

* increase TOTAL_TARGETS on jwt-hs loadtest
2025-06-17 00:10:58 -05:00
steve-chavez ba7aaa8ab1 nix: dedup vegeta command in nix loadtest 2025-06-17 00:10:58 -05:00
Taimoor ZaeemandGitHub c318d46469 fix: jwt-aud config not failing when set to invalid URI (#4140)
The `jwt-aud` config was not validated when containing ':'
character according to RFC 3986. This fix validates it and
fails at startup if it is invalid.
2025-06-16 15:40:47 -05:00
Laurence Isla a2892ab1dd fix: regression that makes fts not work on domain types based on tsvector 2025-06-16 16:53:29 +00:00
Laurence Isla 1879c813c8 fix: detect the correct base type of recursive domains in schema cache for tables and views
In OpenAPI it shows the correct base type in properties' definitions (including enums).
2025-06-16 16:53:29 +00:00
Taimoor ZaeemandGitHub 2eb9e4a8a4 test: upserts with case sensitive table and sequence name (#4131)
Closes #3712.
2025-06-07 12:39:50 -05:00
Laurence Isla a9d4237bc2 chore: update UTM tracking for Euronodes 2025-06-06 12:55:55 -05:00
Laurence Isla f85113669d chore: update sponsor 2025-06-06 14:53:20 +00:00
Michal KleczekandGitHub 69072116be test: Use RSA 4096 algorithm for JWT load test (#4118)
Until now we had a load test with 50k unique JWTs signed with symmetric key.
This commit adds a new load test with 10k JWTs signed with RSA 4096.

Existing -k jwt parameter was changed to -k jwt-hs-50k.
New test is run with -k jwt-rsa-10k parameter.

Additionally a new parameter --jwtcache=off was added to turn off JWT caching in the above load tests.
2025-06-05 07:44:05 -05:00
steve-chavez b2f8786821 nix: detect unused python code
Now `postgrest-lint` shows:

```
Linting workflows...
Scanning nix files for unused code...
Scanning python files for unused code...
nix/tools/generate_targets.py:13: unused variable 'JWT_DURATION' (60% confidence)
test/io/test_cli.py:6: unused import 'repeat' (90% confidence)
```

Also corrected the above detected files
2025-06-03 20:47:39 -05:00
Taimoor ZaeemandSteve Chavez dc46aea15e fix: max-affected preference not failing for rpc with strict handling 2025-06-03 14:31:17 -05:00
Laurence Isla e33ce843dd chore: add changelog entry for v13.0.2 2025-06-02 18:09:29 -05:00
Laurence Isla f7fa717411 fix: regression that makes order by with nulls order not work alongside limits 2025-06-02 17:44:57 +00:00
Michał KłeczekandSteve Chavez a409a2cb94 Extracted JWT validation functions to a separate module.
This change introduces a PostgREST.Auth.Jwt module containing JWT validation functions.

The reason to extract them from Auth is to enable JwtCache module to reuse them without introducing module dependency cycle.
2025-06-02 12:26:39 -05:00
Michał KłeczekandSteve Chavez 7e3fb2ba08 Define MetricsState as record and use Applicative to initialize one 2025-06-02 11:49:01 -05:00
renovate[bot]andWolfgang Walther 9084d8c358 chore(deps): update codecov/codecov-action action to v5.4.3 2025-06-02 06:15:33 +00:00
Taimoor ZaeemandWolfgang Walther 4ae5db57dc chore: add changelog entry for v13.0.1 2025-06-02 06:14:50 +00:00
Taimoor ZaeemandSteve Chavez c5ccf742d6 feat: improve error details of PGRST301 error 2025-05-31 13:30:32 -05:00
Thilo HohltandSteve Chavez f6316b86e4 Update ecosystem.rst
The repository has been moved from a dedicated organisation to my personal profile, so this old link will no longer work after 90 days.
2025-05-31 06:42:38 -05:00
Taimoor ZaeemandSteve Chavez aebdc716c7 refactor: move jwt error messages to Error.hs module 2025-05-31 06:41:22 -05:00
steve-chavez 72f6036432 docs: external authentication page in explanations
- Move page from External JWT generation
2025-05-30 17:59:51 -05:00
steve-chavez afc989403d docs: move jwt using SSL to tutorial 1
Removes jwt.io example in favor of a bash script
2025-05-30 17:59:51 -05:00
Taimoor ZaeemandGitHub ea9d4f49b2 fix: log db-schemas and db-extra-search-path in schema cache load error (#4108) 2025-05-30 10:13:19 -05:00
Laurence Isla 9c40a9c6df docs: JWK kid parameter validation 2025-05-29 21:01:39 +00:00
Taimoor ZaeemandSteve Chavez 000cb87ec1 fix: allow db-extra-search-path to accept empty value 2025-05-29 14:25:28 -05:00
steve-chavez 054ee463a1 docs: remove Greenplum integration
They're not really a sponsor, so it's not fair to include them.
2025-05-28 17:43:16 -05:00
Wolfgang Walther 07d9747c40 docs: fix functions link in api/preferences
External link syntax was used instead of internal reference.
2025-05-28 09:09:13 +02:00
Wolfgang Walther 2d5d5ed704 docs: apply redirects
Those redirect, so we might as well hardcode the them.
2025-05-28 09:09:13 +02:00
Wolfgang Walther 52d2bd93f5 docs: remove outdated "in production" links
Moat has been bought by Oracle. The advertising subpage redirects to
oracle.com, but pointing at that would be a bit misleading.

No need to keep failing links either.
2025-05-28 09:09:10 +02:00
steve-chavez da467fe3b6 nix: add PGRST_ADMIN_SERVER_PORT to postgrest-run
It's frequently needed during manual testing.
2025-05-27 20:12:00 -05:00
steve-chavez 52cf4658c5 docs: update architecture HTTP link
It links directly to warp page, which is confusing. Link to the
same page reference instead, which finally links to warp.
2025-05-26 13:44:20 -05:00
Taimoor ZaeemandSteve Chavez 94d6ac2f2e docs: explain use of max-affected preference with rpc 2025-05-22 12:23:52 -05:00
Taimoor ZaeemandSteve Chavez 5f9e0a2739 test: add missing tests for max-affected preference with rpc 2025-05-22 12:23:52 -05:00
Wolfgang Walther 7933685ffb docs: Update sphinx-rtd-theme to 3.0.2 2025-05-22 06:07:26 +00:00
Taimoor ZaeemandSteve Chavez 1258ea663c docs: add note in JWT Role Extraction section
Add a note describing that the used JSPath DSL does not
strictly follow the JSONPath as described in RFC 9535
2025-05-18 13:36:43 -05:00
Adam WespiserandGitHub a4880f0372 bump version 0.3.5 (#152) 2025-05-15 22:15:12 -04:00
daad7c317d Support GHC 9.12 (#151)
* Test 9.6 and 9.8 in CI

* Support GHC 9.10

* Support GHC 9.12

---------

Co-authored-by: Tom Ellis <tom-git@jaguarpaw.co.uk>
2025-05-15 22:13:14 -04:00
steve-chavez 520631913f docs: add warning for duplicate keys in spread 2025-05-15 17:42:13 -05:00
steve-chavez 10e31c4e8c nix: clarify output of loadtest jwt 2025-05-15 16:38:59 -05:00
steve-chavez a659b0005a docs: clarify spread join table 2025-05-15 15:50:54 -05:00
steve-chavez 23f11e3abb docs: clarify fts 2025-05-15 11:57:08 -05:00
steve-chavez 211e27a4d7 docs: clarify spread feature 2025-05-15 11:14:06 -05:00
Laurence Isla 0b3c8c98d8 feat: improve error response when the requested schema is invalid
- It now shows the invalid schema in the "message"
- The exposed schemas are now listed in the "hint" instead of the "message"
2025-05-15 02:21:00 +00:00
renovate[bot]andWolfgang Walther 605d82285d chore(deps): update haskell-actions/setup action to v2.8.0 2025-05-14 19:41:02 +00:00
Taimoor ZaeemandWolfgang Walther 07f51f323e refactor: remove unused optValue function from Config.hs module 2025-05-14 17:41:57 +00:00
Taimoor ZaeemandSteve Chavez 8b63ea82ec test: add test for duplicate entries in pg_description with same OID 2025-05-14 09:31:48 -05:00
Taimoor ZaeemandGitHub 8390df0fa5 fix: jwt error return status 400 for invalid role (#4081) 2025-05-13 15:09:25 -05:00
Taimoor ZaeemandLaurence Isla 1609e32c3a test: add test when using .aud in jwt-role-claim-key 2025-05-10 16:19:22 +00:00
Laurence Isla c5cba11ecb docs: fix link to SQL Query Logs 2025-05-09 20:59:51 -05:00
steve-chavez 257a7d1488 docs: jwt role extraction link to config
The feature section was missing a link to its config.

Also shorten the section name.
2025-05-09 20:45:37 -05:00
Wolfgang Walther bcf66253bd chore: adjust changelog for db-extra-search-path
Came up in #4073
2025-05-09 14:56:53 +02:00
Wolfgang Walther 451676c5be bump version to 13.1 2025-05-08 21:48:51 +02:00
Adam WespiserandGitHub 20f2e894c9 0.3.4 release (#148) 2024-02-04 22:23:39 -05:00
Erik de Castro LopoandGitHub 5a98f0c26d Make it build with ghc 9.8 (update deps only) (#146) 2024-02-04 22:19:13 -05:00
4680e62d7b ghc 9.4 PR (w/ Cabal improvement) (#142)
* Release 0.3.3, with support for GHC 9.4

- allow base-4.18 (GHC 9.4)
- allow ghc-prim 0.10
- allow bytestring 0.11.4
- test against GHC 9.4.4

Further CI tweaks:

- cabal: update GHC versions to the latest releases of the respective major version
- cabal: remove non-latest minor versions
- stack: add lts-20 (GHC 9.2.5)
- stack: bring the list of GHC versions up to date

* Update Cabal CI

---------

Co-authored-by: Robert Vollmert <rob@vllmrt.net>
2023-02-15 21:41:08 -05:00
Christoph SchiesslandGitHub cd83ebec00 Updates README to correctly list all supported stack LTS versions (#140)
* Updates README to correctly list all supported stack LTS versions

* Updates README to include LTS 19.14 and higher
2022-08-27 19:59:13 -04:00
Adam WespiserandGitHub e40b7351ec 0.3.2 Release (#127) (#138) 2022-06-12 13:46:49 -04:00
Adam WespiserandGitHub 3e249724fd 0.3.1 Release (#133) 2022-03-12 21:42:32 -05:00
Adam WespiserandGitHub 1b453b6064 Re-export isInfixOf, isSuffixOf from Data.List, Issue #119 (#135) 2022-03-06 11:20:07 -05:00
Adam WespiserandGitHub 3611929f01 Fix Hackage Formatting (#134) 2022-02-28 23:34:03 -05:00
f8cf1375d5 Add HasCallStack to unsafe* functions (#129)
Co-authored-by: Adam Wespiser <adamwespiser@gmail.com>
2022-02-21 14:38:19 -05:00
Adam WespiserandGitHub ee4d94feab Support ghc-9.0.1 (#131) 2022-02-20 20:19:01 -05:00
4e11d80eb7 Allow transformers-compat 0.7 (#125)
Tested to build fine.

Co-authored-by: Adam Wespiser <adamwespiser@gmail.com>
2021-12-01 00:33:59 -05:00
84d228a3b5 gcdInt' and gcdWord' are defined only with integer-gmp (#123)
Co-authored-by: Adam Wespiser <adam.wespiser@simspace.com>
2021-11-20 16:03:29 -05:00
Adam WespiserandGitHub f162c21d1b Update github actions, add new lts to tests (#124) 2021-11-17 09:17:40 -05:00
Stephen DiehlandGitHub e613ed4dd2 Merge pull request #120 from martijnbastiaan/readMaybeEither
Banish `String` on `readMaybe` and `readEither`
2021-01-04 18:30:54 +00:00
Martijn Bastiaan 36ce510547 Banish String on readMaybe and readEither 2020-12-05 20:06:45 +01:00
sdiehl 22e2cecaee 8.10.1 support to CI 2020-07-15 14:40:41 +01:00
Stephen DiehlandGitHub 0a92513108 Merge pull request #118 from protolude/strconv
Migrate show to use Conv.StringConv
2020-05-04 16:08:54 +01:00
sdiehl 9309ca3107 Migrate show to use Conv.StringConv 2020-04-25 11:58:41 +01:00
sdiehl 8ff8b7ae49 Update bounds in README 2020-03-27 12:40:31 +00:00
sdiehl 68f668951f Bump base & ghc-prim bounds for 8.10.1 2020-03-27 09:12:59 +00:00
sdiehl 7e081500f3 Supports lts 15.x 2020-03-21 13:20:57 +00:00
Stephen DiehlandGitHub 2666f1e830 0.3 Release (#115)
* Add total ConvertText alternative to Conv

* Explain ConvertText's meaning

* Rename convertText to toS for compatibility

* 0.3.0 Refactor (#111)

* Begin work on 0.3 refactor

* Remove old docs folder

* Fix dodgy exports

* 4.8 constraint for null and length

* Guards for Semigroup export for base<4.9

* Fix Data.Bits exports

* Guards for typeable exports

* Remove unused pragmas

* Update hlint.yaml

* Use liftM because of pre-AMP quirkk

* Data.Char exports

* Rework Exception exports

* Fix bounds

* Adding Monad.Fail shim

* Fix displayException export

* Explicit GHC.Prim import for ancient ghc

* Explicit raise# for base-4.7

* Flush legacy testing infrastructure

* Update git location

* Update README

* Add Partial module

* Add concurrency exports

* Explicit GHC.Float exports

* Bounds for threadWaitReadSTM, threadWaitWriteSTM, forkOSWithUnmask

* Fix for weird undocumented underflowError weirdness

* forkOSWithUnask for base>4.8

* Fix GHC.Real exports pre base-4.7

* Fix withMVarMasked for base-4.7

* Update nix derivation

* Update derivation

* Update derivation

* Explicit functor exports

* <$ export

* Overwrite binary

* Fix some missing exports

* Update Changelog

* Minor export fixes base<4.9

* Explicit exports

* Export handler

* Generate export lists for multiple versions (#114)

* Generate export lists for #112

* Make export lists format OccName uniformly

* Make compile on ancient GHC

* Use Foldable.concat

* Hacks to make ghc-7.6 API happy

* liftIO shim

* Fix sortOn warning

* Update ChangeLog

* Update base bounds

* Export conventions

* Update Haddocks

* Document GHC magic
2020-01-24 11:06:09 +00:00
sdiehl 03f73d8cde Name nix workflow 2020-01-04 23:12:42 +00:00
sdiehl af6cabe185 Added Nix CI 2020-01-04 23:02:48 +00:00
sdiehl e7a8e99f3f Fix install path for cabal. 2020-01-04 19:07:36 +00:00
sdiehl 0fda50b372 Cache cabal builds 2020-01-04 19:04:42 +00:00
sdiehl 76ad00a018 Run cabal update. 2020-01-04 18:49:38 +00:00
sdiehl e9da6f635e Add HLint action. 2020-01-04 18:48:01 +00:00
sdiehl e02ac85388 Fix Stack build names 2020-01-04 17:57:19 +00:00
sdiehl 3dd5152aba Build Stack CI on PRs 2020-01-04 17:55:55 +00:00
sdiehl 0ea2c5146a Seperate Stack and Cabal scripts 2020-01-04 17:54:59 +00:00
sdiehl 612726f87e Fix YAML for workflow 2020-01-04 17:29:28 +00:00
sdiehl 4d1f8dc86b Add Stack CI script 2020-01-04 17:28:27 +00:00
sdiehl 1277dfd941 Test all supported GHC versions 2020-01-04 17:19:50 +00:00
sdiehl a645953330 Fix GHC version 2020-01-04 16:26:15 +00:00
sdiehl fa0f1dc0fa Build on pull requeests 2020-01-04 16:23:51 +00:00
sdiehl 5e1b1ea982 Update build status badges 2020-01-04 16:18:33 +00:00
sdiehl f39de46d9f Don't install 2020-01-04 15:58:57 +00:00
sdiehl 95ccde5a2d Use cabal-new-build 2020-01-04 15:54:10 +00:00
Stephen DiehlandGitHub b8fa8a0729 Create haskell.yml 2020-01-04 15:39:54 +00:00
sdiehl ae9dd77749 Support all lts-14 resolvers 2019-11-22 08:06:09 +00:00
sdiehl 66d6d3506f Add lockfiles for resolvers 2019-11-02 18:46:01 +00:00
Stephen Diehl 357c0fdbed Update readme for 8.8.1 support 2019-10-10 11:49:44 +01:00
Stephen Diehl a93c7e6343 Support lts-14.* and GHC 8.8.1 2019-10-10 10:37:27 +01:00
Pi3randStephen Diehl 65c61c1d63 Fix #107: support ghc-8.8 (#108)
* Fix #107: support ghc-8.8

* Add travis build for ghc 8.8.1
2019-10-08 11:43:18 +02:00
Ary BorenszweigandStephen Diehl 2770a143d0 Update link to exported functions (#106)
The file `Symbols.md` doesn't exist anymore in the repository.

In the meantime Haddock fixed a long standing bug that allows Hackage to display all exported symbols now so we can now link to it.
2019-07-23 06:28:56 +01:00
Stephen Diehl c649da1944 Update LTS 13 resolvers 2019-06-20 11:29:01 +01:00
Stephen Diehl 9d450cd9ff Fixity declaration for <<*>>, fixes #103 2019-04-15 10:04:25 +01:00
Thomas ScholtesandStephen Diehl 7491e92f2a 'Protolude.Error.error' produces call stacks (#102)
Calling `Protolude.Error.error` will now include the call stack in the
`ErrorCall` that is raised. Before this was not the case because we used
the wrong implicit variable.
2019-04-10 15:38:14 +01:00
VilemandStephen Diehl 3add75ac4d Add lines, words, unlines, unwords (#101)
These operations (over `String` instead of `Text`) are part of Prelude.
2019-04-06 14:30:53 +01:00
Stephen Diehl 278b6c59e6 Bump licenses for 2019 2019-04-02 15:02:33 +01:00
Stephen Diehl ff8ed02b81 Support LTS-13.x resolvers 2019-03-28 16:58:36 +00:00
Alex PankoffandStephen Diehl cfa026a068 Remove note about error function from README (#100) 2019-03-18 10:38:04 +00:00
Greg SteuckandStephen Diehl a69d4ec1dd Typo (#98) 2019-01-24 13:30:54 +00:00
Stephen Diehl b45c3e6e73 New resolvers 2018-12-06 16:41:46 +00:00
Stephen Diehl b1f7eb5899 All LTS 1.2x resolvers 2018-11-21 12:39:16 +00:00
Stephen Diehl 8bf457d6b7 Remove symbols.md file 2018-11-08 14:12:58 +00:00
Stephen Diehl 8c3c133342 Fix for TypeInType before 8.6 2018-10-02 10:37:58 +01:00
Stephen Diehl ced5fd366e Minor version bump 2018-10-02 10:30:43 +01:00
Andre Van Der MerweandStephen Diehl 8c88bc7d64 GHC 8.6.1 support (#95)
* GHC 8.6.1 support

 - Bounds changes for base, containers and stm
 - stack lts 12.* tests
 - works with stack 8.6.1 nightly
    stack build --resolver nightly --haddock --test --bench --no-run-benchmarks
 - works with cabal new-build

* GHCVER-8.6.1
2018-10-01 20:20:06 +01:00
Stephen DiehlandGitHub 5024f3fef9 Add support for GHC 8.6 (#94)
* Add support for GHC 8.6

* Fix STM version bounds on pragma
2018-10-01 17:35:27 +01:00
Stephen Diehl 1b1f82b749 Export groupBy, fixes #91 2018-08-03 13:14:31 +01:00
Tony DayandStephen Diehl f75c99bda8 Some fixes for ghc-8.6 (#93) 2018-07-29 08:04:03 +01:00
Stephen Diehl 7c0e45c844 Support LTS-11 family of resolvers for testing 2018-06-15 10:29:42 +01:00
David HewsonandStephen Diehl ace10b648c <&> docs fix (#88)
`@<&>@`  appears as `&` on the page, which seems wrong
2018-06-10 09:20:15 +01:00
Michael SnoymanandStephen Diehl 8a8eb8c728 Add extra-source-files (#87) 2018-05-28 11:21:12 +01:00
Stephen Diehl 3bd6f07f9b Remove error function from symbol list 2018-05-08 09:39:55 +01:00
Stephen Diehl d6a710e40e Expose fromLeft and fromRight 2018-04-16 14:42:53 +01:00
Stephen Diehl 675837c232 Fix Data.Functor export list 2018-03-26 13:05:57 +01:00
Stephen Diehl 243a309bc1 On Base 4.11 use the provided <&>, fixes #53 2018-03-26 11:33:46 +01:00
Stephen Diehl 60943c0596 Drop safe dependency 2018-03-26 11:18:42 +01:00
Stephen DiehlandGitHub a8d1363581 Rework Safe Module (#83)
* Initial fork on minimal safe submodule

* Add new Safe module

Signed-off-by: Stephen Diehl <stephen.m.diehl@gmail.com>

* Refactor Safe module
2018-03-22 13:31:29 +00:00
Tony DayandStephen Diehl 57912017fe Bump upper bound for base & ghc84 bumps (#82) 2018-03-19 10:11:35 +00:00
Stephen Diehl f542a361a4 Bump upper bound of protolude transformers-compat 2018-03-01 14:21:01 +00:00
venandStephen Diehl 70fca4ab9c Fix symbols.md rendering (#80) 2018-02-08 13:55:00 +00:00
Stephen Diehl 81dcc985fc Bump minor version 2018-02-05 14:52:51 +00:00
Stephen Diehl 9a61a70a19 Looser lower-bound on Data.Kind export for GHC 8.0.x for #79 2018-02-05 14:33:12 +00:00
Stephen Diehl 8c9d0f4666 Bump upper bound for async 2.2.1 2018-02-05 10:20:40 +00:00
Stephen Diehl fd7fc5fb8e Update changelog 2018-01-12 11:11:09 +00:00
Stephen Diehl 65a0518008 Update changelog 2018-01-08 17:05:20 +00:00
Stephen Diehl 7f29497262 Minor version bump 2018-01-08 16:29:18 +00:00
Stephen Diehl 6d2a32f0dd Add transformers-compat for ancients MTL/Transformer versions 2018-01-08 16:28:14 +00:00
Stephen Diehl 74f185e22f Update stack build scripts 2018-01-07 13:03:56 +00:00
Stephen Diehl 8db43f6bff Bump upper bounds for safe 2018-01-07 09:04:20 +00:00
Ian JeffriesandStephen Diehl 4694fee383 Fix spelling. (#77) 2017-12-27 10:29:52 +00:00
Moritz KieferandStephen Diehl 2d8d1f3357 Reexport scanl' (#74)
This is useful for the same reasons that foldl' is useful
2017-12-18 19:03:45 +00:00
ProfpatschandStephen Diehl d462550f07 add mapExcept(T) and withExcept(T) (#76)
Since we already export functions like `withState` and the names don’t clash
with anything, we export these transformation functions as well.
Every function from Control.Monad.Except is now exported, the user doesn’t need
to import it for common error handling tasks.
2017-12-18 13:04:43 +00:00
Pi3randStephen Diehl c9a2d176d1 Add throwE & catchE (#73)
* Add throwE & catchE

My understanding is that `throwError` & `catchError` are deprecated (maybe we should remove them?)

* Update Protolude.hs

* Update Protolude.hs
2017-11-30 13:31:19 +00:00
TimothyandStephen Diehl 8eb1633dd8 Add warnings for partial functions (#70) 2017-10-24 14:27:18 +01:00
Stephen Diehl 2c44add128 Merge branch '4e6-ghc-822rc1' 2017-10-05 13:20:58 +01:00
Stephen Diehl 62393669dc update the travis file for 8.2.2 2017-10-05 13:20:47 +01:00
Dmitry Bushev abf2fbc369 Support GHC-8.2.2
When compiling with GHC 8.2.2-rc1:

```
src/Error.hs:25:17: error:
    Variable ‘r’ used as both a kind and a type
    Did you intend to use TypeInType?
   |
25 | error :: forall (r :: RuntimeRep) . forall (a :: TYPE r) . HasCallStack => Text -> a
   |                 ^^^^^^^^^^^^^^^^^
```

`TypeInType` should be enabled, see GHC issue 14121
https://ghc.haskell.org/trac/ghc/ticket/14121
2017-10-05 14:29:35 +03:00
Pi3randStephen Diehl 72085dec92 Add putErrLn to match putStrLn (#67)
* Add `putErrLn` to match `putStrLn`

Fix #66

* Add putErr for the most usual inference case

* Rename `putErr` into `putErrText`

In order to allow further specializations in the future if necessary.
2017-10-04 08:53:19 +01:00
Tony DayandStephen Diehl 923194c5b2 ghc-8.2 HasField, Type & * (#65) 2017-09-15 13:43:41 +01:00
Stephen Diehl 5964f545cf fix bifunctor import for base 4.8 2017-08-22 19:55:51 +01:00
Stephen DiehlandGitHub 8387808d6e Fix README with relative links 2017-08-22 19:26:57 +01:00
Stephen Diehl 2cd38fcb03 remove hidden modules 2017-08-22 19:25:27 +01:00
Stephen Diehl 9533e739ff use hierarchical namespace for all modules 2017-08-22 19:23:46 +01:00
Stephen Diehl 6c9b60700e expose debug module 2017-08-17 10:05:02 +01:00
Michael BurgeandStephen Diehl 7908bad846 Debug trace functions now output to stderr (#62) 2017-08-05 14:22:21 +01:00
Tony DayandStephen Diehl bfc7306ed7 Added RealFloat (#61) 2017-07-28 13:06:13 +01:00
Stephen Diehl 63d561de0c bump docs upper bounds for base for GHC 8.2 2017-07-25 13:03:07 +01:00
Pi3randStephen Diehl 3175e6c1eb Update protolude.cabal (#60)
Increase upperbound of safe.

This allows the master git version to build using the latest stackage`lts-8.23`
2017-07-24 17:54:42 +01:00
Stephen Diehl eccb07f726 polymorphic return type for die 2017-07-17 16:33:12 +01:00
Stephen Diehl 459d82012b Merge branch 'cocreature-ghc-8.2' 2017-07-05 14:42:40 +01:00
Stephen Diehl 5717b9a42c description and synopsis lines for latest cabal 2017-07-05 14:42:30 +01:00
Moritz Kiefer d7bc982142 Bump base upper bound for GHC 8.2 2017-07-05 08:02:57 +02:00
ProfpatschandStephen Diehl d30d6a39ab add (<&>), fixes issue #53 (#56) 2017-06-14 07:33:23 +02:00
Stephen DiehlandGitHub 46220a1a4a Added HasCallStack constraint for trace functions (#55)
* added HasCallStack constraint for trace functions, for issue #39

* unpack string on 7.6
2017-05-31 10:13:08 +01:00
Stephen Diehl c2570f77e6 better named either helper function, fixes #54 2017-05-20 19:03:29 +01:00
Stephen Diehl b4d33c3c96 include until from GHC.Base 2017-05-06 13:39:48 +01:00
Stephen Diehl 8c676e28de expose all pointers 2017-05-03 10:48:48 +01:00
Stephen Diehl a2c66fc236 update changelog 2017-05-03 10:44:31 +01:00
Stephen Diehl 456a063e35 update changelog 2017-05-03 10:37:39 +01:00
Stephen Diehl 269c81b1d2 make die take Text argument, fixes #51 2017-05-03 10:29:55 +01:00
Moritz KieferandStephen Diehl 307ecd7d6a Add hPutStr and hPutStrLn (#52) 2017-05-03 10:01:19 +01:00
Stephen Diehl 41710698ee note about unzip exposure 2017-03-24 10:14:49 +00:00
Stephen Diehl 8b9197ff01 ghc 8.0.2 supported 2017-03-17 13:09:12 +00:00
Stephen Diehl 89d4a49c7e export constructors for GHC.Generics sum/product 2017-03-17 13:07:24 +00:00
Stephen Diehl ca5087201b adds unzip, fixes issue #45 2017-03-12 15:54:30 +00:00
Stephen Diehl 8ad2522cda add strictness functions documentation 2017-03-11 09:59:58 +00:00
Stephen Diehl 5866877d3f reformat base exports of typelits 2017-03-11 09:54:30 +00:00
Pi3randStephen Diehl 92905843a4 Update CHANGES (#42) 2017-03-09 22:48:04 +00:00
Pi3randStephen Diehl a324e26d54 Update safe upper bound for ghc >=7.8.0 (#43) 2017-03-09 22:47:29 +00:00
Pi3randStephen Diehl 79bbc2de6e Add short-circuiting version of '<||>' and '<&&>' (#41) 2017-03-05 14:05:05 +00:00
Pi3randStephen Diehl 721374d42c Add (<&&>),(<||>) (#40) 2017-02-28 14:59:05 +00:00
Stephen Diehl 0ab61665ee liftIO1 and liftIO2 for issue #38 2017-02-11 14:52:56 +00:00
Stephen Diehl 6ac3e01da0 fix safe bounds for breakage on GHC 7.0.1 build 2017-02-11 13:47:31 +00:00
Alexander KjeldaasandStephen Diehl fd3d667cde Typo? (#37) 2017-02-07 14:12:47 +00:00
Stephen Diehl f9b5a5cbf4 export Floating 2017-01-21 14:53:04 +00:00
Carl BaatzandStephen Diehl 12cd9fae46 String is not exported. (#36) 2017-01-13 07:26:34 +00:00
Stephen Diehl 531a07ccfc test all stack resolvers 2017-01-03 15:50:05 +00:00
Stephen Diehl e72d06929e Hold off on exporting TypeInType machinery 2017-01-03 14:13:25 +00:00
Stephen Diehl 39d56792ce Fix up PBase exports, expose Generics metadata 2017-01-02 13:28:21 +00:00
Stephen Diehl 3994639b2b Mask supporting modules 2017-01-02 12:06:37 +00:00
Stephen Diehl 03f5746e96 Rework implicit exports to be explicit. 2017-01-02 11:46:11 +00:00
Stephen Diehl 070ac54067 Fix byteswap functions under GHC 7.6 2017-01-02 10:59:05 +00:00
Stephen Diehl e452604224 Fix Void and Proxy under GHC 7.6 2017-01-02 10:53:01 +00:00
Stephen Diehl e836d3f690 stack test harness 2017-01-02 10:45:43 +00:00
Ian JeffriesandStephen Diehl 51fdf38c71 Rename msg to fatalErrorMessage. (#34)
This is to free up `msg` as a variable name.
2017-01-01 18:45:08 -05:00
Stephen Diehl d0e81532af Use Data.Function (&) if base>4.8, fixes #33 2017-01-01 23:43:43 +00:00
Stephen Diehl 4a2ea2735b Merge branch 'docs'
Conflicts:
	CHANGES.md
2017-01-01 20:24:57 +00:00
Stephen Diehl 6d3940b4e5 new difflog 2017-01-01 20:24:32 +00:00
Stephen Diehl 254dafcb12 basic examples 2016-12-29 19:46:57 +00:00
Stephen Diehl 33e412b59b bump license 2016-12-26 17:49:43 +00:00
Stephen Diehl 5ce97cd0e9 expand list processing functions 2016-12-15 15:38:15 +00:00
Stephen Diehl 1140df0f91 stub out rest of toc 2016-12-15 15:06:15 +00:00
Stephen Diehl ed6fa9c8ea refine monaderror section 2016-12-14 17:16:20 +00:00
Stephen Diehl 1f2ed3e4cb fix lower bounds 2016-12-13 12:31:47 +00:00
Stephen Diehl cc0565112f monoid and fold rearranging 2016-12-13 09:14:39 +00:00
Stephen Diehl 0fb7730b0c expand semigroup 2016-12-12 16:30:52 +00:00
Stephen Diehl d6d1004070 monoid module 2016-12-12 16:21:49 +00:00
Stephen Diehl c7eeb5349e fix exports for functor module 2016-12-12 16:10:49 +00:00
Stephen Diehl 257a38f68f functor module 2016-12-12 13:09:18 +00:00
Stephen Diehl 66958def93 export encoding error handlers 2016-12-12 11:14:42 +00:00
Stephen Diehl c692eb03fb only export byteswap functions for ghc >7.6 2016-12-12 11:04:52 +00:00
Stephen Diehl a33669ca6d maybe functions 2016-12-12 11:03:34 +00:00
Stephen Diehl 6cb17bb94b utility functions 2016-12-10 16:01:47 +00:00
Stephen Diehl 00c2fce11a console functions 2016-12-10 14:51:33 +00:00
Stephen Diehl 8995aa71f3 bits and files 2016-12-10 13:28:32 +00:00
Stephen Diehl b32c80d0bb basic hierarchy in place 2016-12-10 12:46:48 +00:00
Stephen Diehl c28fa6b00c debug module 2016-12-08 13:12:42 +00:00
Stephen Diehl e041d6de8a added makefile 2016-12-08 12:23:56 +00:00
Stephen Diehl 7cdf6f1cc8 markdown source processor 2016-12-08 12:23:15 +00:00
Stephen Diehl fb6a942954 export generic list functions 2016-12-08 09:55:27 +00:00
Stephen Diehl ca74e2901d document structure 2016-12-08 09:47:06 +00:00
Stephen Diehl 60ca33fecb begin conversion to rst 2016-12-08 09:36:00 +00:00
Stephen Diehl fb6f00b90b clearer directions 2016-12-08 09:03:22 +00:00
Stephen Diehl dac4888f61 ignore ghc 8.0 only pragma 2016-12-06 13:57:48 +00:00
Stephen Diehl 50faedad80 added ghc 8.0.1 test 2016-12-06 09:39:23 +00:00
Stephen Diehl d5db73dbbf conditional safe version bounds for ghc 2016-12-06 09:06:47 +00:00
Stephen Diehl 6da0d42e8d updated changelog 2016-12-04 08:46:11 +00:00
Stephen Diehl 7060f55fdf export typelits symbols from base 2016-12-03 14:31:42 +00:00
Stephen Diehl 2b729aaadc Type level literals 2016-12-03 14:17:49 +00:00
Stephen Diehl fa482cfd46 bump version to 0.1.11 2016-11-15 16:18:43 +00:00
Stephen Diehl 3972d847e6 constrain safe upper bound for backwards compat with ghc 7.6 2016-11-15 15:14:16 +00:00
Stephen Diehl 82e0b04e4d use default monoid (<>) instead of semigroup 2016-11-15 14:57:16 +00:00
Stephen Diehl 7560af0955 relax lower async bound 2016-11-08 01:40:20 +00:00
Stephen Diehl 5b6bc27cbe constrainted bytestring print functions 2016-10-28 19:04:58 +01:00
Stephen Diehl aeacdd9630 include hashable 2016-10-28 16:41:28 +01:00
Stephen Diehl 250cfe2b7f version bump 2016-10-27 10:12:29 +01:00
Stephen Diehl c43a282322 Merge branch 'master' of github.com:sdiehl/protolude 2016-10-27 10:07:23 +01:00
Stephen Diehl d090411207 bump version 2016-10-27 10:05:52 +01:00
Stephen DiehlandGitHub 077198f1a5 Merge pull request #27 from cocreature/fixproduct
Fix product implementation
2016-10-18 15:59:15 +01:00
Moritz Kiefer bccd31e327 Fix product implementation 2016-10-18 15:13:01 +02:00
Stephen Diehl cf2fb7cd3a Note about strictness 2016-10-16 20:13:13 +01:00
Stephen DiehlandGitHub f95489b8f2 Merge pull request #26 from cocreature/sumproduct
Export strict versions of sum and product
2016-10-16 20:11:59 +01:00
Moritz Kiefer 961f71b971 Export strict versions of sum and product 2016-10-14 22:06:44 +02:00
Stephen Diehl 547aca5af4 fix nested functor composition 2016-10-14 17:21:57 +01:00
Stephen Diehl 860f74b3c2 Use explicit 'bool' import. 2016-10-14 14:06:57 +01:00
Stephen Diehl a86046b654 guarded and guardedA added to root. 2016-10-14 11:03:37 +01:00
Stephen Diehl c061df8f06 Applicative combinators. 2016-10-14 10:56:37 +01:00
Stephen Diehl a2e97dc936 Update FAQ. 2016-10-12 11:05:39 +01:00
Stephen Diehl e3e2857424 Changelog for 0.1.8. 2016-10-10 12:50:31 +01:00
Stephen Diehl 4f96a523da AMP fallout compatability fix. 2016-10-10 12:36:09 +01:00
Stephen Diehl 9e4f374811 Bump version. 2016-10-10 11:15:12 +01:00
Stephen Diehl 7a0e274b20 note and hush for #22 2016-10-10 11:13:26 +01:00
Stephen Diehl 2010cec78e Mask yield, fixes #23 2016-10-10 11:05:40 +01:00
Stephen Diehl 0346b366ee Remove Handler export, fixes #25. 2016-10-10 11:02:24 +01:00
Stephen Diehl ee06770742 `pass` function, fixes #25 . 2016-10-10 11:00:42 +01:00
Stephen Diehl a678ca3b60 Remove head test from travis. 2016-09-14 16:33:02 +01:00
Stephen Diehl 36b56ad3a2 for function for #19 2016-09-14 09:47:47 +01:00
Stephen Diehl e14e1e3613 Change log for 0.1.7. 2016-08-15 08:43:55 -04:00
Stephen Diehl d17fc9aab3 traceShow and traceShowId for #16 2016-08-13 16:14:15 -04:00
Stephen Diehl 5bf3b7f812 Full outline. 2016-07-29 12:28:29 -04:00
Stephen Diehl 5de8f47138 Stubs. 2016-07-29 12:07:32 -04:00
Stephen Diehl 4437583e3f Fix links. 2016-07-29 11:36:38 -04:00
Stephen Diehl 76f3f9f17c monad docs 2016-07-29 11:33:32 -04:00
Stephen Diehl 1cb0630529 New symbol documentation. 2016-07-21 14:49:09 -04:00
Stephen Diehl 7aa8b6646e Expose `state and `reader` functions. 2016-07-05 07:22:46 -04:00
Stephen Diehl 245dd5190e Explicitly lift throwIO and throwTo. 2016-07-02 20:11:20 -04:00
Stephen Diehl 2f619f3ebd Link to pretty printer library. 2016-07-02 17:57:44 -04:00
Stephen Diehl b658b4c8ef Note explicit String types. 2016-07-02 17:32:11 -04:00
Stephen Diehl b621258ce7 Better example text for panic. 2016-07-02 17:31:00 -04:00
Stephen Diehl 827c0ef87b Formatting for FAQ. 2016-07-02 17:27:40 -04:00
Stephen Diehl 6b6f8967ac Note about exception handling. 2016-07-02 14:00:26 -04:00
Stephen Diehl 21be7f2908 Fix 0.1.6 changelog. 2016-07-02 13:50:31 -04:00
Stephen Diehl f0fd11791c Add unsnoc function. 2016-07-01 11:25:10 -04:00
Stephen Diehl f6586ba8b4 Change safety language flags. 2016-06-30 23:02:39 -04:00
Stephen Diehl 63d5ed625d Encoding functions in scope by default. 2016-06-30 22:56:00 -04:00
Stephen Diehl c2ca1677c8 Control.Exception as qualified import. 2016-06-30 18:49:28 -04:00
Stephen Diehl b8479ebcb5 Move throw to Unsafe exports. 2016-06-30 18:48:55 -04:00
Stephen Diehl 89fdc587e0 Single SrcLoc export. 2016-06-30 18:28:21 -04:00
Stephen Diehl cf1fa981ef Remove showCallStack. 2016-06-30 18:14:30 -04:00
Stephen Diehl cef28ed3a0 Remove throw and assert exports. 2016-06-30 17:59:09 -04:00
Stephen Diehl 205643ea14 Callstack for GHC 8.x. 2016-06-30 17:45:39 -04:00
Stephen Diehl fa58c5452a Added changelog. 2016-06-30 11:14:47 -04:00
Stephen Diehl 22c0e743f9 Added changelog. 2016-06-30 11:09:58 -04:00
Stephen Diehl f4178f0472 FAQ section. 2016-06-30 11:04:51 -04:00
Stephen Diehl e2b886bb64 MOre specializers. 2016-06-30 10:59:15 -04:00
Stephen Diehl a7bc40452f Fix up bound documentation. 2016-06-30 10:49:13 -04:00
Stephen Diehl 0aa40b8b21 Don't support alternative Base. 2016-06-30 10:41:55 -04:00
Stephen Diehl dce9f0c9d5 github table formatting 2016-06-17 09:51:34 -04:00
Stephen Diehl b6805513f6 Dependencies note. 2016-06-17 09:49:49 -04:00
Stephen Diehl e0cace8a4d Symbols list. 2016-06-11 16:19:03 -04:00
Stephen Diehl 8d794da86c Remove printf. 2016-06-09 21:18:10 -04:00
Stephen Diehl 78b16ebcfa IO handle functions. 2016-06-09 20:18:55 -04:00
Stephen Diehl 173b86de45 Read actions for Strict text in scope by default. 2016-06-08 23:02:57 -04:00
Stephen Diehl 30d0bbca93 Debug functions to use Text. 2016-06-08 20:08:21 -04:00
Stephen Diehl a9c8d300a5 Remove string-conv dependency. 2016-06-08 19:47:08 -04:00
Stephen Diehl 6edc320b69 DeriveTyepable pragma. 2016-06-08 19:45:33 -04:00
Stephen Diehl 6ae19be4b7 Explicit Typeable for older GHC. 2016-06-08 19:38:45 -04:00
Stephen Diehl 6df421ad72 Panic module. 2016-06-08 19:32:03 -04:00
Stephen Diehl 1e690a9e78 bump version 2016-06-08 19:15:03 -04:00
Stephen Diehl f05079bf98 Add 8.0.1 support to Travis. 2016-06-08 19:05:43 -04:00
Stephen Diehl d39e014533 unsafeFromJust 2016-06-06 08:50:12 -04:00
Stephen Diehl 75f5f4d88f pull Conv into core 2016-05-09 14:22:13 -04:00
Stephen Diehl a70f6e2d84 bump version 2016-05-07 09:43:20 -04:00
Stephen Diehl 561ee5077e fix traceShow fixes #10 2016-04-27 15:27:42 -04:00
Stephen Diehl a9cc28f3b1 remove partial functions 2016-04-21 18:50:01 -04:00
Stephen Diehl 0b3090973e pulling semiring in module 2016-04-19 09:32:59 -04:00
Stephen Diehl fba329438f bump version 2016-04-19 09:13:06 -04:00
Stephen Diehl c0b161602d export generics 2016-04-18 18:09:50 -04:00
Stephen Diehl 2c83d2dbf6 data.records still in flux upstream 2016-04-18 14:02:58 -04:00
Stephen Diehl 5c8186f618 handle semigroup monoid 8.0 compat 2016-04-18 13:50:18 -04:00
Stephen Diehl aecd72fa5c ghc 8.0 record and typeintype prelude objects 2016-04-18 13:39:36 -04:00
Stephen Diehl 8756b6507b unbreak functor/monad issue in old ghc vers 2016-04-18 11:17:02 -04:00
Stephen Diehl 4b3caa5c18 bring 7.10 type-level equality into scope 2016-04-18 11:09:03 -04:00
Stephen Diehl da7da2fe75 mask fail function 2016-04-18 10:51:02 -04:00
Stephen Diehl e442b31203 polymorphic show func 2016-04-18 10:35:34 -04:00
Stephen Diehl ed6d680c70 bump version 2016-04-16 11:08:30 -04:00
Stephen Diehl ea709c2945 Squashed commit of the following:
commit 416dc35d5a6ead5ce62063b56539d899e91bfd36
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Thu Apr 14 14:00:23 2016 -0400

    fix readme formatting

commit 8bf3029d01
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 18:39:39 2016 -0400

    design points in readme

commit 76bc617db9
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 17:09:10 2016 -0400

    functor include

commit cbaa117b8a
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 16:39:47 2016 -0400

    brenden's list function

commit ef52c8d507
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 16:36:42 2016 -0400

    gracefully handle 7.10 modules if present

commit f6fca1059d
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 16:28:37 2016 -0400

    not worth backporting void

commit 26d679e257
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 16:12:55 2016 -0400

    explicit base types, IsString export, Proxy

commit a14ad9bdd6
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 15:20:15 2016 -0400

    all non-partial list functions
2016-04-14 14:02:20 -04:00
Stephen Diehl e7debe1a2c Merge pull request #7 from sdiehl/list-extras
all non-partial list functions
2016-04-13 18:56:58 -04:00
Stephen Diehl 8bf3029d01 design points in readme 2016-04-13 18:39:39 -04:00
Stephen Diehl 76bc617db9 functor include 2016-04-13 17:09:10 -04:00
Stephen Diehl cbaa117b8a brenden's list function 2016-04-13 16:39:47 -04:00
Stephen Diehl ef52c8d507 gracefully handle 7.10 modules if present 2016-04-13 16:36:42 -04:00
Stephen Diehl f6fca1059d not worth backporting void 2016-04-13 16:28:37 -04:00
Stephen Diehl 26d679e257 explicit base types, IsString export, Proxy 2016-04-13 16:12:55 -04:00
Stephen Diehl a14ad9bdd6 all non-partial list functions 2016-04-13 15:20:15 -04:00
Stephen Diehl 5388b8cd4b Squashed commit of the following:
commit a6f62265f345c8b7a7226515171752586b0d66e5
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 13:41:05 2016 -0400

    bump version

commit 1a809623cd1484ce215612e6b3ecef15015bc602
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 13:26:11 2016 -0400

    masking for ghc 8.0 specific type

commit 54bafb0bb80c8450863eac53a1f3a20a21c8b0c9
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 12:55:08 2016 -0400

    bump ghc-prim for GHC 8.0 compat

commit 8808d5f37369107b3e5961255089a8a9e02bf3d5
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 12:53:39 2016 -0400

    expose base State transformers

commit 05c32a4542aa66f715aea3855e140f74e97d4852
Author: Stephen Diehl <stephen.m.diehl@gmail.com>
Date:   Wed Apr 13 12:46:00 2016 -0400

    adds compiler-independent base module
2016-04-13 13:51:47 -04:00
Stephen Diehl 99427e741c Merge pull request #5 from mitchellwrosen/master
Fix some re-exports
2016-04-13 11:42:26 -04:00
Mitchell Rosen 33d029c1b0 Fix some re-exports 2016-04-13 11:03:23 -04:00
Stephen Diehl 949d62cc12 qualified import of ByteString fixes #4 2016-04-12 09:43:59 -04:00
Stephen Diehl ef5b47b4f7 expose seq and asTypeOf 2016-04-09 20:43:26 -04:00
Stephen Diehl 26c148510e expose rest of safe functions 2016-04-09 20:17:55 -04:00
Stephen Diehl 1a6ce9436f include either module 2016-04-09 20:02:11 -04:00
Stephen Diehl 1f0a5a9576 backport bifunctor 2016-04-09 19:57:02 -04:00
Stephen Diehl 806939605a better readme 2016-04-09 19:35:23 -04:00
Stephen Diehl bd5f8f1b23 fix backwards compart for ($!) 2016-04-09 19:25:55 -04:00
Stephen Diehl 2c47ec7262 selectively expose more of ghc.base 2016-04-09 15:53:25 -04:00
Stephen Diehl cff538114d fix data.functor exports 2016-04-09 15:34:30 -04:00
Stephen Diehl 1c8fc29c4a bring flip into scope 2016-04-09 15:18:30 -04:00
Stephen Diehl 22fda7cedc added enum class 2016-04-09 15:16:56 -04:00
Stephen Diehl b3674708d4 functor module 2016-04-09 15:14:21 -04:00
Stephen Diehl 7a62c5d489 functor module 2016-04-09 15:13:13 -04:00
Stephen Diehl 959cd272f7 fix typo in fun name 2016-04-09 14:56:55 -04:00
Stephen Diehl 8cd2b4ffd3 build status 2016-04-09 14:50:45 -04:00
Stephen Diehl d5bdaf0c88 use in module traceM 2016-04-09 14:49:16 -04:00
Stephen Diehl 8f6e97633c backwards compat for traceM 2016-04-09 14:25:20 -04:00
Stephen Diehl 4bd0ed3e83 modern ghc only 2016-04-09 13:20:05 -04:00
Stephen Diehl 6ede03c8ce travis build 2016-04-09 13:07:45 -04:00
Stephen Diehl dd6a97adfa hackage package 2016-04-08 11:25:58 -04:00
Stephen Diehl ccf89378f8 fix import formatting 2016-04-07 17:33:20 -04:00
Stephen Diehl 8417d2a031 fix gitignore 2016-04-07 17:14:57 -04:00
Stephen Diehl 28dad7fca1 fix warnings 2016-04-07 17:14:42 -04:00
Stephen Diehl e94c364d65 readme 2016-04-07 15:34:56 -04:00
Stephen Diehl 29b854cf98 initial commit 2016-04-07 15:22:44 -04:00
261 changed files with 11885 additions and 4820 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
freebsd_instance:
image_family: freebsd-14-2
image_family: freebsd-14-3
build_task:
# Don't change this name without adjusting .github/workflows/build.yaml
@@ -35,7 +35,7 @@ build_task:
- find main src -type f -iname '*.hs' -exec md5sum "{}" +
build_script: |
stack build -j 1 --local-bin-path . --copy-bins --stack-yaml stack-21.7.yaml
stack build -j 1 --local-bin-path . --copy-bins
strip postgrest
bin_artifacts:
+2
View File
@@ -0,0 +1,2 @@
# Ignore blame for commit that moved protolude files under src/protolude
d4949c633e8172d0e4dd8f5c991eaaae6b48fbb0
-55
View File
@@ -1,55 +0,0 @@
# Contributing to PostgREST
**First:** if you're unsure or afraid of _anything_, just ask or
submit the issue or pull request anyways. You won't be yelled at
for giving your best effort. The worst that can happen is that
you'll be politely asked to change something. We appreciate any
sort of contributions, and don't want a wall of rules to get in the
way of that.
However, for those individuals who want a bit more guidance on the
best way to contribute to the project, read on. This document will
cover what we're looking for. By addressing all the points we're
looking for, it raises the chances we can quickly merge or address
your contributions.
## Issues
For questions on how to use PostgREST, please use
[GitHub discussions](https://github.com/PostgREST/postgrest/discussions).
### Reporting an Issue
* Make sure you test against the latest [stable release](https://github.com/PostgREST/postgrest/releases/latest)
and also against the latest [nightly release](https://github.com/PostgREST/postgrest/releases/tag/nightly).
It is possible we already fixed the bug you're experiencing.
* Provide steps to reproduce the issue, including your OS version and
the specific database schema that you are using.
* Please include SQL logs for issues involving runtime problems. To obtain logs first
[enable logging all statements](http://www.microhowto.info/howto/log_all_queries_to_a_postgresql_server.html),
then [find your logs](http://blog.endpoint.com/2014/11/dear-postgresql-where-are-my-logs.html).
* If your database schema has changed while the PostgREST server is running,
[send the server a `SIGUSR1` signal](http://postgrest.org/en/latest/admin.html#schema-reloading) or restart it to ensure the schema cache
is not stale. This sometimes fixes apparent bugs.
## Code
We have a fully nix-based development environment with many tools for a smooth development workflow available.
Check the [development docs](https://github.com/PostgREST/postgrest/blob/main/nix/README.md) on how to set it up and use it.
### Haskell Conventions
* All contributions must pass the tests before being merged. When
you create a pull request your code will automatically be tested.
* All code must also pass [hlint](http://community.haskell.org/~ndm/hlint/) and [stylish-haskell](https://github.com/jaspervdj/stylish-haskell)
with no warnings. This helps enforce a uniform style for all committers. Continuous integration will check this as well on every
pull request. There are useful tools in the nix-shell that help with checking this locally. You can run `postgrest-check` to do this manually but
we recommend adding it to `.git/hooks/pre-commit` as `nix-shell --run postgrest-check` to automatically check this before doing a commit.
### Running Tests
For instructions on running tests, see the [development docs](https://github.com/PostgREST/postgrest/blob/main/nix/README.md#testing).
+12 -11
View File
@@ -4,17 +4,18 @@ When submitting a new feature or fix:
- Add a new entry to the CHANGELOG - https://github.com/PostgREST/postgrest/blob/main/CHANGELOG.md#unreleased
- If relevant, update the docs
- Use a prefix for the PR title or commits, e.g. "fix: description of the fix".
+ `fix`, bug fixes
+ `feat`, new features added
+ `perf`, performance improvements
+ `docs`, updating the documentation
+ `nix`, related to the Nix development environment
+ `ci`, related to the Continuous Integration modules
+ `test`, related to the testing modules
+ `refactor`, refactoring code
+ `deprecate`, deprecating a feature
+ `changelog`, updating the CHANGELOG
+ `chore`, maintenance (build process, updating sponsors, etc.)
+ `add`, Add a new feature
+ `amend`, To amend an unrealease commit
+ `change`, Breaking changes
+ `chore`, Maintenance, update sponsors, changelog, readme etc
+ `ci`, CI configuration files and scripts
+ `docs`, Documentation
+ `fix`, Bug fix
+ `nix`, Related to Nix
+ `perf`, Performance improvements
+ `refactor`, Refactoring code
+ `remove`, Remove a feature or fix
+ `test`, Adding tests
+ Other prefixes may be used if necessary
- If there's a breaking change, add `BREAKING CHANGE` and an explanation to your commit message
-->
-5
View File
@@ -1,5 +0,0 @@
# TODO: Remove this once a new actionlint release has been cut
# and made its way to us through nixpkgs.
self-hosted-runner:
labels:
- ubuntu-24.04-arm
@@ -112,7 +112,7 @@ runs:
echo "artifacts=${artifacts}" >> "$GITHUB_OUTPUT"
- name: Save artifact to GitHub Actions
if: steps.find-task.outputs.task_found
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ inputs.upload }}
path: ${{ steps.download.outputs.artifacts }}
+6 -7
View File
@@ -8,7 +8,6 @@ inputs:
required: true
save-prs:
description: Whether to additionally store the cache in a pull request, too. Should only be used for very small caches.
type: boolean
prefix:
description: Cache key prefix to be used in both primary key and restore-keys.
required: true
@@ -19,17 +18,17 @@ inputs:
runs:
using: composite
steps:
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
- uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
if: ${{ startsWith(github.ref, 'refs/heads/') || (inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }}
with:
path: ${{ inputs.path }}
key: ${{ runner.os }}-${{ inputs.prefix }}-${{ inputs.suffix }}
key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.prefix }}-${{ inputs.suffix }}
restore-keys: |
${{ runner.os }}-${{ inputs.prefix }}-
- uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
${{ runner.os }}-${{ runner.arch }}-${{ inputs.prefix }}-
- uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
if: ${{ !startsWith(github.ref, 'refs/heads/') && !(inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }}
with:
path: ${{ inputs.path }}
key: ${{ runner.os }}-${{ inputs.prefix }}-${{ inputs.suffix }}
key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.prefix }}-${{ inputs.suffix }}
restore-keys: |
${{ runner.os }}-${{ inputs.prefix }}-
${{ runner.os }}-${{ runner.arch }}-${{ inputs.prefix }}-
+2 -2
View File
@@ -11,12 +11,12 @@ inputs:
runs:
using: composite
steps:
- uses: nixbuild/nix-quick-install-action@5bb6a3b3abe66fd09bbf250dce8ada94f856a703 # v30
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
with:
nix_conf: |-
always-allow-substitutes = true
max-jobs = auto
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
- uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17
with:
name: postgrest
authToken: ${{ inputs.authToken }}
+3
View File
@@ -4,6 +4,9 @@ codecov:
comment: false
github_checks:
annotations: true
coverage:
status:
project:
+7 -19
View File
@@ -3,7 +3,7 @@
"extends": [
"config:best-practices"
],
"baseBranches": [
"baseBranchPatterns": [
"main",
"/^v[0-9]+/"
],
@@ -13,28 +13,16 @@
},
"packageRules": [
{
"matchBaseBranches": [ "/^v[0-9]+/" ],
"matchManagers": ["haskell-cabal"],
"matchManagers": [
"haskell-cabal"
],
"enabled": false
},
{
"matchBaseBranches": [ "/^v[0-9]+/" ],
"matchBaseBranches": [
"/^v[0-9]+/"
],
"groupName": "all dependencies"
},
{
"matchManagers": ["haskell-cabal"],
"matchPackageNames": ["base", "bytestring", "containers", "directory", "mtl", "parsec", "process", "text"],
"groupName": "GHC dependencies"
},
{
"matchManagers": ["haskell-cabal"],
"matchPackageNames": ["hasql", "hasql-dynamic-statements", "hasql-notifications", "hasql-transaction", "hasql-pool"],
"groupName": "hasql"
},
{
"matchManagers": ["haskell-cabal"],
"matchPackageNames": ["fuzzyset"],
"allowedVersions": "<0.3"
}
]
}
+52
View File
@@ -0,0 +1,52 @@
name: Backport
on:
pull_request_target:
types:
- closed
- labeled
jobs:
backport:
name: Backport
runs-on: ubuntu-24.04
# It triggers only when PR is already merged on either:
#
# - The merge event itself (action != labeled) or
# - A label event with the right label (backport ...).
#
# The result will be that we can add the label before or after merge,
# but the workflow will only run once the PR had been merged.
if: >
github.event.pull_request.merged &&
(
github.event.action != 'labeled' ||
startsWith(github.event.label.name, 'backport')
)
steps:
# This actions creates the github token using the postgrest app secrets
- name: Create Github App Token
id: app-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
app-id: ${{ vars.POSTGREST_CI_APP_ID }}
private-key: ${{ secrets.POSTGREST_CI_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
permission-workflows: write # required when backporting CI changes
# This is required for backport action to cherry-pick the PR
- name: Fetch PR ref
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ github.event.pull_request.head.sha }}
token: ${{ steps.app-token.outputs.token }}
# Backport action that creates the PR with given settings
- name: Create backport PR
uses: korthout/backport-action@7c3f6cd5843cac11bc59a04a1b7699af93261670 # v4.5
with:
github_token: ${{ steps.app-token.outputs.token }}
pull_description: 'Backport for #${pull_number}.'
pull_title: '${target_branch}: ${pull_title}'
+39 -42
View File
@@ -16,6 +16,7 @@ on:
- .github/*
- '*.nix'
- nix/**
- flake.lock
- .cirrus.yml
- cabal.project*
- postgrest.cabal
@@ -30,56 +31,61 @@ concurrency:
jobs:
static:
name: Nix - Linux x86-64 static
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
include:
- name: Linux aarch64
runs-on: ubuntu-24.04-arm
artifact: aarch64
- name: Linux x86-64
runs-on: ubuntu-24.04
artifact: x86-64
name: Nix - ${{ matrix.name }} static
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build static executable
run: nix-build -A postgrestStatic
run: nix-build -A postgrestStatic -A postgrestStatic.tests
- name: Save built executable as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: postgrest-linux-static-x86-64
name: postgrest-linux-static-${{ matrix.artifact }}
path: result/bin/postgrest
if-no-files-found: error
- name: Build Docker image
run: nix-build -A docker.image --out-link postgrest-docker.tar.gz
run: nix-build -A docker.image --out-link postgrest-docker-${{ matrix.artifact }}.tar.gz
- name: Save built Docker image as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: postgrest-docker-x86-64
path: postgrest-docker.tar.gz
name: postgrest-docker-${{ matrix.artifact }}
path: postgrest-docker-${{ matrix.artifact }}.tar.gz
if-no-files-found: error
macos:
name: Nix - MacOS
runs-on: macos-14
runs-on: macos-15
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Install gnu sed
run: brew install gnu-sed
- name: Install nix-build-uncached
run: nix-env -f default.nix -iA nix-build-uncached
- name: Build everything
run: |
# The --dry-run will give us a list of derivations to download from cachix and
# derivations to build. We only take those that would have to be built and then build
# those explicitly. This has the advantage that pure verification will not include
# a download anymore, making it much faster. If something needs to be built, only
# the dependencies required to do so will be downloaded, but not everything.
nix-build --dry-run 2>&1 \
| gsed -e '1,/derivations will be built:$/d' -e '/paths will be fetched/Q' \
| xargs nix-build
- name: Build everything (default.nix)
run: nix-build-uncached
- name: Build everything (shell.nix)
run: nix-build-uncached shell.nix
stack:
@@ -87,15 +93,6 @@ jobs:
fail-fast: false
matrix:
include:
- name: Linux aarch64
runs-on: ubuntu-24.04-arm
cache: |
~/.stack/pantry
~/.stack/snapshots
~/.stack/stack.sqlite3
artifact: postgrest-ubuntu-aarch64
deps: sudo apt-get update && sudo apt-get install libpq-dev
- name: MacOS aarch64
runs-on: macos-14
cache: |
@@ -106,7 +103,7 @@ jobs:
deps: brew link --force libpq
- name: MacOS x86-64
runs-on: macos-13
runs-on: macos-15-intel
cache: |
~/.stack/pantry
~/.stack/snapshots
@@ -126,11 +123,11 @@ jobs:
name: Stack - ${{ matrix.name }}
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: haskell-actions/setup@64445b6b5dd545faf5f8e2acee8253eb5c2b29aa # v2.7.11
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: haskell-actions/setup@cd0d9bdd65b20557f41bea4dbe43d0b5fbbfe553 # v2.11.0
with:
# This must match the version in stack.yaml's resolver
ghc-version: 9.6.6
ghc-version: 9.10.3
enable-stack: true
stack-no-global: true
stack-setup-ghc: true
@@ -155,7 +152,7 @@ jobs:
- name: Strip Executable
run: strip result/postgrest*
- name: Save built executable as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.artifact }}
path: |
@@ -168,7 +165,7 @@ jobs:
name: Stack - FreeBSD from CirrusCI
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: ./.github/actions/artifact-from-cirrus
with:
token: ${{ github.token }}
@@ -180,13 +177,13 @@ jobs:
cabal:
strategy:
matrix:
ghc: ['9.6.6', '9.8.2']
ghc: ['9.10.3', '9.12.3']
fail-fast: false
name: Cabal - Linux x86-64 - GHC ${{ matrix.ghc }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: haskell-actions/setup@64445b6b5dd545faf5f8e2acee8253eb5c2b29aa # v2.7.11
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: haskell-actions/setup@cd0d9bdd65b20557f41bea4dbe43d0b5fbbfe553 # v2.11.0
with:
ghc-version: ${{ matrix.ghc }}
- name: Cache .cabal
+22 -1
View File
@@ -20,7 +20,7 @@ jobs:
name: Lint & Style
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
@@ -30,3 +30,24 @@ jobs:
run: postgrest-lint
- name: Run style check (auto-format with `nix-shell --run postgrest-style`)
run: postgrest-style-check
commit:
if: github.event_name != 'push' # we don't run this on a push, a failure on push disrupts the release workflow
name: Commit
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 100 # fetch history (last 100 commits) instead of default shallow clone history, this is deemed enough for a PR history
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: gitTools.commitCheck.bin
- name: Run commitlint (check locally with `nix-shell --run postgrest-commitlint`)
run: |
# Fetch target branch explicitly
git fetch origin ${{ github.base_ref }}
# Run commitlint
postgrest-commitlint --from origin/${{ github.base_ref }} --to HEAD
+2 -2
View File
@@ -50,14 +50,14 @@ jobs:
- test
- build
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ssh-key: ${{ secrets.POSTGREST_SSH_KEY }}
- name: Tag latest commit
run: |
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
if [[ "$cabal_version" == *.*.* ]]; then
if [[ "$cabal_version" == *.* ]]; then
git fetch --tags
if [ -z "$(git tag --list "v$cabal_version")" ]; then
+3 -2
View File
@@ -14,6 +14,7 @@ on:
- .github/actions/setup-nix/**
- default.nix
- nix/**
- flake.lock
- docs/**
- '!**.md'
@@ -27,7 +28,7 @@ jobs:
name: Build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
@@ -41,7 +42,7 @@ jobs:
name: Spellcheck
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
+2 -1
View File
@@ -3,12 +3,13 @@ name: Linkcheck
on:
schedule:
- cron: '1 2 * * 3'
workflow_dispatch:
jobs:
linkcheck:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
+33 -41
View File
@@ -26,7 +26,7 @@ jobs:
needs:
- build
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check the version to be released
run: |
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
@@ -49,7 +49,7 @@ jobs:
echo "Relevant extract from CHANGELOG.md:"
cat CHANGES.md
- name: Save CHANGES.md as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-changes
path: CHANGES.md
@@ -64,9 +64,9 @@ jobs:
needs:
- prepare
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download all artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
- name: Create release bundle with archives for all builds
@@ -75,6 +75,9 @@ jobs:
mkdir -p release-bundle
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-linux-static-aarch64.tar.xz" \
-C artifacts/postgrest-linux-static-aarch64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-linux-static-x86-64.tar.xz" \
-C artifacts/postgrest-linux-static-x86-64 postgrest
@@ -87,14 +90,11 @@ jobs:
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-freebsd-x86-64.tar.xz" \
-C artifacts/postgrest-freebsd-x86-64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-ubuntu-aarch64.tar.xz" \
-C artifacts/postgrest-ubuntu-aarch64 postgrest
zip --junk-paths "release-bundle/postgrest-${GITHUB_REF_NAME}-windows-x86-64.zip" \
artifacts/postgrest-windows-x86-64/postgrest.exe
- name: Save release bundle
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-bundle
path: release-bundle
@@ -138,50 +138,42 @@ jobs:
env:
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download aarch64 Docker image
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: postgrest-docker-aarch64
- name: Download x86-64 Docker image
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: postgrest-docker-x86-64
- name: Download aarch64 binary
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: postgrest-ubuntu-aarch64
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
username: ${{ vars.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
- name: Build aarch64 Docker image
run: |
# This only pushes the image via digest, not a tag. This will not appear
# in the image list on Docker Hub, yet. It will be later added to the main
# tag's manifest.
docker buildx build \
-t "$DOCKER_REPO/postgrest" \
--platform linux/arm64 \
--output push-by-digest=true,type=image,push=true \
--metadata-file metadata.json \
.
echo "SHA256_ARM=$(jq -r '."containerimage.digest"' metadata.json)" >> "$GITHUB_ENV"
- name: Publish images on Docker Hub
run: |
docker load -i postgrest-docker.tar.gz
docker load -i postgrest-docker-aarch64.tar.gz
docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-arm64"
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-arm64"
docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
docker buildx imagetools create --append \
-t "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}" \
"$DOCKER_REPO/postgrest@$SHA256_ARM"
docker load -i postgrest-docker-x86-64.tar.gz
docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-amd64"
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-amd64"
docker manifest create "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}" \
"$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-arm64" \
"$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-amd64"
docker manifest push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
# Only tag 'latest' for full releases
if [ "${GITHUB_REF_NAME}" != "devel" ]; then
echo "Pushing to 'latest' tag for full release of ${GITHUB_REF_NAME} ..."
docker tag postgrest:latest "$DOCKER_REPO"/postgrest:latest
docker push "$DOCKER_REPO"/postgrest:latest
docker buildx imagetools create --append \
-t "$DOCKER_REPO/postgrest:latest" \
"$DOCKER_REPO/postgrest@$SHA256_ARM"
docker manifest create "$DOCKER_REPO/postgrest:latest" \
"$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-arm64" \
"$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-amd64"
docker manifest push "$DOCKER_REPO/postgrest:latest"
else
echo "Skipping push to 'latest' tag for pre-release..."
fi
@@ -194,8 +186,8 @@ jobs:
vars.DOCKER_REPO && vars.DOCKER_USER &&
github.ref == 'refs/tags/devel'
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4.0.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
with:
username: ${{ vars.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
+41 -23
View File
@@ -17,6 +17,7 @@ on:
- .github/actions/setup-nix/**
- default.nix
- nix/**
- flake.lock
- .stylish-haskell.yaml
- cabal.project
- postgrest.cabal
@@ -39,17 +40,19 @@ jobs:
# https://github.com/actions/runner/issues/241#issuecomment-842566950
shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: tests.coverage.bin tests.testDoctests.bin tests.testSpecIdempotence.bin
tools: tests.coverage.bin tests.testDoctests.bin tests.testSpecIdempotence.bin cabalTools.update.bin
- name: Run coverage (IO tests and Spec tests against PostgreSQL 15)
- run: postgrest-cabal-update
- name: Run coverage (IO tests and Spec tests against latest supported PostgreSQL)
run: postgrest-coverage
- name: Upload coverage to codecov
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
with:
files: ./coverage/codecov.json
token: ${{ secrets.CODECOV_TOKEN }}
@@ -67,7 +70,7 @@ jobs:
strategy:
fail-fast: false
matrix:
pgVersion: [12, 13, 14, 15, 16, 17]
pgVersion: [14, 15, 16, 17, 18]
name: PG ${{ matrix.pgVersion }}
runs-on: ubuntu-24.04
defaults:
@@ -76,36 +79,45 @@ jobs:
# https://github.com/actions/runner/issues/241#issuecomment-842566950
shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: tests.testSpec.bin tests.testIO.bin tests.testBigSchema.bin withTools.postgresql-${{ matrix.pgVersion }}.bin
tools: tests.testSpec.bin tests.testObservability.bin tests.testIO.bin tests.testBigSchema.bin withTools.pg-${{ matrix.pgVersion }}.bin cabalTools.update.bin
- run: postgrest-cabal-update
- name: Run spec tests
if: always()
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-spec
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-spec
- name: Run observability tests
if: always()
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-observability
- name: Run IO tests
if: always()
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-io -vv
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-io -vv
- name: Run IO tests on a big schema
if: always()
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-big-schema -vv
run: postgrest-with-pg-${{ matrix.pgVersion }} postgrest-test-big-schema -vv
memory:
name: Memory
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: tests.testMemory.bin
tools: tests.testMemory.bin cabalTools.update.bin
- run: postgrest-cabal-update
- name: Run memory tests
run: postgrest-test-memory
@@ -113,40 +125,46 @@ jobs:
loadtest:
strategy:
matrix:
kind: ['mixed', 'jwt']
kind: ['mixed', 'errors', 'jwt-hs', 'jwt-hs-cache', 'jwt-hs-cache-worst', 'jwt-rsa', 'jwt-rsa-cache', 'jwt-rsa-cache-worst']
name: Loadtest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: loadtest.loadtestAgainst.bin loadtest.report.bin
- uses: WyriHaximus/github-action-get-previous-tag@04e8485ecb6487243907e330d522ff60f02283ce # v1.4.0
id: get-latest-tag
with:
prefix: v
tools: loadtest.loadtestAgainst.bin loadtest.report.bin cabalTools.update.bin
- run: postgrest-cabal-update
- name: Run loadtest
env:
TARGET_BRANCH: ${{ github.base_ref || github.ref_name }}
run: |
postgrest-loadtest-against -k ${{ matrix.kind }} main ${{ steps.get-latest-tag.outputs.tag }}
postgrest-loadtest-report >> "$GITHUB_STEP_SUMMARY"
if [ "$TARGET_BRANCH" = "main" ]; then
latest_tag=$(git tag --sort=-creatordate --list "v*" | head -n1)
else
latest_tag=$(git tag --merged HEAD --sort=-creatordate "v*" | head -n1)
fi
postgrest-loadtest-against -k ${{ matrix.kind }} "$TARGET_BRANCH" "$latest_tag"
postgrest-loadtest-report -g ${{ matrix.kind }} >> "$GITHUB_STEP_SUMMARY"
flake:
strategy:
fail-fast: false
matrix:
runs-on:
- macos-13 # x86_64-darwin
- macos-15-intel # x86_64-darwin
- macos-14 # aarch64-darwin
- ubuntu-24.04 # x86_64-linux
- ubuntu-24.04-arm # aarch64-linux
name: Flake Check
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Setup Nix Environment
+2
View File
@@ -25,3 +25,5 @@ loadtest
.history
.docs-build
gen_targets.http
gen_jwk.json
gen_private.json
+1 -1
View File
@@ -7,4 +7,4 @@ python:
build:
os: ubuntu-24.04
tools:
python: "3.11"
python: "3.12"
+15 -10
View File
@@ -13,26 +13,26 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
<img width="296px" src="static/supabase.svg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/code-build.png">
<a href="https://www.euronodes.com/postgrest" target="_blank">
<img width="296px" src="static/euronodes.svg">
</a>
</td>
</tr>
<tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
<img width="296px" src="static/supabase.png">
<a href="https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/bytebase.svg">
</a>
</td>
</tr>
@@ -89,8 +89,13 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
</a>
</td>
<td align="center" valign="middle">
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="222px" src="static/gnuhost.png">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="222px" src="static/code-build.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
</a>
</td>
</tr>
+204 -5
View File
@@ -1,10 +1,205 @@
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
All notable changes to this project will be documented in this file. From version `14.0` onwards PostgREST follows a `MAJOR.PATCH` two-part versioning. Only even-numbered MAJOR versions will be released, reserving odd-numbered MAJOR versions for development.
## Unreleased
### Added
- Log error when `db-schemas` config contains schema `pg_catalog` or `information_schema` by @taimoorzaeem in #4359
- Add string slicing operator for `jwt-role-claim-key` by @taimoorzaeem in #4599
- Optimize requests with `Prefer: count=exact` that do not use ranges or `db-max-rows` by @laurenceisla in #3957
+ Removed unnecessary double count when building the `Content-Range`.
- Add config `client-error-verbosity` to customize error verbosity by @taimoorzaeem in #4088, #3980, #3824
- Add `Vary` header to responses by @develop7 in #4609
- Add config `db-timezone-enabled` for optional querying of timezones by @taimoorzaeem in #4751
- Log schema cache queries timings on `log-level=debug` by @steve-chavez in #4805
### Fixed
- Shutdown should wait for in flight requests by @mkleczek in #4702
- Fix login with uppercase and mixed case role names by @taimoorzaeem in #4678
- Remove automatic transaction retries on `40001 (serialization_failure)` errors to prevent replication lag by @laurenceisla in #3673
- Fix unexpected results when embedding and filtering the same table more than once by @laurenceisla in #4075
### Changed
- Drop support for PostgreSQL EOL version 13 by @wolfgangwalther in #4193
- All responses now include a `Vary` header by @develop7 in #4609
- Log error when `db-schemas` config contains schema `pg_catalog` or `information_schema` by @taimoorzaeem in #4359
+ Now fails at startup. Prior to this, it failed with `PGRST205` on requests related to these schemas.
- Build a static executable for aarch64-linux by @wolfgangwalther in #4193
- Build the minimal docker image for aarch64-linux by @wolfgangwalther in #4193
- The name of an embedded table can no longer be used in filters if it has an alias by @laurenceisla in #4075
+ e.g. `?select=alias:table(*)&table.id=eq.1` is not possible anymore, use `?select=alias:table(*)&alias.id=eq.1` instead.
## [14.10] - 2026-04-16
### Added
- Log when the pool is released during schema cache reload on `log-level=debug` by @mkleczek in #4668
### Fixed
- Fix unnecessary connection pool flushes during schema cache reloading by @mkleczek in #4645
## [14.9] - 2026-04-10
### Added
- Log host, port and pg version of listener database connection by @mkleczek in #4617 #4618
### Fixed
- Remove red herring warp logs on default log-level, only emit them on `log-level=debug` by @steve-chavez in #4799
## [14.8] - 2026-04-03
### Added
- Log a `HINT` when the LISTEN channel stops working due to a PostgreSQL bug by @laurenceisla in #4581
### Fixed
- Fix invalid OpenAPI 2.0 format for integer types (`smallint`, `integer`, `bigint`) by @arturbent0 in #4641
## [14.7] - 2026-03-20
### Fixed
- Fix not logging SIGTERM and SIGINT by @steve-chavez in #4728
## [14.6] - 2026-03-06
### Fixed
- Fix leaking table and function names when calculating error hint by @taimoorzaeem in #4675
## [14.5] - 2026-02-12
### Fixed
- Don't hide async exceptions in logs by @stevechavez in #4646
## [14.4] - 2026-01-29
### Fixed
- Ensure Listener connections are released by @mkleczek in #4614
- Fix incorrectly filtering the returned representation for PATCH requests when using `or/and` filters by @laurenceisla in #3707
- Fix listener running with exception masked after first failure by @mkleczek in #4615
## [14.3] - 2026-01-03
### Fixed
- Fix performance and high memory usage of relation hint calculation by @mkleczek in #4462, #4463
## [14.2] - 2025-12-18
### Fixed
- Fix `hasSingleUnnamedParam` incorrectly matching functions with named parameters by @joelonsql in #4553
+ Functions with a single named parameter (e.g., `foo(data json)`) no longer incorrectly match the single-param fallback, returning a clean `PGRST202` error instead of a confusing PostgreSQL `42883` error.
- Fix misleading logs on unsupported PostgreSQL versions by @taimoorzaeem in #4519
- Fix regression where the `PGRST103` error response was truncated by @laurenceisla in #4455
+ Happened when an `offset` was greater than the rows requested and `Prefer: count=exact` was sent.
- Fix not returning `Content-Length` on empty HTTP `201` responses by @laurenceisla in #4518
- Fix inaccurate Server-Timing header durations by @steve-chavez in #4522
- Fix inaccurate "Schema cache queried" logs by @steve-chavez in #4522
## [14.1] - 2025-11-05
## Fixed
- Fix `db-pre-config` function failing when function names are pg reserved words by @taimoorzaeem in #4380
- Fix `server-host=!6` incorrectly binds to IPv4 address by @taimoorzaeem in #3202
## [14.0] - 2025-10-24
### Added
- Bounded JWT cache using the SIEVE algorithm by @mkleczek in #4084
+ It now uses a fixed size cache instead of arbitrary sized cache.
- Add `--ready` flag for postgrest healthcheck by @taimoorzaeem in #4239
### Fixed
- Fix not logging OpenAPI queries when `log-query=main-query` is enabled by @steve-chavez in #4226
- Fix not logging explain query when `log-query=main-query` is enabled by @steve-chavez in #4319
- Fix not logging transaction variables and db-pre-request function when `log-query=main-query` is enabled by @steve-chavez in #3934
- Fix not logging the JSON message to stderr on a `PGRST002` error by @laurenceisla in #4129
- Fix reloading the Schema Cache unnecessarily on a `PGRST002` error by @laurenceisla in #4367
- Fix schema cache loading taking a long time for large schemas by @mkleczek in #4360, #3704
### Changed
- Drop support for PostgreSQL EOL version 12 by @wolfgangwalther in #3865
- From now on PostgREST will follow a `MAJOR.PATCH` two-part versioning. Only even-numbered MAJOR versions will be released, reserving odd-numbered MAJOR versions for development.
- Replaced `jwt-cache-max-lifetime` config with `jwt-cache-max-entries` by @mkleczek in #4084
- `log-query` config now takes a boolean instead of a string value by @steve-chavez in #3934
## [13.0.8] - 2025-10-24
### Fixed
- Fix loading utf-8 config files with `ASCII` locale set by @taimoorzaeem in #4386
## [13.0.7] - 2025-09-14
### Added
- Improve the `PGRST106` error when the requested schema is invalid by @laurenceisla in #4089
+ It now shows the invalid schema in the `message` field.
+ The exposed schemas are now listed in the `hint` instead of the `message` field.
- Improve error details of `PGRST301` error by @taimoorzaeem in #4051
## [13.0.6] - 2025-08-30
### Fixed
- Fix logging the Haskell type instead of the listener error message directly by @laurenceisla in #3588
- Fix format of `IPv6` address logged at PostgREST startup by @taimoorzaeem in #4291
- Fix empty enum in `preferParams` OpenAPI parameter by @laurenceisla in #4292
## [13.0.5] - 2025-08-24
### Fixed
- Fix OpenAPI broken docs link by @taimoorzaeem in #4080
- Fix OpenAPI specification incorrectly exposing GET methods for volatile functions by @joelonsql in #4174
- Fix empty spread embeddings return unexpected SQL error by @taimoorzaeem in #3887
- Fix `/metrics` endpoint not responding with `Content-Type` header by @taimoorzaeem in #4271
## [13.0.4] - 2025-06-17
### Fixed
- Fix regression that makes full-text search not work on domain types based on `tsvector` by @laurenceisla in #4135
- Fix `jwt-aud` config not failing when set to an invalid URI by @taimoorzaeem in #4132
## [13.0.3] - 2025-06-16
- Fix `max-affected` preference not failing with RPC when `handling=strict` by @taimoorzaeem in #4100
- Fix a property definition's type in OpenAPI not showing the correct base type of a recursive domain by @laurenceisla in #4136
### Fixed
## [13.0.2] - 2025-06-02
### Fixed
- Fix regression that makes `ORDER BY` with nulls-order not work alongside limits by @laurenceisla in #4109
## [13.0.1] - 2025-06-01
### Fixed
- Fix jwt error returning HTTP status `400` for invalid role by @taimoorzaeem in #3601
- Fix `db-extra-search-path` cannot be set to nothing by @taimoorzaeem in #4074
+ It can now be disabled by setting it to empty string.
+ Schema Cache load error is now logged including `db-schemas` and `db-extra-search-path` config values.
## [13.0.0] - 2025-05-08
### Added
@@ -47,8 +242,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #2052, Dropped support for PostgreSQL 11 - @wolfgangwalther
- #3508, PostgREST now fails to start when `server-port` and `admin-server-port` config options are the same - @develop7
- #3607, PostgREST now fails to start when the JWT secret is less than 32 characters long - @laurenceisla
- #3644, Fail schema cache lookup with invalid db-schemas config - @wolfgangwalther
- #3644, Fail schema cache lookup with invalid `db-schemas` or `db-extra-search-path` config - @wolfgangwalther
- Previously, this would silently return 200 - OK on the root endpoint, but don't provide any usable endpoints.
- Note: This also applies when deleting the `public` schema - both config options default to that.
- #3757, Remove support for `Prefer: params=single-object` - @joelonsql
+ This preference was deprecated in favor of Functions with an array of JSON objects
- #3013, Drop support for Limited updates/deletes
@@ -56,6 +252,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #3956, Drop `/config` endpoint of admin server - @steve-chavez
+ The endpoint was at risk of being left unprotected when exposing it.
+ The accompanying `admin-server-config-enabled` config was also dropped.
- #3598, PostgREST now validates the `kid` parameter of the JWT - @wolfgangwalther
+ If the JWT contains a ``kid`` parameter, then PostgREST will look for the JSON Web Key in the `jwt-secret`.
+ If the JWT doesn't contain a `kid`, the behavior should be backwards compatible. PostgREST will try each key in the `jwt-secret` one by one until it finds one that works.
- #3697, #3602, Querying non-existent table now returns `PGRST205` error instead of empty json - @taimoorzaeem
- #3600, #3926, Improve JWT errors - @taimoorzaeem
+ Return `PGRST301` error when `Bearer` in auth header is sent empty
@@ -492,7 +691,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added
- #1933, #2109, Add a minimal health check endpoint - @steve-chavez
+ For enabling this, the `admin-server-port` config must be set explictly
+ For enabling this, the `admin-server-port` config must be set explicitly
+ A `<host>:<admin_server_port>/live` endpoint is available for checking if postgrest is running on its port/socket. 200 OK = alive, 503 = dead.
+ A `<host>:<admin_server_port>/ready` endpoint is available for checking a correct internal state(the database connection plus the schema cache). 200 OK = ready, 503 = not ready.
- #1988, Add the current user to the request log on stdout - @DavidLindbom, @wolfgangwalther
@@ -975,7 +1174,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Customize content negotiation per route - @begriffs
- Allow using nulls order without explicit order direction - @steve-chavez
- Fatal error on postgres unsupported version, format supported version in error message - @steve-chavez
- Prevent database memory cosumption by prepared statements caches - @ruslantalpa
- Prevent database memory consumption by prepared statements caches - @ruslantalpa
- Use specific columns in the RETURNING section - @ruslantalpa
- Fix columns alias for RETURNING - @steve-chavez
+62
View File
@@ -0,0 +1,62 @@
# Contributing to PostgREST
## AI Policy
We adhere to [Gentoo's AI policy](https://wiki.gentoo.org/wiki/Project:Council/AI_policy):
> It is expressly forbidden to contribute [...] any content that has been created with the assistance of Natural Language Processing artificial intelligence tools. This motion can be revisited, should a case been made over such a tool that does not pose copyright, ethical and quality concerns.
You can find more about its rationale [here](https://wiki.gentoo.org/wiki/Project:Council/AI_policy#Rationale).
## Issues
For questions on how to use PostgREST, please use
[GitHub discussions](https://github.com/PostgREST/postgrest/discussions).
### Reporting an Issue
* Make sure you test against the latest [stable release](https://github.com/PostgREST/postgrest/releases/latest)
and also against the latest [devel release](https://github.com/PostgREST/postgrest/releases/tag/devel).
It is possible we already fixed the bug you're experiencing.
* Provide steps to reproduce the issue, including your OS version and
the specific database schema that you are using.
* Please include SQL logs for issues involving runtime problems. To obtain logs first
[enable logging all statements](http://www.microhowto.info/howto/log_all_queries_to_a_postgresql_server.html),
then [find your logs](http://blog.endpoint.com/2014/11/dear-postgresql-where-are-my-logs.html).
* If your database schema has changed while the PostgREST server is running,
[send the server a `SIGUSR1` signal](http://postgrest.org/en/latest/admin.html#schema-reloading) or restart it to ensure the schema cache
is not stale. This sometimes fixes apparent bugs.
## Code
We have a fully nix-based development environment with many tools for a smooth development workflow available.
Check the [development docs](https://github.com/PostgREST/postgrest/blob/main/nix/README.md) on how to set it up and use it.
* All contributions must pass the tests before being merged. When
you create a pull request your code will automatically be tested.
* All fixes or features must have a test proving the improvement.
* All code must also pass a [linter](http://community.haskell.org/~ndm/hlint/) and [styler](https://github.com/jaspervdj/stylish-haskell)
with no warnings. This helps enforce a uniform style for all committers. Continuous integration will check this as well on every
pull request. There are useful tools in the nix-shell that help with checking this locally. You can run `postgrest-check` to do this manually but
we recommend adding it to `.git/hooks/pre-commit` as `nix-shell --run postgrest-check` to automatically check this before doing a commit.
### Running Tests
For instructions on running tests, see the [development docs](https://github.com/PostgREST/postgrest/blob/main/nix/README.md#testing).
### Structuring commits in pull requests
To simplify reviews, make it easy to split pull requests if deemed necessary, and to maintain clean and meaningful history of changes, you will be asked to update your PR if it does not follow the below rules:
* It must be possible to merge the PR branch into target using `git merge --ff-only`, ie. the source branch must be rebased on top of target.
* No merge commits in the source branch.
* All commits in the source branch must be self contained, meaning: it should be possible to treat each commit as a separate PR.
* Commits in the source branch must contain only related changes (related means the changes target a single problem/goal). For example, any refactorings should be isolated from the actual change implementation into separate commits.
* Tests, documentation, and changelog updates should be contained in the same commits as the actual code changes they relate to. An exception to this rule is when test or documentation changes are made in separate PR.
* Commit messages must be prefixed with one of the prefixes defined in [the list used by commit verification scripts](https://github.com/PostgREST/postgrest/blob/main/nix/tools/gitTools.nix#L11).
* Commit messages should contain a longer description of the purpose of the changes contained in the commit and, for non-trivial changes, a description of the changes themselves.
-21
View File
@@ -1,21 +0,0 @@
# PostgREST Docker Hub image for aarch64.
# The x86-64 is a single-static-binary image built via Nix, see:
# nix/tools/docker/README.md
FROM ubuntu:noble@sha256:6015f66923d7afbc53558d7ccffd325d43b4e249f41a6e93eef074c9505d2233 AS postgrest
RUN apt-get update -y \
&& apt install -y --no-install-recommends libpq-dev zlib1g-dev jq gcc libnuma-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
COPY postgrest /usr/bin/postgrest
RUN chmod +x /usr/bin/postgrest
EXPOSE 3000
USER 1000
# Use the array form to avoid running the command using bash, which does not handle `SIGTERM` properly.
# See https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop
CMD ["postgrest"]
+1 -2
View File
@@ -1,5 +1,4 @@
Copyright (c) 2014 Joe Nelson
Copyright (c) 2019 Steve Chavez
Copyright (c) 2014-2026 The PostgREST contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+15 -11
View File
@@ -22,26 +22,26 @@ API than you are likely to write from scratch.
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
<img width="296px" src="static/supabase.svg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/code-build.png">
<a href="https://www.euronodes.com/postgrest" target="_blank">
<img width="296px" src="static/euronodes.svg">
</a>
</td>
</tr>
<tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
<img width="296px" src="static/supabase.png">
<a href="https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/bytebase.svg">
</a>
</td>
</tr>
@@ -52,8 +52,8 @@ Big thanks to our sponsors! You can join them by supporting PostgREST on [Patreo
## Usage
1. Download the binary ([latest release](https://github.com/PostgREST/postgrest/releases/latest))
for your platform.
1. See the docs for [how to install PostgREST on your platform](https://docs.postgrest.org/en/stable/explanations/install.html). You can also [use Docker](https://docs.postgrest.org/en/stable/explanations/install.html#docker).
2. Invoke for help:
```bash
@@ -125,7 +125,7 @@ and limited with - range headers. More about
## Data Integrity
Rather than relying on an Object Relational Mapper and custom
imperative coding, this system requires you put declarative constraints
imperative coding, this system requires you to put declarative constraints
directly into your database. Hence no application can corrupt your
data (including your API server).
@@ -142,6 +142,10 @@ You can help PostgREST ongoing maintenance and development by making a regular d
Every donation will be spent on making PostgREST better for the whole community.
## Contributing
Contributions are always welcome and appreciated. Please see the [Contributing guidelines](https://github.com/PostgREST/postgrest/blob/main/CONTRIBUTING.md).
## Thanks
The PostgREST organization is grateful to:
+2 -2
View File
@@ -1,4 +1,4 @@
packages: postgrest.cabal
tests: true
package *
ghc-options: -split-sections
allow-newer:
hasql:postgresql-libpq
+1 -1
View File
@@ -1 +1 @@
index-state: hackage.haskell.org 2025-02-01T14:59:33Z
index-state: hackage.haskell.org 2026-04-18T18:42:36Z
+29 -14
View File
@@ -1,6 +1,6 @@
{ system ? builtins.currentSystem
, compiler ? "ghc948"
, compiler ? "ghc9123"
, # Commit of the Nixpkgs repository that we want to use.
# It defaults to reading the inputs from flake.lock, which serves
@@ -43,9 +43,7 @@ let
allOverlays.build-toolbox
allOverlays.checked-shell-script
allOverlays.gitignore
allOverlays.postgresql-libpq
(allOverlays.haskell-packages { inherit compiler; })
allOverlays.slocat
];
# Evaluated expression of the Nixpkgs repository.
@@ -54,16 +52,17 @@ let
postgresqlVersions =
[
{ name = "postgresql-17"; postgresql = pkgs.postgresql_17.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-13"; postgresql = pkgs.postgresql_13.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-12"; postgresql = pkgs.postgresql_12.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "pg-18"; postgresql = pkgs.postgresql_18.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "pg-17"; postgresql = pkgs.postgresql_17.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "pg-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "pg-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "pg-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
];
haskellPackages = pkgs.haskell.packages."${compiler}";
# Dynamic derivation for PostgREST
postgrest = pkgs.lib.pipe (pkgs.haskell.packages."${compiler}".callCabal2nix name src { }) [
postgrest = pkgs.lib.pipe (haskellPackages.callCabal2nix name src { }) [
# To allow ghc-datasize to be used.
lib.disableLibraryProfiling
# We are never going to use dynamic haskell libraries anyway. "Dynamic" refers to how
@@ -75,7 +74,7 @@ let
# Options passed to cabal in dev tools and tests
devCabalOptions =
"-f dev --test-show-detail=direct --disable-shared";
"-f dev --test-show-detail=direct";
inherit (pkgs.haskell) lib;
in
@@ -84,9 +83,14 @@ rec {
# Derivation for the PostgREST Haskell package, including the executable,
# libraries and documentation. We disable running the test suite on Nix
# builds, as they require a database to be set up.
postgrestPackage =
lib.dontCheck postgrest;
# builds, as they require a database to be set up. We split the binary
# into a separate output, so that the default distribution via flake.nix
# has a much smaller closure size.
postgrestPackage = pkgs.lib.pipe postgrest [
lib.dontCheck
lib.enableSeparateBinOutput
(haskellPackages.generateOptparseApplicativeCompletions [ "postgrest" ])
];
# Profiled dynamic executable.
postgrestProfiled = pkgs.lib.pipe postgrestPackage [
@@ -103,6 +107,9 @@ rec {
inherit (pkgs.haskell.packages."${compiler}") ghcWithPackages;
};
# Used by CI on MacOS
inherit (pkgs) nix-build-uncached;
### Tools
cabalTools =
@@ -119,10 +126,18 @@ rec {
docs =
pkgs.callPackage nix/tools/docs.nix { };
# Git tools.
gitTools =
pkgs.callPackage nix/tools/gitTools.nix { };
# Load testing tools.
loadtest =
pkgs.callPackage nix/tools/loadtest.nix { inherit withTools; };
# Utility for updating the pinned version of Nixpkgs.
nixpkgsTools =
pkgs.callPackage nix/tools/nixpkgsTools.nix { };
# Scripts for publishing new releases.
release =
pkgs.callPackage nix/tools/release.nix { };
+8 -10
View File
@@ -19,26 +19,26 @@ write from scratch.
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/neon.jpg">
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/supabase.svg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/code-build.png">
<a href="https://www.euronodes.com/postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/euronodes.svg">
</a>
</td>
</tr>
<tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/tembo.png">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/neon.jpg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/supabase.png">
<a href="https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/bytebase.svg">
</a>
</td>
</tr>
@@ -61,5 +61,3 @@ The image is built from scratch using
no commands are listed in the image history. See the [PostgREST
repository](https://github.com/PostgREST/postgrest/tree/main/nix/tools/docker) for
details on the build process and how to inspect the image.
This does not apply to the arm64 variant, which is based on Ubuntu.
+10 -5
View File
@@ -40,9 +40,14 @@ database "PostgreSQL" {
:user:
hexagon Proxy
:user: .r-> Proxy
:user: .r-> Proxy : request with JWT
HTTPAPI <.l- Proxy
hexagon ExternalAuth
ExternalAuth -u[hidden]- Proxy
:user: .r-> ExternalAuth : login
:user: <.r- ExternalAuth : JWT
:operator: .d-> HTTPADMIN
:operator: .d-> CLI
@@ -51,9 +56,8 @@ PostgreSQL <.developer : "\t"
Listener -r.> "PostgreSQL"
"Connection Pool" -r.> "PostgreSQL" : "\t\t"
note bottom of Auth
Authenticates the user request
Validates the JWT
end note
note bottom of ApiRequest
@@ -72,6 +76,7 @@ note top of Listener
LISTEN session
end note
url of ExternalAuth is [[../explanations/external_auth.html]]
url of Admin is [[../references/admin_server.html#admin-server]]
url of API is [[../explanations/schema_isolation.html]]
url of Auth is [[../references/auth.html#authn]]
@@ -82,8 +87,8 @@ url of Authorization is [[../explanations/db_authz.html]]
url of CLI is [[../references/cli.html#cli]]
url of "Connection Pool" is [[../references/connection_pool.html]]
url of Config is [[../references/configuration.html#configuration]]
url of HTTPADMIN is [[https://aosabook.org/en/posa/warp.html]]
url of HTTPAPI is [[https://aosabook.org/en/posa/warp.html]]
url of HTTPADMIN is [[../explanations/architecture.html#http]]
url of HTTPAPI is [[../explanations/architecture.html#http]]
url of Listener is [[../references/listener.html#listener]]
url of Proxy is [[../explanations/nginx.html]]
url of "Schema Cache" is [[../references/schema_cache.html#schema-cache]]
+1 -1
View File
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 28 KiB

+1 -1
View File
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 29 KiB

+6 -5
View File
@@ -12,7 +12,6 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
@@ -49,14 +48,14 @@ source_suffix = ".rst"
# The master toctree document.
master_doc = "index"
# This is overriden by readthedocs with the version tag anyway
version = "13.0"
# This is overridden by readthedocs with the version tag anyway
version = "devel"
# To avoid repetition in <title> we set this to an empty string.
release = ""
# General information about the project.
project = "PostgREST " + version
author = "Joe Nelson, Steve Chavez"
author = "The PostgREST contributors"
copyright = "2017, " + author
# The language for content autogenerated by Sphinx. Refer to documentation
@@ -114,7 +113,7 @@ html_theme = "sphinx_rtd_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {"display_version": False}
html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
@@ -300,8 +299,10 @@ linkcheck_ignore = [
# 403 only in CI / GitHub Actions
r"https://www.patreon.com/postgrest",
r"https://blog.frankel.ch/poor-man-api",
r"https://www.cybertec-postgresql.com/.*",
# Odd SSL error
r"https://www.dripdepot.com",
r"https://www.euronodes.com",
# New GitHub UI delays comment load, so anchor fails
r"https://github.com/.*#issuecomment",
# Random 500 Internal Server Error
+3 -2
View File
@@ -6,7 +6,7 @@ Community Tutorials
* `Building a Contacts List with PostgREST and Vue.js <https://www.youtube.com/watch?v=iHtsALtD5-U>`_ -
In this video series, DigitalOcean shows how to build and deploy an Nginx + PostgREST(using a managed PostgreSQL database) + Vue.js webapp in an Ubuntu server droplet.
* `PostgREST + Auth0: Create REST API in mintutes, and add social login using Auth0 <https://samkhawase.com/blog/postgrest/>`_ - A step-by-step tutorial to show how to dockerize and integrate Auth0 to PostgREST service.
* `PostgREST + Auth0: Create REST API in minutes, and add social login using Auth0 <https://samkhawase.com/blog/postgrest-1-introduction/>`_ - A step-by-step tutorial to show how to dockerize and integrate Auth0 to PostgREST service.
* `"CodeLess" backend using postgres, postgrest and oauth2 authentication with keycloak <https://www.mathieupassenaud.fr/codeless_backend/>`_ -
A step-by-step tutorial for using PostgREST with KeyCloak(hosted on a managed service).
@@ -34,9 +34,10 @@ Templates
Example Apps
------------
* `archtika <https://github.com/archtika/archtika>`_ - selfhosted CMS
* `archtika <https://github.com/thiloho/archtika>`_ - self-hosted CMS
* `delibrium-postgrest <https://gitlab.com/delibrium/delibrium-postgrest/>`_ - example school API and front-end in Vue.js
* `ETH-transactions-storage <https://github.com/Adamant-im/ETH-transactions-storage>`_ - indexer for Ethereum to get transaction list by ETH address
* `fullstack template <https://github.com/jenstroeger/fullstack-webapp-template>`_ - a complete fullstack webapp template using PG as db and message queue, Python and Dramatiq to implement async jobs, db migrations, test runners, and more.
* `general <https://github.com/PierreRochard/general>`_ - example auth back-end
* `guild-operators <https://github.com/cardano-community/koios-artifacts/tree/main/files/grest>`_ - example queries and functions that the Cardano Community uses for their Guild Operators' Repository
* `PostGUI <https://github.com/priyank-purohit/PostGUI>`_ - React Material UI admin panel
+2 -2
View File
@@ -13,7 +13,7 @@ A role can be thought of as either a database user, or a group of database users
Roles for Each Web User
-----------------------
PostgREST can accommodate either viewpoint. If you treat a role as a single user then the :ref:`jwt_impersonation` does most of what you need. When an authenticated user makes a request PostgREST will switch into the database role for that user, which in addition to restricting queries, is available to SQL through the :code:`current_user` variable.
PostgREST can accommodate either viewpoint. If you treat a role as a single user then :ref:`user_impersonation` does most of what you need. When an authenticated user makes a request PostgREST will switch into the database role for that user, which in addition to restricting queries, is available to SQL through the :code:`current_user` variable.
You can use row-level security to flexibly restrict visibility and access for the current user. Here is an `example <https://www.enterprisedb.com:443/blog/application-users-vs-row-level-security>`_ from Tomas Vondra, a chat table storing messages sent between users. Users can insert rows into it to send messages to other users, and query it to see messages sent to them by other users.
@@ -163,7 +163,7 @@ Another option is to define the function with the :code:`SECURITY DEFINER` optio
.. code-block:: postgres
-- login as a user wich has privileges on the private schemas
-- login as a user which has privileges on the private schemas
-- create a sample function
create or replace function login(email text, pass text, out token text) as $$
@@ -1,6 +1,6 @@
.. _external_jwt:
.. _external_auth:
External JWT Generation
External Authentication
-----------------------
JWT from Auth0
@@ -9,21 +9,3 @@ JWT from Auth0
An external service like `Auth0 <https://auth0.com/>`_ can do the hard work transforming OAuth from Github, Twitter, Google etc into a JWT suitable for PostgREST. Auth0 can also handle email signup and password reset flows.
To use Auth0, create `an application <https://auth0.com/docs/get-started/applications>`_ for your app and `an API <https://auth0.com/docs/get-started/apis>`_ for your PostgREST server. Auth0 supports both HS256 and RS256 scheme for the issued tokens for APIs. For simplicity, you may first try HS256 scheme while creating your API on Auth0. Your application should use your PostgREST API's `API identifier <https://auth0.com/docs/get-started/apis/api-settings>`_ by setting it with the `audience parameter <https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#control-access-token-audience>`_ during the authorization request. This will ensure that Auth0 will issue an access token for your PostgREST API. For PostgREST to verify the access token, you will need to set ``jwt-secret`` on PostgREST config file with your API's signing secret.
JWT using OpenSSL
~~~~~~~~~~~~~~~~~
To manually generate a JWT using ``openssl`` commands, you can use the following script. This may be useful for testing JWT related features of PostgREST.
.. code:: bash
#!/bin/bash
set -e
TEST_JWT_SECRET='test_secret_that_is_at_least_32_characters_long'
_base64 () { openssl base64 -e -A | tr '+/' '-_' | tr -d '='; }
header=$(echo -n '{"alg":"HS256","typ":"JWT"}' | _base64)
exp=$(( EPOCHSECONDS + 60*60 )) # 1 hour
payload=$(echo -n "{\"role\":\"test_role\",\"exp\":$exp}" | _base64)
signature=$(echo -n "$header.$payload" | openssl dgst -sha256 -hmac "$TEST_JWT_SECRET" -binary | _base64)
echo -n "$header.$payload.$signature"
+23 -1
View File
@@ -16,7 +16,7 @@ Supported PostgreSQL versions
=============================
=============== =================================
**Supported** PostgreSQL >= 12
**Supported** PostgreSQL >= 14
=============== =================================
PostgREST works with all PostgreSQL versions still `officially supported <https://www.postgresql.org/support/versioning/>`_.
@@ -75,8 +75,12 @@ You can get the `official PostgREST Docker image <https://hub.docker.com/r/postg
.. code-block:: bash
# pull the latest version
docker pull postgrest/postgrest
# to pull a particular version, use one of the versions on https://hub.docker.com/r/postgrest/postgrest/tags
docker pull postgrest/postgrest:<version>
To configure the container image, use :ref:`env_variables_config`.
There are two ways to run the PostgREST container: with an existing external database, or through docker-compose.
@@ -142,6 +146,7 @@ To avoid having to install the database at all, you can run both it and the serv
ports:
- "3000:3000"
environment:
PGRST_SERVER_HOST: 0.0.0.0 # necessary for `postgrest --ready` flag to work
PGRST_DB_URI: postgres://app_user:password@db:5432/app_db
PGRST_OPENAPI_SERVER_PROXY_URI: http://127.0.0.1:3000
depends_on:
@@ -176,6 +181,23 @@ If you want to have a visual overview of your API in your browser you can add sw
With this you can see the swagger-ui in your browser on port 8080.
.. _docker_cpu_contraint:
Docker Resource Constraints
---------------------------
PostgREST does not support ``--cpus`` `constraint option <https://docs.docker.com/engine/containers/resource_constraints/#configure-the-default-cfs-scheduler>`_.
As a workaround, you may use the `GHC RTS <https://ghc.gitlab.haskell.org/ghc/doc/users_guide/runtime_control.html#runtime-system-rts-options>`_ ``-N`` option. For instance, to limit it to 2 CPU cores, do:
.. code::
# Set environment variable GHCRTS set to "-N2"
docker run --rm -p 3000:3000 \
-e PGRST_DB_URI="postgres://app_user:password@10.0.0.10/postgres" \
-e GHCRTS="-N2"
postgrest/postgrest
.. _build_source:
Building from Source
@@ -43,7 +43,7 @@ As in :ref:`sql_user_management`, we create the :code:`pgcrypto` and :code:`pgjw
CREATE EXTENSION pgcrypto WITH SCHEMA ext_pgcrypto;
Concerning the `pgjwt extension <https://github.com/michelp/pgjwt>`_, please cf. to :ref:`client_auth`.
Concerning the `pgjwt extension <https://github.com/michelp/pgjwt>`_, please cf. to :ref:`jwt-from-sql`.
.. code-block:: postgres
@@ -157,7 +157,7 @@ Here we use the username instead of the email address to identify a user.
Logins
~~~~~~
As described in :ref:`client_auth`, we'll create a JWT token inside our login function. Note that you'll need to adjust the secret key which is hard-coded in this example to a secure (at least thirty-two character) secret of your choosing.
As described in :ref:`jwt-from-sql`, we'll create a JWT token inside our login function. Note that you'll need to adjust the secret key which is hard-coded in this example to a secure (at least thirty-two character) secret of your choosing.
.. code-block:: postgres
+3 -1
View File
@@ -3,7 +3,7 @@
SQL User Management
===================
As mentioned on :ref:`jwt_generation`, an external service can provide user management and coordinate with the PostgREST server using JWT. Its also possible to support logins entirely through SQL. Its a fair bit of work, so get ready.
As mentioned on :ref:`jwt_generation`, an external service can provide user management and coordinate with the PostgREST server using JWT. It's also possible to support logins entirely through SQL. It's a fair bit of work, so get ready.
Storing Users and Passwords
---------------------------
@@ -110,6 +110,8 @@ Then, add ``db-anon-role`` to the configuration file to allow anonymous requests
db-anon-role = "anon"
.. _jwt-from-sql:
JWT from SQL
~~~~~~~~~~~~
+58 -36
View File
@@ -38,49 +38,53 @@ Sponsors
.. image:: ../static/cybertec.svg
:target: https://www.cybertec-postgresql.com/en/?utm_source=postgrest.org&utm_medium=referral&utm_campaign=postgrest
.. container:: img-dark
.. image:: ../static/supabase-dark.svg
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
.. container:: img-light
.. image:: ../static/supabase.svg
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
.. container:: img-dark
.. image:: ../static/euronodes.svg
:target: https://www.euronodes.com/postgrest
.. container:: img-light
.. image:: ../static/euronodes.svg
:target: https://www.euronodes.com/postgrest
|
.. container:: img-dark
.. image:: ../static/neon-dark.jpg
:target: https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest
:target: https://neon.com/?utm_source=sponsor&utm_campaign=postgrest
.. container:: img-light
.. image:: ../static/neon.jpg
:target: https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest
:target: https://neon.com/?utm_source=sponsor&utm_campaign=postgrest
.. container:: img-dark
.. image:: ../static/code-build-dark.png
:target: https://code.build/?utm_source=sponsor&utm_campaign=postgrest
.. image:: ../static/bytebase-dark.svg
:target: https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest
.. container:: img-light
.. image:: ../static/code-build.png
:target: https://code.build/?utm_source=sponsor&utm_campaign=postgrest
|
.. image:: ../static/tembo.png
:target: https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest
.. container:: img-dark
.. image:: ../static/supabase-dark.png
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
.. container:: img-light
.. image:: ../static/supabase.png
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
.. image:: _static/empty.png
:target: #sponsors
.. image:: ../static/bytebase.svg
:target: https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest
.. The static/empty.png(created with `convert -size 320x95 xc:#fcfcfc empty.png`) is an ugly workaround
to create space and center the logos. It's not easy to layout with restructuredText.
.. .. image:: _static/empty.png
:target: #sponsors
.. image:: _static/empty.png
:target: #sponsors
|
@@ -109,10 +113,17 @@ Getting Support
The project has a friendly and growing community. For discussions, use the Github `discussions page <https://github.com/PostgREST/postgrest/discussions>`_. You can also report or search for bugs/features on the Github `issues <https://github.com/PostgREST/postgrest/issues>`_ page.
Release Notes
-------------
Releases
--------
The release notes are published on `PostgREST's GitHub release page <https://github.com/PostgREST/postgrest/releases>`_.
PostgREST follows ``MAJOR.PATCH`` two-part versioning:
- ``MAJOR``: feature release, may deprecate or remove things.
- ``PATCH``: fix/security release only; no features, no behavior changes.
Starting from ``v14.0``, only even-numbered MAJOR versions will be released, reserving odd-numbered MAJOR versions for development.
All the releases are published on `PostgREST's GitHub release page <https://github.com/PostgREST/postgrest/releases>`_.
Tutorials
---------
@@ -209,20 +220,14 @@ In Production
Here are some companies that use PostgREST in production.
* `Catarse <https://www.catarse.me>`_
* `Datrium <https://www.datrium.com>`_
* `Drip Depot <https://www.dripdepot.com>`_
* `Image-charts <https://www.image-charts.com>`_
* `Moat <https://www.oracle.com/advertising/>`_
* `Netwo <https://www.netwo.io>`_
* `Nimbus <https://www.nimbusfacility.com/sg/home>`_
- See how Nimbus uses PostgREST in `Paul Copplestone's blog post <https://paul.copplest.one/blog/nimbus-tech-2019-04.html>`_.
* `OpenBooking <https://openbooking.ch>`_
* `Supabase <https://supabase.com>`_
.. Failing links
* `eGull <http://www.egull.co>`_
* `MotionDynamic - Fast highly dynamic video generation at scale <https://motiondynamic.tech>`_
Testimonials
------------
@@ -266,4 +271,21 @@ Testimonials
Contributing
------------
Please see the `Contributing guidelines <https://github.com/PostgREST/postgrest/blob/main/.github/CONTRIBUTING.md>`_ in the main PostgREST repository.
Please see the `Contributing guidelines <https://github.com/PostgREST/postgrest/blob/main/CONTRIBUTING.md>`_ in the main PostgREST repository.
.. raw:: html
<script type="text/javascript">
let hash = window.location.hash;
const redirects = {
// Tables and Views
'#release-notes': '#releases',
};
let willRedirectTo = redirects[hash];
if (willRedirectTo) {
window.location.href = willRedirectTo;
}
</script>
-6
View File
@@ -1,6 +0,0 @@
Greenplum
#########
`Greenplum <https://blogs.vmware.com/tanzu/tanzu-greenplum/>`_ has been reported to work by adding ``LOGIN`` to the :ref:`anonymous and user roles <roles>`.
For more details, see https://github.com/PostgREST/postgrest/issues/2021.
+8 -2
View File
@@ -4,6 +4,7 @@ API's
APIs
APISIX
AST
async
aud
Auth
auth
@@ -14,6 +15,7 @@ BOM
Bytea
Cardano
cd
CDNs
centric
CLI
CMS
@@ -30,6 +32,7 @@ DDL
DOM
DSL
DevOps
Dramatiq
dockerize
enum
Enums
@@ -41,12 +44,12 @@ EveryLayout
filename
FreeBSD
fts
fullstack
GeoJSON
Github
Google
grantor
GraphQL
Greenplum
gte
GUC
Haskell
@@ -104,7 +107,6 @@ Observability
Okta
OpenAPI
openapi
OpenSSL
ov
parametrized
passphrase
@@ -176,6 +178,7 @@ unikernel
unix
updatable
unfulfillable
unselected
Untyped
UPSERT
Upsert
@@ -189,9 +192,12 @@ verifier
versioning
Vondra
Vue
webapp
webhooks
websearch
Websockets
webuser
wfts
www
debouncing
deduplicates
+1 -1
View File
@@ -12,7 +12,7 @@ Health Check
You can enable a health check to verify if PostgREST is available for client requests. Also to check the status of its internal state.
Two endpoints ``live`` and ``ready`` will then be available.
Two endpoints ``live`` and ``ready`` will then be available. Both these endpoints reply with a status code and empty response body.
.. important::
+1
View File
@@ -21,6 +21,7 @@ PostgREST exposes three database objects of a schema as resources: tables, views
api/aggregate_functions.rst
api/openapi.rst
api/preferences.rst
api/vary_header.rst
api/*
.. raw:: html
@@ -173,4 +173,4 @@ Domain Representations avoid all the above drawbacks. Their only drawback is tha
Why not create a `base type <https://www.postgresql.org/docs/current/sql-createtype.html#id-1.9.3.94.5.8>`_ instead? ``CREATE TYPE app_uuid (INTERNALLENGTH = 22, INPUT = app_uuid_parser, OUTPUT = app_uuid_formatter)``.
Creating base types need superuser, which is restricted on cloud hosted databases. Additionally this way lets how the data is presented dictate how the data is stored which would be backwards.
Creating base types need superuser, which is restricted on cloud hosted databases. Additionally this way lets "how the data is presented" dictate "how the data is stored" which would be backwards.
+37
View File
@@ -69,6 +69,26 @@ If the function doesn't modify the database, it will also run under the GET meth
The function parameter names match the JSON object keys in the POST case, for the GET case they match the query parameters ``?a=1&b=2``.
If the function is defined to have default values for the parameters then arguments for these parameters can be omitted in the request. For instance:
.. code-block:: postgres
CREATE FUNCTION greet_user(username TEXT DEFAULT 'guest')
RETURNS TEXT AS $$
SELECT 'Hello ' || username || '!';
$$ LANGUAGE SQL IMMUTABLE;
.. code-block:: bash
curl -i "http://localhost:3000/rpc/greet_user"
.. code-block:: http
HTTP/1.1 200 OK
Context-Type: application/json; charset=utf-8
"Hello guest!"
.. _function_single_json:
Functions with an array of JSON objects
@@ -294,6 +314,23 @@ Let's get its :ref:`explain_plan` when calling it with filters applied:
Notice there's no "Function Scan" node in the plan, which tells us it has been inlined.
Horizontal Filtering
~~~~~~~~~~~~~~~~~~~~
Table-valued functions support horizontal filtering on selected and unselected columns.
For example, the following RPC with filter on unselected column returns:
.. code-block:: bash
curl "http://localhost:3000/rpc/getallprojects?select=id,client_id&name=like.OSX"
.. code-block:: json
[
{ "id": 4, "client_id": 2 }
]
.. _scalar_functions:
Scalar functions
+1 -1
View File
@@ -15,7 +15,7 @@ Using these domains, :ref:`functions <functions>` can become handlers and `user-
.. important::
- PostgREST vendor media types (``application/vnd.pgrst.plan``, ``application/vnd.pgrst.object`` and ``application/vnd.pgrst.array``) cannot be overriden.
- PostgREST vendor media types (``application/vnd.pgrst.plan``, ``application/vnd.pgrst.object`` and ``application/vnd.pgrst.array``) cannot be overridden.
- Long media types like ``application/vnd.openxmlformats-officedocument.wordprocessingml.document`` cannot be expressed as domains since they surpass `PostgreSQL identifier length <https://www.postgresql.org/docs/current/limits.html#LIMITS-TABLE>`_.
For these you can use the :ref:`any_handler`.
+37 -1
View File
@@ -117,6 +117,10 @@ However, with ``handling=strict``, an invalid time zone preference will throw an
HTTP/1.1 400 Bad Request
.. note::
This feature requires querying `pg_timezone_names <https://www.postgresql.org/docs/current/view-pg-timezone-names.html>`_ during :ref:`schema_cache` load. If this is not desired, you can disable the feature with :ref:`db-timezone-enabled`.
.. _prefer_return:
Return Representation
@@ -242,7 +246,7 @@ Will result in:
Max Affected
============
You can set a limit to the amount of resources affected in a request by sending ``max-affected`` preference. This feature works in combination with ``handling=strict`` preference. ``max-affected`` would be ignored with lenient handling. The "affected resources" are the number of rows returned by ``DELETE`` and ``PATCH`` requests. This is also supported through ``RPC`` calls.
You can set a limit to the amount of resources affected in a request by sending ``max-affected`` preference. This feature works in combination with ``handling=strict`` preference. ``max-affected`` would be ignored with lenient handling. The "affected resources" are the number of rows returned by ``DELETE`` and ``PATCH`` requests.
To illustrate the use of this preference, consider the following scenario where the ``items`` table contains 14 rows.
@@ -264,3 +268,35 @@ To illustrate the use of this preference, consider the following scenario where
"details": "The query affects 14 rows",
"hint": null
}
With :ref:`RPC <functions>`, the preference is honored completely on the basis of the number of rows returned in the result set of the function. This can be useful for complex mutation queries using `data-modifying statements <https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-MODIFYING>`_. A simple example:
.. code-block:: postgres
CREATE FUNCTION test.delete_items()
RETURNS SETOF items AS $$
DELETE FROM items WHERE id < 15 RETURNING *;
$$ LANGUAGE SQL;
.. code-block:: bash
curl -i "http://localhost:3000/rpc/delete_items" \
-H "Content-Type: application/json" \
-H "Prefer: handling=strict, max-affected=10"
.. code-block:: http
HTTP/1.1 400 Bad Request
.. code-block:: json
{
"code": "PGRST124",
"message": "Query result exceeds max-affected preference constraint",
"details": "The query affects 14 rows",
"hint": null
}
.. note::
It is important for functions to return ``SETOF`` or ``TABLE`` when called with ``max-affected`` preference. A violation of this would cause a :ref:`PGRST128 <pgrst128>` error.
+85 -61
View File
@@ -143,7 +143,7 @@ Since the table name is plural, we can be more accurate by making it singular wi
One-to-many relationships
-------------------------
The **foreign key reference** establishes the inverse one-to-many relationship. In this case, ``films`` returns as a JSON array because of the to-many end.
The **foreign key reference** establishes the inverse one-to-many relationship. In this case, ``films`` returns as a JSON array because of the "to-many" end.
.. code-block:: bash
@@ -251,6 +251,12 @@ Computed Relationships
You can manually define relationships by using functions. This is useful for database objects that can't define foreign keys, like `Foreign Data Wrappers <https://wiki.postgresql.org/wiki/Foreign_data_wrappers>`_.
Computed relationships have good performance as their intended design enable `function inlining <https://wiki.postgresql.org/wiki/Inlining_of_SQL_functions#Inlining_conditions_for_table_functions>`_.
.. important::
- Always use ``SETOF`` when creating computed relationships. Functions can return a table without using ``SETOF``, but bear in mind that PostgreSQL will not inline them. e.g. ``RETURNS <table_name>`` is not inlinable.
Assuming there's a foreign table ``premieres`` that we want to relate to ``films``.
.. code-block:: postgres
@@ -283,6 +289,10 @@ The name of the function ``film`` is arbitrary and can be used to do the embeddi
".."
]
.. warning::
- Make sure to correctly label the ``to-one`` part of the relationship. When using the ``ROWS 1`` estimation, PostgREST will expect a single row to be returned. If that is not the case, it will unnest the embedding and return repeated values for the top level resource.
Now let's define the opposite one-to-many relationship.
.. code-block:: postgres
@@ -331,12 +341,6 @@ Thanks to overloaded functions, you can use the same function name for different
Computed relationships have good performance as their intended design enable `function inlining <https://wiki.postgresql.org/wiki/Inlining_of_SQL_functions#Inlining_conditions_for_table_functions>`_.
.. warning::
- Always use ``SETOF`` when creating computed relationships. Functions can return a table without using ``SETOF``, but bear in mind that PostgreSQL will not inline them.
- Make sure to correctly label the ``to-one`` part of the relationship. When using the ``ROWS 1`` estimation, PostgREST will expect a single row to be returned. If that is not the case, it will unnest the embedding and return repeated values for the top level resource.
.. _embed_disamb:
.. _target_disamb:
.. _hint_disamb:
@@ -1150,27 +1154,19 @@ For example, to arrange the films in descending order using the director's last
Spread embedded resource
========================
The ``...`` operator lets you "spread" an embedded resource.
That is, it removes the surrounding JSON object for the embedded resource columns.
.. note::
The spread operator ``...`` is borrowed from the Javascript `spread syntax <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax>`_.
You can modify the shape of the embedded resources by using the spread syntax (``...``).
.. _spread_to_one_embed:
Spread To-One relationships
---------------------------
This applies to :ref:`one-to-one <one-to-one>` and :ref:`many-to-one <many-to-one>` relationships.
Take the following example:
Spread on resources forming :ref:`one-to-one <one-to-one>` and :ref:`many-to-one <many-to-one>` relationships, will lift the embedded columns to the top object.
.. code-block:: bash
# curl "http://localhost:3000/films?select=title,...directors(director_last_name:last_name)&title=like.*Workers*"
curl --get "http://localhost:3000/films" \
-d "select=title,...directors(director_last_name:last_name)" \
-d "select=title,...directors(director_first_name:first_name, director_last_name:last_name)" \
-d "title=like.*Workers*"
.. code-block:: json
@@ -1178,48 +1174,22 @@ Take the following example:
[
{
"title": "Workers Leaving The Lumière Factory In Lyon",
"director_first_name": "Louis",
"director_last_name": "Lumière"
}
]
Note that there is no ``"directors"`` object. Also the embed columns can be aliased normally.
You can use this to get the columns of a join table in a many-to-many relationship. For instance, to get films and its actors, but including the ``character`` column from the roles table:
.. code-block:: bash
# curl "http://localhost:3000/films?select=title,actors:roles(character,...actors(first_name,last_name))&title=like.*Lighthouse*"
curl --get "http://localhost:3000/films" \
-d "select=title,actors:roles(character,...actors(first_name,last_name))" \
-d "title=like.*Lighthouse*"
.. code-block:: json
[
{
"title": "The Lighthouse",
"actors": [
{
"character": "Thomas Wake",
"first_name": "Willem",
"last_name": "Dafoe"
}
]
}
]
Note that there is no wrapping ``"directors"`` object, unlike regularly embedding :ref:`many-to-one <many-to-one>` relationships. Also note that embedded columns can be aliased normally.
.. _spread_to_many_embed:
Spread To-Many relationships
----------------------------
The spread columns in :ref:`one-to-many <one-to-many>` or :ref:`many-to-many <many-to-many>` relationships will show the data in arrays.
Spread on resources forming :ref:`one-to-many <one-to-many>` and :ref:`many-to-many <many-to-many>` relationships, will convert the embedded columns into correlated arrays.
.. code-block:: bash
# curl -g "http://localhost:3000/directors?select=first_name,...films(film_titles:title,film_years:year)&first_name=like.Quentin*"
curl --get "http://localhost:3000/directors" \
-d "select=first_name,...films(film_titles:title,film_years:year)" \
-d "first_name=like.Quentin*"
@@ -1240,16 +1210,17 @@ The spread columns in :ref:`one-to-many <one-to-many>` or :ref:`many-to-many <ma
}
]
Note that there is no ``films`` array of objects.
Note that ``films`` is no longer an array of objects, unlike regularly embedding :ref:`one-to-many`. The embedded columns become arrays and they're correlated-in the above result, we can say that "Pulp Fiction" premiered in 1994 and "Reservoir Dogs" in 1992.
By default, the order of the values inside the resulting array is unspecified but `it is safe to assume <https://www.postgresql.org/message-id/15950.1491843689%40sss.pgh.pa.us>`_ that all the columns return the values in the same unspecified order.
From the previous result, we can say that "Pulp Fiction" premiered in 1994 and "Reservoir Dogs" in 1992.
You can still order all the resulting arrays explicitly. For example, to order by the release year:
Order in spread to-many
~~~~~~~~~~~~~~~~~~~~~~~
In the above example, the order of the values inside the correlated arrays is unspecified, but all the values are guaranteed to be in the same unspecified order.
You can order the correlated arrays explicitly. For example, to order by the film year:
.. code-block:: bash
# curl -g "http://localhost:3000/directors?select=first_name,...films(film_titles:title,film_years:year)&first_name=like.Quentin*&films.order=year"
curl --get "http://localhost:3000/directors" \
-d "select=first_name,...films(film_titles:title,film_years:year)" \
-d "first_name=like.Quentin*" \
@@ -1271,15 +1242,38 @@ You can still order all the resulting arrays explicitly. For example, to order b
}
]
Nesting Spreads
~~~~~~~~~~~~~~~
.. warning::
For example, let's nest ``...technical_specs`` (one-to-one) and ``...roles`` (one-to-many) inside ``...films``:
Aliasing spread columns is recommended since JSON allows duplicate keys. Example:
.. code-block:: bash
curl --get "localhost:3000/projects" \
-d "select=id,name,...clients(id,name)"
.. code-block:: json
[{"id":1,"name":"Windows 7","id":1,"name":"Microsoft"},
{"id":2,"name":"Windows 10","id":1,"name":"Microsoft"},
{"id":3,"name":"IOS","id":2,"name":"Apple"},
{"id":4,"name":"OSX","id":2,"name":"Apple"},
{"id":5,"name":"Orphan","id":null,"name":null}]
This can be a problem in Javascript objects, since only the last duplicated key will be considered. To solve it do:
.. code-block:: bash
curl --get "localhost:3000/projects" \
-d "select=id,name,...clients(client_id:id,client_name:name)"
Multiple Spreads
----------------
You can use multiple spreads at any level. For example, let's spread ``technical_specs`` and ``roles`` into ``films`` and then spread ``films`` into ``directors``:
.. code-block:: bash
# curl -g "http://localhost:3000/directors?select=first_name,...films(film_titles:title,film_years:year,...technical_specs(film_runtimes:runtime),...roles(film_characters:character))&first_name=like.Quentin*&films.order=year&films.roles.order=character"
curl --get "http://localhost:3000/directors" \
-d "select=first_name,...films(film_titles:title,film_years:year,...technical_specs(film_runtimes:runtime),...roles(film_characters:character))" \
-d "first_name=like.Quentin*" \
@@ -1310,6 +1304,36 @@ For example, let's nest ``...technical_specs`` (one-to-one) and ``...roles`` (on
}
]
All the elements inside ``films`` are selected in the same order, including both nested resources.
For example, we can say that "Reservoir Dogs" premiered in 1992, its runtime is 1:39:00 and it has the following characters: ``[ "Mr. Pink", "Mr. White" ]``.
Note that the data inside to-many nested resources can also be ordered (``roles`` by the ``character`` name in our example).
Note that:
- All the ``film_*`` arrays are correlated-"Reservoir Dogs" premiered in 1992, its runtime is 1:39:00 and it has the following characters: ``[ "Mr. Pink", "Mr. White" ]``.
- The ``film_*`` arrays are ordered by ``year`` (due to ``films.order=year``).
- The bottom level array ``film_characters`` is ordered (due to ``films.roles.order=character``).
Spread a join table
-------------------
Spread can be used to move the columns of a join table in a :ref:`many-to-many <many-to-many>` to the top object. For instance, to get the ``character`` column of the ``roles`` join table into ``actors``:
.. code-block:: bash
curl --get "http://localhost:3000/films" \
-d "select=title,actors:roles(character,...actors(first_name,last_name))" \
-d "title=like.*Lighthouse*"
.. code-block:: json
[
{
"title": "The Lighthouse",
"actors": [
{
"character": "Thomas Wake",
"first_name": "Willem",
"last_name": "Dafoe"
}
]
}
]
+4
View File
@@ -5,6 +5,10 @@ Schemas
PostgREST can expose a single or multiple schema's tables, views and functions. The :ref:`active database role <roles>` must have the usage privilege on the schemas to access them.
.. important::
``pg_catalog`` and ``information_schema`` are not allowed in :ref:`db-schemas`. This is done to prevent leaking sensitive information and hence they cannot be accessed directly. If you wish to expose objects of these schemas, expose another schema that contains wrapper views or functions over ``pg_catalog`` or ``information_schema`` objects.
Single schema
-------------
+26 -9
View File
@@ -175,23 +175,29 @@ To ensure best performance on larger data sets, an `appropriate index <https://w
Full-Text Search
~~~~~~~~~~~~~~~~
The :code:`fts` filter mentioned above has a number of options to support flexible textual queries, namely the choice of plain vs phrase search and the language used for stemming. Suppose that :code:`tsearch` is a table with column :code:`my_tsv`, of type `tsvector <https://www.postgresql.org/docs/current/datatype-textsearch.html>`_. The following examples illustrate the possibilities.
The :code:`fts` operator has a number of options to support flexible textual queries, namely the choice of plain vs phrase search and the language used for stemming.
The following examples illustrate the possibilities, assuming column :code:`my_tsv` is of type `tsvector <https://www.postgresql.org/docs/current/datatype-textsearch.html>`_.
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_tsv=fts(french).amusant"
curl --get "http://localhost:3000/people" \
-d "my_tsv=fts(french).amusant"
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_tsv=plfts.The%20Fat%20Cats"
curl --get "http://localhost:3000/people" \
-d "my_tsv=plfts.The%20Fat%20Cats"
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_tsv=not.phfts(english).The%20Fat%20Cats"
curl --get "http://localhost:3000/people" \
-d "my_tsv=not.phfts(english).The%20Fat%20Cats"
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_tsv=not.wfts(french).amusant"
curl --get "http://localhost:3000/people" \
-d "my_tsv=not.wfts(french).amusant"
.. _fts_to_tsvector:
@@ -199,15 +205,26 @@ Automatic ``tsvector`` conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If the filtered column is not of type ``tsvector``, then it will be automatically converted using `to_tsvector() <https://www.postgresql.org/docs/current/functions-textsearch.html#TEXTSEARCH-FUNCTIONS-TABLE>`_.
This allows using ``fts`` on ``text`` and ``json`` types out of the box, for example.
This allows using the ``fts`` operator on ``text`` and ``json`` types out of the box.
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_text_column=fts(french).amusant"
curl --get "http://localhost:3000/people" \
-d "my_text_column=fts(french).amusant"
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_json_column=not.phfts(english).The%20Fat%20Cats"
curl --get "http://localhost:3000/people" \
-d "my_json_column=not.phfts(english).The%20Fat%20Cats"
.. important::
To ensure this operation is fast, you need to create an index on the expression:
.. code-block:: postgres
CREATE INDEX idx_people_col ON people
USING GIN (to_tsvector('french', my_text_column));
.. _v_filter:
@@ -622,7 +639,7 @@ However, it can work with surrogate primary keys (e.g. ``id serial primary key``
.. code-block:: bash
curl "http://localhost:3000/employees?colums=id,name,salary" \
curl "http://localhost:3000/employees?columns=id,name,salary" \
-X POST -H "Content-Type: application/json" \
-H "Prefer: resolution=merge-duplicates, missing=default" \
-d @- << EOF
+2 -2
View File
@@ -14,7 +14,7 @@ Custom Queries
The PostgREST URL grammar limits the kinds of queries clients can perform. It prevents arbitrary, potentially poorly constructed and slow client queries. It's good for quality of service, but means database administrators must create custom views and functions to provide richer endpoints. The most common causes for custom endpoints are
* Table unions
* SET operators like `UNION, INTERSECT and EXCEPT <https://www.postgresql.org/docs/current/queries-union.html>`_.
* More complicated joins than those provided by :ref:`resource_embedding`.
* Geo-spatial queries that require an argument, like "points near (lat,lon)"
@@ -51,7 +51,7 @@ You can request table/columns with spaces in them by percent encoding the spaces
Reserved characters
~~~~~~~~~~~~~~~~~~~
If filters include PostgREST reserved characters(``,``, ``.``, ``:``, ``()``) you'll have to surround them in percent encoded double quotes ``%22`` for correct processing.
If filters include PostgREST reserved characters(``,``, ``.``, ``:``, ``*``, ``(``, ``)``) you'll have to surround them in percent encoded double quotes ``%22`` for correct processing.
Here ``Hebdon,John`` and ``Williams,Mary`` are values.
+16
View File
@@ -0,0 +1,16 @@
.. _vary_header:
Vary Header
===========
In order to assist caching proxies and CDNs, PostgREST includes a ``Vary`` header of value
``Accept, Prefer, Range`` in its responses which should fit most of the bills. As any other
response header, it's available for override
by updating ``response.headers`` GUC variable accordingly, for example:
.. code-block:: postgres
-- Override the Vary header to include Accept, Prefer and X-Test-Vary headers
perform set_config('response.headers', '[{"Vary": "Accept, Prefer, X-Test-Vary"}]', true);
In this case PostgREST will use provided value verbatim.
+108 -38
View File
@@ -31,7 +31,7 @@ The authenticator role is used for connecting to the database and should be conf
.. _user_impersonation:
User Impersonation
------------------
~~~~~~~~~~~~~~~~~~
The picture below shows how the server handles authentication. If auth succeeds, it switches into the user role specified by the request, otherwise it switches into the anonymous role (if it's set in :ref:`db-anon-role`).
@@ -43,12 +43,13 @@ This role switching mechanism is called **user impersonation**. In PostgreSQL it
The impersonated roles will have their settings applied. See :ref:`impersonated_settings`.
.. _jwt_impersonation:
.. _jwt_auth:
JWT-Based User Impersonation
----------------------------
JWT Authentication
------------------
We use `JSON Web Tokens <https://jwt.io/>`_ to authenticate API requests, this allows us to be stateless and not require database lookups for verification. As you'll recall a JWT contains a list of cryptographically signed claims. All claims are allowed but PostgREST cares specifically about a claim called role.
We use `JSON Web Tokens <https://datatracker.ietf.org/doc/html/rfc7519/>`_ to authenticate API requests, this allows us to be stateless and not require database lookups for verification.
As you'll recall a JWT contains a list of cryptographically signed claims. All claims are allowed but PostgREST cares specifically about a claim called role (configurable with :ref:`jwt_role_extract`).
.. code:: json
@@ -72,17 +73,10 @@ Note that the database administrator must allow the authenticator role to switch
If the client included no JWT (or one without a role claim) then PostgREST switches into the anonymous role. The database administrator must set the anonymous role permissions correctly to prevent anonymous users from seeing or changing things they shouldn't.
.. _jwt_generation:
.. _bearer_auth:
JWT Generation
~~~~~~~~~~~~~~
You can create a valid JWT either from inside your database (see :ref:`sql_user_management`) or via an external service (see :ref:`external_jwt`).
.. _client_auth:
Client Auth
~~~~~~~~~~~
Bearer Authentication
~~~~~~~~~~~~~~~~~~~~~
To make an authenticated request the client must include an :code:`Authorization` HTTP header with the value :code:`Bearer <jwt>`. For instance:
@@ -93,24 +87,29 @@ To make an authenticated request the client must include an :code:`Authorization
The ``Bearer`` header value can be used with or without capitalization(``bearer``).
.. _jwt_caching:
.. _jwt_generation:
JWT Caching
-----------
JWT Generation
~~~~~~~~~~~~~~
PostgREST validates ``JWTs`` on every request. We can cache ``JWTs`` to avoid this performance overhead.
You can create a valid JWT either from inside your database (see :ref:`sql_user_management`) or via an external service (see :ref:`external_auth`).
To enable JWT caching, the config :code:`jwt-cache-max-lifetime` is to be set. It is the maximum number of seconds for which the cache stores the JWT validation results. The cache uses the :code:`exp` claim to set the cache entry lifetime. If the JWT does not have an :code:`exp` claim, it uses the config value. See :ref:`jwt-cache-max-lifetime` for more details.
.. _jwt_signature:
.. note::
JWT Signature Verification
--------------------------
You can use the :ref:`server-timing_header` to see the effect of JWT caching.
PostgREST supports both symmetric and asymmetric keys for verifying the signature of the token.
Symmetric Keys
~~~~~~~~~~~~~~
Each token is cryptographically signed with a secret key. In the case of symmetric cryptography the signer and verifier share the same secret passphrase, which can be configured with :ref:`jwt-secret`.
If it is set to a simple string value like “reallyreallyreallyreallyverysafe” then PostgREST interprets it as an HMAC-SHA256 passphrase.
In the case of symmetric cryptography the signer and verifier share the same secret passphrase, which can be configured with :ref:`jwt-secret`.
If it is set to a simple string then PostgREST interprets it as an HMAC-SHA256 passphrase.
.. code-block:: ini
jwt-secret = "reallyreallyreallyreallyverysafe"
.. _asym_keys:
@@ -156,26 +155,39 @@ You can specify the literal value as we saw earlier, or reference a filename to
jwt-secret = "@rsa.jwk.pub"
``kid`` verification
^^^^^^^^^^^^^^^^^^^^
PostgREST has built-in verification of the `key ID parameter <https://www.rfc-editor.org/rfc/rfc7517#section-4.5>`_, useful when working with a JSON Web Key Set.
It goes as follows:
- If the JWT contains a ``kid`` parameter, then PostgREST will look for the JSON Web Key in the :ref:`jwt-secret`.
+ If no key has a matching ``kid`` (or if they don't have one defined), the token will be rejected with a :ref:`401 Unauthorized <pgrst301>` error.
+ If a key matches the ``kid`` value then it will validate the token against that key accordingly.
- If the JWT doesn't have a ``kid``, PostgREST will try each key in the :ref:`jwt-secret` one by one until it finds one that works.
.. _jwt_claims_validation:
JWT Claims Validation
~~~~~~~~~~~~~~~~~~~~~
---------------------
PostgREST honors the following `JWT claims <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4>`_:
Time-Based claims validation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The time-based JWT claims specified in `RFC 7519 <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4>`_ are validated:
- ``exp`` Expiration Time
- ``iat`` Issued At
- ``nbf`` Not Before
- ``aud`` :ref:`Audience <jwt_aud_validation>`
.. note::
PostgREST allows for a 30-second clock skew when validating the ``exp``, ``iat`` and ``nbf`` claims.
In other words, it gives an extra 30 seconds before the token is rejected if there is a slight discrepancy in the timestamps.
We allow a 30-second clock skew when validating the above claims. In other words, we give an extra 30 seconds before the JWT is rejected if there is a slight discrepancy in the timestamps.
.. _jwt_aud_validation:
.. _jwt_aud:
JWT ``aud`` Claim Validation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``aud`` validation
~~~~~~~~~~~~~~~~~~
PostgREST has built-in validation of the `JWT audience claim <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3>`_.
It works this way:
@@ -188,12 +200,31 @@ It works this way:
+ If the match fails or if the ``aud`` value is not a string or array of strings, then the token will be rejected with a :ref:`401 Unauthorized <pgrst303>` error.
+ If the ``aud`` key **is not present** or if its value is ``null`` or ``[]``, PostgREST will interpret this token as allowed for all audiences and will complete the request.
.. _jwt_role_claim_key_extract:
.. _jwt_caching:
JWT Role Claim Key Extraction
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
JWT Cache
---------
A JSPath DSL that specifies the location of the :code:`role` key in the JWT claims. This can be used to consume a JWT provided by a third party service like Auth0, Okta, Microsoft Entra or Keycloak.
JWT signature validation (specially :ref:`asym_keys` such as RSA) is slow, we can cache ``JWT`` validation results to avoid this performance overhead.
The JWT cache is bounded and uses the `SIEVE algorithm <https://cachemon.github.io/SIEVE-website>`_ for efficient eviction. The cache is enabled by default and can be configured with :ref:`jwt-cache-max-entries`.
It's recommended to leave the JWT cache enabled as our load tests indicate ~20% more throughput for simple GET requests when using it. This while reducing CPU utilization in exchange for a bit more memory.
:ref:`jwt_cache_metrics` are available.
.. note::
- If the ``jwt-secret`` is changed and the config is reloaded, the JWT cache will reset.
- JWTs that pass :ref:`jwt_signature` are cached, regardless if they pass :ref:`jwt_claims_validation`. We do this to ensure responses stays fast under common failure cases (such as expired JWTs).
- You can use the :ref:`server-timing_header` to see the performance benefit of JWT caching.
.. _jwt_role_extract:
JWT Role Extraction
-------------------
A JSPath DSL that specifies the location of the :code:`role` key in the JWT claims. It's configured by :ref:`jwt-role-claim-key`. This can be used to consume a JWT provided by a third party service like Auth0, Okta, Microsoft Entra or Keycloak.
The DSL follows the `JSONPath <https://goessner.net/articles/JsonPath/>`_ expression grammar with extended string comparison operators. Supported operators are:
@@ -203,6 +234,17 @@ The DSL follows the `JSONPath <https://goessner.net/articles/JsonPath/>`_ expres
- ``==^`` selects the first array element that ends with the right operand
- ``*==`` selects the first array element that contains the right operand
The selected role value can also be sliced using the slice operator ``[a:b]``. It is similar to `slice operator in python <https://docs.python.org/3/library/functions.html#slice>`_. Negative index values are also supported. The syntax is as:
- ``[a:b]`` take slice from index ``a`` up to ``b``
- ``[a:]`` take slice from index ``a`` to end
- ``[:b]`` take slice from start to index ``b``
- ``[:]`` select everything, no slicing
.. important::
Make sure that you are not taking a slice where the start index comes after the end index like ``[11:2]``. The result of this would be empty string and so no role would get selected.
Usage examples:
.. code:: bash
@@ -224,9 +266,17 @@ Usage examples:
jwt-role-claim-key = ".postgrest.roles[?(@ ==^ \"hor\")]"
jwt-role-claim-key = ".postgrest.roles[?(@ *== \"utho\")]"
# {"postgrest":{"wlcg": ["/groupa", "/groupb/"]}}
# skip the "/" character using slice operator
jwt-role-claim-key = ".postgrest.wlcg[0][1:]"
jwt-role-claim-key = ".postgrest.wlcg[1][1:-1]"
.. note::
The string comparison operators are implemented as a custom extension to the JSPath and does not strictly follow the `RFC 9535 <https://www.rfc-editor.org/rfc/rfc9535.html>`_.
JWT Security
~~~~~~~~~~~~
------------
There are at least three types of common critiques against using JWT: 1) against the standard itself, 2) against using libraries with known security vulnerabilities, and 3) against using JWT for web sessions. We'll briefly explain each critique, how PostgREST deals with it, and give recommendations for appropriate user action.
@@ -262,3 +312,23 @@ doing custom logic based on the web user info.
END IF;
END
$$ LANGUAGE plpgsql;
.. raw:: html
<script type="text/javascript">
let hash = window.location.hash;
const redirects = {
'#jwt-based-user-impersonation': '#jwt-authentication',
'#client-auth': '#bearer-authentication',
'#jwt-caching': '#jwt-cache',
'#jwk-kid-validation': '#kid-verification',
'#jwt-aud-claim-validation': '#aud-validation',
};
let willRedirectTo = redirects[hash];
if (willRedirectTo) {
window.location.href = willRedirectTo;
}
</script>
+46 -8
View File
@@ -3,23 +3,47 @@
CLI
===
PostgREST provides a CLI with the commands listed below:
PostgREST provides a CLI with the options listed below:
.. code:: text
Usage: postgrest [-v|--version] [-e|--example] [--dump-config | --dump-schema | --ready]
[FILENAME]
PostgREST / create a REST API to an existing Postgres
database
Available options:
-h,--help Show this help text
-v,--version Show the version information
-e,--example Show an example configuration file
--dump-config Dump loaded configuration and exit
--dump-schema Dump loaded schema as JSON and exit (for debugging,
output structure is unstable)
--ready Checks the health of PostgREST by doing a request on
the admin server /ready endpoint
FILENAME Path to configuration file
FILENAME
--------
Runs PostgREST with the given :ref:`file_config`.
Help
----
.. code:: bash
$ postgrest [-h|--help]
$ postgrest --help
Shows all the commands available.
Shows all the options available.
Version
-------
.. code:: bash
$ postgrest [-v|--version]
$ postgrest --version
Prints the PostgREST version.
@@ -28,16 +52,16 @@ Example
.. code:: bash
$ postgrest [-e|--example]
$ postgrest --example
Shows example configuration options.
Shows example configuration settings.
Dump Config
-----------
.. code:: bash
$ postgrest [--dump-config]
$ postgrest --dump-config
Dumps the loaded :ref:`configuration` values, considering the configuration file, environment variables and :ref:`in_db_config`.
@@ -46,6 +70,20 @@ Dump Schema
.. code:: bash
$ postgrest [--dump-schema]
$ postgrest --dump-schema
Dumps the schema cache in JSON format.
Ready Flag
----------
Makes a request to the ``/ready`` endpoint of the :ref:`admin_server`. It exits with a return code of ``0`` on success and ``1`` on failure.
.. code-block:: bash
$ postgrest --ready
OK: http://localhost:3001/ready
.. note::
The ``--ready`` flag cannot be used when :ref:`server-host` is configured with special hostnames. We suggest to change it to ``localhost``.
+62 -25
View File
@@ -195,6 +195,33 @@ app.settings.*
The :code:`current_setting` function has `an optional boolean second <https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADMIN-SET>`_ argument to avoid it from raising an error if the value was not defined. Default values to :code:`app.settings` can then be given by combining this argument with :code:`coalesce` and :code:`nullif` : :code:`coalesce(nullif(current_setting('app.settings.my_custom_variable', true), ''), 'default value')`. The use of :code:`nullif` is necessary because if set in a transaction, the setting is sometimes not "rolled back" to :code:`null`. See also :ref:`this section <guc_req_headers_cookies_claims>` for more information on this behaviour.
.. _client-error-verbosity:
client-error-verbosity
----------------------
=============== =======================
**Type** String
**Default** verbose
**Reloadable** Y
**Environment** PGRST_CLIENT_ERROR_VERBOSITY
**In-Database** pgrst.client_error_verbosity
=============== =======================
Specifies the verbosity of PostgREST errors. See :ref:`client_error_verbosity`.
.. code:: bash
# Return error "code", "message", "details" and "hint"
client-error-verbosity = "verbose"
# Return only "code" and "message"
client-error-verbosity = "minimal"
.. note::
This setting only affects client side error messages. Server side logs are not affected by this setting.
.. _db-aggregates-enabled:
db-aggregates-enabled
@@ -264,7 +291,7 @@ db-channel-enabled
When this is set to :code:`true`, the notification channel specified in :ref:`db-channel` is enabled.
You should set this to ``false`` when using PostgresSQL behind an external connection pooler such as PgBouncer working in transaction pooling mode. See :ref:`this section <external_connection_poolers>` for more information.
You should set this to ``false`` when using PostgreSQL behind an external connection pooler such as PgBouncer working in transaction pooling mode. See :ref:`this section <external_connection_poolers>` for more information.
.. _db-config:
@@ -315,6 +342,10 @@ db-extra-search-path
Multiple schemas can be added in a comma-separated string, e.g. ``public, extensions``.
.. important::
We default this config to ``public`` because it is the most common schema used to install PostgreSQL extensions such as :ref:`PostGIS <ww_postgis>`. You can disable this by setting this config to ``""``.
.. _db-hoisted-tx-settings:
db-hoisted-tx-settings
@@ -405,7 +436,7 @@ db-pool-max-idletime
**In-Database** `n/a`
=============== =================================
*For backwards compatibility, this config parameter is also available as db-pool-timeout.*
*For backwards compatibility, this config parameter is also available as "db-pool-timeout".*
Time in seconds to close idle pool connections.
@@ -475,7 +506,7 @@ db-prepared-statements
When disabled, the generated queries will be parameterized (invulnerable to SQL injection) but they will not be prepared (cached in the database session). Not using prepared statements will noticeably decrease performance, so it's recommended to always have this setting enabled.
You should only set this to ``false`` when using PostgresSQL behind an external connection pooler such as PgBouncer working in transaction pooling mode. See :ref:`this section <external_connection_poolers>` for more information.
You should only set this to ``false`` when using PostgreSQL behind an external connection pooler such as PgBouncer working in transaction pooling mode. See :ref:`this section <external_connection_poolers>` for more information.
.. _db-root-spec:
@@ -509,6 +540,21 @@ db-schemas
The list of database schemas to expose to clients. See :ref:`schemas`.
.. _db-timezone-enabled:
db-timezone-enabled
-------------------
=============== =================================
**Type** Boolean
**Default** True
**Reloadable** Y
**Environment** PGRST_DB_TIMEZONE_ENABLED
**In-Database** pgrst.db_timezone_enabled
=============== =================================
Enables the use of :ref:`prefer_timezone` preference header. Disabled when set to ``false``.
.. _db-tx-end:
db-tx-end
@@ -522,7 +568,7 @@ db-tx-end
**In-Database** pgrst.db_tx_end
=============== =================================
Specifies how to terminate the database transactions.
Specifies how to terminate the database transactions. See :ref:`prefer_tx`.
.. code:: bash
@@ -599,7 +645,7 @@ jwt-aud
**In-Database** pgrst.jwt_aud
=============== =================================
Specifies an audience for the JWT ``aud`` claim. See :ref:`jwt_aud_validation`.
Specifies an audience for the JWT ``aud`` claim. See :ref:`jwt_aud`.
.. _jwt-role-claim-key:
@@ -616,7 +662,7 @@ jwt-role-claim-key
*For backwards compatibility, this config parameter is also available without prefix as "role-claim-key".*
See :ref:`jwt_role_claim_key_extract` on how to specify key paths and usage examples.
See :ref:`jwt_role_extract` on how to specify key paths and usage examples.
.. _jwt-secret:
@@ -654,20 +700,20 @@ jwt-secret-is-base64
When this is set to :code:`true`, the value derived from :code:`jwt-secret` will be treated as a base64 encoded secret.
.. _jwt-cache-max-lifetime:
.. _jwt-cache-max-entries:
jwt-cache-max-lifetime
jwt-cache-max-entries
----------------------
=============== =================================
**Type** Int
**Default** 0
**Default** 1000
**Reloadable** Y
**Environment** PGRST_JWT_CACHE_MAX_LIFETIME
**In-Database** pgrst.jwt_cache_max_lifetime
**Environment** PGRST_JWT_CACHE_MAX_ENTRIES
**In-Database** pgrst.jwt_cache_max_entries
=============== =================================
Maximum number of seconds of lifetime for cached entries. The default :code:`0` disables caching. See :ref:`jwt_caching`.
Maximum number of entries in JWT cache. The value :code:`0` disables JWT caching. See :ref:`jwt_caching`.
.. _log-level:
@@ -710,23 +756,14 @@ log-query
---------
=============== =================================
**Type** String
**Default** "disabled"
**Type** Boolean
**Default** False
**Reloadable** Y
**Environment** PGRST_LOG_QUERY
**In-Database** `n/a`
=============== =================================
Logs the SQL query for the corresponding request at the current :ref:`log-level`.
See :ref:``sql_query_logs``.
.. code:: bash
# Logs the main SQL query
log-query = "main-query"
# Disables logging the SQL query
log-query = "disabled"
Logs the SQL query for the corresponding request at the current :ref:`log-level`. See :ref:`sql_query_logs`.
.. _openapi-mode:
@@ -890,7 +927,7 @@ server-timing-enabled
**In-Database** pgrst.server_timing_enabled
=============== =================================
Enables the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>`_ header.
Enables the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing>`_ header.
See :ref:`server-timing_header`.
.. _server-unix-socket:
+2 -2
View File
@@ -15,7 +15,7 @@ Dynamic Connection Pool
To conserve system resources, PostgREST uses a dynamic connection pool. This enables the number of connections in the pool to increase and decrease depending on request traffic.
- If all the connections are being used, a new connection is added. The pool can grow until it reaches the :ref:`db-pool` size. Note that its pointless to set this higher than the ``max_connections`` setting in your database.
- If all the connections are being used, a new connection is added. The pool can grow until it reaches the :ref:`db-pool` size. Note that it's pointless to set this higher than the ``max_connections`` setting in your database.
- If a connection is unused for a period of time (:ref:`db-pool-max-idletime`), it will be released.
- For connecting to the database, the :ref:`authenticator <roles>` role is used. You can configure this using :ref:`db-uri`.
@@ -106,4 +106,4 @@ Also set :ref:`db-channel-enabled` to ``false`` since ``LISTEN`` is not compatib
.. note::
Its not recommended to use an external connection pooler. `Our benchmarks <https://github.com/PostgREST/postgrest/issues/2294#issuecomment-1139148672>`_ indicate it provides much lower performance than PostgREST built-in pool.
It's not recommended to use an external connection pooler. `Our benchmarks <https://github.com/PostgREST/postgrest/issues/2294#issuecomment-1139148672>`_ indicate it provides much lower performance than PostgREST built-in pool.
+40 -1
View File
@@ -267,6 +267,10 @@ Related to the HTTP request elements.
| | | implemented. |
| PGRST127 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst128: | 400 | ``max-affected`` preference is violated with ``RPC`` call. |
| | | See :ref:`prefer_max_affected`. |
| PGRST128 | | |
+---------------+-------------+-------------------------------------------------------------+
.. _pgrst2**:
@@ -325,7 +329,7 @@ Related to the authentication process using JWT. You can follow the :ref:`tut1`
| PGRST301 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst302: | 401 | Attempted to do a request without |
| | | :ref:`authentication <client_auth>` when the anonymous role |
| | | :ref:`bearer_auth` when the anonymous role |
| PGRST302 | | is disabled by not setting it in :ref:`db-anon-role`. |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst303: | 401 | :ref:`JWT claims validation <jwt_claims_validation>` |
@@ -469,3 +473,38 @@ For example, doing a request on a table with high count (say 30_000_000), we get
Proxy-Status: PostgREST; error=57014
The PostgreSQL error code ``57014`` (`ref <https://www.postgresql.org/docs/current/errcodes-appendix.html>`_) reveals that the error is due to a short ``statement_timeout`` value.
.. _client_error_verbosity:
Client Error Verbosity
======================
For HTTP clients, the error verbosity can be set via :ref:`client-error-verbosity` config.
With ``verbose``, it returns ``code``, ``message``, ``details`` and ``hint``.
.. code:: bash
curl "localhost:3000/itemsxx"
.. code-block:: json
{
"code": "PGRST205",
"message": "Could not find the table 'public.itemsxx' in the schema cache",
"details": "Perhaps you meant the table 'public.items'",
"hint": null
}
With ``minimal``, just ``code`` and ``message`` is returned.
.. code:: bash
curl "localhost:3000/itemsxx"
.. code-block:: json
{
"code": "PGRST205",
"message": "Could not find the table 'public.itemsxx' in the schema cache"
}
+4 -2
View File
@@ -4,7 +4,7 @@ Listener
########
PostgREST uses `LISTEN <https://www.postgresql.org/docs/current/sql-listen.html>`_ to reload its :ref:`Schema Cache <schema_reloading_notify>` and :ref:`Configuration <config_reloading_notify>` via `NOTIFY <https://www.postgresql.org/docs/current/sql-notify.html>`_.
This is useful in environments where you cant send SIGUSR1 or SIGUSR2 Unix Signals.
This is useful in environments where you can't send SIGUSR1 or SIGUSR2 Unix Signals.
Like on cloud managed containers or on Windows systems.
.. code:: postgresql
@@ -46,7 +46,9 @@ This will cause the :ref:`connection_pool` to connect to the read replica host a
.. note::
Under the hood, PostgREST forces `target_session_attrs=read-write <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-TARGET-SESSION-ATTRS>`_ for the ``LISTEN`` session.
- Under the hood, PostgREST forces `target_session_attrs=read-write <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-TARGET-SESSION-ATTRS>`_ for the ``LISTEN`` session.
So if you specify ``target_session_attrs=read-only`` as mentioned above, PostgREST will override it for the ``LISTEN``.
- ``read-only`` is only available on libpq >= 14, if you use a lower version you will get an error like ``invalid target_session_attrs value: \"read-only\"``.
.. _listener_automatic_recovery:
+44 -7
View File
@@ -52,14 +52,12 @@ For diagnostic information about the server itself, PostgREST logs to ``stderr``
SQL Query Logs
--------------
To log the :ref:`main SQL query <main_query>` executed for a request, set the :ref:`log-query` to ``main-query``.
It will be logged based on the current :ref:`log-level` setting.
For example, with this configuration:
To log the SQL queries executed for a request, set the :ref:`log-query` to ``true``. It will be logged based on the current :ref:`log-level` setting.
.. code-block:: bash
log-level = "warn"
log-query = "main-query"
log-query = "true"
The SQL queries will only be logged on ``400`` HTTP errors and up.
So, if the user requests a resource without sufficient privileges:
@@ -122,12 +120,17 @@ Restart the database and watch the log file in real-time to understand how HTTP
Metrics
=======
The ``metrics`` endpoint on the :ref:`admin_server` endpoint provides metrics in `Prometheus text format <https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format>`_.
The ``metrics`` endpoint on the :ref:`admin_server` endpoint provides metrics in `Prometheus text format <https://prometheus.io/docs/instrumenting/exposition_formats/#prometheus-text-format>`_.
.. code-block:: bash
curl "http://localhost:3001/metrics"
.. code-block:: http
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
# HELP pgrst_schema_cache_query_time_seconds The query time in seconds of the last schema cache load
# TYPE pgrst_schema_cache_query_time_seconds gauge
pgrst_schema_cache_query_time_seconds 1.5937927e-2
@@ -201,6 +204,40 @@ pgrst_db_pool_max
Max pool connections.
.. _jwt_cache_metrics:
JWT Cache Metrics
-----------------
Metrics related to the :ref:`jwt_caching`.
pgrst_jwt_cache_requests_total
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
======== =======
**Type** Counter
======== =======
The total number of JWT cache lookups.
pgrst_jwt_cache_hits_total
~~~~~~~~~~~~~~~~~~~~~~~~~~
======== =======
**Type** Counter
======== =======
The total number of JWT cache hits.
pgrst_jwt_cache_evictions_total
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
======== =======
**Type** Counter
======== =======
The total number of JWT cache evictions.
Traces
======
@@ -246,7 +283,7 @@ See :ref:`proxy-status_header`.
Server-Timing Header
--------------------
You can enable the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>`_ header by setting :ref:`server-timing-enabled` on.
You can enable the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing>`_ header by setting :ref:`server-timing-enabled` on.
This header communicates metrics of the different phases in the request-response cycle.
.. code-block:: bash
@@ -260,7 +297,7 @@ This header communicates metrics of the different phases in the request-response
Server-Timing: jwt;dur=14.9, parse;dur=71.1, plan;dur=109.0, transaction;dur=353.2, response;dur=4.4
- All the durations (``dur``) are in milliseconds.
- The ``jwt`` stage is when :ref:`jwt_impersonation` is done. This duration can be lowered with :ref:`jwt_caching`.
- The ``jwt`` stage is when :ref:`jwt_auth` is done. This duration can be lowered with :ref:`jwt_caching`.
- On the ``parse`` stage, the :ref:`url_grammar` is parsed.
- On the ``plan`` stage, the :ref:`schema_cache` is used to generate the :ref:`main_query` of the transaction.
- The ``transaction`` stage corresponds to the database transaction. See :ref:`transactions`.
+20 -1
View File
@@ -3,10 +3,16 @@
Schema Cache
============
PostgREST requires metadata from the database schema to provide a REST API that abstracts SQL details. One example of this is the interface for :ref:`resource_embedding`.
PostgREST requires metadata from the database to provide a REST API that abstracts SQL details. One example of this is the interface for :ref:`resource_embedding`.
Getting this metadata requires expensive queries. To avoid repeating this work, PostgREST uses a schema cache.
.. note::
- Schema cache queries have been optimized over time to stay fast, even on complex databases. You can see a summary of their execution time in :ref:`pgrst_logging` and :ref:`metrics`.
- If the schema cache queries are slow, the most likely cause is *system catalog bloat*, see `issue#3212 <https://github.com/PostgREST/postgrest/issues/3212>`_ for more details.
- You can turn the :ref:`log-level` to ``debug`` to see the time of each schema cache query.
.. _schema_reloading:
Schema Cache Reloading
@@ -53,6 +59,19 @@ To reload the schema cache from within the database, you can use the ``NOTIFY``
NOTIFY pgrst, 'reload schema'
Debouncing
~~~~~~~~~~
PostgREST does not reload the schema cache for each notification when several ``NOTIFY pgrst`` events are generated quickly after one another.
There are two cases to consider: when notifications are sent within a single transaction and when they are sent across multiple transactions.
In the first case, PostgreSQL deduplicates identical ``NOTIFY`` events within the same transaction. This means that even if multiple ``NOTIFY pgrst`` statements are executed before a ``COMMIT``, only a single notification is delivered to PostgREST.
In the second case, when notifications are sent from separate transactions in a short time span, PostgREST applies a debouncing mechanism to avoid excessive schema cache reloads.
Instead of reloading the schema cache for each notification, events are grouped within a small time window of 100 milliseconds. The reload function is executed once immediately when the first notification is received and once more after the burst of events settles, resulting in at most two executions within that time window.
.. _auto_schema_reloading:
Automatic Schema Cache Reloading
+1 -1
View File
@@ -221,7 +221,7 @@ Notice that the ``response.headers`` should be set to an *array* of single-key o
.. note::
PostgREST provided headers such as ``Content-Type``, ``Location``, etc. can be overriden this way. Note that irrespective of overridden ``Content-Type`` response header, the content will still be converted to JSON, unless you use :ref:`custom_media`.
PostgREST provided headers such as ``Content-Type``, ``Location``, etc. can be overridden this way. Note that irrespective of overridden ``Content-Type`` response header, the content will still be converted to JSON, unless you use :ref:`custom_media`.
.. _guc_resp_status:
+4 -4
View File
@@ -1,7 +1,7 @@
# This file is auto-generated by postgrest-nixpkgs-upgrade
sphinx==7.4.7
sphinx==9.1.0
sphinx-copybutton==0.5.2
sphinx-rtd-dark-mode==1.3.0
sphinx-rtd-theme==2.0.0
sphinx-tabs==3.4.7
sphinxext-opengraph==0.9.1
sphinx-rtd-theme==3.1.0
sphinx-tabs==3.5.0
sphinxext-opengraph==0.13.0
+1 -1
View File
@@ -22,7 +22,7 @@ Step 1. Install PostgreSQL
If you're already familiar with using PostgreSQL and have it installed on your system you can use the existing installation (see :ref:`pg-dependency` for minimum requirements). For this tutorial we'll describe how to use the database in Docker because database configuration is otherwise too complicated for a simple tutorial.
If Docker is not installed, you can get it `here <https://www.docker.com/get-started>`_. Next, let's pull and start the database image:
If Docker is not installed, you can get it `here <https://www.docker.com/get-started>`_. Make sure that Docker service is `started <https://docs.docker.com/engine/daemon/start/#start-the-daemon-using-operating-system-utilities>`_. Next, let's pull and start the database image:
.. code-block:: bash
+33 -11
View File
@@ -52,17 +52,31 @@ Check that the :code:`tutorial.conf` (created in the previous tutorial) has the
If the PostgREST server is still running from the previous tutorial, restart it to load the updated configuration file.
.. _tut1_step3:
Step 3. Sign a Token
--------------------
Ordinarily your own code in the database or in another server will create and sign authentication tokens, but for this tutorial we will make one "by hand." Go to `jwt.io <https://jwt.io/#debugger-io>`_ and fill in the fields like this:
Ordinarily your own code in the database or in another server will create and sign authentication tokens, but for this tutorial we will make one "by hand" using ``bash`` and ``openssl``.
.. figure:: ../_static/tuts/tut1-jwt-io.png
:alt: jwt.io interface
.. code:: bash
How to create a token at https://jwt.io
#!/bin/bash
set -e
**Remember to fill in the secret you generated rather than the word "secret".** After you have filled in the secret and payload, the encoded data on the left will update. Copy the encoded token.
JWT_SECRET='test_secret_that_is_at_least_32_characters_long'
_base64 () { openssl base64 -e -A | tr '+/' '-_' | tr -d '='; }
header=$(echo -n '{"alg":"HS256","typ":"JWT"}' | _base64)
payload=$(echo -n "{\"role\":\"todo_user\"}" | _base64)
signature=$(echo -n "$header.$payload" | openssl dgst -sha256 -hmac "$JWT_SECRET" -binary | _base64)
echo -n "$header.$payload.$signature"
**Remember to fill in the secret you generated rather than keeping the "test_secret_that_is_at_least_32_characters_long".** After you have filled in the secret and payload, the encoded data on the left will update. Copy the encoded token.
.. note::
@@ -145,14 +159,22 @@ To observe expiration in action, we'll add an :code:`exp` claim of five minutes
select extract(epoch from now() + '5 minutes'::interval) :: integer;
Go back to jwt.io and change the payload to
Or in ``bash``:
.. code-block:: json
{
"role": "todo_user",
"exp": 123456789
}
.. code-block:: bash
exp=$(( EPOCHSECONDS + 5*60 )) # five minutes
echo $exp
Go back to :ref:`tut1_step3` and change the payload to
.. code-block:: bash
payload=$(echo -n "{\"role\":\"todo_user\",\"exp\":\"123456789\"}" | _base64)
echo -n "$header.$payload.$signature"
**NOTE**: Don't forget to change the dummy epoch value :code:`123456789` in the snippet above to the epoch value returned by the :code:`psql` command.
Generated
+3 -3
View File
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1731165248,
"narHash": "sha256-DiHFKIdBmMx5/DUARhVqaxvEIiy4EE6Eqs9Qs4oxme8=",
"lastModified": 1776949667,
"narHash": "sha256-GMSVw35Q+294GlrTUKlx087E31z7KurReQ1YHSKp5iw=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a90280100f41a10914edfe729a4053e60c92b8e3",
"rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30",
"type": "github"
},
"original": {
+7 -3
View File
@@ -33,8 +33,8 @@
in
{
packages = genSystems (attrs: {
default = attrs.postgrestPackage;
profiled = attrs.postgrestProfiled;
default = attrs.postgrestPackage.bin;
profiled = attrs.postgrestProfiled.bin;
} // nixpkgs.lib.optionalAttrs (attrs ? postgrestStatic) {
static = attrs.postgrestStatic;
});
@@ -42,9 +42,13 @@
apps = genSystems (attrs: {
default = {
type = "app";
program = "${attrs.postgrestStatic or attrs.postgrestPackage}/bin/postgrest";
program = "${attrs.postgrestStatic or attrs.postgrestPackage.bin}/bin/postgrest";
meta.description = "REST API for any Postgres database";
};
});
devShells = genSystems (postgrest: {
default = import ./shell.nix { inherit postgrest; };
});
};
}
+15 -15
View File
@@ -72,9 +72,10 @@ The PostgREST utilities available in `nix-shell` all have names that begin with
```bash
# Note: The utilities listed here might not be up to date.
[nix-shell]$ postgrest-<tab>
postgrest-build postgrest-profiled-run
postgrest-check postgrest-push-cachix
postgrest-clean postgrest-release
postgrest-build postgrest-parallel-curl
postgrest-check postgrest-profiled-run
postgrest-clean postgrest-push-cachix
postgrest-commitlint postgrest-release
postgrest-coverage postgrest-repl
postgrest-coverage-draft-overlay postgrest-run
postgrest-docs-build postgrest-style
@@ -90,15 +91,14 @@ postgrest-gen-ctags postgrest-watch
postgrest-gen-jwt postgrest-with-all
postgrest-gen-secret postgrest-with-git
postgrest-git-hooks postgrest-with-pgrst
postgrest-hsie-graph-modules postgrest-with-postgresql-12
postgrest-hsie-graph-symbols postgrest-with-postgresql-13
postgrest-hsie-minimal-imports postgrest-with-postgresql-14
postgrest-lint postgrest-with-postgresql-15
postgrest-loadtest postgrest-with-postgresql-16
postgrest-loadtest-against postgrest-with-postgresql-17
postgrest-loadtest-report postgrest-with-slow-pg
postgrest-nixpkgs-upgrade postgrest-with-slow-postgrest
postgrest-parallel-curl
postgrest-hsie-graph-modules postgrest-with-pg-14
postgrest-hsie-graph-symbols postgrest-with-pg-15
postgrest-hsie-minimal-imports postgrest-with-pg-16
postgrest-lint postgrest-with-pg-17
postgrest-loadtest postgrest-with-pg-18
postgrest-loadtest-against postgrest-with-slow-pg
postgrest-loadtest-report postgrest-with-slow-postgrest
postgrest-nixpkgs-upgrade
...
[nix-shell]$
@@ -174,7 +174,7 @@ $ nix-shell --run "postgrest-with-all postgrest-test-spec"
# Run the tests against a specific version of PostgreSQL (use tab-completion in
# nix-shell to see all available versions):
$ nix-shell --run "postgrest-with-postgresql-13 postgrest-test-spec"
$ nix-shell --run "postgrest-with-pg-17 postgrest-test-spec"
```
@@ -284,7 +284,7 @@ Tools like `postgrest-build`, `postgrest-run`, `postgrest-repl` etc. are simple
also run in CI, with the exception of the IO and Memory checks that need to be run
separately.
`postgrest-with-postgresql-*` take a command as an argument and will run it
`postgrest-with-pg-*` take a command as an argument and will run it
with a temporary database. `postgrest-with-all` will run the command against
all supported PostgreSQL versions. Tests run without `postgrest-with-*` are
run against the latest PostgreSQL version by default.
@@ -380,7 +380,7 @@ that).
We also use `default.nix` to load our pinned version of the `nixpkgs`
repository. This set of packages will always be the same, independently from
where or when you use it. The pinned version is taken from `flake.lock` and
can be updated with `nix flake update`.
can be updated with `postgrest-nixpkgs-upgrade`.
### `shell.nix`
+6 -24
View File
@@ -16,11 +16,8 @@ The following checklist guides you through the complete process in more detail.
## Upgrade the pinned version of `nixpkgs`
The pinned version of [`nixpkgs`](https://github.com/NixOS/nixpkgs) is defined
in [`nix/nixpkgs-version.nix`](nixpkgs-version.nix). The pin refers directly to
a GitHub tarball for the given revision, which is more efficient than pulling
the complete Git repository. To upgrade it to the current `main` of
`nixpkgs`, you can use a small utility script defined in
[`nix/nixpkgs-update.nix`](nixpkgs-update.nix):
in [`flake.nix`](../flake.nix). To upgrade it, you can use a small utility
script defined in [`nix/tools/nixpkgsTools.nix`](tools/nixpkgsTools.nix):
```bash
# From the root of the repository, enter nix-shell
@@ -30,21 +27,12 @@ nix-shell
postgrest-nixpkgs-upgrade
# Exit the nix-shell with Ctrl-d
```
## Review overlays
Check whether the individual [overlays](overlays) are still required.
## Check if patches are still required and update them as needed
We track a number of PostgREST-specific patches in [`nix/patches`](patches).
Check whether the pull-requests/issues linked in the
[`default.nix`](patches/default.nix) have progressed and remove/modify the
patches if they did. If conflicting changes occurred, you might have to rebase
the respective patches.
## Build everything
Using the PostgREST binary Nix cache is recommended. Install
@@ -58,25 +46,19 @@ errors, this is probably due to one of our patches. Try to fix them and re-run
## Update the PostgREST binary cache
If you have access to the PostgREST cachix signing key, you can push the
If you have access to the PostgREST cachix project, you can push the
artifacts that you built locally to the binary cache. This will accelerate the
CI builds and tests, sometimes dramatically. This might sometimes even be
required to avoid build timeouts in CI.
You'll need to set the `CACHIX_SIGNING_KEY` before proceeding, e.g. by creating
a file containing `export CACHIX_SIGNING_KEY=...` and sourcing that file, which
avoids having the secret in your shell history.
You'll need to login with your token with `cachix authtoken <token>`.
To push all new artifacts to Cachix, run:
```
nix-store -qR --include-outputs $$(nix-instantiate) | cachix push postgrest
# Or, equivalently
nix-shell --run postgrest-push-cachix
```
The `nix-store` command will query the nix-store to list all dependencies and
build artifacts of PostgREST. The `cachix` command will efficiently push
The `postgrest-push-cachix` command will query the nix-store to list all
dependencies and build artifacts of PostgREST. It will then push
everything that is not yet cached to the binary cache.
+20 -7
View File
@@ -4,6 +4,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
-- | Haskell Imports and Exports tool
@@ -33,13 +34,16 @@ import Data.Function ((&))
import Data.List (intercalate)
import Data.Maybe (catMaybes, mapMaybe)
import Data.Text (Text)
import GHC.Driver.Errors.Types (GhcMessage)
import GHC.Generics (Generic)
import GHC.Hs.Extension (GhcPs)
import GHC.Types.Error (getMessages)
import GHC.Types.Error (Messages, defaultDiagnosticOpts,
getMessages)
import GHC.Types.Name.Occurrence (occNameString)
import GHC.Types.Name.Reader (rdrNameOcc)
import GHC.Unit.Module.Name (moduleNameString)
import GHC.Unit.Module (moduleNameString)
import GHC.Utils.Error (pprMsgEnvelopeBagWithLoc)
import GHC.Utils.Outputable (showSDocUnsafe)
import System.Directory.Recursive (getFilesRecursive)
import System.Exit (exitFailure)
@@ -198,7 +202,7 @@ sourceSymbols source = do
return $ concatMap (importSymbols source filepath . GHC.unLoc) hsmodImports
-- | Parse a Haskell module
parseModule :: FilePath -> IO GHC.HsModule
parseModule :: FilePath -> IO (GHC.HsModule GhcPs)
parseModule filepath = do
result <- ExactPrint.parseModule GHC.Paths.libdir filepath
case result of
@@ -206,7 +210,13 @@ parseModule filepath = do
return $ GHC.unLoc hsmod
Left errs ->
fail $ "Errors with " <> show filepath <> ":\n "
<> show (pprMsgEnvelopeBagWithLoc $ getMessages errs)
<> formatParseErrors errs
formatParseErrors :: Messages GhcMessage -> String
formatParseErrors errs =
intercalate "\n "
. fmap showSDocUnsafe
$ pprMsgEnvelopeBagWithLoc (defaultDiagnosticOpts @GhcMessage) (getMessages errs)
-- | Symbols imported in an import declaration.
--
@@ -214,9 +224,12 @@ parseModule filepath = do
-- only one item is returned.
importSymbols :: FilePath -> FilePath -> GHC.ImportDecl GhcPs -> [ImportedSymbol]
importSymbols source filepath GHC.ImportDecl{..} =
case ideclHiding of
Just (hiding, syms) ->
symbol (if hiding then Hiding else Explicit) . Just . GHC.unLoc <$> GHC.unLoc syms
case ideclImportList of
Just (importListInterpretation, syms) ->
symbol (if importListInterpretation == GHC.EverythingBut then Hiding else Explicit)
. Just
. GHC.unLoc
<$> GHC.unLoc syms
Nothing ->
[ symbol Wildcard Nothing ]
where
-61
View File
@@ -1,61 +0,0 @@
# Creating a separate libpq package is is discussed in
# https://github.com/NixOS/nixpkgs/issues/61580, but nixpkgs has not moved
# forward, yet.
# This package is passed to postgresql-libpq (haskell) which needs to be
# cross-compiled to the static build and possibly other architectures as
# as well. To reduce the number of dependencies that need to be built with
# it, this derivation focuses on building the client libraries only. No
# server, no tests.
{ stdenv
, lib
, openssl
, zlib
, postgresql
, pkg-config
, tzdata
}:
stdenv.mkDerivation {
pname = "libpq";
inherit (postgresql) src version patches;
__structuredAttrs = true;
env.CFLAGS = "-fdata-sections -ffunction-sections"
+ (if stdenv.cc.isClang then " -flto" else " -fmerge-constants -Wl,--gc-sections");
configureFlags = [
"--without-gssapi"
"--without-icu"
"--without-readline"
"--with-openssl"
"--with-system-tzdata=${tzdata}/share/zoneinfo"
"--sysconfdir=/etc/postgresql"
];
nativeBuildInputs = [ pkg-config tzdata ];
buildInputs = [ openssl zlib ];
buildFlags = [ "submake-libpq" "submake-libpgport" ];
installPhase = ''
runHook preInstall
make -C src/bin/pg_config install
make -C src/common install
make -C src/include install
make -C src/interfaces/libpq install
make -C src/port install
rm -rfv $out/share
runHook postInstall
'';
outputs = [ "out" ];
meta = with lib; {
homepage = "https://www.postgresql.org";
description = "Client API library for PostgreSQL";
license = licenses.postgresql;
};
}
@@ -6,6 +6,7 @@
, coreutils
, git
, lib
, moreutils
, runCommand
, shellcheck
, stdenv
@@ -56,7 +57,7 @@ let
# Example: This way `postgrest-watch -h` will return the help output for watch, while
# `postgrest-watch postgrest-test-spec -h` will return the help output for test-spec.
# Taken from: https://github.com/matejak/argbash/issues/114#issuecomment-557108274
sed '/_positionals_count + 1/a\\t\t\t\tset -- "''${@:1:1}" "--" "''${@:2}"' -i $out
sed '/_positionals_count + 1/a\\t\t\t\tset -- "''${@:1:1}" "--" "''${@:2}"' $out | ${moreutils}/bin/sponge $out
'';
bash-completion =
@@ -66,7 +67,7 @@ let
''
+ lib.optionalString (positionalCompletion != "") ''
sed 's#COMPREPLY.*compgen -o bashdefault .*$#${escape positionalCompletion}#' -i $out
sed 's#COMPREPLY.*compgen -o bashdefault .*$#${escape positionalCompletion}#' $out | ${moreutils}/bin/sponge $out
''
);
@@ -103,8 +104,7 @@ let
''
+ lib.optionalString withTmpDir ''
mkdir -p "''${TMPDIR:-/tmp}/postgrest"
tmpdir="$(${coreutils}/bin/mktemp -d --tmpdir postgrest/${name}-XXX)"
tmpdir="$(${coreutils}/bin/mktemp -d --tmpdir=/tmp ${name}-XXX)"
# we keep the tmpdir when an error occurs for debugging
trap 'echo Temporary directory kept at: $tmpdir' ERR
-2
View File
@@ -3,6 +3,4 @@
checked-shell-script = import ./checked-shell-script;
gitignore = import ./gitignore.nix;
haskell-packages = import ./haskell-packages.nix;
postgresql-libpq = import ./postgresql-libpq.nix;
slocat = import ./slocat.nix;
}
+32 -26
View File
@@ -47,37 +47,43 @@ let
# - To modify and try packages locally, see "Working with locally modified Haskell packages" in the Nix README.
# Before upgrading fuzzyset to 0.3, check: https://github.com/PostgREST/postgrest/issues/3329
# jailbreak, because hspec limit for tests
fuzzyset = prev.fuzzyset_0_2_4;
hasql-pool = lib.dontCheck (prev.callHackageDirect
{
pkg = "hasql-pool";
ver = "1.0.1";
sha256 = "sha256-Hf1f7lX0LWkjrb25SDBovCYPRdmUP1H6pAxzi7kT4Gg=";
}
{ });
http2 =
prev.callHackageDirect
{
pkg = "http2";
ver = "5.4.0";
sha256 = "sha256-PeEWVd61bQ8G7LvfLeXklzXqNJFaAjE2ecRMWJZESPE=";
}
{ };
hasql-notifications = lib.dontCheck (prev.callHackageDirect
{
pkg = "hasql-notifications";
ver = "0.2.2.2";
sha256 = "sha256-myKwlug7OgTa/qP6mHfCD+5Q8IhM17JvpJBfSo+M01k=";
}
{ });
http-semantics =
prev.callHackageDirect
{
pkg = "http-semantics";
ver = "0.4.0";
sha256 = "sha256-rh0z51EKvsu5rQd5n2z3fSRjjEObouNZSBPO9NFYOF0=";
}
{ };
# newer nixpkgs already has 0.10., so we fallback to default for forward compat
jose-jwt = prev.jose-jwt_0_10_0 or prev.jose-jwt;
network-run =
prev.callHackageDirect
{
pkg = "network-run";
ver = "0.5.0";
sha256 = "sha256-vbXh+CzxDsGApjqHxCYf/ijpZtUCApFbkcF5gyN0THU=";
}
{ };
postgresql-libpq = lib.dontCheck (prev.callHackageDirect
{
pkg = "postgresql-libpq";
ver = "0.10.1.0";
sha256 = "sha256-tXOMqCO8opMilI9rx0D+njqjIjbZsH168Bzb8Aq8Ff4=";
}
{
postgresql = super.libpq;
});
warp =
lib.dontCheck (prev.callHackageDirect
{
pkg = "warp";
ver = "3.4.13";
sha256 = "sha256-jmr8kpeSPDkOhT0i9PhozZapX4nUs92cOX7POAGb7/M=";
}
{ });
};
in
{
-7
View File
@@ -1,7 +0,0 @@
_: super:
{
# Depending on which nixpkgs version is pinned, libpq might either be available already - or not.
libpq = super.libpq or (super.callPackage ../libpq.nix {
postgresql = super.postgresql_16;
});
}
-13
View File
@@ -1,13 +0,0 @@
_: prev:
{
slocat = prev.buildGoModule {
name = "slocat";
src = prev.fetchFromGitHub {
owner = "robx";
repo = "slocat";
rev = "52e7512c6029fd00483e41ccce260a3b4b9b3b64";
sha256 = "sha256-qn6luuh5wqREu3s8RfuMCP5PKdS2WdwPrujRYTpfzQ8=";
};
vendorHash = null;
};
}
+13 -53
View File
@@ -8,65 +8,25 @@ let
inherit (pkgs) pkgsStatic;
inherit (pkgsStatic.haskell) lib;
packagesStatic =
pkgsStatic.haskell.packages."${compiler}".override (old: {
ghc = pkgsStatic.pkgsBuildHost.haskell.compiler."${compiler}".override {
# Using the bundled libffi generally works better for cross-compiling
libffi = null;
# Building sphinx fails on some platforms
enableDocs = false;
# Cross compiling with native bignum works better than with gmp
enableNativeBignum = true;
};
overrides = pkgs.lib.composeExtensions old.overrides (_: prev: {
postgresql-libpq = (lib.overrideCabal prev.postgresql-libpq {
# TODO: This section can be simplified when this PR has made it's way to us:
# https://github.com/NixOS/nixpkgs/pull/286370
# Additionally, we need to use the default version in nixpkgs, otherwise the
# override will not be active as well.
# Using use-pkg-config flag, because pg_config won't work when cross-compiling
configureFlags = [ "-fuse-pkg-config" ];
# postgresql doesn't build in the fully static overlay - but the default
# derivation is built with static libraries anyway.
libraryPkgconfigDepends = [ pkgsStatic.libpq ];
librarySystemDepends = [ ];
}).overrideAttrs (_: prevAttrs: {
buildInputs = prevAttrs.buildInputs ++ [ pkgsStatic.openssl ];
});
});
});
packagesStatic = pkgsStatic.haskell.packages.native-bignum."${compiler}";
makeExecutableStatic = drv: pkgs.lib.pipe drv [
lib.compose.justStaticExecutables
# To successfully compile a redistributable, fully static executable we need to:
# 1. make executable really statically linked.
# 2. avoid any references to /nix/store to prevent blowing up the closure size.
# 3. be able to run the executable.
# When checking for references, we ignore the following:
# - eeee... are removed references which don't actually exist
# - openssl-etc references are purposely designed to be very small
(lib.compose.overrideCabal (drv: {
postFixup = drv.postFixup + ''
exe="$out/bin/postgrest"
# 1. avoid any references to /nix/store to prevent blowing up the closure size.
(drv: drv.overrideAttrs {
allowedReferences = [
pkgsStatic.openssl.etc
];
})
if ! (file "$exe" | grep 'statically linked') then
echo "not a static executable, ldd output:"
ldd "$exe"
exit 1
fi
echo "Checking for references to /nix/store..."
(${pkgsStatic.binutils}/bin/strings "$exe" \
| grep -v /nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee \
| grep -v -etc/etc/ssl \
| grep /nix/store || exit 0 && exit 1)
echo "No references to /nix/store found"
"$exe" --help
'';
}))
# 2. be able to run the executable.
(drv: drv.overrideAttrs {
passthru.tests.version = pkgsStatic.testers.testVersion {
package = drv;
};
})
];
in
+16 -5
View File
@@ -15,7 +15,6 @@ let
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-update
exec ${cabal-install}/bin/cabal v2-build ${devCabalOptions} "''${_arg_leftovers[@]}"
'';
@@ -34,6 +33,17 @@ let
exec ${cabal-install}/bin/cabal v2-clean
'';
update =
checkedShellScript
{
name = "postgrest-cabal-update";
docs = "Update cabal's package list from hackage.haskell.org";
workingDir = "/";
}
''
exec ${cabal-install}/bin/cabal v2-update
'';
run =
checkedShellScript
{
@@ -45,6 +55,7 @@ let
"ARG_USE_ENV([PGRST_DB_POOL], [1], [PostgREST pool size])"
"ARG_USE_ENV([PGRST_DB_POOL_ACQUISITION_TIMEOUT], [1], [PostgREST pool timeout])"
"ARG_USE_ENV([PGRST_JWT_SECRET], [reallyreallyreallyreallyverysafe], [PostgREST JWT secret])"
"ARG_USE_ENV([PGRST_ADMIN_SERVER_PORT], [3001], [PostgREST admin server port])"
"ARG_LEFTOVERS([PostgREST arguments])"
];
workingDir = "/";
@@ -55,6 +66,7 @@ let
export PGRST_DB_POOL
export PGRST_DB_POOL_ACQUISITION_TIMEOUT
export PGRST_JWT_SECRET
export PGRST_ADMIN_SERVER_PORT
exec ${cabal-install}/bin/cabal v2-run ${devCabalOptions} --verbose=0 -- \
postgrest "''${_arg_leftovers[@]}"
@@ -83,10 +95,8 @@ let
export PGRST_DB_POOL_ACQUISITION_TIMEOUT
export PGRST_JWT_SECRET
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal --builddir="dist-prof" v2-build --enable-profiling --disable-shared exe:postgrest
${cabal-install}/bin/cabal --builddir="dist-prof" v2-run -- \
postgrest +RTS -p -h -RTS "''${_arg_leftovers[@]}"
exec ${cabal-install}/bin/cabal --builddir="dist-prof" v2-run --enable-profiling --disable-shared exe:postgrest -- \
+RTS -p -h -RTS "''${_arg_leftovers[@]}"
'';
repl =
@@ -109,6 +119,7 @@ buildToolbox
inherit
build
clean
update
run
runProfiled
repl;
+10 -5
View File
@@ -10,6 +10,7 @@
, hsie
, nix
, silver-searcher
, stdenv
, style
, tests
, withTools
@@ -53,10 +54,14 @@ let
Requires authentication with `cachix authtoken ...`.
'';
args =
[
"ARG_OPTIONAL_SINGLE([system], , [System], [${stdenv.system}])"
];
workingDir = "/";
}
''
${nix}/bin/nix-instantiate \
${nix}/bin/nix-instantiate --argstr system "$_arg_system" \
| xargs ${nix}/bin/nix-store -qR --include-outputs \
| ${cachix}/bin/cachix push postgrest
'';
@@ -77,6 +82,7 @@ let
}
''
${tests}/bin/postgrest-test-spec
${tests}/bin/postgrest-test-observability
${tests}/bin/postgrest-test-doctests
${tests}/bin/postgrest-test-io
${tests}/bin/postgrest-test-big-schema
@@ -166,7 +172,7 @@ let
# The following unsets all GIT_ variables.
unset "''${!GIT_@}"
# shellcheck disable=SC2317
# shellcheck disable=SC2329
function restore () {
ref="$(git stash list --format=format:%gD --grep "$1" -n1)"
# this will avoid merge conflicts when applying the stash
@@ -199,7 +205,7 @@ let
${git}/bin/git add .
;;
pre-push)
# Create a clean working tree without any uncomitted changes.
# Create a clean working tree without any uncommitted changes.
${withTools.withGit} HEAD ${style}/bin/postgrest-lint
;;
esac
@@ -226,7 +232,7 @@ let
${style}/bin/postgrest-lint
;;
pre-push)
# Create a clean working tree without any uncomitted changes.
# Create a clean working tree without any uncommitted changes.
${withTools.withGit} HEAD ${check}
;;
esac
@@ -246,7 +252,6 @@ let
}
''
mkdir -p "$_arg_dumpdir"
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal v2-build ${devCabalOptions} \
--builddir="$tmpdir" \
--ghc-option=-ddump-minimal-imports \
+11 -2
View File
@@ -35,12 +35,15 @@ let
workingDir = "/docs";
}
''
# https://github.com/sphinx-doc/sphinx/issues/11739
export LC_ALL=C
function build() {
${python}/bin/sphinx-build --color -W -a -n . -b "$@"
}
if [ "$_arg_language" == "" ]; then
# clean previous build, otherwise some errors might be supressed
# clean previous build, otherwise some errors might be suppressed
rm -rf "../.docs-build/html/default"
if [ -d languages ]; then
@@ -51,7 +54,7 @@ let
build html "../.docs-build/html/default"
else
# clean previous build, otherwise some errors might be supressed
# clean previous build, otherwise some errors might be suppressed
rm -rf "../.docs-build/html/$_arg_language"
# update and build specific locale, can be used to create new locale
@@ -119,6 +122,8 @@ let
workingDir = "/docs";
}
''
export LC_ALL=C
FILES=$(find . -type f -iname '*.rst' | tr '\n' ' ')
# shellcheck disable=SC2086 disable=SC2016
@@ -139,6 +144,8 @@ let
workingDir = "/docs";
}
''
export LC_ALL=C
FILES=$(find . -type f -iname '*.rst' | tr '\n' ' ')
tail -n+2 postgrest.dict \
@@ -157,6 +164,8 @@ let
workingDir = "/docs";
}
''
export LC_ALL=C
${python}/bin/sphinx-build --color -b linkcheck . ../.docs-build
'';
+52
View File
@@ -0,0 +1,52 @@
# Generate RSA JWK/public material for loadtests.
import argparse
import sys
from pathlib import Path
import jwcrypto.jwk as jwk
def main():
parser = argparse.ArgumentParser(
description="Generate RSA JWK/private key pair for loadtests"
)
parser.add_argument(
"--rsa",
dest="jwk_path",
metavar="JWK_PATH",
type=Path,
required=True,
help="Path to write the RSA JWK file",
)
parser.add_argument(
"--private-key",
dest="private_key_path",
metavar="PRIVATE_KEY_PATH",
type=Path,
required=True,
help="Path to write the RSA private key file",
)
args = parser.parse_args()
key = jwk.JWK.generate(kty="RSA", size=4096)
private_jwk, public_jwk = key.export_private(), key.export_public()
try:
args.jwk_path.write_text(public_jwk)
print(f"Created RSA JWK on {args.jwk_path}")
except OSError as e:
print(f"Error writing to {args.jwk_path}:{e}", file=sys.stderr)
sys.exit(1)
try:
args.private_key_path.write_text(private_jwk)
print(f"Created private key on {args.private_key_path}")
except OSError as e:
print(f"Error writing to {args.private_key_path}:{e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
+184 -51
View File
@@ -1,63 +1,92 @@
# generates a file to be used by the vegeta load testing tool
# It includes a worst case scenario for the JWT cache:
# - all requests will have a unique JWT so no cache hits
# - all jwts have an expiration that will be long enough to be
# valid at time of request but short enough that already
# validated jwts will expire later during the loadtest run
# - the above guarantees JWT cache purging will happen
# - we want this to track resource consumption in the worst case
# And a more normal scenario where non-expiring JWTs are picked
# from an array
import time
import hmac
import hashlib
import base64
import json
import argparse
import subprocess
import sys
import random
import jwt
from typing import Optional
from pathlib import Path
from enum import Enum
SECRET = b"reallyreallyreallyreallyverysafe"
URL = "http://postgrest"
JWT_DURATION = 120
TOTAL_TARGETS = 50000 # tuned by hand to reduce result variance
secret_key = b"reallyreallyreallyreallyverysafe"
def base64url_encode(data: bytes) -> str:
"""URL-safe Base64 encode without padding."""
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")
def generate_jwt(exp_inc: int) -> str:
"""Generate an HS256 JWT"""
# Header & payload
header = {"alg": "HS256", "typ": "JWT"}
now = int(time.time())
def generate_jwt(
now: int,
exp_inc: Optional[int],
rsa_private_key: Optional[jwt.algorithms.RSAAlgorithm],
) -> str:
"""Generate an HS256 or RS256 JWT"""
payload = {
"sub": f"user_{random.getrandbits(32)}",
"iat": now,
"exp": now + exp_inc,
"role": "postgrest_test_author",
}
# Encode to JSON and then to Base64URL
header_b = json.dumps(header, separators=(",", ":")).encode()
payload_b = json.dumps(payload, separators=(",", ":")).encode()
header_b64 = base64url_encode(header_b)
payload_b64 = base64url_encode(payload_b)
if exp_inc is not None:
payload["exp"] = now + exp_inc
# Sign (HMACSHA256) the "<header>.<payload>" string
signing_input = f"{header_b64}.{payload_b64}".encode()
signature = hmac.new(SECRET, signing_input, hashlib.sha256).digest()
signature_b64 = base64url_encode(signature)
return f"{header_b64}.{payload_b64}.{signature_b64}"
if rsa_private_key is None:
key = secret_key
alg = "HS256"
else:
key = rsa_private_key
alg = "RS256"
return jwt.encode(payload, key, alg)
# We want to ensure 401 Unauthorized responses don't happen during
# JWT validation, this can happen when the jwt `exp` is too short.
# At the same time, we want to ensure the `exp` is not too big,
# so expires will occur and postgREST will have to clean cached expired JWTs.
def estimate_adequate_jwt_exp_increase(iteration: int) -> int:
# estimated time takes to build and run postgrest itself
build_run_postgrest_time = 2
# estimated time it takes to generate the targets file
file_generation_time = TOTAL_TARGETS // (10**-5)
# estimated exp time so some JWTs will expire
dynamic_exp_inc = iteration // 1000
HTTP_METHODS = (
"GET",
"OPTIONS",
)
return build_run_postgrest_time + file_generation_time + dynamic_exp_inc
HttpMethod = Enum(
"HttpMethod",
{method: method for method in HTTP_METHODS},
type=str,
module=__name__,
)
def append_targets(lines: list[str], token: str, http_method: HttpMethod):
lines.append(f"{http_method.value} {URL}/authors_only")
lines.append(f"Authorization: Bearer {token}")
lines.append("") # blank line to separate requests
# we use this to chain commands on loadtest.nix
def run_command(command: list[str]):
if not command:
return
if command[0] == "--":
command = command[1:]
if not command:
return
try:
subprocess.run(command, check=True)
except subprocess.CalledProcessError as exc:
print(
f"Error executing command {' '.join(command)}: {exc}",
file=sys.stderr,
)
sys.exit(exc.returncode)
def main():
@@ -65,29 +94,133 @@ def main():
description="Generate Vegeta targets with unique JWTs"
)
parser.add_argument(
"output",
"targets_path",
metavar="TARGETS_PATH",
help="Path to write the generated targets file",
)
parser.add_argument(
"--private-key",
dest="private_key_path",
metavar="PRIVATE_KEY_PATH",
type=Path,
default=None,
help="Path to the RSA private key file (required when --rsa is used)",
)
parser.add_argument(
"--worst",
dest="worst",
action=argparse.BooleanOptionalAction,
default=False,
help="Generate worst case targets for a JWT cache",
)
parser.add_argument(
"--rsa",
dest="jwk_path",
metavar="JWK_PATH",
type=Path,
default=None,
help="Path to an existing RSA JWK file used for signing tokens",
)
parser.add_argument(
"--method",
dest="http_method",
choices=list(HTTP_METHODS),
required=True,
help="HTTP method for the vegeta targets",
)
parser.add_argument(
"command",
nargs=argparse.REMAINDER,
help="Command (and arguments) to run after generating the targets",
)
args = parser.parse_args()
lines = []
rsa_private_key: Optional[jwt.algorithms.RSAAlgorithm] = None
is_hs = args.jwk_path is None
http_method = HttpMethod(args.http_method)
nsamples = 1000
if is_hs:
ntargets = 200000
else:
# The asymmetric targets take too long to compute so we reduce them
ntargets = 50000
if not is_hs:
if args.private_key_path is None:
parser.error("--rsa requires the --private-key option")
try:
private_key_data = args.private_key_path.read_text()
except OSError as e:
err = (
f"Error reading RSA private key from {args.private_key_path}: "
f"{e}. Generate RSA materials first with gen_rsa_materials.py."
)
print(err, file=sys.stderr)
sys.exit(1)
try:
rsa_private_key = jwt.algorithms.RSAAlgorithm.from_jwk(private_key_data)
except Exception as exc: # broad exception to capture parsing errors
err = (
f"Error loading RSA private key from {args.private_key_path}: " f"{exc}"
)
print(err, file=sys.stderr)
sys.exit(1)
print(f"Generating {ntargets} targets...")
start_time = time.time()
for i in range(TOTAL_TARGETS):
token = generate_jwt(estimate_adequate_jwt_exp_increase(i))
lines.append(f"OPTIONS {URL}/authors_only")
lines.append(f"Authorization: Bearer {token}")
lines.append("") # blank line to separate requests
now = int(start_time)
lines = []
# We want to ensure 401 Unauthorized responses don't happen during
# JWT validation, this can happen when the jwt `exp` is too short.
# At the same time, we want to ensure the `exp` is not too big,
# so expires will occur and postgREST needs to
# clean cached expired JWTs
if args.worst:
# estimated time takes to build and run postgrest itself
build_run_postgrest_time = 2
# estimated time it takes to generate the targets file
# the division numbers are tuned by hand
if is_hs: # hs generation is much faster
gen_time = ntargets // 66666
else: # asymmetric is slower so the time is higher
gen_time = ntargets // 220
# estimated exp time so some JWTs will expire
inc = build_run_postgrest_time + gen_time
for i in range(ntargets):
token = generate_jwt(now, inc + i // 1000, rsa_private_key)
append_targets(lines, token, http_method)
else:
tokens = [generate_jwt(now, None, rsa_private_key) for _ in range(nsamples)]
for i in range(ntargets):
token = random.choice(tokens)
append_targets(lines, token, http_method)
try:
with open(args.output, "w") as f:
with open(args.targets_path, "w") as f:
f.write("\n".join(lines))
except IOError as e:
print(f"Error writing to {args.output}: {e}", file=sys.stderr)
print(f"Error writing to {args.targets_path}: {e}", file=sys.stderr)
sys.exit(1)
elapsed = time.time() - start_time
print(f"Created {TOTAL_TARGETS} targets in {args.output} ({elapsed:.2f}s)")
print(f"Created {ntargets} targets", end=" ")
print(f"in {args.targets_path} ({elapsed:.2f}s)")
run_command(args.command)
if __name__ == "__main__":
+60
View File
@@ -0,0 +1,60 @@
{ buildToolbox
, checkedShellScript
, commitlint
, writeText
}:
let
# Rules format: [<severity>, <"always"/"never">, <value>]
commitlintConfig = writeText "commitlint.config.mjs" ''
export default {
rules: {
"type-enum": [2, "always", [
'add', // Add a new feature
'amend', // To amend an unrealease commit
'change', // Breaking changes
'chore', // Update sponsors, changelog, readme etc
'ci', // CI configuration files and scripts
'docs', // Documentation
'fix', // Bug fix
'nix', // Related to Nix
'perf', // Performance improvements
'refactor', // Refactoring code
'remove', // Remove a feature or fix
'test', // Adding tests
]],
'subject-case': [2, 'never', ['pascal-case', 'start-case']],
'subject-empty': [2, 'never'],
'subject-full-stop': [2, 'never', '.'],
'subject-max-length': [2, 'always', 80],
'subject-min-length': [2, 'always', 5],
'scope-case': [2, 'always', 'lower-case'],
'body-leading-blank': [2, 'always'],
},
};
'';
commitCheck =
checkedShellScript
{
name = "postgrest-commitlint";
docs = "Script to validate commit messages";
workingDir = "/";
args = [
"ARG_OPTIONAL_SINGLE([from],, [commit ref start from], [main])"
"ARG_OPTIONAL_SINGLE([to],, [commit ref end at], [HEAD])"
];
}
''
# Run commitlint with the given configuration
${commitlint}/bin/commitlint --config ${commitlintConfig} --from "$_arg_from" --to "$_arg_to"
'';
in
buildToolbox
{
name = "postgrest-commitlint";
tools = { inherit commitCheck; };
}
+155 -20
View File
@@ -18,6 +18,8 @@ let
];
}
''
echo "Starting vegeta loadtest..."
# ARG_USE_ENV only adds defaults or docs for environment variables
# We manually implement a required check here
# See also: https://github.com/matejak/argbash/issues/80
@@ -41,8 +43,11 @@ let
args = [
"ARG_OPTIONAL_SINGLE([output], [o], [Filename to dump json output to], [./loadtest/result.bin])"
"ARG_OPTIONAL_SINGLE([testdir], [t], [Directory to load tests and fixtures from], [./test/load])"
"ARG_OPTIONAL_SINGLE([kind], [k], [Kind of loadtest (mixed: repeat mixed requests, jwt: run once over many requests with unique jwts)], [mixed])"
"ARG_TYPE_GROUP_SET([KIND], [KIND], [kind], [mixed,jwt])"
"ARG_OPTIONAL_SINGLE([kind], [k], [Kind of loadtest], [mixed])"
"ARG_OPTIONAL_SINGLE([method],, [HTTP method used for the jwt loadtests], [OPTIONS])"
"ARG_TYPE_GROUP_SET([KIND], [KIND], [kind], [mixed,errors,jwt-hs,jwt-hs-cache,jwt-hs-cache-worst,jwt-rsa,jwt-rsa-cache,jwt-rsa-cache-worst])"
"ARG_TYPE_GROUP_SET([METHOD], [METHOD], [method], [OPTIONS,GET])"
"ARG_OPTIONAL_SINGLE([monitor], [m], [Monitoring file], [./loadtest/result.csv])"
"ARG_LEFTOVERS([additional vegeta arguments])"
];
workingDir = "/";
@@ -58,35 +63,127 @@ let
export PGRST_DB_TX_END="rollback-allow-override"
export PGRST_LOG_LEVEL="crit"
export PGRST_JWT_SECRET="reallyreallyreallyreallyverysafe"
export PGRST_JWT_CACHE_MAX_LIFETIME="86400"
mkdir -p "$(dirname "$_arg_output")"
abs_output="$(realpath "$_arg_output")"
case "$_arg_kind" in
jwt)
${genTargets} "$_arg_testdir"/gen_targets.http
jwt-hs)
export PGRST_JWT_CACHE_MAX_ENTRIES="0"
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withPgrst} \
sh -c "cd \"$_arg_testdir\" && ${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
${vegeta}/bin/vegeta report -type=text "$_arg_output"
${withTools.withPgrst} -m "$_arg_monitor" \
${withGenTargets} --method "$_arg_method" "$_arg_testdir"/gen_targets.http \
sh -c "cd \"$_arg_testdir\" && \
${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
;;
*)
jwt-hs-cache)
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withPgrst} -m "$_arg_monitor" \
${withGenTargets} --method "$_arg_method" "$_arg_testdir"/gen_targets.http \
sh -c "cd \"$_arg_testdir\" && \
${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
;;
jwt-hs-cache-worst)
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withPgrst} -m "$_arg_monitor" \
${withGenTargets} --method "$_arg_method" --worst "$_arg_testdir"/gen_targets.http \
sh -c "cd \"$_arg_testdir\" && \
${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
;;
jwt-rsa)
export PGRST_JWT_CACHE_MAX_ENTRIES="0"
${genRsaMaterials} --rsa="$_arg_testdir"/gen_jwk.json --private-key="$_arg_testdir"/gen_private.json
export PGRST_JWT_SECRET="@$_arg_testdir/gen_jwk.json"
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withSlowPg} \
${withTools.withPgrst} \
${withTools.withSlowPgrst} \
sh -c "cd \"$_arg_testdir\" && ${runner} -targets targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
${vegeta}/bin/vegeta report -type=text "$_arg_output"
${withTools.withPgrst} -m "$_arg_monitor" \
${withGenTargets} --method "$_arg_method" --rsa="$_arg_testdir"/gen_jwk.json --private-key="$_arg_testdir"/gen_private.json "$_arg_testdir"/gen_targets.http \
sh -c "cd \"$_arg_testdir\" && \
${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
;;
jwt-rsa-cache)
${genRsaMaterials} --rsa="$_arg_testdir"/gen_jwk.json --private-key="$_arg_testdir"/gen_private.json
export PGRST_JWT_SECRET="@$_arg_testdir/gen_jwk.json"
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withPgrst} -m "$_arg_monitor" \
${withGenTargets} --method "$_arg_method" --rsa="$_arg_testdir"/gen_jwk.json --private-key="$_arg_testdir"/gen_private.json "$_arg_testdir"/gen_targets.http \
sh -c "cd \"$_arg_testdir\" && \
${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
;;
jwt-rsa-cache-worst)
export PGRST_JWT_SECRET="@$_arg_testdir/gen_jwk.json"
${genRsaMaterials} --rsa="$_arg_testdir"/gen_jwk.json --private-key="$_arg_testdir"/gen_private.json
export PGRST_JWT_SECRET="@$_arg_testdir/gen_jwk.json"
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withPgrst} -m "$_arg_monitor" \
${withGenTargets} --method "$_arg_method" --worst --rsa="$_arg_testdir"/gen_jwk.json --private-key="$_arg_testdir"/gen_private.json "$_arg_testdir"/gen_targets.http \
sh -c "cd \"$_arg_testdir\" && \
${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
;;
mixed)
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withPgrst} -m "$_arg_monitor" \
sh -c "cd \"$_arg_testdir\" && \
${runner} -targets targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
;;
# here we sleep purposefully to check how much memory does the schema cache consume in the final report
errors)
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/errors.sql \
${withTools.withPgrst} --timeout 2 --sleep 5 -m "$_arg_monitor" \
sh -c "cd \"$_arg_testdir\" && \
${runner} -targets errors.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
;;
esac
${vegeta}/bin/vegeta report -type=text "$_arg_output"
if [ "$_arg_kind" != "errors" ]; then
# fail in case 401 happened on jwt loadtests
unauthorized_count="$(${vegeta}/bin/vegeta report -type=json "$_arg_output" \
| ${jq}/bin/jq -r '.status_codes["401"] // 0')"
if [ "$unauthorized_count" -gt 0 ]; then
last_unauthorized_body="$(${vegeta}/bin/vegeta encode "$_arg_output" \
| ${jq}/bin/jq -rn '
reduce inputs as $item (null;
if $item.code == 401 then $item else . end
)
| if . == null then
empty
else
(.body | @base64d)
end
')"
echo "loadtest failed: found $unauthorized_count 401 Unauthorized responses" >&2
if [ -n "$last_unauthorized_body" ]; then
printf '%s\n' "Last 401 response body:" >&2
printf '%s\n' "$last_unauthorized_body" >&2
fi
exit 1
fi
fi
'';
loadtestAgainst =
@@ -115,11 +212,12 @@ let
workingDir = "/";
}
''
# run loadtest for every target
for tgt in "''${_arg_target[@]}"; do
cat << EOF
Running loadtest on "$tgt"...
Running "$_arg_kind" loadtest on "$tgt"...
EOF
@@ -128,7 +226,7 @@ let
# Save the results in the current working tree, too,
# otherwise they'd be lost in the temporary working tree
# created by withTools.withGit.
${withTools.withGit} "$tgt" ${loadtest} -k "$_arg_kind" --output "$PWD/loadtest/$tgt.bin" --testdir "$PWD/test/load"
${withTools.withGit} "$tgt" ${loadtest} -k "$_arg_kind" -m "$PWD/loadtest/$tgt.csv" --output "$PWD/loadtest/$tgt.bin" --testdir "$PWD/test/load"
cat << EOF
@@ -138,13 +236,15 @@ let
done
# run loadtest once on HEAD
cat << EOF
Running loadtest on HEAD...
Running "$_arg_kind" loadtest on HEAD...
EOF
${loadtest} -k "$_arg_kind" --output "$PWD/loadtest/head.bin" --testdir "$PWD/test/load"
${loadtest} -k "$_arg_kind" -m "$PWD/loadtest/head.csv" --output "$PWD/loadtest/head.bin" --testdir "$PWD/test/load"
cat << EOF
@@ -181,6 +281,7 @@ let
pd.read_json(sys.stdin) \
.set_index('param') \
.drop(['branch', 'earliest', 'end', 'latest']) \
.fillna("") \
.convert_dtypes() \
.to_markdown(sys.stdout, floatfmt='.0f')
'';
@@ -191,16 +292,50 @@ let
{
name = "postgrest-loadtest-report";
docs = "Create a report of all loadtest reports as markdown.";
args = [
"ARG_OPTIONAL_SINGLE([group], [g], [Marker to group results])"
];
workingDir = "/";
}
''
marker=''${_arg_group:+"($_arg_group)"}
echo -e "## Loadtest results $marker\n"
find loadtest -type f -iname '*.bin' -exec ${reporter} {} \; \
| ${jq}/bin/jq '[paths(scalars) as $path | {param: $path | join("."), (.branch): getpath($path)}]' \
| ${jq}/bin/jq --slurp 'flatten | group_by(.param) | map(add)' \
| ${toMarkdown}
echo -e "\n\n## Loadtest elapsed seconds vs CPU/MEM usage $marker\n"
find loadtest -type f -iname '*.csv' \
| sort -m \
| ${mergeMonitorResults}
'';
genTargets = writers.writePython3 "postgrest-gen-loadtest-targets" { } (builtins.readFile ./generate_targets.py);
withGenTargets =
writers.writePython3 "postgrest-with-gen-loadtest-targets"
{
libraries = [ python3Packages.pyjwt python3Packages.jwcrypto ];
doCheck = false; # postgrest-style conflicts with this
}
(builtins.readFile ./generate_targets.py);
genRsaMaterials =
writers.writePython3 "postgrest-gen-rsa-materials"
{
libraries = [ python3Packages.jwcrypto ];
doCheck = false; # postgrest-style conflicts with this
}
(builtins.readFile ./gen_rsa_materials.py);
mergeMonitorResults =
writers.writePython3 "postgrest-merge-monitor-results"
{
libraries = [ python3Packages.pandas python3Packages.tabulate ];
}
(builtins.readFile ./merge_monitor_result.py);
in
buildToolbox {
name = "postgrest-loadtest";
+44
View File
@@ -0,0 +1,44 @@
import os
import sys
import pandas as pd
KEY = "Elapsed seconds"
BASE_METRICS = ["CPU (%)", "Real (MB)"]
branch_order = []
merged = None
paths = [p.strip() for p in sys.stdin.read().split() if p.strip()]
for csv_path in paths:
# br is branch (variable shortened to pass linter)
br = os.path.splitext(os.path.basename(csv_path))[0]
branch_order.append(br)
df = pd.read_csv(csv_path)
if KEY not in df.columns:
sys.exit(f"{csv_path} is missing the {KEY} column")
for m in BASE_METRICS:
if m not in df.columns:
sys.exit(f"Error: '{csv_path}' missing required column '{m}'.")
# add branch marker to every metric column
df = df.rename(columns={c: f"{c} [{br}]" for c in df.columns if c != KEY})
# outer join so missing rows appear
merged = df if merged is None else merged.merge(df, on=KEY, how="outer")
# Re-order columns so related metrics are adjacent
ordered_cols = [KEY]
for metric in BASE_METRICS:
for br in branch_order:
col_name = f"{metric} [{br}]"
if col_name in merged.columns:
ordered_cols.append(col_name)
merged = merged[ordered_cols]
# replace nan with empty string
merged = merged.fillna("")
merged.to_markdown(sys.stdout, index=False, tablefmt="github")
+57
View File
@@ -0,0 +1,57 @@
# Monitor a process pid with psutil and emits a CSV.
import sys
import time
import psutil
import pandas as pd
KEY = "Elapsed seconds"
BASE_METRICS = ["CPU (%)", "Real (MB)"]
SAMPLE_INTERVAL_SECS = 1
if len(sys.argv) != 2 or not sys.argv[1].isdigit():
sys.exit(f"Usage: {sys.argv[0]} <PID>")
pid = int(sys.argv[1])
try:
proc = psutil.Process(pid)
except psutil.NoSuchProcess:
sys.exit(f"Error: process {pid} not found.")
print(f"Starting monitoring of {pid} pid", file=sys.stderr)
records = []
start = time.time()
# ignore first result as per docs recommendation
# https://psutil.readthedocs.io/en/latest/#psutil.cpu_percent
proc.cpu_percent(None)
while True:
try:
if not proc.is_running():
break
time.sleep(SAMPLE_INTERVAL_SECS)
elapsed_secs = int(time.time() - start)
cpu = proc.cpu_percent(None)
meminfo = proc.memory_info()
bytes_in_MB = 1024**2
rss_mb = meminfo.rss / bytes_in_MB
records.append(
[
str(elapsed_secs),
f"{cpu:.3f}",
f"{rss_mb:.3f}",
]
)
except psutil.NoSuchProcess:
break
end = time.time()
total_time = end - start
print(f"Finished {pid} pid monitoring in {total_time:.3f}", file=sys.stderr)
cols = [KEY] + BASE_METRICS
df = pd.DataFrame(records, columns=cols, dtype=str)
df.to_csv(sys.stdout, index=False)
+28
View File
@@ -0,0 +1,28 @@
{ buildToolbox
, checkedShellScript
}:
# Utility script for pinning the latest stable version of Nixpkgs.
# Instead of running `nix flake update` manually, we run this script
# to also pin readthedocs dependencies at the same time.
let
upgrade =
checkedShellScript
{
name = "postgrest-nixpkgs-upgrade";
docs = "Pin the newest version of Nixpkgs.";
workingDir = "/";
}
''
nix flake update
echo "# This file is auto-generated by postgrest-nixpkgs-upgrade" > docs/requirements.txt
cat "$(nix-build -A docs.requirements)" >> docs/requirements.txt
'';
in
buildToolbox
{
name = "postgrest-nixpkgs";
tools = { inherit upgrade; };
}
+15 -22
View File
@@ -20,27 +20,24 @@ let
git diff --exit-code HEAD postgrest.cabal > /dev/null
trap "" ERR
# TODO: Support C+D bumps when implementing hackage releases
bump () {
current_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
# shellcheck disable=SC2034
IFS=. read -r major minor patch <<< "$current_version"
IFS=. read -r A B C D <<< "$current_version"
echo "Current version is $current_version"
case "$1" in
major)
new_version="$((major+1)).0.0"
new_docs_version="$((major+1)).0"
A)
new_version="$((A+1)).0"
new_docs_version="$((A+1))"
;;
minor)
new_version="$major.$((minor+1)).0"
new_docs_version="$major.$((minor+1))"
;;
patch)
new_version="$major.$minor.$((patch+1))"
new_docs_version="$major.$minor"
B)
new_version="$A.$((B+1))"
new_docs_version="$A"
;;
devel)
new_version="$major.$((minor+1))"
new_version="$((A+1))"
new_docs_version="devel"
;;
esac
@@ -55,13 +52,9 @@ let
today_date_for_changelog="$(date '+%Y-%m-%d')"
if [[ "$current_branch" == "main" ]]; then
if [[ "$_arg_major" == "on" ]]; then
bump major
else
bump minor
fi
bump A
else
bump patch
bump B
fi
echo "Updating CHANGELOG.md ..."
@@ -75,10 +68,10 @@ let
bump devel
# The order of operations is important here:
# - bump devel is run and $major is upated to the new version
# - the branch is created with the new major, but the commit before the devel bump
# - bump devel is run and $A is updated to the new version
# - the branch is created with the new A, but the commit before the devel bump
# - the devel bump is committed
git branch -f "v$major"
git branch "v$A"
echo "Committing (devel bump)..."
git commit -m "bump version to $new_version" > /dev/null
@@ -90,7 +83,7 @@ let
if [[ "$current_branch" == "main" ]]; then
push1="git push $remote $current_branch"
push2="git push $remote v$major --force"
push2="git push $remote v$A"
else
push1="git push $remote $current_branch"
push2=""
+33 -6
View File
@@ -7,9 +7,12 @@
, hlint
, hsie
, nixpkgs-fmt
, python3Packages
, ruff
, silver-searcher
, statix
, stylish-haskell
, writeText
}:
let
style =
@@ -26,19 +29,20 @@ let
# Format Haskell files
# --vimgrep fixes a bug in ag: https://github.com/ggreer/the_silver_searcher/issues/753
${silver-searcher}/bin/ag -l --vimgrep -g '\.l?hs$' . \
# TODO: fix style issues in src/protolude and include it
${silver-searcher}/bin/ag -l --vimgrep -g '\.l?hs$' --ignore-dir=src/protolude . \
| xargs ${stylish-haskell}/bin/stylish-haskell -i
# Format Python files
${black}/bin/black . 2> /dev/null
'';
# Script to check whether any uncommited changes result from postgrest-style
# Script to check whether any uncommitted changes result from postgrest-style
styleCheck =
checkedShellScript
{
name = "postgrest-style-check";
docs = "Check whether postgrest-style results in any uncommited changes.";
docs = "Check whether postgrest-style results in any uncommitted changes.";
workingDir = "/";
}
''
@@ -49,6 +53,20 @@ let
${git}/bin/git diff-index --exit-code HEAD -- '*.hs' '*.lhs' '*.nix' '*.py'
'';
hlintConfig = writeText "hlintConfig.yml" ''
# Arguments passed to hlint
- arguments: [-j, -XQuasiQuotes, -XNoPatternSynonyms]
# Warnings
- warn: { lhs: "a == a", rhs: "True", note: "This comparison always evaluates to True" }
- warn: { lhs: "a /= a", rhs: "False", note: "This comparison always evaluates to False" }
- warn: { lhs: "a < a", rhs: "False", note: "This comparison always evaluates to False" }
- warn: { lhs: "a > a", rhs: "False", note: "This comparison always evaluates to False" }
- warn: { lhs: "a <= a", rhs: "True", note: "This comparison always evaluates to True" }
- warn: { lhs: "a >= a", rhs: "True", note: "This comparison always evaluates to True" }
'';
lint =
checkedShellScript
{
@@ -63,13 +81,22 @@ let
echo "Scanning nix files for unused code..."
${deadnix}/bin/deadnix -f
# ruff has gaps in scanning for unused code, so we use vulture
echo "Scanning python files for unused code..."
${silver-searcher}/bin/ag -l --vimgrep -g '\.l?py$' . \
| xargs ${python3Packages.vulture}/bin/vulture --exclude docs/conf.py --min-confidence 80
echo "Linting python files..."
${ruff}/bin/ruff check .
echo "Checking consistency of import aliases in Haskell code..."
${hsie} check-aliases main src
${hsie} check-aliases main src/PostgREST
echo "Linting Haskell files..."
# --vimgrep fixes a bug in ag: https://github.com/ggreer/the_silver_searcher/issues/753
${silver-searcher}/bin/ag -l --vimgrep -g '\.l?hs$' . \
| xargs ${hlint}/bin/hlint -X QuasiQuotes -X NoPatternSynonyms
# TODO: fix lint issues in src/protolude and include it
${silver-searcher}/bin/ag -l --vimgrep -g '\.l?hs$' --ignore-dir=src/protolude . \
| xargs ${hlint}/bin/hlint --hint=${hlintConfig}
'';
in
+29 -19
View File
@@ -7,7 +7,6 @@
, glibcLocales ? null
, gnugrep
, hpc-codecov
, hostPlatform
, jq
, lib
, postgrest
@@ -28,11 +27,24 @@ let
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-update
${withTools.withPg} -f test/spec/fixtures/load.sql \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:spec -- "''${_arg_leftovers[@]}"
'';
testObservability =
checkedShellScript
{
name = "postgrest-test-observability";
docs = "Run the Haskell observability test suite.";
args = [ "ARG_LEFTOVERS([hspec arguments])" ];
workingDir = "/";
withEnv = postgrest.env;
}
''
${withTools.withPg} -f test/observability/fixtures/load.sql \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:observability -- "''${_arg_leftovers[@]}"
'';
testDoctests =
checkedShellScript
{
@@ -42,7 +54,6 @@ let
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-update
# 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
@@ -57,7 +68,6 @@ let
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-update
${withTools.withPg} -f test/spec/fixtures/load.sql \
${runtimeShell} -c " \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:spec && \
@@ -85,9 +95,8 @@ let
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal v2-build ${devCabalOptions} exe:postgrest
${cabal-install}/bin/cabal v2-exec -- ${withTools.withPg} -f test/io/fixtures.sql \
${cabal-install}/bin/cabal v2-exec -- ${withTools.withPg} -f test/io/fixtures/load.sql \
${ioTestPython}/bin/pytest --ignore=test/io/test_big_schema.py --ignore=test/io/test_replica.py -v test/io "''${_arg_leftovers[@]}"
'';
@@ -101,9 +110,8 @@ let
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal v2-build ${devCabalOptions} exe:postgrest
${cabal-install}/bin/cabal v2-exec -- ${withTools.withPg} -f test/io/big_schema.sql \
${cabal-install}/bin/cabal v2-exec -- ${withTools.withPg} -f test/io/fixtures/big_schema.sql \
${ioTestPython}/bin/pytest -v test/io/test_big_schema.py "''${_arg_leftovers[@]}"
'';
@@ -117,9 +125,8 @@ let
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal v2-build ${devCabalOptions} exe:postgrest
${cabal-install}/bin/cabal v2-exec -- ${withTools.withPg} --replica -f test/io/replica.sql \
${cabal-install}/bin/cabal v2-exec -- ${withTools.withPg} --replica -f test/io/fixtures/replica.sql \
${ioTestPython}/bin/pytest -v test/io/test_replica.py "''${_arg_leftovers[@]}"
'';
@@ -133,7 +140,6 @@ let
withPath = [ jq ];
}
''
${cabal-install}/bin/cabal v2-update
${withTools.withPg} -f test/spec/fixtures/load.sql \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} --verbose=0 -- \
postgrest --dump-schema
@@ -152,7 +158,7 @@ let
}
(
# required for `hpc markup` in CI; glibcLocales is not available e.g. on Darwin
lib.optionalString (stdenv.isLinux && hostPlatform.libc == "glibc") ''
lib.optionalString (stdenv.isLinux && stdenv.hostPlatform.libc == "glibc") ''
export LOCALE_ARCHIVE="${glibcLocales}/lib/locale/locale-archive"
'' +
@@ -162,8 +168,7 @@ let
rm -rf coverage/*
# build once before running all the tests
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal v2-build ${devCabalOptions} exe:postgrest lib:postgrest test:spec
${cabal-install}/bin/cabal v2-build ${devCabalOptions} exe:postgrest lib:postgrest test:spec test:observability
(
trap 'echo Found dead code: Check file list above.' ERR ;
@@ -172,26 +177,31 @@ let
# collect all tests
HPCTIXFILE="$tmpdir"/io.tix \
${withTools.withPg} -f test/io/fixtures.sql \
${withTools.withPg} -f test/io/fixtures/load.sql \
${cabal-install}/bin/cabal v2-exec ${devCabalOptions} -- ${ioTestPython}/bin/pytest --ignore=test/io/test_big_schema.py --ignore=test/io/test_replica.py -v test/io
HPCTIXFILE="$tmpdir"/big_schema.tix \
${withTools.withPg} -f test/io/big_schema.sql \
${withTools.withPg} -f test/io/fixtures/big_schema.sql \
${cabal-install}/bin/cabal v2-exec ${devCabalOptions} -- ${ioTestPython}/bin/pytest -v test/io/test_big_schema.py
HPCTIXFILE="$tmpdir"/replica.tix \
${withTools.withPg} --replica -f test/io/replica.sql \
${withTools.withPg} --replica -f test/io/fixtures/replica.sql \
${cabal-install}/bin/cabal v2-exec ${devCabalOptions} -- ${ioTestPython}/bin/pytest -v test/io/test_replica.py
HPCTIXFILE="$tmpdir"/spec.tix \
${withTools.withPg} -f test/spec/fixtures/load.sql \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:spec
HPCTIXFILE="$tmpdir"/observability.tix \
${withTools.withPg} -f test/observability/fixtures/load.sql \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:observability
# Note: No coverage for doctests, as doctests leverage GHCi and GHCi does not support hpc
# collect all the tix files
${ghc}/bin/hpc sum --union --exclude=Paths_postgrest --output="$tmpdir"/tests.tix \
"$tmpdir"/io*.tix "$tmpdir"/big_schema*.tix "$tmpdir"/replica*.tix "$tmpdir"/spec.tix
"$tmpdir"/io*.tix "$tmpdir"/big_schema*.tix "$tmpdir"/replica*.tix "$tmpdir"/spec.tix \
"$tmpdir"/observability.tix
# prepare the overlay
${ghc}/bin/hpc overlay --output="$tmpdir"/overlay.tix test/coverage.overlay
@@ -246,7 +256,6 @@ let
withPath = [ curl ];
}
''
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal --builddir="dist-prof" v2-build --enable-profiling --disable-shared exe:postgrest
${cabal-install}/bin/cabal --builddir="dist-prof" v2-exec -- ${withTools.withPg} -f test/spec/fixtures/load.sql \
test/memory/memory-tests.sh
@@ -259,6 +268,7 @@ buildToolbox
tools = {
inherit
testSpec
testObservability
testDoctests
testSpecIdempotence
testIO
+95 -105
View File
@@ -5,8 +5,9 @@
, lib
, postgresqlVersions
, postgrest
, slocat
, python3Packages
, writeText
, writers
}:
let
withTmpDb =
@@ -23,7 +24,7 @@ let
"ARG_OPTIONAL_SINGLE([fixtures], [f], [SQL file to load fixtures from])"
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
"ARG_USE_ENV([PGUSER], [postgrest_test_authenticator], [Authenticator PG role])"
"ARG_USE_ENV([PGUSER], [Postgrest_Test_Authenticator], [Authenticator PG role])" # user is written in mixed case to implicitly test that it is being properly quoted in schema cache queries
"ARG_USE_ENV([PGDATABASE], [postgres], [PG database name])"
"ARG_USE_ENV([PGRST_DB_SCHEMAS], [test], [Schema to expose])"
"ARG_USE_ENV([PGTZ], [utc], [Timezone to use])"
@@ -44,7 +45,7 @@ let
}
# Avoid starting multiple layers of withTmpDb, but make sure to have the last invocation
# load fixtures. Otherwise postgrest-with-postgresql-xx postgrest-test-io would not be possible.
# load fixtures. Otherwise postgrest-with-pg-xx postgrest-test-io would not be possible.
if ! test -v PGHOST; then
mkdir -p "$tmpdir"/{db,socket}
@@ -72,7 +73,13 @@ let
>> "$setuplog"
log "Starting the database cluster..."
# Instead of listening on a local port, we will listen on a unix domain socket.
# NOTE: unix domain socket filename name must remain under max limit.
# On Linux, it's 108 chars (including '\0' terminator)
# On MacOS, it's 104 chars
# See: https://serverfault.com/questions/641347/check-if-a-path-exceeds-maximum-for-unix-domain-socket
pg_ctl -l "$tmpdir/db.log" -w start -o "-F -c listen_addresses=\"\" -c hba_file=$HBA_FILE -k $PGHOST -c log_statement=\"all\" " \
>> "$setuplog"
@@ -98,7 +105,8 @@ let
log "Starting replica on $replica_host"
pg_ctl -D "$replica_dir" -l "$replica_dblog" -w start -o "-F -c listen_addresses=\"\" -c hba_file=$HBA_FILE -k $replica_host -c log_statement=\"all\" " \
# We set a low max_standby_streaming_delay to make the replication conflict fail faster in tests (otherwise it waits for the default 30s)
pg_ctl -D "$replica_dir" -l "$replica_dblog" -w start -o "-F -c listen_addresses=\"\" -c hba_file=$HBA_FILE -k $replica_host -c log_statement=\"all\" -c max_standby_streaming_delay=\"3s\" " \
>> "$setuplog"
>&2 echo "${commandName}: Replica enabled. You can connect to it with: psql 'postgres:///$PGDATABASE?host=$replica_host' -U postgres"
@@ -109,7 +117,7 @@ let
export PGRST_DB_URI="postgres:///$PGDATABASE?host=$PGREPLICAHOST,$PGHOST"
fi
# shellcheck disable=SC2317
# shellcheck disable=SC2329
stop () {
log "Stopping the database cluster..."
pg_ctl stop --mode=immediate >> "$setuplog"
@@ -124,9 +132,11 @@ let
fi
if test "$_arg_fixtures"; then
log "Loading fixtures under the postgres role..."
load_start=$SECONDS
>&2 printf "${commandName}: Loading fixtures under the postgres role..."
psql -U postgres -v PGUSER="$PGUSER" -v ON_ERROR_STOP=1 -f "$_arg_fixtures" >> "$setuplog"
log "Done. Running command..."
load_end=$((SECONDS - load_start))
>&2 printf " done in %ss. Running command...\n" "$load_end"
fi
("$_arg_command" "''${_arg_leftovers[@]}")
@@ -175,81 +185,6 @@ let
withPg = withTmpDb (builtins.head postgresqlVersions);
withSlowPg =
checkedShellScript
{
name = "postgrest-with-slow-pg";
docs = "Run the given command with simulated high latency postgresql";
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
"ARG_USE_ENV([PGHOST], [], [PG host (socket name)])"
"ARG_USE_ENV([PGDELAY], [0ms], [extra PG latency (duration)])"
];
positionalCompletion = "_command";
workingDir = "/";
redirectTixFiles = false;
withTmpDir = true;
}
''
delay="''${PGDELAY:-0ms}"
echo "delaying data to/from postgres by $delay"
REALPGHOST="$PGHOST"
export PGHOST="$tmpdir/socket"
mkdir -p "$PGHOST"
${slocat}/bin/slocat -delay "$delay" -src "$PGHOST/.s.PGSQL.5432" -dst "$REALPGHOST/.s.PGSQL.5432" &
SLOCAT_PID=$!
# shellcheck disable=SC2317
stop_slocat() {
kill "$SLOCAT_PID" || true
wait "$SLOCAT_PID" || true
}
trap stop_slocat EXIT
sleep 1 # should wait for socket file to appear instead
("$_arg_command" "''${_arg_leftovers[@]}")
'';
withSlowPgrst =
checkedShellScript
{
name = "postgrest-with-slow-postgrest";
docs = "Run the given command with simulated high latency postgrest";
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
"ARG_USE_ENV([PGRST_SERVER_UNIX_SOCKET], [], [PostgREST host (socket name)])"
"ARG_USE_ENV([PGRST_DELAY], [0ms], [extra PostgREST latency (duration)])"
];
positionalCompletion = "_command";
workingDir = "/";
redirectTixFiles = false;
withTmpDir = true;
}
''
delay="''${PGRST_DELAY:-0ms}"
echo "delaying data to/from PostgREST by $delay"
REAL_PGRST_SERVER_UNIX_SOCKET="$PGRST_SERVER_UNIX_SOCKET"
export PGRST_SERVER_UNIX_SOCKET="$tmpdir/postgrest.socket"
${slocat}/bin/slocat -delay "$delay" -src "$PGRST_SERVER_UNIX_SOCKET" -dst "$REAL_PGRST_SERVER_UNIX_SOCKET" &
SLOCAT_PID=$!
# shellcheck disable=SC2317
stop_slocat() {
kill "$SLOCAT_PID" || true
wait "$SLOCAT_PID" || true
}
trap stop_slocat EXIT
sleep 1 # should wait for socket file to appear instead
("$_arg_command" "''${_arg_leftovers[@]}")
'';
withGit =
let
name = "postgrest-with-git";
@@ -327,15 +262,38 @@ let
done
'';
# Broadcast SIGINT to any running postgrest instances on the host. Uses python for cross-platform compatibility.
signalPostgrest =
writers.writePython3 "postgrest-signal-int"
{ libraries = [ python3Packages.psutil ]; }
''
import psutil
import signal
for proc in psutil.process_iter(["name"]):
try:
if proc.info["name"] == "postgrest":
proc.send_signal(signal.SIGINT)
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
'';
withPgrst =
let
commandName = "postgrest-with-pgrst";
in
checkedShellScript
{
name = "postgrest-with-pgrst";
name = commandName;
docs = "Build and run PostgREST and run <command> with PGRST_SERVER_UNIX_SOCKET set.";
args =
[
"ARG_POSITIONAL_SINGLE([command], [Command to run])"
"ARG_LEFTOVERS([command arguments])"
"ARG_OPTIONAL_SINGLE([monitor], [m], [Enable CPU and memory monitoring of the PostgREST process and output to the designated file as markdown])"
"ARG_OPTIONAL_SINGLE([timeout], [t], [Maximum time to wait for PostgREST to be ready], [5])"
"ARG_OPTIONAL_SINGLE([sleep], [s], [Sleep time after PostgREST is ready, this is useful for monitoring])"
"ARG_USE_ENV([PGRST_CMD], [], [PostgREST executable to run])"
];
positionalCompletion = "_command";
workingDir = "/";
@@ -345,41 +303,75 @@ let
''
export PGRST_SERVER_UNIX_SOCKET="$tmpdir"/postgrest.socket
rm -f result
if [ -z "''${PGRST_BUILD_CABAL:-}" ]; then
echo -n "Building postgrest (nix)... "
nix-build -A postgrestPackage > "$tmpdir"/build.log 2>&1 || {
echo "failed, output:"
cat "$tmpdir"/build.log
exit 1
}
PGRST_CMD=./result/bin/postgrest
else
echo -n "Building postgrest (cabal)... "
postgrest-build
PGRST_CMD=postgrest-run
if [ -z "''${PGRST_CMD:-}" ]; then
rm -f result
build_start=$SECONDS
if [ -z "''${PGRST_BUILD_CABAL:-}" ]; then
echo -n "${commandName}: Building postgrest (nix)... "
# Using lib.getBin to also make this work with older checkouts, where .bin was not a thing, yet.
nix-build -E 'with import ./. {}; pkgs.lib.getBin postgrestPackage' > "$tmpdir"/build.log 2>&1 || {
echo "failed, output:"
cat "$tmpdir"/build.log
exit 1
}
PGRST_CMD=$(echo ./result*/bin/postgrest)
else
echo -n "${commandName}: Building postgrest (cabal)... "
postgrest-build
PGRST_CMD=postgrest-run
fi
build_end=$((SECONDS - build_start))
printf "done in %ss.\n" "$build_end"
fi
echo "done."
echo -n "Starting postgrest... "
ver=$($PGRST_CMD ${legacyConfig} --version)
echo -n "${commandName}: Starting $ver... "
$PGRST_CMD ${legacyConfig} > "$tmpdir"/run.log 2>&1 &
pid=$!
# shellcheck disable=SC2317
# shellcheck disable=SC2329
cleanup() {
# Send INT to all postgrest processes.
# Workaround to trigger dumping postgrest.prof for postgrest-profiled-run
# Caveat: we cannot realistically limit this to the current process' tree,
# since pkill's --parent supports only direct children; therefore this
# would reap neighbor postgrest instances as well, because INT is asking
# the process to terminate too.
# TODO: consider cgroups to make this cleaner
${signalPostgrest}
kill "$pid" || true
}
trap cleanup EXIT
timeout -s TERM 5 ${waitForPgrstReady} || {
wait_start=$SECONDS
timeout -s TERM "$_arg_timeout" ${waitForPgrstReady} || {
echo "timed out, output:"
cat "$tmpdir"/run.log
exit 1
}
echo "done."
wait_duration=$((SECONDS - wait_start))
printf "done in %ss.\n" "$wait_duration"
echo "${commandName}: You can tail the server logs with: tail -f $tmpdir/run.log"
if [[ -n "$_arg_monitor" ]]; then
${monitorPid} "$pid" > "$_arg_monitor" &
fi
if [[ -n "$_arg_sleep" ]]; then
sleep "$_arg_sleep"
fi
("$_arg_command" "''${_arg_leftovers[@]}")
'';
monitorPid =
writers.writePython3 "postgrest-monitor-pid"
{
libraries = [ python3Packages.pandas python3Packages.tabulate python3Packages.psutil ];
}
(builtins.readFile ./monitor_pid.py);
in
buildToolbox
{
@@ -388,11 +380,9 @@ buildToolbox
inherit
withGit
withPgAll
withPgrst
withSlowPg
withSlowPgrst;
withPgrst;
} // builtins.listToAttrs (
# Create a `postgrest-with-postgresql-` for each PostgreSQL version
# Create a `postgrest-with-pg-` for each PostgreSQL version
builtins.map (pg: { inherit (pg) name; value = withTmpDb pg; }) postgresqlVersions
);
# make latest withPg available for other nix files
+141 -47
View File
@@ -1,34 +1,31 @@
cabal-version: 3.0
name: postgrest
version: 13.0.0
version: 15
synopsis: REST API for any Postgres database
description: Reads the schema of a PostgreSQL database and creates RESTful routes
for tables, views, and functions, supporting all HTTP methods that security
permits.
license: MIT
license-file: LICENSE
author: Joe Nelson, Adam Baker, Steve Chavez
author: Joe Nelson, Adam Baker, Steve Chavez, Wolfgang Walther
maintainer: Steve Chavez <stevechavezast@gmail.com>
category: Executable, PostgreSQL, Network APIs
homepage: https://postgrest.org
bug-reports: https://github.com/PostgREST/postgrest/issues
build-type: Simple
extra-source-files: CHANGELOG.md
cabal-version: >= 1.10
tested-with:
-- stack on FreeBSD
GHC == 9.4.5
-- nix, cabal on Ubuntu (arm)
, GHC == 9.4.8
-- cabal on Ubuntu
-- stack on MacOS, Ubuntu, Windows
, GHC == 9.6.6
-- stack on FreeBSD, MacOS, Ubuntu, Windows
, GHC == 9.10.3
-- cabal on Ubuntu
, GHC == 9.8.2
-- nix
, GHC == 9.12.3
source-repository head
type: git
location: git://github.com/PostgREST/postgrest.git
location: https://github.com/PostgREST/postgrest.git
flag dev
default: False
@@ -49,11 +46,15 @@ library
PostgREST.App
PostgREST.AppState
PostgREST.Auth
PostgREST.Auth.Jwt
PostgREST.Auth.JwtCache
PostgREST.Auth.Types
PostgREST.Cache.Sieve
PostgREST.CLI
PostgREST.Client
PostgREST.Config
PostgREST.Config.Database
PostgREST.Debounce
PostgREST.Config.JSPath
PostgREST.Config.PgVersion
PostgREST.Config.Proxy
@@ -65,19 +66,23 @@ library
PostgREST.SchemaCache.Representations
PostgREST.SchemaCache.Table
PostgREST.Error
PostgREST.Error.Types
PostgREST.Listener
PostgREST.Logger
PostgREST.MainTx
PostgREST.MediaType
PostgREST.Metrics
PostgREST.Network
PostgREST.Observation
PostgREST.Query
PostgREST.Query.PreQuery
PostgREST.Query.QueryBuilder
PostgREST.Query.SqlFragment
PostgREST.Query.Statements
PostgREST.Plan
PostgREST.Plan.CallPlan
PostgREST.Plan.MutatePlan
PostgREST.Plan.Negotiate
PostgREST.Plan.ReadPlan
PostgREST.Plan.Types
PostgREST.RangeQuery
@@ -85,61 +90,60 @@ library
PostgREST.ApiRequest
PostgREST.ApiRequest.Preferences
PostgREST.ApiRequest.QueryParams
PostgREST.ApiRequest.Payload
PostgREST.ApiRequest.Types
PostgREST.Response
PostgREST.Response.OpenAPI
PostgREST.Response.GucHeader
PostgREST.Response.Performance
PostgREST.TimeIt
PostgREST.Version
other-modules: Paths_postgrest
build-depends: base >= 4.9 && < 4.20
build-depends: base >= 4.9 && < 4.22
, HTTP >= 4000.3.7 && < 4000.5
, Ranged-sets >= 0.3 && < 0.5
, Ranged-sets >= 0.3 && < 0.6
, aeson >= 2.0.3 && < 2.3
, auto-update >= 0.1.4 && < 0.2
, auto-update >= 0.1.4 && < 0.3
, base64-bytestring >= 1 && < 1.3
, bytestring >= 0.10.8 && < 0.13
, cache >= 0.1.3 && < 0.2.0
, case-insensitive >= 1.2 && < 1.3
, cassava >= 0.4.5 && < 0.6
, clock >= 0.8.3 && < 0.9.0
, configurator-pg >= 0.2 && < 0.3
, containers >= 0.5.7 && < 0.7
, cookie >= 0.4.2 && < 0.5
, configurator-pg >= 0.2.11 && < 0.3
, containers >= 0.5.7 && < 0.8
, cookie >= 0.4.2 && < 0.6
-- crypton 1.1.0 moved from `memory` to `ram`, which jose-jwt fails to build with right now.
-- should be possible to remove this once jose-jwt had a new release.
, crypton < 1.1.0
, directory >= 1.2.6 && < 1.4
, either >= 4.4.1 && < 5.1
, extra >= 1.7.0 && < 2.0
, fuzzyset >= 0.2.4 && < 0.3
, hasql >= 1.6.1.1 && < 1.7
, hasql-dynamic-statements >= 0.3.1 && < 0.4
, hasql-notifications >= 0.2.2.2 && < 0.2.3
, hasql-pool >= 1.0.1 && < 1.1
, hasql-transaction >= 1.0.1 && < 1.1
, heredoc >= 0.2 && < 0.3
, hasql >= 1.9 && <= 1.9.3.1
, hasql-dynamic-statements >= 0.3.1 && <= 0.3.1.8
, hasql-notifications >= 0.2.4.0 && < 0.3
, hasql-pool >= 1.1 && <= 1.3.0.4
, hasql-transaction >= 1.0.1 && <= 1.2.1
, http-client >= 0.7.19 && < 0.8
, http-types >= 0.12.2 && < 0.13
, insert-ordered-containers >= 0.2.2 && < 0.3
, iproute >= 1.7.0 && < 1.8
, jose-jwt >= 0.9.6 && < 0.11
, lens >= 4.14 && < 5.3
, lens >= 4.14 && < 5.4
, lens-aeson >= 1.0.1 && < 1.3
, mtl >= 2.2.2 && < 2.4
, neat-interpolation >= 0.5 && < 0.6
, network >= 2.6 && < 3.2
, network >= 2.6 && < 3.3
, network-uri >= 2.6.1 && < 2.8
, optparse-applicative >= 0.13 && < 0.19
, parsec >= 3.1.11 && < 3.2
-- Technically unused, can be removed after updating to hasql >= 1.7
, postgresql-libpq >= 0.10
, prometheus-client >= 1.1.1 && < 1.2.0
, protolude >= 0.3.1 && < 0.4
, protolude
, regex-tdfa >= 1.2.2 && < 1.4
, retry >= 0.7.4 && < 0.10
, scientific >= 0.3.4 && < 0.4
, streaming-commons >= 0.1.1 && < 0.3
, streaming-commons >= 0.2.3.1 && < 0.3
, swagger2 >= 2.4 && < 2.9
, text >= 1.2.2 && < 2.2
, time >= 1.6 && < 1.13
, timeit >= 2.0 && < 2.1
, time >= 1.6 && < 1.15
, unordered-containers >= 0.2.8 && < 0.3
, unix-compat >= 0.5.4 && < 0.8
, vault >= 0.3.1.5 && < 0.4
@@ -152,7 +156,11 @@ library
-- for unix sockets; this is tested in test/io/test_io.py. See
-- https://github.com/kazu-yamamoto/logger/commit/3a71ca70afdbb93d4ecf0083eeba1fbbbcab3fc3
, wai-logger >= 2.4.0
, warp >= 3.3.19 && < 3.4
, warp >= 3.4.13 && < 3.5
, stm >= 2.5 && < 3
, stm-hamt >= 1.2 && < 2
, focus >= 1.0 && < 2
, some >= 1.0.4.1 && < 2
-- -fno-spec-constr may help keep compile time memory use in check,
-- see https://gitlab.haskell.org/ghc/ghc/issues/16017#note_219304
-- -optP-Wno-nonportable-include-path
@@ -172,16 +180,64 @@ library
build-depends:
unix
library protolude
visibility: private
default-language: Haskell2010
default-extensions: NoImplicitPrelude
FlexibleContexts
MultiParamTypeClasses
OverloadedStrings
hs-source-dirs: src/protolude
exposed-modules: Protolude
Protolude.Applicative
Protolude.Base
Protolude.Bifunctor
Protolude.Bool
Protolude.CallStack
Protolude.Conv
Protolude.ConvertText
Protolude.Debug
Protolude.Either
Protolude.Error
Protolude.Exceptions
Protolude.Functor
Protolude.List
Protolude.Monad
Protolude.Panic
Protolude.Partial
Protolude.Safe
Protolude.Semiring
Protolude.Show
Protolude.Unsafe
build-depends: array >= 0.4 && < 0.6
, async >= 2.0 && < 2.3
, base >= 4.6 && < 4.22
, bytestring >= 0.10.8 && < 0.13
, containers >= 0.5.7 && < 0.8
, deepseq >= 1.3 && < 1.6
, ghc-prim >= 0.3 && < 0.14
, hashable >= 1.2 && < 1.6
, mtl >= 2.1 && < 2.4
, mtl-compat >= 0.2 && < 0.3
, stm >= 2.5 && < 3
, text >= 1.2.2 && < 2.2
, transformers >= 0.2 && < 0.7
, transformers-compat >= 0.4 && < 0.8
-- Protolude has some partial functions, so
-- it is fine to disable that specific warning
ghc-options: -Werror -Wall -fwarn-identities -Wno-x-partial
-fno-spec-constr -optP-Wno-nonportable-include-path
executable postgrest
default-language: Haskell2010
default-extensions: OverloadedStrings
NoImplicitPrelude
hs-source-dirs: main
main-is: Main.hs
build-depends: base >= 4.9 && < 4.20
, containers >= 0.5.7 && < 0.7
build-depends: base >= 4.9 && < 4.22
, containers >= 0.5.7 && < 0.8
, postgrest
, protolude >= 0.3.1 && < 0.4
, protolude
ghc-options: -threaded -rtsopts "-with-rtsopts=-N -I0 -qg"
-O2 -Werror -Wall -fwarn-identities
-fno-spec-constr -optP-Wno-nonportable-include-path
@@ -236,7 +292,9 @@ test-suite spec
Feature.Query.PgSafeUpdateSpec
Feature.Query.PlanSpec
Feature.Query.PostGISSpec
Feature.Query.PreferencesSpec
Feature.Query.Preferences.HandlingSpec
Feature.Query.Preferences.MaxAffectedSpec
Feature.Query.Preferences.TimezoneSpec
Feature.Query.QueryLimitedSpec
Feature.Query.QuerySpec
Feature.Query.RangeSpec
@@ -252,28 +310,30 @@ test-suite spec
Feature.RollbackSpec
Feature.RpcPreRequestGucsSpec
SpecHelper
build-depends: base >= 4.9 && < 4.20
build-depends: base >= 4.9 && < 4.22
, aeson >= 2.0.3 && < 2.3
, aeson-qq >= 0.8.1 && < 0.9
, async >= 2.1.1 && < 2.3
, base64-bytestring >= 1 && < 1.3
, bytestring >= 0.10.8 && < 0.13
, case-insensitive >= 1.2 && < 1.3
, containers >= 0.5.7 && < 0.7
, hasql-pool >= 1.0.1 && < 1.1
, hasql-transaction >= 1.0.1 && < 1.1
, containers >= 0.5.7 && < 0.8
, hasql-pool >= 1.0.1 && <= 1.3.0.4
, hasql-transaction >= 1.0.1 && <= 1.2.1
, heredoc >= 0.2 && < 0.3
, hspec >= 2.3 && < 2.12
, hspec-expectations >= 0.8.4 && < 0.9
, hspec-wai >= 0.10 && < 0.12
, hspec-wai-json >= 0.10 && < 0.12
, http-types >= 0.12.3 && < 0.13
, jose-jwt >= 0.9.6 && < 0.11
, lens >= 4.14 && < 5.3
, lens >= 4.14 && < 5.4
, lens-aeson >= 1.0.1 && < 1.3
, monad-control >= 1.0.1 && < 1.1
, postgrest
, process >= 1.4.2 && < 1.7
, protolude >= 0.3.1 && < 0.4
, prometheus-client >= 1.1.1 && < 1.2.0
, protolude
, regex-tdfa >= 1.2.2 && < 1.4
, scientific >= 0.3.4 && < 0.4
, text >= 1.2.2 && < 2.2
@@ -287,6 +347,40 @@ test-suite spec
-- https://github.com/PostgREST/postgrest/issues/387
-with-rtsopts=-K33K
test-suite observability
type: exitcode-stdio-1.0
default-language: Haskell2010
default-extensions: OverloadedStrings
QuasiQuotes
NoImplicitPrelude
hs-source-dirs: test/observability
main-is: Main.hs
other-modules: ObsHelper
Observation.JwtCache
Observation.MetricsSpec
Observation.SchemaCacheSpec
build-depends: base >= 4.9 && < 4.22
, base64-bytestring >= 1 && < 1.3
, bytestring >= 0.10.8 && < 0.13
, hasql-pool >= 1.0.1 && <= 1.3.0.4
, hasql-transaction >= 1.0.1 && <= 1.2.1
, hspec >= 2.3 && < 2.12
, hspec-expectations >= 0.8.4 && < 0.9
, hspec-wai >= 0.10 && < 0.12
, hspec-wai-json >= 0.10 && < 0.12
, http-types >= 0.12.3 && < 0.13
, jose-jwt >= 0.9.6 && < 0.11
, postgrest
, prometheus-client >= 1.1.1 && < 1.2.0
, protolude
, text >= 1.2.2 && < 2.2
, wai >= 3.2.1 && < 3.3
ghc-options: -threaded -O0 -Werror -Wall -fwarn-identities
-fno-spec-constr -optP-Wno-nonportable-include-path
-fwrite-ide-info
-- https://github.com/PostgREST/postgrest/issues/387
-with-rtsopts=-K33K
test-suite doctests
type: exitcode-stdio-1.0
default-language: Haskell2010
@@ -294,10 +388,10 @@ test-suite doctests
NoImplicitPrelude
hs-source-dirs: test/doc
main-is: Main.hs
build-depends: base >= 4.9 && < 4.20
build-depends: base >= 4.9 && < 4.22
, doctest >= 0.8
, postgrest
, pretty-simple
, protolude >= 0.3.1 && < 0.4
, protolude
ghc-options: -threaded -O0 -Werror -Wall -fwarn-identities
-fno-spec-constr -optP-Wno-nonportable-include-path
+7 -6
View File
@@ -7,11 +7,9 @@
# We highly recommend that use the PostgREST binary cache by installing cachix
# (https://app.cachix.org/) and running `cachix use postgrest`.
{ docker ? false
, postgrest ? import ./default.nix { }
}:
let
postgrest =
import ./default.nix { };
inherit (postgrest) pkgs;
inherit (pkgs) lib;
@@ -21,7 +19,9 @@ let
postgrest.cabalTools
postgrest.devTools
postgrest.docs
postgrest.gitTools
postgrest.loadtest
postgrest.nixpkgsTools
postgrest.release
postgrest.style
postgrest.tests
@@ -35,10 +35,7 @@ lib.overrideDerivation postgrest.env (
buildInputs =
base.buildInputs ++ [
pkgs.cabal-install
pkgs.cabal2nix
pkgs.git
pkgs.postgresql
pkgs.update-nix-fetchgit
postgrest.hsie.bin
]
++ toolboxes;
@@ -47,6 +44,10 @@ lib.overrideDerivation postgrest.env (
''
export HISTFILE=.history
# Bypass proxy for all hosts, it prevents HTTP client failures used in test
# suites. See: https://github.com/PostgREST/postgrest/issues/4633 for more info
export NO_PROXY=*
source ${pkgs.bash-completion}/etc/profile.d/bash_completion.sh
source ${pkgs.git}/share/git/contrib/completion/git-completion.bash
source ${postgrest.hsie.bash-completion}
+16 -19
View File
@@ -1,5 +1,3 @@
{-# LANGUAGE NamedFieldPuns #-}
module PostgREST.Admin
( runAdmin
) where
@@ -9,36 +7,35 @@ import qualified Network.HTTP.Types.Status as HTTP
import qualified Network.Wai as Wai
import qualified Network.Wai.Handler.Warp as Warp
import Control.Monad.Extra (whenJust)
import Network.Socket
import Control.Monad.Extra (whenJust)
import Network.Socket hiding (addrFamily)
import Network.Socket.ByteString
import PostgREST.AppState (AppState)
import PostgREST.Config (AppConfig (..))
import PostgREST.MediaType (MediaType (..), toContentType)
import PostgREST.Metrics (metricsToText)
import PostgREST.Network (resolveHost)
import PostgREST.Network (resolveSocketToAddress)
import PostgREST.Observation (Observation (..))
import qualified PostgREST.AppState as AppState
import Protolude
import qualified Network.Socket as NS
import Protolude
runAdmin :: AppState -> Warp.Settings -> IO ()
runAdmin appState settings = do
AppConfig{configAdminServerPort} <- AppState.getConfig appState
whenJust (AppState.getSocketAdmin appState) $ \adminSocket -> do
host <- resolveHost adminSocket
observer $ AdminStartObs host configAdminServerPort
runAdmin :: AppState -> Maybe NS.Socket -> NS.Socket -> Warp.Settings -> IO ()
runAdmin appState maybeAdminSocket socketREST settings = do
whenJust maybeAdminSocket $ \adminSocket -> do
address <- resolveSocketToAddress adminSocket
observer $ AdminStartObs address
void . forkIO $ Warp.runSettingsSocket settings adminSocket adminApp
where
adminApp = admin appState
adminApp = admin appState socketREST
observer = AppState.getObserver appState
-- | PostgREST admin application
admin :: AppState.AppState -> Wai.Application
admin appState req respond = do
isMainAppReachable <- isRight <$> reachMainApp (AppState.getSocketREST appState)
admin :: AppState.AppState -> NS.Socket -> Wai.Application
admin appState socketREST req respond = do
isMainAppReachable <- isRight <$> reachMainApp socketREST
isLoaded <- AppState.isLoaded appState
isPending <- AppState.isPending appState
@@ -58,7 +55,7 @@ admin appState req respond = do
respond $ Wai.responseLBS HTTP.status200 [] (maybe mempty JSON.encode sCache)
["metrics"] -> do
mets <- metricsToText
respond $ Wai.responseLBS HTTP.status200 [] mets
respond $ Wai.responseLBS HTTP.status200 [toContentType MTTextPlain] mets -- Content-Type is required for prometheus compliance
_ ->
respond $ Wai.responseLBS HTTP.status404 [] mempty
+12 -164
View File
@@ -6,44 +6,30 @@ Description : PostgREST functions to translate HTTP request to a domain type cal
{-# LANGUAGE NamedFieldPuns #-}
module PostgREST.ApiRequest
( ApiRequest(..)
, InvokeMethod(..)
, Mutation(..)
, MediaType(..)
, Action(..)
, DbAction(..)
, Payload(..)
, userApiRequest
, userPreferences
) where
import qualified Data.Aeson as JSON
import qualified Data.Aeson.Key as K
import qualified Data.Aeson.KeyMap as KM
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.CaseInsensitive as CI
import qualified Data.Csv as CSV
import qualified Data.HashMap.Strict as HM
import qualified Data.List.NonEmpty as NonEmptyList
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import qualified Data.Text.Encoding as T
import qualified Data.Vector as V
import qualified Data.CaseInsensitive as CI
import qualified Data.HashMap.Strict as HM
import qualified Data.List.NonEmpty as NonEmptyList
import qualified Data.Set as S
import qualified Data.Text.Encoding as T
import Data.Either.Combinators (mapBoth)
import Control.Arrow ((***))
import Data.Aeson.Types (emptyArray, emptyObject)
import Data.List (lookup)
import Data.Ranged.Ranges (emptyRange, rangeIntersection,
rangeIsEmpty)
import Network.HTTP.Types.Header (RequestHeaders, hCookie)
import Network.HTTP.Types.URI (parseSimpleQuery)
import Network.Wai (Request (..))
import Network.Wai.Parse (parseHttpAccept)
import Web.Cookie (parseCookies)
import PostgREST.ApiRequest.Payload (getPayload)
import PostgREST.ApiRequest.QueryParams (QueryParams (..))
import PostgREST.ApiRequest.Types (Action (..), DbAction (..),
InvokeMethod (..),
Mutation (..), Payload (..),
RequestBody, Resource (..))
import PostgREST.Config (AppConfig (..),
OpenAPIMode (..))
import PostgREST.Config.Database (TimezoneNames)
@@ -64,44 +50,6 @@ import qualified PostgREST.MediaType as MediaType
import Protolude
type RequestBody = LBS.ByteString
data Payload
= ProcessedJSON -- ^ Cached attributes of a JSON payload
{ payRaw :: LBS.ByteString
-- ^ This is the raw ByteString that comes from the request body. We
-- cache this instead of an Aeson Value because it was detected that for
-- large payloads the encoding had high memory usage, see
-- https://github.com/PostgREST/postgrest/pull/1005 for more details
, payKeys :: S.Set Text
-- ^ Keys of the object or if it's an array these keys are guaranteed to
-- be the same across all its objects
}
| ProcessedUrlEncoded { payArray :: [(Text, Text)], payKeys :: S.Set Text }
| RawJSON { payRaw :: LBS.ByteString }
| RawPay { payRaw :: LBS.ByteString }
data InvokeMethod = Inv | InvRead Bool deriving Eq
data Mutation = MutationCreate | MutationDelete | MutationSingleUpsert | MutationUpdate deriving Eq
data Resource
= ResourceRelation Text
| ResourceRoutine Text
| ResourceSchema
data DbAction
= ActRelationRead {dbActQi :: QualifiedIdentifier, actHeadersOnly :: Bool}
| ActRelationMut {dbActQi :: QualifiedIdentifier, actMutation :: Mutation}
| ActRoutine {dbActQi :: QualifiedIdentifier, actInvMethod :: InvokeMethod}
| ActSchemaRead Schema Bool
data Action
= ActDb DbAction
| ActRelationInfo QualifiedIdentifier
| ActRoutineInfo QualifiedIdentifier InvokeMethod
| ActSchemaInfo
{-|
Describes what the user wants to do. This data type is a
translation of the raw elements of an HTTP request into domain
@@ -116,7 +64,7 @@ data ApiRequest = ApiRequest {
, iPayload :: Maybe Payload -- ^ Data sent by client and used for mutation actions
, iPreferences :: Preferences.Preferences -- ^ Prefer header values
, iQueryParams :: QueryParams.QueryParams
, iColumns :: S.Set FieldName -- ^ parsed colums from &columns parameter and payload
, iColumns :: S.Set FieldName -- ^ parsed columns from &columns parameter and payload
, iHeaders :: [(ByteString, ByteString)] -- ^ HTTP request headers
, iCookies :: [(ByteString, ByteString)] -- ^ Request Cookies
, iPath :: ByteString -- ^ Raw request path
@@ -207,7 +155,7 @@ getAction resource schema method =
getSchema :: AppConfig -> RequestHeaders -> ByteString -> Either ApiRequestError (Schema, Bool)
getSchema AppConfig{configDbSchemas} hdrs method = do
case profile of
Just p | p `notElem` configDbSchemas -> Left $ UnacceptableSchema $ toList configDbSchemas
Just p | p `notElem` configDbSchemas -> Left $ UnacceptableSchema p $ toList configDbSchemas
| otherwise -> Right (p, True)
Nothing -> Right (defaultSchema, length configDbSchemas /= 1) -- if we have many schemas, assume the default schema was negotiated
where
@@ -240,103 +188,3 @@ getRanges method QueryParams{qsRanges} hdrs
-- The only emptyRange allowed is the limit zero range
isInvalidRange = topLevelRange == emptyRange && not (hasLimitZero limitRange)
topLevelRange = fromMaybe allRange $ HM.lookup "limit" ranges -- if no limit is specified, get all the request rows
getPayload :: RequestBody -> MediaType -> QueryParams.QueryParams -> Action -> Either ApiRequestError (Maybe Payload, S.Set FieldName)
getPayload reqBody contentMediaType QueryParams{qsColumns} action = do
checkedPayload <- if shouldParsePayload then payload else Right Nothing
let cols = case (checkedPayload, columns) of
(Just ProcessedJSON{payKeys}, _) -> payKeys
(Just ProcessedUrlEncoded{payKeys}, _) -> payKeys
(Just RawJSON{}, Just cls) -> cls
_ -> S.empty
return (checkedPayload, cols)
where
payload :: Either ApiRequestError (Maybe Payload)
payload = mapBoth InvalidBody Just $ case (contentMediaType, isProc) of
(MTApplicationJSON, _) ->
if isJust columns
then Right $ RawJSON reqBody
else note "All object keys must match" . payloadAttributes reqBody
=<< if LBS.null reqBody && isProc
then Right emptyObject
else first BS.pack $
-- Drop parsing error message in favor of generic one (https://github.com/PostgREST/postgrest/issues/2344)
maybe (Left "Empty or invalid json") Right $ JSON.decode reqBody
(MTTextCSV, _) -> do
json <- csvToJson <$> first BS.pack (CSV.decodeByName reqBody)
note "All lines must have same number of fields" $ payloadAttributes (JSON.encode json) json
(MTUrlEncoded, True) ->
Right $ ProcessedUrlEncoded params (S.fromList $ fst <$> params)
(MTUrlEncoded, False) ->
let paramsMap = HM.fromList $ (identity *** JSON.String) <$> params in
Right $ ProcessedJSON (JSON.encode paramsMap) $ S.fromList (HM.keys paramsMap)
(MTTextPlain, True) -> Right $ RawPay reqBody
(MTTextXML, True) -> Right $ RawPay reqBody
(MTOctetStream, True) -> Right $ RawPay reqBody
(ct, _) -> Left $ "Content-Type not acceptable: " <> MediaType.toMime ct
shouldParsePayload = case action of
ActDb (ActRelationMut _ MutationDelete) -> False
ActDb (ActRelationMut _ _) -> True
ActDb (ActRoutine _ Inv) -> True
_ -> False
columns = case action of
ActDb (ActRelationMut _ MutationCreate) -> qsColumns
ActDb (ActRelationMut _ MutationUpdate) -> qsColumns
ActDb (ActRoutine _ Inv) -> qsColumns
_ -> Nothing
isProc = case action of
ActDb (ActRoutine _ _) -> True
_ -> False
params = (T.decodeUtf8 *** T.decodeUtf8) <$> parseSimpleQuery (LBS.toStrict reqBody)
type CsvData = V.Vector (M.Map Text LBS.ByteString)
{-|
Converts CSV like
a,b
1,hi
2,bye
into a JSON array like
[ {"a": "1", "b": "hi"}, {"a": 2, "b": "bye"} ]
The reason for its odd signature is so that it can compose
directly with CSV.decodeByName
-}
csvToJson :: (CSV.Header, CsvData) -> JSON.Value
csvToJson (_, vals) =
JSON.Array $ V.map rowToJsonObj vals
where
rowToJsonObj = JSON.Object . KM.fromMapText .
M.map (\str ->
if str == "NULL"
then JSON.Null
else JSON.String . T.decodeUtf8 $ LBS.toStrict str
)
payloadAttributes :: RequestBody -> JSON.Value -> Maybe Payload
payloadAttributes raw json =
-- Test that Array contains only Objects having the same keys
case json of
JSON.Array arr ->
case arr V.!? 0 of
Just (JSON.Object o) ->
let canonicalKeys = S.fromList $ K.toText <$> KM.keys o
areKeysUniform = all (\case
JSON.Object x -> S.fromList (K.toText <$> KM.keys x) == canonicalKeys
_ -> False) arr in
if areKeysUniform
then Just $ ProcessedJSON raw canonicalKeys
else Nothing
Just _ -> Nothing
Nothing -> Just emptyPJArray
JSON.Object o -> Just $ ProcessedJSON raw (S.fromList $ K.toText <$> KM.keys o)
-- truncate everything else to an empty array.
_ -> Just emptyPJArray
where
emptyPJArray = ProcessedJSON (JSON.encode emptyArray) S.empty
+138
View File
@@ -0,0 +1,138 @@
-- |
-- Module : PostgREST.ApiRequest.Payload
-- Description : Parser for PostgREST Request Body
--
-- This module is in charge of parsing the request body (payload)
--
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
module PostgREST.ApiRequest.Payload
( getPayload
) where
import qualified Data.Aeson as JSON
import qualified Data.Aeson.Key as K
import qualified Data.Aeson.KeyMap as KM
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Csv as CSV
import qualified Data.HashMap.Strict as HM
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import qualified Data.Text.Encoding as T
import qualified Data.Vector as V
import Control.Arrow ((***))
import Data.Aeson.Types (emptyArray, emptyObject)
import Data.Either.Combinators (mapBoth)
import Network.HTTP.Types.URI (parseSimpleQuery)
import PostgREST.ApiRequest.QueryParams (QueryParams (..))
import PostgREST.ApiRequest.Types
import PostgREST.Error (ApiRequestError (..))
import PostgREST.MediaType (MediaType (..))
import PostgREST.SchemaCache.Identifiers (FieldName)
import qualified PostgREST.MediaType as MediaType
import Protolude
getPayload :: RequestBody -> MediaType -> QueryParams -> Action -> Either ApiRequestError (Maybe Payload, S.Set FieldName)
getPayload reqBody contentMediaType QueryParams{qsColumns} action = do
checkedPayload <- if shouldParsePayload then payload else Right Nothing
let cols = case (checkedPayload, columns) of
(Just ProcessedJSON{payKeys}, _) -> payKeys
(Just ProcessedUrlEncoded{payKeys}, _) -> payKeys
(Just RawJSON{}, Just cls) -> cls
_ -> S.empty
return (checkedPayload, cols)
where
payload :: Either ApiRequestError (Maybe Payload)
payload = mapBoth InvalidBody Just $ case (contentMediaType, isProc) of
(MTApplicationJSON, _) ->
if isJust columns
then Right $ RawJSON reqBody
else note "All object keys must match" . payloadAttributes reqBody
=<< if LBS.null reqBody && isProc
then Right emptyObject
else first BS.pack $
-- Drop parsing error message in favor of generic one (https://github.com/PostgREST/postgrest/issues/2344)
maybe (Left "Empty or invalid json") Right $ JSON.decode reqBody
(MTTextCSV, _) -> do
json <- csvToJson <$> first BS.pack (CSV.decodeByName reqBody)
note "All lines must have same number of fields" $ payloadAttributes (JSON.encode json) json
(MTUrlEncoded, True) ->
Right $ ProcessedUrlEncoded params (S.fromList $ fst <$> params)
(MTUrlEncoded, False) ->
let paramsMap = HM.fromList $ (identity *** JSON.String) <$> params in
Right $ ProcessedJSON (JSON.encode paramsMap) $ S.fromList (HM.keys paramsMap)
(MTTextPlain, True) -> Right $ RawPay reqBody
(MTTextXML, True) -> Right $ RawPay reqBody
(MTOctetStream, True) -> Right $ RawPay reqBody
(ct, _) -> Left $ "Content-Type not acceptable: " <> MediaType.toMime ct
shouldParsePayload = case action of
ActDb (ActRelationMut _ MutationDelete) -> False
ActDb (ActRelationMut _ _) -> True
ActDb (ActRoutine _ Inv) -> True
_ -> False
columns = case action of
ActDb (ActRelationMut _ MutationCreate) -> qsColumns
ActDb (ActRelationMut _ MutationUpdate) -> qsColumns
ActDb (ActRoutine _ Inv) -> qsColumns
_ -> Nothing
isProc = case action of
ActDb (ActRoutine _ _) -> True
_ -> False
params = (T.decodeUtf8 *** T.decodeUtf8) <$> parseSimpleQuery (LBS.toStrict reqBody)
type CsvData = V.Vector (M.Map Text LBS.ByteString)
{-|
Converts CSV like
a,b
1,hi
2,bye
into a JSON array like
[ {"a": "1", "b": "hi"}, {"a": 2, "b": "bye"} ]
The reason for its odd signature is so that it can compose
directly with CSV.decodeByName
-}
csvToJson :: (CSV.Header, CsvData) -> JSON.Value
csvToJson (_, vals) =
JSON.Array $ V.map rowToJsonObj vals
where
rowToJsonObj = JSON.Object . KM.fromMapText .
M.map (\str ->
if str == "NULL"
then JSON.Null
else JSON.String . T.decodeUtf8 $ LBS.toStrict str
)
payloadAttributes :: RequestBody -> JSON.Value -> Maybe Payload
payloadAttributes raw json =
-- Test that Array contains only Objects having the same keys
case json of
JSON.Array arr ->
case arr V.!? 0 of
Just (JSON.Object o) ->
let canonicalKeys = S.fromList $ K.toText <$> KM.keys o
areKeysUniform = all (\case
JSON.Object x -> S.fromList (K.toText <$> KM.keys x) == canonicalKeys
_ -> False) arr in
if areKeysUniform
then Just $ ProcessedJSON raw canonicalKeys
else Nothing
Just _ -> Nothing
Nothing -> Just emptyPJArray
JSON.Object o -> Just $ ProcessedJSON raw (S.fromList $ K.toText <$> KM.keys o)
-- truncate everything else to an empty array.
_ -> Just emptyPJArray
where
emptyPJArray = ProcessedJSON (JSON.encode emptyArray) S.empty
+6 -1
View File
@@ -19,6 +19,7 @@ module PostgREST.ApiRequest.Preferences
, PreferMaxAffected(..)
, fromHeaders
, shouldCount
, shouldExplainCount
, prefAppliedHeader
) where
@@ -155,7 +156,7 @@ fromHeaders allowTxDbOverride acceptedTzNames headers =
listStripPrefix prefix prefList = listToMaybe $ mapMaybe (BS.stripPrefix prefix) prefList
timezonePref = listStripPrefix "timezone=" prefs
isTimezonePrefAccepted = (S.member <$> (decodeUtf8 <$> timezonePref) <*> pure acceptedTzNames) == Just True
isTimezonePrefAccepted = ((S.member . decodeUtf8 <$> timezonePref) <*> pure acceptedTzNames) == Just True
maxAffectedPref = listStripPrefix "max-affected=" prefs >>= readMaybe . BS.unpack
@@ -238,6 +239,10 @@ shouldCount :: Maybe PreferCount -> Bool
shouldCount prefCount =
prefCount == Just ExactCount || prefCount == Just EstimatedCount
shouldExplainCount :: Maybe PreferCount -> Bool
shouldExplainCount prefCount =
prefCount == Just PlannedCount || prefCount == Just EstimatedCount
-- | Whether to commit or roll back transactions.
data PreferTransaction
= Commit -- ^ Commit transaction - the default.
+58 -1
View File
@@ -30,12 +30,69 @@ module PostgREST.ApiRequest.Types
, QuantOperator(..)
, FtsOperator(..)
, SelectItem(..)
, Payload (..)
, InvokeMethod (..)
, Mutation (..)
, Resource (..)
, DbAction (..)
, Action (..)
, RequestBody
) where
import PostgREST.SchemaCache.Identifiers (FieldName)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Set as S
import PostgREST.SchemaCache.Identifiers (FieldName,
QualifiedIdentifier (..),
Schema)
import Protolude
data InvokeMethod = Inv | InvRead Bool
deriving Eq
data Mutation
= MutationCreate
| MutationDelete
| MutationSingleUpsert
| MutationUpdate
deriving Eq
data Resource
= ResourceRelation Text
| ResourceRoutine Text
| ResourceSchema
data DbAction
= ActRelationRead {dbActQi :: QualifiedIdentifier, actHeadersOnly :: Bool}
| ActRelationMut {dbActQi :: QualifiedIdentifier, actMutation :: Mutation}
| ActRoutine {dbActQi :: QualifiedIdentifier, actInvMethod :: InvokeMethod}
| ActSchemaRead Schema Bool
data Action
= ActDb DbAction
| ActRelationInfo QualifiedIdentifier
| ActRoutineInfo QualifiedIdentifier InvokeMethod
| ActSchemaInfo
type RequestBody = LBS.ByteString
data Payload
= ProcessedJSON -- ^ Cached attributes of a JSON payload
{ payRaw :: LBS.ByteString
-- ^ This is the raw ByteString that comes from the request body. We
-- cache this instead of an Aeson Value because it was detected that for
-- large payloads the encoding had high memory usage, see
-- https://github.com/PostgREST/postgrest/pull/1005 for more details
, payKeys :: S.Set Text
-- ^ Keys of the object or if it's an array these keys are guaranteed to
-- be the same across all its objects
}
| ProcessedUrlEncoded { payArray :: [(Text, Text)], payKeys :: S.Set Text }
| RawJSON { payRaw :: LBS.ByteString }
| RawPay { payRaw :: LBS.ByteString }
-- | The value in `/tbl?select=alias:field.aggregateFunction()::cast`
data SelectItem
= SelectField
+146 -59
View File
@@ -9,18 +9,25 @@ Some of its functionality includes:
- Producing HTTP Headers according to RFCs.
- Content Negotiation
-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
module PostgREST.App
( postgrest
, run
) where
import GHC.IO.Exception (IOErrorType (..))
import System.IO.Error (ioeGetErrorType)
import Control.Monad.Except (liftEither)
import Control.Monad.Extra (whenJust)
import Data.Either.Combinators (mapLeft, whenLeft)
import Data.Maybe (fromJust)
import Data.String (IsString (..))
import Network.Wai.Handler.Warp (defaultSettings, setHost, setPort,
import Network.Wai.Handler.Warp (defaultSettings, setHost,
setOnException, setPort,
setServerName)
import qualified Data.Text.Encoding as T
@@ -35,6 +42,7 @@ import qualified PostgREST.Cors as Cors
import qualified PostgREST.Error as Error
import qualified PostgREST.Listener as Listener
import qualified PostgREST.Logger as Logger
import qualified PostgREST.MainTx as MainTx
import qualified PostgREST.Plan as Plan
import qualified PostgREST.Query as Query
import qualified PostgREST.Response as Response
@@ -43,49 +51,68 @@ import qualified PostgREST.Unix as Unix (installSignalHandlers)
import PostgREST.ApiRequest (ApiRequest (..))
import PostgREST.AppState (AppState)
import PostgREST.Auth.Types (AuthResult (..))
import PostgREST.Config (AppConfig (..), LogLevel (..),
LogQuery (..))
import PostgREST.Config.PgVersion (PgVersion (..))
import PostgREST.Config (AppConfig (..), LogLevel (..))
import PostgREST.Error (Error)
import PostgREST.Network (resolveHost)
import PostgREST.Network (resolveSocketToAddress)
import PostgREST.Observation (Observation (..))
import PostgREST.Response.Performance (ServerTiming (..),
serverTimingHeader)
import PostgREST.SchemaCache (SchemaCache (..))
import PostgREST.TimeIt (timeItT)
import PostgREST.Version (docsVersion, prettyVersion)
import qualified Data.ByteString.Char8 as BS
import qualified Data.List as L
import qualified Network.HTTP.Types as HTTP
import qualified Network.Socket as NS
import Protolude hiding (Handler)
import System.TimeIt (timeItT)
import qualified Data.ByteString.Char8 as BS
import qualified Data.List as L
import Data.Streaming.Network (bindPortTCP,
bindRandomPortTCP)
import qualified Data.Text as T
import qualified Network.HTTP.Types as HTTP
import qualified Network.HTTP.Types.Header as HTTP (hVary)
import qualified Network.Socket as NS
import PostgREST.Unix (createAndBindDomainSocket)
import Protolude hiding (Handler)
type Handler = ExceptT Error
run :: AppState -> IO ()
run appState = do
let observer = AppState.getObserver appState
conf@AppConfig{..} <- AppState.getConfig appState
AppState.schemaCacheLoader appState -- Loads the initial SchemaCache
Unix.installSignalHandlers (AppState.getMainThreadId appState) (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState)
(mainSocket, adminSocket) <- initSockets conf
let closeSockets = do
whenJust adminSocket NS.close
NS.close mainSocket
Unix.installSignalHandlers observer closeSockets (AppState.schemaCacheLoader appState) (AppState.readInDbConfig False appState)
Listener.runListener appState
Admin.runAdmin appState (serverSettings conf)
Admin.runAdmin appState adminSocket mainSocket (serverSettings conf)
let app = postgrest configLogLevel appState (AppState.schemaCacheLoader appState)
case configServerUnixSocket of
Just path -> do
observer $ AppServerUnixObs path
Nothing -> do
port <- NS.socketPort $ AppState.getSocketREST appState
host <- resolveHost $ AppState.getSocketREST appState
observer $ AppServerPortObs (fromJust host) port
do
address <- resolveSocketToAddress mainSocket
observer $ AppServerAddressObs address
Warp.runSettingsSocket (serverSettings conf) (AppState.getSocketREST appState) app
Warp.runSettingsSocket (serverSettings conf & setOnException onWarpException) mainSocket app
where
observer = AppState.getObserver appState
onWarpException :: Maybe Wai.Request -> SomeException -> IO ()
onWarpException _ ex =
when (shouldDisplayException ex) $
observer $ WarpServerObs $ show ex
-- Similar to wai defaultShouldDisplayException in
-- https://github.com/yesodweb/wai//blob/8c3882c60f6abe043889fc20c7efd3fa9747fa4a/warp/Network/Wai/Handler/Warp/Settings.hs#L251-L258
-- but without omitting AsyncException since it's important to log for ThreadKilled, StackOverflow and other cases.
-- We want to reuse this to avoid flooding the logs for some transient failure cases.
shouldDisplayException :: SomeException -> Bool
shouldDisplayException se
| Just (_ :: Warp.InvalidRequest) <- fromException se = False
| Just (ioeGetErrorType -> et) <- fromException se, et == ResourceVanished || et == InvalidArgument = False
| otherwise = True
serverSettings :: AppConfig -> Warp.Settings
serverSettings AppConfig{..} =
@@ -103,42 +130,48 @@ postgrest logLevel appState connWorker =
Logger.middleware logLevel Auth.getRole $
-- fromJust can be used, because the auth middleware will **always** add
-- some AuthResult to the vault.
\req respond -> case fromJust $ Auth.getResult req of
Left err -> respond $ Error.errorResponseFor err
Right authResult -> do
appConf <- AppState.getConfig appState -- the config must be read again because it can reload
maybeSchemaCache <- AppState.getSchemaCache appState
pgVer <- AppState.getPgVersion appState
\req respond -> do
appConf@AppConfig{..} <- AppState.getConfig appState -- the config must be read again because it can reload
case fromJust $ Auth.getResult req of
Left err -> respond $ Error.errorResponseFor configClientErrorVerbosity err
Right authResult -> do
maybeSchemaCache <- AppState.getSchemaCache appState
let
eitherResponse :: IO (Either Error Wai.Response)
eitherResponse =
runExceptT $ postgrestResponse appState appConf maybeSchemaCache pgVer authResult req
let
eitherResponse :: IO (Either Error Wai.Response)
eitherResponse =
runExceptT $ postgrestResponse appState appConf maybeSchemaCache authResult req
response <- either Error.errorResponseFor identity <$> eitherResponse
-- Launch the connWorker when the connection is down. The postgrest
-- function can respond successfully (with a stale schema cache) before
-- the connWorker is done.
when (isServiceUnavailable response) connWorker
resp <- do
delay <- AppState.getNextDelay appState
return $ addRetryHint delay response
respond resp
response <- either (Error.errorResponseFor configClientErrorVerbosity) identity <$> eitherResponse
-- Launch the connWorker when the connection is down. The postgrest
-- function can respond successfully (with a stale schema cache) before
-- the connWorker is done. However, when there's an empty schema cache
-- postgrest responds with the error `PGRST002`; this means that the schema
-- cache is still loading, so we don't launch the connWorker here because
-- it would duplicate the loading process, e.g. https://github.com/PostgREST/postgrest/issues/3704
-- TODO: this process may be unnecessary when the Listener is enabled. Revisit once https://github.com/PostgREST/postgrest/issues/1766 is done
when (isServiceUnavailable response && isJust maybeSchemaCache) connWorker
resp <- do
delay <- AppState.getNextDelay appState
return $ addRetryHint delay response
respond resp
postgrestResponse
:: AppState.AppState
-> AppConfig
-> Maybe SchemaCache
-> PgVersion
-> AuthResult
-> Wai.Request
-> Handler IO Wai.Response
postgrestResponse appState conf@AppConfig{..} maybeSchemaCache pgVer authResult@AuthResult{..} req = do
postgrestResponse appState conf@AppConfig{..} maybeSchemaCache authResult@AuthResult{..} req = do
let observer = AppState.getObserver appState
sCache <-
case maybeSchemaCache of
Just sCache ->
return sCache
Nothing ->
Nothing -> do
lift $ observer SchemaCacheEmptyObs
throwError Error.NoSchemaCacheError
body <- lift $ Wai.strictRequestBody req
@@ -147,31 +180,49 @@ postgrestResponse appState conf@AppConfig{..} maybeSchemaCache pgVer authResult@
timezones = dbTimezones sCache
prefs = ApiRequest.userPreferences conf req timezones
(parseTime, apiReq@ApiRequest{..}) <- withTiming $ liftEither . mapLeft Error.ApiRequestError $ ApiRequest.userApiRequest conf prefs req body
(parseTime, apiReq@ApiRequest{..}) <- withTiming $ liftEither . mapLeft Error.ApiRequestErr $ ApiRequest.userApiRequest conf prefs req body
(planTime, plan) <- withTiming $ liftEither $ Plan.actionPlan iAction conf apiReq sCache
let query = Query.query conf authResult apiReq plan sCache pgVer
logSQL = lift . AppState.getObserver appState . DBQuery (Query.getSQLQuery query)
let mainQ = Query.mainQuery plan conf apiReq authResult configDbPreRequest
tx = MainTx.mainTx mainQ conf authResult apiReq plan sCache
obsQuery s = when configLogQuery $ observer $ QueryObs mainQ s
(queryTime, queryResult) <- withTiming $ do
case query of
Query.NoDbQuery r -> pure r
Query.DbQuery{..} -> do
(txTime, txResult) <- withTiming $ do
case tx of
MainTx.NoDbTx r -> pure r
MainTx.DbTx{..} -> do
dbRes <- lift $ AppState.usePool appState (dqTransaction dqIsoLevel dqTxMode $ runExceptT dqDbHandler)
let eitherResp = mapLeft Error.PgErr . mapLeft (Error.PgError (Just authRole /= configDbAnonRole)) $ dbRes
when (configLogQuery /= LogQueryDisabled) $ whenLeft eitherResp $ logSQL . Error.status
liftEither eitherResp >>= liftEither
let eitherResp = join $ mapLeft (Error.PgErr . Error.PgError (Just authRole /= configDbAnonRole)) dbRes
-- TODO: we use obsQuery twice, one here and one below because in case of an error with the usePool above, the request will finish here and return an error message.
-- This is because of a combination of ExceptT + our Error module which has Wai.responseLBS.
-- This needs refactoring so only the below obsQuery is used.
lift $ whenLeft eitherResp $ obsQuery . Error.status
liftEither eitherResp
(respTime, resp) <- withTiming $ do
let response = Response.actionResponse queryResult apiReq (T.decodeUtf8 prettyVersion, docsVersion) conf sCache iSchema iNegotiatedByProfile
when (configLogQuery /= LogQueryDisabled) $ logSQL $ either Error.status Response.pgrstStatus response
let response = Response.actionResponse txResult apiReq (T.decodeUtf8 prettyVersion, docsVersion) conf sCache
status' = either Error.status Response.pgrstStatus response
-- TODO: see above obsQuery, only this obsQuery should remain after refactoring (because the QueryObs depends on the status)
lift $ obsQuery status'
liftEither response
return $ toWaiResponse (ServerTiming jwtTime parseTime planTime queryTime respTime) resp
return $ toWaiResponse (ServerTiming jwtTime parseTime planTime txTime respTime) resp
where
toWaiResponse :: ServerTiming -> Response.PgrstResponse -> Wai.Response
toWaiResponse timing (Response.PgrstResponse st hdrs bod) = Wai.responseLBS st (hdrs ++ ([serverTimingHeader timing | configServerTimingEnabled])) bod
toWaiResponse timing (Response.PgrstResponse st hdrs bod) =
Wai.responseLBS st (hdrs ++ serverTimingHeaders timing ++ [varyHeader | not $ varyHeaderPresent hdrs]) bod
serverTimingHeaders :: ServerTiming -> [HTTP.Header]
serverTimingHeaders timing = [serverTimingHeader timing | configServerTimingEnabled]
varyHeader :: HTTP.Header
varyHeader = (HTTP.hVary, "Accept, Prefer, Range")
varyHeaderPresent :: [HTTP.Header] -> Bool
varyHeaderPresent = any (\(h, _v) -> h == HTTP.hVary)
withTiming :: Handler IO a -> Handler IO (Maybe Double, a)
withTiming f = if configServerTimingEnabled
@@ -199,3 +250,39 @@ addRetryHint delay response = do
isServiceUnavailable :: Wai.Response -> Bool
isServiceUnavailable response = Wai.responseStatus response == HTTP.status503
type AppSockets = (NS.Socket, Maybe NS.Socket)
initSockets :: AppConfig -> IO AppSockets
initSockets AppConfig{..} = do
let
cfg'usp = configServerUnixSocket
cfg'uspm = configServerUnixSocketMode
cfg'host = configServerHost
cfg'port = configServerPort
cfg'adminHost = configAdminServerHost
cfg'adminPort = configAdminServerPort
sock <- case cfg'usp of
-- I'm not using `streaming-commons`' bindPath function here because it's not defined for Windows,
-- but we need to have runtime error if we try to use it in Windows, not compile time error
Just path -> createAndBindDomainSocket path cfg'uspm
Nothing -> do
(_, sock) <-
if cfg'port /= 0
then do
sock <- bindPortTCP cfg'port (fromString $ T.unpack cfg'host)
pure (cfg'port, sock)
else do
-- explicitly bind to a random port, returning bound port number
(num, sock) <- bindRandomPortTCP (fromString $ T.unpack cfg'host)
pure (num, sock)
pure sock
adminSock <- case cfg'adminPort of
Just adminPort -> do
adminSock <- bindPortTCP adminPort (fromString $ T.unpack cfg'adminHost)
pure $ Just adminSock
Nothing -> pure Nothing
pure (sock, adminSock)

Some files were not shown because too many files have changed in this diff Show More