Compare commits

...
700 Commits
Author SHA1 Message Date
Taimoor Zaeem 02d83d1c01 test(io): move remaining tests in test_io.py to their modules
We had just 3 tests remaining in test_io.py. This commit moves them to
their modules. So we have:

* test_graceful_shutdown.py

* test_zero_downtime.py

* test_pg_internal.py

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-13 03:42:29 +05:00
Taimoor Zaeem e89e0bc255 test(io): move config related behavior tests to test_config.py
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-13 03:42:29 +05:00
Taimoor Zaeem 9e20e5df90 test(io): move logs and observations tests to test_log.py
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-13 03:42:29 +05:00
Taimoor Zaeem 2122dcef97 test(io): move connection related tests to test_connection.py
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-13 03:42:29 +05:00
Taimoor Zaeem d84d00be8e test(io): move reloading related tests to test_reloading.py
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-13 03:42:29 +05:00
Taimoor ZaeemandSteve Chavez 3a034fcc2a chore: add changelog entry for v16.1
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-12 10:14:34 -05:00
Michał KłeczekandSteve Chavez a2a592a617 fix: JWT validation uses wrong current time due to a bug in auto-update
Upgrade auto-update to 0.2.7 which contains a fix to a bug causing some threads not seeing updates to the cached values.
2026-08-10 17:20:56 -05:00
Taimoor ZaeemandWolfgang Walther 89fe63fce0 nix(release): automate updating source file links in the docs
Closes #5133.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-10 19:14:04 +00:00
steve-chavez f21949a517 chore(changelog): missed entry for ghcr 2026-08-07 19:15:50 -05:00
steve-chavez 6ead34e70b chore(changelog): add integrations section
Also clarify some parts.
2026-08-07 16:17:56 -05:00
steve-chavezandWolfgang Walther e3206262d2 chore(changelog): make it in postgres style
This is to make it easier for users to understand the changes,
much like PostgreSQL does for its changelog: https://www.postgresql.org/docs/19/release-19.html#RELEASE-19-SERVER
(see how they classify "Optimizer", "General Performance", etc).

We classify features, fixes and deprecation in subsections.
Breaking changes are put inside a "Migration to v16" guide.
2026-08-07 19:59:15 +00:00
Taimoor Zaeem a3f36d6184 test: fix failing test of legacy target names warning
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-07 22:47:09 +05:00
renovate[bot]andWolfgang Walther 6cc1698c05 chore(deps): update vmactions/freebsd-vm action to v1.5.3 2026-08-07 07:43:06 +00:00
Wolfgang Walther 77d6055683 chore: bump version to 17 2026-08-07 09:33:46 +02:00
Wolfgang Walther 05d1e0f83d chore: bump version to 16.0 2026-08-07 09:33:45 +02:00
Wolfgang Walther 6fdc230637 nix: remove outdated code / comment in release script 2026-08-07 09:33:29 +02:00
Wolfgang Walther a841dc9c39 chore: ignore stackoverflow in linkcheck
Seems like stackoverflow started blocking GHA runners as well.
2026-08-07 09:14:33 +02:00
steve-chavez 18371ec372 chore(changelog): clarified JSON Path feature 2026-08-06 18:36:16 -05:00
steve-chavez 6951e1301d docs: keep working when scache reload fails
Docs for 54430c3a2c
2026-08-06 17:54:23 -05:00
steve-chavez 75891975f5 docs: fix wrong ref in admin 2026-08-06 17:24:56 -05:00
steve-chavez 142b54158e docs: graceful shutdown docs
Considered the explanations and use cases on:

- https://github.com/yesodweb/wai/issues/853
- https://github.com/PostgREST/postgrest/pull/4580
2026-08-06 17:24:53 -05:00
steve-chavez 876dfad9d9 chore(changelog): move fixed entry to added
Graceful shutdown is really a feature
2026-08-06 17:19:45 -05:00
steve-chavez 2ad6d239a0 docs: add new http server page 2026-08-06 17:19:45 -05:00
Taimoor Zaeem 426e15bbb4 chore(cabal): update haskell language edition to GHC2021
This includes a good set of default language extensions that are
often used by us. It frees us of explicitly importing common extensions.

Ref: https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/control.html#extension-GHC2021

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-05 12:38:29 +05:00
steve-chavez 7e8212870d docs: release cycle 2026-08-04 19:49:48 -05:00
renovate[bot]andWolfgang Walther 6a9c99d54e chore(deps): update haskell-actions/setup action to v2.12.0 2026-08-04 21:05:25 +00:00
steve-chavez e44178445d docs: timezone offsets 2026-08-04 13:41:40 -05:00
steve-chavez 59a644bb99 test: prefer timezone offsets 2026-08-04 13:41:40 -05:00
steve-chavez 932c4f6328 perf: no caching for prefer timezone
`Prefer: timezone` no longer requires the schema cache.
Previously this required caching `pg_timezone_names` which was slow in some systems.

Closes https://github.com/PostgREST/postgrest/issues/5100 and
https://github.com/PostgREST/postgrest/issues/4751.
2026-08-04 13:41:40 -05:00
steve-chavez a41396c425 Revert "add: config db-timezone-enabled for optional querying of timezones"
This reverts commit d6c338d588.
2026-08-04 13:41:40 -05:00
steve-chavez ca4a6d9e99 Revert "add: configs as json GUC for db-root-spec"
This reverts commit f34ca15e84.
2026-08-04 00:50:18 -05:00
steve-chavez f34ca15e84 add: configs as json GUC for db-root-spec
These are needed for a complete OpenAPI spec
2026-08-03 23:41:03 -05:00
Wolfgang Walther f84c44dafa nix: add postgrest-with-oriole-18 2026-08-02 14:51:50 +00:00
Wolfgang Walther 549ab36c30 docs: add NixOS integration section
Just a very basic example of how to use the NixOS module that Nixpkgs
provides.
2026-08-02 14:51:50 +00:00
Wolfgang Walther 42754cb6c9 chore(deps): update nixpkgs pin
Nixpkgs has removed support for x86_64-darwin, so removing that from
CI's flake check.

A x86_64-darwin binary is still built via Stack.
2026-08-02 14:51:50 +00:00
Wolfgang Walther 57e8d20811 nix: show stderr output for postgrest-style
Hiding this will also hide errors when they happen...

In my case, my nix-shell's TMPDIR was too long, so black was failing
silently because it couldn't create a unix socket for its forkserver.
2026-08-02 14:51:50 +00:00
Taimoor ZaeemandWolfgang Walther 8ede8fb0dc test(io): move settings related tests to test_settings.py
Towards #4946.

Moves app and pg settings related tests from test_io.py to
test_settings.py.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-08-02 11:53:32 +00:00
Joel JacobsonandWolfgang Walther 131df9b578 perf: use pg_basetype on PG 17+ for schema cache 2026-08-02 11:47:26 +00:00
Taimoor Zaeem 6a7ad33524 fix: db-channel-enabled not reloadable on config reload
Fixes #4894.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-31 21:39:27 +05:00
Taimoor Zaeem b174295bf2 refactor(chore): rename conf to oldConf in readInDbConfig function
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-31 21:39:27 +05:00
renovate[bot]andWolfgang Walther 6304265cd9 chore(deps): update docker/login-action action to v4.6.0 2026-07-30 20:41:39 +00:00
Taimoor Zaeem cb9b00d374 docs: update link of listener in architecture page
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-30 11:23:56 +05:00
Taimoor Zaeem 59081195f0 chore: add changelog entry for v14.16
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-28 23:31:31 +05:00
Taimoor Zaeem 022f0faa38 add: make config log-level reloadable
Closes #5113.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-28 11:33:33 +05:00
Taimoor Zaeem f6d34fd4fc refactor: move reloading related logic to Reload.hs
This commit moves, schema cache reload, config reload and listener
reload logic to `Reload.hs` module.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-25 14:39:48 +05:00
Taimoor Zaeem e32e2b07b5 refactor: move connection pool functions to Pool.hs
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-25 14:39:48 +05:00
Taimoor Zaeem a108d66968 refactor: move AppState type and update functions to AppState/Types.hs
`AppState.hs` is imported by many modules. Some of those modules contain
important functions that need to be imported back to `AppState.hs`, causing
circular dependency problem.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-25 14:39:48 +05:00
renovate[bot]andWolfgang Walther e820cc7370 chore(deps): update docker/login-action action to v4.5.1 2026-07-24 19:26:16 +00:00
renovate[bot]andWolfgang Walther 74c8a3580d chore(deps): update vmactions/freebsd-vm action to v1.5.2 2026-07-24 18:51:13 +00:00
steve-chavez 03c67f3410 test: move psql_as_superuser as util and reuse it 2026-07-24 13:44:58 -05:00
renovate[bot]andWolfgang Walther 1d195bf865 chore(deps): update docker/login-action action to v4.5.0 2026-07-23 20:11:53 +00:00
renovate[bot]andWolfgang Walther 473734f717 chore(deps): update actions/checkout action to v7.0.1 2026-07-23 20:11:28 +00:00
Taimoor Zaeem 178b1d3e38 fix: kill postgrest main thread on admin server crash
Fixes #5096.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-21 20:53:40 +05:00
Taimoor Zaeem 080abcb695 chore: increase columns length in .stylish-haskell.yaml
This gives the import statements more space, essentially, it collectively
removes 90+ unneeded lines in the imports statements.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-19 20:56:12 +05:00
Taimoor ZaeemandWolfgang Walther 8faf9c0519 test: resolve pytest warning when running io tests
When running `postgrest-test-io`, pytest raises a `InsecureKeyLengthWarning`
for a test. To clear that warning, this commit increases the key length to
more than 32 characters.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-17 17:42:51 +00:00
Taimoor Zaeem f81dd29cd1 chore: build haskell source modules in parallel
`postgrest-build` now builds twice as fast as compared to previous
build time. This can be tested by running `rm -rf dist-newstyle/` and
then run `postgrest-build`.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-16 13:34:59 +05:00
Michał KłeczekandSteve Chavez c297d051dc add: use SO_REUSEPORT on platform supporting it 2026-07-15 11:51:21 -05:00
Wolfgang Walther de19b04fe4 amend(aa7d442d): fix docs link to new Main.hs location 2026-07-15 08:55:19 +02:00
Taimoor Zaeem 51e9fd6efd fix: schema cache dump missing RPC transaction isolation level
Fixes #5079.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-14 23:13:21 +05:00
Taimoor Zaeem 63a2267f53 chore: add changelog entry for v14.15
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-14 21:04:15 +05:00
Wolfgang Walther aa7d442d32 chore: move executable code to src/
src/ now contains all source code - in subdirectories, according to the
.cabal component they belong to. This will allow us to put vendored
libraries in the same place - and later split our own code into multiple
components/libraries as well.
2026-07-14 06:58:15 +00:00
Wolfgang Walther 44e15e4e9b chore: run doctests in parallel
Runs the doctests much faster, which is potentially useful in
combination with postgrest-watch for local development.

This implies that doctests run on compiled code, not in a GHCi session,
which has some implications:
- Only exported functions can be tested.
- Imports need to be made explicit in doctests themselves.

On the flipside, this would allow us to potentially include doctest
results in code coverage, I believe.

This change is a requirement to vendor hasql, which otherwise breaks the
existing doctests: hasql contains a .hsc file, which *needs* to be
compiled - not interpreted - to make the tests work.
2026-07-14 06:55:32 +00:00
Wolfgang Walther aa6c19ebda test: remove useless doctest in Network.hs
This essentially just tests upstream's show instance.
2026-07-14 06:55:32 +00:00
Taimoor ZaeemandWolfgang Walther 8776ece7d5 test(io): move admin server tests to test_admin.py
Towards #4946.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-11 19:20:59 +00:00
steve-chavez 205135853d amend: update cabal index so cabal build succeeds 2026-07-11 13:24:09 -05:00
steve-chavez a71ab36096 amend: use warp 3.4.14 for 3522917
Use a release instead of a git commit
2026-07-11 13:12:03 -05:00
steve-chavezandLaurence Isla 490d1dc5d3 add: config to emit warning for legacy target names
Adds the `url_use_legacy_target_names` config.

Enabled (default):
* It allows using the resource name in filters,
  orders or limits when it has an alias, e.g.
  `table?select=alias:target(*)&target.id=eq.1`
* Logs a WARNING with a hint to use the alias
* Returns a Warning header in the response

Disabled:
* It returns an error, only the alias is allowed
* No warnings returned

This feature is deprecated
2026-07-11 02:15:07 +00:00
steve-chavez 2fa8de4e52 chore: add changelog entry for 5077 2026-07-10 19:54:11 -05:00
steve-chavez 3522917021 fix: admin server dies silently by upgrading warp
Uses warp main branch https://github.com/yesodweb/wai/commit/ad041216b643f69a2a9c87cbf4c2988aa4633dd5
since there's no release yet.
2026-07-10 17:56:15 -05:00
Michał KłeczekandSteve Chavez 4fc47754c2 refactor: do not open a TCP connection in liveness check
This change introduces a new way to perform liveness check - instead of trying to open a TCP connection to main server, we check if main socket is listening and if main server accept loop thread is alive.

Opening a TCP connection in liveness check was problematic because:
* it used available file descriptors which might have been a problem under load
* made liveness check unreliable when multiple PostgREST instances are available on the same port (eg. using SO_REUSEPORT)
2026-07-10 12:45:59 -05:00
Taimoor Zaeem 0bda2bcdff refactor: remove redundant destroyPool function
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-08 21:09:20 +05:00
Taimoor Zaeem c03ac09dbb test: move prepared statements config related tests to spec tests
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-07 23:32:40 +05:00
Taimoor Zaeem 44edf962d8 test: move db-pre-config with pg reserved word func to spec tests
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-07 23:32:40 +05:00
Taimoor Zaeem 6670b1a4b6 test(io): add test to db-pre-config with non-existent function
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-07 23:32:40 +05:00
Taimoor Zaeem c73c676849 test: move error verbosity test from io tests to spec tests
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-07 23:32:40 +05:00
steve-chavez 6191243c64 ci: add git to freebsd
Otherwise when using a git commit on stack the build fails because it
lacks the git dependency.
2026-07-06 21:50:26 -05:00
Michał KłeczekandSteve Chavez c5c9dc33c9 refactor: make sure proper sockets cleanup is performed in App.run
Right now code in App.run does not properly use bracket/finally to close sockets and clean-up mainSocketRef. This is not a big problem at the moment because the application is going to exit enyway but introducting proper resource handling will make future refactorings safer.
2026-07-06 10:59:05 -05:00
Michał KłeczekandSteve Chavez 56df1dc532 refactor: encapsulate application termination
This change makes AppState and Listener modules independent from the way how application is terminated. It removes stateMainThreadId from AppState and introduces stateKillApp. It also removes exported  function AppState.getMainThreadId replacing it with more general killApp.
2026-07-06 10:29:17 -05:00
Michał KłeczekandSteve Chavez 06bda07db1 refactor: encapsulate how main application liveness check is done
This change makes Admin module independent from how liveness check is performed. It moves reachMainApp function to App module and makes Admin.runAdmin, instead of action to get the main socket, take an IO action checking liveness as a parameter.

Thanks to this, any change in how liveness check is performed and, more importantly, what data it uses, does not require changing multiple modules (Admin and App).
2026-07-05 15:22:37 -05:00
Wolfgang Walther 0bd2821937 chore(deps): update hackage freeze, stackage snapshot and nixpkgs pin
This brings in PostgreSQL 19 beta 1 to start testing against.
2026-07-05 12:50:14 +00:00
renovate[bot]andWolfgang Walther 936d9df13d chore(deps): update docker/login-action action to v4.4.0 2026-07-05 12:49:52 +00:00
Taimoor Zaeem 75b315d077 nix: provide default file name when generating module graph
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-07-05 00:44:05 +05:00
renovate[bot]andWolfgang Walther 76c1ec5b06 chore(deps): update docker/setup-buildx-action action to v4.2.0 2026-07-02 20:08:24 +00:00
renovate[bot]andWolfgang Walther a836fb5e37 chore(deps): update docker/login-action action to v4.3.0 2026-07-02 08:56:54 +00:00
ncikandWolfgang Walther 69d21a82c9 docs: fix example jwt expiration epoch
Issue: the example epoch date is wrapped in parentheses. This causes the server to return PGRST303: "The JWT 'exp' claim must be a number"

Fix: remove parentheses
2026-07-01 19:22:59 +00:00
steve-chavez 412c6a1d26 chore: mentions docs on CONTRIBUTING 2026-06-30 10:06:45 -05:00
renovate[bot]andWolfgang Walther 5a987c06fe chore(deps): update korthout/backport-action action to v4.6 2026-06-30 06:24:53 +00:00
Taimoor ZaeemandSteve Chavez af17a75ae1 chore: add changelog entry for v14.14
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-29 16:42:14 -05:00
renovate[bot]andWolfgang Walther 9f3dc46502 chore(deps): update vmactions/freebsd-vm action to v1.5.0 2026-06-29 17:46:01 +00:00
Taimoor ZaeemandSteve Chavez b967a5033a fix(admin): log admin server exceptions and close admin socket
Admin server was crashing silently and requests hang indefinitely.
With this fix, we are now logging the admin server exceptions and also
close the socket afterwards so admin request don't hang.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-29 12:43:54 -05:00
Taimoor Zaeem 18646a6c03 chore: enable GHC NumericUnderscores language extension
The `_` character between numeric literals improve their readablity.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-28 01:01:12 +05:00
Wolfgang Walther 84e2a0c829 nix(loadtest): generate targets at nix build time
Instead of generating them at loadtest runtime, we generate these
dynamic targets once via Nix. Because we're using libfaketime, we're not
bound to doing it at the same time as running the tests.

This allows us to run each loadtest right after each other, with minimal
other stuff going on inbetween. It's also a tiny bit more reproducible,
because the loadtests against both branches run with exactly the same
set of targets, where they did not before.
2026-06-27 18:01:50 +00:00
Wolfgang Walther f1649bf6ee nix(loadtest): run all target branches almost at the same time
Instead of building, running, building, running, ... we now build all
executables once ahead of time and then run all loadtests right after
each other. This can sometimes reduce noise when load on the GHA runner
varies over time.

Since this requires us to move building into the loadtest-against
script, it also allows to go back to have the regular postgrest-loadtest
command default to building with cabal for faster local iteration.
2026-06-27 18:01:50 +00:00
Wolfgang Walther bc5d7a0e92 nix: remove postgrest-git-hooks
I'm not sure whether anyone is actually using them, but they never
worked really well, I believe. We should add something based on an
existing pre-commit hook manager, not that brittle custom thing we have.

Allows me to remove postgrest-with-git in the next commit instead of
duplicating it.
2026-06-27 18:01:50 +00:00
Wolfgang Walther d5875c1554 nix(loadtest): refactor loadtest-against
No need to duplicate this code, all of it is right there.
2026-06-27 18:01:50 +00:00
Wolfgang Walther 576805b7b0 nix: remove hint about installing tools locally from README
This is a heavily discouraged way of using these tools - they will
become outdated almost immediately and would need to be reinstalled on
every change to main.
2026-06-27 18:01:30 +00:00
Wolfgang Walther 2b463ab1c6 nix: remove docker tools note from README
This is outdated, we don't have that docker argument anymore - docker
tools are exposed by default, when on Linux.
2026-06-27 18:01:30 +00:00
Wolfgang Walther 6f899ee493 nix: reduce list of commands in README
This list is chronically outdated and hard to maintain with the two
column layout. Simplify and reduce, not important to keep up-to-date to
bring the point across.
2026-06-27 18:01:30 +00:00
Wolfgang Walther 556a5dad47 chore: remove eol-whitespace in postgrest.cabal 2026-06-27 19:20:24 +02:00
renovate[bot]andWolfgang Walther cbaf5ac8fc chore(deps): update vmactions/freebsd-vm action to v1.4.9 2026-06-27 09:41:20 +00:00
renovate[bot]andWolfgang Walther 76261d5bfc chore(deps): update actions/cache action to v6.1.0 2026-06-26 19:48:22 +00:00
Wolfgang Walther dcc99040d6 nix(loadtest): run more requests in jwt-cache test
We don't need to restrict us to run every request once. Instead we can
run as many as possible within 60s by removing the `-lazy` flag.

This also allows us to generate fewer targets, because vegeta will do
the repetition for us.
2026-06-26 19:33:51 +00:00
Wolfgang Walther 07a9752866 nix(loadtest): remove jwt-cache-worst
This test is not really functional (anymore?). It depends on some tokens
expiring - but they don't, really. This is because:
1) Before merging the RSA and HS variants earlier in this patch series,
they ran roughly 15s and 34s respectively in CI.
2) Since PostgREST takes a clock skew of up to 30 seconds into account,
there would be *at most* 4s of expiring tokens in a test run - and
*only* in the HS case, not for RSA.
2026-06-26 19:33:51 +00:00
Wolfgang Walther 7cafa67f0a nix(loadtest): use faketime in jwt-cache test
While we didn't have much problem in this test, it's surely not a
problem either to make the test more reproducible with a fixed base
timestamp. This gives us a tiny bit less of a diff on the next change.
2026-06-26 19:33:51 +00:00
Wolfgang Walther 3909e85f67 nix(loadtest): remove jwt test
This test is not very interesting, really: It's hard to imagine to be
able to produce a regression that would slow down the no-cache case, but
would *not* show when a cache is used.
2026-06-26 19:33:51 +00:00
Wolfgang Walther e83a25a698 nix(loadtest): remove genKeyMaterials
Merge the same code into genTargets, which removes the need to save the
private key to disk and read it again.
2026-06-26 19:33:51 +00:00
Wolfgang Walther 32706284f0 nix(loadtest): refactor key selection
Just a bit simpler.
2026-06-26 19:33:51 +00:00
Wolfgang Walther a079d23de1 nix(loadtest): remove useless try/except blocks
Rethrowing the same error, but without stacktrace is not really useful,
but only makes the code (and debugging!) harder than it should be.
2026-06-26 19:33:51 +00:00
Wolfgang Walther d470213857 nix(loadtest): remove pyjwt dependency
Let's use the same dependency when creating key material and when
creating tokens, no need to carry multiple different dependencies and
converting keys between them.
2026-06-26 19:33:51 +00:00
Wolfgang Walther 1446f11222 nix(loadtest): refactor genTargets argument
Instead of passing a path to the output target file, just pass the
directory in which to create the file. This allows the script to create
multiple files later.
2026-06-26 19:33:51 +00:00
Wolfgang Walther ef72787907 nix(loadtest): remove left-over run_command helper
When we changed the test structure to use libfaketime, we moved away
from generating targets as part of the chained command running
with-pg/with-pgrst. This function was left-over from that, the
genTargets script does not need to relay its remaining arguments
arguments anymore.
2026-06-26 19:33:51 +00:00
Wolfgang Walther 66d40c0159 nix(loadtest): merge jwt-rsa-* and jwt-hs-* tests
Instead of creating separate test suites for the key type, the PostgREST
instance now accepts both keys via a JWKSet and the targets are
generated 50/50 for both.

The results are still reported seperately by using a different URL,
which shows up as separate rows in the results.
2026-06-26 19:33:51 +00:00
Wolfgang Walther 2d340e8a8c nix(loadtest): refactor generate_jwt -> generate_target
This makes the next change easier to do, but should be easier to review
step-by-step.
2026-06-26 19:33:51 +00:00
Wolfgang Walther 94be1b7250 nix(loadtest): remove --rsa option from genTargets
The public key is not needed for target generation, only the private
key, so it's enough to pass that.
2026-06-26 19:33:51 +00:00
Wolfgang Walther b32c477b1d nix(loadtest): remove --method argument for JWT loadtests
This is not used by CI and I doubt it's actually used by anyone locally.
2026-06-26 19:33:51 +00:00
Wolfgang Walther e5eb98c8a0 nix(loadtest): fix postgrest-loadtest-report locally
The script currently depends on results from "head" and "main" to be
present to calculate the change ratio. Fallback nicely in case these are
not available, which allows using the same to report URL-by-URL stats
locally.
2026-06-26 19:33:51 +00:00
Taimoor ZaeemandWolfgang Walther bb63c3fade change: use RFC 9535 syntax for jwt-role-claim-key config
BREAKING CHANGE

Breaks the string comparison operators implemented in #3813. Those can
be replaced with regex searches using JSON Path `search()` function.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-26 18:32:05 +00:00
Wolfgang Walther a0bb87d693 nix(loadtest): fix cpu/mem monitoring for tests using libfaketime
Instead of starting a separate process, which would make the pid we
store the one from `faketime` instead of `postgrest`, we can also just
start libfaketime directly via LD_PRELOAD.
2026-06-26 18:30:25 +00:00
Wolfgang Walther ba9336f402 nix: change reference from master to main in README 2026-06-26 18:16:36 +02:00
Wolfgang Walther 5feb55a95b nix: remove PGRST_DELAY AND PGDELAY from README
These had been removed a while ago.
2026-06-26 18:16:25 +02:00
Taimoor Zaeem 67956b3cb1 refactor: log server listening observations after listening socket is ready
Correct behavior is to log this after the listening socket is ready.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-26 16:01:55 +05:00
renovate[bot]andWolfgang Walther a6840f9bf9 chore(deps): update actions/cache action to v6 2026-06-25 20:10:47 +00:00
Taimoor ZaeemandSteve Chavez 081c4c6d70 test(spec): sort imports in SpecHelper.hs
The imports were scattered all around. This commit
sorts and group them.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-25 11:21:28 -05:00
Taimoor ZaeemandSteve Chavez b5f10be167 test: move jwt cache tests from io tests to spec tests
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-25 11:21:28 -05:00
Taimoor ZaeemandSteve Chavez 0bc9fe813f test: move jwt iat claim test from io tests to spec tests
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-25 11:21:28 -05:00
Taimoor ZaeemandSteve Chavez feb4853273 test(io): add test for admin server listening observation
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-25 10:39:16 -05:00
Taimoor Zaeem 9e0f9bc4ee refactor: correct admin server port setting
For admin server, port server-setting was set to the same port as
app server port. This doesn't have any effect because it is overridden
by the already initialized admin server socket, but it's better to
explicitly correct it to avoid anything unexpected.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-23 23:05:02 +05:00
Taimoor Zaeem f5fd2e71b6 test: move jwt error tests from io tests to spec tests
Towards #4946.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-22 23:52:45 +05:00
Taimoor Zaeem ee30bd03ac test(io): remove needless server-timing config coverage tests
These 2 tests don't test any specific behavior - they were added
only to please code coverage.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-22 23:52:45 +05:00
Taimoor Zaeem 1a35af5024 test(spec): rename misleading function name in ErrorSpec.hs
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-22 23:52:45 +05:00
steve-chavez ded9be6774 nix(loadtest): add comment on loadtest-against 2026-06-22 12:55:56 -05:00
Wolfgang Walther ffe4cc6f42 nix(loadtest): allow running multiple postgrest-loadtest in same working directory
There is no need to store the out-links to the various build artifacts
in the current working directory while running postgrest-with-pg, which
is used by postgrest-loadtest. Instead reference the nix store paths
directly.

Resolves #5028
2026-06-21 12:56:42 +02:00
renovate[bot]andWolfgang Walther 79e9e77e46 chore(deps): update vmactions/freebsd-vm action to v1.4.8 2026-06-20 21:57:24 +00:00
renovate[bot]andWolfgang Walther 87b480bc0a chore(deps): update actions/checkout action to v7 2026-06-19 19:09:44 +00:00
renovate[bot]andWolfgang Walther 336d32d1ce chore(deps): update nixbuild/nix-quick-install-action action to v35 2026-06-19 19:09:02 +00:00
renovate[bot]andWolfgang Walther 9aef6f30a8 chore(deps): update vmactions/freebsd-vm action to v1.4.7 2026-06-19 19:08:17 +00:00
Taimoor ZaeemandSteve Chavez 242e5ba87e chore(cabal): explain performance related build flags
These flags were added in 9f97147cc3. Adding
a comment to clarify the use.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-17 14:15:45 -05:00
Michał KłeczekandTaimoor Zaeem 9f97147cc3 perf: add ghc 9.12 options -fexpose-overloaded-unfoldings -fspecialise-aggressively
Before 9.12.1 it was necessary to mark functions as INLINABLE or INLINE to make GHC consider cross-module specialization of polymorphic functions.
9.12 added a new -fexpose-overloaded-unfoldings flag that exposes optimized polymorphic functions in interface files. -fspecialise-aggressively then makes GHC apply aggresive specialization.
2026-06-17 13:13:48 +05:00
Taimoor ZaeemandSteve Chavez 9048332b0e test(io): clarify test names
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-16 13:13:51 -05:00
Taimoor ZaeemandSteve Chavez b6c12abf0e test: move http header related tests from io tests to spec tests
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-16 13:13:51 -05:00
Michał KłeczekandSteve Chavez 8fa26ee865 fix: Start listening after schema cache load
This change ensures PostgREST starts listening on a server socket only after it loaded the schema cache and is ready to handle requests. It is no longer going to return 503 errors during startup until the schema cache is loaded.
2026-06-16 12:30:51 -05:00
Michał KłeczekandWolfgang Walther fae6253932 refactor: make nextListenerDelay local to Listener module
Right now stateNextListenerDelay is only used in Listener module.
This change is a small refactoring moving nextListenerDelay to Listener to increase cohesion and decrease coupling.
2026-06-14 18:39:59 +00:00
Wolfgang Walther 2976eb047b add: support running admin server on unix socket
This is useful when multiple instances run on the same machine, for
example behind a proxy. Unix sockets for web and admin servers can then
be put in the same folder for each instance.

Can be helpful when writing tests as well.
2026-06-14 17:18:37 +00:00
Wolfgang Walther f24bc7092f test(io): fix UnboundLocalError
The `if response` check a few rows down would not actually work without
initializing the variable first. It'd throw:

```
E       UnboundLocalError: cannot access local variable 'response' where
it is not associated with a value
```
2026-06-14 17:18:37 +00:00
Wolfgang Walther 6d87fc5879 test(io): move some tests to unix sockets
No need to run these with TCP and freeport, I believe.
2026-06-14 17:18:37 +00:00
Michał KłeczekandSteve Chavez 54430c3a2c fix: Do not clear the schema cache during retries
retryingSchemaCacheLoad should not clear existing schema cache upon failure - there is no reason to do that. If there is a communication issue with the database server or db is down, clients are going to get 502 anyway. If it was a glitch when loading the schema cache - the clients are going to use old (stale) schema cache for some time until next retry re-loads it successfully.
2026-06-11 13:14:37 -05:00
Taimoor Zaeem e9a016670f Revert "add: string slicing operator for jwt-role-claim-key"
This reverts commit fe0386e9c4.

As discussed in https://github.com/PostgREST/postgrest/pull/4984#issuecomment-4652725178.
2026-06-11 23:07:05 +05:00
steve-chavez 1ebf480258 amend: required membership for postgrest_test_anonymous
Previous test correction required GRANTing membership for
postgrest_test_anonymous.
2026-06-11 12:00:02 -05:00
steve-chavez e7c8d70333 test: correct test_admin_ready_includes_schema_cache_state
There was an oversight on d556cea, `timeout_authenticator` doesn't have
any privileges on the tables so it shouldn't be making requests to the
API server or it will end up with 401 responses.
2026-06-11 11:51:14 -05:00
Wolfgang Walther 9097752888 ci(release): lowercase ghcr repo
ghcr does not support uppercase letters, which was not a problem when
testing in my fork. But the PostgREST org's name obviously has uppercase
letters in it, so we need to lowercase these for the ghcr namespace.
2026-06-10 14:18:12 +02:00
Wolfgang Walther 62503466a0 Revert "ci(ci): avoid running build jobs twice on pushes to main"
This reverts commit 840d3f99ed.

This was a nice idea in theory, but in practice this means that the
build jobs do not run at all on the default branch anymore. This means
the caches they push to won't be used by any other jobs, neither on the
tag pipelines, nor on PRs. This in turn makes all of these jobs really
slow.

Not helpful!
2026-06-10 14:04:59 +02:00
Wolfgang Walther 1560078ce2 ci: push container images to ghcr.io
Resolves #2836
2026-06-10 13:17:37 +02:00
Taimoor ZaeemandWolfgang Walther 8bde0ad474 test: move cors related tests from io tests to spec tests
Towards #4946.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-10 10:27:49 +00:00
Taimoor ZaeemandWolfgang Walther 21433d10c2 refactor(config): use correct data type for server-cors-allowed-origins
Replaces the `Maybe [Text]` with `[Text]`. The `Maybe` is unnecessary
because we handle `Just []` and `Nothing` the same way.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-09 12:35:47 +00:00
Wolfgang Walther 044d623424 ci(test): fail loadtest correctly
Previously this would only fail if *each* row had `:x:` in it, which was
never the case, because the header never has it. It is supposed to fail
when *at least one* row has an .
2026-06-09 12:35:25 +00:00
renovate[bot]andWolfgang Walther 0b5655b9d3 chore(deps): update codecov/codecov-action action to v7 2026-06-07 11:01:07 +00:00
steve-chavez 4df0654998 docs: add how-to for Query Identifier 2026-06-06 06:47:33 -05:00
steve-chavez ad790baefb test: explain verbose reveals query identifier
This also requires enabling shared_preload_libraries=pg_stat_statements.
Really we only need compute_query_id=on, but pg_stat_statements is
useful for other tests and it already enables compute_query_id (since
it's `auto` by default).
2026-06-06 06:47:33 -05:00
Wolfgang Walther cb6fc55a2d chore(deps): update nixpkgs, stackage and hackage pins 2026-06-05 20:29:48 +00:00
Wolfgang Walther b114bb9395 nix: replace silver-searcher with fd
The former has been removed from Nixpkgs and won't be available on the
next bump.
2026-06-05 20:29:48 +00:00
Taimoor ZaeemandSteve Chavez da8738b88e chore: add changelog entry for v14.13
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-05 13:30:59 -05:00
renovate[bot]andWolfgang Walther 3ca876da62 chore(deps): update actions/checkout action to v6.0.3 2026-06-04 09:09:49 +00:00
Laurence IslaandSteve Chavez 416a15480f fix: request failures when work_mem is set on a role 2026-06-03 13:45:34 -05:00
Wolfgang Walther a149405d11 ci: remove deprecation warning
app-id was replaced with client-id
2026-06-03 10:09:38 +02:00
netandWolfgang Walther 3d596e2dbc fix: don't mention retrying in the database connection error message
The PGRST000 database connection error message was "Database connection
error. Retrying the connection.", but reconnection attempts are already
logged separately by the reconnection observation, and on fatal errors
(e.g. authentication failure) PostgREST does not retry at all. Drop the
"Retrying the connection." part, leaving "Database connection error.".
2026-06-03 08:04:40 +00:00
Pedro Gil MoraandWolfgang Walther fae58174fa docs: Add efcore-postgrest library to client-side libraries 2026-06-02 08:19:45 +00:00
Wolfgang Walther 840d3f99ed ci(ci): avoid running build jobs twice on pushes to main
It's enough to run the build jobs in the release pipeline, no need to
run them on the push event as well.
2026-06-02 10:08:16 +02:00
Wolfgang Walther 871aa058f8 ci(release): only update docker description from devel release
This condition was accidentally removed when merging 4 release jobs into
2.
2026-06-02 10:07:37 +02:00
Wolfgang Walther 8552c66c1e ci: Use FreeBSD VM instead of cirrus 2026-06-02 07:36:59 +00:00
netandWolfgang Walther 097a1de67d chore: sort config dump alphabetically
The config dump in Config.hs listed db-config, db-pre-config and the
db-pool-* settings out of alphabetical order, while the rest of the dump
was sorted. Now the whole dump is consistently alphabetical and update
the expected IO test configs to match.
2026-06-02 07:32:11 +00:00
Wolfgang Walther ed4b68c364 test(spec): remove obsolete extra search path from postgis tests
This was brought over in the last commit, because the postgis was
re-using the same config as another test. Now it has a separate config,
so we can reduce it a bit.
2026-06-02 06:49:15 +00:00
Wolfgang Walther 268ab00ed9 test(spec): inline config into test suite
Previously, information about each test-suite was repeated in 3 separate
places:
- as a label and as implicit knowledge in the test-suite itself,
- as a comment in Main.hs, and
- as a configuration in SpecHelper.hs.

With this change, there will be a single source of truth in the test
suite itself. This will allow a single test-suite to easily test
multiple different configurations.
2026-06-02 06:49:15 +00:00
Wolfgang Walther 7803960cd1 test(spec): fix test labels 2026-06-02 06:49:15 +00:00
Wolfgang Walther 0e46474cb2 test(spec): fix typo in comment 2026-06-02 06:49:15 +00:00
Wolfgang Walther 7c806a2bf9 test(spec): move two tests with basic config into list
Everything that uses withApp is in that list.
2026-06-02 06:49:15 +00:00
Wolfgang Walther c2d32be3c5 test(spec): remove obsolete ANALYZE calls
These are now part of the with- helpers.
2026-06-02 06:49:15 +00:00
Michał KłeczekandTaimoor Zaeem 13c0e7061e refactor: simplify control flow in App.postgrest
Currently, authentication and response execution each unwrap ExceptT with separate runExceptT calls, which split the main request flow across nested pattern matching and Either handling. Control flow is complex and difficult to understand.

The goal of this change is to make request execution as sequential
monadic code with clear error handling.

To implement that, request handling is now run in ExceptT over WriterT (Last ByteString) IO monad stack. Auth role is written after authentication succeeds and further returned along the response. Thanks to it response observation generation is centralized at the end of request handling.

It was necessary to abstract monad stack in getAuthResult, lookupJwtCache, postgrestResponse, and withTiming to enable introduction of WriterT.
2026-06-02 11:28:19 +05:00
Wolfgang Walther 1d6e0bd35f nix(loadtest): report percentage change
This reports the percentage change between the current head branch and
the main branch, which is exactly the number we'll want to make our
decisions on "success or fail" on.

CI failures will initially be reported for regressions of 5% or more on
an individual number.
2026-06-01 20:49:35 +00:00
Wolfgang Walther ff92846e64 nix(loadtest): report multiple percentiles at once
We can look at the data over time and see which percentile works best
for our purpose.
2026-06-01 20:49:35 +00:00
Wolfgang Walther 640039a180 nix(loadtest): move errors into mixed
Because we separate loadtest results per URL now, we can move the error
tests into the regular mixed bag of loadtests - we will be able to tell
from the misspelled URLs when we hit a regression in that area.

We should be able to do similar things for JWT tests, but we'll need
more infrastructure here.
2026-06-01 20:49:35 +00:00
Wolfgang Walther 59dffc258a nix(loadtest): report latency instead of rate
We previously used "rate", i.e. number of requests per second, as the
primary metric to judge loadtest results. However, this has always been
varying from run to run quite a bit, especially in CI where other jobs
possibly run on the same VM host.

The run-to-run variance has massively increased after splitting the
results up per request. Example run in CI with rate on the PR
introducing this change (on which we would expect no change at all):

| rate [1/s]                         |   main |   head |    Δ |
|:-----------------------------------|-------:|-------:|-----:|
| /                                  |    9.4 |    9.5 |   1% |
| /actors                            |  870.4 | 1023.0 |  18% |
| /actors?actor=eq.1                 |  188.5 |  198.6 |   5% |
| /actors?actor=eq.1&columns=name    |  197.3 |  167.1 | -15% |
| /actors?select=*,roles(*,films(*)) |  153.9 |  144.9 |  -6% |
| /films?columns=id,title            |  157.9 |  182.6 |  16% |
| /films?columns=id,title,year,...   |   87.0 |   87.1 |   0% |
| /roles                             |  204.5 |  267.3 |  31% |
| /rpc/call_me                       |  231.3 |  208.8 | -10% |
| /rpc/call_me?name=John             |  212.2 |  201.7 |  -5% |

From the data we can easily tell that the very reason that rate as a
paramter has only worked, so far, because the data was *heavily*
dominated by the requests on the root endpoint for OpenAPI. The longer
duration makes the request much less vulnerable for concurrent activity.
For all other requests its essentially not possible to judge the effect
of a PR this way.

One way to counter this would be to massively increase the time the
loadtest runs. More samples will result in a smoother average. However,
that's not practical for usability of CI. In the original PR #1812 I
already evaluated using the *minimum latency* as the most reliable
criteriumi, but this has never really caught on. The theory behind this
is: The variation in timings between requests is happening because of
concurrent activity, priority chosen by the scheduler, availability of
resources and such - all factors *outside* our control, and *irrelevant*
to the Haskell code we're writing.

Using the minimum latency is an estimation of how fast the code can run
*in the best case*. This might not be a number relevant for production,
but it's much more directly related to the code we write.

Here's to show how variation becomes *much* smaller with minimum latency
as the parameter:

| min latency [μs]                   |     main |   head |    Δ |
|:-----------------------------------|---------:|-------:|-----:|
| /                                  |   1275.3 | 1263.6 |  -1% |
| /actors                            |     10.0 |    9.9 |  -1% |
| /actors?actor=eq.1                 |     50.7 |   48.3 |  -5% |
| /actors?actor=eq.1&columns=name    |     54.1 |   54.0 |   0% |
| /actors?select=*,roles(*,films(*)) |     63.2 |   61.9 |  -2% |
| /films?columns=id,title            |     51.1 |   50.7 |  -1% |
| /films?columns=id,title,year,...   |    121.9 |  121.8 |   0% |
| /roles                             |     42.9 |   42.6 |  -1% |
| /rpc/call_me                       |     45.6 |   45.4 |   0% |
| /rpc/call_me?name=John             |     44.4 |   44.2 |   0% |

Since we're separating results per request now, we can only sensibly
focus on *one* parameter - otherwise this would get really clunky
UI-wise. Especially for automated CI failures, minimum latency is the
logical choice.

This commit starts using minimum latency, i.e. P0, but any percentile
should be an improvement over the status quo. A later commit will change
to a different P-value.
2026-06-01 20:49:35 +00:00
Wolfgang Walther 8a9f98371e nix(loadtest): group results by status, method and URL
Different requests hit different code paths and perform very
differently. By looking at each request type separately, we should be
able to get a much better idea of what kind of change in performance
we're looking at and where the root cause might be.

It will hopefully also allow us to migrate some of the other test-cases
into the main loadtest.
2026-06-01 20:49:35 +00:00
Wolfgang Walther 5cdf2e0569 nix(loadtest): remove noise from report
Ultimately, we only look at the `rate` column, so we can just as well
remove all other columns.

This makes the next step, when we split results by request type, much
less noisy.
2026-06-01 20:49:35 +00:00
Taimoor ZaeemandSteve Chavez 669fc9ede8 docs: restructure PostGIS page
Restructure PostGIS page with order:

- `Accept: application/geo+json` request example
- Generated column example
- String representation example

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-06-01 12:59:15 -05:00
Michał KłeczekandSteve Chavez 0df56f9ea8 refactor: assemble main transaction session in MainTx
This change makes the API surface between MainTx and App smaller.

Currently, App reconstructs a database transaction by unpacking the isolation
level, transaction mode, DbHandler, and transaction runner returned by MainTx.
That exposes MainTx internals at the call site even though MainTx already owns
query setup, execution, decoding, and rollback behavior.

The goal is to keep transaction assembly in MainTx while App remains responsible
for pool execution, database error mapping, and response orchestration. DbTx now
carries the assembled SQL session, and App passes that session directly to the
connection pool.
2026-05-31 15:52:56 -05:00
Michał KłeczekandSteve Chavez 56ad5a9324 refactor: get rid of dbQueryTimings from SchemaCache
Schema cache query timings are only needed immediately after a schema-cache reload to emit SchemaCacheQueriedObs. Storing them inside SchemaCache makes the cache carry transient observability data that is not part of the cached schema state and is never used by request handling.

This change makes querySchemaCache to return query timings in a tuple in parallel to SchemaCache and removes dbQueryTimings field.
2026-05-31 14:20:35 -05:00
Taimoor ZaeemandSteve Chavez 9162cea7ba test(io): remove unused config variables from config test
Config variables are tested already via reading the config files in
the `configs/` directory.

If more are to be tested, it should be done via adding a file in
`configs/` and compare it with its associated file in `configs/expected/`.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-30 09:51:26 -05:00
Taimoor ZaeemandSteve Chavez e1d547623e nix(docs): print message to console on script runs
It's not immediately visible that these scripts are run when
doing `postgrest-docs-check`.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-27 15:23:59 -05:00
Michał KłeczekandSteve Chavez 998d232ac0 docs: PGRST107 error should map to 406 not to 415 2026-05-27 14:37:23 -05:00
Michał KłeczekandWolfgang Walther 1a6ba2072c refactor: Simplify App.initServerSocket
This change gets rid of unnecessary explicit bindRandomPortTCP in initServerSocket. Returned port value was ignored in removed code anyway as assigned port retrieval from an open socket is handled elsewhere.
2026-05-24 23:56:05 +02:00
renovate[bot]andWolfgang Walther ae00c04faf chore(deps): update docker/login-action action to v4.2.0 2026-05-22 20:54:17 +00:00
renovate[bot]andWolfgang Walther e0e14a1fe4 chore(deps): update docker/setup-buildx-action action to v4.1.0 2026-05-22 20:52:03 +00:00
Taimoor ZaeemandSteve Chavez 901624a891 chore: add changelog entry for v14.12
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-21 10:26:17 -05:00
Michał KłeczekandSteve Chavez 913fe001e5 refactor(remove): schema cache load delay config
Remove internal schema cache load and relationship load sleep settings plus
the delay wrappers they enabled. Drop IO tests that depended on the removed
settings.
2026-05-19 10:59:27 -05:00
Michał KłeczekandSteve Chavez 86d6ed10bb test: cover stale schema cache database error
Add an IO test that drops a table while schema cache reload is delayed. It verifies the stale cache path returns PostgreSQL 42P01 and the refreshed cache returns PGRST205.
2026-05-19 09:11:04 -05:00
renovate[bot]andWolfgang Walther 55f9c45899 chore(deps): update codecov/codecov-action action to v6.0.1 2026-05-19 07:04:42 +00:00
Michał KłeczekandTaimoor Zaeem 07938aaab2 amend: Move #4622 to proper Changelog section 2026-05-19 10:55:53 +05:00
Wolfgang Walther 61da5dd88b nix(loadtest): prevent timing errors for worst-case JWT test
Instead of taking wild guesses at the runtime of the target generation
itself, we're just making sure to reset the system time to a fixed value
when we ultimately start PostgREST. This allows us to create the right
JWT expiry values ahead of time.
2026-05-18 16:23:37 +00:00
Wolfgang Walther d9f73ac71b nix(loadtest): remove duplicate line 2026-05-18 16:23:37 +00:00
Taimoor ZaeemandWolfgang Walther e6d8d95c0a chore: remove unplanned TODO in Logger.hs
We decided against doing this in #4913, therefore removing it. With that,
also mentioning that control flow never reaches there to avoid confusion.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-18 16:23:08 +00:00
Wolfgang Walther 9d67febb93 ci(release): merge 4 jobs into 2
No need to do this in as many jobs. Splitting all the github stuff from
docker stuff into two jobs is enough. This still allows to conditionally
enable docker jobs in contributors repos, depending on whether the
relevant docker credentials are provided - but avoids using too many
concurrent runners.
2026-05-18 16:22:49 +00:00
steve-chavez 6220ab3f31 test: adjust test_positive_pool_metric
Adjusted so it waits for liveness instead of requiring sleeping
2026-05-18 10:46:02 -05:00
steve-chavez 1eba9855c1 test: change wait_for_readiness to an enum
This so we can wait for both readiness and liveness
2026-05-18 10:45:36 -05:00
Michał KłeczekandSteve Chavez a297391071 fix: implement connection tracking in metrics
Right now metrics observation handler does not track database connections but updates a single Gauge based on HasqlPoolObs events. This is problematic because Hasql pool reports various connection events in multiple phases. The connection state machine is not simple and to precisely report the number of connections in various states, it is necessary to track their lifecycles.

This change adds a ConnTrack data structure and logic to track database connections lifecycles. At the moment it supports "connected" and "inUse" connection counts precisely. The "pgrst_db_pool_available" metric is implemented on top of ConnTrack instead of a simple Gauge.
2026-05-18 10:09:00 -05:00
Wolfgang Walther 4f9bc89ab2 nix(loadtest): remove outdated PGRST_DB_URI default
This was required for v9 and earlier, but these don't build with the
current nix invocation anymore anyway. Even loadtesting against v10 does
not work, because `--version` is used in one of the wait scripts and
this was only added in v11.2.

So no need to pretend we'd support comparing against older versions.
2026-05-18 15:18:05 +02:00
Taimoor ZaeemandWolfgang Walther 084a8eca55 test(io): move utility functions to util.py
The functions `drain_stdout` and `match_log` should be in `util.py`
so they can be reused in other modules.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-18 12:54:08 +00:00
Wolfgang Walther ed344c795a ci(release): run docker job on regular VM runner
Tried to run it on a -slim runner in fb24b6b3, but the result is that no
docker socket is available. This jobs needs one of the big runners.
2026-05-18 14:46:21 +02:00
Wolfgang Walther c335da9334 ci: avoid running pg18 tests twice
We already test PG18, the default, with the coverage job, so why run it
twice?
2026-05-18 14:06:16 +02:00
Wolfgang Walther fb24b6b37f ci: use -slim runner for small jobs
No need to spin up full VM runners for small automation tasks, when we
can use single-CPU runners in containers instead.

https://docs.github.com/en/actions/reference/runners/github-hosted-runners#single-cpu-runners

(some of this will potentially not work, because dependencies in the
slim image might not be available - however, it makes no sense to create
this as a PR, because all jobs touched here run on branches only. Thus
pushing directly to main)
2026-05-18 14:05:41 +02:00
steve-chavez 8868d13214 test: adjust sleep in test_positive_pool_metric
Otherwise it's not enough time for the pool metric to
reach a negative value.
2026-05-17 16:39:11 -05:00
Wolfgang Walther c7260bddab test: consistently analyze tables exactly once
Disabling the autovacuum daemon should also help reproducibility in
theory, although I don't know of any cases where we hit a problem with
that.

VACUUM changes the order of rows that PostgreSQL returns for some table
without explicit ordering, thus doing the latter to make it consistently
reproducible.

After ANALYZE estimates are 100% exact for the moment, so some requests
which returned 206 Partial Response now return 200 instead. The fact
that PostgREST returns 206 on an unfiltered endpoint can probably be
considered a bug.
2026-05-17 20:03:15 +00:00
Wolfgang Walther abe3e511bf nix(postgrest-with-pg-...): use postgresql.conf instead of CLI arguments
This is easier to reason about and easier to extend. Also removes a tiny
bit of repetition.
2026-05-17 20:03:15 +00:00
steve-chavez 70327cf869 test: negative pgrst_db_pool_available in metrics
Proves the failure on https://github.com/PostgREST/postgrest/issues/4622.

This doesn't require additional test infra, only nginx. Taking advantage
of the `stream {}` context which is also compatible with unix socket
besides TCP.
2026-05-17 12:58:58 -05:00
Wolfgang Walther a9713208e4 ci: ignore loadtest failures for jwt-rsa-cache-worst 2026-05-15 23:25:38 +02:00
Wolfgang Walther 2783ec7b51 ci: run other loadtests to completion when one of them fails
The most likely offender to fail early is jwt-rsa-cache-worst - which
then cancels *all* loadtests at once. This is unnecessary churn for CI.
Instead we can re-run only that one test later.
2026-05-15 23:21:54 +02:00
Taimoor Zaeem ab43ee1fbb docs: add redirect of the moved postgis section
In 055921ea, we missed redirecting the old link to the new one.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-15 23:01:36 +05:00
renovate[bot]andWolfgang Walther 2ab2ea2c6c chore(deps): update dependency macos to v26 2026-05-14 19:45:32 +00:00
Aiden ParkandWolfgang Walther 703a5535cf chore: remove duplicated words in Listener and Plan comments
Signed-off-by: Aiden Park <275402320+vip892766gma@users.noreply.github.com>
2026-05-14 14:23:09 +00:00
renovate[bot]andWolfgang Walther 187ea6d546 chore(deps): update actions/create-github-app-token action to v3.2.0 2026-05-13 21:01:47 +00:00
Taimoor Zaeem 055921eaf5 docs: move PostGIS under Integrations
For better visibility.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-13 12:41:44 +05:00
Taimoor ZaeemandWolfgang Walther f90d7d7296 ci: catch linkcheck failure
The scheduled linkcheck job fails without notification to maintainers.
To catch the failure, a github workflow step has been added which
comments on issue #4106 so that the maintainers get notified.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-12 17:27:45 +00:00
renovate[bot]andWolfgang Walther 27aea13798 chore(deps): update cachix/cachix-action digest to 5f2d7c5 2026-05-12 13:10:57 +00:00
renovate[bot]andWolfgang Walther d75beed5dd chore(deps): update korthout/backport-action digest to 6606540 2026-05-12 13:03:16 +00:00
Wolfgang Walther 243bbb1b61 test: make some tests more stable
These fail with orioledb, because it randomly returns a different order.
Of course, that's allowed - ordering is not guaranteed unless specified.
We should write our tests with more explicit ordering in general, even
if multiple major versions show the same behavior.
2026-05-08 18:03:54 +02:00
Taimoor ZaeemandSteve Chavez 98f8e52b46 refactor: remove auth and logging middleware
This commit removes auth middleware for it hides
side effects and obscures logic. The auth operations
are now done in its own stage in the request-response
cycle.

It also removes the logging middleware because now
we instead use observation module to log the response.
2026-05-07 11:47:17 -05:00
Wolfgang Walther 0bba1d265a ci: test NixOS' VM test for PostgREST
This adds a CI job to run our latest postgrest version against the NixOS
VM test currently available in Nixpkgs. Now, this will not always be in
sync, so has the potential to be failing. However, since the Nixpkgs VM
test is really simple, this should only happen when we introduce a
breaking change on a very fundamental level. The failing test will then
be resolved once the new version is available in Nixpkgs and we have
updated our lock file.

This is essentially just a sanity check to make sure we're not breaking
something fundamentally - and if we do, it's a head up for me to adjust
the Nixpkgs tests accordingly. Those might otherwise break unnoticed
since Nixpkgs does not have a good notification system for such
breakages in place.

We do use the chance to run the static executable in this test, which
was previously not tested at all.

It also gives us a first test whether NixOS VM tests work well in GitHub
Actions.
2026-05-07 07:10:56 +00:00
Taimoor ZaeemandWolfgang Walther 96f12f83f0 ci: cancel previous runs for tag pipelines
Reverts the change in ad5bb38d70.

https://github.com/orgs/community/discussions/13015 is now solved.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-07 07:08:41 +00:00
steve-chavez 02a1de2afe test: OPTIONS produce logs but not CORS preflight 2026-05-06 17:21:31 -05:00
renovate[bot]andWolfgang Walther beafd0b53f chore(deps): update korthout/backport-action digest to bf97bcf 2026-05-06 19:47:13 +00:00
Taimoor Zaeem 4c04572783 nix(chore): add commit prefix in release commit message
We should follow our commit convention.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-06 23:26:06 +05:00
steve-chavez 6b3ec5d9e0 test: empty db-anon-role lacks role in logs 2026-05-05 19:29:59 -05:00
steve-chavez 6804ce3cbe test: empty schema cache error has role in logs 2026-05-05 19:29:59 -05:00
steve-chavez 42e53e84e1 test: invalid rpc call contains role in logs 2026-05-05 19:29:59 -05:00
steve-chavez 8105375b64 test: expired JWT shows empty role in logs 2026-05-05 19:29:59 -05:00
steve-chavez e39740cca3 nix: allow empty PGRST_DB_ANON_ROLE on postgrest-run
So we can do `PGRST_DB_ANON_ROLE="" postgrest-run` since empty string has
meaning. argbash conflates both unset and empty string so this requires
a workaround.
2026-05-05 17:32:50 -05:00
Taimoor ZaeemandWolfgang Walther c8e7f11688 chore: add changelog entry for v14.11
Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-05 15:53:15 +00:00
Taimoor Zaeem fd3f9378ac fix: functions count in startup logs not counting overloaded functions
Renames the "Functions" in the logs to "RPCs". This clarifies that
we log number of callable functions and not the number of SQL objects.

Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
2026-05-04 20:42:20 +05:00
Michał KłeczekandWolfgang Walther 85d91e5c0a add: Publish GHC runtime metrics to Prometheus metrics endpoint 2026-05-03 11:41:02 +00:00
Laurence IslaandGitHub c09394517d fix: call pg_notification_queue_usage() automatically when the LISTEN channel bug is detected (#4858)
There's a PostgreSQL bug that doesn't let any listener to register in the DB:
https://www.postgresql.org/message-id/flat/CAK98qZ3wZLE-RZJN_Y%2BTFjiTRPPFPBwNBpBi5K5CU8hUHkzDpw%40mail.gmail.com
The only workaround is to advance the async notification queue tail,
which can be done by executing:  "SELECT pg_notification_queue_usage();".
Before we just logged a HINT with this suggestion, but now we call that function directly
and then let the listener to automatically recover.

No automated tests were added here as it would be too complex and this is a PostgreSQL bug. But this was manually tested following the steps on https://github.com/PostgREST/postgrest/pull/4581#issuecomment-3690610592
2026-04-30 18:22:59 -05:00
Michal KleczekandGitHub 04a0e041e4 fix: Restore showing LISTEN pgrst in pg_stat_activity 2026-04-30 17:21:12 -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
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
324 changed files with 14510 additions and 10641 deletions
-42
View File
@@ -1,42 +0,0 @@
freebsd_instance:
image_family: freebsd-14-2
build_task:
# Don't change this name without adjusting .github/workflows/build.yaml
name: Build FreeBSD (Stack)
install_script: pkg install -y postgresql16-client hs-stack git
only_if: |
$CIRRUS_TAG != '' || $CIRRUS_BRANCH == 'main' || $CIRRUS_BRANCH =~ 'v*' ||
changesInclude(
'.github/workflows/build.yaml',
'.github/actions/artifact-from-cirrus/**',
'.cirrus.yml',
'postgrest.cabal',
'stack.yaml*',
'**.hs'
)
stack_cache:
folders: /.stack
fingerprint_script:
- echo $CIRRUS_OS
- stack --version
- md5sum postgrest.cabal
- md5sum stack.yaml.lock
stack_work_cache:
folders: .stack-work
fingerprint_script:
- echo $CIRRUS_OS
- stack --version
- md5sum postgrest.cabal
- md5sum stack.yaml.lock
- 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
strip postgrest
bin_artifacts:
path: postgrest
-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 - Add a new entry to the CHANGELOG - https://github.com/PostgREST/postgrest/blob/main/CHANGELOG.md#unreleased
- If relevant, update the docs - If relevant, update the docs
- Use a prefix for the PR title or commits, e.g. "fix: description of the fix". - Use a prefix for the PR title or commits, e.g. "fix: description of the fix".
+ `fix`, bug fixes + `add`, Add a new feature
+ `feat`, new features added + `amend`, To amend an unrealease commit
+ `perf`, performance improvements + `change`, Breaking changes
+ `docs`, updating the documentation + `chore`, Maintenance, update sponsors, changelog, readme etc
+ `nix`, related to the Nix development environment + `ci`, CI configuration files and scripts
+ `ci`, related to the Continuous Integration modules + `docs`, Documentation
+ `test`, related to the testing modules + `fix`, Bug fix
+ `refactor`, refactoring code + `nix`, Related to Nix
+ `deprecate`, deprecating a feature + `perf`, Performance improvements
+ `changelog`, updating the CHANGELOG + `refactor`, Refactoring code
+ `chore`, maintenance (build process, updating sponsors, etc.) + `remove`, Remove a feature or fix
+ `test`, Adding tests
+ Other prefixes may be used if necessary + Other prefixes may be used if necessary
- If there's a breaking change, add `BREAKING CHANGE` and an explanation to your commit message - 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
@@ -1,119 +0,0 @@
name: Artifact from Cirrus
description: Waits for a specific Cirrus CI run to complete, then downloads the artifact and uploads it to the current workflow. This will silently succeed if Cirrus CI did not schedule a task within 2 minutes.
inputs:
download:
description: Name of Artifact to download from Cirrus CI
required: true
task:
description: Name of Cirrus Task
required: true
token:
description: GitHub Token
required: true
upload:
description: Name of Artifact to upload on GitHub Actions
required: true
runs:
using: composite
steps:
- shell: bash
run: echo "GH_TOKEN=${{ inputs.token }}" >> "$GITHUB_ENV"
- name: Wait for Check Suite to be created
id: check-suite
env:
# GITHUB_SHA does weird things for pull request, so we roll our own:
COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
shell: bash
run: |
get_check_runs_url() {
gh api "repos/{owner}/{repo}/commits/${COMMIT}/check-suites" \
| jq -r '.check_suites[] | select(.app.slug == "cirrus-ci") | .check_runs_url'
}
for _ in $(seq 1 12); do
check_runs_url="$(get_check_runs_url)"
if [ -z "$check_runs_url" ]; then
echo "Cirrus CI task has not started, yet. Waiting..."
sleep 10
else
echo "check_runs_url=$check_runs_url" >> "$GITHUB_OUTPUT"
exit 0
fi
done
>&2 echo "Cirrus CI check suite not found. Is Cirrus CI enabled for this repo?"
- name: Find task by name
id: find-task
if: steps.check-suite.outputs.check_runs_url
shell: bash
run: |
get_number_of_tasks() {
gh api "${{ steps.check-suite.outputs.check_runs_url }}" \
| jq -r '.check_runs | map(select(.name == "${{ inputs.task }}")) | length'
}
tasks="$(get_number_of_tasks)"
case "$tasks" in
0)
echo "Task not found, assuming it's skipped intentionally..."
exit 0
;;
1)
echo "task_found=1" >> "$GITHUB_OUTPUT"
exit 0
;;
*)
>&2 echo "More than 1 task with the same name found. Don't know what to do..."
exit 1
;;
esac
- name: Wait for Cirrus CI to complete task
if: steps.find-task.outputs.task_found
shell: bash
run: |
get_conclusion() {
gh api "${{ steps.check-suite.outputs.check_runs_url }}" \
| jq -r '.check_runs[] | select(.name == "${{ inputs.task }}" and .status == "completed") | .conclusion'
}
while true; do
conclusion="$(get_conclusion)"
if [ -z "$conclusion" ]; then
echo "Cirrus CI task has not completed, yet. Waiting..."
sleep 30
else
if [ "$conclusion" == "success" ]; then
break
else
exit 1
fi
fi
done
- name: Download artifact from Cirrus CI
if: steps.find-task.outputs.task_found
id: download
shell: bash
run: |
get_external_id() {
gh api "${{ steps.check-suite.outputs.check_runs_url }}" \
| jq -er '.check_runs[] | select(.name == "${{ inputs.task }}") | .external_id'
}
archive="$(mktemp)"
artifacts="$(mktemp -d)"
until curl --no-progress-meter --fail -o "${archive}" \
"https://api.cirrus-ci.com/v1/artifact/task/$(get_external_id)/${{ inputs.download }}.zip"
do
# This happens when a tag is pushed on the same commit. In this case the
# job is immediately marked as "completed" for us, so we end up here after a few
# seconds - but the actual Cirrus CI task is still running and didn't produce its artifact, yet.
echo "Artifact not found on Cirrus CI, yet. Waiting..."
sleep 30
done
unzip "${archive}" -d "${artifacts}"
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
with:
name: ${{ inputs.upload }}
path: ${{ steps.download.outputs.artifacts }}
if-no-files-found: error
+6 -7
View File
@@ -8,7 +8,6 @@ inputs:
required: true required: true
save-prs: save-prs:
description: Whether to additionally store the cache in a pull request, too. Should only be used for very small caches. description: Whether to additionally store the cache in a pull request, too. Should only be used for very small caches.
type: boolean
prefix: prefix:
description: Cache key prefix to be used in both primary key and restore-keys. description: Cache key prefix to be used in both primary key and restore-keys.
required: true required: true
@@ -19,17 +18,17 @@ inputs:
runs: runs:
using: composite using: composite
steps: steps:
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
if: ${{ startsWith(github.ref, 'refs/heads/') || (inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }} if: ${{ startsWith(github.ref, 'refs/heads/') || (inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }}
with: with:
path: ${{ inputs.path }} path: ${{ inputs.path }}
key: ${{ runner.os }}-${{ inputs.prefix }}-${{ inputs.suffix }} key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.prefix }}-${{ inputs.suffix }}
restore-keys: | restore-keys: |
${{ runner.os }}-${{ inputs.prefix }}- ${{ runner.os }}-${{ runner.arch }}-${{ inputs.prefix }}-
- uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
if: ${{ !startsWith(github.ref, 'refs/heads/') && !(inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }} if: ${{ !startsWith(github.ref, 'refs/heads/') && !(inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }}
with: with:
path: ${{ inputs.path }} path: ${{ inputs.path }}
key: ${{ runner.os }}-${{ inputs.prefix }}-${{ inputs.suffix }} key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.prefix }}-${{ inputs.suffix }}
restore-keys: | restore-keys: |
${{ runner.os }}-${{ inputs.prefix }}- ${{ runner.os }}-${{ runner.arch }}-${{ inputs.prefix }}-
+35
View File
@@ -0,0 +1,35 @@
name: Run anywhere
description: Runs the same code either in a VM or on the bare machine
inputs:
vm:
description: Which VM to run on.
envs:
description: List of relevant environment variables, which might need to be copied into the VM.
prepare:
description: Code to run in a prepare step, e.g. installing dependencies.
run:
description: Code to run as the main action.
required: true
runs:
using: composite
steps:
- if: ${{ inputs.vm == 'freebsd' }}
uses: vmactions/freebsd-vm@83b151f58c6047089f4c80eb5ba2039d158ce093 # v1.5.3
with:
envs: ${{ inputs.envs }}
prepare: ${{ inputs.prepare }}
# Work around https://github.com/vmactions/freebsd-vm/issues/59
run: |
pw user add -n action -m
su action -c '${{ inputs.run }}'
- if: ${{ inputs.vm == '' }}
name: Prepare
shell: ${{ runner.os == 'Windows' && 'pwsh' || 'bash' }}
run: ${{ inputs.prepare }}
- if: ${{ inputs.vm == '' }}
name: Run
shell: ${{ runner.os == 'Windows' && 'pwsh' || 'bash' }}
run: ${{ inputs.run }}
+2 -2
View File
@@ -11,12 +11,12 @@ inputs:
runs: runs:
using: composite using: composite
steps: steps:
- uses: nixbuild/nix-quick-install-action@5bb6a3b3abe66fd09bbf250dce8ada94f856a703 # v30 - uses: nixbuild/nix-quick-install-action@9f63be77f412a248c9d9a65a4c82cf066cdf8f0c # v35
with: with:
nix_conf: |- nix_conf: |-
always-allow-substitutes = true always-allow-substitutes = true
max-jobs = auto max-jobs = auto
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
with: with:
name: postgrest name: postgrest
authToken: ${{ inputs.authToken }} authToken: ${{ inputs.authToken }}
+3
View File
@@ -4,6 +4,9 @@ codecov:
comment: false comment: false
github_checks:
annotations: true
coverage: coverage:
status: status:
project: project:
+7 -19
View File
@@ -3,7 +3,7 @@
"extends": [ "extends": [
"config:best-practices" "config:best-practices"
], ],
"baseBranches": [ "baseBranchPatterns": [
"main", "main",
"/^v[0-9]+/" "/^v[0-9]+/"
], ],
@@ -13,28 +13,16 @@
}, },
"packageRules": [ "packageRules": [
{ {
"matchBaseBranches": [ "/^v[0-9]+/" ], "matchManagers": [
"matchManagers": ["haskell-cabal"], "haskell-cabal"
],
"enabled": false "enabled": false
}, },
{ {
"matchBaseBranches": [ "/^v[0-9]+/" ], "matchBaseBranches": [
"/^v[0-9]+/"
],
"groupName": "all dependencies" "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"
} }
] ]
} }
+53
View File
@@ -0,0 +1,53 @@
name: Backport
on:
pull_request_target:
types:
- closed
- labeled
jobs:
backport:
name: Backport
runs-on: ubuntu-slim
# 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@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
allow-unsafe-pr-checkout: true
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@2e830a1d0b8269505846ddd407a70876913ad1f8 # v4.6
with:
github_token: ${{ steps.app-token.outputs.token }}
pull_description: 'Backport for #${pull_number}.'
pull_title: '${target_branch}: ${pull_title}'
+63 -74
View File
@@ -16,6 +16,7 @@ on:
- .github/* - .github/*
- '*.nix' - '*.nix'
- nix/** - nix/**
- flake.lock
- .cirrus.yml - .cirrus.yml
- cabal.project* - cabal.project*
- postgrest.cabal - postgrest.cabal
@@ -30,56 +31,66 @@ concurrency:
jobs: jobs:
static: static:
name: Nix - Linux x86-64 static 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 runs-on: ubuntu-24.04
artifact: x86-64
name: Nix - ${{ matrix.name }} static
runs-on: ${{ matrix.runs-on }}
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Build static executable - name: Build static executable
run: nix-build -A postgrestStatic run: nix-build -A postgrestStatic -A postgrestStatic.tests
- name: Save built executable as artifact - name: Save built executable as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: postgrest-linux-static-x86-64 name: postgrest-linux-static-${{ matrix.artifact }}
path: result/bin/postgrest path: result/bin/postgrest
if-no-files-found: error if-no-files-found: error
- name: Build Docker image - 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 - name: Save built Docker image as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: postgrest-docker-x86-64 name: postgrest-docker-${{ matrix.artifact }}
path: postgrest-docker.tar.gz path: postgrest-docker-${{ matrix.artifact }}.tar.gz
if-no-files-found: error if-no-files-found: error
- name: Test static executable with NixOS' VM test
# GHA's ARM runner does not support KVM
if: runner.arch == 'X64'
run: nix-build -A nixpkgs-nixos-test
macos: macos:
name: Nix - MacOS name: Nix - MacOS
runs-on: macos-14 runs-on: macos-26
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Install gnu sed - name: Install nix-build-uncached
run: brew install gnu-sed run: nix-env -f default.nix -iA nix-build-uncached
- name: Build everything - name: Build everything (default.nix)
run: | run: nix-build-uncached
# 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 - name: Build everything (shell.nix)
# those explicitly. This has the advantage that pure verification will not include run: nix-build-uncached shell.nix
# 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
stack: stack:
@@ -87,75 +98,66 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- name: Linux aarch64 - name: FreeBSD x86-64
runs-on: ubuntu-24.04-arm runs-on: ubuntu-24.04
cache: | vm: freebsd
~/.stack/pantry artifact: postgrest-freebsd-x86-64
~/.stack/snapshots deps: pkg install -y git postgresql16-client hs-stack
~/.stack/stack.sqlite3
artifact: postgrest-ubuntu-aarch64
deps: sudo apt-get update && sudo apt-get install libpq-dev
- name: MacOS aarch64 - name: MacOS aarch64
runs-on: macos-14 runs-on: macos-14
cache: |
~/.stack/pantry
~/.stack/snapshots
~/.stack/stack.sqlite3
artifact: postgrest-macos-aarch64 artifact: postgrest-macos-aarch64
deps: brew link --force libpq deps: brew link --force libpq
- name: MacOS x86-64 - name: MacOS x86-64
runs-on: macos-13 runs-on: macos-15-intel
cache: |
~/.stack/pantry
~/.stack/snapshots
~/.stack/stack.sqlite3
artifact: postgrest-macos-x86-64 artifact: postgrest-macos-x86-64
deps: brew link --force libpq deps: brew link --force libpq
- name: Windows - name: Windows
runs-on: windows-2022 runs-on: windows-2022
cache: |
C:\sr\pantry
C:\sr\snapshots
C:\sr\stack.sqlite3
deps: Add-Content $env:GITHUB_PATH $env:PGBIN deps: Add-Content $env:GITHUB_PATH $env:PGBIN
artifact: postgrest-windows-x86-64 artifact: postgrest-windows-x86-64
name: Stack - ${{ matrix.name }} name: Stack - ${{ matrix.name }}
runs-on: ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }}
env:
# Putting .stack in the working directory helps with moving this in and out of the FreeBSD VM.
STACK_ROOT: ${{ github.workspace }}/.stack
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: haskell-actions/setup@64445b6b5dd545faf5f8e2acee8253eb5c2b29aa # v2.7.11 - if: ${{ !matrix.vm }}
uses: haskell-actions/setup@6037f33647c3f17758a2356c80fc4a53d7e0685d # v2.12.0
with: with:
# This must match the version in stack.yaml's resolver # This must match the version in stack.yaml's resolver
ghc-version: 9.6.6 ghc-version: 9.10.3
enable-stack: true enable-stack: true
stack-no-global: true stack-no-global: true
stack-setup-ghc: true stack-setup-ghc: true
- name: Cache ~/.stack - name: Cache .stack
uses: ./.github/actions/cache-on-main uses: ./.github/actions/cache-on-main
with: with:
path: ${{ matrix.cache }} path: .stack
prefix: stack prefix: ${{ matrix.vm }}${{ matrix.vm && '-' }}stack
suffix: ${{ hashFiles('postgrest.cabal', 'stack.yaml.lock') }} suffix: ${{ hashFiles('postgrest.cabal', 'stack.yaml.lock') }}
- name: Cache .stack-work - name: Cache .stack-work
uses: ./.github/actions/cache-on-main uses: ./.github/actions/cache-on-main
with: with:
path: .stack-work path: .stack-work
save-prs: true save-prs: true
prefix: stack-work-${{ hashFiles('postgrest.cabal', 'stack.yaml.lock') }} prefix: ${{ matrix.vm }}${{ matrix.vm && '-' }}stack-work-${{ hashFiles('postgrest.cabal', 'stack.yaml.lock') }}
suffix: ${{ hashFiles('main/**/*.hs', 'src/**/*.hs') }} suffix: ${{ hashFiles('main/**/*.hs', 'src/**/*.hs') }}
- name: Install dependencies
if: matrix.deps
run: ${{ matrix.deps }}
- name: Build with Stack - name: Build with Stack
run: stack build --lock-file error-on-write --local-bin-path result --copy-bins uses: ./.github/actions/run-anywhere
- name: Strip Executable with:
run: strip result/postgrest* vm: ${{ matrix.vm }}
envs: STACK_ROOT
prepare: ${{ matrix.deps }}
run: |
stack build --lock-file error-on-write --local-bin-path result --copy-bins
strip result/postgrest*
- name: Save built executable as artifact - name: Save built executable as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: ${{ matrix.artifact }} name: ${{ matrix.artifact }}
path: | path: |
@@ -164,29 +166,16 @@ jobs:
if-no-files-found: error if-no-files-found: error
freebsd:
name: Stack - FreeBSD from CirrusCI
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: ./.github/actions/artifact-from-cirrus
with:
token: ${{ github.token }}
task: Build FreeBSD (Stack)
download: bin
upload: postgrest-freebsd-x86-64
cabal: cabal:
strategy: strategy:
matrix: matrix:
ghc: ['9.6.6', '9.8.2'] ghc: ['9.10.3', '9.12.3']
fail-fast: false fail-fast: false
name: Cabal - Linux x86-64 - GHC ${{ matrix.ghc }} name: Cabal - Linux x86-64 - GHC ${{ matrix.ghc }}
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: haskell-actions/setup@64445b6b5dd545faf5f8e2acee8253eb5c2b29aa # v2.7.11 - uses: haskell-actions/setup@6037f33647c3f17758a2356c80fc4a53d7e0685d # v2.12.0
with: with:
ghc-version: ${{ matrix.ghc }} ghc-version: ${{ matrix.ghc }}
- name: Cache .cabal - name: Cache .cabal
+22 -1
View File
@@ -20,7 +20,7 @@ jobs:
name: Lint & Style name: Lint & Style
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
@@ -30,3 +30,24 @@ jobs:
run: postgrest-lint run: postgrest-lint
- name: Run style check (auto-format with `nix-shell --run postgrest-style`) - name: Run style check (auto-format with `nix-shell --run postgrest-style`)
run: postgrest-style-check 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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
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
+4 -5
View File
@@ -41,23 +41,22 @@ jobs:
concurrency: concurrency:
# Never tag outdated commits on the main branch by skipping superseded commits # Never tag outdated commits on the main branch by skipping superseded commits
group: ci-tag-${{ (github.ref == 'refs/heads/main' && github.ref) || github.run_id }} group: ci-tag-${{ (github.ref == 'refs/heads/main' && github.ref) || github.run_id }}
# TODO: Enable this once https://github.com/orgs/community/discussions/13015 is solved cancel-in-progress: true
cancel-in-progress: false
if: vars.RELEASE_ENABLED if: vars.RELEASE_ENABLED
runs-on: ubuntu-24.04 runs-on: ubuntu-slim
needs: needs:
- docs - docs
- test - test
- build - build
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
ssh-key: ${{ secrets.POSTGREST_SSH_KEY }} ssh-key: ${{ secrets.POSTGREST_SSH_KEY }}
- name: Tag latest commit - name: Tag latest commit
run: | run: |
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)" cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
if [[ "$cabal_version" == *.*.* ]]; then if [[ "$cabal_version" == *.* ]]; then
git fetch --tags git fetch --tags
if [ -z "$(git tag --list "v$cabal_version")" ]; then if [ -z "$(git tag --list "v$cabal_version")" ]; then
+3 -2
View File
@@ -14,6 +14,7 @@ on:
- .github/actions/setup-nix/** - .github/actions/setup-nix/**
- default.nix - default.nix
- nix/** - nix/**
- flake.lock
- docs/** - docs/**
- '!**.md' - '!**.md'
@@ -27,7 +28,7 @@ jobs:
name: Build name: Build
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
@@ -41,7 +42,7 @@ jobs:
name: Spellcheck name: Spellcheck
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
+28 -2
View File
@@ -3,15 +3,41 @@ name: Linkcheck
on: on:
schedule: schedule:
- cron: '1 2 * * 3' - cron: '1 2 * * 3'
workflow_dispatch:
jobs: jobs:
linkcheck: linkcheck:
name: Linkcheck
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: docs.linkcheck.bin tools: docs.linkcheck.bin
- run: postgrest-docs-linkcheck
- name: Run Linkcheck
id: linkcheck
run: postgrest-docs-linkcheck
# This actions creates the github token using the postgrest app secrets
- name: Create Github App Token (Runs only on linkcheck failure)
id: app-token
if: ${{ failure() && steps.linkcheck.outcome == 'failure' }} # only create the token on linkcheck failure
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.POSTGREST_CI_APP_ID }}
private-key: ${{ secrets.POSTGREST_CI_PRIVATE_KEY }}
permission-issues: write # required for commenting on issues
- name: Notify on linkcheck failure by commenting on GH Issue 4106
if: ${{ failure() && steps.linkcheck.outcome == 'failure' }}
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
with:
token: ${{ steps.app-token.outputs.token }}
issue-number: 4106
body: |
**Linkcheck Job Failed!**
A broken link was detected in the docs. Please check the [failed run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.
+91 -70
View File
@@ -9,8 +9,7 @@ on:
concurrency: concurrency:
# Terminate all previous runs of the same workflow for the same tag. # Terminate all previous runs of the same workflow for the same tag.
group: release-${{ github.ref }} group: release-${{ github.ref }}
# TODO: Enable this once https://github.com/orgs/community/discussions/13015 is solved cancel-in-progress: true
cancel-in-progress: false
jobs: jobs:
build: build:
@@ -20,13 +19,15 @@ jobs:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
prepare: github:
name: Prepare name: GitHub
runs-on: ubuntu-24.04 permissions:
contents: write
runs-on: ubuntu-slim
needs: needs:
- build - build
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Check the version to be released - name: Check the version to be released
run: | run: |
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)" cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
@@ -48,25 +49,9 @@ jobs:
echo "Relevant extract from CHANGELOG.md:" echo "Relevant extract from CHANGELOG.md:"
cat CHANGES.md cat CHANGES.md
- name: Save CHANGES.md as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: release-changes
path: CHANGES.md
if-no-files-found: error
github:
name: GitHub
permissions:
contents: write
runs-on: ubuntu-24.04
needs:
- prepare
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
path: artifacts path: artifacts
- name: Create release bundle with archives for all builds - name: Create release bundle with archives for all builds
@@ -75,6 +60,9 @@ jobs:
mkdir -p release-bundle 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" \ tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-linux-static-x86-64.tar.xz" \
-C artifacts/postgrest-linux-static-x86-64 postgrest -C artifacts/postgrest-linux-static-x86-64 postgrest
@@ -87,14 +75,11 @@ jobs:
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-freebsd-x86-64.tar.xz" \ tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-freebsd-x86-64.tar.xz" \
-C artifacts/postgrest-freebsd-x86-64 postgrest -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" \ zip --junk-paths "release-bundle/postgrest-${GITHUB_REF_NAME}-windows-x86-64.zip" \
artifacts/postgrest-windows-x86-64/postgrest.exe artifacts/postgrest-windows-x86-64/postgrest.exe
- name: Save release bundle - name: Save release bundle
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: release-bundle name: release-bundle
path: release-bundle path: release-bundle
@@ -116,14 +101,14 @@ jobs:
gh release edit devel \ gh release edit devel \
-t devel \ -t devel \
--verify-tag \ --verify-tag \
-F artifacts/release-changes/CHANGES.md \ -F CHANGES.md \
--prerelease --prerelease
gh release upload --clobber devel release-bundle/* gh release upload --clobber devel release-bundle/*
else else
gh release create "${GITHUB_REF_NAME}" \ gh release create "${GITHUB_REF_NAME}" \
-t "${GITHUB_REF_NAME}" \ -t "${GITHUB_REF_NAME}" \
--verify-tag \ --verify-tag \
-F artifacts/release-changes/CHANGES.md \ -F CHANGES.md \
release-bundle/* release-bundle/*
fi fi
@@ -132,70 +117,55 @@ jobs:
name: Docker Hub name: Docker Hub
runs-on: ubuntu-24.04-arm runs-on: ubuntu-24.04-arm
needs: needs:
- prepare - github
if: | if: |
vars.DOCKER_REPO && vars.DOCKER_USER vars.DOCKER_REPO && vars.DOCKER_USER
env: env:
DOCKER_REPO: ${{ vars.DOCKER_REPO }} DOCKER_REPO: ${{ vars.DOCKER_REPO }}
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Download aarch64 Docker image
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: postgrest-docker-aarch64
- name: Download x86-64 Docker image - name: Download x86-64 Docker image
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
name: postgrest-docker-x86-64 name: postgrest-docker-x86-64
- name: Download aarch64 binary - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
name: postgrest-ubuntu-aarch64
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with: with:
username: ${{ vars.DOCKER_USER }} username: ${{ vars.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }} 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 - name: Publish images on Docker Hub
run: | 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 load -i postgrest-docker-x86-64.tar.gz
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}" docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-amd64"
docker buildx imagetools create --append \ docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-amd64"
-t "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}" \
"$DOCKER_REPO/postgrest@$SHA256_ARM" 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 # Only tag 'latest' for full releases
if [ "${GITHUB_REF_NAME}" != "devel" ]; then if [ "${GITHUB_REF_NAME}" != "devel" ]; then
echo "Pushing to 'latest' tag for full release of ${GITHUB_REF_NAME} ..." echo "Pushing to 'latest' tag for full release of ${GITHUB_REF_NAME} ..."
docker tag postgrest:latest "$DOCKER_REPO"/postgrest:latest docker manifest create "$DOCKER_REPO/postgrest:latest" \
docker push "$DOCKER_REPO"/postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-arm64" \
docker buildx imagetools create --append \ "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}-linux-amd64"
-t "$DOCKER_REPO/postgrest:latest" \ docker manifest push "$DOCKER_REPO/postgrest:latest"
"$DOCKER_REPO/postgrest@$SHA256_ARM"
else else
echo "Skipping push to 'latest' tag for pre-release..." echo "Skipping push to 'latest' tag for pre-release..."
fi fi
- uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
docker-description: if: github.ref == 'refs/tags/devel'
name: Docker Hub Description name: Docker Hub Description
runs-on: ubuntu-24.04
if: |
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
with: with:
username: ${{ vars.DOCKER_USER }} username: ${{ vars.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }} password: ${{ secrets.DOCKER_PASS }}
@@ -203,3 +173,54 @@ jobs:
short-description: ${{ github.event.repository.description }} short-description: ${{ github.event.repository.description }}
readme-filepath: ./docker-hub-readme.md readme-filepath: ./docker-hub-readme.md
ghcr:
name: GitHub Container Registry
runs-on: ubuntu-24.04-arm
needs:
- github
permissions:
packages: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- 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@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: postgrest-docker-x86-64
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Publish images on Docker Hub
run: |
docker load -i postgrest-docker-aarch64.tar.gz
docker tag postgrest:latest "ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}-linux-arm64"
docker push "ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}-linux-arm64"
docker load -i postgrest-docker-x86-64.tar.gz
docker tag postgrest:latest "ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}-linux-amd64"
docker push "ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}-linux-amd64"
docker manifest create "ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}" \
"ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}-linux-arm64" \
"ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}-linux-amd64"
docker manifest push "ghcr.io/${GITHUB_REPOSITORY,,}:${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 manifest create "ghcr.io/${GITHUB_REPOSITORY,,}:latest" \
"ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}-linux-arm64" \
"ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_REF_NAME}-linux-amd64"
docker manifest push "ghcr.io/${GITHUB_REPOSITORY,,}:latest"
else
echo "Skipping push to 'latest' tag for pre-release..."
fi
+76 -25
View File
@@ -17,6 +17,7 @@ on:
- .github/actions/setup-nix/** - .github/actions/setup-nix/**
- default.nix - default.nix
- nix/** - nix/**
- flake.lock
- .stylish-haskell.yaml - .stylish-haskell.yaml
- cabal.project - cabal.project
- postgrest.cabal - postgrest.cabal
@@ -24,6 +25,10 @@ on:
- test/** - test/**
- '!**.md' - '!**.md'
defaults:
run:
shell: bash
concurrency: concurrency:
# Terminate all previous runs of the same workflow for pull requests # Terminate all previous runs of the same workflow for pull requests
group: test-${{ github.head_ref || github.run_id }} group: test-${{ github.head_ref || github.run_id }}
@@ -39,24 +44,26 @@ jobs:
# https://github.com/actions/runner/issues/241#issuecomment-842566950 # https://github.com/actions/runner/issues/241#issuecomment-842566950
shell: script -qec "bash --noprofile --norc -eo pipefail {0}" shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 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 run: postgrest-coverage
- name: Upload coverage to codecov - name: Upload coverage to codecov
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2 uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with: with:
files: ./coverage/codecov.json files: ./coverage/codecov.json
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
- name: Run doctests - name: Run doctests
if: always() if: always()
run: postgrest-test-doctests run: nix-shell --run postgrest-test-doctests
- name: Check the spec tests for idempotence - name: Check the spec tests for idempotence
if: always() if: always()
@@ -67,8 +74,9 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
pgVersion: [12, 13, 14, 15, 16, 17] # Latest version is tested via `coverage` above.
name: PG ${{ matrix.pgVersion }} pgVersion: [pg-14, pg-15, pg-16, pg-17, oriole-18, pg-18]
name: ${{ matrix.pgVersion }}
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
defaults: defaults:
run: run:
@@ -76,77 +84,120 @@ jobs:
# https://github.com/actions/runner/issues/241#issuecomment-842566950 # https://github.com/actions/runner/issues/241#issuecomment-842566950
shell: script -qec "bash --noprofile --norc -eo pipefail {0}" shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 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.${{ matrix.pgVersion }}.bin cabalTools.update.bin
- run: postgrest-cabal-update
- name: Run spec tests - name: Run spec tests
if: always() if: always()
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-spec run: postgrest-with-${{ matrix.pgVersion }} postgrest-test-spec
- name: Run observability tests
if: always()
run: postgrest-with-${{ matrix.pgVersion }} postgrest-test-observability
- name: Run IO tests - name: Run IO tests
if: always() if: always()
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-io -vv run: postgrest-with-${{ matrix.pgVersion }} postgrest-test-io -vv
- name: Run IO tests on a big schema - name: Run IO tests on a big schema
if: always() if: always()
run: postgrest-with-postgresql-${{ matrix.pgVersion }} postgrest-test-big-schema -vv run: postgrest-with-${{ matrix.pgVersion }} postgrest-test-big-schema -vv
memory: memory:
name: Memory name: Memory
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: tests.testMemory.bin tools: tests.testMemory.bin cabalTools.update.bin
- run: postgrest-cabal-update
- name: Run memory tests - name: Run memory tests
run: postgrest-test-memory run: postgrest-test-memory
loadtest: loadtest:
strategy: strategy:
fail-fast: false
matrix: matrix:
kind: ['mixed', 'jwt'] kind: ['mixed', 'jwt-cache']
name: Loadtest name: Loadtest
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup Nix Environment - name: Setup Nix Environment
uses: ./.github/actions/setup-nix uses: ./.github/actions/setup-nix
with: with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: loadtest.loadtestAgainst.bin loadtest.report.bin tools: loadtest.loadtestAgainst.bin loadtest.report.bin loadtest.report-load.bin cabalTools.update.bin
- uses: WyriHaximus/github-action-get-previous-tag@04e8485ecb6487243907e330d522ff60f02283ce # v1.4.0
id: get-latest-tag - run: postgrest-cabal-update
with:
prefix: v
- name: Run loadtest - name: Run loadtest
env:
TARGET_BRANCH: ${{ github.base_ref || github.ref_name }}
run: | run: |
postgrest-loadtest-against -k ${{ matrix.kind }} main ${{ steps.get-latest-tag.outputs.tag }} if [ "$TARGET_BRANCH" = "main" ]; then
postgrest-loadtest-report >> "$GITHUB_STEP_SUMMARY" 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"
- name: Report P50
# This step checks whether any red cross indicators (:x:) are present in the step summary.
# The loadtest reporter writes them when any of individual steps fails the performance
# regression threshold.
run: |
! (postgrest-loadtest-report -g ${{ matrix.kind }} -p 50 \
| tee "$GITHUB_STEP_SUMMARY" \
| grep ':x:')
- name: Report P0
if: always()
run: |
postgrest-loadtest-report -g ${{ matrix.kind }} -p 0 >> "$GITHUB_STEP_SUMMARY"
- name: Report P90
if: always()
run: |
postgrest-loadtest-report -g ${{ matrix.kind }} -p 90 >> "$GITHUB_STEP_SUMMARY"
- name: Report P95
if: always()
run: |
postgrest-loadtest-report -g ${{ matrix.kind }} -p 95 >> "$GITHUB_STEP_SUMMARY"
- name: Report CPU/MEM
if: always()
run: |
postgrest-loadtest-report-load -g ${{ matrix.kind }} >> "$GITHUB_STEP_SUMMARY"
flake: flake:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
runs-on: runs-on:
- macos-13 # x86_64-darwin
- macos-14 # aarch64-darwin - macos-14 # aarch64-darwin
- ubuntu-24.04 # x86_64-linux - ubuntu-24.04 # x86_64-linux
- ubuntu-24.04-arm # aarch64-linux - ubuntu-24.04-arm # aarch64-linux
name: Flake Check name: Flake Check
runs-on: ${{ matrix.runs-on }} runs-on: ${{ matrix.runs-on }}
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup Nix Environment - name: Setup Nix Environment
+6
View File
@@ -25,3 +25,9 @@ loadtest
.history .history
.docs-build .docs-build
gen_targets.http gen_targets.http
gen_jwks.json
gen_private.json
.pytest_cache
.ruff_cache
postgrest-module-graph.png
.ghc.environment.*
+1 -1
View File
@@ -7,4 +7,4 @@ python:
build: build:
os: ubuntu-24.04 os: ubuntu-24.04
tools: tools:
python: "3.11" python: "3.12"
+1 -1
View File
@@ -200,7 +200,7 @@ steps:
# A common setting is the number of columns (parts of) code will be wrapped # A common setting is the number of columns (parts of) code will be wrapped
# to. Different steps take this into account. Default: 80. # to. Different steps take this into account. Default: 80.
columns: 70 columns: 80
# By default, line endings are converted according to the OS. You can override # By default, line endings are converted according to the OS. You can override
# preferred format here. # preferred format here.
+15 -10
View File
@@ -13,26 +13,26 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
</a> </a>
</td> </td>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <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/neon.jpg"> <img width="296px" src="static/supabase.svg">
</a> </a>
</td> </td>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <a href="https://www.euronodes.com/postgrest" target="_blank">
<img width="296px" src="static/code-build.png"> <img width="296px" src="static/euronodes.svg">
</a> </a>
</td> </td>
</tr> </tr>
<tr></tr> <tr></tr>
<tr> <tr>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png"> <img width="296px" src="static/neon.jpg">
</a> </a>
</td> </td>
<td align="center" valign="middle"> <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"> <a href="https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/supabase.png"> <img width="296px" src="static/bytebase.svg">
</a> </a>
</td> </td>
</tr> </tr>
@@ -89,8 +89,13 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
</a> </a>
</td> </td>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="222px" src="static/gnuhost.png"> <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> </a>
</td> </td>
</tr> </tr>
+318 -5
View File
@@ -1,10 +1,319 @@
# Change Log # Change Log
All notable changes to this project will be documented in this file. 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.
This project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased ## Unreleased
## [16.1] - 2026-08-10
### Fixed
- JWT validation uses wrong current time due to a bug in auto-update by @mkleczek in #5159
## [16.0] - 2026-08-07
### Changes
#### HTTP Server
- [Graceful shutdown](https://docs.postgrest.org/en/v16/references/http_server.html#graceful-shutdown) by @mkleczek, @Vlix in #4702
- [server-reuseport](https://docs.postgrest.org/en/v16/references/configuration.html#server-reuseport) allows starting multiple PostgREST instances using the same port on supported platforms by @mkleczek in #4703, #4694
#### Performance
- Optimize schema cache domain type resolution by using [pg_basetype](https://www.postgresql.org/docs/current/functions-info.html#FUNCTIONS-INFO-CATALOG) on PostgreSQL 17+ by @joelonsql in #4567
- [Prefer: count=exact](https://docs.postgrest.org/en/v16/references/api/pagination_count.html#exact-count) no longer does a double count on requests that do not use ranges or `db-max-rows` by @laurenceisla in #3957
- [Prefer: timezone](https://docs.postgrest.org/en/v16/references/api/preferences.html#prefer-timezone) no longer requires the schema cache by @steve-chavez in #5100
+ Previously this required caching [pg_timezone_names](https://www.postgresql.org/docs/current/view-pg-timezone-names.html) which was slow in some systems
#### Integrations
- PostgREST is now tested to work with [OrioleDB](https://github.com/orioledb/orioledb/) in #4845 by @wolfgangwalther
+ See [our guide for running OrioleDB on NixOS](https://docs.postgrest.org/en/v16/integrations/nixos.html)
#### JWT
- [JWT Role Extraction](https://docs.postgrest.org/en/v16/references/auth.html#jwt-role-extract) is now more flexible, supporting the standard JSON Path defined in RFC 9535 by @taimoorzaeem in #4984
#### API
- [Prefer: timezone](https://docs.postgrest.org/en/v16/references/api/preferences.html#timezone) now supports numeric offsets like `05:00` or `-4` by @steve-chavez in #5100
- Fix unexpected results when embedding and filtering the same table more than once by @laurenceisla in #4075
+ You need to set [url-use-legacy-target-names](https://docs.postgrest.org/en/v16/references/configuration.html#url-use-legacy-target-names) to `false`.
- Deprecate filters, orders and limits with the name of an embedded table when it has an alias by @steve-chavez, @laurenceisla in #4075
+ e.g. `?select=alias:table(*)&table.id=eq.1` will not be possible anymore, use `?select=alias:table(*)&alias.id=eq.1` instead.
+ You will see a warning in the logs and a `Warning` header on the client response when this happens.
+ You can disable this behavior now by setting `url-use-legacy-target-names = false`.
- Add `Vary` header to responses by @develop7 in #4609
- Fix automatic transaction retries on `40001 (serialization_failure)` errors to prevent replication lag by @laurenceisla in #3673
#### Observability
- [GHC runtime metrics](https://docs.postgrest.org/en/v16/references/observability.html#ghc-runtime-metrics) by @mkleczek in #4862
- [client-error-verbosity](https://docs.postgrest.org/en/v16/references/configuration.html#client-error-verbosity) to customize responses error verbosity by @taimoorzaeem in #4088, #3980, #3824
- [log-level](https://docs.postgrest.org/en/v16/references/configuration.html#log-level) config is now reloadable by @taimoorzaeem in #5113
- Log error when `db-schemas` config contains schema `pg_catalog` or `information_schema` by @taimoorzaeem in #4359
- Log schema cache queries timings on `log-level=debug` by @steve-chavez in #4805
#### Admin Server
- [admin-server-unix-socket](https://docs.postgrest.org/en/v16/references/configuration.html#admin-server-unix-socket)/[admin-server-unix-socket-mode](https://docs.postgrest.org/en/v16/references/configuration.html#admin-server-unix-socket-mode) to run the admin server on a unix socket by @wolfgangwalther in #5003
- Fix responding with `Something went wrong` on Admin server when under EMFILE by @mkleczek in #5077
#### Deployment
- Make executable for aarch64-linux static instead of Ubuntu-based by @wolfgangwalther in #4193
- Docker image for aarch64-linux is now built from scratch instead of being Ubuntu-based by @wolfgangwalther in #4193
- Besides Docker Hub, docker images are now published to Github Container Registry by @wolfgangwalther in #2836
#### Schema Cache
- Fix requests failing when the schema cache fails to reload, when this happens PostgREST will continue serving requests in "best effort" by @mkleczek in #4873 #4869
- Fix reporting 503s errors unnecessarily while the schema cache is loading at startup by @mkleczek in #4880
- Fix schema cache dump missing RPC transaction isolation level by @taimoorzaeem in #5079
#### Listener
- Fix config `db-channel-enabled` not reloading by @taimoorzaeem in #4894
### Migration to v16
- Drop support for PostgreSQL EOL version 13 by @wolfgangwalther in #4193
+ PostgreSQL 13 end of life was on 2025 ([ref](https://www.postgresql.org/support/versioning/))
+ Upgrade your PostgreSQL version to at least 14 to use this new PostgREST version.
- Fail at startup when `db-schemas` contains schema `pg_catalog` or `information_schema` by @taimoorzaeem in #4359
+ Previously it failed at runtime with `PGRST205` on requests related to these schemas.
+ Remove `pg_catalog` and `information_schema` from `db-schemas`.
- `Prefer: timezone` no longer complies with `handling=lenient` and instead always fails by @steve-chavez in #5128
+ Supporting this required caching `pg_timezone_names`, which was expensive.
+ Ensure your requests always have a valid timezone.
- `jwt-role-claim-key` no longer uses the JSPath DSL and instead uses JSON Path by @taimoorzaeem in #4984
+ Now all config values must start with `$` character.
Example: `.roles.read` -> `$.roles.read`
+ Keys with special characters, with the exception of `_` char must be quoted.
Example: `.roles.write-role` -> `$.roles["write-role"]`
+ String comparison operators (`^==`, `==^` and `*==`) are replaced with regular expression search.
Example: `.roles[?(@ ^== "postgrest_test_")]` -> `$.roles[?search(@, "^postgrest_test_")]`
+ Update the `jwt-role-claim-key` value accoring to the above rules. Also see the syntax reference: [RFC 9535](https://www.rfc-editor.org/rfc/rfc9535.html#name-jsonpath-syntax-and-semanti).
## [14.16] - 2026-07-27
### Fixed
- Fix admin server crashing without a way to recover by @taimoorzaeem in #5096
## [14.15] - 2026-07-13
### Fixed
- Fix admin server dying silently by @Vlix, @mkleczek, @steve-chavez in #5012
## [14.14] - 2026-06-29
### Fixed
- Fix admin server not logging cause of failure by @taimoorzaeem in #5012
## [14.13] - 2026-06-04
### Fixed
- Fix connection retrying message in `PGRST000` error by @netqo in #4980
+ Remove redundant "Retrying the connection." from message because it is logged separately
- Fix request failures when `work_mem` is set on a role by @laurenceisla in #4955
## [14.12] - 2026-05-20
### Fixed
- Fix race condition in pool_available metric causing negative values during network instability by @mkleczek in #4622
## [14.11] - 2026-05-04
### Fixed
- Fix login with uppercase and mixed case role names by @taimoorzaeem in #4678
- Restore Listener query shape so it can be found in `pg_stat_activity` by @mkleczek in #4857 #4859
- The LISTEN channel now automatically recovers when it stops working due to a PostgreSQL bug @laurenceisla in #3147
- Fix misleading "Functions" name on schema cache summary in startup logs by @taimoorzaeem in #4821
## [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 ## [13.0.0] - 2025-05-08
### Added ### Added
@@ -47,8 +356,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #2052, Dropped support for PostgreSQL 11 - @wolfgangwalther - #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 - #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 - #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. - 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 - #3757, Remove support for `Prefer: params=single-object` - @joelonsql
+ This preference was deprecated in favor of Functions with an array of JSON objects + This preference was deprecated in favor of Functions with an array of JSON objects
- #3013, Drop support for Limited updates/deletes - #3013, Drop support for Limited updates/deletes
@@ -56,6 +366,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #3956, Drop `/config` endpoint of admin server - @steve-chavez - #3956, Drop `/config` endpoint of admin server - @steve-chavez
+ The endpoint was at risk of being left unprotected when exposing it. + The endpoint was at risk of being left unprotected when exposing it.
+ The accompanying `admin-server-config-enabled` config was also dropped. + 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 - #3697, #3602, Querying non-existent table now returns `PGRST205` error instead of empty json - @taimoorzaeem
- #3600, #3926, Improve JWT errors - @taimoorzaeem - #3600, #3926, Improve JWT errors - @taimoorzaeem
+ Return `PGRST301` error when `Bearer` in auth header is sent empty + Return `PGRST301` error when `Bearer` in auth header is sent empty
@@ -492,7 +805,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added ### Added
- #1933, #2109, Add a minimal health check endpoint - @steve-chavez - #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>/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. + 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 - #1988, Add the current user to the request log on stdout - @DavidLindbom, @wolfgangwalther
@@ -975,7 +1288,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Customize content negotiation per route - @begriffs - Customize content negotiation per route - @begriffs
- Allow using nulls order without explicit order direction - @steve-chavez - Allow using nulls order without explicit order direction - @steve-chavez
- Fatal error on postgres unsupported version, format supported version in error message - @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 - Use specific columns in the RETURNING section - @ruslantalpa
- Fix columns alias for RETURNING - @steve-chavez - Fix columns alias for RETURNING - @steve-chavez
+64
View File
@@ -0,0 +1,64 @@
# 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 features must document the new behavior. Critical fixes that introduce new behavior must be documented too.
* 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) 2014-2026 The PostgREST contributors
Copyright (c) 2019 Steve Chavez
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the 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> </a>
</td> </td>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <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/neon.jpg"> <img width="296px" src="static/supabase.svg">
</a> </a>
</td> </td>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <a href="https://www.euronodes.com/postgrest" target="_blank">
<img width="296px" src="static/code-build.png"> <img width="296px" src="static/euronodes.svg">
</a> </a>
</td> </td>
</tr> </tr>
<tr></tr> <tr></tr>
<tr> <tr>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png"> <img width="296px" src="static/neon.jpg">
</a> </a>
</td> </td>
<td align="center" valign="middle"> <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"> <a href="https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/supabase.png"> <img width="296px" src="static/bytebase.svg">
</a> </a>
</td> </td>
</tr> </tr>
@@ -52,8 +52,8 @@ Big thanks to our sponsors! You can join them by supporting PostgREST on [Patreo
## Usage ## Usage
1. Download the binary ([latest release](https://github.com/PostgREST/postgrest/releases/latest)) 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).
for your platform.
2. Invoke for help: 2. Invoke for help:
```bash ```bash
@@ -125,7 +125,7 @@ and limited with - range headers. More about
## Data Integrity ## Data Integrity
Rather than relying on an Object Relational Mapper and custom 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 directly into your database. Hence no application can corrupt your
data (including your API server). 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. 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 ## Thanks
The PostgREST organization is grateful to: The PostgREST organization is grateful to:
+5 -2
View File
@@ -1,4 +1,7 @@
packages: postgrest.cabal packages: postgrest.cabal
tests: true tests: true
package * allow-newer:
ghc-options: -split-sections hasql:postgresql-libpq
-- https://github.com/martijnbastiaan/doctest-parallel/blob/main/example/README.md#cabalproject
write-ghc-environment-files: always
+1 -1
View File
@@ -1 +1 @@
index-state: hackage.haskell.org 2025-02-01T14:59:33Z index-state: hackage.haskell.org 2026-08-10T16:58:32Z
+52 -15
View File
@@ -1,6 +1,6 @@
{ system ? builtins.currentSystem { system ? builtins.currentSystem
, compiler ? "ghc948" , compiler ? "ghc9123"
, # Commit of the Nixpkgs repository that we want to use. , # Commit of the Nixpkgs repository that we want to use.
# It defaults to reading the inputs from flake.lock, which serves # It defaults to reading the inputs from flake.lock, which serves
@@ -43,9 +43,7 @@ let
allOverlays.build-toolbox allOverlays.build-toolbox
allOverlays.checked-shell-script allOverlays.checked-shell-script
allOverlays.gitignore allOverlays.gitignore
allOverlays.postgresql-libpq
(allOverlays.haskell-packages { inherit compiler; }) (allOverlays.haskell-packages { inherit compiler; })
allOverlays.slocat
]; ];
# Evaluated expression of the Nixpkgs repository. # Evaluated expression of the Nixpkgs repository.
@@ -54,16 +52,26 @@ let
postgresqlVersions = postgresqlVersions =
[ [
{ name = "postgresql-17"; postgresql = pkgs.postgresql_17.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "pg-19"; postgresql = pkgs.postgresql_19.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "pg-18"; postgresql = pkgs.postgresql_18.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "pg-17"; postgresql = pkgs.postgresql_17.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "pg-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-13"; postgresql = pkgs.postgresql_13.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "pg-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-12"; postgresql = pkgs.postgresql_12.withPackages (p: [ p.postgis p.pg_safeupdate ]); } { name = "pg-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{
name = "oriole-18";
postgresql = pkgs.orioledb.withPackages (p: [ p.postgis p.pg_safeupdate ]);
config = "
default_table_access_method = 'orioledb'
shared_preload_libraries = 'orioledb, pg_stat_statements'
";
}
]; ];
haskellPackages = pkgs.haskell.packages."${compiler}";
# Dynamic derivation for PostgREST # 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. # To allow ghc-datasize to be used.
lib.disableLibraryProfiling lib.disableLibraryProfiling
# We are never going to use dynamic haskell libraries anyway. "Dynamic" refers to how # We are never going to use dynamic haskell libraries anyway. "Dynamic" refers to how
@@ -75,18 +83,33 @@ let
# Options passed to cabal in dev tools and tests # Options passed to cabal in dev tools and tests
devCabalOptions = devCabalOptions =
"-f dev --test-show-detail=direct --disable-shared"; "-f dev --test-show-detail=direct";
inherit (pkgs.haskell) lib; inherit (pkgs.haskell) lib;
nixos-lib = import (pkgs.path + "/nixos/lib") { };
runTest = postgrest: test: (nixos-lib.runTest {
hostPkgs = pkgs;
# Replace the top-level `pkgs.postgrest` attribute with our current version on this branch.
defaults.nixpkgs.overlays = [ (_: _: { inherit postgrest; }) ];
# Speeds up evaluation a little bit; documentation is really not required for tests.
defaults.documentation.enable = pkgs.lib.mkDefault false;
imports = [ test ];
}).config.result;
in in
rec { rec {
inherit nixpkgs pkgs; inherit nixpkgs pkgs;
# Derivation for the PostgREST Haskell package, including the executable, # Derivation for the PostgREST Haskell package, including the executable,
# libraries and documentation. We disable running the test suite on Nix # libraries and documentation. We disable running the test suite on Nix
# builds, as they require a database to be set up. # builds, as they require a database to be set up. We split the binary
postgrestPackage = # into a separate output, so that the default distribution via flake.nix
lib.dontCheck postgrest; # has a much smaller closure size.
postgrestPackage = pkgs.lib.pipe postgrest [
lib.dontCheck
lib.enableSeparateBinOutput
(haskellPackages.generateOptparseApplicativeCompletions [ "postgrest" ])
];
# Profiled dynamic executable. # Profiled dynamic executable.
postgrestProfiled = pkgs.lib.pipe postgrestPackage [ postgrestProfiled = pkgs.lib.pipe postgrestPackage [
@@ -103,6 +126,9 @@ rec {
inherit (pkgs.haskell.packages."${compiler}") ghcWithPackages; inherit (pkgs.haskell.packages."${compiler}") ghcWithPackages;
}; };
# Used by CI on MacOS
inherit (pkgs) nix-build-uncached;
### Tools ### Tools
cabalTools = cabalTools =
@@ -113,16 +139,24 @@ rec {
# Development tools. # Development tools.
devTools = devTools =
pkgs.callPackage nix/tools/devTools.nix { inherit tests style devCabalOptions hsie withTools; }; pkgs.callPackage nix/tools/devTools.nix { inherit tests style devCabalOptions hsie; };
# Documentation tools. # Documentation tools.
docs = docs =
pkgs.callPackage nix/tools/docs.nix { }; pkgs.callPackage nix/tools/docs.nix { };
# Git tools.
gitTools =
pkgs.callPackage nix/tools/gitTools.nix { };
# Load testing tools. # Load testing tools.
loadtest = loadtest =
pkgs.callPackage nix/tools/loadtest.nix { inherit withTools; }; 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. # Scripts for publishing new releases.
release = release =
pkgs.callPackage nix/tools/release.nix { }; pkgs.callPackage nix/tools/release.nix { };
@@ -147,4 +181,7 @@ rec {
# Docker images and loading script. # Docker images and loading script.
docker = docker =
pkgs.callPackage nix/tools/docker { postgrest = postgrestStatic; }; pkgs.callPackage nix/tools/docker { postgrest = postgrestStatic; };
# NixOS VM tests
nixpkgs-nixos-test = runTest postgrestStatic (pkgs.path + "/nixos/tests/postgrest.nix");
} }
+8 -10
View File
@@ -19,26 +19,26 @@ write from scratch.
</a> </a>
</td> </td>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <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/neon.jpg"> <img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/supabase.svg">
</a> </a>
</td> </td>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <a href="https://www.euronodes.com/postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/code-build.png"> <img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/euronodes.svg">
</a> </a>
</td> </td>
</tr> </tr>
<tr></tr> <tr></tr>
<tr> <tr>
<td align="center" valign="middle"> <td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank"> <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/tembo.png"> <img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/neon.jpg">
</a> </a>
</td> </td>
<td align="center" valign="middle"> <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"> <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/supabase.png"> <img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/bytebase.svg">
</a> </a>
</td> </td>
</tr> </tr>
@@ -61,5 +61,3 @@ The image is built from scratch using
no commands are listed in the image history. See the [PostgREST no commands are listed in the image history. See the [PostgREST
repository](https://github.com/PostgREST/postgrest/tree/main/nix/tools/docker) for repository](https://github.com/PostgREST/postgrest/tree/main/nix/tools/docker) for
details on the build process and how to inspect the image. 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: :user:
hexagon Proxy hexagon Proxy
:user: .r-> Proxy :user: .r-> Proxy : request with JWT
HTTPAPI <.l- Proxy HTTPAPI <.l- Proxy
hexagon ExternalAuth
ExternalAuth -u[hidden]- Proxy
:user: .r-> ExternalAuth : login
:user: <.r- ExternalAuth : JWT
:operator: .d-> HTTPADMIN :operator: .d-> HTTPADMIN
:operator: .d-> CLI :operator: .d-> CLI
@@ -51,9 +56,8 @@ PostgreSQL <.developer : "\t"
Listener -r.> "PostgreSQL" Listener -r.> "PostgreSQL"
"Connection Pool" -r.> "PostgreSQL" : "\t\t" "Connection Pool" -r.> "PostgreSQL" : "\t\t"
note bottom of Auth note bottom of Auth
Authenticates the user request Validates the JWT
end note end note
note bottom of ApiRequest note bottom of ApiRequest
@@ -72,6 +76,7 @@ note top of Listener
LISTEN session LISTEN session
end note end note
url of ExternalAuth is [[../explanations/external_auth.html]]
url of Admin is [[../references/admin_server.html#admin-server]] url of Admin is [[../references/admin_server.html#admin-server]]
url of API is [[../explanations/schema_isolation.html]] url of API is [[../explanations/schema_isolation.html]]
url of Auth is [[../references/auth.html#authn]] 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 CLI is [[../references/cli.html#cli]]
url of "Connection Pool" is [[../references/connection_pool.html]] url of "Connection Pool" is [[../references/connection_pool.html]]
url of Config is [[../references/configuration.html#configuration]] url of Config is [[../references/configuration.html#configuration]]
url of HTTPADMIN is [[https://aosabook.org/en/posa/warp.html]] url of HTTPADMIN is [[../references/http_server.html]]
url of HTTPAPI is [[https://aosabook.org/en/posa/warp.html]] url of HTTPAPI is [[../references/http_server.html]]
url of Listener is [[../references/listener.html#listener]] url of Listener is [[../references/listener.html#listener]]
url of Proxy is [[../explanations/nginx.html]] url of Proxy is [[../explanations/nginx.html]]
url of "Schema Cache" is [[../references/schema_cache.html#schema-cache]] 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: 31 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: 32 KiB

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

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

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

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

+7 -5
View File
@@ -12,7 +12,6 @@
# All configuration values have a default; values that are commented out # All configuration values have a default; values that are commented out
# serve to show the default. # serve to show the default.
import sys
import os import os
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
@@ -49,14 +48,14 @@ source_suffix = ".rst"
# The master toctree document. # The master toctree document.
master_doc = "index" master_doc = "index"
# This is overriden by readthedocs with the version tag anyway # This is overridden by readthedocs with the version tag anyway
version = "13.0" version = "devel"
# To avoid repetition in <title> we set this to an empty string. # To avoid repetition in <title> we set this to an empty string.
release = "" release = ""
# General information about the project. # General information about the project.
project = "PostgREST " + version project = "PostgREST " + version
author = "Joe Nelson, Steve Chavez" author = "The PostgREST contributors"
copyright = "2017, " + author copyright = "2017, " + author
# The language for content autogenerated by Sphinx. Refer to documentation # 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 # 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 # further. For a list of options available for each theme, see the
# documentation. # documentation.
html_theme_options = {"display_version": False} html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory. # Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = [] # html_theme_path = []
@@ -300,8 +299,11 @@ linkcheck_ignore = [
# 403 only in CI / GitHub Actions # 403 only in CI / GitHub Actions
r"https://www.patreon.com/postgrest", r"https://www.patreon.com/postgrest",
r"https://blog.frankel.ch/poor-man-api", r"https://blog.frankel.ch/poor-man-api",
r"https://www.cybertec-postgresql.com/.*",
r"https://stackoverflow.com/.*",
# Odd SSL error # Odd SSL error
r"https://www.dripdepot.com", r"https://www.dripdepot.com",
r"https://www.euronodes.com",
# New GitHub UI delays comment load, so anchor fails # New GitHub UI delays comment load, so anchor fails
r"https://github.com/.*#issuecomment", r"https://github.com/.*#issuecomment",
# Random 500 Internal Server Error # Random 500 Internal Server Error
+4 -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>`_ - * `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. 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/>`_ - * `"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). A step-by-step tutorial for using PostgREST with KeyCloak(hosted on a managed service).
@@ -34,9 +34,10 @@ Templates
Example Apps 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 * `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 * `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 * `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 * `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 * `PostGUI <https://github.com/priyank-purohit/PostGUI>`_ - React Material UI admin panel
@@ -82,6 +83,7 @@ Extensions
Client-Side Libraries Client-Side Libraries
--------------------- ---------------------
* `efcore-postgrest <https://github.com/pedro-gilmora/EF.PostgREST.Provider>`_ - C#
* `postgrest-csharp <https://github.com/supabase-community/postgrest-csharp>`_ - C# * `postgrest-csharp <https://github.com/supabase-community/postgrest-csharp>`_ - C#
* `postgrest-dart <https://github.com/supabase/postgrest-dart>`_ - Dart * `postgrest-dart <https://github.com/supabase/postgrest-dart>`_ - Dart
* `postgrest-ex <https://github.com/supabase-community/postgrest-ex>`_ - Elixir * `postgrest-ex <https://github.com/supabase-community/postgrest-ex>`_ - Elixir
+11 -16
View File
@@ -31,65 +31,60 @@ This section talks briefly about various important modules.
Main Main
---- ----
The starting point of the program is `Main.hs <https://github.com/PostgREST/postgrest/blob/main/main/Main.hs>`_. The starting point of the program is `Main.hs <https://github.com/PostgREST/postgrest/blob/main/src/executable/Main.hs>`_.
CLI CLI
--- ---
Main then calls `CLI.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/CLI.hs>`_, which is in charge of :ref:`cli`. Main then calls `CLI.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/CLI.hs>`_, which is in charge of :ref:`cli`.
App App
--- ---
`App.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/App.hs>`_ is then in charge of composing the different modules. `App.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/App.hs>`_ is then in charge of composing the different modules.
Auth Auth
---- ----
`Auth.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Auth.hs>`_ is in charge of :ref:`authn`. `Auth.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/Auth.hs>`_ is in charge of :ref:`authn`.
Api Request Api Request
----------- -----------
`ApiRequest.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/ApiRequest.hs>`_ is in charge of parsing the URL query string (following PostgREST syntax), the request headers, and the request body. `ApiRequest.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/ApiRequest.hs>`_ is in charge of parsing the URL query string (following PostgREST syntax), the request headers, and the request body.
A request might be rejected at this level if it's invalid. For example when providing an unknown media type to PostgREST or using an unknown HTTP method. A request might be rejected at this level if it's invalid. For example when providing an unknown media type to PostgREST or using an unknown HTTP method.
Plan Plan
---- ----
Using the Schema Cache, `Plan.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Plan.hs>`_ generates an internal AST, filling out-of-band SQL details (like an ``ON CONFLICT (pk)`` clause) required to complete the user request. Using the Schema Cache, `Plan.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/Plan.hs>`_ generates an internal AST, filling out-of-band SQL details (like an ``ON CONFLICT (pk)`` clause) required to complete the user request.
A request might be rejected at this level if it's invalid. For example when doing resource embedding on a nonexistent resource. A request might be rejected at this level if it's invalid. For example when doing resource embedding on a nonexistent resource.
Query Query
----- -----
`Query.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Query.hs>`_ generates the SQL queries (parametrized and prepared) required to satisfy the user request. `Query.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/Query.hs>`_ generates the SQL queries (parametrized and prepared) required to satisfy the user request.
Only at this stage a connection from the pool might be used. Only at this stage a connection from the pool might be used.
Schema Cache Schema Cache
------------ ------------
`SchemaCache.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/SchemaCache.hs>`_ is in charge of :ref:`schema_cache`. `SchemaCache.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/SchemaCache.hs>`_ is in charge of :ref:`schema_cache`.
Config Config
------ ------
`Config.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Config.hs>`_ is in charge of :ref:`configuration`. `Config.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/Config.hs>`_ is in charge of :ref:`configuration`.
Admin Admin
----- -----
`Admin.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Admin.hs>`_ is in charge of the :ref:`admin_server`. `Admin.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/Admin.hs>`_ is in charge of the :ref:`admin_server`.
HTTP
----
The HTTP server is provided by `Warp <https://aosabook.org/en/posa/warp.html>`_.
Listener Listener
-------- --------
`Listener.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Listener.hs>`_ is in charge of the :ref:`listener`. `Reload.hs <https://github.com/PostgREST/postgrest/blob/main/src/library/PostgREST/AppState/Reload.hs>`_ is in charge of the :ref:`listener`.
+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 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. 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 .. 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 a sample function
create or replace function login(email text, pass text, out token text) as $$ 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 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. 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. 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/>`_. 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 .. code-block:: bash
# pull the latest version
docker pull postgrest/postgrest 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`. 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. 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: ports:
- "3000:3000" - "3000:3000"
environment: 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_DB_URI: postgres://app_user:password@db:5432/app_db
PGRST_OPENAPI_SERVER_PROXY_URI: http://127.0.0.1:3000 PGRST_OPENAPI_SERVER_PROXY_URI: http://127.0.0.1:3000
depends_on: 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. 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: .. _build_source:
Building from Source Building from Source
@@ -0,0 +1,62 @@
.. _debugging_performance_pg_stat_statements:
Debugging Performance with pg_stat_statements
=============================================
This how-to shows how to get a query identifier through PostgREST and then use it to inspect the same query in ``pg_stat_statements``.
.. important::
- :ref:`db-plan-enabled` must be enabled in PostgREST.
- PostgreSQL 14 or newer with ``pg_stat_statements`` available.
Get the Query Identifier from PostgREST
---------------------------------------
Request the plan in JSON format with the ``verbose`` option:
.. code-block:: bash
curl "http://localhost:3000/projects?select=id,name&order=id" \
-H "Accept: application/vnd.pgrst.plan+json; options=verbose"
The response will contain a top-level ``Query Identifier`` field:
.. code-block:: json
[
{
"Plan": {
"Node Type": "Aggregate"
},
"Query Identifier": -432192689578025496
}
]
Look up the query in pg_stat_statements
---------------------------------------
Use that identifier against ``pg_stat_statements``:
.. code-block:: postgres
select
calls,
total_exec_time,
mean_exec_time,
rows,
query
from pg_stat_statements
where queryid = -432192689578025496;
.. csv-table::
:header: "calls", "total_exec_time", "mean_exec_time", "rows", "query"
"13", "0.6355850000000001", "0.04889115384615385", "13", "WITH pgrst_source AS (...)"
This lets you correlate a PostgREST request with PostgreSQL runtime statistics such as:
- how often the query ran
- total and average execution time
- how many rows it produced
- the normalized SQL text recorded by PostgreSQL
@@ -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; 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 .. code-block:: postgres
@@ -157,7 +157,7 @@ Here we use the username instead of the email address to identify a user.
Logins 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 .. code-block:: postgres
+3 -1
View File
@@ -3,7 +3,7 @@
SQL User Management 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 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" db-anon-role = "anon"
.. _jwt-from-sql:
JWT from SQL JWT from SQL
~~~~~~~~~~~~ ~~~~~~~~~~~~
@@ -318,144 +318,6 @@ You can insert a new product using a JSON object for the ``extra_info`` column:
To query and filter the data see :ref:`json_columns` for a complete reference. To query and filter the data see :ref:`json_columns` for a complete reference.
.. _ww_postgis:
PostGIS
-------
You can use the string representation for `PostGIS <https://postgis.net/>`_ data types such as ``geometry`` or ``geography`` (you need to `install PostGIS <https://postgis.net/documentation/getting_started/>`_ first).
.. code-block:: postgres
-- Activate the postgis module in the current database
create extension if not exists postgis;
create table coverage (
id int primary key,
name text unique,
area geometry
);
To add areas in polygon format, you can use string representation:
.. code-block:: bash
curl "http://localhost:3000/coverage" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
[
{ "id": 1, "name": "small", "area": "SRID=4326;POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))" },
{ "id": 2, "name": "big", "area": "SRID=4326;POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))" }
]
EOF
Now, when you request the information, PostgREST will automatically cast the ``area`` column into a ``Polygon`` geometry type. Although this is useful, you may need the whole output to be in `GeoJSON <https://geojson.org/>`_ format out of the box, which can be done by including the ``Accept: application/geo+json`` in the request. This will work for PostGIS versions 3.0.0 and up and will return the output as a `FeatureCollection Object <https://www.rfc-editor.org/rfc/rfc7946#section-3.3>`_:
.. code-block:: bash
curl "http://localhost:3000/coverage" \
-H "Accept: application/geo+json"
.. code-block:: json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[1,0],[1,1],[0,1],[0,0]]
]
},
"properties": {
"id": 1,
"name": "small"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"properties": {
"id": 2,
"name": "big"
}
}
]
}
If you need to add an extra property, like the area in square units by using ``st_area(area)``, you could add a generated column to the table and it will appear in the ``properties`` key of each ``Feature``.
.. code-block:: postgres
alter table coverage
add square_units double precision generated always as ( st_area(area) ) stored;
In the case that you are using older PostGIS versions, then creating a function is your best option:
.. code-block:: postgres
create or replace function coverage_geo_collection() returns json as $$
select
json_build_object(
'type', 'FeatureCollection',
'features', json_agg(
json_build_object(
'type', 'Feature',
'geometry', st_AsGeoJSON(c.area)::json,
'properties', json_build_object('id', c.id, 'name', c.name)
)
)
)
from coverage c;
$$ language sql;
Now this query will return the same results:
.. code-block:: bash
curl "http://localhost:3000/rpc/coverage_geo_collection"
.. code-block:: json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[1,0],[1,1],[0,1],[0,0]]
]
},
"properties": {
"id": 1,
"name": "small"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"properties": {
"id": 2,
"name": "big"
}
}
]
}
Ranges Ranges
------ ------
@@ -609,3 +471,20 @@ You can use other comparative filters and also all the `PostgreSQL special date/
"due_date": "2022-02-27T06:00:00-05:00" "due_date": "2022-02-27T06:00:00-05:00"
} }
] ]
.. raw:: html
<script type="text/javascript">
let hash = window.location.hash;
const redirects = {
// PostGIS
'#postgis': '../integrations/postgis.html#postgis',
};
let willRedirectTo = redirects[hash];
if (willRedirectTo) {
window.location.href = willRedirectTo;
}
</script>
+60 -35
View File
@@ -38,48 +38,52 @@ Sponsors
.. image:: ../static/cybertec.svg .. image:: ../static/cybertec.svg
:target: https://www.cybertec-postgresql.com/en/?utm_source=postgrest.org&utm_medium=referral&utm_campaign=postgrest :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 .. container:: img-dark
.. image:: ../static/neon-dark.jpg .. 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 .. container:: img-light
.. image:: ../static/neon.jpg .. 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 .. container:: img-dark
.. image:: ../static/code-build-dark.png .. image:: ../static/bytebase-dark.svg
:target: https://code.build/?utm_source=sponsor&utm_campaign=postgrest :target: https://www.bytebase.com/?utm_source=sponsor&utm_campaign=postgrest
.. container:: img-light .. container:: img-light
.. image:: ../static/code-build.png .. image:: ../static/bytebase.svg
:target: https://code.build/?utm_source=sponsor&utm_campaign=postgrest :target: https://www.bytebase.com/?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
.. The static/empty.png(created with `convert -size 320x95 xc:#fcfcfc empty.png`) is an ugly workaround .. 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. to create space and center the logos. It's not easy to layout with restructuredText.
.. .. image:: _static/empty.png .. image:: _static/empty.png
:target: #sponsors :target: #sponsors
| |
@@ -109,10 +113,20 @@ 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. 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 and no behavior changes.
MAJOR releases are published twice a year, with their scope and target dates tracked through `GitHub milestones <https://github.com/PostgREST/postgrest/milestones>`_.
PATCH releases are published on an as-needed basis.
Starting from ``v14.0``, only even-numbered MAJOR versions are released, reserving odd-numbered MAJOR versions for development.
All releases are published on `PostgREST's GitHub release page <https://github.com/PostgREST/postgrest/releases>`_, along with the corresponding upgrade guides.
Tutorials Tutorials
--------- ---------
@@ -209,20 +223,14 @@ In Production
Here are some companies that use PostgREST in production. Here are some companies that use PostgREST in production.
* `Catarse <https://www.catarse.me>`_ * `Catarse <https://www.catarse.me>`_
* `Datrium <https://www.datrium.com>`_
* `Drip Depot <https://www.dripdepot.com>`_ * `Drip Depot <https://www.dripdepot.com>`_
* `Image-charts <https://www.image-charts.com>`_ * `Image-charts <https://www.image-charts.com>`_
* `Moat <https://www.oracle.com/advertising/>`_
* `Netwo <https://www.netwo.io>`_ * `Netwo <https://www.netwo.io>`_
* `Nimbus <https://www.nimbusfacility.com/sg/home>`_ * `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>`_. - 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>`_ * `OpenBooking <https://openbooking.ch>`_
* `Supabase <https://supabase.com>`_ * `Supabase <https://supabase.com>`_
.. Failing links
* `eGull <http://www.egull.co>`_
* `MotionDynamic - Fast highly dynamic video generation at scale <https://motiondynamic.tech>`_
Testimonials Testimonials
------------ ------------
@@ -266,4 +274,21 @@ Testimonials
Contributing 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.
+36
View File
@@ -0,0 +1,36 @@
NixOS
=====
Nixpkgs contains a `NixOS module to run PostgREST <https://search.nixos.org/options?channel=unstable&query=services.postgrest&type=options>`_, which can be enabled with ``services.postgrest.enable = true``.
A PostgreSQL server can be enabled on the same machine with ``services.postgresql.enable = true``. Connections will use the name of the system user as user and database names by default, in this case ``postgrest``.
A minimal example could look like this:
.. code-block:: nix
{
pkgs,
...
}:
{
services.postgresql = {
enable = true;
initialScript = pkgs.writeText "init.sql" ''
CREATE ROLE postgrest LOGIN NOINHERIT;
CREATE ROLE anon ROLE postgrest;
'';
};
services.postgrest = {
enable = true;
settings.db-anon-role = "anon";
settings.db-uri.dbname = "postgres";
};
}
This will expose the PostgREST server on localhost on the NixOS machine and allow anonymous access.
.. tip::
NixOS also allows to quickly spin up different PostgreSQL versions or even forks this way. For example, to test the current beta version of `OrioleDB <https://www.orioledb.com>`_, use ``services.postgresql.package = pkgs.orioledb``.
+154
View File
@@ -0,0 +1,154 @@
.. _ww_postgis:
PostGIS
=======
To work with `PostGIS <https://postgis.net/>`_ data types such as ``geometry`` or ``geography``, you'll need to `install PostGIS <https://postgis.net/documentation/getting_started/>`_ first.
.. code-block:: postgres
-- Activate the postgis module in the current database
create extension if not exists postgis;
create table coverage (
id int primary key,
name text unique,
area geometry
);
insert into coverage (id, name, area) values
(1, 'small', ST_GeomFromText('POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))',4326)),
(2, 'big', ST_GeomFromText('POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))', 4326);
.. _application/geo+json:
``application/geo+json``
------------------------
PostgREST supports the `standard <https://www.iana.org/assignments/media-types/application/geo+json>`_ ``application/geo+json`` media type which can be used to get the output in `GeoJSON <https://geojson.org/>`_ format. This will work for PostGIS versions 3.0.0 and up and will return the output as a `FeatureCollection Object <https://www.rfc-editor.org/rfc/rfc7946#section-3.3>`_:
.. code-block:: bash
curl "http://localhost:3000/coverage" \
-H "Accept: application/geo+json"
.. code-block:: json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[1,0],[1,1],[0,1],[0,0]]
]
},
"properties": {
"id": 1,
"name": "small"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"properties": {
"id": 2,
"name": "big"
}
}
]
}
Using generated columns
-----------------------
If you need to add an extra property, like the area in square units by using ``st_area(area)``, you could add a generated column to the table and it will appear in the ``properties`` key of each ``Feature``.
.. code-block:: postgres
alter table coverage
add square_units double precision generated always as ( st_area(area) ) stored;
In the case that you are using older PostGIS versions, then creating a function is your best option:
.. code-block:: postgres
create or replace function coverage_geo_collection() returns json as $$
select
json_build_object(
'type', 'FeatureCollection',
'features', json_agg(
json_build_object(
'type', 'Feature',
'geometry', st_AsGeoJSON(c.area)::json,
'properties', json_build_object('id', c.id, 'name', c.name)
)
)
)
from coverage c;
$$ language sql;
Now this query will return the same results:
.. code-block:: bash
curl "http://localhost:3000/rpc/coverage_geo_collection"
.. code-block:: json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[1,0],[1,1],[0,1],[0,0]]
]
},
"properties": {
"id": 1,
"name": "small"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"properties": {
"id": 2,
"name": "big"
}
}
]
}
Using string representation
---------------------------
To insert areas in polygon format, you can use string representation:
.. code-block:: bash
curl "http://localhost:3000/coverage" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
[
{ "id": 3, "name": "strip", "area": "SRID=4326;POLYGON((0 0, 50 0, 50 2, 0 2, 0 0))" },
{ "id": 4, "name": "diamond", "area": "SRID=4326;POLYGON((5 0, 10 5, 5 10, 0 5, 5 0))" }
]
EOF
PostgREST will automatically cast the ``area`` column into a ``Polygon`` geometry type.
+15 -4
View File
@@ -1,9 +1,11 @@
personal_ws-1.1 en 0 utf-8 personal_ws-1.1 en 0 utf-8
api api
autoscaling
API's API's
APIs APIs
APISIX APISIX
AST AST
async
aud aud
Auth Auth
auth auth
@@ -14,6 +16,7 @@ BOM
Bytea Bytea
Cardano Cardano
cd cd
CDNs
centric centric
CLI CLI
CMS CMS
@@ -28,10 +31,11 @@ CSV
durations durations
DDL DDL
DOM DOM
DSL
DevOps DevOps
Dramatiq
dockerize dockerize
enum enum
ECS
Enums Enums
Entra Entra
eq eq
@@ -41,12 +45,14 @@ EveryLayout
filename filename
FreeBSD FreeBSD
fts fts
fullstack
GC
GeoJSON GeoJSON
GHC
Github Github
Google Google
grantor grantor
GraphQL GraphQL
Greenplum
gte gte
GUC GUC
Haskell Haskell
@@ -71,7 +77,6 @@ isdistinct
JS JS
js js
JSON JSON
JSPath
JWK JWK
JWT JWT
jwt jwt
@@ -94,6 +99,7 @@ namespaced
Nanos Nanos
neq neq
nginx nginx
NixOS
nixpkgs nixpkgs
npm npm
nxl nxl
@@ -104,7 +110,6 @@ Observability
Okta Okta
OpenAPI OpenAPI
openapi openapi
OpenSSL
ov ov
parametrized parametrized
passphrase passphrase
@@ -140,11 +145,13 @@ Redux
refactor refactor
reloadable reloadable
Reloadable Reloadable
reuseport
requester's requester's
RESTful RESTful
RLS RLS
RPC RPC
RSA RSA
RTS
safeupdate safeupdate
savepoint savepoint
schemas schemas
@@ -176,6 +183,7 @@ unikernel
unix unix
updatable updatable
unfulfillable unfulfillable
unselected
Untyped Untyped
UPSERT UPSERT
Upsert Upsert
@@ -189,9 +197,12 @@ verifier
versioning versioning
Vondra Vondra
Vue Vue
webapp
webhooks webhooks
websearch websearch
Websockets Websockets
webuser webuser
wfts wfts
www www
debouncing
deduplicates
+4 -3
View File
@@ -3,7 +3,9 @@
Admin Server Admin Server
############ ############
PostgREST provides an admin server that can be enabled by setting :ref:`admin-server-port`. PostgREST provides an admin server that can be enabled by setting :ref:`admin-server-port` or :ref:`admin-server-unix-socket`.
Multiple PostgREST instances can share the same public API host and port when :ref:`server-reuseport` is enabled. Admin ports are not shared: give each instance a different :ref:`admin-server-port`, otherwise the new instance will fail to start.
.. _health_check: .. _health_check:
@@ -12,7 +14,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. 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:: .. important::
@@ -72,5 +74,4 @@ Provides the ``schema_cache`` endpoint that prints the runtime :ref:`schema_cach
"dbRepresentations": ["..."], "dbRepresentations": ["..."],
"dbRoutines": ["..."], "dbRoutines": ["..."],
"dbTables": ["..."], "dbTables": ["..."],
"dbTimezones": ["..."]
} }
+1
View File
@@ -21,6 +21,7 @@ PostgREST exposes three database objects of a schema as resources: tables, views
api/aggregate_functions.rst api/aggregate_functions.rst
api/openapi.rst api/openapi.rst
api/preferences.rst api/preferences.rst
api/vary_header.rst
api/* api/*
.. raw:: html .. 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)``. 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``. 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: .. _function_single_json:
Functions with an array of JSON objects 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. 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:
Scalar functions Scalar functions
+1 -1
View File
@@ -15,7 +15,7 @@ Using these domains, :ref:`functions <functions>` can become handlers and `user-
.. important:: .. 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>`_. - 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`. For these you can use the :ref:`any_handler`.
+47 -10
View File
@@ -62,8 +62,12 @@ The server ignores unrecognized or unfulfillable preferences by default. You can
Timezone Timezone
======== ========
The ``timezone`` preference allows you to change the `PostgreSQL timezone <https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-TIMEZONE>`_. It accepts all time zones in `pg_timezone_names <https://www.postgresql.org/docs/current/view-pg-timezone-names.html>`_. .. important::
``handling=lenient`` is ignored for ``timezone``. Invalid time zones always return an error.
The ``timezone`` preference allows you to change the `PostgreSQL timezone <https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-TIMEZONE>`_.
It accepts all time zones in `pg_timezone_names <https://www.postgresql.org/docs/current/view-pg-timezone-names.html>`_ and numeric offsets.
.. code-block:: bash .. code-block:: bash
@@ -84,34 +88,35 @@ The ``timezone`` preference allows you to change the `PostgreSQL timezone <https
{"t":"2023-10-18T09:37:59.611-07:00"} {"t":"2023-10-18T09:37:59.611-07:00"}
] ]
For an invalid time zone, PostgREST returns values with the default time zone (configured on ``postgresql.conf`` or as a setting on the :ref:`authenticator <roles>`). Offsets are also accepted:
.. code-block:: bash .. code-block:: bash
curl -i "http://localhost:3000/timestamps" \ curl -i "http://localhost:3000/timestamps" \
-H "Prefer: timezone=Jupiter/Red_Spot" -H "Prefer: timezone=05:30"
.. code-block:: http .. code-block:: http
HTTP/1.1 200 OK HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8 Content-Type: application/json; charset=utf-8
Preference-Applied: timezone=05:30
.. code-block:: json .. code-block:: json
[ [
{"t":"2023-10-18T12:37:59.611+00:00"}, {"t":"2023-10-18T17:07:59.611+05:30"},
{"t":"2023-10-18T14:37:59.611+00:00"}, {"t":"2023-10-18T19:07:59.611+05:30"},
{"t":"2023-10-18T16:37:59.611+00:00"} {"t":"2023-10-18T21:07:59.611+05:30"}
] ]
Note that there's no ``Preference-Applied`` in the response. You can also use negative offsets like ``-03:00``.
However, with ``handling=strict``, an invalid time zone preference will throw an :ref:`error <pgrst122>`. For an invalid time zone, PostgREST returns a database error.
.. code-block:: bash .. code-block:: bash
curl -i "http://localhost:3000/timestamps" \ curl -i "http://localhost:3000/timestamps" \
-H "Prefer: handling=strict, timezone=Jupiter/Red_Spot" -H "Prefer: timezone=Jupiter/Red_Spot"
.. code-block:: http .. code-block:: http
@@ -242,7 +247,7 @@ Will result in:
Max Affected 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. To illustrate the use of this preference, consider the following scenario where the ``items`` table contains 14 rows.
@@ -264,3 +269,35 @@ To illustrate the use of this preference, consider the following scenario where
"details": "The query affects 14 rows", "details": "The query affects 14 rows",
"hint": null "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.
+84 -60
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 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 .. 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>`_. 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``. Assuming there's a foreign table ``premieres`` that we want to relate to ``films``.
.. code-block:: postgres .. 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. Now let's define the opposite one-to-many relationship.
.. code-block:: postgres .. 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>`_. 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: .. _embed_disamb:
.. _target_disamb: .. _target_disamb:
.. _hint_disamb: .. _hint_disamb:
@@ -1150,27 +1154,19 @@ For example, to arrange the films in descending order using the director's last
Spread embedded resource Spread embedded resource
======================== ========================
The ``...`` operator lets you "spread" an embedded resource. You can modify the shape of the embedded resources by using the spread syntax (``...``).
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>`_.
.. _spread_to_one_embed: .. _spread_to_one_embed:
Spread To-One relationships Spread To-One relationships
--------------------------- ---------------------------
This applies to :ref:`one-to-one <one-to-one>` and :ref:`many-to-one <many-to-one>` relationships. 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.
Take the following example:
.. code-block:: bash .. 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" \ 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*" -d "title=like.*Workers*"
.. code-block:: json .. code-block:: json
@@ -1178,48 +1174,22 @@ Take the following example:
[ [
{ {
"title": "Workers Leaving The Lumière Factory In Lyon", "title": "Workers Leaving The Lumière Factory In Lyon",
"director_first_name": "Louis",
"director_last_name": "Lumière" "director_last_name": "Lumière"
} }
] ]
Note that there is no ``"directors"`` object. Also the embed columns can be aliased normally. 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.
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"
}
]
}
]
.. _spread_to_many_embed: .. _spread_to_many_embed:
Spread To-Many relationships 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 .. 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" \ curl --get "http://localhost:3000/directors" \
-d "select=first_name,...films(film_titles:title,film_years:year)" \ -d "select=first_name,...films(film_titles:title,film_years:year)" \
-d "first_name=like.Quentin*" -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. Order in spread to-many
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:
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 .. 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" \ curl --get "http://localhost:3000/directors" \
-d "select=first_name,...films(film_titles:title,film_years:year)" \ -d "select=first_name,...films(film_titles:title,film_years:year)" \
-d "first_name=like.Quentin*" \ -d "first_name=like.Quentin*" \
@@ -1271,14 +1242,37 @@ 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 .. 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 "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 --get "http://localhost:3000/directors" \ 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 "select=first_name,...films(film_titles:title,film_years:year,...technical_specs(film_runtimes:runtime),...roles(film_characters:character))" \
@@ -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. Note that:
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). - 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"
}
]
}
]
@@ -51,7 +51,7 @@ Builtin handlers are offered for common standard media types.
* ``text/csv`` and ``application/json``, for all API endpoints. See :ref:`tables_views` and :ref:`functions`. * ``text/csv`` and ``application/json``, for all API endpoints. See :ref:`tables_views` and :ref:`functions`.
* ``application/openapi+json``, for the root endpoint. See :ref:`open-api`. * ``application/openapi+json``, for the root endpoint. See :ref:`open-api`.
* ``application/geo+json``, see :ref:`ww_postgis`. * ``application/geo+json``, see :ref:`application/geo+json`.
* ``*/*``, resolves to ``application/json`` for API endpoints and to ``application/openapi+json`` for the root endpoint. * ``*/*``, resolves to ``application/json`` for API endpoints and to ``application/openapi+json`` for the root endpoint.
The following vendor media types handlers are also supported. The following vendor media types handlers are also supported.
+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. 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 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 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 .. 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 .. 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 .. 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 .. 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: .. _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>`_. 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 .. 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 .. 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: .. _v_filter:
@@ -622,7 +639,7 @@ However, it can work with surrogate primary keys (e.g. ``id serial primary key``
.. code-block:: bash .. 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" \ -X POST -H "Content-Type: application/json" \
-H "Prefer: resolution=merge-duplicates, missing=default" \ -H "Prefer: resolution=merge-duplicates, missing=default" \
-d @- << EOF -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 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`. * More complicated joins than those provided by :ref:`resource_embedding`.
* Geo-spatial queries that require an argument, like "points near (lat,lon)" * 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 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. 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.
+100 -55
View File
@@ -31,7 +31,7 @@ The authenticator role is used for connecting to the database and should be conf
.. _user_impersonation: .. _user_impersonation:
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`). 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`. 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 .. 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. 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 Bearer Authentication
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
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
~~~~~~~~~~~
To make an authenticated request the client must include an :code:`Authorization` HTTP header with the value :code:`Bearer <jwt>`. For instance: 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``). 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 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`. 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. 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: .. _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" 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:
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 - ``exp`` Expiration Time
- ``iat`` Issued At - ``iat`` Issued At
- ``nbf`` Not Before - ``nbf`` Not Before
- ``aud`` :ref:`Audience <jwt_aud_validation>`
.. note:: 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.
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.
.. _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>`_. 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: It works this way:
@@ -188,45 +200,58 @@ 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 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. + 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 DSL follows the `JSONPath <https://goessner.net/articles/JsonPath/>`_ expression grammar with extended string comparison operators. Supported operators are: 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`.
- ``==`` selects the first array element that exactly matches the right operand 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.
- ``!=`` selects the first array element that does not match the right operand
- ``^==`` selects the first array element that starts with the right operand :ref:`jwt_cache_metrics` are available.
- ``==^`` selects the first array element that ends with the right operand
- ``*==`` selects the first array element that contains the right operand .. 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 JSON Path (`RFC 9535 <https://www.rfc-editor.org/rfc/rfc9535.html>`_) can be specified for 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.
You can quickly try out JSON Path by visiting https://serdejsonpath.live.
Usage examples: Usage examples:
.. code:: bash .. code:: bash
# {"postgrest":{"roles": ["other", "author"]}} # {"postgrest":{"roles": ["other", "author"]}}
# the DSL accepts characters that are alphanumerical or one of "_$@" as keys jwt-role-claim-key = "$$.postgrest.roles[1]"
jwt-role-claim-key = ".postgrest.roles[1]"
# {"https://www.example.com/role": { "key": "author" }} # {"https://www.example.com/role": { "key": "author" }}
# non-alphanumerical characters can go inside quotes(escaped in the config value) # non-alphanumerical characters can go inside single quotes
jwt-role-claim-key = ".\"https://www.example.com/role\".key" jwt-role-claim-key = "$$['https://www.example.com/role'].key"
# {"postgrest":{"roles": ["other", "author"]}} # {"postgrest":{"roles": ["other", "author"]}}
# `@` represents the current element in the array # filter based on equality or regular expression
# all the these match the string "author" jwt-role-claim-key = "$$.postgrest.roles[?(@ == 'author')]"
jwt-role-claim-key = ".postgrest.roles[?(@ == \"author\")]" jwt-role-claim-key = "$$.postgrest.roles[?search(@, '^au')]"
jwt-role-claim-key = ".postgrest.roles[?(@ != \"other\")]"
jwt-role-claim-key = ".postgrest.roles[?(@ ^== \"aut\")]"
jwt-role-claim-key = ".postgrest.roles[?(@ ==^ \"hor\")]"
jwt-role-claim-key = ".postgrest.roles[?(@ *== \"utho\")]"
.. note::
- If JSON Path query returns multiple values, the first one gets selected.
- Only when using the :ref:`file_config`, all ``$`` characters in the value must be escaped with an additional ``$`` char. For :ref:`env_variables_config` and :ref:`in_db_config`, only use a single ``$`` char.
- In our implementation, only the `search()` function from `JSON Path Functions <https://www.rfc-editor.org/rfc/rfc9535.html#name-function-extensions>`_ is available for filtering.
JWT Security 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. 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 +287,23 @@ doing custom logic based on the web user info.
END IF; END IF;
END END
$$ LANGUAGE plpgsql; $$ 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 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 Help
---- ----
.. code:: bash .. code:: bash
$ postgrest [-h|--help] $ postgrest --help
Shows all the commands available. Shows all the options available.
Version Version
------- -------
.. code:: bash .. code:: bash
$ postgrest [-v|--version] $ postgrest --version
Prints the PostgREST version. Prints the PostgREST version.
@@ -28,16 +52,16 @@ Example
.. code:: bash .. code:: bash
$ postgrest [-e|--example] $ postgrest --example
Shows example configuration options. Shows example configuration settings.
Dump Config Dump Config
----------- -----------
.. code:: bash .. 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`. 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 .. code:: bash
$ postgrest [--dump-schema] $ postgrest --dump-schema
Dumps the schema cache in JSON format. 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``.
+171 -27
View File
@@ -176,6 +176,46 @@ admin-server-port
Specifies the port for the :ref:`admin_server`. Cannot be equal to :ref:`server-port`. Specifies the port for the :ref:`admin_server`. Cannot be equal to :ref:`server-port`.
.. _admin-server-unix-socket:
admin-server-unix-socket
------------------------
=============== =================================
**Type** String
**Default** `n/a`
**Reloadable** N
**Environment** PGRST_ADMIN_SERVER_UNIX_SOCKET
**In-Database** `n/a`
=============== =================================
`Unix domain socket <https://en.wikipedia.org/wiki/Unix_domain_socket>`_ where to bind the :ref:`admin_server`.
If specified, this takes precedence over :ref:`admin-server-port`. Example:
.. code:: bash
admin-server-unix-socket = "/tmp/pgrst-admin.sock"
.. _admin-server-unix-socket-mode:
admin-server-unix-socket-mode
-----------------------------
=============== ===================================
**Type** String
**Default** 660
**Reloadable** N
**Environment** PGRST_ADMIN_SERVER_UNIX_SOCKET_MODE
**In-Database** `n/a`
=============== ===================================
`Unix file mode <https://en.wikipedia.org/wiki/File_system_permissions>`_ to be set for the socket specified in :ref:`admin-server-unix-socket`
Needs to be a valid octal between 600 and 777.
.. code:: bash
admin-server-unix-socket-mode = "660"
.. _app.settings.*: .. _app.settings.*:
app.settings.* app.settings.*
@@ -195,6 +235,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. 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:
db-aggregates-enabled db-aggregates-enabled
@@ -264,7 +331,7 @@ db-channel-enabled
When this is set to :code:`true`, the notification channel specified in :ref:`db-channel` is 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: .. _db-config:
@@ -315,6 +382,10 @@ db-extra-search-path
Multiple schemas can be added in a comma-separated string, e.g. ``public, extensions``. 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:
db-hoisted-tx-settings db-hoisted-tx-settings
@@ -405,7 +476,7 @@ db-pool-max-idletime
**In-Database** `n/a` **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. Time in seconds to close idle pool connections.
@@ -475,7 +546,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. 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: .. _db-root-spec:
@@ -522,7 +593,7 @@ db-tx-end
**In-Database** pgrst.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 .. code:: bash
@@ -599,7 +670,7 @@ jwt-aud
**In-Database** pgrst.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: .. _jwt-role-claim-key:
@@ -608,7 +679,7 @@ jwt-role-claim-key
=============== ================================= =============== =================================
**Type** String **Type** String
**Default** .role **Default** $.role
**Reloadable** Y **Reloadable** Y
**Environment** PGRST_JWT_ROLE_CLAIM_KEY **Environment** PGRST_JWT_ROLE_CLAIM_KEY
**In-Database** pgrst.jwt_role_claim_key **In-Database** pgrst.jwt_role_claim_key
@@ -616,7 +687,11 @@ jwt-role-claim-key
*For backwards compatibility, this config parameter is also available without prefix as "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.
.. warning::
Only when using :ref:`file_config`, the ``$`` char needs to be escaped, so use ``$$`` and PostgREST will interpret it as a single ``$`` character.
.. _jwt-secret: .. _jwt-secret:
@@ -654,20 +729,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. 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 **Type** Int
**Default** 0 **Default** 1000
**Reloadable** Y **Reloadable** Y
**Environment** PGRST_JWT_CACHE_MAX_LIFETIME **Environment** PGRST_JWT_CACHE_MAX_ENTRIES
**In-Database** pgrst.jwt_cache_max_lifetime **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: .. _log-level:
@@ -677,7 +752,7 @@ log-level
=============== ================================= =============== =================================
**Type** String **Type** String
**Default** error **Default** error
**Reloadable** N **Reloadable** Y
**Environment** PGRST_LOG_LEVEL **Environment** PGRST_LOG_LEVEL
**In-Database** `n/a` **In-Database** `n/a`
=============== ================================= =============== =================================
@@ -710,23 +785,14 @@ log-query
--------- ---------
=============== ================================= =============== =================================
**Type** String **Type** Boolean
**Default** "disabled" **Default** False
**Reloadable** Y **Reloadable** Y
**Environment** PGRST_LOG_QUERY **Environment** PGRST_LOG_QUERY
**In-Database** `n/a` **In-Database** `n/a`
=============== ================================= =============== =================================
Logs the SQL query for the corresponding request at the current :ref:`log-level`. Logs the SQL query for the corresponding request at the current :ref:`log-level`. See :ref:`sql_query_logs`.
See :ref:``sql_query_logs``.
.. code:: bash
# Logs the main SQL query
log-query = "main-query"
# Disables logging the SQL query
log-query = "disabled"
.. _openapi-mode: .. _openapi-mode:
@@ -862,6 +928,50 @@ server-port
The TCP port to bind the web server. Use ``0`` to automatically assign a port. The TCP port to bind the web server. Use ``0`` to automatically assign a port.
.. _server-reuseport:
server-reuseport
----------------
=============== =================================
**Type** Bool
**Default** false
**Reloadable** N
**Environment** PGRST_SERVER_REUSEPORT
**In-Database** `n/a`
=============== =================================
Enables ``SO_REUSEPORT`` on the TCP server socket. This allows multiple
PostgREST processes to bind to the same :ref:`server-host` and
:ref:`server-port` when the operating system supports it.
For example, two PostgREST processes can use the same configuration:
.. code:: ini
server-host = "127.0.0.1"
server-port = 3000
server-reuseport = true
New connections are then distributed by the operating system between the
running PostgREST processes. This can be used to start a replacement process
before stopping the old one, or to run several PostgREST processes behind one
port.
If ``server-reuseport`` is disabled, starting another PostgREST process on
the same host and port will fail with the usual address-in-use error.
Enabling this setting on an operating system that does not support
``SO_REUSEPORT`` is a configuration error. PostgREST will fail to start
instead of falling back to a normal TCP socket.
When running multiple PostgREST instances on the same :ref:`server-port`, use
a different ``admin-server-port`` for each instance. Admin ports are not shared
between instances, so readiness checks always target one specific PostgREST
instance.
This setting does not apply when :ref:`server-unix-socket` is used.
.. _server-trace-header: .. _server-trace-header:
server-trace-header server-trace-header
@@ -890,7 +1000,7 @@ server-timing-enabled
**In-Database** pgrst.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`. See :ref:`server-timing_header`.
.. _server-unix-socket: .. _server-unix-socket:
@@ -932,3 +1042,37 @@ server-unix-socket-mode
.. code:: bash .. code:: bash
server-unix-socket-mode = "660" server-unix-socket-mode = "660"
.. _url-use-legacy-target-names:
url-use-legacy-target-names
---------------------------
=============== =================================
**Type** Boolean
**Default** True
**Reloadable** Y
**Environment** PGRST_URL_USE_LEGACY_TARGET_NAMES
**In-Database** pgrst.url_use_legacy_target_names
=============== =================================
When active, it allows using the the name of an embedded table in filters, orders or limits even if it has an alias:
.. code:: bash
curl "http://localhost:3000/table?select=alias:target(*)&target.order=id" -i
.. code:: text
Warning: 299 PostgRESTv16 "Embedded resource was referenced by relation name even though it has an alias. This is deprecated and will stop working in a future release. Update `target` to `alias` in query string filters, orders or limits."
[...]
Note that the response includes a deprecation message in the ``Warning`` header.
This will also show in the PostgREST logs:
.. code::
28/May/2026:20:33:22 -0500: WARNING: Embedded resource was referenced by relation name even though it has an alias. This is deprecated and will stop working in a future release.
28/May/2026:20:33:22 -0500: Update filters, orders or limits that use `target` to `alias` in `GET /table?select=alias:target(*)&target.order=id`
This feature will be removed in a future release, so you should start using the ``alias`` in these cases.
+4 -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. 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. - 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`. - For connecting to the database, the :ref:`authenticator <roles>` role is used. You can configure this using :ref:`db-uri`.
@@ -47,6 +47,8 @@ Under a busy system, the :ref:`db-pool-max-idletime` won't be reached and the co
To avoid this problem and save resources, a connection max lifetime (:ref:`db-pool-max-lifetime`) is enforced. To avoid this problem and save resources, a connection max lifetime (:ref:`db-pool-max-lifetime`) is enforced.
After the max lifetime is reached, connections from the pool will be released and new ones will be created. This doesn't affect running requests, only unused connections will be released. After the max lifetime is reached, connections from the pool will be released and new ones will be created. This doesn't affect running requests, only unused connections will be released.
.. _pool_timeout:
Acquisition Timeout Acquisition Timeout
------------------- -------------------
@@ -106,4 +108,4 @@ Also set :ref:`db-channel-enabled` to ``false`` since ``LISTEN`` is not compatib
.. note:: .. 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.
+41 -2
View File
@@ -199,7 +199,7 @@ Related to the HTTP request elements.
| | | :ref:`switching schemas <multiple-schemas>` is not present | | | | :ref:`switching schemas <multiple-schemas>` is not present |
| PGRST106 | | in the :ref:`db-schemas` configuration variable. | | PGRST106 | | in the :ref:`db-schemas` configuration variable. |
+---------------+-------------+-------------------------------------------------------------+ +---------------+-------------+-------------------------------------------------------------+
| .. _pgrst107: | 415 | The ``Content-Type`` sent in the request is invalid. | | .. _pgrst107: | 406 | The ``Accept`` media type sent in the request is invalid. |
| | | | | | | |
| PGRST107 | | | | PGRST107 | | |
+---------------+-------------+-------------------------------------------------------------+ +---------------+-------------+-------------------------------------------------------------+
@@ -267,6 +267,10 @@ Related to the HTTP request elements.
| | | implemented. | | | | implemented. |
| PGRST127 | | | | PGRST127 | | |
+---------------+-------------+-------------------------------------------------------------+ +---------------+-------------+-------------------------------------------------------------+
| .. _pgrst128: | 400 | ``max-affected`` preference is violated with ``RPC`` call. |
| | | See :ref:`prefer_max_affected`. |
| PGRST128 | | |
+---------------+-------------+-------------------------------------------------------------+
.. _pgrst2**: .. _pgrst2**:
@@ -325,7 +329,7 @@ Related to the authentication process using JWT. You can follow the :ref:`tut1`
| PGRST301 | | | | PGRST301 | | |
+---------------+-------------+-------------------------------------------------------------+ +---------------+-------------+-------------------------------------------------------------+
| .. _pgrst302: | 401 | Attempted to do a request without | | .. _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`. | | PGRST302 | | is disabled by not setting it in :ref:`db-anon-role`. |
+---------------+-------------+-------------------------------------------------------------+ +---------------+-------------+-------------------------------------------------------------+
| .. _pgrst303: | 401 | :ref:`JWT claims validation <jwt_claims_validation>` | | .. _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 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. 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"
}
+18
View File
@@ -0,0 +1,18 @@
.. _http_server:
HTTP Server
###########
The HTTP server is provided by `Warp <https://aosabook.org/en/posa/warp.html>`_.
Graceful shutdown
-----------------
PostgREST uses Warp's graceful shutdown, when a ``SIGTERM`` is received:
- It stops accepting new requests.
- Allows requests that are already in progress to finish.
- Closes idle ``Keep-Alive`` connections instead of waiting for them to expire.
- Responses sent during shutdown indicate that the connection should not be reused (e.g. for HTTP/1.x, it sends ``Connection: close``).
This allows PostgREST to shut down promptly without interrupting in-flight requests. Useful for zero-downtime upgrades and autoscaling/load-balancing under cloud environments (AWS ECS, Kubernetes).
+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>`_. 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. Like on cloud managed containers or on Windows systems.
.. code:: postgresql .. code:: postgresql
@@ -46,7 +46,9 @@ This will cause the :ref:`connection_pool` to connect to the read replica host a
.. note:: .. 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: .. _listener_automatic_recovery:
+86 -8
View File
@@ -39,7 +39,7 @@ For diagnostic information about the server itself, PostgREST logs to ``stderr``
06/May/2024:08:16:11 -0500: Listening for database notifications on the "pgrst" channel 06/May/2024:08:16:11 -0500: Listening for database notifications on the "pgrst" channel
06/May/2024:08:16:11 -0500: Config reloaded 06/May/2024:08:16:11 -0500: Config reloaded
06/May/2024:08:16:11 -0500: Schema cache queried in 3.8 milliseconds 06/May/2024:08:16:11 -0500: Schema cache queried in 3.8 milliseconds
06/May/2024:08:16:11 -0500: Schema cache loaded 15 Relations, 8 Relationships, 8 Functions, 0 Domain Representations, 4 Media Type Handlers 06/May/2024:08:16:11 -0500: Schema cache loaded 15 Relations, 8 Relationships, 8 RPCs, 0 Domain Representations, 4 Media Type Handlers
06/May/2024:14:11:27 -0500: Received a config reload message on the "pgrst" channel 06/May/2024:14:11:27 -0500: Received a config reload message on the "pgrst" channel
06/May/2024:14:11:27 -0500: Config reloaded 06/May/2024:14:11:27 -0500: Config reloaded
@@ -52,14 +52,12 @@ For diagnostic information about the server itself, PostgREST logs to ``stderr``
SQL Query Logs SQL Query Logs
-------------- --------------
To log the :ref:`main SQL query <main_query>` executed for a request, set the :ref:`log-query` to ``main-query``. 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.
It will be logged based on the current :ref:`log-level` setting.
For example, with this configuration:
.. code-block:: bash .. code-block:: bash
log-level = "warn" log-level = "warn"
log-query = "main-query" log-query = "true"
The SQL queries will only be logged on ``400`` HTTP errors and up. The SQL queries will only be logged on ``400`` HTTP errors and up.
So, if the user requests a resource without sufficient privileges: 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 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 .. code-block:: bash
curl "http://localhost:3001/metrics" 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 # 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 # TYPE pgrst_schema_cache_query_time_seconds gauge
pgrst_schema_cache_query_time_seconds 1.5937927e-2 pgrst_schema_cache_query_time_seconds 1.5937927e-2
@@ -201,6 +204,79 @@ pgrst_db_pool_max
Max pool connections. 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.
GHC Runtime Metrics
-------------------
PostgREST can also expose GHC runtime system metrics. These use the ``ghc_*``
prefix and include
`GHC RTS statistics <https://ghc.gitlab.haskell.org/ghc/doc/libraries/base-4.22.0.0-inplace/GHC-Stats.html#g:1>`_
for runtime allocation, garbage collection, memory, and CPU/elapsed time.
These are useful for monitoring PostgREST process health and diagnosing memory
pressure or GC behavior.
To expose these metrics, enable GHC RTS statistics when starting PostgREST:
.. code-block:: bash
postgrest +RTS -T -RTS
When enabled, the admin ``/metrics`` endpoint includes samples such as:
.. code-block:: text
# HELP ghc_gcs_total Total number of GCs
# TYPE ghc_gcs_total counter
ghc_gcs_total 1
# HELP ghc_allocated_bytes_total Total bytes allocated
# TYPE ghc_allocated_bytes_total counter
ghc_allocated_bytes_total 12345678
Other available GHC runtime metrics include:
- ``ghc_gcs_total``
- ``ghc_major_gcs_total``
- ``ghc_allocated_bytes_total``
- ``ghc_max_live_bytes``
- ``ghc_max_mem_in_use_bytes``
- ``ghc_mutator_cpu_seconds_total``
- ``ghc_gc_cpu_seconds_total``
- ``ghc_elapsed_seconds_total``
Traces Traces
====== ======
@@ -246,7 +322,7 @@ See :ref:`proxy-status_header`.
Server-Timing 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. This header communicates metrics of the different phases in the request-response cycle.
.. code-block:: bash .. code-block:: bash
@@ -260,7 +336,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 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. - 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 ``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. - 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`. - The ``transaction`` stage corresponds to the database transaction. See :ref:`transactions`.
@@ -354,6 +430,8 @@ By default the plan is assumed to generate the JSON representation of a resource
The other available parameters are ``analyze``, ``verbose``, ``settings``, ``buffers`` and ``wal``, which correspond to the `EXPLAIN command options <https://www.postgresql.org/docs/current/sql-explain.html>`_. To use the ``analyze`` and ``wal`` parameters for example, you would add them like ``Accept: application/vnd.pgrst.plan; options=analyze|wal``. The other available parameters are ``analyze``, ``verbose``, ``settings``, ``buffers`` and ``wal``, which correspond to the `EXPLAIN command options <https://www.postgresql.org/docs/current/sql-explain.html>`_. To use the ``analyze`` and ``wal`` parameters for example, you would add them like ``Accept: application/vnd.pgrst.plan; options=analyze|wal``.
For a workflow that takes the ``Query Identifier`` from a verbose PostgREST plan and uses it to inspect the same query in ``pg_stat_statements``, see :ref:`debugging_performance_pg_stat_statements`.
Note that akin to the EXPLAIN command, the changes will be committed when using the ``analyze`` option. To avoid this, you can use the :ref:`db-tx-end` and the ``Prefer: tx=rollback`` header. Note that akin to the EXPLAIN command, the changes will be committed when using the ``analyze`` option. To avoid this, you can use the :ref:`db-tx-end` and the ``Prefer: tx=rollback`` header.
Securing the Execution Plan Securing the Execution Plan
+21 -2
View File
@@ -3,10 +3,16 @@
Schema Cache 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. 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_reloading:
Schema Cache Reloading Schema Cache Reloading
@@ -18,7 +24,7 @@ You can do this with UNIX signals or with PostgreSQL notifications. It's also po
.. note:: .. note::
- Requests will wait until the schema cache reload is done. This to prevent client errors due to an stale schema cache. - If the schema cache fails to reload (e.g. due to a ``statement_timeout`` or :ref:`pool timeout <pool_timeout>`), PostgREST will continue serving requests in a "best effort" basis.
- If you are using the :ref:`in_db_config`, a schema cache reload will :ref:`reload the configuration<config_reloading>` as well. - If you are using the :ref:`in_db_config`, a schema cache reload will :ref:`reload the configuration<config_reloading>` as well.
.. _schema_reloading_signals: .. _schema_reloading_signals:
@@ -53,6 +59,19 @@ To reload the schema cache from within the database, you can use the ``NOTIFY``
NOTIFY pgrst, 'reload schema' 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: .. _auto_schema_reloading:
Automatic Schema Cache 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:: .. 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: .. _guc_resp_status:
+4 -4
View File
@@ -1,7 +1,7 @@
# This file is auto-generated by postgrest-nixpkgs-upgrade # This file is auto-generated by postgrest-nixpkgs-upgrade
sphinx==7.4.7 sphinx==9.1.0
sphinx-copybutton==0.5.2 sphinx-copybutton==0.5.2
sphinx-rtd-dark-mode==1.3.0 sphinx-rtd-dark-mode==1.3.0
sphinx-rtd-theme==2.0.0 sphinx-rtd-theme==3.1.0
sphinx-tabs==3.4.7 sphinx-tabs==3.5.0
sphinxext-opengraph==0.9.1 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 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 .. 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. 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 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 .. code:: bash
:alt: jwt.io interface
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:: .. 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; 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
{ .. code-block:: bash
"role": "todo_user",
"exp": 123456789 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. **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": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1731165248, "lastModified": 1784115452,
"narHash": "sha256-DiHFKIdBmMx5/DUARhVqaxvEIiy4EE6Eqs9Qs4oxme8=", "narHash": "sha256-BoYPdqk6jlKXy+DyUzyGV/CtRGfAhk2MmIgBhsemTGI=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a90280100f41a10914edfe729a4053e60c92b8e3", "rev": "35d3407a3816f3b341d8cf1d60abaf2b7b8166ac",
"type": "github" "type": "github"
}, },
"original": { "original": {
+7 -3
View File
@@ -33,8 +33,8 @@
in in
{ {
packages = genSystems (attrs: { packages = genSystems (attrs: {
default = attrs.postgrestPackage; default = attrs.postgrestPackage.bin;
profiled = attrs.postgrestProfiled; profiled = attrs.postgrestProfiled.bin;
} // nixpkgs.lib.optionalAttrs (attrs ? postgrestStatic) { } // nixpkgs.lib.optionalAttrs (attrs ? postgrestStatic) {
static = attrs.postgrestStatic; static = attrs.postgrestStatic;
}); });
@@ -42,9 +42,13 @@
apps = genSystems (attrs: { apps = genSystems (attrs: {
default = { default = {
type = "app"; 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"; meta.description = "REST API for any Postgres database";
}; };
}); });
devShells = genSystems (postgrest: {
default = import ./shell.nix { inherit postgrest; };
});
}; };
} }
+10 -65
View File
@@ -70,55 +70,16 @@ The PostgREST utilities available in `nix-shell` all have names that begin with
`<tab>`) in `nix-shell` to see all that are available: `<tab>`) in `nix-shell` to see all that are available:
```bash ```bash
# Note: The utilities listed here might not be up to date.
[nix-shell]$ postgrest-<tab> [nix-shell]$ postgrest-<tab>
postgrest-build postgrest-profiled-run postgrest-build
postgrest-check postgrest-push-cachix postgrest-cabal-update
postgrest-clean postgrest-release postgrest-check
postgrest-coverage postgrest-repl postgrest-clean
postgrest-coverage-draft-overlay postgrest-run postgrest-commitlint
postgrest-docs-build postgrest-style
postgrest-docs-check postgrest-style-check
postgrest-docs-dictcheck postgrest-test-big-schema
postgrest-docs-linkcheck postgrest-test-doctests
postgrest-docs-render postgrest-test-io
postgrest-docs-serve postgrest-test-memory
postgrest-docs-spellcheck postgrest-test-replica
postgrest-dump-minimal-imports postgrest-test-spec
postgrest-dump-schema postgrest-test-spec-idempotence
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
... ...
[nix-shell]$
``` ```
The `docker` module has large dependencies to be build before the shell becomes Most of these commands provide a `--help` output, make sure to check it out.
available, which could take an especially long time if the cachix binary cache
is not used. You can activate it by passing a flag to `nix-shell` with
`nix-shell --arg docker true`. This will make the respective utilities available:
```bash
$ nix-shell --arg docker true
[nix-shell]$ postgrest-docker-<tab>
postgrest-docker-load
...
```
Note that `postgrest-docker-load` is now also available.
To run one-off commands, you can also use `nix-shell --run <command>`, which To run one-off commands, you can also use `nix-shell --run <command>`, which
will launch the Nix shell, run that one command and exit. Note that the tab will launch the Nix shell, run that one command and exit. Note that the tab
@@ -134,16 +95,6 @@ $ nix-shell --run "postgrest-foo --bar"
``` ```
A third option is to install utilities that you use very often locally:
```bash
$ nix-env -f default.nix -iA devTools
# `postgrest-style` can now be run directly:
$ postgrest-style
```
If you use `nix-shell` very often, you might like to use If you use `nix-shell` very often, you might like to use
https://github.com/xzfc/cached-nix-shell, which skips evaluating all our Nix https://github.com/xzfc/cached-nix-shell, which skips evaluating all our Nix
expressions if nothing changed, reducing startup time for the shell expressions if nothing changed, reducing startup time for the shell
@@ -174,7 +125,7 @@ $ nix-shell --run "postgrest-with-all postgrest-test-spec"
# Run the tests against a specific version of PostgreSQL (use tab-completion in # Run the tests against a specific version of PostgreSQL (use tab-completion in
# nix-shell to see all available versions): # 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"
``` ```
@@ -209,13 +160,7 @@ The loadtests ensure that performance doesn't drop on a change. Underlyingly the
[nix-shell]$ postgrest-loadtest [nix-shell]$ postgrest-loadtest
# You can loadtest comparing to a different branch # You can loadtest comparing to a different branch
[nix-shell]$ postgrest-loadtest-against master [nix-shell]$ postgrest-loadtest-against main
# You can simulate latency client/postgrest and postgrest/database
[nix-shell]$ PGRST_DELAY=5ms PGDELAY=5ms postgrest-loadtest
# You can build postgrest directly with cabal for faster iteration
[nix-shell]$ PGRST_BUILD_CABAL=1 postgrest-loadtest
# Produce a markdown report to be used on CI # Produce a markdown report to be used on CI
[nix-shell]$ postgrest-loadtest-report [nix-shell]$ postgrest-loadtest-report
@@ -284,7 +229,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 also run in CI, with the exception of the IO and Memory checks that need to be run
separately. 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 with a temporary database. `postgrest-with-all` will run the command against
all supported PostgreSQL versions. Tests run without `postgrest-with-*` are all supported PostgreSQL versions. Tests run without `postgrest-with-*` are
run against the latest PostgreSQL version by default. run against the latest PostgreSQL version by default.
@@ -380,7 +325,7 @@ that).
We also use `default.nix` to load our pinned version of the `nixpkgs` 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 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 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` ### `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` ## Upgrade the pinned version of `nixpkgs`
The pinned version of [`nixpkgs`](https://github.com/NixOS/nixpkgs) is defined 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 in [`flake.nix`](../flake.nix). To upgrade it, you can use a small utility
a GitHub tarball for the given revision, which is more efficient than pulling script defined in [`nix/tools/nixpkgsTools.nix`](tools/nixpkgsTools.nix):
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):
```bash ```bash
# From the root of the repository, enter nix-shell # From the root of the repository, enter nix-shell
@@ -30,21 +27,12 @@ nix-shell
postgrest-nixpkgs-upgrade postgrest-nixpkgs-upgrade
# Exit the nix-shell with Ctrl-d # Exit the nix-shell with Ctrl-d
``` ```
## Review overlays ## Review overlays
Check whether the individual [overlays](overlays) are still required. 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 ## Build everything
Using the PostgREST binary Nix cache is recommended. Install 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 ## 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 artifacts that you built locally to the binary cache. This will accelerate the
CI builds and tests, sometimes dramatically. This might sometimes even be CI builds and tests, sometimes dramatically. This might sometimes even be
required to avoid build timeouts in CI. required to avoid build timeouts in CI.
You'll need to set the `CACHIX_SIGNING_KEY` before proceeding, e.g. by creating You'll need to login with your token with `cachix authtoken <token>`.
a file containing `export CACHIX_SIGNING_KEY=...` and sourcing that file, which
avoids having the secret in your shell history.
To push all new artifacts to Cachix, run: 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 nix-shell --run postgrest-push-cachix
``` ```
The `nix-store` command will query the nix-store to list all dependencies and The `postgrest-push-cachix` command will query the nix-store to list all
build artifacts of PostgREST. The `cachix` command will efficiently push dependencies and build artifacts of PostgREST. It will then push
everything that is not yet cached to the binary cache. everything that is not yet cached to the binary cache.
+19 -7
View File
@@ -4,6 +4,7 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-} {-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
-- | Haskell Imports and Exports tool -- | Haskell Imports and Exports tool
@@ -33,13 +34,15 @@ import Data.Function ((&))
import Data.List (intercalate) import Data.List (intercalate)
import Data.Maybe (catMaybes, mapMaybe) import Data.Maybe (catMaybes, mapMaybe)
import Data.Text (Text) import Data.Text (Text)
import GHC.Driver.Errors.Types (GhcMessage)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import GHC.Hs.Extension (GhcPs) 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.Occurrence (occNameString)
import GHC.Types.Name.Reader (rdrNameOcc) 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.Error (pprMsgEnvelopeBagWithLoc)
import GHC.Utils.Outputable (showSDocUnsafe)
import System.Directory.Recursive (getFilesRecursive) import System.Directory.Recursive (getFilesRecursive)
import System.Exit (exitFailure) import System.Exit (exitFailure)
@@ -198,7 +201,7 @@ sourceSymbols source = do
return $ concatMap (importSymbols source filepath . GHC.unLoc) hsmodImports return $ concatMap (importSymbols source filepath . GHC.unLoc) hsmodImports
-- | Parse a Haskell module -- | Parse a Haskell module
parseModule :: FilePath -> IO GHC.HsModule parseModule :: FilePath -> IO (GHC.HsModule GhcPs)
parseModule filepath = do parseModule filepath = do
result <- ExactPrint.parseModule GHC.Paths.libdir filepath result <- ExactPrint.parseModule GHC.Paths.libdir filepath
case result of case result of
@@ -206,7 +209,13 @@ parseModule filepath = do
return $ GHC.unLoc hsmod return $ GHC.unLoc hsmod
Left errs -> Left errs ->
fail $ "Errors with " <> show filepath <> ":\n " 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. -- | Symbols imported in an import declaration.
-- --
@@ -214,9 +223,12 @@ parseModule filepath = do
-- only one item is returned. -- only one item is returned.
importSymbols :: FilePath -> FilePath -> GHC.ImportDecl GhcPs -> [ImportedSymbol] importSymbols :: FilePath -> FilePath -> GHC.ImportDecl GhcPs -> [ImportedSymbol]
importSymbols source filepath GHC.ImportDecl{..} = importSymbols source filepath GHC.ImportDecl{..} =
case ideclHiding of case ideclImportList of
Just (hiding, syms) -> Just (importListInterpretation, syms) ->
symbol (if hiding then Hiding else Explicit) . Just . GHC.unLoc <$> GHC.unLoc syms symbol (if importListInterpretation == GHC.EverythingBut then Hiding else Explicit)
. Just
. GHC.unLoc
<$> GHC.unLoc syms
Nothing -> Nothing ->
[ symbol Wildcard Nothing ] [ symbol Wildcard Nothing ]
where where
+7 -7
View File
@@ -5,10 +5,10 @@ project. It's available in PostgREST's `nix-shell` by default.
## Dumping imports ## Dumping imports
Given source code in the directories `src` and `main`, for example, you can run: Given source code in the directories `src/library` and `src/executable`, for example, you can run:
``` ```
hsie dump-imports src main hsie dump-imports src/library src/executable
``` ```
This dumps all imports of the modules in the given directory to a CSV file, This dumps all imports of the modules in the given directory to a CSV file,
@@ -18,7 +18,7 @@ To dump to a JSON file (e.g., to further process with `jq`), add the `--json`
flag: flag:
``` ```
hsie dump-imports --json src main hsie dump-imports --json src/library src/executable
``` ```
## Graphing imports ## Graphing imports
@@ -27,7 +27,7 @@ The tool can generate `graphviz` graphs of module and symbol imports by printing
a file to `stdout` that can directly be rendered with `dot`: a file to `stdout` that can directly be rendered with `dot`:
``` ```
hsie graph-modules src main | dot -Tpng -o modules.png hsie graph-modules src/library src/executable | dot -Tpng -o modules.png
``` ```
The command `graph-modules` prints a graph of which modules insert which other The command `graph-modules` prints a graph of which modules insert which other
@@ -39,7 +39,7 @@ To check whether modules are imported under consistent aliases in your project,
run: run:
``` ```
hsie check-aliases main src hsie check-aliases src/library src/executable
``` ```
This will exit with a non-zero exit code if any inconsistent aliases are found. This will exit with a non-zero exit code if any inconsistent aliases are found.
@@ -48,13 +48,13 @@ The following command checks whether any modules are imported as wildcards, i.e.
not qualified and without specifying symbols. not qualified and without specifying symbols.
``` ```
hsie check-wildcards main src hsie check-wildcards src/library src/executable
``` ```
To whitelist certain modules to be imported as wildcards, use `--ok`: To whitelist certain modules to be imported as wildcards, use `--ok`:
``` ```
hsie check-wildcards main src --ok Protolude --ok Test.Module hsie check-wildcards src/library src/executable --ok Protolude --ok Test.Module
``` ```
## Current limitations ## Current limitations
-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 , coreutils
, git , git
, lib , lib
, moreutils
, runCommand , runCommand
, shellcheck , shellcheck
, stdenv , stdenv
@@ -56,7 +57,7 @@ let
# Example: This way `postgrest-watch -h` will return the help output for watch, while # 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. # `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 # 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 = bash-completion =
@@ -66,7 +67,7 @@ let
'' ''
+ lib.optionalString (positionalCompletion != "") '' + 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 '' + lib.optionalString withTmpDir ''
mkdir -p "''${TMPDIR:-/tmp}/postgrest" tmpdir="$(${coreutils}/bin/mktemp -d --tmpdir=/tmp ${name}-XXX)"
tmpdir="$(${coreutils}/bin/mktemp -d --tmpdir postgrest/${name}-XXX)"
# we keep the tmpdir when an error occurs for debugging # we keep the tmpdir when an error occurs for debugging
trap 'echo Temporary directory kept at: $tmpdir' ERR trap 'echo Temporary directory kept at: $tmpdir' ERR
-2
View File
@@ -3,6 +3,4 @@
checked-shell-script = import ./checked-shell-script; checked-shell-script = import ./checked-shell-script;
gitignore = import ./gitignore.nix; gitignore = import ./gitignore.nix;
haskell-packages = import ./haskell-packages.nix; haskell-packages = import ./haskell-packages.nix;
postgresql-libpq = import ./postgresql-libpq.nix;
slocat = import ./slocat.nix;
} }
+53 -26
View File
@@ -47,37 +47,64 @@ let
# - To modify and try packages locally, see "Working with locally modified Haskell packages" in the Nix README. # - 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 # 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; fuzzyset = prev.fuzzyset_0_2_4;
hasql-pool = lib.dontCheck (prev.callHackageDirect # TODO: Remove once available in nixpkgs
auto-update =
prev.callHackageDirect
{ {
pkg = "hasql-pool"; pkg = "auto-update";
ver = "1.0.1"; ver = "0.2.7";
sha256 = "sha256-Hf1f7lX0LWkjrb25SDBovCYPRdmUP1H6pAxzi7kT4Gg="; sha256 = "sha256-fHX/OqF/cB9rbpGpLUtA29bcEJS43HUWHcK55yUxKoo=";
}
{ };
# TODO: Remove once available in nixpkgs
aeson-jsonpath =
prev.callHackageDirect
{
pkg = "aeson-jsonpath";
ver = "0.4.2.0";
sha256 = "sha256-K+3brf1zjSSjojtSCXFrip5rrP7AO/S4zndAxAnvEfc=";
}
{ };
http2 =
prev.callHackageDirect
{
pkg = "http2";
ver = "5.4.0";
sha256 = "sha256-PeEWVd61bQ8G7LvfLeXklzXqNJFaAjE2ecRMWJZESPE=";
}
{ };
http-semantics =
prev.callHackageDirect
{
pkg = "http-semantics";
ver = "0.4.0";
sha256 = "sha256-rh0z51EKvsu5rQd5n2z3fSRjjEObouNZSBPO9NFYOF0=";
}
{ };
network-run =
prev.callHackageDirect
{
pkg = "network-run";
ver = "0.5.0";
sha256 = "sha256-vbXh+CzxDsGApjqHxCYf/ijpZtUCApFbkcF5gyN0THU=";
}
{ };
warp =
lib.dontCheck
(prev.callHackageDirect
{
pkg = "warp";
ver = "3.4.14";
sha256 = "sha256-RnoOUlC6dOP0sK/tYAJCX1oLzVFG1GILUY+yVbmvW8Y=";
} }
{ }); { });
hasql-notifications = lib.dontCheck (prev.callHackageDirect
{
pkg = "hasql-notifications";
ver = "0.2.2.2";
sha256 = "sha256-myKwlug7OgTa/qP6mHfCD+5Q8IhM17JvpJBfSo+M01k=";
}
{ });
# 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;
postgresql-libpq = lib.dontCheck (prev.callHackageDirect
{
pkg = "postgresql-libpq";
ver = "0.10.1.0";
sha256 = "sha256-tXOMqCO8opMilI9rx0D+njqjIjbZsH168Bzb8Aq8Ff4=";
}
{
postgresql = super.libpq;
});
}; };
in 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 (pkgs) pkgsStatic;
inherit (pkgsStatic.haskell) lib; inherit (pkgsStatic.haskell) lib;
packagesStatic = packagesStatic = pkgsStatic.haskell.packages.native-bignum."${compiler}";
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 ];
});
});
});
makeExecutableStatic = drv: pkgs.lib.pipe drv [ makeExecutableStatic = drv: pkgs.lib.pipe drv [
lib.compose.justStaticExecutables lib.compose.justStaticExecutables
# To successfully compile a redistributable, fully static executable we need to: # To successfully compile a redistributable, fully static executable we need to:
# 1. make executable really statically linked. # 1. avoid any references to /nix/store to prevent blowing up the closure size.
# 2. avoid any references to /nix/store to prevent blowing up the closure size. (drv: drv.overrideAttrs {
# 3. be able to run the executable. allowedReferences = [
# When checking for references, we ignore the following: pkgsStatic.openssl.etc
# - 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"
if ! (file "$exe" | grep 'statically linked') then # 2. be able to run the executable.
echo "not a static executable, ldd output:" (drv: drv.overrideAttrs {
ldd "$exe" passthru.tests.version = pkgsStatic.testers.testVersion {
exit 1 package = drv;
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
'';
}))
]; ];
in in
+26 -7
View File
@@ -15,7 +15,6 @@ let
withEnv = postgrest.env; withEnv = postgrest.env;
} }
'' ''
${cabal-install}/bin/cabal v2-update
exec ${cabal-install}/bin/cabal v2-build ${devCabalOptions} "''${_arg_leftovers[@]}" exec ${cabal-install}/bin/cabal v2-build ${devCabalOptions} "''${_arg_leftovers[@]}"
''; '';
@@ -34,6 +33,17 @@ let
exec ${cabal-install}/bin/cabal v2-clean 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 = run =
checkedShellScript checkedShellScript
{ {
@@ -41,20 +51,26 @@ let
docs = "Run PostgREST after building it interactively with cabal-install"; docs = "Run PostgREST after building it interactively with cabal-install";
args = args =
[ [
"ARG_USE_ENV([PGRST_DB_ANON_ROLE], [postgrest_test_anonymous], [PostgREST anonymous role])" "ARG_USE_ENV([PGRST_DB_ANON_ROLE], [], [PostgREST anonymous role. (default: 'postgrest_test_anonymous')])"
"ARG_USE_ENV([PGRST_DB_POOL], [1], [PostgREST pool size])" "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_DB_POOL_ACQUISITION_TIMEOUT], [1], [PostgREST pool timeout])"
"ARG_USE_ENV([PGRST_JWT_SECRET], [reallyreallyreallyreallyverysafe], [PostgREST JWT secret])" "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])" "ARG_LEFTOVERS([PostgREST arguments])"
]; ];
workingDir = "/"; workingDir = "/";
withEnv = postgrest.env; withEnv = postgrest.env;
} }
'' ''
# when there's a default, argbash conflates empty string with unset, so we do this workaround to be able to do `PGRST_DB_ANON_ROLE="" <command>` for manual testing
if [[ ! ''${PGRST_DB_ANON_ROLE+x} ]]; then
PGRST_DB_ANON_ROLE="postgrest_test_anonymous"
fi
export PGRST_DB_ANON_ROLE export PGRST_DB_ANON_ROLE
export PGRST_DB_POOL export PGRST_DB_POOL
export PGRST_DB_POOL_ACQUISITION_TIMEOUT export PGRST_DB_POOL_ACQUISITION_TIMEOUT
export PGRST_JWT_SECRET export PGRST_JWT_SECRET
export PGRST_ADMIN_SERVER_PORT
exec ${cabal-install}/bin/cabal v2-run ${devCabalOptions} --verbose=0 -- \ exec ${cabal-install}/bin/cabal v2-run ${devCabalOptions} --verbose=0 -- \
postgrest "''${_arg_leftovers[@]}" postgrest "''${_arg_leftovers[@]}"
@@ -68,7 +84,7 @@ let
docs = "Run a profiled build of postgREST. This will generate a postgrest.prof file that can be used to do optimization."; docs = "Run a profiled build of postgREST. This will generate a postgrest.prof file that can be used to do optimization.";
args = args =
[ [
"ARG_USE_ENV([PGRST_DB_ANON_ROLE], [postgrest_test_anonymous], [PostgREST anonymous role])" "ARG_USE_ENV([PGRST_DB_ANON_ROLE], [], [PostgREST anonymous role. (default: 'postgrest_test_anonymous')])"
"ARG_USE_ENV([PGRST_DB_POOL], [1], [PostgREST pool size])" "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_DB_POOL_ACQUISITION_TIMEOUT], [1], [PostgREST pool timeout])"
"ARG_USE_ENV([PGRST_JWT_SECRET], [reallyreallyreallyreallyverysafe], [PostgREST JWT secret])" "ARG_USE_ENV([PGRST_JWT_SECRET], [reallyreallyreallyreallyverysafe], [PostgREST JWT secret])"
@@ -78,15 +94,17 @@ let
withEnv = postgrest.env; withEnv = postgrest.env;
} }
'' ''
# when there's a default, argbash conflates empty string with unset, so we do this workaround to be able to do `PGRST_DB_ANON_ROLE="" <command>` for manual testing
if [[ ! ''${PGRST_DB_ANON_ROLE+x} ]]; then
PGRST_DB_ANON_ROLE="postgrest_test_anonymous"
fi
export PGRST_DB_ANON_ROLE export PGRST_DB_ANON_ROLE
export PGRST_DB_POOL export PGRST_DB_POOL
export PGRST_DB_POOL_ACQUISITION_TIMEOUT export PGRST_DB_POOL_ACQUISITION_TIMEOUT
export PGRST_JWT_SECRET export PGRST_JWT_SECRET
${cabal-install}/bin/cabal v2-update exec ${cabal-install}/bin/cabal --builddir="dist-prof" v2-run --enable-profiling --disable-shared exe:postgrest -- \
${cabal-install}/bin/cabal --builddir="dist-prof" v2-build --enable-profiling --disable-shared exe:postgrest +RTS -p -h -RTS "''${_arg_leftovers[@]}"
${cabal-install}/bin/cabal --builddir="dist-prof" v2-run -- \
postgrest +RTS -p -h -RTS "''${_arg_leftovers[@]}"
''; '';
repl = repl =
@@ -109,6 +127,7 @@ buildToolbox
inherit inherit
build build
clean clean
update
run run
runProfiled runProfiled
repl; repl;
+11 -159
View File
@@ -5,14 +5,13 @@
, curl , curl
, devCabalOptions , devCabalOptions
, entr , entr
, git , fd
, graphviz , graphviz
, hsie , hsie
, nix , nix
, silver-searcher , stdenv
, style , style
, tests , tests
, withTools
, haskellPackages , haskellPackages
, ctags , ctags
, openssl , openssl
@@ -40,7 +39,7 @@ let
} }
'' ''
while true; do while true; do
(! ${silver-searcher}/bin/ag -l . | ${entr}/bin/entr -dr "$_arg_command" "''${_arg_leftovers[@]}") (! ${fd}/bin/fd -H -E .git | ${entr}/bin/entr -dr "$_arg_command" "''${_arg_leftovers[@]}")
done done
''; '';
@@ -53,10 +52,14 @@ let
Requires authentication with `cachix authtoken ...`. Requires authentication with `cachix authtoken ...`.
''; '';
args =
[
"ARG_OPTIONAL_SINGLE([system], , [System], [${stdenv.system}])"
];
workingDir = "/"; workingDir = "/";
} }
'' ''
${nix}/bin/nix-instantiate \ ${nix}/bin/nix-instantiate --argstr system "$_arg_system" \
| xargs ${nix}/bin/nix-store -qR --include-outputs \ | xargs ${nix}/bin/nix-store -qR --include-outputs \
| ${cachix}/bin/cachix push postgrest | ${cachix}/bin/cachix push postgrest
''; '';
@@ -77,6 +80,7 @@ let
} }
'' ''
${tests}/bin/postgrest-test-spec ${tests}/bin/postgrest-test-spec
${tests}/bin/postgrest-test-observability
${tests}/bin/postgrest-test-doctests ${tests}/bin/postgrest-test-doctests
${tests}/bin/postgrest-test-io ${tests}/bin/postgrest-test-io
${tests}/bin/postgrest-test-big-schema ${tests}/bin/postgrest-test-big-schema
@@ -85,156 +89,6 @@ let
${style}/bin/postgrest-style-check ${style}/bin/postgrest-style-check
''; '';
gitHooks =
let
name = "postgrest-git-hooks";
in
checkedShellScript
{
inherit name;
docs =
''
Enable or disable git pre-commit and pre-push hooks.
Basic is faster and will only run:
- pre-commit: postgrest-style
- pre-push: postgrest-lint
Full takes a lot more time and will run:
- pre-commit: postgrest-style && postgrest-lint
- pre-push: postgrest-check
Changes made by postgrest-style will be staged automatically.
Example usage:
postgrest-git-hooks disable
postgrest-git-hooks enable basic
postgrest-git-hooks enable full
The "run" operation and "--hook" argument are only used internally.
'';
args =
[
"ARG_POSITIONAL_SINGLE([operation], [Operation])"
"ARG_TYPE_GROUP_SET([OPERATION], [OPERATION], [operation], [disable,enable,run])"
"ARG_POSITIONAL_SINGLE([mode], [Mode], [basic])"
"ARG_TYPE_GROUP_SET([MODE], [MODE], [mode], [basic,full])"
"ARG_OPTIONAL_SINGLE([hook], , [Hook], [pre-commit])"
"ARG_TYPE_GROUP_SET([HOOK], [HOOK], [hook], [pre-commit,pre-push])"
];
positionalCompletion =
''
if test "$prev" == "${name}"; then
COMPREPLY=( $(compgen -W "enable disable" -- "$cur") )
elif test "$prev" == "enable" || test "$prev" == "disable"; then
COMPREPLY=( $(compgen -W "basic full" -- "$cur") )
fi
'';
workingDir = "/";
}
''
if [ run != "$_arg_operation" ]; then
# Remove all hooks first and ignore failures because the file might be missing.
# This assumes that we're only adding lines that include "postgrest-git-hooks"
# to the hook file.
sed -i -e '/postgrest-git-hooks/d' .git/hooks/pre-{commit,push} 2> /dev/null || true
if [ disable != "$_arg_operation" ]; then
# The nix-shell && + nix-shell || pattern makes sure we can run the hook
# in a pure nix-shell, where nix-shell itself is not available, too.
# The $(nix-shell --run "command -v ...") pattern ensures we only need to enable
# the hooks once and still run the latest of our hook scripts, even when we
# update them in the repo.
echo 'command -v nix-shell > /dev/null || postgrest-git-hooks --hook=pre-commit run' "$_arg_mode" \
>> .git/hooks/pre-commit
# shellcheck disable=SC2016
echo 'command -v nix-shell > /dev/null && $(nix-shell --quiet -Q --run "command -v postgrest-git-hooks") --hook=pre-commit run' "$_arg_mode" \
>> .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
echo 'command -v nix-shell > /dev/null || postgrest-git-hooks --hook=pre-push run' "$_arg_mode" \
>> .git/hooks/pre-push
# shellcheck disable=SC2016
echo 'command -v nix-shell > /dev/null && $(nix-shell --quiet -Q --run "command -v postgrest-git-hooks") --hook=pre-push run' "$_arg_mode" \
>> .git/hooks/pre-push
chmod +x .git/hooks/pre-push
fi
else
# When run from a git hook, the GIT_ environment variables conflict with our withGit helper.
# The following unsets all GIT_ variables.
unset "''${!GIT_@}"
# shellcheck disable=SC2317
function restore () {
ref="$(git stash list --format=format:%gD --grep "$1" -n1)"
# this will avoid merge conflicts when applying the stash
${git}/bin/git restore --source="$ref" .
# restore untracked files, too. could fail with no files
if [ "$(git show --numstat --format=oneline "$ref^3" | wc -l)" -gt 1 ]; then
${git}/bin/git restore --overlay --source="$ref^3" .
fi
${git}/bin/git stash drop "$ref"
}
case "$_arg_mode" in
basic)
case "$_arg_hook" in
pre-commit)
# To be able to automatically add only changes from postgrest-style to the staging area,
# we need to run postgrest-style twice. Otherwise we'd risk merge conflicts when popping
# the stash afterwards.
${style}/bin/postgrest-style
stash="postgrest-git-hooks-$RANDOM"
${git}/bin/git stash push --include-untracked --keep-index -m "$stash"
if [ "$(git stash list --grep $stash)" ]; then
# Only create the stash pop trap, if we actually created a stash.
# Otherwise stash pop will cause havoc.
trap 'restore "$stash"' EXIT
fi
${style}/bin/postgrest-style
${git}/bin/git add .
;;
pre-push)
# Create a clean working tree without any uncomitted changes.
${withTools.withGit} HEAD ${style}/bin/postgrest-lint
;;
esac
;;
full)
case "$_arg_hook" in
pre-commit)
# To be able to automatically add only changes from postgrest-style to the staging area,
# we need to run postgrest-style twice. Otherwise we'd risk merge conflicts when popping
# the stash afterwards.
${style}/bin/postgrest-style
stash="postgrest-git-hooks-$RANDOM"
${git}/bin/git stash push --include-untracked --keep-index -m "$stash"
if [ "$(git stash list --grep $stash)" ]; then
# Only create the stash pop trap, if we actually created a stash.
# Otherwise stash pop will cause havoc.
trap 'restore "$stash"' EXIT
fi
${style}/bin/postgrest-style
${git}/bin/git add .
${style}/bin/postgrest-lint
;;
pre-push)
# Create a clean working tree without any uncomitted changes.
${withTools.withGit} HEAD ${check}
;;
esac
;;
esac
fi
'';
dumpMinimalImports = dumpMinimalImports =
checkedShellScript checkedShellScript
{ {
@@ -246,7 +100,6 @@ let
} }
'' ''
mkdir -p "$_arg_dumpdir" mkdir -p "$_arg_dumpdir"
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal v2-build ${devCabalOptions} \ ${cabal-install}/bin/cabal v2-build ${devCabalOptions} \
--builddir="$tmpdir" \ --builddir="$tmpdir" \
--ghc-option=-ddump-minimal-imports \ --ghc-option=-ddump-minimal-imports \
@@ -276,10 +129,10 @@ let
{ {
name = "postgrest-hsie-graph-modules"; name = "postgrest-hsie-graph-modules";
docs = "Create a PNG graph of modules imported within the codebase."; docs = "Create a PNG graph of modules imported within the codebase.";
args = [ "ARG_POSITIONAL_SINGLE([outfile], [Output filename])" ]; args = [ "ARG_OPTIONAL_SINGLE([outfile], [o], [Output filename], [postgrest-module-graph.png])" ];
} }
'' ''
${hsie} graph-modules main src | ${graphviz}/bin/dot -Tpng -o "$_arg_outfile" ${hsie} graph-modules src/library src/executable | ${graphviz}/bin/dot -Tpng -o "$_arg_outfile"
''; '';
hsieGraphSymbols = hsieGraphSymbols =
@@ -390,7 +243,6 @@ buildToolbox
inherit inherit
check check
dumpMinimalImports dumpMinimalImports
gitHooks
hsieGraphModules hsieGraphModules
hsieGraphSymbols hsieGraphSymbols
hsieMinimalImports hsieMinimalImports
+15 -2
View File
@@ -35,12 +35,15 @@ let
workingDir = "/docs"; workingDir = "/docs";
} }
'' ''
# https://github.com/sphinx-doc/sphinx/issues/11739
export LC_ALL=C
function build() { function build() {
${python}/bin/sphinx-build --color -W -a -n . -b "$@" ${python}/bin/sphinx-build --color -W -a -n . -b "$@"
} }
if [ "$_arg_language" == "" ]; then 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" rm -rf "../.docs-build/html/default"
if [ -d languages ]; then if [ -d languages ]; then
@@ -51,7 +54,7 @@ let
build html "../.docs-build/html/default" build html "../.docs-build/html/default"
else 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" rm -rf "../.docs-build/html/$_arg_language"
# update and build specific locale, can be used to create new locale # update and build specific locale, can be used to create new locale
@@ -119,6 +122,10 @@ let
workingDir = "/docs"; workingDir = "/docs";
} }
'' ''
echo "Checking spelling mistakes..."
export LC_ALL=C
FILES=$(find . -type f -iname '*.rst' | tr '\n' ' ') FILES=$(find . -type f -iname '*.rst' | tr '\n' ' ')
# shellcheck disable=SC2086 disable=SC2016 # shellcheck disable=SC2086 disable=SC2016
@@ -139,6 +146,10 @@ let
workingDir = "/docs"; workingDir = "/docs";
} }
'' ''
echo "Detecting obsolete dictionary entries..."
export LC_ALL=C
FILES=$(find . -type f -iname '*.rst' | tr '\n' ' ') FILES=$(find . -type f -iname '*.rst' | tr '\n' ' ')
tail -n+2 postgrest.dict \ tail -n+2 postgrest.dict \
@@ -157,6 +168,8 @@ let
workingDir = "/docs"; workingDir = "/docs";
} }
'' ''
export LC_ALL=C
${python}/bin/sphinx-build --color -b linkcheck . ../.docs-build ${python}/bin/sphinx-build --color -b linkcheck . ../.docs-build
''; '';
+65 -60
View File
@@ -1,63 +1,50 @@
# generates a file to be used by the vegeta load testing tool # 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 time
import hmac
import hashlib
import base64
import json
import argparse import argparse
import sys
import random import random
import jwcrypto.jwt as jwt
from pathlib import Path
SECRET = b"reallyreallyreallyreallyverysafe"
URL = "http://postgrest" URL = "http://postgrest"
JWT_DURATION = 120
TOTAL_TARGETS = 50000 # tuned by hand to reduce result variance secret_key = "reallyreallyreallyreallyverysafe"
def base64url_encode(data: bytes) -> str: def generate_target(
"""URL-safe Base64 encode without padding.""" now: int,
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii") key: jwt.JWK,
) -> list[str]:
"""Generate a target using an HS256 or RS256 JWT"""
def generate_jwt(exp_inc: int) -> str: headers = {
"""Generate an HS256 JWT"""
# Header & payload
header = {"alg": "HS256", "typ": "JWT"}
now = int(time.time())
payload = {
"sub": f"user_{random.getrandbits(32)}", "sub": f"user_{random.getrandbits(32)}",
"iat": now, "iat": now,
"exp": now + exp_inc, }
claims = {
"role": "postgrest_test_author", "role": "postgrest_test_author",
} }
# Encode to JSON and then to Base64URL headers["alg"] = "RS256" if key.get("kty") == "RSA" else "HS256"
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)
# Sign (HMACSHA256) the "<header>.<payload>" string token = jwt.JWT(headers, claims)
signing_input = f"{header_b64}.{payload_b64}".encode() token.make_signed_token(key)
signature = hmac.new(SECRET, signing_input, hashlib.sha256).digest()
signature_b64 = base64url_encode(signature)
return f"{header_b64}.{payload_b64}.{signature_b64}" return [
f"OPTIONS {URL}/authors_only?{headers["alg"]}",
f"Authorization: Bearer {token.serialize()}",
# We want to ensure 401 Unauthorized responses don't happen during "", # blank line to separate requests
# 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
return build_run_postgrest_time + file_generation_time + dynamic_exp_inc
def main(): def main():
@@ -65,29 +52,47 @@ def main():
description="Generate Vegeta targets with unique JWTs" description="Generate Vegeta targets with unique JWTs"
) )
parser.add_argument( parser.add_argument(
"output", "generated_path",
help="Path to write the generated targets file", metavar="GENERATED_PATH",
help="Path to write the generated files",
type=Path,
) )
args = parser.parse_args() args = parser.parse_args()
targets_path = args.generated_path / "gen_targets.http"
hs = jwt.JWK.from_password(secret_key)
rsa = jwt.JWK.generate(kty="RSA", size=4096)
jwks = jwt.JWKSet()
jwks.add(hs)
jwks.add(rsa)
jwks_path = args.generated_path / "gen_jwks.json"
# Technically, this exports the private keys, because HS does not have the concept
# of a public key. This is not a problem for tests, though, PostgREST can verify
# tokens with the private key just as well.
jwks_path.write_text(jwks.export())
print(f"Created JWKSet on {jwks_path}")
ntargets = 1000
print(f"Generating {ntargets} targets...")
now = int(time.time())
lines = [] lines = []
start_time = time.time()
for i in range(TOTAL_TARGETS): for i in range(ntargets):
token = generate_jwt(estimate_adequate_jwt_exp_increase(i)) target = generate_target(now, hs if i % 2 == 0 else rsa)
lines.append(f"OPTIONS {URL}/authors_only") lines.extend(target)
lines.append(f"Authorization: Bearer {token}")
lines.append("") # blank line to separate requests
try: with open(targets_path, "w") as f:
with open(args.output, "w") as f:
f.write("\n".join(lines)) f.write("\n".join(lines))
except IOError as e:
print(f"Error writing to {args.output}: {e}", file=sys.stderr)
sys.exit(1)
elapsed = time.time() - start_time print(f"Created {ntargets} targets", end=" ")
print(f"Created {TOTAL_TARGETS} targets in {args.output} ({elapsed:.2f}s)")
if __name__ == "__main__": 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; };
}
+162 -56
View File
@@ -1,7 +1,11 @@
{ buildToolbox { buildToolbox
, checkedShellScript , checkedShellScript
, git
, jq , jq
, libfaketime
, python3
, python3Packages , python3Packages
, runCommand
, vegeta , vegeta
, withTools , withTools
, writers , writers
@@ -18,6 +22,8 @@ let
]; ];
} }
'' ''
echo "Starting vegeta loadtest..."
# ARG_USE_ENV only adds defaults or docs for environment variables # ARG_USE_ENV only adds defaults or docs for environment variables
# We manually implement a required check here # We manually implement a required check here
# See also: https://github.com/matejak/argbash/issues/80 # See also: https://github.com/matejak/argbash/issues/80
@@ -40,53 +46,75 @@ let
docs = "Run the vegeta loadtests with PostgREST."; docs = "Run the vegeta loadtests with PostgREST.";
args = [ args = [
"ARG_OPTIONAL_SINGLE([output], [o], [Filename to dump json output to], [./loadtest/result.bin])" "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])"
"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-cache,jwt-cache-worst])"
"ARG_TYPE_GROUP_SET([KIND], [KIND], [kind], [mixed,jwt])" "ARG_OPTIONAL_SINGLE([monitor], [m], [Monitoring file], [./loadtest/result.csv])"
"ARG_LEFTOVERS([additional vegeta arguments])" "ARG_LEFTOVERS([additional vegeta arguments])"
]; ];
workingDir = "/"; workingDir = "/";
} }
'' ''
# previously required settings to make this work with older branches
export PGRST_DB_ANON_ROLE="postgrest_test_anonymous" export PGRST_DB_ANON_ROLE="postgrest_test_anonymous"
export PGRST_DB_URI="postgresql://"
export PGRST_DB_SCHEMAS="test"
export PGRST_DB_CONFIG="false" export PGRST_DB_CONFIG="false"
export PGRST_DB_POOL="1" export PGRST_DB_POOL="1"
export PGRST_DB_SCHEMAS="test"
export PGRST_DB_TX_END="rollback-allow-override" export PGRST_DB_TX_END="rollback-allow-override"
export PGRST_LOG_LEVEL="crit" export PGRST_LOG_LEVEL="crit"
export PGRST_JWT_SECRET="reallyreallyreallyreallyverysafe" export PGRST_JWT_SECRET="reallyreallyreallyreallyverysafe"
export PGRST_JWT_CACHE_MAX_LIFETIME="86400"
mkdir -p "$(dirname "$_arg_output")" mkdir -p "$(dirname "$_arg_output")"
abs_output="$(realpath "$_arg_output")" abs_output="$(realpath "$_arg_output")"
case "$_arg_kind" in case "$_arg_kind" in
jwt) jwt-cache)
export PGRST_JWT_SECRET="@${generatedTargets}/gen_jwks.json"
${genTargets} "$_arg_testdir"/gen_targets.http
# shellcheck disable=SC2145 # shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \ ${withTools.withPg} -f test/load/fixtures.sql \
${withTools.withPgrst} \ ${withTools.withPgrst} --faketime '2000-01-01 00:00:00' -m "$_arg_monitor" \
sh -c "cd \"$_arg_testdir\" && ${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\"" sh -c "cd test/load && \
${vegeta}/bin/vegeta report -type=text "$_arg_output" ${runner} -targets ${generatedTargets}/gen_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
mixed)
# shellcheck disable=SC2145 # shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \ ${withTools.withPg} -f test/load/fixtures.sql \
${withTools.withSlowPg} \ ${withTools.withPgrst} --timeout 2 --sleep 5 -m "$_arg_monitor" \
${withTools.withPgrst} \ sh -c "cd test/load && \
${withTools.withSlowPgrst} \ ${runner} -targets targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
sh -c "cd \"$_arg_testdir\" && ${runner} -targets targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
${vegeta}/bin/vegeta report -type=text "$_arg_output"
;; ;;
esac esac
${vegeta}/bin/vegeta report -type=text "$_arg_output"
if [ "$_arg_kind" != "mixed" ]; 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 = loadtestAgainst =
@@ -101,6 +129,9 @@ let
Run the vegeta loadtest against every target branch and HEAD: Run the vegeta loadtest against every target branch and HEAD:
- once on the every <target-#> branch - once on the every <target-#> branch
- once in the current worktree - once in the current worktree
Note that the Nix tooling is always taken from the HEAD branch, while the PostgREST binary is taken from the target branch.
For a discussion on why this is set up like this, see https://github.com/PostgREST/postgrest/pull/5013#discussion_r3431508441.
''; '';
args = [ args = [
"ARG_POSITIONAL_INF([target], [Commit-ish reference to compare with], 1)" "ARG_POSITIONAL_INF([target], [Commit-ish reference to compare with], 1)"
@@ -115,20 +146,48 @@ let
workingDir = "/"; workingDir = "/";
} }
'' ''
for tgt in "''${_arg_target[@]}"; do # Build postgrest for every target and HEAD.
# Keeps a reference to the postgrest binary and faketime lib for every branch to run later.
declare -A pgrst faketime
for tgt in "''${_arg_target[@]}" HEAD; do
# not using withTmpDir here, because we don't want to keep the directory on error
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
${git}/bin/git worktree add -f "$tmpdir" "$tgt" > /dev/null
pushd "$tmpdir" > /dev/null
build_start=$SECONDS
echo -n "${name}: Building postgrest (nix) on $tgt... "
# Using lib.getBin to also make this work with older checkouts, where .bin was not a thing, yet.
nix-build --no-out-link -E 'with import ./. {}; pkgs.lib.getBin postgrestPackage' > build.log 2>&1 || {
echo "failed, output:"
cat build.log
exit 1
}
pgrst[$tgt]="$(nix-build --no-out-link -E 'with import ./. {}; pkgs.lib.getBin postgrestPackage')/bin/postgrest"
# To avoid glibc mismatches with back-branches, we need to take libfaketime from the target branch.
faketime[$tgt]="$(nix-build --no-out-link -A pkgs.libfaketime)/lib/libfaketime.so.1"
build_end=$((SECONDS - build_start))
printf "done in %ss.\n" "$build_end"
popd > /dev/null
${git}/bin/git worktree remove -f "$tmpdir" > /dev/null
rm -rf "$tmpdir"
done
# Run loadtest for every target and HEAD.
# Running the tests is separated from building them to reduce the chances of
# other processes skewing the results between two runs.
for tgt in "''${_arg_target[@]}" HEAD; do
cat << EOF cat << EOF
Running loadtest on "$tgt"... Running "$_arg_kind" loadtest on "$tgt"...
EOF EOF
# Runs the test files from the current working tree FAKETIME_LIB="''${faketime[$tgt]}" PGRST_CMD="''${pgrst[$tgt]}" ${loadtest} -k "$_arg_kind" -m "loadtest/$tgt.csv" --output "loadtest/$tgt.bin"
# to make sure both tests are run with the same files.
# 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"
cat << EOF cat << EOF
@@ -137,20 +196,6 @@ let
EOF EOF
done done
cat << EOF
Running loadtest on HEAD...
EOF
${loadtest} -k "$_arg_kind" --output "$PWD/loadtest/head.bin" --testdir "$PWD/test/load"
cat << EOF
Done running on HEAD.
EOF
''; '';
reporter = reporter =
@@ -160,12 +205,14 @@ let
docs = "Create a named json report for a single result file."; docs = "Create a named json report for a single result file.";
args = [ args = [
"ARG_POSITIONAL_SINGLE([file], [Filename of result to create report for])" "ARG_POSITIONAL_SINGLE([file], [Filename of result to create report for])"
"ARG_OPTIONAL_SINGLE([percentile], [p], [Percentile to report latency for], 50)"
"ARG_LEFTOVERS([additional vegeta arguments])" "ARG_LEFTOVERS([additional vegeta arguments])"
]; ];
workingDir = "/"; workingDir = "/";
} }
'' ''
${vegeta}/bin/vegeta report -type=json "$_arg_file" \ ${vegeta}/bin/vegeta encode "$_arg_file" \
| ${jq}/bin/jq --arg percentile "$_arg_percentile" --slurp 'map(select(.url != "")) | group_by("\(.code) \(.method) \(.url)") | map({("\(.[0].code) \(.[0].method) \(.[0].url)" | sub("http://postgrest";"")): map(.latency) | sort | .[(length-1) * ($percentile | tonumber) / 100 | floor] / 10e3 }) | .[]' \
| ${jq}/bin/jq --arg branch "$(basename "$_arg_file" .bin)" '. + {branch: $branch}' | ${jq}/bin/jq --arg branch "$(basename "$_arg_file" .bin)" '. + {branch: $branch}'
''; '';
@@ -178,11 +225,31 @@ let
import sys import sys
import pandas as pd import pandas as pd
def evaluate_change(df):
try:
return ((df['HEAD'] / df['main'] - 1) * 100) \
.map(lambda r: "{icon} {ratio:.1f} %".format(
ratio=r,
# Hardcoded failure threshold for CI is 5% here.
icon="" if r < 5 else ":x:"
))
except KeyError:
return None
pd.read_json(sys.stdin) \ pd.read_json(sys.stdin) \
.set_index('param') \ .rename(columns={'latency': sys.argv[1]}) \
.drop(['branch', 'earliest', 'end', 'latest']) \ .set_index(sys.argv[1]) \
.drop(['branch']) \
.convert_dtypes() \ .convert_dtypes() \
.to_markdown(sys.stdout, floatfmt='.0f') .assign(change=evaluate_change) \
.to_markdown(
sys.stdout,
floatfmt='.1f',
colglobalalign='right',
colalign=('left',)
)
''; '';
@@ -191,18 +258,57 @@ let
{ {
name = "postgrest-loadtest-report"; name = "postgrest-loadtest-report";
docs = "Create a report of all loadtest reports as markdown."; docs = "Create a report of all loadtest reports as markdown.";
args = [
"ARG_OPTIONAL_SINGLE([group], [g], [Marker to group results])"
"ARG_OPTIONAL_SINGLE([percentile], [p], [Percentile to report latency for], 50)"
];
workingDir = "/"; workingDir = "/";
} }
'' ''
find loadtest -type f -iname '*.bin' -exec ${reporter} {} \; \ echo -e "## Loadtest results $_arg_group (P$_arg_percentile)\n"
| ${jq}/bin/jq '[paths(scalars) as $path | {param: $path | join("."), (.branch): getpath($path)}]' \
| ${jq}/bin/jq --slurp 'flatten | group_by(.param) | map(add)' \ find loadtest -type f -iname '*.bin' -exec ${reporter} -p "$_arg_percentile" {} \; \
| ${toMarkdown} | ${jq}/bin/jq '[paths(scalars) as $path | {latency: $path | join("."), (.branch): getpath($path)}]' \
| ${jq}/bin/jq --slurp 'flatten | group_by(.latency) | map(add)' \
| ${toMarkdown} "P$_arg_percentile latency [μs]"
''; '';
genTargets = writers.writePython3 "postgrest-gen-loadtest-targets" { } (builtins.readFile ./generate_targets.py); report-load =
checkedShellScript
{
name = "postgrest-loadtest-report-load";
docs = "Create a report of all CPU/MEM usage as markdown.";
args = [
"ARG_OPTIONAL_SINGLE([group], [g], [Marker to group results])"
];
workingDir = "/";
}
''
echo -e "\n\n## Loadtest elapsed seconds vs CPU/MEM usage $_arg_group\n"
find loadtest -type f -iname '*.csv' \
| sort -m \
| ${mergeMonitorResults}
'';
generatedTargets =
runCommand "postgrest-loadtest-targets"
{
nativeBuildInputs = [ (python3.withPackages (pyps: [ pyps.jwcrypto ])) ];
}
''
mkdir -p "$out"
${libfaketime}/bin/faketime '2000-01-01 00:00:00' python3 ${./generate_targets.py} "$out"
'';
mergeMonitorResults =
writers.writePython3 "postgrest-merge-monitor-results"
{
libraries = [ python3Packages.pandas python3Packages.tabulate ];
}
(builtins.readFile ./merge_monitor_result.py);
in in
buildToolbox { buildToolbox {
name = "postgrest-loadtest"; name = "postgrest-loadtest";
tools = { inherit loadtest loadtestAgainst report; }; tools = { inherit loadtest loadtestAgainst report report-load; };
} }
+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 --no-out-link -A docs.requirements)" >> docs/requirements.txt
'';
in
buildToolbox
{
name = "postgrest-nixpkgs";
tools = { inherit upgrade; };
}
+20 -26
View File
@@ -7,7 +7,6 @@ let
{ {
name = "postgrest-release"; name = "postgrest-release";
docs = "Patch postgrest.cabal, CHANGELOG.md, commit and push all in one go."; docs = "Patch postgrest.cabal, CHANGELOG.md, commit and push all in one go.";
args = [ "ARG_OPTIONAL_BOOLEAN([major], [m], [Bump to new major version (only applies on main branch).])" ];
workingDir = "/"; workingDir = "/";
} }
'' ''
@@ -23,24 +22,20 @@ let
bump () { bump () {
current_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)" current_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
# shellcheck disable=SC2034 # 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" echo "Current version is $current_version"
case "$1" in case "$1" in
major) A)
new_version="$((major+1)).0.0" new_version="$((A+1)).0"
new_docs_version="$((major+1)).0" new_docs_version="$((A+1))"
;; ;;
minor) B)
new_version="$major.$((minor+1)).0" new_version="$A.$((B+1))"
new_docs_version="$major.$((minor+1))" new_docs_version="$A"
;;
patch)
new_version="$major.$minor.$((patch+1))"
new_docs_version="$major.$minor"
;; ;;
devel) devel)
new_version="$major.$((minor+1))" new_version="$((A+1))"
new_docs_version="devel" new_docs_version="devel"
;; ;;
esac esac
@@ -50,18 +45,17 @@ let
echo "Updating docs/conf.py ..." echo "Updating docs/conf.py ..."
sed -i -E "s/^(version = ).*$/\1\"$new_docs_version\"/" docs/conf.py > /dev/null sed -i -E "s/^(version = ).*$/\1\"$new_docs_version\"/" docs/conf.py > /dev/null
git add postgrest.cabal docs/conf.py > /dev/null echo "Updating Haskell source file links ..."
sed -i -E "s#(github\.com/PostgREST/postgrest/blob)/main/#\1/$new_version/#g" docs/explanations/architecture.rst
git add postgrest.cabal docs/conf.py docs/explanations/architecture.rst > /dev/null
} }
today_date_for_changelog="$(date '+%Y-%m-%d')" today_date_for_changelog="$(date '+%Y-%m-%d')"
if [[ "$current_branch" == "main" ]]; then if [[ "$current_branch" == "main" ]]; then
if [[ "$_arg_major" == "on" ]]; then bump A
bump major
else else
bump minor bump B
fi
else
bump patch
fi fi
echo "Updating CHANGELOG.md ..." echo "Updating CHANGELOG.md ..."
@@ -69,19 +63,19 @@ let
git add CHANGELOG.md > /dev/null git add CHANGELOG.md > /dev/null
echo "Committing ..." echo "Committing ..."
git commit -m "bump version to $new_version" > /dev/null git commit -m "chore: bump version to $new_version" > /dev/null
if [[ "$current_branch" == "main" ]]; then if [[ "$current_branch" == "main" ]]; then
bump devel bump devel
# The order of operations is important here: # The order of operations is important here:
# - bump devel is run and $major is upated to the new version # - bump devel is run and $A is updated to the new version
# - the branch is created with the new major, but the commit before the devel bump # - the branch is created with the new A, but the commit before the devel bump
# - the devel bump is committed # - the devel bump is committed
git branch -f "v$major" git branch "v$A"
echo "Committing (devel bump)..." echo "Committing (devel bump)..."
git commit -m "bump version to $new_version" > /dev/null git commit -m "chore: bump version to $new_version" > /dev/null
fi fi
trap "echo Remote not found. Please push manually ..." ERR trap "echo Remote not found. Please push manually ..." ERR
@@ -90,7 +84,7 @@ let
if [[ "$current_branch" == "main" ]]; then if [[ "$current_branch" == "main" ]]; then
push1="git push $remote $current_branch" push1="git push $remote $current_branch"
push2="git push $remote v$major --force" push2="git push $remote v$A"
else else
push1="git push $remote $current_branch" push1="git push $remote $current_branch"
push2="" push2=""
+35 -11
View File
@@ -3,13 +3,16 @@
, buildToolbox , buildToolbox
, checkedShellScript , checkedShellScript
, deadnix , deadnix
, fd
, git , git
, hlint , hlint
, hsie , hsie
, nixpkgs-fmt , nixpkgs-fmt
, silver-searcher , python3Packages
, ruff
, statix , statix
, stylish-haskell , stylish-haskell
, writeText
}: }:
let let
style = style =
@@ -18,27 +21,27 @@ let
name = "postgrest-style"; name = "postgrest-style";
docs = "Automatically format Haskell, Nix and Python files."; docs = "Automatically format Haskell, Nix and Python files.";
workingDir = "/"; workingDir = "/";
withTmpDir = true;
} }
'' ''
# Format Nix files # Format Nix files
${statix}/bin/statix fix ${statix}/bin/statix fix
${nixpkgs-fmt}/bin/nixpkgs-fmt . > /dev/null 2> /dev/null ${nixpkgs-fmt}/bin/nixpkgs-fmt .
# Format Haskell files # Format Haskell files
# --vimgrep fixes a bug in ag: https://github.com/ggreer/the_silver_searcher/issues/753 ${fd}/bin/fd '\.l?hs$' \
${silver-searcher}/bin/ag -l --vimgrep -g '\.l?hs$' . \
| xargs ${stylish-haskell}/bin/stylish-haskell -i | xargs ${stylish-haskell}/bin/stylish-haskell -i
# Format Python files # Format Python files
${black}/bin/black . 2> /dev/null TMPDIR="$tmpdir" ${black}/bin/black .
''; '';
# Script to check whether any uncommited changes result from postgrest-style # Script to check whether any uncommitted changes result from postgrest-style
styleCheck = styleCheck =
checkedShellScript checkedShellScript
{ {
name = "postgrest-style-check"; 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 = "/"; workingDir = "/";
} }
'' ''
@@ -49,6 +52,20 @@ let
${git}/bin/git diff-index --exit-code HEAD -- '*.hs' '*.lhs' '*.nix' '*.py' ${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 = lint =
checkedShellScript checkedShellScript
{ {
@@ -63,13 +80,20 @@ let
echo "Scanning nix files for unused code..." echo "Scanning nix files for unused code..."
${deadnix}/bin/deadnix -f ${deadnix}/bin/deadnix -f
# ruff has gaps in scanning for unused code, so we use vulture
echo "Scanning python files for unused code..."
${fd}/bin/fd '\.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..." echo "Checking consistency of import aliases in Haskell code..."
${hsie} check-aliases main src ${hsie} check-aliases src/library src/executable
echo "Linting Haskell files..." echo "Linting Haskell files..."
# --vimgrep fixes a bug in ag: https://github.com/ggreer/the_silver_searcher/issues/753 ${fd}/bin/fd '\.l?hs$' \
${silver-searcher}/bin/ag -l --vimgrep -g '\.l?hs$' . \ | xargs ${hlint}/bin/hlint --hint=${hlintConfig}
| xargs ${hlint}/bin/hlint -X QuasiQuotes -X NoPatternSynonyms
''; '';
in in

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