Compare commits

...
300 Commits
Author SHA1 Message Date
Laurence Isla 97b6022f5a bump version to 13.0.2 2025-06-02 14:18:26 -05:00
Laurence Isla c413833ec8 fix: regression that makes order by with nulls order not work alongside limits 2025-06-02 14:17:35 -05:00
steve-chavez dee7d6f39c bump version to 13.0.1 2025-06-01 08:10:43 -05:00
Thilo HohltandWolfgang Walther 6fb8077950 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 13:50:41 +02:00
steve-chavez d4f82919f7 docs: external authentication page in explanations
- Move page from External JWT generation
2025-05-30 18:08:40 -05:00
steve-chavez 610a8be9c4 docs: move jwt using SSL to tutorial 1
Removes jwt.io example in favor of a bash script
2025-05-30 18:08:34 -05:00
Taimoor ZaeemandWolfgang Walther ba42e4610a fix: log db-schemas and db-extra-search-path in schema cache load error (#4108) 2025-05-30 20:56:04 +02:00
Laurence IslaandWolfgang Walther 8531c502d7 docs: JWK kid parameter validation 2025-05-30 14:35:58 +02:00
Taimoor ZaeemandWolfgang Walther 0ba47180ae fix: allow db-extra-search-path to accept empty value 2025-05-30 14:35:57 +02:00
Taimoor ZaeemandWolfgang Walther b77605e0d3 refactor: remove unused optValue function from Config.hs module 2025-05-30 14:35:54 +02:00
steve-chavez 800b32a59c docs: remove Greenplum integration
They're not really a sponsor, so it's not fair to include them.
2025-05-28 17:44:00 -05:00
Wolfgang Walther c48b6bc85b docs: fix functions link in api/preferences
External link syntax was used instead of internal reference.
2025-05-28 09:15:50 +02:00
Wolfgang Walther f899957675 docs: apply redirects
Those redirect, so we might as well hardcode the them.
2025-05-28 09:15:50 +02:00
Wolfgang Walther 609289d2bb 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:15:47 +02:00
steve-chavez 9e58946ec6 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:45:33 -05:00
Taimoor Zaeemandsteve-chavez 48a7b8dee7 docs: explain use of max-affected preference with rpc 2025-05-22 12:49:53 -05:00
Wolfgang Walther 23a4573a9c docs: Update sphinx-rtd-theme to 3.0.2 2025-05-22 08:07:54 +02:00
Taimoor ZaeemandWolfgang Walther 91814cd4f8 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-21 21:02:00 +02:00
steve-chavez 8ef5263b04 docs: add warning for duplicate keys in spread 2025-05-15 17:42:47 -05:00
steve-chavez a71f938a44 docs: clarify spread join table 2025-05-15 15:51:14 -05:00
steve-chavez e6d4bfa465 docs: clarify fts 2025-05-15 11:57:23 -05:00
steve-chavez b90d26034e docs: clarify spread feature 2025-05-15 11:17:59 -05:00
Taimoor ZaeemandWolfgang Walther 0230a844b2 test: add test for duplicate entries in pg_description with same OID 2025-05-14 21:44:23 +02:00
Taimoor ZaeemandWolfgang Walther e0e60fa433 fix: jwt error return status 400 for invalid role (#4081) 2025-05-14 21:44:22 +02:00
Taimoor ZaeemandWolfgang Walther 7269630538 test: add test when using .aud in jwt-role-claim-key 2025-05-14 21:44:20 +02:00
Laurence Isla cc2550a58b docs: fix link to SQL Query Logs 2025-05-09 20:59:31 -05:00
steve-chavez e20dc60e83 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:47:30 -05:00
Wolfgang Walther 89fb2878df chore: adjust changelog for db-extra-search-path
Came up in #4073
2025-05-09 14:57:24 +02:00
Wolfgang Walther ad66ae4e74 bump version to 13.0.0 2025-05-08 21:48:49 +02:00
Taimoor ZaeemandWolfgang Walther 657cabe757 fix: schema cache loads duplicate objects with different object type but same oid 2025-05-08 19:42:26 +00:00
Laurence Isla e0c5b3a314 correct: handle array values in JWT aud claim correctly 2025-05-07 21:54:32 +00:00
Laurence Isla b3bff90d68 correct: fail on invalid types of registered JWT claims (exp, nbf, iat, aud) 2025-05-07 21:54:32 +00:00
renovate[bot]andWolfgang Walther 066b136597 chore(deps): update ubuntu:noble docker digest to 6015f66 2025-05-07 16:24:23 +00:00
renovate[bot]andWolfgang Walther 324be09c2b chore(deps): update actions/download-artifact action to v4.3.0 2025-05-07 16:24:08 +00:00
Wolfgang Walther 497f3faca3 nix: keep forward compat with newer nixpkgs
This is useful for those who consume the repo via flake.
2025-05-06 10:49:16 +02:00
steve-chavez 98ca7c15d5 drop: Admin server config endpoint
BREAKING CHANGE

The endpoint was at risk of being left unprotected when exposing it.

The accompanying `admin-server-config-enabled` config was also dropped.
2025-05-04 13:53:50 -05:00
steve-chavez 7d04731be1 chore: add changelog for v12.2.12 2025-05-04 13:53:50 -05:00
steve-chavez b58253833b refactor: split preference parsing from userApiRequest
This allows obtaining the preferences header before doing the full parse
on userApiRequest. Which is needed by #3507.
2025-05-02 19:04:02 -05:00
Taimoor ZaeemandSteve Chavez bf79766a9b docs: add example to generate JWTs using openssl 2025-05-02 16:59:15 -05:00
Taimoor ZaeemandSteve Chavez f53147674e fix: filter on unselected columns in a table-valued function 2025-04-27 14:20:13 -05:00
Taimoor ZaeemandSteve Chavez cd5a611a1a refactor: change CallPlan returnings to a Set instead of a List 2025-04-26 10:02:30 -05:00
Laurence Isla 01432ce963 chore: update sponsors 2025-04-25 23:30:12 -05:00
Laurence IslaandSteve Chavez 57ef9988a5 feat: add Content-Length response header 2025-04-24 12:49:18 -05:00
Taimoor ZaeemandWolfgang Walther 98fcbedca5 chore: add changelog for v12.2.11 2025-04-23 07:34:19 +00:00
Taimoor ZaeemandSteve Chavez fdf902319d fix: regression with parameter charset=utf-8 in mediatype 2025-04-20 16:10:33 -05:00
steve-chavez 58237be608 test: add loadtest for async purge of JWT cache 2025-04-20 15:11:41 -05:00
renovate[bot]andWolfgang Walther 86be19e674 chore(deps): update haskell-actions/setup action to v2.7.11 2025-04-20 09:15:44 +00:00
renovate[bot]andWolfgang Walther a17a73e17b chore(deps): update codecov/codecov-action action to v5.4.2 2025-04-20 09:15:26 +00:00
renovate[bot]andWolfgang Walther cbc2bcfcff chore(deps): update ubuntu:noble docker digest to 1e622c5 2025-04-20 09:15:09 +00:00
steve-chavez c732591f37 chore: add changelog for 12.2.10 2025-04-18 21:30:22 -05:00
steve-chavez b740fcb1ff changelog: add missing entry jwt cache purge fix 2025-04-18 20:46:25 -05:00
Michal KleczekandGitHub 4d8502371d fix: purge JWT cache asynchronously in a separate thread
Otherwise performance was reduced unnecessarily.
2025-04-18 17:50:32 -05:00
steve-chavez 58b5dff188 Revert "nix: add loadtest with unique JWTs" 2025-04-18 17:43:10 -05:00
steve-chavez 51743016fd ci: github report for jwt loadtest 2025-04-18 13:05:14 -05:00
steve-chavez 9c3816218a ci: adjust upper bound of PATCH memory test 2025-04-17 23:11:33 -05:00
steve-chavez 608f7ca45a nix: add loadtest with unique JWTs
This loadtests the jwt decoding logic. For this it adds an optional
`-k`(kind) parameter to `postgrest-loadtest` and
`postgrest-loadtest-against`.

Old kind (default):

```
postgrest-loadtest -k mixed
postgrest-loadtest-against -k mixed
```

New kind:

```
postgrest-loadtest -k jwt
postgrest-loadtest-against -k jwt
```

Internally it uses a dynamically generated targets file using python
which looks like:

```
GET http://postgrest/authors_only
Authorization: Bearer <jwt>

GET http://postgrest/authors_only
Authorization: Bearer <another-jwt>
...
```

Then this is used to run vegeta with the `-lazy` option.
2025-04-17 23:11:33 -05:00
Wolfgang Walther a37ec1e1a5 chore: add changelog for 12.2.9 2025-04-16 20:41:04 +02:00
Taimoor ZaeemandGitHub bc5ec43300 fix: invalid JWTs after jwt-secret is changed in a config reload (#4015) 2025-04-16 09:40:36 -05:00
Taimoor ZaeemandGitHub feb5b7d494 fix: regression that replaces an unknown media type with */* (#4013) 2025-04-14 09:57:54 -05:00
Taimoor ZaeemandGitHub a1009d1bae refactor: separate SchemaCacheError from ApiRequestError (#4010) 2025-04-13 10:34:17 -05:00
Taimoor ZaeemandGitHub a6e81a5241 fix: parsing of the for parameter of plan media type (#4005) 2025-04-12 06:10:25 -05:00
Thilo HohltandGitHub 6b4648d2e4 docs: add archtika to example apps section on ecosystem page (#4007) 2025-04-10 14:25:31 -05:00
Taimoor ZaeemandGitHub 61a3c7b9e8 docs: add note that ordering of columns is not enforced (#3999) 2025-04-09 16:40:52 -05:00
Taimoor ZaeemandGitHub f7f87b42ca feat: add Proxy-Status header for better error response 2025-04-05 13:43:39 -05:00
renovate[bot]andWolfgang Walther 2811d6f997 chore(deps): update peter-evans/dockerhub-description action to v4.0.2 2025-04-03 12:09:22 +00:00
Taimoor ZaeemandSteve Chavez 2e3dc2d41e refactor: create error body with ErrorBody typeclass
The old error design didn't allow us to reuse error `code`,
`message` etc. With this refactor, these parts of the error body
can be reused for other potential features.

This also removes the `ErrorCode` type and replace the types
with Text codes.
2025-04-02 15:29:39 -05:00
steve-chavez d89e7a2173 docs: redirect from broken #bulk-insert-default 2025-04-02 13:05:12 -05:00
Taimoor ZaeemandSteve Chavez c7da7fab3a docs: mention that updates also supports specifying columns and missing pref 2025-04-02 12:59:18 -05:00
Taimoor ZaeemandSteve Chavez ddd7d98652 docs: explain missing preference header 2025-04-02 12:59:18 -05:00
renovate[bot]andWolfgang Walther 20f1fdd35c chore(deps): update peter-evans/dockerhub-description action to v4.0.1 2025-04-01 19:50:34 +00:00
Wolfgang Walther 95e36fdad9 nix: avoid rebuilding memory tests when entering nix-shell
The memory tests are now run in the same way as the regular tests.
2025-03-30 18:57:39 +00:00
Wolfgang Walther 001835eddc nix: reduce number of rebuilds for local development slightly 2025-03-30 18:57:39 +00:00
Taimoor ZaeemandSteve Chavez 3c0baecec5 refactor: add pg error and custom error to ErrorCode
Our current ErrorCode type wasn't giving us a full picture
of how many different types of errors we are handling. This
PR makes this explicit by including the error code type for
all types of errors.
2025-03-28 11:27:59 -05:00
Wolfgang Walther 1b57774bdf nix: make nix expressions forward-compatible with newer nixpkgs
When consuming PostgREST via flake, nixpkgs can be pinned to a newer
version, to which we might not be compatible, yet.
2025-03-28 09:22:34 +00:00
Wolfgang Walther 149be6bc33 nix: expose nixpkgs input on flake
This also moves the pin for nixpkgs into flake.lock instead of our
custom file. Even for the classic interface via default.nix, the pin
will be loaded from flake.lock, thus everything stays in-sync.
2025-03-28 09:22:34 +00:00
Wolfgang Walther 144b0c46ca nix: add basic flake.nix
This just exposes the PostgREST package, not more.

The goal is to avoid duplication, so we're re-using only exports from
default.nix.

Resolves #3026
Supersedes #3105
2025-03-28 09:22:34 +00:00
Wolfgang Walther 139acb4251 chore: add .editorconfig file 2025-03-28 09:22:34 +00:00
renovate[bot]andWolfgang Walther fc01a72f4e chore(deps): update cachix/cachix-action action to v16 2025-03-26 18:02:59 +00:00
Taimoor ZaeemandSteve Chavez f91f47ff57 docs: mention log-level setting in the logs section 2025-03-26 11:25:57 -05:00
Wolfgang Walther aeb246b673 docs: Remove broken link 2025-03-26 17:00:11 +01:00
renovate[bot]andWolfgang Walther 02590f2e55 chore(deps): update docker/setup-buildx-action action to v3.10.0 2025-03-25 18:55:39 +00:00
renovate[bot]andWolfgang Walther ab2d9945fa chore(deps): update docker/login-action action to v3.4.0 2025-03-25 18:20:14 +00:00
renovate[bot]andWolfgang Walther 67573f4f10 chore(deps): update codecov/codecov-action action to v5.4.0 2025-03-25 17:50:47 +00:00
renovate[bot]andWolfgang Walther d284e9acea chore(deps): update actions/download-artifact action to v4.2.1 2025-03-24 16:27:45 +00:00
renovate[bot]andWolfgang Walther 62150aaf53 chore(deps): update nixbuild/nix-quick-install-action action to v30 2025-03-24 16:24:24 +00:00
renovate[bot]andWolfgang Walther 48f4b6d77d chore(deps): update haskell-actions/setup action to v2.7.10 2025-03-24 16:13:17 +00:00
Laurence IslaandGitHub 0b618d0bef feat: allow spreading one-to-many and many-to-many embedded resources
* Note: Aggregates are not implemented
2025-03-24 14:45:56 +00:00
renovate[bot]andWolfgang Walther 09ba7c0d28 chore(deps): update actions/upload-artifact action to v4.6.2 2025-03-24 11:36:06 +00:00
renovate[bot]andWolfgang Walther 1887c9b5b2 chore(deps): update actions/cache action to v4.2.3 2025-03-24 08:34:34 +00:00
Wolfgang Walther 2b91df8004 nix: Disable building profiled or dynamic libraries by default
We never need dynamic haskell libraries, because even the dynamic builds
only dynamically link non-haskell dependencies, but always link haskell
dependencies statically.

Profiled libraries are only required when running the memory test, so
explicitly enable them for the profiled package.

This also means, that we don't need to hide the memory test behind a
feature flag anymore. The reason always was assumed to be the big number
of rebuilds required for it. I assume ever since we moved off of
static-haskell-nix and back to nixpkgs-based builds, we have been
building profiled libraries for all our dependencies anway.
2025-03-22 19:37:03 +00:00
Wolfgang Walther 57d11c7914 chore: Update nix/README's command list
We had added the release tools by default a while ago.. and by now have
many more tools available.
2025-03-22 19:37:03 +00:00
Taimoor ZaeemandGitHub fdc26d52fc fix: empty error messages for disabled openapi and /invalid/nested/paths 2025-03-21 11:51:40 -05:00
Taimoor ZaeemandSteve Chavez a1c0a8ce6d docs: add missing max-affected violation error 2025-03-21 08:40:52 -05:00
Taimoor ZaeemandSteve Chavez fc35d6d0f8 fix: Fix ordering with mutation queries 2025-03-17 14:13:34 +01:00
Wolfgang Walther 5ff51de36f docs: remove broken link 2025-03-14 23:21:26 +01:00
Taimoor ZaeemandSteve Chavez dd29e74150 test: fix config value in io test 2025-03-13 10:19:29 +01:00
Taimoor ZaeemandSteve Chavez e3041fc4a0 test: correct jwt parse time test 2025-03-13 10:19:29 +01:00
Taimoor ZaeemandSteve Chavez 36b6a2c86b fix: improve jwt errors 2025-03-13 00:20:54 +01:00
Taimoor ZaeemandSteve Chavez 4819520e3a refactor: decouple module SchemaCache and ApiRequest 2025-03-10 05:21:51 +01:00
Wolfgang Walther 359e5fbf75 ci: Add MacOS x86-64 binaries to release
The supported architectures for each GitHub Actions runner image can be
seen here:
https://github.com/actions/runner-images?tab=readme-ov-file#available-images

Resolves #3937
2025-03-09 13:39:33 +00:00
Taimoor ZaeemandSteve Chavez 53ca035e9b test: rename module NoJwtSpec.hs -> NoJwtSecretSpec.hs 2025-03-06 10:30:02 -05:00
steve-chavez 4348cb2057 docs: fix AST keyword missing from dict 2025-03-05 18:39:23 -05:00
steve-chavez 3af3371e1e docs: add note about Plan in architecture page
Also add links to the ApiRequest, Plan and Query components in the
diagram.
2025-03-05 18:37:10 -05:00
Taimoor ZaeemandSteve Chavez 4ddf33df76 refactor: group jwt errors 2025-03-04 16:54:42 -05:00
Taimoor ZaeemandGitHub c9a625ced6 feat: Log PoolRequest and PoolRequestFullfilled observations (#3925) 2025-02-28 12:01:10 -05:00
Wolfgang Walther 1a287edf7e chore: Ignore two links for linkcheck
I removed those exceptions earlier this week, because I got fooled by my
local test output. Those only return 403 in GitHub Actions - it seems
like those websites block access from there.
2025-02-26 20:53:58 +01:00
renovate[bot]andWolfgang Walther 8d1bd61e69 chore(deps): update ubuntu:noble docker digest to 7229784 2025-02-26 17:49:50 +01:00
Wolfgang Walther 6442afb1f2 chore: Fix style check 2025-02-22 17:00:54 +01:00
Wolfgang Walther 5d445a70d3 docs: Fix outdated links 2025-02-22 16:10:44 +01:00
Wolfgang Walther 9def1664bb ci: Fix cirrus FreeBSD builds
Apparently Cirrus removed the 14-1 image. When I firsted looked into
this some days ago, when the job started failing, the docs were not
updated, yet - so it wasn't clear. Now the docs mention freebsd-14-2
explicitly...
2025-02-22 14:22:15 +01:00
Taimoor ZaeemandGitHub 390ba19932 fix: handle queries on non-existing table gracefully 2025-02-21 13:49:54 -05:00
Laurence IslaandGitHub 9c880c082a feat: allow logging the SQL query to stderr
- Logs the main SQL query when `log-query=main-query`.
- Only logs at the current `log-level`.
2025-02-18 19:17:26 -05:00
Taimoor ZaeemandSteve Chavez 66e966d864 refactor: move jwt caching logic to Auth/JwtCache.hs 2025-02-17 14:19:40 -05:00
Laurence Isla 5619a5279b refactor: move the logic to check if the response should be logged into a separate function 2025-02-14 19:52:59 -05:00
Laurence Isla 8157e6ee0b refactor: remove IO from the Query.hs module
Will make logging SQL queries to stderr possible
2025-02-14 19:52:59 -05:00
Laurence Isla 7be5782179 docs: make the aggregate functions docs less verbose 2025-02-14 18:14:43 -05:00
Taimoor ZaeemandSteve Chavez e04cd70d83 refactor: move ApiRequestError to Error module 2025-02-13 09:38:18 -05:00
steve-chavez 33b69b5894 docs: reduce verbosity of aggregate functions 2025-02-12 20:12:38 -05:00
Taimoor ZaeemandGitHub 560c511f81 docs: add missing jwt claims and clock skew (#3908) 2025-02-12 15:38:20 -05:00
Steve ChavezandGitHub 307692c325 break: remove limited updated/delete feature (#3907)
BREAKING CHANGE

As agreed on https://github.com/PostgREST/postgrest/issues/3013#issuecomment-1770186262,
this removes the limited update/delete feature.

The feature was complicated, largely unused and caused other bugs in
mutations.

It was added in #2195 and #2211.
2025-02-12 14:48:08 -05:00
steve-chavez 94f0edb61a docs: correct package for installation under Nix 2025-02-12 14:41:21 -05:00
M. Taimoor ZaeemandWolfgang Walther e4f3c2cf3b changelog: Add v12.2.8 2025-02-11 21:27:53 +01:00
M. Taimoor ZaeemandSteve Chavez c96dc3ee90 fix: log 503 client error to stderr 2025-02-08 21:08:29 -05:00
M. Taimoor ZaeemandSteve Chavez 3f78615dff refactor: move AuthResult to Auth/Types.hs module
The `AuthResult` type does not belong to AppState
module. This commit refactor this by moving it to
a new module `Auth/Types.hs`.
2025-02-04 11:56:42 -05:00
Wolfgang Walther db85e64971 changelog: Add v12.2.7 2025-02-03 18:40:45 +01:00
Diogo BiazusandGitHub b285f5fba6 fix: Fix regression for schema cache reloading via NOTIFY on Windows
Upstream accidentally removed the fix, which was introduced for #2524. Fixed again.
2025-02-03 15:40:37 +01:00
M. Taimoor ZaeemandWolfgang Walther f4889160a0 changelog: Add v12.2.4, v12.2.5 and v12.2.6 2025-01-31 20:33:44 +01:00
Wolfgang Walther 749e2996f3 chore: Add new issue type to issue templates 2025-01-31 19:25:16 +01:00
Taimoor ZaeemandGitHub 71a147392a fix: jwt cache is not purged (#3801) 2025-01-29 14:53:10 -05:00
Laurence Isla b7d0a1f68c feat: apply to_tsvector() explicitly to the full-text search filtered column, only if it's not of tsvector type 2025-01-28 19:14:54 -05:00
renovate[bot]andWolfgang Walther e7cc8fedc0 chore(deps): update codecov/codecov-action action to v5.3.1 2025-01-25 12:01:13 +01:00
Wolfgang Walther 66a9422498 chore: Remove unused haskell dependencies
Resolves #3873
2025-01-25 12:00:57 +01:00
renovate[bot]andWolfgang Walther a2b5af0861 chore(deps): update codecov/codecov-action action to v5.3.0 2025-01-25 11:12:54 +01:00
Wolfgang Walther e2dd4354d5 fix: Make postgrest binary in arm64 docker image executable
This happened in 06aebfaa and caused the arm64 docker image to not start
up properly.

Resolves #3867
2025-01-20 18:23:19 +01:00
Wolfgang Walther 9ae8854867 Revert "ci: Remove brew install libpq for macos-14 stack build"
This partially reverts commit 53164453d8.
2025-01-18 19:01:01 +01:00
Wolfgang Walther 4ad78235dc chore: Update renovate config for new haskell-cabal manager
This manager was recently introduced to renovate and is now creating PRs
for upper version bounds of our haskell dependencies. We still need to
figure out how to deal with those in the best way, but some basic
configuration can already be done. Here, we:
- disallow any of those updates on the backbranches.
- group GHC-provided dependencies together.
- group packages from the hasql ecosystem together.
- the fuzzyset dependency must be restricted to <0.3 - we know that
already and did that on purpose.
2025-01-18 18:21:26 +01:00
Wolfgang Walther 14449bc882 ci: Fix stack cache on Windows
Apparently the STACK_ROOT has been moved to C:\sr - for unknown reasons,
at least to me.

This should enable caching again and make the stack on windows builds
much faster than recently.
2025-01-18 18:01:35 +01:00
Wolfgang Walther 5c567600cd ci: Split ci into ci and release workflows
This is now possible, after we moved to the ARM build to the GitHub
runners.
2025-01-18 18:01:35 +01:00
Wolfgang Walther 75788cff05 ci: Remove left-over permissions setting from tag job
This has been replaced by using the SSH key.
2025-01-18 18:01:35 +01:00
Wolfgang Walther 9a86ff6029 ci: Display loadtest results in step summary
Much easier to implement and should be easier to find, too.
2025-01-18 18:01:35 +01:00
Wolfgang Walther 06aebfaaaf ci: Build the ubuntu-aarch64 binary with new ARM runners
The new GitHub arm runners are available, so we can use them to build
the ubuntu aarch64 binary instead of our custom machine.
2025-01-18 18:01:35 +01:00
Wolfgang Walther 6858709866 ci: Skip cachix push when no cachix token is set
This happens in forks.
2025-01-18 18:01:35 +01:00
Wolfgang Walther 53164453d8 ci: Remove brew install libpq for macos-14 stack build
When macos-14 was rolled out libpq was not installed, but by now it is
by default. Thus, we don't need to do that, it only creates a warning
annotation right now.
2025-01-18 18:01:35 +01:00
Wolfgang Walther ee6bac4e49 ci: Fix release name of x86-64 binaries
This should have been x86-64, only x64 is not a thing.
2025-01-18 18:01:35 +01:00
Wolfgang Walther cbe7d8e1dd ci: Fix release name of macos binary
This is built on macos-14, which is running on new arm based hardware,
not the old x86_64 ones.
2025-01-18 18:01:35 +01:00
Wolfgang Walther 48a9a3540e ci: Update stack builder to ubuntu 24.04
Renovate doesn't seem to pick this up, because it's in a matrix
specification.
2025-01-18 18:01:35 +01:00
renovate[bot]andWolfgang Walther 972bc80664 chore(deps): update actions/upload-artifact action to v4.6.0 2025-01-17 20:59:10 +01:00
renovate[bot]andWolfgang Walther c7ac1db07f chore(deps): update haskell-actions/setup action to v2.7.9 2025-01-17 20:58:06 +01:00
renovate[bot]andWolfgang Walther ce27425f7c chore(deps): update haskell-actions/setup action to v2.7.8 2024-12-30 16:32:00 +01:00
M. Taimoor ZaeemandSteve Chavez 56c14474da fix: insert with missing=default uses column default before using domain default 2024-12-23 15:27:40 -05:00
Wolfgang Walther 0d640442b1 nix: Change postgrest-nixpkgs-upgrade to unstable
Since we're currently on the unstable channel and will likely stay there
for a while, let's encode this in the update script.

Once we switch back to stable, if we do, we can still adjust it again.
2024-12-22 19:07:11 +01:00
Wolfgang Walther 07d6d75abe chore: remove deprecation warning in IO tests 2024-12-22 18:49:20 +01:00
renovate[bot]andWolfgang Walther f5f64ac7da chore(deps): update codecov/codecov-action action to v5.1.2 2024-12-20 20:00:22 +01:00
renovate[bot]andWolfgang Walther b5645b969a chore(deps): update haskell-actions/setup action to v2.7.7 2024-12-20 19:59:55 +01:00
M. Taimoor ZaeemandSteve Chavez a9d74eba2a feat: allow not_null value for the is operator 2024-12-19 10:19:41 -05:00
renovate[bot]andWolfgang Walther a1769d17be chore(deps): update actions/upload-artifact action to v4.5.0 2024-12-18 12:56:17 +01:00
kjcsb1andGitHub 3e1a904785 docs: Add example of comment on view 2024-12-12 20:54:12 +01:00
M. Taimoor ZaeemandSteve Chavez af6b79d4d7 feat: support string comparison for jwt-role-claim-key 2024-12-12 08:47:06 -05:00
renovate[bot]andWolfgang Walther 2df167637d chore(deps): update codecov/codecov-action action to v5.1.1 2024-12-06 09:48:06 +01:00
renovate[bot]andWolfgang Walther 82f43a567c chore(deps): update actions/cache action to v4.2.0 2024-12-06 09:47:55 +01:00
renovate[bot]andWolfgang Walther 366d6321f0 chore(deps): update ubuntu:noble docker digest to 80dd3c3 2024-12-04 08:45:07 +01:00
Christophe EymardandGitHub c5a9455959 docs: Add an example for PGRST_APP_SETTINGS_* (#3804) 2024-12-01 14:41:39 -05:00
renovate[bot]andWolfgang Walther d78877cc65 chore(deps): update codecov/codecov-action action to v5.0.7 2024-11-21 21:26:09 +01:00
renovate[bot]andWolfgang Walther b85e28c007 chore(deps): update codecov/codecov-action action to v5.0.5 2024-11-20 19:36:35 +01:00
Steve ChavezandGitHub 6db245aacd fix: clarify PGRST116 error message (#3795)
Currently it's redundant and not easy to read.

```
{"message":"JSON object requested, multiple (or no) rows returned",
"details":"The result contains 2 rows"}
```

Now:

```
{"message":"Cannot coerce the result to a single JSON object",
"details":"The result contains an array of 0 objects"}
``

Also correct docs which had a wrong error code.
2024-11-20 12:15:46 -05:00
renovate[bot]andWolfgang Walther e929834f82 chore(deps): update ubuntu:noble docker digest to 278628f 2024-11-16 22:40:48 +01:00
steve-chavez 80a4edbd2d chore: add comments on the Observation module 2024-11-15 16:11:26 -05:00
steve-chavez 2766b844a9 fix: always show schema cache load time
It used to be that this was only enabled with log-level=debug.
But the default log-level is misleading, for example:

```
$ PGRST_DB_SCHEMAS="apflora" postgrest-with-postgresql-16  -f test/io/big_schema.sql postgrest-run

...
13/Nov/2024:22:08:20 -0500: Config reloaded
13/Nov/2024:22:08:20 -0500: Schema cache queried in 36.3 milliseconds
13/Nov/2024:22:08:20 -0500: Schema cache loaded 326 Relations, 305 Relationships, 7 Functions, 0 Domain Representations, 4 Media Type Handlers, 1194 Timezones
```

The "Schema cache loaded" can take a while to appear, yet the 22:08:20
time is the same. If we reveal the load time this is clarified:

```
13/Nov/2024:22:08:37 -0500: Schema cache loaded in 16770.1 milliseconds
```
2024-11-15 16:11:26 -05:00
steve-chavez dca09c84b9 nix: add exp support for postgrest-gen-jwt 2024-11-15 14:41:02 -05:00
renovate[bot]andWolfgang Walther 4d3883ea2e chore(deps): update codecov/codecov-action action to v5.0.2 2024-11-15 18:54:17 +01:00
Laurence Isla 9c863dbddc test: add tests for bulk upserts with surrogate keys 2024-11-15 12:05:14 -05:00
Laurence Isla fcf828fd92 docs: clarify usage of upsert with surrogate primary keys 2024-11-15 12:05:14 -05:00
renovate[bot]andWolfgang Walther 313f52d3fa chore(deps): update codecov/codecov-action action to v5 2024-11-14 20:57:31 +01:00
renovate[bot]andWolfgang Walther f3aa00a838 chore(deps): update dependency ubuntu to v24 2024-11-13 14:41:23 +01:00
Wolfgang WaltherandWolfgang Walther 3c95d24d45 nix: update package list from hackage before building
This prevents errors in CI after updating the hackage index-state.
2024-11-12 21:13:31 +01:00
Wolfgang WaltherandWolfgang Walther 09adb44cc8 chore(deps): update readthedocs os to ubuntu-24.04 2024-11-12 21:13:31 +01:00
Wolfgang WaltherandWolfgang Walther 4c61749de9 chore(deps): update stackage snapshot to LTS 22.41 2024-11-12 21:13:31 +01:00
Wolfgang WaltherandWolfgang Walther 6f0c180b6b chore(deps): update GHC for cabal builds 2024-11-12 21:13:31 +01:00
Wolfgang WaltherandWolfgang Walther 04a14d5941 nix: remove pkgsCross workaround for libpq
This will make it much easier to actually cross-compile the static
executable to different systems.
2024-11-12 21:13:31 +01:00
Wolfgang WaltherandWolfgang Walther 48aabeb473 nix: add postgrest-with-postgresql-17
PostgreSQL 17 has been released:
https://www.postgresql.org/about/news/postgresql-17-released-2936/

Let's make sure CI runs with it, too.
2024-11-12 21:13:31 +01:00
Wolfgang WaltherandWolfgang Walther a023bd5742 nix: keep readthedocs dependencies in-sync with nix
This is to make sure that we will always have the same development
environment for the docs build as is used live on the website.
2024-11-12 21:13:31 +01:00
Wolfgang WaltherandWolfgang Walther 6c46f7dba5 chore(deps): update nixpkgs to unstable 2024-11-09 2024-11-12 21:13:31 +01:00
renovate[bot]andWolfgang Walther b83899340e chore(deps): update dependency macos to v14 2024-11-06 09:43:41 +01:00
Wolfgang Walther 5be2327797 chore: Lift restriction for macos CI image
After updating to nix-quick-install-action v29 this should be possible
to do now.
2024-11-05 22:09:57 +01:00
renovate[bot]andWolfgang Walther 5f7a2cda15 chore(deps): update nixbuild/nix-quick-install-action action to v29 2024-11-05 22:07:51 +01:00
steve-chavez 2564b323d7 chore: disallow github blank issue and cleanup 2024-11-05 13:04:32 -05:00
steve-chavez b821857861 changelog: drop Removed heading and use Changed 2024-11-05 13:04:32 -05:00
Joel JakobssonandGitHub 180a96ce48 remove support for Prefer: params=single-object (#3757)
BREAKING CHANGE

Using this preference was deprecated in 6c3d7a9, in favor of Functions with an array of JSON objects.
2024-11-04 20:19:08 -05:00
Wolfgang Walther da0f48ea92 Revert "docs: fix deprecation of analytics in RTD"
This reverts commit 4874428a17.

We'll stick with RTD-builtin-analytics for now.
2024-10-29 20:31:23 +01:00
Steve Chavez afa63f891e chore: update github issue templates
Adds a feature request template.
2024-10-29 10:31:38 -05:00
Laurence IslaandSteve Chavez 4874428a17 docs: fix deprecation of analytics in RTD 2024-10-28 22:10:17 -05:00
jinjiaduandWolfgang Walther 765696dfd0 chore: fix some typos in comments 2024-10-28 11:32:10 +01:00
Wolfgang WaltherandWolfgang Walther 0b0b4f2a79 ci: Update cirrus' freebsd image to 14.1
This should fix CI which is failing lately like this:
https://cirrus-ci.com/task/4665005218463744

ld-elf.so.1: /lib/libc.so.7: version FBSD_1.8 required by
/usr/local/bin/stack not found
2024-10-26 14:51:13 +02:00
renovate[bot]andWolfgang Walther 994b60a187 chore(deps): update actions/cache action to v4.1.2 2024-10-24 05:15:43 +02:00
renovate[bot]andWolfgang Walther 64f7f1451a chore(deps): update actions/upload-artifact action to v4.4.3 2024-10-24 05:15:06 +02:00
renovate[bot]andWolfgang Walther 204ae996a3 chore(deps): update actions/checkout action to v4.2.2 2024-10-24 05:09:39 +02:00
renovate[bot]andWolfgang Walther 719cadf14b chore(deps): update codecov/codecov-action action to v4.6.0 2024-10-24 05:06:21 +02:00
renovate[bot]andWolfgang Walther addbe5b7e2 chore(deps): update ubuntu:noble docker digest to 99c3519 2024-10-24 05:04:28 +02:00
steve-chavez bee862c2fa docs: inline one-to-one relationship SQL
More direct than having to jump to the sample film database definition.
2024-10-21 14:45:53 -05:00
Dan KurinandSteve Chavez 5ca969f4b8 docs: add PGRST123 to error table 2024-10-17 19:21:07 -05:00
steve-chavez 28ebe37e07 docs: example for server-host 2024-10-07 17:14:43 -05:00
Wolfgang Walther db5cbab3d5 docs: Remove broken link
https://github.com/PostgREST/postgrest/actions/runs/11136795565/job/30949162312
2024-10-04 16:02:08 +02:00
steve-chavez 7e99babec7 feat: log pool maximum size
It's important for observability to have an historic trace of the pool
size. Currently we expose it on the metrics endpoint, but not all
deployments use it.

This logs the pool size after the successful connection log to make it
more visible:

<timestamp>: Connection Pool initialized with a maximum size of 4 connections
2024-10-02 22:47:22 -05:00
steve-chavez 87dddd66d2 fix: clarify "listening" logs
It's not immediately clear on which port the API server is listening.
Also it's not clear that the "pgrst" channel is for database
notifications.

Goes from:

<timestamp>: Admin server listening on 0.0.0.0:3001
<timestamp>: Listening on 0.0.0.0:3000
<timestamp>: Listening for notifications on the "pgrst" channel

To:

<timestamp>: Admin server listening on 0.0.0.0:3001
<timestamp>: API server listening on 0.0.0.0:3000
<timestamp>: Listening for database notifications on the "pgrst" channel
2024-10-02 22:47:22 -05:00
renovate[bot]andWolfgang Walther bfbd033c6e chore(deps): update ubuntu:noble docker digest to dfc1087 2024-09-18 20:01:51 +02:00
renovate[bot]andWolfgang Walther a064d0df94 chore(deps): update dependency urllib3 to v2.2.3 2024-09-12 21:00:50 +02:00
Andrei DziahelandWolfgang Walther c2513c8861 ci: drop directories from windows release
Puts windows release in line with others which have the executable on the top level
2024-09-11 19:22:37 +02:00
renovate[bot]andWolfgang Walther 678103bbfa chore(deps): update actions/upload-artifact action to v4.4.0 2024-09-04 13:29:49 +02:00
Jason Closeandsteve-chavez f21053dbee docs: rpc example for array of json objects
This change adds an explanation of how to handle an array of JSON objects within an RPC call.  To pass multiple objects, an array of JSON objects must be the JSON value, with the key being the json or jsonb variable name of the Postgres function.

For people who want to perform multiple tasks/inserts/updates within a single API call, this is a needed explanation for that use-case.
2024-08-23 13:01:43 -05:00
Laurence Isla ded2e997e9 fix: spread embeds failing when using the "count()" aggregate without a field - @laurenceisla
- Fixed "column reference <col> is ambiguous" error when selecting "?select=...table(col,count())"
- Fixed "column <json_aggregate>.<alias> does not exist" error when selecting "?select=...table(aias:count())"
2024-08-21 16:56:32 -05:00
Laurence Isla 2302f78539 refactor: simplify functions in the "hoist from selected fields" process 2024-08-21 16:56:32 -05:00
Laurence Isla e9244f1a4f fix: a nested spread embedding now correctly groups by the fields of its top parent relationship 2024-08-21 16:56:32 -05:00
Laurence Isla 3539aaff89 fix: prevent spread embed to use aggregates when disabled 2024-08-21 16:56:32 -05:00
renovate[bot]andWolfgang Walther 9a079607dd chore(deps): update haskell-actions/setup action to v2.7.6 2024-08-18 14:04:19 +02:00
renovate[bot]andWolfgang Walther 07febf41cc chore(deps): update ubuntu:noble docker digest to 8a37d68 2024-08-18 14:04:05 +02:00
renovate[bot]andLaurence Isla a9ba148373 chore(deps): update actions/upload-artifact action to v4.3.6 2024-08-13 13:25:55 -05:00
renovate[bot]andWolfgang Walther 6c7963c1c4 chore(deps): update actions/upload-artifact action to v4.3.5 2024-08-02 21:07:32 +02:00
closeobserveandWolfgang Walther 6b11332d6d chore: fix some comments 2024-08-02 09:01:15 +02:00
steve-chavez cccf8b750d docs: rename to hoisted function settings 2024-08-01 19:17:56 -05:00
Wolfgang Walther 7af8f8175a changelog: Add 12.2.3 2024-08-01 18:56:36 +02:00
Andrei DziahelandGitHub 46537879ae feat: Add resolved host to "Listening on ..." messages (#3560)
This adds resolved host's IP to "Listening on ..." messages emitted when
app and admin servers start.
2024-08-01 11:31:35 -05:00
Laurence Isla 48edab24c6 changelog: add missing entry for 3670 2024-08-01 11:17:01 -05:00
7c74f6cf0a fix: schema cache loading before the in-db config (#3670)
Fixes #3660. Load the config after getting the pg version but before loading the schema.

The regression happened on f09655b.

Also remove schema cache load wrapper and separate db queries in different functions.

Co-authored-by: Laurence Isla <lau.isla.c@gmail.com>
2024-08-01 10:37:48 -05:00
Dan KurinandGitHub b261abd5f5 fix: Remove OpenAPI format for rowFilter params (#3661) 2024-07-16 11:13:47 -05:00
Wolfgang WaltherandWolfgang Walther d7da18147b refactor: Simplify pks_uniques_cols 2024-07-13 22:26:36 +02:00
Wolfgang WaltherandWolfgang Walther 50bdb6a3de fix: Embed One-to-One relationship with different column order properly 2024-07-13 22:26:36 +02:00
Wolfgang Walther 9d9233b061 chore: Adjust changelog after v12.2.2 release 2024-07-13 17:17:00 +02:00
steve-chavez ce7ef3b188 chore: remove links to gitter
We'll now use github discussions for support.
2024-07-12 14:30:28 -05:00
Salim BandWolfgang Walther 1452720be6 fix: update OpenAPI externalDocs URL
fixes https://github.com/PostgREST/postgrest/issues/3091
2024-07-11 15:07:14 +02:00
steve-chavez 6be59066df fix: schema cache retrying without backoff
Fixes https://github.com/PostgREST/postgrest/issues/3523.

Now if there's a failure when obtaining the pg version OR schema cache,
we do the same retrying process. This way we don't add two retries.

Refactors and renames the "connectionWorker" to "schemaCacheLoader".
This makes more sense since what we really want is the schema cache,
the version is the pre-requisite for ensuring our
schema cache queries work.

Additionally, we no longer log ` Attempting to connect to the database...`
at startup unnecessarily. This is only logged whenever there's a retry attempt.
2024-07-10 21:14:24 -05:00
Wolfgang Walther 03111cedbf refactor: Fix typo in QueryBuilder
Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2024-07-10 22:16:17 +02:00
Wolfgang Walther 3e7c130a0d test: Reorganize upsert tests matching contexts
Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2024-07-10 21:22:28 +02:00
Wolfgang WaltherandWolfgang Walther b135d9b438 test: Raise limit for memory tests 2024-07-09 18:35:29 +02:00
Wolfgang Walther 889a3450c2 chore: Remove left-over CONTRIBUTING.md from docs repo 2024-07-09 10:16:17 +02:00
Wolfgang WaltherandWolfgang Walther b598b594df refactor: Simplify schemaDescription query 2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 86c3257f54 feat: Fail schema cache lookup with invalid db-schemas config
Previously, we'd silently report "200 OK" on the root endpoint, but
would never return any endpoints from the schema cache.

Now the schema cache query fails because of the ::regnamespace cast.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther f31848f2e5 refactor: Simplify funcsSqlQuery
This allows to re-use ANY($$1) in the next commit.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 735e1edbf6 refactor: Simplify columns_agg 2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 01a18d8199 fix: List correct enum options when multiple types with same name are present
The schema cache and OpenAPI output would currently list the first found
enum with the same name instead of the correct type. One other case
where this comes up is when a regular type and an enum type have the
same name. For example in the spec fixtures, we have an enum called
"bit". Every "bit" type, no matter whether it's that enum or the
built-in bit type, will show those enum options in the OpenApi output.

Not adding a test, because OpenAPI is supposed to go away in the future
anyway.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 1747a4fcc4 refactor: Replace pg_namespace joins with ::regnamespace in schema cache
Less joins are much easier to read and understand.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 5ea83de7ec refactor: Simplify tbl_pk_cols query 2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 3daeec4e76 refactor: Make schema cache dumps more predictable with consistent ORDER
This helps diffing schema cache changes during development.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 0e2f78d9f2 refactor: Use ::regnamespace casts instead of comparing schemas by name
Casting pg_catalog to regnamespace is slightly more efficient, because
the comparison will be oid-based, not text-based.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther baae4d715f refactor: Remove redundant conditions in schema cache
Those conditions are covered by the respective nspname = ANY branches.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 6581663da9 refactor: Remove useless DISTINCT
There is already a GROUP BY in the same SELECT.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther dfb0be9354 refactor: Remove unused columns from schema cache queries 2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 7e8e9a9529 refactor: Fix some spelling mistakes in comments and whitespace 2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 0335b465d7 fix: Show number of loaded timezones in log output
There is no reason to hide those, right?
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther 957472a7a7 fix: Make --dump-schema work with in-database pgrst.db_schemas setting
This needs to be loaded from in-database configuration first, otherwise
the dump-schema output will be for the default (public) schema.
2024-07-09 08:31:31 +02:00
Wolfgang WaltherandWolfgang Walther ee4bfbf253 perf: Pass arguments to RPCs called via GET directly
Previously they were passed as a JSON payload. This results in a LATERAL
join for the calling expression, which prevents LIMIT from being pushed
into the inlined function call, making some requests really slow.

Resolves #2858
2024-07-09 08:29:13 +02:00
steve-chavez 0dc1345eb4 chore: remove paypal links
It was tied to a personal account and donations there have been too rare.
2024-07-08 10:19:30 -05:00
Wolfgang WaltherandWolfgang Walther a132a4fe2c chore(deps): update nixpkgs 2024-07-07 11:05:10 +02:00
Wolfgang WaltherandWolfgang Walther 64a6cf8cb8 nix: Store branch reference in nixpkgs-version.nix
This makes it clearer which nixpkgs release we are currently on.
2024-07-07 11:05:10 +02:00
renovate[bot]andWolfgang Walther d9e6d3c7e2 chore(deps): update actions/checkout action to v4 2024-07-06 11:38:24 +02:00
renovate[bot]andWolfgang Walther 4b31205395 chore(deps): update haskell-actions/setup action to v2.7.5 2024-07-06 11:36:12 +02:00
renovate[bot]andWolfgang Walther ced8665076 chore(deps): update actions/download-artifact action to v4.1.8 2024-07-06 11:35:29 +02:00
renovate[bot]andWolfgang Walther 7f8f76c0dd chore(deps): update actions/upload-artifact action to v4.3.4 2024-07-06 11:35:21 +02:00
Laurence Isla c3070bbd4e fix: nested empty embeds no longer return empty values and are correctly omitted 2024-07-04 14:21:47 -05:00
Laurence Isla e0baf7e78e feat: log error message when JWT secret is less than 32 characters long
breaking change: PostgREST now fails to start or reload the config when the JWT secret is less than 32 characters long.
2024-07-04 12:06:24 -05:00
Laurence Isla d9385a4523 changelog: update to 12.2.1 2024-07-03 18:57:19 -05:00
Andrei DziahelandGitHub 06cbc4be36 config forbid same server-port and admin-server-port (#3559)
* fix: forbid same server-port and admin-server-port

Forbids server-port and admin-server-port from being equal altogether,
despite they might not conflict at all in case admin and app are bound
to different addresses. Implemented as per the discussion at
https://github.com/PostgREST/postgrest/issues/3508#issuecomment-2125123633
2024-07-03 13:02:02 -05:00
Laurence Isla b9004baa3f docs: add missing "curl --get" on embedding example 2024-07-02 15:20:54 -05:00
Sandro BauerandGitHub 2fd5a00269 docs: fix rendering for inline code block in operator list 2024-07-02 12:27:58 +02:00
renovate[bot]andWolfgang Walther 0d91266309 chore(deps): update actions/checkout action to v3.4.0 2024-06-29 10:22:56 +02:00
Laurence Isla 40ed349bba changelog: add missing entries for #3592 and #3616 2024-06-26 19:46:36 -05:00
Laurence Isla d458114f33 nix: remove texlive dependencies from postgrest-docs-render 2024-06-26 11:33:04 -05:00
Laurence Isla 295b00f360 docs: use PlantUML instead of Latex to generate Schema Isolation image 2024-06-26 11:33:04 -05:00
Laurence Isla 5acb29ce94 chore: organize diagrams in different folders 2024-06-26 11:33:04 -05:00
steve-chavez ecf9d56c91 docs: add listener recovery 2024-06-25 20:03:22 -05:00
steve-chavez f912c0dd29 fix: don't reload cache on every listener fail
Revert "prevent GSSAPI error between Listener and pool"

This reverts commit 4beac10d3d.
2024-06-25 20:03:22 -05:00
Andrei DziahelandGitHub 9d7e87b3e0 feat: add the "admin-server-host" config to set the host for the admin server 2024-06-24 14:47:19 -05:00
renovate[bot]andWolfgang Walther 4761fad956 chore(deps): update ubuntu:noble docker digest to 2e863c4 2024-06-19 19:22:38 +02:00
Wolfgang Walther fd6cd037ec docs: Fix linkcheck
Some URLs are still forbidden for our linkcheck tool, so disabling them
again.

Others are permanently redirected, so adjusting them.
2024-06-19 08:40:15 +02:00
Wolfgang WaltherandWolfgang Walther 0166d3c558 feat: Remove commit hash from version number
This reduces our Template Haskell dependencies.

The commit hash never made it into the nix-based static executable
anyway. Since we'd like to move to produce more executables via nix in
the future, it will be hard to maintain the commit hash.
2024-06-18 08:28:57 +02:00
Wolfgang WaltherandWolfgang Walther c045b261c4 refactor: Remove dependency on Paths_ module
The cabal-provided Paths_ module allows us to use the version number
from postgrest.cabal. This can be done equally well with the GHC-defined
CPP macro "VERSION_postgrest".

By making this change we avoid the inclusion of the Paths_ module, which
also stores some paths related to the cabal configuration. Those are
problematic to go into the final executable, because for nix-based
builds those are paths to the /nix/store/... - which means that our
static executable then depends on those paths.. and we can't build a
minimal docker image anymore.

To counter this, we have been using dead code elimination when building
the static executable. This has been working well, but there is a
problem on aarch64-darwin, which we will hit once can finally make our
way there: GHC on aarch64-darwin (or darwin in general?) can't do dead
code elimination - and thus it'd be impossible to create those minimal
docker images for those platforms. More information upstream in nixpkgs:
https://github.com/NixOS/nixpkgs/issues/318013
2024-06-18 08:28:57 +02:00
Wolfgang WaltherandWolfgang Walther d311fb17c4 fix: Treat pre-release and docs versions correctly for new release workflow
Since we changed our release workflow, we have adjusted:
- the docs to use postgrest.org/en/v12/ -style URLs, i.e. only using the
major component.
- the pre-release / devel versions to contain only two instead of four
version parts, i.e. currently 12.3.
2024-06-18 08:28:57 +02:00
renovate[bot]andWolfgang Walther fae24c04b1 chore(deps): update dependency urllib3 to v2.2.2 2024-06-17 21:03:43 +02:00
Wolfgang WaltherandWolfgang Walther 465170c7d6 refactor: Use jose-jwt instead of hs-jose
This removes one more dependency on Template Haskell.
2024-06-17 08:55:32 +02:00
Wolfgang WaltherandWolfgang Walther 0948d38863 test: Rewrite JWT cache tests
Timing dependent tests in the IO tests don't work too well when the next
commit increases the JWT parsing performance.

The remaining IO tests are for coverage and basic breakage. Loadtests
are adapted so that performance regressions for JWT caching would be
detected that way.
2024-06-17 08:55:32 +02:00
Wolfgang WaltherandWolfgang Walther f69ef6c42d test: Add basic tests for JWT errors 2024-06-17 08:55:32 +02:00
Laurence IslaandSteve Chavez 2e910e5338 docs: improve architecture diagram
- SVG format instead of PNG
- The components now have links to their reference in the Docs
- Supports dark mode
2024-06-16 17:31:26 -05:00
Wolfgang WaltherandWolfgang Walther e5fb1e0ec1 refactor: Replace interpolatedstring-perl6 with neat-interpolation
The former depends on th-orphans which does not cross-compile well,
because of template haskell usage.

neat-interpolation is also much better maintained.

This also potentially helps with packaging for Debian/Ubuntu in #2273.
2024-06-16 14:01:46 +02:00
Wolfgang WaltherandWolfgang Walther 0b25039f0f refactor: Pass params in SchemaCache without contrazip2
Contravariant.Extras uses Template Haskell, which is hard to
cross-compile. Reducing usage of Template Haskell with the ultimate goal
of solving all cross compilation challenges.
2024-06-16 00:59:10 +02:00
Wolfgang Walther 08692f52d6 chore: Sort doctests 2024-06-15 18:12:30 +02:00
Wolfgang Walther 2ed9ac7e57 ci: Run linkcheck once a week instead of every PR
Resolves #3544
2024-06-15 17:52:21 +02:00
Wolfgang WaltherandWolfgang Walther b38ea4dcd0 feat: Raise minimum supported version to 12.1
There is no reason to support the 12.0 version, which is outdated for
many years already. We still support all other minors for v12.
2024-06-15 17:23:34 +02:00
Wolfgang WaltherandWolfgang Walther 7d2d363575 docs: Fix punctuation in install.rst 2024-06-15 17:23:34 +02:00
Wolfgang WaltherandWolfgang Walther bb96c2dc74 feat: Drop support for pg 11
PostgreSQL 11 is EOL since November 2023.
2024-06-15 17:23:34 +02:00
Wolfgang WaltherandWolfgang Walther 126178642b feat: Drop support for pg 10 2024-06-15 17:23:34 +02:00
Wolfgang WaltherandWolfgang Walther daa77d17aa feat: Drop support for pg 9.6 2024-06-15 17:23:34 +02:00
Wolfgang Walther ec110720dc nix: Make postgrest-release bump docs version
Resolves #3583
2024-06-15 17:13:10 +02:00
Michal KleczekandGitHub 7a87f495df docs: add pg-notify-stdout to ecosystem 2024-06-14 19:25:43 +02:00
renovate[bot]andWolfgang Walther 35910eb4b0 chore(deps): update codecov/codecov-action action to v4.5.0 2024-06-13 19:51:07 +02:00
renovate[bot]andWolfgang Walther 9efedc5306 chore(deps): update ubuntu:noble docker digest to e3f92ab 2024-06-13 08:46:38 +02:00
renovate[bot]andWolfgang Walther 94d1bec0f9 chore(deps): update actions/checkout action to v4.1.7 2024-06-13 08:45:58 +02:00
Laurence IslaandSteve Chavez 15a97738fb docs: fix example of listener failure on read replicas 2024-06-12 19:43:58 -05:00
Laurence Isla b52937ef4a docs: clarify what is logged when "log-level=debug" 2024-06-12 18:19:16 -05:00
Laurence Isla 3f9027904a docs: add missing logs to stderr
- Schema cache stats are now logged to stderr
- Log when the LISTEN channel gets a notification
2024-06-12 18:19:16 -05:00
Laurence IslaandSteve Chavez 5afa321e89 docs: add "Listener" page
Co-authored-by: Steve Chavez <stevechavezast@gmail.com>
2024-06-12 18:19:16 -05:00
steve-chavez 21f15643b4 bump version to 12.3 2024-06-11 09:57:05 -05:00
214 changed files with 7729 additions and 5291 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
freebsd_instance:
image_family: freebsd-14-0
image_family: freebsd-14-2
build_task:
# Don't change this name without adjusting .github/workflows/build.yaml
+9
View File
@@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
-17
View File
@@ -1,17 +0,0 @@
<!--
Before reporting a bug:
If your database schema has changed while the PostgREST server is running,
send the server a SIGUSR1 signal or restart it(http://postgrest.org/en/stable/admin.html#schema-reloading)
to ensure the schema cache is not stale. This sometimes fixes apparent bugs.
-->
### Environment
* PostgreSQL version: (if using docker, specify the image)
* PostgREST version: (if using docker, specify the image)
* Operating system:
### Description of issue
(Expected behavior vs actual behavior)
(Steps to reproduce: Include a minimal SQL definition plus how you make the request to PostgREST and the response body)
+28
View File
@@ -0,0 +1,28 @@
---
name: Bug report
about: Create a bug report to help us improve
type: Bug
title: ''
labels: ''
assignees: ''
---
<!--
Before reporting a bug:
If your database schema has changed while the PostgREST server is running,
send the server a SIGUSR1 signal or restart it (http://postgrest.org/en/stable/admin.html#schema-reloading) to ensure the schema cache is not stale. This sometimes fixes apparent bugs.
-->
### Environment
* PostgreSQL version: (if using docker, specify the image)
* PostgREST version: (if using docker, specify the image)
* Operating system:
### Description of issue
Describe the behavior you expected vs the actual behavior. Include:
- A minimal SQL definition.
- How you make the request to PostgREST (curl command preferred).
- The PostgREST response.
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an enhancement for this project
type: Feature
title: ''
labels: ''
assignees: ''
---
## Problem
A clear and concise description of what the problem is.
## Solution
A clear and concise description of what you want to happen.
+5
View File
@@ -0,0 +1,5 @@
# TODO: Remove this once a new actionlint release has been cut
# and made its way to us through nixpkgs.
self-hosted-runner:
labels:
- ubuntu-24.04-arm
@@ -112,7 +112,7 @@ runs:
echo "artifacts=${artifacts}" >> "$GITHUB_OUTPUT"
- name: Save artifact to GitHub Actions
if: steps.find-task.outputs.task_found
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ inputs.upload }}
path: ${{ steps.download.outputs.artifacts }}
+2 -2
View File
@@ -19,14 +19,14 @@ inputs:
runs:
using: composite
steps:
- uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: ${{ startsWith(github.ref, 'refs/heads/') || (inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }}
with:
path: ${{ inputs.path }}
key: ${{ runner.os }}-${{ inputs.prefix }}-${{ inputs.suffix }}
restore-keys: |
${{ runner.os }}-${{ inputs.prefix }}-
- uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
if: ${{ !startsWith(github.ref, 'refs/heads/') && !(inputs.save-prs && startsWith(github.ref, 'refs/pull/')) }}
with:
path: ${{ inputs.path }}
+3 -2
View File
@@ -11,15 +11,16 @@ inputs:
runs:
using: composite
steps:
- uses: nixbuild/nix-quick-install-action@60e9c39264d4714139af3cdf15f691b19eec3530 # v28
- uses: nixbuild/nix-quick-install-action@5bb6a3b3abe66fd09bbf250dce8ada94f856a703 # v30
with:
nix_conf: |-
always-allow-substitutes = true
max-jobs = auto
- uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: postgrest
authToken: ${{ inputs.authToken }}
skipPush: ${{ inputs.authToken == '' }}
- if: ${{ inputs.tools }}
run: nix-env -f default.nix -iA ${{ inputs.tools }}
shell: bash
+19 -4
View File
@@ -8,18 +8,33 @@
"/^v[0-9]+/"
],
"rebaseWhen": "conflicted",
"pip_requirements": {
"enabled": false
},
"packageRules": [
{
"matchBaseBranches": [ "/^v[0-9]+/" ],
"matchManagers": ["haskell-cabal"],
"enabled": false
},
{
"matchBaseBranches": [ "/^v[0-9]+/" ],
"groupName": "all dependencies"
},
{
"matchPackageNames": ["docutils"],
"allowedVersions": "<0.21.0"
"matchManagers": ["haskell-cabal"],
"matchPackageNames": ["base", "bytestring", "containers", "directory", "mtl", "parsec", "process", "text"],
"groupName": "GHC dependencies"
},
{
"matchPackageNames": ["macos"],
"allowedVersions": "<13"
"matchManagers": ["haskell-cabal"],
"matchPackageNames": ["hasql", "hasql-dynamic-statements", "hasql-notifications", "hasql-transaction", "hasql-pool"],
"groupName": "hasql"
},
{
"matchManagers": ["haskell-cabal"],
"matchPackageNames": ["fuzzyset"],
"allowedVersions": "<0.3"
}
]
}
-72
View File
@@ -1,72 +0,0 @@
#!/bin/bash
set -Eeuo pipefail
# This script builds PostgREST in a remote ARM server
[ -z "$1" ] && { echo "Missing 1st argument: PostgREST github commit SHA"; exit 1; }
[ -z "$2" ] && { echo "Missing 2nd argument: Build environment directory name"; exit 1; }
[ -z "$3" ] && { echo "Missing 3rd argument: GHC version"; exit 1; }
PGRST_GITHUB_COMMIT="$1"
SCRIPT_DIR="$2"
DOCKER_BUILD_DIR="$SCRIPT_DIR/docker-env"
# latest is a shortcut documented on https://www.haskell.org/ghcup/guide/#tags-and-shortcuts
CABAL_VERSION="latest"
GHC_VERSION="$3"
install_packages() {
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git build-essential curl libffi-dev libffi7 libgmp-dev libgmp10 libncurses-dev libncurses5 libtinfo5 llvm libnuma-dev zlib1g-dev libpq-dev jq gcc
sudo apt-get clean
}
install_ghcup() {
export BOOTSTRAP_HASKELL_NONINTERACTIVE=1
export BOOTSTRAP_HASKELL_MINIMAL=1
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
source ~/.ghcup/env
}
install_cabal() {
ghcup upgrade
ghcup install cabal $CABAL_VERSION
ghcup set cabal $CABAL_VERSION
}
install_ghc() {
ghcup upgrade
ghcup install ghc $GHC_VERSION
ghcup set ghc $GHC_VERSION
}
install_packages
# Add ghcup to the PATH for this session
[ -f ~/.ghcup/env ] && source ~/.ghcup/env
ghcup --version || install_ghcup
ghcup set cabal $CABAL_VERSION || install_cabal
ghcup set ghc $GHC_VERSION || install_ghc
cd ~/$SCRIPT_DIR
# Clone the repository and build the project
git clone https://github.com/PostgREST/postgrest.git
cd postgrest
git checkout $PGRST_GITHUB_COMMIT
cabal v2-update && cabal v2-build
# Strip unused symbols from executable
PGRST_BIN=$(cabal exec which postgrest | tail -1)
strip $PGRST_BIN
# Copy the built binary to the Dockerfile directory
cp $PGRST_BIN ~/$DOCKER_BUILD_DIR
# Move and compress the built binary
mkdir -p ~/$SCRIPT_DIR/result
mv $PGRST_BIN ~/$SCRIPT_DIR/result
cd ~/$SCRIPT_DIR
tar -cJf result.tar.xz result
-50
View File
@@ -1,50 +0,0 @@
#!/bin/bash
set -Eeuo pipefail
# This script publishes the Docker ARM images to Docker Hub.
[ -z "$1" ] && { echo "Missing 1st argument: PostgREST github commit SHA"; exit 1; }
[ -z "$2" ] && { echo "Missing 2nd argument: Docker repo"; exit 1; }
[ -z "$3" ] && { echo "Missing 3rd argument: Docker username"; exit 1; }
[ -z "$4" ] && { echo "Missing 4th argument: Docker password"; exit 1; }
[ -z "$5" ] && { echo "Missing 5th argument: Build environment directory name"; exit 1; }
[ -z "$6" ] && { echo "Missing 6th argument: PostgREST version"; exit 1; }
PGRST_GITHUB_COMMIT="$1"
DOCKER_REPO="$2"
DOCKER_USER="$3"
DOCKER_PASS="$4"
SCRIPT_DIR="$5"
PGRST_VERSION="$6"
DOCKER_BUILD_DIR="$SCRIPT_DIR/docker-env"
clean_env()
{
sudo docker logout
}
# Login to Docker
sudo docker logout
{ echo $DOCKER_PASS | sudo docker login -u $DOCKER_USER --password-stdin; } || { echo "Couldn't login to docker"; exit 1; }
trap clean_env sigint sigterm exit
# Move to the docker build environment
cd ~/$DOCKER_BUILD_DIR
# Push final images to Docker hub
# NOTE: This command publishes a separate ARM image because the builds cannot
# be added to the manifest if they are not in the registry beforehand.
# This image must be manually deleted from Docker Hub at the end of the process.
sudo docker buildx build --build-arg PGRST_GITHUB_COMMIT=$PGRST_GITHUB_COMMIT \
-t $DOCKER_REPO/postgrest:$PGRST_VERSION-arm \
--push .
# Add the arm images to the manifest
# NOTE: This assumes that there already is a `postgrest:<version>` image
# for the amd64 architecture pushed to Docker Hub
sudo docker buildx imagetools create --append -t $DOCKER_REPO/postgrest:$PGRST_VERSION $DOCKER_REPO/postgrest:$PGRST_VERSION-arm
[ "$PGRST_VERSION" != "devel" ] && sudo docker buildx imagetools create --append -t $DOCKER_REPO/postgrest:latest $DOCKER_REPO/postgrest:$PGRST_VERSION-arm
sudo docker logout
+44 -37
View File
@@ -30,10 +30,10 @@ concurrency:
jobs:
static:
name: Nix - Linux static
runs-on: ubuntu-22.04
name: Nix - Linux x86-64 static
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
@@ -42,27 +42,27 @@ jobs:
- name: Build static executable
run: nix-build -A postgrestStatic
- name: Save built executable as artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: postgrest-linux-static-x64
name: postgrest-linux-static-x86-64
path: result/bin/postgrest
if-no-files-found: error
- name: Build Docker image
run: nix-build -A docker.image --out-link postgrest-docker.tar.gz
- name: Save built Docker image as artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: postgrest-docker-x64
name: postgrest-docker-x86-64
path: postgrest-docker.tar.gz
if-no-files-found: error
macos:
name: Nix - MacOS
runs-on: macos-12
runs-on: macos-14
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
@@ -87,42 +87,50 @@ jobs:
fail-fast: false
matrix:
include:
- name: Linux
runs-on: ubuntu-22.04
- name: Linux aarch64
runs-on: ubuntu-24.04-arm
cache: |
~/.stack/pantry
~/.stack/snapshots
~/.stack/stack.sqlite3
# no artifact for Linux, because we use the static build
artifact: postgrest-ubuntu-aarch64
deps: sudo apt-get update && sudo apt-get install libpq-dev
- name: MacOS
runs-on: macos-12
- name: MacOS aarch64
runs-on: macos-14
cache: |
~/.stack/pantry
~/.stack/snapshots
~/.stack/stack.sqlite3
artifact: postgrest-macos-x64
artifact: postgrest-macos-aarch64
deps: brew link --force libpq
- name: MacOS x86-64
runs-on: macos-13
cache: |
~/.stack/pantry
~/.stack/snapshots
~/.stack/stack.sqlite3
artifact: postgrest-macos-x86-64
deps: brew link --force libpq
- name: Windows
runs-on: windows-2022
cache: |
~\AppData\Roaming\stack\pantry
~\AppData\Local\Programs\stack\pantry
~\AppData\Roaming\stack\snapshots
~\AppData\Local\Programs\stack\snapshots
~\AppData\Roaming\stack\stack.sqlite3
~\AppData\Local\Programs\stack\stack.sqlite3
C:\sr\pantry
C:\sr\snapshots
C:\sr\stack.sqlite3
deps: Add-Content $env:GITHUB_PATH $env:PGBIN
artifact: postgrest-windows-x64
artifact: postgrest-windows-x86-64
name: Stack - ${{ matrix.name }}
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: haskell-actions/setup@33585e1a16afa5875e124b0ebc89dd0c2f872c21 # v2.7.3
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: haskell-actions/setup@64445b6b5dd545faf5f8e2acee8253eb5c2b29aa # v2.7.11
with:
# This must match the version in stack.yaml's resolver
ghc-version: 9.6.5
ghc-version: 9.6.6
enable-stack: true
stack-no-global: true
stack-setup-ghc: true
@@ -147,8 +155,7 @@ jobs:
- name: Strip Executable
run: strip result/postgrest*
- name: Save built executable as artifact
if: matrix.artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ matrix.artifact }}
path: |
@@ -159,27 +166,27 @@ jobs:
freebsd:
name: Stack - FreeBSD from CirrusCI
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- 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-x64
upload: postgrest-freebsd-x86-64
cabal:
strategy:
matrix:
ghc: ['9.6.4', '9.8.2']
ghc: ['9.6.6', '9.8.2']
fail-fast: false
name: Cabal - Linux GHC ${{ matrix.ghc }}
runs-on: ubuntu-22.04
name: Cabal - Linux x86-64 - GHC ${{ matrix.ghc }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: haskell-actions/setup@33585e1a16afa5875e124b0ebc89dd0c2f872c21 # v2.7.3
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: haskell-actions/setup@64445b6b5dd545faf5f8e2acee8253eb5c2b29aa # v2.7.11
with:
ghc-version: ${{ matrix.ghc }}
- name: Cache .cabal
@@ -188,8 +195,8 @@ jobs:
path: |
~/.cabal/packages
~/.cabal/store
prefix: cabal-${{ matrix.ghc }}
suffix: ${{ hashFiles('postgrest.cabal', 'cabal.project', 'cabal.project.freeze') }}
prefix: cabal-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }}
suffix: ${{ hashFiles('postgrest.cabal', 'cabal.project') }}
- name: Cache dist-newstyle
uses: ./.github/actions/cache-on-main
with:
+2 -2
View File
@@ -18,9 +18,9 @@ concurrency:
jobs:
lint-style:
name: Lint & Style
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
+4 -296
View File
@@ -5,21 +5,10 @@ on:
branches:
- main
- v[0-9]+
tags:
- devel
- v*
concurrency:
# Terminate all previous runs of the same workflow for the same tag, but never
# cancel for the main / release branch pipelines.
group: ci-${{ (github.ref_type == 'tag' && github.ref) || github.run_id }}
# TODO: Enable this once https://github.com/orgs/community/discussions/13015 is solved
cancel-in-progress: false
jobs:
check:
name: Check
if: startsWith(github.ref, 'refs/heads/')
uses: ./.github/workflows/check.yaml
secrets:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
@@ -27,7 +16,6 @@ jobs:
docs:
name: Docs
if: startsWith(github.ref, 'refs/heads/')
uses: ./.github/workflows/docs.yaml
secrets:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
@@ -35,7 +23,6 @@ jobs:
test:
name: Test
if: startsWith(github.ref, 'refs/heads/')
uses: ./.github/workflows/test.yaml
secrets:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
@@ -49,87 +36,21 @@ jobs:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
arm:
name: Build / Cabal - aarch64 GHC 9.4.8
if: vars.SSH_ARM_ENABLED
runs-on: ubuntu-22.04
outputs:
remotepath: ${{ steps.Remote-Dir.outputs.remotepath }}
env:
GITHUB_COMMIT: ${{ github.sha }}
GHC_VERSION: '9.4.8'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- id: Remote-Dir
name: Unique directory name for the remote build
run: echo "remotepath=postgrest-build-$(uuidgen)" >> "$GITHUB_OUTPUT"
- name: Copy script files to the remote server
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SSH_ARM_HOST }}
username: ubuntu
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
source: ".github/scripts/arm/*"
target: ${{ steps.Remote-Dir.outputs.remotepath }}
strip_components: 3
- name: Build ARM
uses: appleboy/ssh-action@master
env:
REMOTE_DIR: ${{ steps.Remote-Dir.outputs.remotepath }}
with:
host: ${{ secrets.SSH_ARM_HOST }}
username: ubuntu
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
command_timeout: 120m
script_stop: true
envs: GITHUB_COMMIT,REMOTE_DIR,GHC_VERSION
script: bash ~/$REMOTE_DIR/build.sh "$GITHUB_COMMIT" "$REMOTE_DIR" "$GHC_VERSION"
- name: Download binaries from remote server
uses: nicklasfrahm/scp-action@main
with:
direction: download
host: ${{ secrets.SSH_ARM_HOST }}
username: ubuntu
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
source: "${{ steps.Remote-Dir.outputs.remotepath }}/result.tar.xz"
target: "result.tar.xz"
- name: Extract downloaded binaries
run: tar -xvf result.tar.xz && rm result.tar.xz
- name: Save aarch64 executable as artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: postgrest-ubuntu-aarch64
path: result/postgrest
if-no-files-found: error
tag:
name: Release / Tag
name: Tag
concurrency:
# 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 }}
# TODO: Enable this once https://github.com/orgs/community/discussions/13015 is solved
cancel-in-progress: false
if: |
vars.RELEASE_ENABLED &&
startsWith(github.ref, 'refs/heads/') &&
needs.docs.result == 'success' &&
needs.test.result == 'success' &&
needs.build.result == 'success' &&
(needs.arm.result == 'skipped' || success())
permissions:
contents: write
runs-on: ubuntu-22.04
if: vars.RELEASE_ENABLED
runs-on: ubuntu-24.04
needs:
- docs
- test
- build
- arm
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ssh-key: ${{ secrets.POSTGREST_SSH_KEY }}
- name: Tag latest commit
@@ -147,216 +68,3 @@ jobs:
git tag -f "devel"
git push -f origin "devel"
fi
prepare:
name: Release / Prepare
if: |
startsWith(github.ref, 'refs/tags/') &&
needs.build.result == 'success' &&
(needs.arm.result == 'skipped' || success())
runs-on: ubuntu-22.04
needs:
- build
- arm
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Check the version to be released
run: |
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
if [ "${GITHUB_REF_NAME}" != "devel" ] && [ "${GITHUB_REF_NAME}" != "v$cabal_version" ]; then
echo "Tagged version ($GITHUB_REF_NAME) does not match the one in postgrest.cabal (v$cabal_version). Aborting release..."
exit 1
fi
- name: Identify changes from CHANGELOG.md
run: |
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
echo "Getting unreleased changes..."
sed -n "1,/## Unreleased/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
else
version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
echo "Propper release, getting changes for version $version ..."
sed -n "1,/## \[$version\]/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
fi
echo "Relevant extract from CHANGELOG.md:"
cat CHANGES.md
- name: Save CHANGES.md as artifact
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: release-changes
path: CHANGES.md
if-no-files-found: error
github:
name: Release / GitHub
permissions:
contents: write
runs-on: ubuntu-22.04
needs:
- prepare
if: success() || needs.prepare.result == 'success'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Download all artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
path: artifacts
- name: Create release bundle with archives for all builds
run: |
find artifacts -type f -iname postgrest -exec chmod +x {} \;
mkdir -p release-bundle
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-linux-static-x64.tar.xz" \
-C artifacts/postgrest-linux-static-x64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-macos-x64.tar.xz" \
-C artifacts/postgrest-macos-x64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-freebsd-x64.tar.xz" \
-C artifacts/postgrest-freebsd-x64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-ubuntu-aarch64.tar.xz" \
-C artifacts/postgrest-ubuntu-aarch64 postgrest
zip "release-bundle/postgrest-${GITHUB_REF_NAME}-windows-x64.zip" \
artifacts/postgrest-windows-x64/postgrest.exe
- name: Save release bundle
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: release-bundle
path: release-bundle
if-no-files-found: error
- name: Publish release on GitHub
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Releasing version ${GITHUB_REF_NAME} on GitHub..."
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
# To replace the existing release, we must first delete the old assets,
# then modify the release, then add the new assets.
gh release view devel --json assets \
| jq -r '.assets[] | .name' \
| xargs -rn1 \
gh release delete-asset -y devel
gh release edit devel \
-t devel \
--verify-tag \
-F artifacts/release-changes/CHANGES.md \
--prerelease
gh release upload --clobber devel release-bundle/*
else
gh release create "${GITHUB_REF_NAME}" \
-t "${GITHUB_REF_NAME}" \
--verify-tag \
-F artifacts/release-changes/CHANGES.md \
release-bundle/*
fi
docker:
name: Release / Docker Hub
runs-on: ubuntu-22.04
needs:
- prepare
if: |
vars.DOCKER_REPO && vars.DOCKER_USER &&
(success() || needs.prepare.result == 'success')
env:
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
DOCKER_USER: ${{ vars.DOCKER_USER }}
DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Download Docker image
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: postgrest-docker-x64
- name: Publish images on Docker Hub
run: |
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS"
docker load -i postgrest-docker.tar.gz
docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
# Only tag 'latest' for full releases
if [ "${GITHUB_REF_NAME}" != "devel" ]; then
echo "Pushing to 'latest' tag for full release of ${GITHUB_REF_NAME} ..."
docker tag postgrest:latest "$DOCKER_REPO"/postgrest:latest
docker push "$DOCKER_REPO"/postgrest:latest
else
echo "Skipping push to 'latest' tag for pre-release..."
fi
docker-description:
name: Release / Docker Hub Description
runs-on: ubuntu-22.04
if: |
vars.DOCKER_REPO && vars.DOCKER_USER &&
github.ref == 'refs/tags/devel'
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae # v4.0.0
with:
username: ${{ vars.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
repository: ${{ vars.DOCKER_REPO }}/postgrest
short-description: ${{ github.event.repository.description }}
readme-filepath: ./docker-hub-readme.md
docker-arm:
name: Release / Docker Hub Arm
runs-on: ubuntu-22.04
needs:
- arm
- docker
env:
GITHUB_COMMIT: ${{ github.sha }}
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
DOCKER_USER: ${{ vars.DOCKER_USER }}
DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Publish images for ARM builds on Docker Hub
uses: appleboy/ssh-action@master
env:
REMOTE_DIR: ${{ needs.arm.outputs.remotepath }}
with:
host: ${{ secrets.SSH_ARM_HOST }}
username: ubuntu
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
script_stop: true
envs: GITHUB_COMMIT,DOCKER_REPO,DOCKER_USER,DOCKER_PASS,REMOTE_DIR,GITHUB_REF_NAME
script: bash ~/$REMOTE_DIR/docker-publish.sh "$GITHUB_COMMIT" "$DOCKER_REPO" "$DOCKER_USER" "$DOCKER_PASS" "$REMOTE_DIR" "$GITHUB_REF_NAME"
clean-arm:
name: Build / Cleanup
needs:
- arm
- docker-arm
if: ${{ always() && vars.SSH_ARM_ENABLED }}
runs-on: ubuntu-22.04
env:
REMOTE_DIR: ${{ needs.arm.outputs.remotepath }}
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Remove uploaded files from server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_ARM_HOST }}
username: ubuntu
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
envs: REMOTE_DIR
script: rm -rf $REMOTE_DIR
+4 -18
View File
@@ -25,9 +25,9 @@ concurrency:
jobs:
build:
name: Build
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
@@ -39,9 +39,9 @@ jobs:
spellcheck:
name: Spellcheck
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
@@ -51,17 +51,3 @@ jobs:
run: postgrest-docs-spellcheck
- name: Run dictcheck
run: postgrest-docs-dictcheck
linkcheck:
name: Linkcheck
if: github.base_ref == 'main'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: docs.linkcheck.bin
- run: postgrest-docs-linkcheck
+17
View File
@@ -0,0 +1,17 @@
name: Linkcheck
on:
schedule:
- cron: '1 2 * * 3'
jobs:
linkcheck:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: docs.linkcheck.bin
- run: postgrest-docs-linkcheck
+205
View File
@@ -0,0 +1,205 @@
name: Release
on:
push:
tags:
- devel
- v*
concurrency:
# Terminate all previous runs of the same workflow for the same tag.
group: release-${{ github.ref }}
# TODO: Enable this once https://github.com/orgs/community/discussions/13015 is solved
cancel-in-progress: false
jobs:
build:
name: Build
uses: ./.github/workflows/build.yaml
secrets:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
prepare:
name: Prepare
runs-on: ubuntu-24.04
needs:
- build
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Check the version to be released
run: |
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
if [ "${GITHUB_REF_NAME}" != "devel" ] && [ "${GITHUB_REF_NAME}" != "v$cabal_version" ]; then
echo "Tagged version ($GITHUB_REF_NAME) does not match the one in postgrest.cabal (v$cabal_version). Aborting release..."
exit 1
fi
- name: Identify changes from CHANGELOG.md
run: |
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
echo "Getting unreleased changes..."
sed -n "1,/## Unreleased/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
else
version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
echo "Propper release, getting changes for version $version ..."
sed -n "1,/## \[$version\]/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
fi
echo "Relevant extract from CHANGELOG.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
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: artifacts
- name: Create release bundle with archives for all builds
run: |
find artifacts -type f -iname postgrest -exec chmod +x {} \;
mkdir -p release-bundle
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-linux-static-x86-64.tar.xz" \
-C artifacts/postgrest-linux-static-x86-64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-macos-aarch64.tar.xz" \
-C artifacts/postgrest-macos-aarch64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-macos-x86-64.tar.xz" \
-C artifacts/postgrest-macos-x86-64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-freebsd-x86-64.tar.xz" \
-C artifacts/postgrest-freebsd-x86-64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-ubuntu-aarch64.tar.xz" \
-C artifacts/postgrest-ubuntu-aarch64 postgrest
zip --junk-paths "release-bundle/postgrest-${GITHUB_REF_NAME}-windows-x86-64.zip" \
artifacts/postgrest-windows-x86-64/postgrest.exe
- name: Save release bundle
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: release-bundle
path: release-bundle
if-no-files-found: error
- name: Publish release on GitHub
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Releasing version ${GITHUB_REF_NAME} on GitHub..."
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
# To replace the existing release, we must first delete the old assets,
# then modify the release, then add the new assets.
gh release view devel --json assets \
| jq -r '.assets[] | .name' \
| xargs -rn1 \
gh release delete-asset -y devel
gh release edit devel \
-t devel \
--verify-tag \
-F artifacts/release-changes/CHANGES.md \
--prerelease
gh release upload --clobber devel release-bundle/*
else
gh release create "${GITHUB_REF_NAME}" \
-t "${GITHUB_REF_NAME}" \
--verify-tag \
-F artifacts/release-changes/CHANGES.md \
release-bundle/*
fi
docker:
name: Docker Hub
runs-on: ubuntu-24.04-arm
needs:
- prepare
if: |
vars.DOCKER_REPO && vars.DOCKER_USER
env:
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Download x86-64 Docker image
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: postgrest-docker-x86-64
- name: Download aarch64 binary
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: postgrest-ubuntu-aarch64
- uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
with:
username: ${{ vars.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
- name: Build aarch64 Docker image
run: |
# This only pushes the image via digest, not a tag. This will not appear
# in the image list on Docker Hub, yet. It will be later added to the main
# tag's manifest.
docker buildx build \
-t "$DOCKER_REPO/postgrest" \
--platform linux/arm64 \
--output push-by-digest=true,type=image,push=true \
--metadata-file metadata.json \
.
echo "SHA256_ARM=$(jq -r '."containerimage.digest"' metadata.json)" >> "$GITHUB_ENV"
- name: Publish images on Docker Hub
run: |
docker load -i postgrest-docker.tar.gz
docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
docker buildx imagetools create --append \
-t "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}" \
"$DOCKER_REPO/postgrest@$SHA256_ARM"
# Only tag 'latest' for full releases
if [ "${GITHUB_REF_NAME}" != "devel" ]; then
echo "Pushing to 'latest' tag for full release of ${GITHUB_REF_NAME} ..."
docker tag postgrest:latest "$DOCKER_REPO"/postgrest:latest
docker push "$DOCKER_REPO"/postgrest:latest
docker buildx imagetools create --append \
-t "$DOCKER_REPO/postgrest:latest" \
"$DOCKER_REPO/postgrest@$SHA256_ARM"
else
echo "Skipping push to 'latest' tag for pre-release..."
fi
docker-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:
username: ${{ vars.DOCKER_USER }}
password: ${{ secrets.DOCKER_PASS }}
repository: ${{ vars.DOCKER_REPO }}/postgrest
short-description: ${{ github.event.repository.description }}
readme-filepath: ./docker-hub-readme.md
-39
View File
@@ -1,39 +0,0 @@
name: Upload Reports
on:
workflow_run:
workflows:
- CI
- Test
branches-ignore:
- devel
- v[0-9]+
- v[0-9]+.[0-9]+.[0-9]+
types:
- completed
jobs:
loadtest:
name: Loadtest
permissions:
checks: write
runs-on: ubuntu-22.04
if: github.event.workflow_run.conclusion == 'success' || github.event.workflow_run.conclusion == 'failure'
steps:
- name: Download from Artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
name: loadtest.md
path: artifacts
- name: Upload to GitHub Checks
uses: LouisBrunner/checks-action@6b626ffbad7cc56fd58627f774b9067e6118af23 # v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
sha: ${{ github.event.workflow_run.head_sha }}
name: Loadtest Results
conclusion: neutral
output: |
{"summary":""}
output_text_description_file: artifacts/loadtest.md
+38 -18
View File
@@ -32,14 +32,14 @@ concurrency:
jobs:
coverage:
name: Coverage
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
defaults:
run:
# Hack for enabling color output, see:
# https://github.com/actions/runner/issues/241#issuecomment-842566950
shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
@@ -49,7 +49,7 @@ jobs:
- name: Run coverage (IO tests and Spec tests against PostgreSQL 15)
run: postgrest-coverage
- name: Upload coverage to codecov
uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c # v4.4.1
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2
with:
files: ./coverage/codecov.json
token: ${{ secrets.CODECOV_TOKEN }}
@@ -67,16 +67,16 @@ jobs:
strategy:
fail-fast: false
matrix:
pgVersion: ["9_6", 10, 11, 12, 13, 14, 15, 16]
pgVersion: [12, 13, 14, 15, 16, 17]
name: PG ${{ matrix.pgVersion }}
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
defaults:
run:
# Hack for enabling color output, see:
# https://github.com/actions/runner/issues/241#issuecomment-842566950
shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
@@ -98,23 +98,26 @@ jobs:
memory:
name: Memory
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
tools: memory.test.bin
tools: tests.testMemory.bin
- name: Run memory tests
run: postgrest-test-memory
loadtest:
strategy:
matrix:
kind: ['mixed', 'jwt']
name: Loadtest
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0
- name: Setup Nix Environment
@@ -128,11 +131,28 @@ jobs:
prefix: v
- name: Run loadtest
run: |
postgrest-loadtest-against main ${{ steps.get-latest-tag.outputs.tag }}
postgrest-loadtest-report > loadtest/loadtest.md
- name: Upload report
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
postgrest-loadtest-against -k ${{ matrix.kind }} main ${{ steps.get-latest-tag.outputs.tag }}
postgrest-loadtest-report >> "$GITHUB_STEP_SUMMARY"
flake:
strategy:
fail-fast: false
matrix:
runs-on:
- macos-13 # x86_64-darwin
- macos-14 # aarch64-darwin
- ubuntu-24.04 # x86_64-linux
- ubuntu-24.04-arm # aarch64-linux
name: Flake Check
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
name: loadtest.md
path: loadtest/loadtest.md
if-no-files-found: error
fetch-depth: 0
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- name: Run flake check
run: |
nix flake check
+2 -1
View File
@@ -14,7 +14,7 @@ site
.#*
*.swp
result*
dist-newstyle
dist-*
postgrest.hp
postgrest.prof
__pycache__
@@ -24,3 +24,4 @@ coverage
loadtest
.history
.docs-build
gen_targets.http
+1 -1
View File
@@ -5,6 +5,6 @@ python:
install:
- requirements: docs/requirements.txt
build:
os: ubuntu-22.04
os: ubuntu-24.04
tools:
python: "3.11"
+11 -11
View File
@@ -13,21 +13,21 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
</a>
</td>
<td align="center" valign="middle">
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/gnuhost.png">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/code-build.png">
</a>
</td>
</tr>
<tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/code-build.png">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
</a>
</td>
<td align="center" valign="middle">
@@ -35,11 +35,6 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
<img width="296px" src="static/supabase.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
</a>
</td>
</tr>
</tbody>
</table>
@@ -93,6 +88,11 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
<img width="222px" src="static/oblivious.jpg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="222px" src="static/gnuhost.png">
</a>
</td>
</tr>
</tbody>
</table>
+161
View File
@@ -5,6 +5,167 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
## [13.0.2] - 2025-06-02
### Fixed
- Fix regression that makes `ORDER BY` with nulls-order not work alongside limits by @laurenceisla in #4109
## [13.0.1] - 2025-06-01
### Fixed
- Fix jwt error returning HTTP status `400` for invalid role by @taimoorzaeem in #3601
- Fix `db-extra-search-path` cannot be set to nothing by @taimoorzaeem in #4074
+ It can now be disabled by setting it to empty string.
+ Schema Cache load error is now logged including `db-schemas` and `db-extra-search-path` config values.
## [13.0.0] - 2025-05-08
### Added
- #3558, Add the `admin-server-host` config to set the host for the admin server - @develop7
- #3607, Log to stderr when the JWT secret is less than 32 characters long - @laurenceisla
- #2858, Performance improvements when calling RPCs via GET using indexes in more cases - @wolfgangwalther
- #3560, Log resolved host in "Listening on ..." messages - @develop7
- #3727, Log maximum pool size - @steve-chavez
- #1536, Add string comparison feature for jwt-role-claim-key - @taimoorzaeem
- #3747, Allow `not_null` value for the `is` operator - @taimoorzaeem
- #2255, Apply `to_tsvector()` explicitly to the full-text search filtered column (excluding `tsvector` types) - @laurenceisla
- #1578, Log the main SQL query to stderr at the current `log-level` when `log-query=main-query` - @laurenceisla
- #3903, Log connection pool borrows on `log-level=debug` - @taimoorzaeem
- #3041, Allow spreading one-to-many and many-to-many embedded resources - @laurenceisla
+ The selected columns in the embedded resources are aggregated into arrays
+ Aggregates are not supported
- #2967, Add `Proxy-Status` header for better error response - @taimoorzaeem
- #4016, Add `Content-Length` response header - @laurenceisla
### Fixed
- #3693, Prevent spread embedding to allow aggregates when they are disabled - @laurenceisla
- #3693, A nested spread embedding now correctly groups by the fields of its top parent relationship - @laurenceisla
- #3693, Fix spread embedding errors when using the `count()` aggregate without a field - @laurenceisla
+ Fixed `"column reference <col> is ambiguous"` error when selecting `?select=...table(col,count())`
+ Fixed `"column <json_aggregate>.<alias> does not exist"` error when selecting `?select=...table(aias:count())`
- #3727, Clarify "listening" logs - @steve-chavez
- #3795, Clarify `Accept: vnd.pgrst.object` error message - @steve-chavez
- #3697, #3602, Handle queries on non-existing table gracefully - @taimoorzaeem
- #3600, #3926, Improve JWT errors - @taimoorzaeem
- #3013, Fix `order=` with POST, PATCH, PUT and DELETE requests - @taimoorzaeem
- #3965, Fix filter on unselected columns in a table-valued function - @taimoorzaeem
- #4052, Fix schema cache load duplicate objects with different object type but same oid - @taimoorzaeem
### Changed
- #2052, Dropped support for PostgreSQL 9.6 - @wolfgangwalther
- #2052, Dropped support for PostgreSQL 10 - @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
- #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` or `db-extra-search-path` config - @wolfgangwalther
- Previously, this would silently return 200 - OK on the root endpoint, but don't provide any usable endpoints.
- Note: This also applies when deleting the `public` schema - both config options default to that.
- #3757, Remove support for `Prefer: params=single-object` - @joelonsql
+ This preference was deprecated in favor of Functions with an array of JSON objects
- #3013, Drop support for Limited updates/deletes
+ The feature was complicated and largely unused.
- #3956, Drop `/config` endpoint of admin server - @steve-chavez
+ The endpoint was at risk of being left unprotected when exposing it.
+ The accompanying `admin-server-config-enabled` config was also dropped.
- #3697, #3602, Querying non-existent table now returns `PGRST205` error instead of empty json - @taimoorzaeem
- #3600, #3926, Improve JWT errors - @taimoorzaeem
+ Return `PGRST301` error when `Bearer` in auth header is sent empty
+ Diagnostic error messages instead of exposed internals
+ Return new `PGRST303` error when jwt claims decoding fails
- #3906, Return `PGRST125` and `PGRST126` errors instead of empty json - @taimoorzaeem
## [12.2.12] - 2025-05-01
### Fixed
- #3956, Fix exposing admin server `/config` by default - @steve-chavez
+ The above endpoint is now disabled unless the `admin-server-config-enabled` config is set to `true`
## [12.2.11] - 2025-04-22
### Fixed
- #4030, Fix regression with parameter `charset=utf-8` in mediatype - @taimoorzaeem
## [12.2.10] - 2025-04-18
### Fixed
- #3889, Fix: JWT cache purging on every request decreases performance - @mkleczek
## [12.2.9] - 2025-04-16
### Fixed
- #3498, Fix incorrect parsing of the `for` parameter of the `application/vnd.pgrst.plan` media type - @taimoorzaeem
- #4014, Fix JWT cache allows old tokens after the jwt-secret is changed in a config reload - @taimoorzaeem
## [12.2.8] - 2025-02-10
### Fixed
- #3841, Log `503` client error to stderr - @taimoorzaeem
## [12.2.7] - 2025-02-03
### Fixed
- #2524, Fix schema reloading notice on windows - @diogob
## [12.2.6] - 2025-01-29
### Fixed
- #3788, Fix jwt cache does not remove expired entries - @taimoorzaeem
## [12.2.5] - 2025-01-20
### Fixed
- #3867, Fix startup for arm64 docker image - @wolfgangwalther
## [12.2.4] - 2025-01-18
### Fixed
- #3779, Always log the schema cache load time - @steve-chavez
- #3706, Fix insert with `missing=default` uses default value of domain instead of column - @taimoorzaeem
## [12.2.3] - 2024-08-01
### Fixed
- #3091, Broken link in OpenAPI description `externalDocs` - @salim-b
- #3659, Embed One-to-One relationship with different column order properly - @wolfgangwalther
- #3504, Remove `format` from `rowFilter` parameters in OpenAPI - @dantheman2865
- #3660, Fix regression that loaded the schema cache before the in-database configuration - @steve-chavez, @laurenceisla
## [12.2.2] - 2024-07-10
### Fixed
- #3093, Nested empty embeds no longer show empty values and are correctly omitted - @laurenceisla
- #3644, Make --dump-schema work with in-database pgrst.db_schemas setting - @wolfgangwalther
- #3644, Show number of timezones in schema cache load report - @wolfgangwalther
- #3644, List correct enum options in OpenApi output when multiple types with same name are present - @wolfgangwalther
- #3523, Fix schema cache loading retry without backoff - @steve-chavez
## [12.2.1] - 2024-06-27
### Fixed
- #3147, Don't reload schema cache on every listener failure - @steve-chavez
### Documentation
- #3592, Architecture diagram now supports dark mode and has links - @laurenceisla
- #3616, The schema isolation diagram now supports dark mode and uses well-known schemas - @laurenceisla
## [12.2.0] - 2024-06-11
### Added
-3
View File
@@ -1,3 +0,0 @@
This repository follows the same contribution guidelines as the main PostgREST repository contribution guidelines:
https://github.com/PostgREST/postgrest/blob/main/.github/CONTRIBUTING.md
@@ -1,6 +1,8 @@
# PostgREST docker hub image
# 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:3f85b7caad41a95462cf5b787d8a04604c8262cdcdf9a472b8c52ef83375fe15 AS postgrest
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 \
@@ -8,6 +10,7 @@ RUN apt-get update -y \
&& rm -rf /var/lib/apt/lists/*
COPY postgrest /usr/bin/postgrest
RUN chmod +x /usr/bin/postgrest
EXPOSE 3000
+7 -18
View File
@@ -1,8 +1,6 @@
![Logo](static/postgrest.png "Logo")
[![Donate](https://img.shields.io/badge/Donate-Patreon-orange.svg?colorB=F96854)](https://www.patreon.com/postgrest)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/postgrest)
[![Join the chat at https://gitter.im/begriffs/postgrest](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/begriffs/postgrest)
[![Docs](https://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat)](http://postgrest.org)
[![Docker Stars](https://img.shields.io/docker/pulls/postgrest/postgrest.svg)](https://hub.docker.com/r/postgrest/postgrest/)
[![Build Status](https://github.com/postgrest/postgrest/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/PostgREST/postgrest/actions?query=branch%3Amain)
@@ -24,21 +22,21 @@ API than you are likely to write from scratch.
</a>
</td>
<td align="center" valign="middle">
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/gnuhost.png">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/code-build.png">
</a>
</td>
</tr>
<tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/code-build.png">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
</a>
</td>
<td align="center" valign="middle">
@@ -46,11 +44,6 @@ API than you are likely to write from scratch.
<img width="296px" src="static/supabase.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
</a>
</td>
</tr>
</tbody>
</table>
@@ -145,11 +138,7 @@ and the [API guide](http://postgrest.org/en/stable/api.html).
## Supporting development
You can help PostgREST ongoing maintenance and development by:
- Making a regular donation through Patreon https://www.patreon.com/postgrest
- Alternatively, you can make a one-time donation via Paypal https://www.paypal.me/postgrest
You can help PostgREST ongoing maintenance and development by making a regular donation through Patreon https://www.patreon.com/postgrest
Every donation will be spent on making PostgREST better for the whole community.
+1 -1
View File
@@ -1 +1 @@
index-state: hackage.haskell.org 2024-05-17T23:41:49Z
index-state: hackage.haskell.org 2025-02-01T14:59:33Z
+25 -35
View File
@@ -3,7 +3,15 @@
, compiler ? "ghc948"
, # Commit of the Nixpkgs repository that we want to use.
nixpkgsVersion ? import nix/nixpkgs-version.nix
# It defaults to reading the inputs from flake.lock, which serves
# as a compatibility layer for non-flake builds / default.nix / shell.nix.
nixpkgsVersion ? let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
in
{
inherit (lock.nodes.nixpkgs.locked) owner repo rev;
tarballHash = lock.nodes.nixpkgs.locked.narHash;
}
, # Nix files that describe the Nixpkgs repository. We evaluate the expression
# using `import` below.
@@ -19,7 +27,7 @@ let
"postgrest";
# PostgREST source files, filtered based on the rules in the .gitignore files
# and file extensions. We want to include as litte as possible, as the files
# and file extensions. We want to include as little as possible, as the files
# added here will increase the space used in the Nix store and trigger the
# build of new Nix derivations when changed.
src =
@@ -36,9 +44,6 @@ let
allOverlays.checked-shell-script
allOverlays.gitignore
allOverlays.postgresql-libpq
allOverlays.postgresql-legacy
allOverlays.postgresql-future
allOverlays.postgis
(allOverlays.haskell-packages { inherit compiler; })
allOverlays.slocat
];
@@ -49,34 +54,28 @@ let
postgresqlVersions =
[
{ name = "postgresql-17"; postgresql = pkgs.postgresql_17.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-16"; postgresql = pkgs.postgresql_16.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-15"; postgresql = pkgs.postgresql_15.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-14"; postgresql = pkgs.postgresql_14.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-13"; postgresql = pkgs.postgresql_13.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-12"; postgresql = pkgs.postgresql_12.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-11"; postgresql = pkgs.postgresql_11.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-10"; postgresql = pkgs.postgresql_10.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
{ name = "postgresql-9_6"; postgresql = pkgs.postgresql_9_6.withPackages (p: [ p.postgis p.pg_safeupdate ]); }
];
# Dynamic derivation for PostgREST
postgrest =
pkgs.haskell.packages."${compiler}".callCabal2nix name src { };
postgrest = pkgs.lib.pipe (pkgs.haskell.packages."${compiler}".callCabal2nix name src { }) [
# To allow ghc-datasize to be used.
lib.disableLibraryProfiling
# We are never going to use dynamic haskell libraries anyway. "Dynamic" refers to how
# non-haskell deps are linked. All haskell dependencies are always statically linked.
lib.disableSharedLibraries
];
staticHaskellPackage = import nix/static.nix { inherit compiler name pkgs src; };
# Options passed to cabal in dev tools and tests
devCabalOptions =
"-f dev --test-show-detail=direct";
profiledHaskellPackages =
pkgs.haskell.packages."${compiler}".extend (_: super:
{
mkDerivation =
args:
super.mkDerivation (args // { enableLibraryProfiling = true; });
}
);
"-f dev --test-show-detail=direct --disable-shared";
inherit (pkgs.haskell) lib;
in
@@ -90,12 +89,11 @@ rec {
lib.dontCheck postgrest;
# Profiled dynamic executable.
postgrestProfiled =
lib.enableExecutableProfiling (
lib.dontHaddock (
lib.dontCheck (profiledHaskellPackages.callCabal2nix name src { })
)
);
postgrestProfiled = pkgs.lib.pipe postgrestPackage [
lib.enableExecutableProfiling
lib.enableLibraryProfiling
lib.dontHaddock
];
inherit (postgrest) env;
@@ -125,17 +123,9 @@ rec {
loadtest =
pkgs.callPackage nix/tools/loadtest.nix { inherit withTools; };
# Script for running memory tests.
memory =
pkgs.callPackage nix/tools/memory.nix { inherit postgrestProfiled withTools; };
# Utility for updating the pinned version of Nixpkgs.
nixpkgsTools =
pkgs.callPackage nix/tools/nixpkgsTools.nix { };
# Scripts for publishing new releases.
release =
pkgs.callPackage nix/tools/release { };
pkgs.callPackage nix/tools/release.nix { };
# Linting and styling tools.
style =
+7 -14
View File
@@ -1,8 +1,6 @@
# PostgREST
[![Join the chat at https://gitter.im/begriffs/postgrest](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/begriffs/postgrest)
[![Donate](https://img.shields.io/badge/Donate-Patreon-orange.svg?colorB=F96854)](https://www.patreon.com/postgrest)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/postgrest)
[![Docs](https://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat)](http://postgrest.org)
[![Build Status](https://github.com/postgrest/postgrest/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/PostgREST/postgrest/actions?query=branch%3Amain)
@@ -21,21 +19,21 @@ write from scratch.
</a>
</td>
<td align="center" valign="middle">
<a href="https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/gnuhost.png">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/neon.jpg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/neon.jpg">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/code-build.png">
</a>
</td>
</tr>
<tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/code-build.png">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/tembo.png">
</a>
</td>
<td align="center" valign="middle">
@@ -43,11 +41,6 @@ write from scratch.
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/supabase.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="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/tembo.png">
</a>
</td>
</tr>
</tbody>
</table>
@@ -66,7 +59,7 @@ The image is built from scratch using
[Nix](https://nixos.org/nixpkgs/manual/#sec-pkgs-dockerTools) instead of a
`Dockerfile`, which yields a highly secure and optimized image. This is also why
no commands are listed in the image history. See the [PostgREST
respository](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.
This does not apply to the arm64 variant, which is based on Ubuntu.
+8 -23
View File
@@ -5,35 +5,20 @@ The ER diagrams were created with https://github.com/BurntSushi/erd/.
You can go download erd from https://github.com/BurntSushi/erd/releases and then do:
```bash
./erd_static-x86-64 -i film.er -o ../_static/film.png
./erd_static-x86-64 -i ./er/film.er -o ../_static/film.png
```
The fonts used belong to the GNU FreeFont family. You can download them here: http://ftp.gnu.org/gnu/freefont/
## LaTeX
## UML
The schema structure diagram is done with LaTeX. You can use a GUI like https://www.mathcha.io/editor to create the .tex file.
The UML diagrams are created with https://plantuml.com/.
Then use this command to generate the png file.
PlantUML only creates one diagram per file.
That's why we need to create another one for dark mode.
For example, for the file [uml/arch.uml](uml/arch.uml) there's [uml/dark/arch-dark.uml](uml/dark/arch-dark.uml) which includes the first one:
```bash
postgrest-docs-render
```
LaTeX is used because it's a tweakable plain text format.
You can install the full latex suite with `nix`:
```
nix-env -iA texlive.combined.scheme-full
```
To tweak the file with a live reload environment use:
```bash
# open the pdf(zathura used as an example)
zathura db.pdf &
# live reload with entr
echo db.tex | entr pdflatex --shell-escape -halt-on-error db.tex
plantuml -tsvg uml/arch.uml -o ../../_static
plantuml -tsvg -darkmode uml/dark/arch-dark.uml -o ../../../_static
```
-71
View File
@@ -1,71 +0,0 @@
\documentclass[convert]{standalone}
\usepackage{amsmath}
\usepackage{tikz}
\usepackage{mathdots}
\usepackage{yhmath}
\usepackage{cancel}
\usepackage{color}
\usepackage{siunitx}
\usepackage{array}
\usepackage{multirow}
\usepackage{amssymb}
\usepackage{gensymb}
\usepackage{tabularx}
\usepackage{booktabs}
\usetikzlibrary{fadings}
\usetikzlibrary{patterns}
\usetikzlibrary{shadows.blur}
\usetikzlibrary{shapes}
\begin{document}
\newcommand\customScale{0.35}
\begin{tikzpicture}[x=0.75pt,y=0.75pt,yscale=-1,xscale=1, scale=\customScale, every node/.style={scale=\customScale}]
%Shape: Can [id:dp7234864758664346]
\draw [fill={rgb, 255:red, 47; green, 97; blue, 144 } ,fill opacity=1 ] (497.5,51.5) -- (497.5,255.5) .. controls (497.5,275.66) and (423.18,292) .. (331.5,292) .. controls (239.82,292) and (165.5,275.66) .. (165.5,255.5) -- (165.5,51.5) .. controls (165.5,31.34) and (239.82,15) .. (331.5,15) .. controls (423.18,15) and (497.5,31.34) .. (497.5,51.5) .. controls (497.5,71.66) and (423.18,88) .. (331.5,88) .. controls (239.82,88) and (165.5,71.66) .. (165.5,51.5) ;
%Shape: Rectangle [id:dp7384065579958246]
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (189,115) -- (252.5,115) -- (252.5,155) -- (189,155) -- cycle ;
%Shape: Rectangle [id:dp24763906430298177]
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (292,118) -- (362,118) -- (362,158) -- (292,158) -- cycle ;
%Shape: Rectangle [id:dp3775601612537265]
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (397,114) -- (467,114) -- (467,154) -- (397,154) -- cycle ;
%Shape: Rectangle [id:dp7071457022893852]
\draw [fill={rgb, 255:red, 248; green, 231; blue, 28 } ,fill opacity=1 ] (269,199) -- (397.5,199) -- (397.5,273) -- (269,273) -- cycle ;
%Straight Lines [id:da8846759047437789]
\draw (268,234) -- (226.44,155.77) ;
\draw [shift={(225.5,154)}, rotate = 422.02] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
%Straight Lines [id:da6908444738113828]
\draw (309.5,198) -- (307.6,161) ;
\draw [shift={(307.5,159)}, rotate = 447.06] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
%Straight Lines [id:da7168757864413169]
\draw (398.5,233) -- (431.72,154.84) ;
\draw [shift={(432.5,153)}, rotate = 473.03] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
%Up Down Arrow [id:dp14059754167108496]
\draw [fill={rgb, 255:red, 126; green, 211; blue, 33 } ,fill opacity=1 ] (312.5,288.5) -- (330,273) -- (347.5,288.5) -- (338.75,288.5) -- (338.75,319.5) -- (347.5,319.5) -- (330,335) -- (312.5,319.5) -- (321.25,319.5) -- (321.25,288.5) -- cycle ;
% Text Node
\draw (201,129) node [anchor=north west][inner sep=0.75pt] [align=left] {tables};
% Text Node
\draw (307,130) node [anchor=north west][inner sep=0.75pt] [align=left ] {tables};
% Text Node
\draw (414,127) node [anchor=north west][inner sep=0.75pt] [align=left] {tables};
% Text Node
\draw (300,203) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 0; green, 0; blue, 0 } ,opacity=1 ] [align=center] { \\ views \\ + \\ \ \ functions};
% Text Node
\draw (322,178) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{api}};
% Text Node
\draw (190,97) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{internal}};
% Text Node
\draw (300,99) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{private}};
% Text Node
\draw (417,101) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{core}};
% Text Node
\draw (358,306) node [anchor=north west][inner sep=0.75pt] [align=left] {REST};
\end{tikzpicture}
\end{document}
@@ -1,5 +1,7 @@
@startuml
skinparam backgroundColor transparent
package "PostgREST" {
() HTTP as HTTPAPI
HTTPAPI - [Auth]
@@ -14,11 +16,9 @@ package "PostgREST" {
[Admin] -r- () HTTPADMIN
[Config] -l- () CLI
[Config] <-l~ Listener
[Config] <-r~ Listener
HTTPADMIN -[hidden]r- CLI
Listener -[hidden]r- [Schema Cache]
Listener -[hidden]r- [Config]
[Schema Cache] -l[hidden]- [Config]
[Schema Cache] -l[hidden]- [Admin]
[Schema Cache] -l[hidden]- CLI
@@ -26,16 +26,16 @@ package "PostgREST" {
database "PostgreSQL" {
node "API schema" as API {
rectangle "Functions, Views"
}
node Authorization {
rectangle "Roles, GRANT, RLS"
}
node "API schema" as API {
rectangle "Functions, Views"
}
rectangle "Tables, extensions" as tbs
API -d- tbs
API -[hidden]l- Authorization
API -l[hidden]- Authorization
}
:user:
@@ -60,6 +60,10 @@ note bottom of ApiRequest
Parses the URL syntax
end note
note bottom of Plan
Generates internal AST
end note
note bottom of Query
Generates the SQL
end note
@@ -67,4 +71,21 @@ end note
note top of Listener
LISTEN session
end note
url of Admin is [[../references/admin_server.html#admin-server]]
url of API is [[../explanations/schema_isolation.html]]
url of Auth is [[../references/auth.html#authn]]
url of ApiRequest is [[../explanations/architecture.html#api-request]]
url of Plan is [[../explanations/architecture.html#plan]]
url of Query is [[../explanations/architecture.html#query]]
url of Authorization is [[../explanations/db_authz.html]]
url of CLI is [[../references/cli.html#cli]]
url of "Connection Pool" is [[../references/connection_pool.html]]
url of Config is [[../references/configuration.html#configuration]]
url of HTTPADMIN is [[../explanations/architecture.html#http]]
url of HTTPAPI is [[../explanations/architecture.html#http]]
url of Listener is [[../references/listener.html#listener]]
url of Proxy is [[../explanations/nginx.html]]
url of "Schema Cache" is [[../references/schema_cache.html#schema-cache]]
@enduml
+3
View File
@@ -0,0 +1,3 @@
@startuml
!include ../arch.uml
@enduml
+3
View File
@@ -0,0 +1,3 @@
@startuml
!include ../sch-iso.uml
@enduml
+29
View File
@@ -0,0 +1,29 @@
@startuml
skinparam backgroundColor transparent
skinparam linetype ortho
skinparam node {
backgroundColor transparent
borderThickness 1
}
database "PostgreSQL" {
node public {
rectangle tables_public as "tables"
}
node extensions as "**extensions**" {
}
node API as "<size:20>api" {
rectangle vf_api as "views + functions"
}
tables_public <-- vf_api
extensions <-- vf_api
}
vf_api <-[thickness=3]-> () PostgREST
@enduml
+1
View File
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 26 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

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

After

Width:  |  Height:  |  Size: 27 KiB

+4
View File
@@ -149,3 +149,7 @@ html[data-theme="dark"] .img-translucent img {
transition: background-color 0.3s;
margin-bottom: 24px;
}
.svg-container-md {
max-width: 400px;
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 B

After

Width:  |  Height:  |  Size: 156 B

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="391px" preserveAspectRatio="none" style="width:328px;height:391px;" version="1.1" viewBox="0 0 328 391" width="328px" zoomAndPan="magnify"><defs/><g><!--cluster PostgreSQL--><g id="cluster_PostgreSQL"><path d="M6,16 C6,6 158.5,6 158.5,6 C158.5,6 311,6 311,16 L311,293.59 C311,303.59 158.5,303.59 158.5,303.59 C158.5,303.59 6,303.59 6,293.59 L6,16 " fill="none" style="stroke:#E7E7E7;stroke-width:1.0;"/><path d="M6,16 C6,26 158.5,26 158.5,26 C158.5,26 311,26 311,16 " fill="none" style="stroke:#E7E7E7;stroke-width:1.0;"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="92.2305" x="112.3848" y="40.9951">PostgreSQL</text></g><!--cluster public--><g id="cluster_public"><polygon fill="none" points="30,74,40,64,153,64,153,146.29,143,156.29,30,156.29,30,74" style="stroke:#E7E7E7;stroke-width:1.0;"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="143" x2="153" y1="74" y2="64"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="30" x2="143" y1="74" y2="74"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="143" x2="143" y1="74" y2="156.29"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="47.9063" x="63.5469" y="89.9951">public</text></g><!--cluster API--><g id="cluster_API"><polygon fill="none" points="70,190.29,80,180.29,246,180.29,246,269.59,236,279.59,70,279.59,70,190.29" style="stroke:#E7E7E7;stroke-width:1.0;"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="236" x2="246" y1="190.29" y2="180.29"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="70" x2="236" y1="190.29" y2="190.29"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="236" x2="236" y1="190.29" y2="279.59"/><text fill="#FFFFFF" font-family="sans-serif" font-size="20" font-weight="bold" lengthAdjust="spacing" textLength="34.668" x="136.666" y="211.8545">api</text></g><!--entity tables_public--><g id="elem_tables_public"><rect fill="#313139" height="36.2969" rx="2.5" ry="2.5" style="stroke:#E7E7E7;stroke-width:0.5;" width="62.752" x="71.62" y="104"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="42.752" x="81.62" y="126.9951">tables</text></g><!--entity extensions--><g id="elem_extensions"><polygon fill="none" points="169.14,109,179.14,99,294.8695,99,294.8695,135.2969,284.8695,145.2969,169.14,145.2969,169.14,109" style="stroke:#E7E7E7;stroke-width:1.0;"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="284.8695" x2="294.8695" y1="109" y2="99"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="169.14" x2="284.8695" y1="109" y2="109"/><line style="stroke:#E7E7E7;stroke-width:1.0;" x1="284.8695" x2="284.8695" y1="109" y2="145.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="85.7295" x="184.14" y="131.9951">extensions</text></g><!--entity vf_api--><g id="elem_vf_api"><rect fill="#313139" height="36.2969" rx="2.5" ry="2.5" style="stroke:#E7E7E7;stroke-width:0.5;" width="144.6465" x="85.68" y="227.29"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="124.6465" x="95.68" y="250.2851">views + functions</text></g><!--entity PostgREST--><g id="elem_PostgREST"><ellipse cx="158" cy="352.59" fill="#313139" rx="8" ry="8" style="stroke:#E7E7E7;stroke-width:0.5;"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="74.6895" x="120.6553" y="382.5851">PostgREST</text></g><!--reverse link tables_public to vf_api--><g id="link_tables_public_vf_api"><path d="M110.03,146.6 C110.03,169.85 110.03,203.55 110.03,226.86 " fill="none" id="tables_public-backto-vf_api" style="stroke:#E7E7E7;stroke-width:1.0;"/><polygon fill="#E7E7E7" points="110.03,140.6,106.03,149.6,110.03,145.6,114.03,149.6,110.03,140.6" style="stroke:#E7E7E7;stroke-width:1.0;"/></g><!--reverse link extensions to vf_api--><g id="link_extensions_vf_api"><path d="M199.73,151.63 C199.73,175.24 199.73,205.18 199.73,226.88 " fill="none" id="extensions-backto-vf_api" style="stroke:#E7E7E7;stroke-width:1.0;"/><polygon fill="#E7E7E7" points="199.73,145.63,195.73,154.63,199.73,150.63,203.73,154.63,199.73,145.63" style="stroke:#E7E7E7;stroke-width:1.0;"/></g><!--link vf_api to PostgREST--><g id="link_vf_api_PostgREST"><path d="M158,269.62 C158,292.9 158,320.34 158,337.81 " fill="none" id="vf_api-PostgREST" style="stroke:#E7E7E7;stroke-width:3.0;"/><polygon fill="#E7E7E7" points="158,263.62,154,272.62,158,268.62,162,272.62,158,263.62" style="stroke:#E7E7E7;stroke-width:3.0;"/><polygon fill="#E7E7E7" points="158,343.81,162,334.81,158,338.81,154,334.81,158,343.81" style="stroke:#E7E7E7;stroke-width:3.0;"/></g><!--SRC=[KypCIyufJKbLqDFJBqxEqCqipjShpSq10000]--></g></svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

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

After

Width:  |  Height:  |  Size: 5.1 KiB

+12 -7
View File
@@ -50,7 +50,7 @@ source_suffix = ".rst"
master_doc = "index"
# This is overriden by readthedocs with the version tag anyway
version = "devel"
version = "13.0"
# To avoid repetition in <title> we set this to an empty string.
release = ""
@@ -114,7 +114,7 @@ html_theme = "sphinx_rtd_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {"display_version": False}
html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
@@ -292,15 +292,20 @@ def setup(app):
app.add_css_file("css/custom.css")
# taken from https://github.com/sphinx-doc/sphinx/blob/82dad44e5bd3776ecb6fd8ded656bc8151d0e63d/sphinx/util/requests.py#L42
user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0"
user_agent = (
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0"
)
# TODO: these pages are returning 403 right now. Verify if they can be fixed by addressing the issue:
# https://github.com/PostgREST/postgrest/issues/3544
linkcheck_ignore = [
r"https://stackoverflow.com/",
# 403 only in CI / GitHub Actions
r"https://www.patreon.com/postgrest",
r"https://blog.frankel.ch/poor-man-api",
# Odd SSL error
r"https://www.dripdepot.com",
# New GitHub UI delays comment load, so anchor fails
r"https://github.com/.*#issuecomment",
# Random 500 Internal Server Error
r"https://jwt.io",
]
# sphinx-tabs configuration
+3 -4
View File
@@ -8,9 +8,6 @@ Community Tutorials
* `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 + PostGIS API tutorial in 5 minutes <https://gis-ops.com/postgrest-postgis-api-tutorial-geospatial-api-in-5-minutes/>`_ -
In this tutorial, GIS • OPS shows how to perform PostGIS calculations through PostgREST :ref:`functions` interface.
* `"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).
@@ -37,6 +34,7 @@ Templates
Example Apps
------------
* `archtika <https://github.com/thiloho/archtika>`_ - selfhosted CMS
* `delibrium-postgrest <https://gitlab.com/delibrium/delibrium-postgrest/>`_ - example school API and front-end in Vue.js
* `ETH-transactions-storage <https://github.com/Adamant-im/ETH-transactions-storage>`_ - indexer for Ethereum to get transaction list by ETH address
* `general <https://github.com/PierreRochard/general>`_ - example auth back-end
@@ -62,6 +60,7 @@ External Notification
These are PostgreSQL bridges that propagate LISTEN/NOTIFY to external queues for further processing. This allows functions to initiate actions outside the database such as sending emails.
* `pg-notify-stdout <https://github.com/mkleczek/pg-notify-stdout>`_ - writes notifications to standard output (use in shell scripts etc.)
* `pg-notify-webhook <https://github.com/vbalasu/pg-notify-webhook>`_ - trigger webhooks from PostgreSQL's LISTEN/NOTIFY
* `pgsql-listen-exchange <https://github.com/gmr/pgsql-listen-exchange>`_ - RabbitMQ
* `postgres-websockets <https://github.com/diogob/postgres-websockets>`_ - expose web sockets for PostgreSQL's LISTEN/NOTIFY
@@ -89,7 +88,7 @@ Client-Side Libraries
* `postgrest-go <https://github.com/supabase-community/postgrest-go>`_ - Go
* `postgrest-js <https://github.com/supabase/postgrest-js>`_ - TypeScript/JavaScript
* `postgrest-kt <https://github.com/supabase-community/postgrest-kt>`_ - Kotlin
* `postgrest-py <https://github.com/supabase-community/postgrest-py>`_ - Python
* `postgrest-py <https://github.com/supabase/postgrest-py>`_ - Python
* `postgrest-rs <https://github.com/supabase-community/postgrest-rs>`_ - Rust
* `postgrest-swift <https://github.com/supabase-community/postgrest-swift>`_ - Swift
* `redux-postgrest <https://github.com/andytango/redux-postgrest>`_ - TypeScript/JS, client integrated with (React) Redux.
+18 -4
View File
@@ -6,7 +6,22 @@ This page describes the architecture of PostgREST.
Bird's Eye View
===============
.. image:: ../_static/arch.png
You can click on the components to navigate to their respective documentation.
.. container:: img-dark
.. See https://github.com/sphinx-doc/sphinx/issues/2240#issuecomment-187366626
.. raw:: html
<object width="100%" data="../_static/arch-dark.svg" type="image/svg+xml"></object>
.. container:: img-light
.. raw:: html
<object width="100%" data="../_static/arch.svg" type="image/svg+xml"></object>
Code Map
========
@@ -43,7 +58,7 @@ A request might be rejected at this level if it's invalid. For example when prov
Plan
----
Using the Schema Cache, `Plan.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Plan.hs>`_ fills in 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/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.
@@ -77,5 +92,4 @@ The HTTP server is provided by `Warp <https://aosabook.org/en/posa/warp.html>`_.
Listener
--------
`Listener.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Listener.hs>`_ is in charge of maintaining a `LISTEN session <https://www.postgresql.org/docs/current/sql-listen.html>`_
that keeps the :ref:`schema_cache` and the :ref:`in_db_config` up to date.
`Listener.hs <https://github.com/PostgREST/postgrest/blob/main/src/PostgREST/Listener.hs>`_ is in charge of the :ref:`listener`.
+1 -1
View File
@@ -15,7 +15,7 @@ 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.
You can use row-level security to flexibly restrict visibility and access for the current user. Here is an `example <https://www.2ndquadrant.com/en/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.
.. code-block:: postgres
@@ -1,6 +1,6 @@
.. _external_jwt:
.. _external_auth:
External JWT Generation
External Authentication
-----------------------
JWT from Auth0
+4 -9
View File
@@ -3,7 +3,7 @@
Installation
############
The release page has `pre-compiled binaries for macOS, Windows, Linux and FreeBSD <https://github.com/PostgREST/postgrest/releases/latest>`_ .
The release page has `pre-compiled binaries for macOS, Windows, Linux and FreeBSD <https://github.com/PostgREST/postgrest/releases/latest>`_.
The Linux binary is a static executable that can be run on any Linux distribution.
You can also use your OS package manager.
@@ -16,16 +16,11 @@ Supported PostgreSQL versions
=============================
=============== =================================
**Supported** PostgreSQL >= 9.6
**Supported** PostgreSQL >= 12
=============== =================================
PostgREST works with all PostgreSQL versions starting from 9.6.
PostgREST works with all PostgreSQL versions still `officially supported <https://www.postgresql.org/support/versioning/>`_.
.. note::
Support for PostgreSQL versions 9.6, 10 and 11 is deprecated. From this on version onwards, PostgREST will only support non-end-of-life PostgreSQL versions.
See https://www.postgresql.org/support/versioning/.
Running PostgREST
=================
@@ -190,7 +185,7 @@ When a pre-built binary does not exist for your system you can build the project
You can build PostgREST from source with `Stack <https://github.com/commercialhaskell/stack>`_. It will install any necessary Haskell dependencies on your system.
* `Install Stack <https://docs.haskellstack.org/en/stable/README/#how-to-install-stack>`_ for your platform
* `Install Stack <https://docs.haskellstack.org/en/stable/#how-to-install-stack>`_ for your platform
* Install Library Dependencies
===================== =======================================
+14 -6
View File
@@ -1,7 +1,3 @@
.. note::
This page is a work in progress.
.. _schema_isolation:
Schema Isolation
@@ -12,6 +8,18 @@ A PostgREST instance exposes all the tables, views, and functions of a single `P
It is recommended that you don't expose tables on your API schema. Instead expose views and functions which insulate the internal details from the outside world.
This allows you to change the internals of your schema and maintain backwards compatibility. It also keeps your code easier to refactor, and provides a natural way to do API versioning.
.. container:: img-translucent
.. container:: svg-container-md
.. image:: ../_static/db.png
.. container:: img-dark
.. See https://github.com/sphinx-doc/sphinx/issues/2240#issuecomment-187366626
.. raw:: html
<object width="100%" data="../_static/sch-iso-dark.svg" type="image/svg+xml"></object>
.. container:: img-light
.. raw:: html
<object width="100%" data="../_static/sch-iso.svg" type="image/svg+xml"></object>
+8 -21
View File
@@ -16,15 +16,9 @@ PostgREST Documentation
.. image:: https://img.shields.io/docker/pulls/postgrest/postgrest.svg
:target: https://hub.docker.com/r/postgrest/postgrest/
.. image:: https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg
:target: https://gitter.im/begriffs/postgrest
.. image:: https://img.shields.io/badge/Donate-Patreon-orange.svg?colorB=F96854
:target: https://www.patreon.com/postgrest
.. image:: https://img.shields.io/badge/Donate-PayPal-green.svg
:target: https://www.paypal.com/paypalme/postgrest
|
PostgREST is a standalone web server that turns your PostgreSQL database directly into a RESTful API. The structural constraints and permissions in the database determine the API endpoints and operations.
@@ -44,9 +38,6 @@ Sponsors
.. image:: ../static/cybertec.svg
:target: https://www.cybertec-postgresql.com/en/?utm_source=postgrest.org&utm_medium=referral&utm_campaign=postgrest
.. image:: ../static/gnuhost.png
:target: https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest
.. container:: img-dark
.. image:: ../static/neon-dark.jpg
@@ -57,8 +48,6 @@ Sponsors
.. image:: ../static/neon.jpg
:target: https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest
|
.. container:: img-dark
.. image:: ../static/code-build-dark.png
@@ -69,6 +58,11 @@ Sponsors
.. image:: ../static/code-build.png
:target: https://code.build/?utm_source=sponsor&utm_campaign=postgrest
|
.. image:: ../static/tembo.png
:target: https://www.tembo.io/?utm_source=sponsor&utm_campaign=postgrest
.. container:: img-dark
.. image:: ../static/supabase-dark.png
@@ -79,8 +73,8 @@ Sponsors
.. 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/tembo.png
:target: https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest
.. image:: _static/empty.png
:target: #sponsors
.. 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.
@@ -113,7 +107,7 @@ PostgREST has a focused scope. It works well with other tools like Nginx. This f
Getting Support
----------------
The project has a friendly and growing community. For discussions, use the Github `discussions page <https://github.com/PostgREST/postgrest/discussions>`_ or join our `chat room <https://gitter.im/begriffs/postgrest>`_. 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
-------------
@@ -218,19 +212,12 @@ Here are some companies that use PostgREST in production.
* `Datrium <https://www.datrium.com>`_
* `Drip Depot <https://www.dripdepot.com>`_
* `Image-charts <https://www.image-charts.com>`_
* `Moat <https://www.oracle.com/advertising/measurement/>`_
* `Netwo <https://www.netwo.io>`_
* `Nimbus <https://www.nimbusfacility.com/sg/home>`_
- See how Nimbus uses PostgREST in `Paul Copplestone's blog post <https://paul.copplest.one/blog/nimbus-tech-2019-04.html>`_.
* `OpenBooking <https://openbooking.ch>`_
* `Redsmin <https://www.redsmin.com>`_
* `Sompani <https://www.sompani.com>`_
* `Supabase <https://supabase.com>`_
.. Failing links
* `eGull <http://www.egull.co>`_
* `MotionDynamic - Fast highly dynamic video generation at scale <https://motiondynamic.tech>`_
Testimonials
------------
-6
View File
@@ -1,6 +0,0 @@
Greenplum
#########
`Greenplum <https://greenplum.org/>`_ has been reported to work by adding ``LOGIN`` to the :ref:`anonymous and user roles <roles>`.
For more details, see https://github.com/PostgREST/postgrest/issues/2021.
+8 -5
View File
@@ -3,6 +3,7 @@ api
API's
APIs
APISIX
AST
aud
Auth
auth
@@ -12,10 +13,10 @@ booleans
BOM
Bytea
Cardano
casted
cd
centric
CLI
CMS
coercible
conf
Cloudflare
@@ -27,10 +28,12 @@ CSV
durations
DDL
DOM
DSL
DevOps
dockerize
enum
Enums
Entra
eq
ETH
Ethereum
@@ -43,7 +46,6 @@ Github
Google
grantor
GraphQL
Greenplum
gte
GUC
Haskell
@@ -68,9 +70,11 @@ isdistinct
JS
js
JSON
JSPath
JWK
JWT
jwt
Keycloak
Kubernetes
localhost
login
@@ -94,10 +98,11 @@ npm
nxl
nxr
OAuth
ORM
Observability
Okta
OpenAPI
openapi
ORM
ov
parametrized
passphrase
@@ -146,8 +151,6 @@ SHA
signup
SIGUSR
sl
spreaded
Spreaded
SQL
sql
SQLSTATE
-17
View File
@@ -55,23 +55,6 @@ Metrics
Provides :ref:`metrics`.
Runtime Configuration
=====================
Provides a ``config`` endpoint that returns the runtime :ref:`configuration`.
.. code-block:: bash
curl "http://localhost:3001/config"
.. code-block::
db-aggregates-enabled = false
db-anon-role = "web_anon"
db-channel = "pgrst"
db-channel-enabled = false
...
Runtime Schema Cache
====================
+72 -103
View File
@@ -3,20 +3,20 @@
Aggregate Functions
###################
Aggregate functions allow you to summarize data by performing calculations across groups of rows. For instance, if you have an ``orders`` table that has an ``amount`` column, you could use an aggregate function to get the sum of the ``amount`` column, either for all rows, or for each group of rows that share specific values, for instance all rows that share the same ``order_date``.
PostgREST supports the following aggregate functions: ``avg()``, ``count()``, ``max()``, ``min()``, and ``sum()``.
Please refer to the `section on aggregate functions in the PostgreSQL documentation <https://www.postgresql.org/docs/current/functions-aggregate.html>`_ for a detailed explanation of these functions.
.. note::
Aggregate functions are *disabled* by default in PostgREST, as without appropriate safeguards, aggregate functions can create performance problems. See :ref:`db-aggregates-enabled` for further details.
Aggregate functions are *disabled* by default in PostgREST, because they can create performance problems without appropriate safeguards.
See :ref:`db-aggregates-enabled` for further details.
PostgREST supports the following aggregate functions: ``avg()``, ``count()``, ``max()``, ``min()``, and ``sum()``. Please refer to the `section on aggregate functions in the PostgreSQL documentation <https://www.postgresql.org/docs/current/functions-aggregate.html>`_ for a detailed explanation of these functions.
To use an aggregate function, you append the function to a value in the ``select`` parameter, like so:
To use an aggregate function, append it to a column in the ``select`` parameter, like so:
.. code-block:: bash
curl "http://localhost:3000/orders?select=amount.sum()"
With the above query, PostgREST will return a single row with a single column named ``sum`` that contains the sum of all the values in the ``amount`` column:
This will return a ``sum`` of all the values of the ``amount`` column in a single row:
.. code-block:: json
@@ -26,15 +26,29 @@ With the above query, PostgREST will return a single row with a single column na
}
]
You can use multiple aggregate functions by just adding more columns with aggregate functions to the ``select`` parameter.
You can ``select`` multiple aggregate functions at the same time (you may need to :ref:`rename them <renaming_columns>` to disambiguate).
To group by other columns, you simply add those columns to the ``select`` parameter. For instance:
.. code-block:: bash
curl "http://localhost:3000/orders?select=total_amount:amount.sum(),avg_amount:amount.avg(),total_quantity:quantity.sum()"
.. note::
Aggregate functions work alongside other PostgREST features, like :ref:`h_filter`, :ref:`json_columns`, and :ref:`ordering`.
However they are not compatible with :ref:`domain_reps` for the moment.
Additionally, PostgreSQL's ``HAVING`` clause and ordering by aggregated columns are not yet supported.
Automatic ``GROUP BY``
======================
In SQL, a ``GROUP BY`` clause is required to aggregate the selected columns.
However, PostgREST handles grouping automatically if the columns are already present in the ``select`` parameter.
For instance:
.. code-block:: bash
curl "http://localhost:3000/orders?select=amount.sum(),amount.avg(),order_date"
This will return a row for each unique value in the ``order_date`` column, with the sum and average of the ``amount`` column for all rows that share the same ``order_date``:
This will get the sum and average of the amounts grouped by each unique value in the ``order_date`` column:
.. code-block:: json
@@ -51,67 +65,55 @@ This will return a row for each unique value in the ``order_date`` column, with
}
]
.. note::
Aggregate functions work alongside other PostgREST features, like :ref:`h_filter`, :ref:`json_columns`, and :ref:`ordering`. Please note at this time aggregate functions are not compatible with :ref:`domain_reps`. Additionally, PostgreSQL's ``HAVING`` clause and ordering by aggregated columns are not yet supported.
The Case of ``count()``
===========================
The ``count()`` Aggregate
=========================
.. note::
Before the addition of aggregate functions, it was possible to count by adding ``count`` (without parentheses) to the ``select`` parameter. While this is still supported, it may be deprecated in the future, and thus use of this legacy feature is **not recommended.** Please use ``count()`` (with parentheses) instead.
Before the addition of aggregate functions, it was possible to count by adding ``count`` (without parentheses) to the ``select`` parameter.
While this is still supported, it may be deprecated in the future, and thus use of this legacy feature is **not recommended**.
Please use ``count()`` (with parentheses) instead.
``count()`` is treated specially, as it can be used without an associated column. Take for example the following query:
``count()`` is a special case because it can be used with or without an aggregated column. For example:
.. code-block:: bash
curl "http://localhost:3000/orders?select=count(),order_date"
This would return a row for each unique value in the ``order_date`` column, with the count of all rows that share the same ``order_date``:
curl "http://localhost:3000/orders?select=count(),observation_count:observation.count(),order_date"
.. code-block:: json
[
{
"count": 4,
"observation_count": 2,
"order_date": "2023-01-01"
},
{
"count": 2,
"observation_count": 1,
"order_date": "2023-01-02"
}
]
When ``count()`` is used with an associated column, its behavior is slightly different: It will return the count of all values that are not ``NULL``. This is due to how PostgreSQL itself implements the ``count()`` function.
Renaming and Casting
====================
Renaming Aggregates
-------------------
Just like with other columns, you can rename aggregated columns too. See :ref:`renaming_columns` for details.
Renaming columns is especially helpful in the context of aggregate functions, as by default a column with an aggregate function applied will take on the name of the applied aggregate function. You may want to provide a more semantically meaningful name or prevent collisions when using multiple aggregate functions of the same type.
Note that there is a difference between the result of ``count()`` and ``observation.count()``.
The former counts the whole row, while the latter counts the non ``NULL`` values of the ``observation`` column (both grouped by ``order_date``).
This is due to how PostgreSQL itself implements the ``count()`` function.
Casting Aggregates
------------------
==================
When applying an aggregate function to a column, you are able to cast both the value of the input to the aggregate function *and* the value of the output from the aggregate function. In both cases, the syntax works as described in :ref:`casting_columns`, with the only difference being the placement of the cast.
It is :ref:`possible to cast <casting_columns>` the aggregated column or the aggregate itself, or both at the same time.
Casting the Value of the Input
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Casting the Aggregated Column
-----------------------------
For instance, imagine that the ``orders`` table has a JSON column, ``order_details``, and this column contains a JSON object that has a key, ``tax_amount``. Let's say you want to get the sum of the tax amount for every order. You can use the ``->`` or ``->>`` operators to extract the value with this key (see :ref:`json_columns`), but these operators will return values of the types JSON and ``text`` respectively, and neither of these types can be used with ``sum()``.
Therefore, you will need to first cast the input value to a type that is compatible with ``sum()`` (e.g. ``numeric``). Casting the input value is done in exactly the same way as casting any other value:
For example, let's say that ``orders`` has an ``order_details`` :ref:`JSON column <json_columns>` with a ``tax_amount`` key.
We cannot sum ``tax_amount`` directly because using ``->`` or ``->>`` will return the data in ``json`` or ``text`` format.
So we need to cast it to a compatible type (e.g. ``numeric``) right before the aggregate function:
.. code-block:: bash
curl "http://localhost:3000/orders?select=order_details->tax_amount::numeric.sum()"
With this, you will receive the sum of the casted ``tax_amount`` value:
.. code-block:: json
[
@@ -120,17 +122,15 @@ With this, you will receive the sum of the casted ``tax_amount`` value:
}
]
Casting the Value of the Output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Casting the Aggregate
---------------------
Now let's return to an example involving the ``amount`` column of the ``orders`` table. Imagine that we want to get the rounded average of the ``amount`` column. One way to do this is to use the ``avg()`` aggregate function and then to cast the output value of the function to ``int``. To cast the value of the output of the function, we simply place the cast *after* the aggregate function:
For instance, if we wanted to round the average of the ``amount`` column, we could do so by casting ``avg()`` to an ``int``:
.. code-block:: bash
curl "http://localhost:3000/orders?select=amount.avg()::int"
You will then receive the rounded average as the result:
.. code-block:: json
[
@@ -139,27 +139,22 @@ You will then receive the rounded average as the result:
}
]
Of course, you can use both input and output casts at the same time, if you so desire.
Aggregates and Resource Embedding
=================================
You can group an aggregate function by an :ref:`embedded resource <resource_embedding>` and also use the aggregates inside them.
Using Aggregate Functions with Resource Embedding
=================================================
Grouping by an Embedded Resource
--------------------------------
Aggregate functions can be used in conjunction with :ref:`resource_embedding`. You can use embedded resources as grouping columns, use aggregate functions within the context of an embedded resource, or use columns from a spreaded resource as grouping columns or as inputs to aggregate functions.
Using Embedded Resources as Grouping Columns
--------------------------------------------
Using an embedded resource as a grouping column allows you to use data from an association to group the results of an aggregation.
For example, imagine that the ``orders`` table from the examples above is related to a ``customers`` table. If you want to get the sum of the ``amount`` column grouped by the ``name`` column from the ``customers`` table, you can include the customer name, using the standard :ref:`resource_embedding` syntax, and perform a sum on the ``amount`` column.
Similar to grouping by columns, aggregate functions can also be grouped by embedded resources.
For example, let's say that the ``orders`` table is related to a ``customers`` table.
To get the sum of the ``amount`` column grouped by the ``name`` column from the ``customers`` table, we would do the following:
.. code-block:: bash
curl "http://localhost:3000/orders?select=amount.sum(),customers(name)"
You will then get the summed amount, along with the embedded customer resource:
.. code-block:: json
[
@@ -177,15 +172,16 @@ You will then get the summed amount, along with the embedded customer resource:
}
]
.. note::
The previous example uses a has-one association to demonstrate this functionality, but you may also use has-many associations as grouping columns, although there are few obvious use cases for this.
The previous example uses a "to-one" relationship, but this can be done on "to-many" relationships as well (although there are few obvious use cases).
Using Aggregate Functions Within the Context of an Embedded Resource
--------------------------------------------------------------------
This also works in a similar way for :ref:`spread embedded resources <spread_embed>`.
For example, ``select=amount.sum(),...customers(name)`` would sum the ``amount`` grouped by the ``name`` column.
When embedding a resource, you can apply aggregate functions to columns from the associated resource to perform aggregations within the context of an embedded resource.
Using Aggregates Inside Embedded Resources
------------------------------------------
Continuing with the example relationship between ``orders`` and ``customers`` from the previous section, imagine that you want to fetch the ``name``, ``city``, and ``state`` for each customer, along with the sum of amount of the customer's orders, grouped by the order date. This can be done in the following way:
Using the relationship from the previous example, let's take all the ``customers`` and embed their ``orders``.
If we also want to get the total ``amount`` grouped by the ``order_date`` of the ``orders``, we would do the following:
.. code-block:: bash
@@ -226,51 +222,20 @@ Continuing with the example relationship between ``orders`` and ``customers`` fr
}
]
In this example, the ``amount`` column is summed and grouped by the ``order_date`` *within* the context of the embedded resource. That is, the ``name``, ``city``, and ``state`` from the ``customers`` table have no bearing on the aggregation performed in the context of the ``orders`` association; instead, each aggregation can be seen as being performed independently on just the orders belonging to a particular customer, using only the data from the embedded resource for both grouping and aggregation.
Note that the aggregate is done within the embedded resource ``orders``.
It is not affected by any of the columns from the top-level relationship ``customers``.
Using Columns from a Spreaded Resource
--------------------------------------
Aggregates in To-One Spreads
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When you :ref:`spread an embedded resource <spread_embed>`, the columns from the spreaded resource are treated as if they were columns of the top-level resource, both when using them as grouping columns and when applying aggregate functions to them.
Grouping with Columns from a Spreaded Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For instance, assume you want to sum the ``amount`` column from the ``orders`` table, using the ``city`` and ``state`` columns from the ``customers`` table as grouping columns. To achieve this, you may select these two columns from the ``customers`` table and spread them; they will then be used as grouping columns:
All the aggregates inside a :ref:`one-to-one or many-to-one spread embedded resource <spread_to_one_embed>` will be hoisted to the top-level relationship.
In other words, it will behave as if the aggregate was done in the top-level relationship itself. For example:
.. code-block:: bash
curl "http://localhost:3000/orders?select=amount.sum(),...customers(city,state)
curl "http://localhost:3000/orders?select=order_date,...customers(subscription_date.max(),subscription_date.min())
The result will be the same as if ``city`` and ``state`` were columns from the ``orders`` table:
.. code-block:: json
[
{
"sum": 2000.29,
"city": "New York",
"state": "NY"
},
{
"sum": 9241.21,
"city": "Los Angeles",
"state": "CA"
}
]
Aggregate Functions with Columns from a Spreaded Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now imagine that the ``customers`` table has a ``joined_date`` column that represents the date that the customer joined. You want to get both the most recent and the oldest ``joined_date`` for customers that placed an order on every distinct order date. This can be expressed as follows:
.. code-block:: bash
curl "http://localhost:3000/orders?select=order_date,...customers(joined_date.max(),joined_date.min())
As columns from a spreaded resource are treated as if they were columns from the top-level resource, the ``max()`` and ``min()`` are applied *within* the context of the top-level, rather than within the context of the embedded resource, as in the previous section.
The result will be the same as if the aggregations were applied to columns from the top-level:
This will take the ``max`` and ``min`` subscription date of every customer and group it by the ``order_date`` column:
.. code-block:: json
@@ -286,3 +251,7 @@ The result will be the same as if the aggregations were applied to columns from
"min": "2016-02-11"
}
]
.. note::
Aggregates inside to-many spreads are not supported
+35 -5
View File
@@ -3,7 +3,7 @@
Functions as RPC
================
*"A single resource can be the equivalent of a database function, with the power to abstract state changes over any number of storage items"* -- `Roy T. Fielding <http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven#comment-743>`_
*"A single resource can be the equivalent of a database function, with the power to abstract state changes over any number of storage items"* -- `Roy T. Fielding <https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven#comment-743>`_
Functions can perform any operation allowed by PostgreSQL (read data, modify data, :ref:`raise errors <raise_error>`, and even DDL operations). Every function in the :ref:`exposed schema <schemas>` and accessible by the :ref:`active database role <roles>` is executable under the :code:`/rpc` prefix.
@@ -71,6 +71,40 @@ The function parameter names match the JSON object keys in the POST case, for th
.. _function_single_json:
Functions with an array of JSON objects
----------------------------------------------
If you want to pass multiple JSON objects to a Postgres function (an array of objects), you can create a function with a parameter of type ``json`` or ``jsonb``.
Within the curl request, this JSON must be embedded in an object where they key matches the same name as the function's ``json`` or ``jsonb`` parameter.
This will allow you to loop over the array of JSON objects within the Postgres function.
This practice may allow you to reduce the number of ``curl`` requests required to accomplish a task.
For instance, assume we have created this function in the database.
.. code-block:: postgres
CREATE FUNCTION update_data(p_json jsonb)
RETURNS void AS $$
DECLARE
json_item json;
BEGIN
FOR json_item IN SELECT jsonb_array_elements(p_json) LOOP
UPDATE data_table SET data_text_column = (json_item->>'data_text')::text
WHERE data_int_column = (json_item->>'data_int')::integer;
END LOOP;
END;
$$ LANGUAGE SQL IMMUTABLE;
A ``curl`` request using the POST method would look like the following:
.. code-block:: bash
curl "http://localhost:3000/rpc/update_data" \
-X POST -H "Content-Type: application/json" \
-d '{ "p_json": [ { "data_text": "one", "data_int": "1" }, { "data_text": "two", "data_int": "2" } ] }'
Functions with a single unnamed JSON parameter
----------------------------------------------
@@ -97,10 +131,6 @@ For this the ``Content-Type: application/json`` header must be included in the r
If an overloaded function has a single ``json`` or ``jsonb`` unnamed parameter, PostgREST will call this function as a fallback provided that no other overloaded function is found with the parameters sent in the POST request.
.. warning::
Sending the JSON request body as a single argument is also possible with :ref:`Prefer: params=single-object <prefer_params>` but this method is **deprecated**.
.. _function_single_unnamed:
Functions with a single unnamed parameter
+3
View File
@@ -19,6 +19,9 @@ For extra customization, the OpenAPI output contains a "description" field for e
COMMENT ON TABLE monotremes IS
'Freakish mammals lay the best eggs for breakfast';
COMMENT ON VIEW monotremes_v IS
'Only the platypus is publicly visible';
COMMENT ON COLUMN monotremes.has_venomous_claw IS
'Sometimes breakfast is not worth it';
+60 -20
View File
@@ -12,10 +12,9 @@ The following preferences are supported.
- ``Prefer: return``. See :ref:`prefer_return`.
- ``Prefer: count``. See :ref:`prefer_count`.
- ``Prefer: resolution``. See :ref:`prefer_resolution`.
- ``Prefer: missing``. See :ref:`bulk_insert_default`.
- ``Prefer: missing``. See :ref:`prefer_missing`.
- ``Prefer: max-affected``, See :ref:`prefer_max_affected`.
- ``Prefer: tx``. See :ref:`prefer_tx`.
- ``Prefer: params``. See :ref:`prefer_params`.
.. _prefer_handling:
@@ -197,12 +196,53 @@ The ``tx`` preference can be set to specify if the :ref:`transaction <transactio
{"id": 35, "name": "Project X"}
.. _prefer_missing:
Missing
=======
When doing ``POST`` and ``PATCH`` requests, any missing columns in the payload will be inserted as ``null`` value by default. To use the ``DEFAULT`` column value instead, use the ``Prefer: missing=default`` header.
Having:
.. code-block:: postgres
create table foo (
id bigint generated by default as identity primary key
, bar text
, baz int default 100
);
A request:
.. code-block:: bash
curl "http://localhost:3000/foo?columns=id,bar,baz" \
-H "Content-Type: application/json" \
-H "Prefer: missing=default, return=representation" \
-d @- << EOF
[
{ "bar": "val1" },
{ "bar": "val2", "baz": 15 }
]
EOF
Will result in:
.. code-block:: json
[
{ "id": 1, "bar": "val1", "baz": 100 },
{ "id": 2, "bar": "val2", "baz": 15 }
]
.. _prefer_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.
@@ -225,30 +265,30 @@ To illustrate the use of this preference, consider the following scenario where
"hint": null
}
.. _prefer_params:
Single JSON object as Function Parameter
----------------------------------------
.. warning::
Using this preference is **deprecated** in favor of :ref:`function_single_json`.
:code:`Prefer: params=single-object` allows sending the JSON request body as the single argument of a :ref:`function <functions>`.
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 mult_them(param json) RETURNS int AS $$
SELECT (param->>'x')::int * (param->>'y')::int
CREATE FUNCTION test.delete_items()
RETURNS SETOF items AS $$
DELETE FROM items WHERE id < 15 RETURNING *;
$$ LANGUAGE SQL;
.. code-block:: bash
curl "http://localhost:3000/rpc/mult_them" \
-X POST -H "Content-Type: application/json" \
-H "Prefer: params=single-object" \
-d '{ "x": 4, "y": 2 }'
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
8
{
"code": "PGRST124",
"message": "Query result exceeds max-affected preference constraint",
"details": "The query affects 14 rows",
"hint": null
}
+163 -17
View File
@@ -209,18 +209,25 @@ The join table is also detected if the composite key has additional columns.
One-to-one relationships
------------------------
One-to-one relationships are detected in two ways.
One-to-one relationships are detected in two ways. (We'll use the ``films`` and ``technical_specs`` tables from the :ref:`sample film database <erd_film>` as an example).
- When the foreign key is a primary key as specified in the :ref:`sample film database <erd_film>`.
- When the foreign key has a unique constraint.
- When the foreign key is also a primary key.
.. code-block:: postgres
create table technical_specs(
film_id int references films(id) unique,
runtime time,
camera text,
sound text
film_id int references films(id) primary key
-- ...
);
- Or when the foreign key has a unique constraint.
.. code-block:: postgres
create table technical_specs(
id int primary key
, film_id int references films(id) unique
-- ...
);
.. code-block:: bash
@@ -927,7 +934,12 @@ Filters can also be applied on nested embedded resources:
.. code-block:: bash
curl "http://localhost:3000/films?select=*,roles(*,actors(*))&roles.actors.order=last_name&roles.actors.first_name=like.*Tom*"
# curl "http://localhost:3000/films?select=*,roles(*,actors(*))&roles.actors.order=last_name&roles.actors.first_name=like.*Tom*"
curl --get "http://localhost:3000/films" \
-d "select=*,roles(*,actors(*))" \
-d "roles.actors.order=last_name" \
-d "roles.actors.first_name=like.*Tom*"
The result will show the nested actors named Tom and order them by last name. Aliases can also be used instead of the resource names to filter the nested tables.
@@ -1138,14 +1150,19 @@ For example, to arrange the films in descending order using the director's last
Spread embedded resource
========================
On many-to-one and one-to-one relationships, you can "spread" the embedded resource. That is, remove the surrounding JSON object for the embedded resource columns.
You can modify the shape of the embedded resources by using the spread syntax (``...``).
.. _spread_to_one_embed:
Spread 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.
.. code-block:: bash
# curl "http://localhost:3000/films?select=title,...directors(director_last_name:last_name)&title=like.*Workers*"
curl --get "http://localhost:3000/films" \
-d "select=title,...directors(director_last_name:last_name)" \
-d "select=title,...directors(director_first_name:first_name, director_last_name:last_name)" \
-d "title=like.*Workers*"
.. code-block:: json
@@ -1153,17 +1170,148 @@ On many-to-one and one-to-one relationships, you can "spread" the embedded resou
[
{
"title": "Workers Leaving The Lumière Factory In Lyon",
"director_first_name": "Louis",
"director_last_name": "Lumière"
}
]
Note that there is no ``"directors"`` object. Also the embed columns can be aliased normally.
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:
.. _spread_to_many_embed:
Spread To-Many relationships
----------------------------
Spread on resources forming :ref:`one-to-many <one-to-many>` and :ref:`many-to-many <many-to-many>` relationships, will convert the embedded columns into correlated arrays.
.. code-block:: bash
# curl "http://localhost:3000/films?select=title,actors:roles(character,...actors(first_name,last_name))&title=like.*Lighthouse*"
curl --get "http://localhost:3000/directors" \
-d "select=first_name,...films(film_titles:title,film_years:year)" \
-d "first_name=like.Quentin*"
.. code-block:: json
[
{
"first_name": "Quentin",
"film_titles": [
"Pulp Fiction",
"Reservoir Dogs"
],
"film_years": [
1994,
1992
]
}
]
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.
Order in spread to-many
~~~~~~~~~~~~~~~~~~~~~~~
In the above example, the order of the values inside the correlated arrays is unspecified, but all the values are guaranteed to be in the same unspecified order.
You can order the correlated arrays explicitly. For example, to order by the film year:
.. code-block:: bash
curl --get "http://localhost:3000/directors" \
-d "select=first_name,...films(film_titles:title,film_years:year)" \
-d "first_name=like.Quentin*" \
-d "films.order=year"
.. code-block:: json
[
{
"first_name": "Quentin",
"film_titles": [
"Reservoir Dogs",
"Pulp Fiction"
],
"film_years": [
1992,
1994
]
}
]
.. warning::
Aliasing spreaded columns is recommended since JSON allows duplicate keys. Example:
.. code-block:: bash
curl --get "localhost:3000/projects" \
-d "select=id,name,...clients(id,name)"
.. code-block:: json
[{"id":1,"name":"Windows 7","id":1,"name":"Microsoft"},
{"id":2,"name":"Windows 10","id":1,"name":"Microsoft"},
{"id":3,"name":"IOS","id":2,"name":"Apple"},
{"id":4,"name":"OSX","id":2,"name":"Apple"},
{"id":5,"name":"Orphan","id":null,"name":null}]
This can be a problem in Javascript objects, since only the last duplicated key will be considered. To solve it do:
.. code-block:: bash
curl --get "localhost:3000/projects" \
-d "select=id,name,...clients(client_id:id,client_name:name)"
Multiple Spreads
----------------
You can use multiple spreads at any level. For example, let's spread ``technical_specs`` and ``roles`` into ``films`` and then spread ``films`` into ``directors``:
.. code-block:: bash
curl --get "http://localhost:3000/directors" \
-d "select=first_name,...films(film_titles:title,film_years:year,...technical_specs(film_runtimes:runtime),...roles(film_characters:character))" \
-d "first_name=like.Quentin*" \
-d "films.order=year" \
-d "films.roles.order=character"
.. code-block:: json
[
{
"first_name": "Quentin",
"film_titles": [
"Reservoir Dogs",
"Pulp Fiction"
],
"film_years": [
1992,
1994
],
"film_runtimes": [
"01:39:00",
"02:29:00"
]
"film_characters": [
[ "Mr. Pink", "Mr. White" ],
[ "Mia Wallace", "Vincent Vega" ]
]
}
]
Note that:
- All the ``film_*`` arrays are correlated—"Reservoir Dogs" premiered in 1992, its runtime is 1:39:00 and it has the following characters: ``[ "Mr. Pink", "Mr. White" ]``.
- The ``film_*`` arrays are ordered by ``year`` (due to ``films.order=year``).
- The bottom level array ``film_characters`` is ordered (due to ``films.roles.order=character``).
Spread a join table
-------------------
Spread can be used to move the columns of a join table in a :ref:`many-to-many <many-to-many>` to the top object. For instance, to get the ``character`` column of the ``roles`` join table into ``actors``:
.. code-block:: bash
curl --get "http://localhost:3000/films" \
-d "select=title,actors:roles(character,...actors(first_name,last_name))" \
@@ -1184,6 +1332,4 @@ You can use this to get the columns of a join table in a many-to-many relationsh
}
]
.. note::
The spread operator ``...`` is borrowed from the Javascript `spread syntax <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax>`_.
@@ -16,6 +16,32 @@ Use the Accept request header to specify the acceptable format (or formats) for
curl "http://localhost:3000/people" \
-H "Accept: application/json"
.. note::
The ordering of columns in the response isn't guaranteed to align with the order specified in the ``select`` clause. For example, with resource embedding:
.. code-block:: bash
http://localhost:3000/films?select=directors(last_name,id),title
We may get:
.. code-block:: bash
[
{
"title": "title",
"directors": {
"id": 5,
"last_name": "name"
}
}
]
This is in line with the `JSON schema spec <https://json-schema.org/draft/2020-12/json-schema-core#name-instance-data-model>`_:
*"object: An unordered set of properties mapping a string to an instance"*
.. _builtin_media:
Builtin Media Type Handlers
@@ -74,17 +100,15 @@ This returns
{ "id": 1 }
with a :code:`Content-Type: application/vnd.pgrst.object+json`.
When a singular response is requested but no entries are found, the server responds with an error message and 406 Not Acceptable status code rather than the usual empty array and 200 status:
.. code-block:: json
{
"message": "JSON object requested, multiple (or no) rows returned",
"details": "Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row",
"hint": null,
"code": "PGRST505"
"code": "PGRST116",
"message": "Cannot coerce the result to a single JSON object",
"details": "The result contains 0 rows",
"hint": null
}
.. note::
+59 -78
View File
@@ -72,7 +72,7 @@ imatch :code:`~*` ~* operator, see :ref:`pattern_matching`
in :code:`IN` one of a list of values, e.g. :code:`?a=in.(1,2,3)`
also supports commas in quoted strings like
:code:`?a=in.("hi,there","yes,you")`
is :code:`IS` checking for exact equality (null,true,false,unknown)
is :code:`IS` checking for exact equality (null,not_null,true,false,unknown)
isdistinct :code:`IS DISTINCT FROM` not equal, treating :code:`NULL` as a comparable value
fts :code:`@@` :ref:`fts` using to_tsquery
plfts :code:`@@` :ref:`fts` using plainto_tsquery
@@ -82,7 +82,7 @@ cs :code:`@>` contains e.g. :code:`?tags=cs.{example,
cd :code:`<@` contained in e.g. :code:`?values=cd.{1,2,3}`
ov :code:`&&` overlap (have points in common), e.g. :code:`?period=ov.[2017-01-01,2017-06-30]`
also supports array types, use curly braces instead of square brackets e.g.
:code: `?arr=ov.{1,3}`
:code:`?arr=ov.{1,3}`
sl :code:`<<` strictly left of, e.g. :code:`?range=sl.(1,10)`
sr :code:`>>` strictly right of
nxr :code:`&<` does not extend to the right of, e.g. :code:`?range=nxr.(1,10)`
@@ -175,25 +175,47 @@ To ensure best performance on larger data sets, an `appropriate index <https://w
Full-Text Search
~~~~~~~~~~~~~~~~
The :code:`fts` filter mentioned above has a number of options to support flexible textual queries, namely the choice of plain vs phrase search and the language used for stemming. Suppose that :code:`tsearch` is a table with column :code:`my_tsv`, of type `tsvector <https://www.postgresql.org/docs/current/datatype-textsearch.html>`_. The following examples illustrate the possibilities.
The :code:`fts` operator has a number of options to support flexible textual queries, namely the choice of plain vs phrase search and the language used for stemming.
The following examples illustrate the possibilities, assuming column :code:`my_tsv` is of type `tsvector <https://www.postgresql.org/docs/current/datatype-textsearch.html>`_.
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_tsv=fts(french).amusant"
curl --get "http://localhost:3000/people" \
-d "my_tsv=fts(french).amusant"
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_tsv=plfts.The%20Fat%20Cats"
curl --get "http://localhost:3000/people" \
-d "my_tsv=plfts.The%20Fat%20Cats"
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_tsv=not.phfts(english).The%20Fat%20Cats"
curl --get "http://localhost:3000/people" \
-d "my_tsv=not.phfts(english).The%20Fat%20Cats"
.. code-block:: bash
curl "http://localhost:3000/tsearch?my_tsv=not.wfts(french).amusant"
curl --get "http://localhost:3000/people" \
-d "my_tsv=not.wfts(french).amusant"
Using `websearch_to_tsquery` requires PostgreSQL of version at least 11.0 and will raise an error in earlier versions of the database.
.. _fts_to_tsvector:
Automatic ``tsvector`` conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If the filtered column is not of type ``tsvector``, then it will be automatically converted using `to_tsvector() <https://www.postgresql.org/docs/current/functions-textsearch.html#TEXTSEARCH-FUNCTIONS-TABLE>`_.
This allows using the ``fts`` operator on ``text`` and ``json`` types out of the box.
.. code-block:: bash
curl --get "http://localhost:3000/people" \
-d "my_text_column=fts(french).amusant"
.. code-block:: bash
curl --get "http://localhost:3000/people" \
-d "my_json_column=not.phfts(english).The%20Fat%20Cats"
.. _v_filter:
@@ -525,45 +547,6 @@ To bulk insert JSON post an array of objects having all-matching keys
]
EOF
.. _bulk_insert_default:
Bulk Insert with Default Values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Any missing columns in the payload will be inserted as ``null`` values. To use the ``DEFAULT`` column value instead, use the ``Prefer: missing=default`` header.
Having:
.. code-block:: postgres
create table foo (
id bigint generated by default as identity primary key
, bar text
, baz int default 100
);
A request:
.. code-block:: bash
curl "http://localhost:3000/foo?columns=id,bar,baz" \
-H "Content-Type: application/json" \
-H "Prefer: missing=default, return=representation" \
-d @- << EOF
[
{ "bar": "val1" },
{ "bar": "val2", "baz": 15 }
]
EOF
Will result in:
.. code-block:: json
[
{ "id": 1, "bar": "val1", "baz": 100 },
{ "id": 2, "bar": "val2", "baz": 15 }
]
.. _specify_columns:
@@ -606,7 +589,13 @@ To update a row or rows in a table, use the PATCH verb. Use :ref:`h_filter` to s
-X PATCH -H "Content-Type: application/json" \
-d '{ "category": "child" }'
Updates also support :ref:`prefer_return`, :ref:`resource_embedding` and :ref:`v_filter`.
Updates also support:
- :ref:`prefer_return`
- :ref:`resource_embedding`
- :ref:`v_filter`
- :ref:`Missing Preference <prefer_missing>`
- :ref:`specify_columns`
.. warning::
@@ -623,18 +612,34 @@ You can make an upsert with :code:`POST` and the :code:`Prefer: resolution=merge
.. code-block:: bash
curl "http://localhost:3000/employees" \
curl "http://localhost:3000/products" \
-X POST -H "Content-Type: application/json" \
-H "Prefer: resolution=merge-duplicates" \
-d @- << EOF
[
{ "id": 1, "name": "Old employee 1", "salary": 30000 },
{ "id": 2, "name": "Old employee 2", "salary": 42000 },
{ "id": 3, "name": "New employee 3", "salary": 50000 }
{ "sku": "CL2031", "name": "Existing T-shirt", "price": 35 },
{ "sku": "CL2040", "name": "Existing Hoodie", "price": 60 },
{ "sku": "AC1022", "name": "New Cap", "price": 30 }
]
EOF
By default, upsert operates based on the primary key columns, you must specify all of them. You can also choose to ignore the duplicates with :code:`Prefer: resolution=ignore-duplicates`. This works best when the primary key is natural, but it's also possible to use it if the primary key is surrogate (example: "id serial primary key"). For more details read `this issue <https://github.com/PostgREST/postgrest/issues/1118>`_.
By default, upsert operates based on the primary key columns, so you must specify all of them.
You can also choose to ignore the duplicates with :code:`Prefer: resolution=ignore-duplicates`.
Upsert works best when the primary key is natural (e.g. ``sku``).
However, it can work with surrogate primary keys (e.g. ``id serial primary key``), if you also do a :ref:`bulk_insert` with :ref:`prefer_missing`:
.. code-block:: bash
curl "http://localhost:3000/employees?colums=id,name,salary" \
-X POST -H "Content-Type: application/json" \
-H "Prefer: resolution=merge-duplicates, missing=default" \
-d @- << EOF
[
{ "id": 1, "name": "Existing employee 1", "salary": 30000 },
{ "id": 2, "name": "Existing employee 2", "salary": 42000 },
{ "name": "New employee 3", "salary": 50000 }
]
EOF
.. important::
After creating a table or changing its primary key, you must refresh PostgREST schema cache for upsert to work properly. To learn how to refresh the cache see :ref:`schema_reloading`.
@@ -700,31 +705,6 @@ Deletions also support :ref:`prefer_return`, :ref:`resource_embedding` and :ref:
Beware of accidentally deleting all rows in a table. To learn to prevent that see :ref:`block_fulltable`.
.. _limited_update_delete:
Limited Update/Delete
=====================
You can limit the amount of affected rows by :ref:`update` or :ref:`delete` with the ``limit`` query parameter. For this, you must add an explicit ``order`` on a unique column(s).
.. code-block:: bash
curl -X PATCH "/users?limit=10&order=id&last_login=lt.2020-01-01" \
-H "Content-Type: application/json" \
-d '{ "status": "inactive" }'
.. code-block:: bash
curl -X DELETE "http://localhost:3000/users?limit=10&order=id&status=eq.inactive"
If your table has no unique columns, you can use the `ctid <https://www.postgresql.org/docs/current/ddl-system-columns.html>`_ system column.
Using ``offset`` to target a different subset of rows is also possible.
.. note::
There is no native ``UPDATE...LIMIT`` or ``DELETE...LIMIT`` support in PostgreSQL; the generated query simulates that behavior and is based on `this Crunchy Data blog post <https://www.crunchydata.com/blog/simulating-update-or-delete-with-limit-in-postgres-ctes-to-the-rescue>`_.
.. raw:: html
<script type="text/javascript">
@@ -739,6 +719,7 @@ Using ``offset`` to target a different subset of rows is also possible.
'#estimated-count': 'pagination_count.html#estimated-count',
'#prefer-return-headers-only': 'preferences.html#headers-only',
'#prefer-return-representation': 'preferences.html#full',
'#bulk-insert-default': 'preferences.html#prefer-missing',
};
let willRedirectTo = redirects[hash];
+82 -2
View File
@@ -77,7 +77,7 @@ If the client included no JWT (or one without a role claim) then PostgREST switc
JWT Generation
~~~~~~~~~~~~~~
You can create a valid JWT either from inside your database (see :ref:`sql_user_management`) or via an external service (see :ref:`external_jwt`).
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`).
.. _client_auth:
@@ -156,10 +156,90 @@ You can specify the literal value as we saw earlier, or reference a filename to
jwt-secret = "@rsa.jwk.pub"
JWK ``kid`` validation
^^^^^^^^^^^^^^^^^^^^^^
PostgREST has built-in validation of the `key ID parameter <https://www.rfc-editor.org/rfc/rfc7517#section-4.5>`_, useful when working with a JWK Set.
It goes as follows:
- If the JWT contains a ``kid`` parameter, then PostgREST will look for the JWK in the :ref:`jwt-secret`.
+ If no JWK matches the same ``kid`` value (or if they do not have a ``kid``), then the token will be rejected with a :ref:`401 Unauthorized <pgrst301>` error.
+ If a JWK matches the ``kid`` value then it will validate the token against that JWK accordingly.
- If the JWT does not have a ``kid`` parameter, then PostgREST will validate the token against each JWK in the :ref:`jwt-secret`.
.. _jwt_claims_validation:
JWT Claims Validation
~~~~~~~~~~~~~~~~~~~~~
PostgREST honors the :code:`exp` claim for token expiration, rejecting expired tokens.
PostgREST honors the following `JWT claims <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4>`_:
- ``exp`` Expiration Time
- ``iat`` Issued At
- ``nbf`` Not Before
- ``aud`` :ref:`Audience <jwt_aud_validation>`
.. note::
PostgREST allows for a 30-second clock skew when validating the ``exp``, ``iat`` and ``nbf`` claims.
In other words, it gives an extra 30 seconds before the token is rejected if there is a slight discrepancy in the timestamps.
.. _jwt_aud_validation:
JWT ``aud`` Claim Validation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
PostgREST has built-in validation of the `JWT audience claim <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3>`_.
It works this way:
- If :ref:`jwt-aud` is not set (the default), PostgREST identifies with all audiences and allows the JWT for any ``aud`` claim.
- If :ref:`jwt-aud` is set to a specific audience, PostgREST will check if this audience is present in the ``aud`` claim:
+ If the ``aud`` value is a JSON string, it will match it to the :ref:`jwt-aud`.
+ If the ``aud`` value is a JSON array of strings, it will search every element for a match.
+ If the match fails or if the ``aud`` value is not a string or array of strings, then the token will be rejected with a :ref:`401 Unauthorized <pgrst303>` error.
+ If the ``aud`` key **is not present** or if its value is ``null`` or ``[]``, PostgREST will interpret this token as allowed for all audiences and will complete the request.
.. _jwt_role_extract:
JWT Role Extraction
~~~~~~~~~~~~~~~~~~~
A JSPath DSL that specifies the location of the :code:`role` key in the JWT claims. It's configured by :ref:`jwt-role-claim-key`. This can be used to consume a JWT provided by a third party service like Auth0, Okta, Microsoft Entra or Keycloak.
The DSL follows the `JSONPath <https://goessner.net/articles/JsonPath/>`_ expression grammar with extended string comparison operators. Supported operators are:
- ``==`` selects the first array element that exactly matches the right operand
- ``!=`` selects the first array element that does not match the right operand
- ``^==`` selects the first array element that starts with the right operand
- ``==^`` selects the first array element that ends with the right operand
- ``*==`` selects the first array element that contains the right operand
Usage examples:
.. code:: bash
# {"postgrest":{"roles": ["other", "author"]}}
# the DSL accepts characters that are alphanumerical or one of "_$@" as keys
jwt-role-claim-key = ".postgrest.roles[1]"
# {"https://www.example.com/role": { "key": "author" }}
# non-alphanumerical characters can go inside quotes(escaped in the config value)
jwt-role-claim-key = ".\"https://www.example.com/role\".key"
# {"postgrest":{"roles": ["other", "author"]}}
# `@` represents the current element in the array
# all the these match the string "author"
jwt-role-claim-key = ".postgrest.roles[?(@ == \"author\")]"
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::
The string comparison operators are implemented as a custom extension to the JSPath and does not strictly follow the `RFC 9535 <https://www.rfc-editor.org/rfc/rfc9535.html>`_.
JWT Security
~~~~~~~~~~~~
+59 -21
View File
@@ -135,19 +135,32 @@ To reload the configuration via signal, send a SIGUSR2 signal to the server proc
Configuration Reload with NOTIFY
--------------------------------
To reload the configuration from within the database, you can use a NOTIFY command.
To reload the configuration from within the database, you can use the ``NOTIFY`` command. See :ref:`listener`.
.. code:: postgresql
NOTIFY pgrst, 'reload config'
The ``"pgrst"`` notification channel is enabled by default. You can name the channel with :ref:`db-channel` and enable or disable it with :ref:`db-channel-enabled`.
.. _config_full_list:
List of parameters
==================
.. _admin-server-host:
admin-server-host
-----------------
=============== =======================
**Type** String
**Default** `server-host` value
**Reloadable** N
**Environment** PGRST_ADMIN_SERVER_HOST
**In-Database** `n/a`
=============== =======================
Specifies the host for the :ref:`admin_server`. Defaults to :ref:`server-host` value.
.. _admin-server-port:
admin-server-port
@@ -161,7 +174,7 @@ admin-server-port
**In-Database** `n/a`
=============== =======================
Specifies the port for the :ref:`admin_server`.
Specifies the port for the :ref:`admin_server`. Cannot be equal to :ref:`server-port`.
.. _app.settings.*:
@@ -178,6 +191,10 @@ app.settings.*
Arbitrary settings that can be used to pass in secret keys directly as strings, or via OS environment variables. For instance: :code:`app.settings.jwt_secret = "$(MYAPP_JWT_SECRET)"` will take :code:`MYAPP_JWT_SECRET` from the environment and make it available to PostgreSQL functions as :code:`current_setting('app.settings.jwt_secret')`.
When using the environment variable `PGRST_APP_SETTINGS_*` form, the remainder of the variable is used as the new name. Case is not important : :code:`PGRST_APP_SETTINGS_MY_ENV_VARIABLE=some_value` can be accessed in postgres as :code:`current_setting('app.settings.my_env_variable')`.
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.
.. _db-aggregates-enabled:
db-aggregates-enabled
@@ -298,6 +315,10 @@ db-extra-search-path
Multiple schemas can be added in a comma-separated string, e.g. ``public, extensions``.
.. important::
We default this config to ``public`` because it is the most common schema used to install PostgreSQL extensions such as :ref:`PostGIS <ww_postgis>`. You can disable this by setting this config to ``""``.
.. _db-hoisted-tx-settings:
db-hoisted-tx-settings
@@ -582,11 +603,7 @@ jwt-aud
**In-Database** pgrst.jwt_aud
=============== =================================
Specifies the `JWT audience claim <https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3>`_. If this claim is present in the client provided JWT then you must set this to the same value as in the JWT, otherwise verifying the JWT will fail.
.. warning::
Using this setting will only reject tokens with a different audience claim. Tokens **without** audience claim will still be accepted.
Specifies an audience for the JWT ``aud`` claim. See :ref:`jwt_aud_validation`.
.. _jwt-role-claim-key:
@@ -603,17 +620,7 @@ jwt-role-claim-key
*For backwards compatibility, this config parameter is also available without prefix as "role-claim-key".*
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 or Keycloak. Usage examples:
.. code:: bash
# {"postgrest":{"roles": ["other", "author"]}}
# the DSL accepts characters that are alphanumerical or one of "_$@" as keys
jwt-role-claim-key = ".postgrest.roles[1]"
# {"https://www.example.com/role": { "key": "author }}
# non-alphanumerical characters can go inside quotes(escaped in the config value)
jwt-role-claim-key = ".\"https://www.example.com/role\".key"
See :ref:`jwt_role_extract` on how to specify key paths and usage examples.
.. _jwt-secret:
@@ -696,10 +703,35 @@ log-level
log-level = "info"
# All the above plus events for development purposes are logged
# Logs connection pool events and the schema cache parsing time
log-level = "debug"
Because currently there's no buffering for logging, the levels with minimal logging(``crit/error``) will increase throughput.
.. _log-query:
log-query
---------
=============== =================================
**Type** String
**Default** "disabled"
**Reloadable** Y
**Environment** PGRST_LOG_QUERY
**In-Database** `n/a`
=============== =================================
Logs the SQL query for the corresponding request at the current :ref:`log-level`.
See :ref:`sql_query_logs`.
.. code:: bash
# Logs the main SQL query
log-query = "main-query"
# Disables logging the SQL query
log-query = "disabled"
.. _openapi-mode:
openapi-mode
@@ -813,6 +845,12 @@ server-host
* :code:`*6` - any IPv4 or IPv6 hostname, IPv6 preferred
* :code:`!6` - any IPv6 hostname
Examples:
.. code:: bash
server-host = "127.0.0.1"
.. _server-port:
server-port
@@ -856,7 +894,7 @@ server-timing-enabled
**In-Database** pgrst.server_timing_enabled
=============== =================================
Enables the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>`_ header.
Enables the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Server-Timing>`_ header.
See :ref:`server-timing_header`.
.. _server-unix-socket:
+56 -14
View File
@@ -5,6 +5,8 @@ Errors
PostgREST error messages follow the PostgreSQL error structure. It includes ``MESSAGE``, ``DETAIL``, ``HINT``, ``ERRCODE`` and will add an HTTP status code to the response.
.. _postgresql_errors:
Errors from PostgreSQL
======================
@@ -205,14 +207,6 @@ Related to the HTTP request elements.
| | | specified in the ``select`` part of the query string. |
| PGRST108 | | See :ref:`embed_filters`. |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst109: | 400 | Restricting a Deletion or an Update using limits must |
| | | include the ordering of a unique column. |
| PGRST109 | | See :ref:`limited_update_delete`. |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst110: | 400 | When restricting a Deletion or an Update using limits |
| | | modifies more rows than the maximum specified in the limit. |
| PGRST110 | | See :ref:`limited_update_delete`. |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst111: | 500 | An invalid ``response.headers`` was set. |
| | | See :ref:`guc_resp_hdrs`. |
| PGRST111 | | |
@@ -241,10 +235,6 @@ Related to the HTTP request elements.
| | | there is no many-to-one or one-to-one relationship between |
| PGRST118 | | them. |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst119: | 400 | Could not use the spread operator on the related table |
| | | because there is no many-to-one or one-to-one relationship |
| PGRST119 | | between them. |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst120: | 400 | An embedded resource can only be filtered using the |
| | | ``is.null`` or ``not.is.null`` :ref:`operators <operators>`.|
| PGRST120 | | |
@@ -257,6 +247,27 @@ Related to the HTTP request elements.
| | | ``Prefer: handling=strict``. See :ref:`prefer_handling`. |
| PGRST122 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst123: | 400 | Aggregate functions are disabled. |
| | | See :ref:`db-aggregates-enabled`. |
| PGRST123 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst124: | 400 | ``max-affected`` preference is violated. |
| | | See :ref:`prefer_max_affected`. |
| PGRST124 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst125: | 404 | Invalid path is specified in request URL. |
| | | |
| PGRST125 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst126: | 404 | Open API config is disabled but API root path is |
| | | accessed. See :ref:`openapi-mode`. |
| PGRST126 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst127: | 400 | The feature specified in the ``details`` field is not |
| | | implemented. |
| PGRST127 | | |
+---------------+-------------+-------------------------------------------------------------+
.. _pgrst2**:
@@ -290,6 +301,10 @@ Related to a :ref:`schema_cache`. Most of the time, these errors are solved by :
| | | in the ``columns`` query parameter is not found. |
| PGRST204 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst205: | 404 | Caused when the :ref:`table specified <tables_views>` in |
| | | the URI is not found. |
| PGRST205 | | |
+---------------+-------------+-------------------------------------------------------------+
.. _pgrst3**:
@@ -305,14 +320,18 @@ Related to the authentication process using JWT. You can follow the :ref:`tut1`
| | | configuration. |
| PGRST300 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst301: | 401 | Any error related to the verification of the JWT, |
| | | which means that the JWT provided is invalid in some way. |
| .. _pgrst301: | 401 | Provided JWT couldn't be decoded or it is invalid. |
| | | |
| PGRST301 | | |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst302: | 401 | Attempted to do a request without |
| | | :ref:`authentication <client_auth>` when the anonymous role |
| PGRST302 | | is disabled by not setting it in :ref:`db-anon-role`. |
+---------------+-------------+-------------------------------------------------------------+
| .. _pgrst303: | 401 | :ref:`JWT claims validation <jwt_claims_validation>` |
| | | or parsing failed. |
| PGRST303 | | |
+---------------+-------------+-------------------------------------------------------------+
.. The Internal Errors Group X** is always at the end
@@ -331,6 +350,8 @@ Internal errors. If you encounter any of these, you may have stumbled on a Postg
| PGRSTX00 | | |
+---------------+-------------+-------------------------------------------------------------+
.. _custom_errors:
Custom Errors
=============
@@ -427,3 +448,24 @@ For non standard HTTP status, you can optionally add ``status_text`` to describe
detail = '{"status":419,"status_text":"Page Expired","headers":{"X-Powered-By":"Nerd Rage"}}';
If PostgREST can't parse the JSON objects ``message`` and ``detail``, it will throw a ``PGRST121`` error. See :ref:`Errors from PostgREST<pgrst1**>`.
.. _proxy-status_header:
Proxy-Status Header
===================
For error cases, the standard `Proxy-Status <https://www.rfc-editor.org/rfc/rfc9209.html#name-the-proxy-status-http-field>`_ header is returned with the error code. The error code comes from either :ref:`PostgREST <pgrst_errors>`, :ref:`PostgreSQL <postgresql_errors>` or :ref:`Custom <custom_errors>` errors. This is useful when doing ``HEAD`` requests where the HTTP status is not descriptive enough.
For example, doing a request on a table with high count (say 30_000_000), we get:
.. code-block:: http
HEAD /table HTTP/1.1
Prefer: count=exact
.. code-block:: http
HTTP/1.1 500 Internal Server Error
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.
+60
View File
@@ -0,0 +1,60 @@
.. _listener:
Listener
########
PostgREST uses `LISTEN <https://www.postgresql.org/docs/current/sql-listen.html>`_ to reload its :ref:`Schema Cache <schema_reloading_notify>` and :ref:`Configuration <config_reloading_notify>` via `NOTIFY <https://www.postgresql.org/docs/current/sql-notify.html>`_.
This is useful in environments where you cant send SIGUSR1 or SIGUSR2 Unix Signals.
Like on cloud managed containers or on Windows systems.
.. code:: postgresql
NOTIFY pgrst, 'reload schema'; -- reload schema cache
NOTIFY pgrst, 'reload config'; -- reload config
NOTIFY pgrst; -- reload both
By default, the LISTEN channel is enabled (:ref:`db-channel-enabled`) and named ``pgrst`` (:ref:`db-channel`).
Listener on Read Replicas
=========================
The ``LISTEN`` and ``NOTIFY`` commands do not work on PostgreSQL read replicas.
Thus, if you connect PostgREST to a read replica the Listener will fail to start.
.. code:: psql
-- check if the instance is a replica
postgres=# select pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)
postgres=# LISTEN pgrst;
ERROR: cannot execute LISTEN during recovery
To work around this, you can connect the Listener to the primary while still using the :ref:`connection_pool` on the replica.
This can be done by using the standard `libpq multiple hosts <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS>`_ and `target_session_attrs <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-TARGET-SESSION-ATTRS>`_ in your :ref:`connection string <db-uri>`.
.. code:: bash
db-uri = "postgres://read_replica.host,primary.host/mydb?target_session_attrs=read-only"
This will cause the :ref:`connection_pool` to connect to the read replica host and ``LISTEN`` on the fallback primary host.
.. 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.
.. _listener_automatic_recovery:
Automatic Recovery
==================
The listener will retry reconnecting to the database if connection loss happens.
- It will retry forever with exponential backoff, with a maximum backoff time of 32 seconds between retries. Each of these attempts are :ref:`logged <pgrst_logging>`.
- Automatic recovery can be disabled by setting :ref:`db-pool-automatic-recovery` to ``false``.
- To ensure a valid state, the listener reloads the :ref:`schema_cache` and :ref:`configuration` when recovering.
+77 -9
View File
@@ -15,28 +15,70 @@ Observability allows measuring a system's current state based on the data it gen
Logs
====
PostgREST logs basic request information to ``stdout``, including the authenticated user if available, the requesting IP address and user agent, the URL requested, and HTTP response status.
PostgREST logs basic request information to ``stdout``, including the authenticated user if available, the requesting IP address and user agent, the URL requested, the HTTP response status and the response body size in bytes if available.
With :ref:`log-level` set to ``info``, we get:
.. code::
127.0.0.1 - user [26/Jul/2021:01:56:38 -0500] "GET /clients HTTP/1.1" 200 - "" "curl/7.64.0"
127.0.0.1 - anonymous [26/Jul/2021:01:56:48 -0500] "GET /unexistent HTTP/1.1" 404 - "" "curl/7.64.0"
127.0.0.1 - user [26/Jul/2021:01:56:38 -0500] "GET /clients HTTP/1.1" 200 56 "" "curl/7.64.0"
127.0.0.1 - anonymous [26/Jul/2021:01:56:48 -0500] "GET /unexistent HTTP/1.1" 404 162 "" "curl/7.64.0"
For diagnostic information about the server itself, PostgREST logs to ``stderr``. It includes the server version and also the version of the connected PostgreSQL.
For diagnostic information about the server itself, PostgREST logs to ``stderr``:
- The full version of the connected PostgreSQL database.
- :ref:`schema_cache` statistics.
- The messages received by the :ref:`listener`.
.. code::
06/May/2024:08:16:11 -0500: Starting PostgREST 12.1...
06/May/2024:08:16:11 -0500: Attempting to connect to the database...
06/May/2024:08:16:11 -0500: Successfully connected to PostgreSQL 14.10 (Ubuntu 14.10-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
06/May/2024:08:16:11 -0500: Listening on port 3000
06/May/2024:08:16:11 -0500: Connection Pool initialized with a maximum size of 10 connections
06/May/2024:08:16:11 -0500: API server listening on port 3000
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: 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:14:11:27 -0500: Received a config reload message on the "pgrst" channel
06/May/2024:14:11:27 -0500: Config reloaded
.. note::
Logs are based on the ``log-level`` setting. See :ref:`log-level`.
.. _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``.
It will be logged based on the current :ref:`log-level` setting.
For example, with this configuration:
.. code-block:: bash
log-level = "warn"
log-query = "main-query"
The SQL queries will only be logged on ``400`` HTTP errors and up.
So, if the user requests a resource without sufficient privileges:
.. code-block:: bash
curl "localhost:3000/protected_table"
This will be logged by PostgREST:
.. code::
17/Feb/2025:17:28:15 -0500: WITH pgrst_source AS ( SELECT "public"."protected_table".* FROM "public"."protected_table" ) SELECT null::bigint AS total_result_set, pg_catalog.count(_postgrest_t) AS page_total, coalesce(json_agg(_postgrest_t), '[]') AS body, nullif(current_setting('response.headers', true), '') AS response_headers, nullif(current_setting('response.status', true), '') AS response_status, '' AS response_inserted FROM ( SELECT * FROM pgrst_source ) _postgrest_t
127.0.0.1 - web_anon [17/Feb/2025:17:28:15 -0500] "GET /protected_table HTTP/1.1" 401 99 "" "curl/8.7.1"
Database Logs
-------------
Currently PostgREST doesn't log the SQL commands executed against the underlying database.
To find the SQL operations, you can watch the database logs. By default PostgreSQL does not keep these logs, so you'll need to make the configuration changes below.
Additionally, to find all the SQL operations, you can watch the database logs. By default PostgreSQL does not keep these logs, so you'll need to make the configuration changes below.
Find :code:`postgresql.conf` inside your PostgreSQL data directory (to find that, issue the command :code:`show data_directory;`). Either find the settings scattered throughout the file and change them to the following values, or append this block of code to the end of the configuration file.
@@ -194,6 +236,11 @@ You can enable tracing HTTP requests by setting :ref:`server-trace-header`. Spec
HTTP/1.1 200 OK
X-Request-Id: 123
Proxy-Status Header
-------------------
See :ref:`proxy-status_header`.
.. _server-timing_header:
Server-Timing Header
@@ -223,6 +270,27 @@ This header communicates metrics of the different phases in the request-response
We're working on lowering the duration of the ``parse`` and ``plan`` stages on https://github.com/PostgREST/postgrest/issues/2816.
.. _content-length_header:
Content-Length Header
---------------------
You can verify the response body size in bytes in the `Content-Length header <https://httpwg.org/specs/rfc9110.html#field.content-length>`_.
.. code-block:: bash
curl -i 'localhost:3000/users'
.. code-block:: http
HTTP/1.1 200 OK
Content-Length: 104
Note that this header won't be returned on ``HEAD`` requests for optimization purposes (see :ref:`head_req`).
This is in line with `RFC 9110 <https://httpwg.org/specs/rfc9110.html#field.content-length>`_.
The body size is also present in the :ref:`PostgREST logs <pgrst_logging>`.
.. _explain_plan:
Execution plan
+1 -5
View File
@@ -47,16 +47,12 @@ For docker you can do:
Schema Cache Reloading with NOTIFY
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PostgREST also allows you to reload its schema cache through PostgreSQL `NOTIFY <https://www.postgresql.org/docs/current/sql-notify.html>`_.
To reload the schema cache from within the database, you can use the ``NOTIFY`` command. See :ref:`listener`.
.. code-block:: postgres
NOTIFY pgrst, 'reload schema'
This is useful in environments where you cant send the SIGUSR1 Unix Signal. Like on cloud managed containers or on Windows systems.
The ``pgrst`` notification channel is enabled by default. For configuring the channel, see :ref:`db-channel` and :ref:`db-channel-enabled`.
.. _auto_schema_reloading:
Automatic Schema Cache Reloading
+4 -5
View File
@@ -284,11 +284,10 @@ However, starting from PostgreSQL 15, you can grant privileges for these setting
GRANT SET ON PARAMETER <setting> TO <authenticator>;
Function Settings
~~~~~~~~~~~~~~~~~
Hoisted Function Settings
~~~~~~~~~~~~~~~~~~~~~~~~~
In addition to :ref:`impersonated_settings`, PostgREST will also apply function settings as transaction-scoped settings. This allows functions settings to override
the impersonated and connection role settings.
PostgREST can "hoist" function settings to transaction-scoped settings. This allows functions settings to override the impersonated and connection role settings.
.. code-block:: postgres
@@ -303,7 +302,7 @@ When calling the above function (see :ref:`functions`), the statement timeout wi
.. note::
Only the transactions that are hoisted by config :ref:`db-hoisted-tx-settings` will be applied.
Only the settings in :ref:`db-hoisted-tx-settings` will be hoisted.
.. _main_query:
+6 -8
View File
@@ -1,9 +1,7 @@
docutils==0.20.1
sphinx-copybutton
sphinx-intl
sphinx-rtd-theme>=0.5.1
sphinx-rtd-dark-mode>=1.3.0
sphinx-tabs>=3.2.0
sphinx>=5.0.2
# This file is auto-generated by postgrest-nixpkgs-upgrade
sphinx==7.4.7
sphinx-copybutton==0.5.2
sphinx-rtd-dark-mode==1.3.0
sphinx-rtd-theme==3.0.2
sphinx-tabs==3.4.7
sphinxext-opengraph==0.9.1
urllib3==2.2.1
+13 -2
View File
@@ -28,13 +28,24 @@
pacman -S postgrest
.. tab:: Nix
.. tab:: Nix via nixpkgs
You can install PostgREST from nixpkgs.
.. code:: bash
nix-env -i haskellPackages.postgrest
nix-env -i postgrest
.. tab:: Nix via flake
You can install PostgREST via flake.
.. code:: nix
{
inputs.postgrest.url = "github:postgrest/postgrest";
# ...
}
.. group-tab:: Windows
+6 -15
View File
@@ -17,12 +17,7 @@ To make an API we'll simply be building a database. All the endpoints and permis
By the end of this tutorial you'll have a working database, PostgREST server, and a simple single-user todo list API.
Step 1. Relax, we'll help
-------------------------
As you begin the tutorial, pop open the project `chat room <https://gitter.im/begriffs/postgrest>`_ in another tab. There are a nice group of people active in the project and we'll help you out if you get stuck.
Step 2. Install PostgreSQL
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.
@@ -48,7 +43,7 @@ This will run the Docker instance as a daemon and expose port 5432 to the host s
In this case, you will need to change the **first** of the two 5432 to something else, for example to :code:`5433:5432`. Remember to also adjust the port in your config file in Step 5!
Step 3. Install PostgREST
Step 2. Install PostgREST
-------------------------
Using a Package Manager
@@ -122,7 +117,7 @@ If everything is working correctly it will print out its version and the availab
</details>
</p>
Step 4. Create Database for API
Step 3. Create Database for API
-------------------------------
Connect to the SQL console (psql) inside the container. To do so, run this from your command line:
@@ -185,7 +180,7 @@ Now quit out of psql; it's time to start the API!
\q
Step 5. Run PostgREST
Step 4. Run PostgREST
---------------------
PostgREST can use a configuration file to tell it how to connect to the database. Create a file :code:`tutorial.conf` with this inside:
@@ -218,12 +213,8 @@ You should see something similar to:
.. code-block:: text
Starting PostgREST 12.0.2...
Attempting to connect to the database...
Connection successful
Listening on port 3000
Config reloaded
Listening for notifications on the pgrst channel
Schema cache loaded
Successfully connected to PostgreSQL 14.10 (Ubuntu 14.10-0ubuntu0.22.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
API server listening on port 3000
It's now ready to serve web requests. There are many nice graphical API exploration tools you can use, but for this tutorial we'll use :code:`curl` because it's likely to be installed on your system already. Open a new terminal (leaving the one open that PostgREST is running inside). Try doing an HTTP request for the todos.
+33 -11
View File
@@ -52,17 +52,31 @@ Check that the :code:`tutorial.conf` (created in the previous tutorial) has the
If the PostgREST server is still running from the previous tutorial, restart it to load the updated configuration file.
.. _tut1_step3:
Step 3. Sign a Token
--------------------
Ordinarily your own code in the database or in another server will create and sign authentication tokens, but for this tutorial we will make one "by hand." Go to `jwt.io <https://jwt.io/#debugger-io>`_ and fill in the fields like this:
Ordinarily your own code in the database or in another server will create and sign authentication tokens, but for this tutorial we will make one "by hand" using ``bash`` and ``openssl``.
.. figure:: ../_static/tuts/tut1-jwt-io.png
:alt: jwt.io interface
.. code:: bash
How to create a token at https://jwt.io
#!/bin/bash
set -e
**Remember to fill in the secret you generated rather than the word "secret".** After you have filled in the secret and payload, the encoded data on the left will update. Copy the encoded token.
JWT_SECRET='test_secret_that_is_at_least_32_characters_long'
_base64 () { openssl base64 -e -A | tr '+/' '-_' | tr -d '='; }
header=$(echo -n '{"alg":"HS256","typ":"JWT"}' | _base64)
payload=$(echo -n "{\"role\":\"todo_user\"}" | _base64)
signature=$(echo -n "$header.$payload" | openssl dgst -sha256 -hmac "$JWT_SECRET" -binary | _base64)
echo -n "$header.$payload.$signature"
**Remember to fill in the secret you generated rather than keeping the "test_secret_that_is_at_least_32_characters_long".** After you have filled in the secret and payload, the encoded data on the left will update. Copy the encoded token.
.. note::
@@ -145,14 +159,22 @@ To observe expiration in action, we'll add an :code:`exp` claim of five minutes
select extract(epoch from now() + '5 minutes'::interval) :: integer;
Go back to jwt.io and change the payload to
Or in ``bash``:
.. code-block:: json
{
"role": "todo_user",
"exp": 123456789
}
.. code-block:: bash
exp=$(( EPOCHSECONDS + 5*60 )) # five minutes
echo $exp
Go back to :ref:`tut1_step3` and change the payload to
.. code-block:: bash
payload=$(echo -n "{\"role\":\"todo_user\",\"exp\":\"123456789\"}" | _base64)
echo -n "$header.$payload.$signature"
**NOTE**: Don't forget to change the dummy epoch value :code:`123456789` in the snippet above to the epoch value returned by the :code:`psql` command.
Generated
+27
View File
@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1731165248,
"narHash": "sha256-DiHFKIdBmMx5/DUARhVqaxvEIiy4EE6Eqs9Qs4oxme8=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a90280100f41a10914edfe729a4053e60c92b8e3",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
+50
View File
@@ -0,0 +1,50 @@
{
description = "REST API for any Postgres database";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
};
nixConfig = {
extra-substituters = "https://postgrest.cachix.org";
extra-trusted-public-keys = "postgrest.cachix.org-1:icgW4R15fz1+LqvhPjt4EnX/r19AaqxiVV+1olwlZtI=";
};
outputs = { nixpkgs, ... }:
let
systems = [
"aarch64-darwin"
"aarch64-linux"
"x86_64-darwin"
"x86_64-linux"
];
pgrstFor = system: import ./default.nix {
inherit system;
nixpkgsVersion = {
owner = "nixos";
repo = "nixpkgs";
inherit (nixpkgs) rev;
tarballHash = nixpkgs.narHash;
};
};
genSystems = f: nixpkgs.lib.genAttrs systems (system: f (pgrstFor system));
in
{
packages = genSystems (attrs: {
default = attrs.postgrestPackage;
profiled = attrs.postgrestProfiled;
} // nixpkgs.lib.optionalAttrs (attrs ? postgrestStatic) {
static = attrs.postgrestStatic;
});
apps = genSystems (attrs: {
default = {
type = "app";
program = "${attrs.postgrestStatic or attrs.postgrestPackage}/bin/postgrest";
meta.description = "REST API for any Postgres database";
};
});
};
}
+36 -30
View File
@@ -72,45 +72,53 @@ The PostgREST utilities available in `nix-shell` all have names that begin with
```bash
# Note: The utilities listed here might not be up to date.
[nix-shell]$ postgrest-<tab>
postgrest-build postgrest-test-spec
postgrest-check postgrest-watch
postgrest-clean postgrest-with-all
postgrest-coverage postgrest-with-postgresql-10
postgrest-lint postgrest-with-postgresql-11
postgrest-run postgrest-with-postgresql-12
postgrest-style postgrest-with-postgresql-13
postgrest-style-check postgrest-with-postgresql-9.6
postgrest-test-io
postgrest-build postgrest-profiled-run
postgrest-check postgrest-push-cachix
postgrest-clean postgrest-release
postgrest-coverage postgrest-repl
postgrest-coverage-draft-overlay postgrest-run
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]$
```
Some additional modules like `memory`, `docker` and `release`
have large dependencies that would need to be built before the shell becomes
The `docker` module has large dependencies to be build before the shell becomes
available, which could take an especially long time if the cachix binary cache
is not used. You can activate those by passing a flag to `nix-shell` with
`nix-shell --arg <module> true`. This will make the respective utilities available:
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 memory true
[nix-shell]$ postgrest-<tab>
postgrest-build postgrest-test-spec
postgrest-check postgrest-watch
postgrest-clean postgrest-with-all
postgrest-coverage postgrest-with-postgresql-10
postgrest-lint postgrest-with-postgresql-11
postgrest-run postgrest-with-postgresql-12
postgrest-style postgrest-with-postgresql-13
postgrest-style-check postgrest-with-postgresql-9.6
postgrest-test-io
postgrest-test-memory
$ nix-shell --arg docker true
[nix-shell]$ postgrest-docker-<tab>
postgrest-docker-load
...
```
Note that `postgrest-test-memory` is now also available.
Note that `postgrest-docker-load` is now also available.
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
@@ -371,10 +379,8 @@ that).
We also use `default.nix` to load our pinned version of the `nixpkgs`
repository. This set of packages will always be the same, independently from
where or when you use it. The pinned version can be upgraded with the small
`nixpkgs-upgrade` utility. Running `nixpkgs-upgrade > nix/nixpkgs-version.nix`
in `nix-shell` will upgrade the pinned version to the latest `nixpkgs-unstable`
version.
where or when you use it. The pinned version is taken from `flake.lock` and
can be updated with `nix flake update`.
### `shell.nix`
@@ -1,46 +0,0 @@
{ buildPythonPackage
, fetchFromGitHub
, lib
, nose
, sphinx
, sphinx-rtd-theme
}:
buildPythonPackage rec {
pname = "sphinx-rtd-dark-mode";
version = "1.3.0";
format = "setuptools";
src = fetchFromGitHub {
owner = "MrDogeBro";
repo = "sphinx_rtd_dark_mode";
rev = "refs/tags/v${version}";
hash = "sha256-N5KG2Wqn9wfGNY3VH4FnBce1aZUbnvVmwD10Loe0Qn4=";
};
propagatedBuildInputs = [
sphinx-rtd-theme
];
nativeCheckInputs = [
nose
sphinx
];
checkPhase = ''
runHook preCheck
nosetests tests
runHook postCheck
'';
pythonImportsCheck = [
"sphinx_rtd_dark_mode"
];
meta = with lib; {
description = "Adds a toggleable dark mode to the Read the Docs theme for Sphinx.";
homepage = "https://github.com/MrDogeBro/sphinx_rtd_dark_mode";
changelog = "https://github.com/MrDogeBro/sphinx_rtd_dark_mode/releases/tag/v${version}";
license = licenses.mit;
};
}
+4
View File
@@ -19,6 +19,10 @@ 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"
-8
View File
@@ -1,8 +0,0 @@
# Pinned version of Nixpkgs, generated with postgrest-nixpkgs-upgrade.
{
owner = "NixOS";
repo = "nixpkgs";
date = "2024-04-20";
rev = "92d295f588631b0db2da509f381b4fb1e74173c5";
tarballHash = "162w28y4i5c8g5qhjvs827qxphf2a8n4c8fwhcywzl1j1a35h2im";
}
-3
View File
@@ -3,9 +3,6 @@
checked-shell-script = import ./checked-shell-script;
gitignore = import ./gitignore.nix;
haskell-packages = import ./haskell-packages.nix;
postgis = import ./postgis.nix;
postgresql-libpq = import ./postgresql-libpq.nix;
postgresql-legacy = import ./postgresql-legacy.nix;
postgresql-future = import ./postgresql-future.nix;
slocat = import ./slocat.nix;
}
+23 -18
View File
@@ -48,31 +48,36 @@ let
# Before upgrading fuzzyset to 0.3, check: https://github.com/PostgREST/postgrest/issues/3329
# jailbreak, because hspec limit for tests
fuzzyset = lib.doJailbreak
(prev.callHackageDirect
{
pkg = "fuzzyset";
ver = "0.2.4";
sha256 = "sha256-lpkrTFcR0B4rT/P6x7ui31Twgq7BBj6KIvjKyqXKdpc=";
}
{ });
fuzzyset = prev.fuzzyset_0_2_4;
hasql-pool = lib.dontCheck prev.hasql-pool_1_0_1;
postgresql-libpq = lib.dontCheck
(prev.postgresql-libpq.override {
postgresql = super.libpq;
});
hasql-pool = lib.dontCheck (prev.callHackageDirect
{
pkg = "hasql-pool";
ver = "1.0.1";
sha256 = "sha256-Hf1f7lX0LWkjrb25SDBovCYPRdmUP1H6pAxzi7kT4Gg=";
}
{ });
hasql-notifications = lib.dontCheck (prev.callHackageDirect
{
pkg = "hasql-notifications";
ver = "0.2.2.0";
sha256 = "sha256-73OQ9/su2qvO7HavF3xuuNWLXSXyB9reBUQDaHys06I=";
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
{
-28
View File
@@ -1,28 +0,0 @@
final: prev:
let
postgis_3_2_3 = rec {
version = "3.2.3";
src = final.fetchurl {
url = "https://download.osgeo.org/postgis/source/postgis-${version}.tar.gz";
sha256 = "sha256-G02LXHVuWrpZ77wYM7Iu/k1lYneO7KVvpJf+susTZow=";
};
meta.broken = false;
};
in
{
postgresql_11 = prev.postgresql_11.override { this = final.postgresql_11; } // {
pkgs = prev.postgresql_11.pkgs // {
postgis = prev.postgresql_11.pkgs.postgis.overrideAttrs (_: postgis_3_2_3);
};
};
postgresql_10 = prev.postgresql_10.override { this = final.postgresql_11; } // {
pkgs = prev.postgresql_10.pkgs // {
postgis = prev.postgresql_10.pkgs.postgis.overrideAttrs (_: postgis_3_2_3);
};
};
postgresql_9_6 = prev.postgresql_9_6.override { this = final.postgresql_11; } // {
pkgs = prev.postgresql_9_6.pkgs // {
postgis = prev.postgresql_9_6.pkgs.postgis.overrideAttrs (_: postgis_3_2_3);
};
};
}
-19
View File
@@ -1,19 +0,0 @@
_: _:
# Overlay that adds future versions of PostgreSQL that are supported by
# PostgREST.
{
## Example for including a postgresql version from a specific nixpks commit:
##
# postgresql_16 =
# let
# rev = "5148520bfab61f99fd25fb9ff7bfbb50dad3c9db";
# tarballHash = "1dfjmz65h8z4lk845724vypzmf3dbgsdndjpj8ydlhx6c7rpcq3p";
#
# pinnedPkgs =
# builtins.fetchTarball {
# url = "https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz";
# sha256 = tarballHash;
# };
# in
# (import pinnedPkgs { }).pkgs.postgresql_16;
}
-49
View File
@@ -1,49 +0,0 @@
_: _:
# Overlay that adds legacy versions of PostgreSQL that are supported by
# PostgREST.
{
# PostgreSQL 9.6 was removed from Nixpkgs with
# https://github.com/NixOS/nixpkgs/commit/757dd008b2f2926fc0f7688fa8189f930ea47521
# We pin its parent commit to get the last version that was available.
postgresql_9_6 =
let
rev = "571cbf3d1db477058303cef8754fb85a14e90eb7";
tarballHash = "0q74wn418i1bn5sssacmw8ykpmqvzr0s93sj6pbs3rf6bf134fkz";
pinnedPkgs =
builtins.fetchTarball {
url = "https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz";
sha256 = tarballHash;
};
in
(import pinnedPkgs { }).pkgs.postgresql_9_6;
# PostgreSQL 10 was removed from Nixpkgs with
# https://github.com/NixOS/nixpkgs/commit/aa1483114bb329fee7e1266100b8d8921ed4723f
# We pin its parent commit to get the last version that was available.
postgresql_10 =
let
rev = "79661ba7e2fb96ebefbb537458a5bbae9dc5bd1a";
tarballHash = "0rn796pfn4sg90ai9fdnwmr10a2s835p1arazzgz46h6s5cxvq97";
pinnedPkgs =
builtins.fetchTarball {
url = "https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz";
sha256 = tarballHash;
};
in
(import pinnedPkgs { }).pkgs.postgresql_10;
# PostgreSQL 11 was removed from Nixpkgs with
# https://github.com/NixOS/nixpkgs/commit/1220a4d4dd1a4590780a5e1c18d1333a121be366
# We pin its parent commit to get the last version that was available.
postgresql_11 =
let
rev = "f5458516e42cc5cb4123cc2d93f45c240548aa18";
tarballHash = "1h03621sxfhw4z6ya74k6c2lyx3z7pvf2jcg4vs7i01yz2m6w3cv";
pinnedPkgs =
builtins.fetchTarball {
url = "https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz";
sha256 = tarballHash;
};
in
(import pinnedPkgs { }).pkgs.postgresql_11;
}
+3 -2
View File
@@ -1,6 +1,7 @@
_: super:
{
libpq = super.callPackage ../libpq.nix {
# 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;
};
});
}
+10 -7
View File
@@ -4,12 +4,8 @@
, src
}:
let
# This builds a static PostgREST exectuable based on pkgsStatic.
# pkgsStatic is based on musl, so is a kind of cross-compilation.
# We still make this explicit here via pkgsCross, because we need
# to get postgresql/libpq for musl, too.
pkgsCross = pkgs.pkgsCross.musl64;
inherit (pkgsCross) pkgsStatic;
# This builds a static PostgREST executable based on pkgsStatic.
inherit (pkgs) pkgsStatic;
inherit (pkgsStatic.haskell) lib;
packagesStatic =
@@ -25,9 +21,16 @@ let
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 = [ pkgsCross.libpq ];
libraryPkgconfigDepends = [ pkgsStatic.libpq ];
librarySystemDepends = [ ];
}).overrideAttrs (_: prevAttrs: {
buildInputs = prevAttrs.buildInputs ++ [ pkgsStatic.openssl ];
});
+31
View File
@@ -15,6 +15,7 @@ let
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-update
exec ${cabal-install}/bin/cabal v2-build ${devCabalOptions} "''${_arg_leftovers[@]}"
'';
@@ -59,6 +60,35 @@ let
postgrest "''${_arg_leftovers[@]}"
'';
runProfiled =
checkedShellScript
{
name = "postgrest-profiled-run";
docs = "Run a profiled build of postgREST. This will generate a postgrest.prof file that can be used to do optimization.";
args =
[
"ARG_USE_ENV([PGRST_DB_ANON_ROLE], [postgrest_test_anonymous], [PostgREST anonymous role])"
"ARG_USE_ENV([PGRST_DB_POOL], [1], [PostgREST pool size])"
"ARG_USE_ENV([PGRST_DB_POOL_ACQUISITION_TIMEOUT], [1], [PostgREST pool timeout])"
"ARG_USE_ENV([PGRST_JWT_SECRET], [reallyreallyreallyreallyverysafe], [PostgREST JWT secret])"
"ARG_LEFTOVERS([PostgREST arguments])"
];
workingDir = "/";
withEnv = postgrest.env;
}
''
export PGRST_DB_ANON_ROLE
export PGRST_DB_POOL
export PGRST_DB_POOL_ACQUISITION_TIMEOUT
export PGRST_JWT_SECRET
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal --builddir="dist-prof" v2-build --enable-profiling --disable-shared exe:postgrest
${cabal-install}/bin/cabal --builddir="dist-prof" v2-run -- \
postgrest +RTS -p -h -RTS "''${_arg_leftovers[@]}"
'';
repl =
checkedShellScript
{
@@ -80,6 +110,7 @@ buildToolbox
build
clean
run
runProfiled
repl;
};
}
+13 -3
View File
@@ -246,6 +246,7 @@ let
}
''
mkdir -p "$_arg_dumpdir"
${cabal-install}/bin/cabal v2-update
${cabal-install}/bin/cabal v2-build ${devCabalOptions} \
--builddir="$tmpdir" \
--ghc-option=-ddump-minimal-imports \
@@ -333,20 +334,29 @@ let
checkedShellScript
{
name = "postgrest-gen-jwt";
docs = "Generate a JWT";
docs = ''
Generate a JWT. Example: postgrest-gen-jwt --exp 10 postgrest_test_author
# This can be used to quickly prove a JWT expiry
$ curl localhost:3000/authors_only -H "Authorization: Bearer \$(postgrest-gen-jwt --exp -31 postgrest_test_author)"
'';
args = [
"ARG_POSITIONAL_SINGLE([role], [role for the jwt payload])"
"ARG_OPTIONAL_SINGLE([secret],, [secret used to sign the JWT], [reallyreallyreallyreallyverysafe])"
"ARG_OPTIONAL_SINGLE([exp],, [seconds for JWT expiry, it accepts negative values], [3600])"
];
}
''
# From https://stackoverflow.com/questions/59002949/how-to-create-a-json-web-token-jwt-using-openssl-shell-commands
# Based on https://stackoverflow.com/questions/59002949/how-to-create-a-json-web-token-jwt-using-openssl-shell-commands
# Construct the header
jwt_header=$(echo -n '{"alg":"HS256","typ":"JWT"}' | base64 | sed s/\+/-/g | sed 's/\//_/g' | sed -E s/=+$//)
# Construct the exp value
expiry=$((EPOCHSECONDS + _arg_exp))
# Construct the payload
payload=$(echo -n "{\"role\":\"$_arg_role\"}" | base64 | sed s/\+/-/g |sed 's/\//_/g' | sed -E s/=+$//)
payload=$(echo -n "{\"role\": \"$_arg_role\", \"exp\": $expiry}" | base64 | sed s/\+/-/g |sed 's/\//_/g' | sed -E s/=+$//)
# Convert secret to hex
hexsecret=$(echo -n "$_arg_secret" | xxd -p | paste -sd "")
+33 -38
View File
@@ -2,25 +2,40 @@
, aspellDicts
, buildToolbox
, checkedShellScript
, imagemagick
, fetchPypi
, lib
, plantuml
, python3
, python3Packages
, texlive
, writeTextFile
, writers
, plantuml
}:
let
selectPythonPackages = ps: [
ps.sphinx
ps.sphinx_rtd_theme
ps.livereload
ps.sphinx-tabs
ps.sphinx-copybutton
ps.sphinxext-opengraph
(ps.callPackage ../docs-extensions/sphinx-rtd-dark-mode.nix { })
# TODO: Remove override once new sphinx-intl version (> 2.1.0) is released and available in nixpkgs
(ps.sphinx-intl.overrideAttrs (drv: { nativeBuildInputs = drv.nativeBuildInputs ++ [ ps.six ]; }))
];
selectPythonPackages = ps:
let
# TODO: Remove with next nixpkgs update
sphinx-rtd-theme = assert ps.sphinx-rtd-theme.version == "2.0.0"; ps.sphinx-rtd-theme.overrideAttrs rec {
version = "3.0.2";
src = fetchPypi {
pname = "sphinx_rtd_theme";
inherit version;
hash = "sha256-t0V7wl3acjsgsIamcLmVPIWeq2CioD7o6yuyPhduX4U=";
};
};
in
[
ps.sphinx
ps.sphinx-copybutton
(ps.sphinx-rtd-dark-mode.override { inherit sphinx-rtd-theme; })
sphinx-rtd-theme
ps.sphinx-tabs
ps.sphinxext-opengraph
];
requirements = writeTextFile {
name = "requirements.txt";
text = lib.concatMapStringsSep "\n" (pkg: "${pkg.pname}==${pkg.version}") (selectPythonPackages python3Packages);
};
python = python3.withPackages selectPythonPackages;
@@ -61,42 +76,21 @@ let
'';
render =
let
pdflatex = texlive.combine {
inherit (texlive)
amsmath
booktabs
cancel
gensymb
mathdots
multirow
pgf
pgf-blur
scheme-basic
siunitx
standalone
yhmath
;
};
in
checkedShellScript
{
name = "postgrest-docs-render";
docs = "Render the diagrams.";
workingDir = "/docs/_diagrams";
withTmpDir = true;
}
''
${pdflatex}/bin/pdflatex -halt-on-error -output-directory="$tmpdir" db.tex
${imagemagick}/bin/convert -density 300 "$tmpdir/db.pdf" ../_static/db.png
${plantuml}/bin/plantuml arch.uml -o ../_static
${plantuml}/bin/plantuml -tsvg uml/*.uml -o ../../_static
${plantuml}/bin/plantuml -tsvg -darkmode uml/dark/*.uml -o ../../../_static
'';
server =
writers.writePython3
"postgrest-docs-server"
{ libraries = selectPythonPackages python3Packages; }
{ libraries = selectPythonPackages python3Packages ++ [ python3Packages.livereload ]; }
''
import sys
from livereload import Server, shell
@@ -206,4 +200,5 @@ buildToolbox
serve
spellcheck;
};
extra = { inherit requirements; };
}
+94
View File
@@ -0,0 +1,94 @@
# generates a file to be used by the vegeta load testing tool
import time
import hmac
import hashlib
import base64
import json
import argparse
import sys
import random
SECRET = b"reallyreallyreallyreallyverysafe"
URL = "http://postgrest"
JWT_DURATION = 120
TOTAL_TARGETS = 50000 # tuned by hand to reduce result variance
def base64url_encode(data: bytes) -> str:
"""URL-safe Base64 encode without padding."""
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")
def generate_jwt(exp_inc: int) -> str:
"""Generate an HS256 JWT"""
# Header & payload
header = {"alg": "HS256", "typ": "JWT"}
now = int(time.time())
payload = {
"sub": f"user_{random.getrandbits(32)}",
"iat": now,
"exp": now + exp_inc,
"role": "postgrest_test_author",
}
# Encode to JSON and then to Base64URL
header_b = json.dumps(header, separators=(",", ":")).encode()
payload_b = json.dumps(payload, separators=(",", ":")).encode()
header_b64 = base64url_encode(header_b)
payload_b64 = base64url_encode(payload_b)
# Sign (HMACSHA256) the "<header>.<payload>" string
signing_input = f"{header_b64}.{payload_b64}".encode()
signature = hmac.new(SECRET, signing_input, hashlib.sha256).digest()
signature_b64 = base64url_encode(signature)
return f"{header_b64}.{payload_b64}.{signature_b64}"
# We want to ensure 401 Unauthorized responses don't happen during
# JWT validation, this can happen when the jwt `exp` is too short.
# At the same time, we want to ensure the `exp` is not too big,
# so expires will occur and postgREST will have to clean cached expired JWTs.
def estimate_adequate_jwt_exp_increase(iteration: int) -> int:
# estimated time takes to build and run postgrest itself
build_run_postgrest_time = 2
# estimated time it takes to generate the targets file
file_generation_time = TOTAL_TARGETS // (10**-5)
# estimated exp time so some JWTs will expire
dynamic_exp_inc = iteration // 1000
return build_run_postgrest_time + file_generation_time + dynamic_exp_inc
def main():
parser = argparse.ArgumentParser(
description="Generate Vegeta targets with unique JWTs"
)
parser.add_argument(
"output",
help="Path to write the generated targets file",
)
args = parser.parse_args()
lines = []
start_time = time.time()
for i in range(TOTAL_TARGETS):
token = generate_jwt(estimate_adequate_jwt_exp_increase(i))
lines.append(f"OPTIONS {URL}/authors_only")
lines.append(f"Authorization: Bearer {token}")
lines.append("") # blank line to separate requests
try:
with open(args.output, "w") as f:
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 {TOTAL_TARGETS} targets in {args.output} ({elapsed:.2f}s)")
if __name__ == "__main__":
main()
+32 -9
View File
@@ -41,6 +41,8 @@ let
args = [
"ARG_OPTIONAL_SINGLE([output], [o], [Filename to dump json output to], [./loadtest/result.bin])"
"ARG_OPTIONAL_SINGLE([testdir], [t], [Directory to load tests and fixtures from], [./test/load])"
"ARG_OPTIONAL_SINGLE([kind], [k], [Kind of loadtest (mixed: repeat mixed requests, jwt: run once over many requests with unique jwts)], [mixed])"
"ARG_TYPE_GROUP_SET([KIND], [KIND], [kind], [mixed,jwt])"
"ARG_LEFTOVERS([additional vegeta arguments])"
];
workingDir = "/";
@@ -55,17 +57,36 @@ let
export PGRST_DB_POOL="1"
export PGRST_DB_TX_END="rollback-allow-override"
export PGRST_LOG_LEVEL="crit"
export PGRST_JWT_SECRET="reallyreallyreallyreallyverysafe"
export PGRST_JWT_CACHE_MAX_LIFETIME="86400"
mkdir -p "$(dirname "$_arg_output")"
abs_output="$(realpath "$_arg_output")"
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withSlowPg} \
${withTools.withPgrst} \
${withTools.withSlowPgrst} \
sh -c "cd \"$_arg_testdir\" && ${runner} -targets targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
${vegeta}/bin/vegeta report -type=text "$_arg_output"
case "$_arg_kind" in
jwt)
${genTargets} "$_arg_testdir"/gen_targets.http
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withPgrst} \
sh -c "cd \"$_arg_testdir\" && ${runner} -lazy -targets gen_targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
${vegeta}/bin/vegeta report -type=text "$_arg_output"
;;
*)
# shellcheck disable=SC2145
${withTools.withPg} -f "$_arg_testdir"/fixtures.sql \
${withTools.withSlowPg} \
${withTools.withPgrst} \
${withTools.withSlowPgrst} \
sh -c "cd \"$_arg_testdir\" && ${runner} -targets targets.http -output \"$abs_output\" \"''${_arg_leftovers[@]}\""
${vegeta}/bin/vegeta report -type=text "$_arg_output"
;;
esac
'';
loadtestAgainst =
@@ -83,6 +104,7 @@ let
'';
args = [
"ARG_POSITIONAL_INF([target], [Commit-ish reference to compare with], 1)"
"ARG_OPTIONAL_SINGLE([kind], [k], [Kind of loadtest], [mixed])"
];
positionalCompletion =
''
@@ -106,7 +128,7 @@ let
# Save the results in the current working tree, too,
# otherwise they'd be lost in the temporary working tree
# created by withTools.withGit.
${withTools.withGit} "$tgt" ${loadtest} --output "$PWD/loadtest/$tgt.bin" --testdir "$PWD/test/load"
${withTools.withGit} "$tgt" ${loadtest} -k "$_arg_kind" --output "$PWD/loadtest/$tgt.bin" --testdir "$PWD/test/load"
cat << EOF
@@ -122,7 +144,7 @@ let
EOF
${loadtest} --output "$PWD/loadtest/head.bin" --testdir "$PWD/test/load"
${loadtest} -k "$_arg_kind" --output "$PWD/loadtest/head.bin" --testdir "$PWD/test/load"
cat << EOF
@@ -178,6 +200,7 @@ let
| ${toMarkdown}
'';
genTargets = writers.writePython3 "postgrest-gen-loadtest-targets" { } (builtins.readFile ./generate_targets.py);
in
buildToolbox {
name = "postgrest-loadtest";
-51
View File
@@ -1,51 +0,0 @@
# The memory tests have large dependencies (a profiled build of PostgREST)
# and are run less often than the spec tests, so we don't include them in
# the default test environment. We make them available through a separate module.
# TODO both of these require reentering the nix-shell if you make a change to the code
{ buildToolbox
, checkedShellScript
, curl
, postgrestProfiled
, withTools
}:
let
test =
checkedShellScript
{
name = "postgrest-test-memory";
docs = "Run the memory tests.";
workingDir = "/";
withPath = [ postgrestProfiled curl ];
}
''
${withTools.withPg} -f test/spec/fixtures/load.sql test/memory/memory-tests.sh
'';
runProfiled =
checkedShellScript
{
name = "postgrest-profiled-run";
docs = "Run a profiled build of postgREST. This will generate a postgrest.prof file that can be used to do optimization. Note: if you make a change to the code, you must reenter the nix-shell for an updated profiled build.";
args =
[
"ARG_USE_ENV([PGRST_DB_ANON_ROLE], [postgrest_test_anonymous], [PostgREST anonymous role])"
"ARG_USE_ENV([PGRST_DB_POOL], [1], [PostgREST pool size])"
"ARG_USE_ENV([PGRST_DB_POOL_ACQUISITION_TIMEOUT], [1], [PostgREST pool timeout])"
"ARG_LEFTOVERS([PostgREST arguments])"
];
workingDir = "/";
withPath = [ postgrestProfiled ];
}
''
export PGRST_DB_ANON_ROLE
export PGRST_DB_POOL
export PGRST_DB_POOL_ACQUISITION_TIMEOUT
postgrest +RTS -p -h -RTS "''${_arg_leftovers[@]}"
'';
in
buildToolbox
{
name = "postgrest-memory";
tools = { inherit test runProfiled; };
}

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