Compare commits

..

38 Commits

Author SHA1 Message Date
Kendell Joseph
501022991f feat: updates exist operator to retrieve null as a value that exists when flag is enabled 2024-03-01 16:44:54 -05:00
Kendell Joseph
53600c7352 feat: adds flag for null field values using the mongoose adapter 2024-03-01 16:42:19 -05:00
Kendell Joseph
76c1b23729 chore: send config to sanitize step 2024-03-01 16:41:28 -05:00
dependabot[bot]
8104fac5ed chore(deps): bump ip from 2.0.0 to 2.0.1 in /examples/whitelabel (#5128)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:25:00 -05:00
dependabot[bot]
59ef1263a5 chore(deps): bump ip from 2.0.0 to 2.0.1 in /examples/auth/payload (#5134)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:24:53 -05:00
dependabot[bot]
813e3dbc98 chore(deps): bump ip from 2.0.0 to 2.0.1 in /examples/redirects/payload (#5138)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:24:45 -05:00
dependabot[bot]
12a23092e1 chore(deps): bump ip from 1.1.8 to 1.1.9 in /examples/email (#5127)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.8 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.8...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:24:23 -05:00
dependabot[bot]
4a49beb552 chore(deps): bump ip from 2.0.0 to 2.0.1 in /templates/blank (#5129)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:24:14 -05:00
dependabot[bot]
80530c666e chore(deps): bump ip from 2.0.0 to 2.0.1 in /examples/multi-tenant (#5130)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:24:09 -05:00
dependabot[bot]
f53e2df951 chore(deps): bump ip from 2.0.0 to 2.0.1 in /templates/website (#5131)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:24:01 -05:00
dependabot[bot]
db58e2bab2 chore(deps): bump ip from 2.0.0 to 2.0.1 in /examples/custom-server (#5132)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:23:56 -05:00
dependabot[bot]
d88e97e123 chore(deps): bump ip in /examples/draft-preview/payload (#5133)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:23:48 -05:00
dependabot[bot]
bb72e506e6 chore(deps): bump ip from 2.0.0 to 2.0.1 in /examples/testing (#5135)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:23:40 -05:00
dependabot[bot]
b1f727fd6a chore(deps): bump ip in /examples/live-preview/payload (#5136)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:23:33 -05:00
dependabot[bot]
72af18229b chore(deps): bump ip in /examples/form-builder/payload (#5137)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:23:27 -05:00
dependabot[bot]
af52b526c8 chore(deps): bump ip in /examples/nested-docs/payload (#5139)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:23:17 -05:00
dependabot[bot]
60525623bf chore(deps): bump ip from 2.0.0 to 2.0.1 in /examples/hierarchy (#5140)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:23:11 -05:00
dependabot[bot]
0fba582926 chore(deps): bump ip from 2.0.0 to 2.0.1 in /templates/ecommerce (#5126)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-26 11:22:49 -05:00
Elliot DeNolf
5d1cad3adb chore(release): db-postgres/0.7.0 [skip ci] 2024-02-23 14:31:55 -05:00
Elliot DeNolf
e31f72da8e chore(release): plugin-nested-docs/1.0.12 [skip ci] 2024-02-23 14:31:26 -05:00
Elliot DeNolf
7aa058d604 chore(release): db-mongodb/1.4.3 [skip ci] 2024-02-23 14:31:11 -05:00
Elliot DeNolf
64e80d242e chore(release): payload/2.11.2 [skip ci] 2024-02-23 14:29:37 -05:00
Dan Ribbens
e8f2ca484e feat(db-postgres): configurable custom schema to use (#5047)
* feat(db-postgres): configurable custom schema to use

* test(db-postgres): use public schema

* chore(db-postgres): simplify drop schema

* chore: add postgres-custom-schema test to ci

* chore: add custom schema to postgres ci

* chore(db-postgres): custom schema in migrate

* chore: ci postgres wait condition
2024-02-23 12:48:06 -05:00
Dan Ribbens
ceca5c4e97 fix(db-postgres): set _parentID for array nested localized fields (#5117)
* fix(db-postgres): find missing path for nested arrays

* fix(db-postgres): set _parentID for array nested localized fields

* fix: afterRead fallbackLocale causing locale data loss

* chore(richtext-lexical): updated args to match payload type change

* test: simplify localization e2e duplicate
2024-02-23 12:44:30 -05:00
Dan Ribbens
ee13736288 chore(plugin-nested-docs): payload added to peerDependencies (#5143) 2024-02-23 12:37:42 -05:00
Dan Ribbens
815bdfac0b fix(db-mongodb): unique sparse for not required fields (#5114)
* fix(db-mongodb): unique sparse for not required fields

* chore(db-mongodb): cleanup sparse index condition

* test: indexed field fix
2024-02-23 12:36:34 -05:00
Dan Ribbens
7a7f0ed7e8 fix: disabling API Key does not remove the key (#5145)
* fix: disabling API Key does not remove the key

* chore: encryptKey hook return null

* chore: fix auth e2e test setup
2024-02-23 12:31:14 -05:00
Dan Ribbens
ad42d541b3 fix: transaction error from access endpoint (#5156)
* fix: transaction error from access endpoint

* chore: fix async race condition in getEntityPolicies
2024-02-23 12:28:43 -05:00
Elliot DeNolf
32ed95e1ee fix: handle thrown errors in config-level afterError hook (#5147) 2024-02-21 16:44:16 -05:00
Yunsup Sim
70e57fef18 fix: Add Context Provider in EditMany Component (#5005)
* fix: Add  Context Provider in EditMany Component

* test: Fix e2e test error
2024-02-21 16:39:34 -05:00
Jarrod Flesch
0a07f607b9 fix: only replace the drawer content with full edit component if it exists (#5144) 2024-02-21 15:44:09 -05:00
Piotr Rogowski
3918fc7c21 chore(plugin-seo): add pl translations (#5021) 2024-02-21 15:01:38 -05:00
Martin Chełminiak
13f71ac475 chore: console error for missing script when running npm run payload (#5078) 2024-02-19 10:13:50 -05:00
Ben Regenspan
07720e777a docs: Reword Hooks Overview re: server-only execution (#5070) 2024-02-19 09:56:55 -05:00
Sondre Ørland
efff47e400 chore: translation for image cropping in norwegian bokmål (#5113) 2024-02-19 09:47:32 -05:00
Elliot DeNolf
453ac218ea chore: reorder changelog 2024-02-17 01:38:13 -05:00
Elliot DeNolf
d4b09bd9cd chore(release): richtext-lexical/0.7.0 [skip ci] 2024-02-16 15:00:13 -05:00
Elliot DeNolf
dd67e03fc1 chore(release): plugin-search/1.1.0 [skip ci] 2024-02-16 15:00:03 -05:00
84 changed files with 780 additions and 364 deletions

View File

@@ -85,7 +85,7 @@ jobs:
strategy:
fail-fast: false
matrix:
database: [ mongoose, postgres, postgres-uuid, supabase ]
database: [mongoose, postgres, postgres-custom-schema, postgres-uuid, supabase]
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
@@ -123,7 +123,7 @@ jobs:
postgresql db: ${{ env.POSTGRES_DB }}
postgresql user: ${{ env.POSTGRES_USER }}
postgresql password: ${{ env.POSTGRES_PASSWORD }}
if: matrix.database == 'postgres' || matrix.database == 'postgres-uuid'
if: startsWith(matrix.database, 'postgres')
- name: Install Supabase CLI
uses: supabase/setup-cli@v1
@@ -139,14 +139,19 @@ jobs:
- name: Wait for PostgreSQL
run: sleep 30
if: matrix.database == 'postgres' || matrix.database == 'postgres-uuid'
if: startsWith(matrix.database, 'postgres')
- name: Configure PostgreSQL
run: |
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE ROLE runner SUPERUSER LOGIN;"
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "SELECT version();"
echo "POSTGRES_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV
if: matrix.database == 'postgres' || matrix.database == 'postgres-uuid'
if: startsWith(matrix.database, 'postgres')
- name: Configure PostgreSQL with custom schema
run: |
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE SCHEMA custom;"
if: matrix.database == 'postgres-custom-schema'
- name: Configure Supabase
run: |

View File

@@ -1,10 +1,24 @@
## [2.11.2](https://github.com/payloadcms/payload/compare/v2.11.1...v2.11.2) (2024-02-23)
### Features
* **db-postgres:** configurable custom schema to use ([#5047](https://github.com/payloadcms/payload/issues/5047)) ([e8f2ca4](https://github.com/payloadcms/payload/commit/e8f2ca484ee56cd7767d5111e46ebd24752ff8de))
### Bug Fixes
* Add Context Provider in EditMany Component ([#5005](https://github.com/payloadcms/payload/issues/5005)) ([70e57fe](https://github.com/payloadcms/payload/commit/70e57fef184f7fcf56344ea755465f246f2253a5))
* **db-mongodb:** unique sparse for not required fields ([#5114](https://github.com/payloadcms/payload/issues/5114)) ([815bdfa](https://github.com/payloadcms/payload/commit/815bdfac0b0afbff2a20e54d5aee64b90f6b3a77))
* **db-postgres:** set _parentID for array nested localized fields ([#5117](https://github.com/payloadcms/payload/issues/5117)) ([ceca5c4](https://github.com/payloadcms/payload/commit/ceca5c4e97f53f1346797a31b6abfc0375e98215))
* disabling API Key does not remove the key ([#5145](https://github.com/payloadcms/payload/issues/5145)) ([7a7f0ed](https://github.com/payloadcms/payload/commit/7a7f0ed7e8132253be607c111c160163b84bd770))
* handle thrown errors in config-level afterError hook ([#5147](https://github.com/payloadcms/payload/issues/5147)) ([32ed95e](https://github.com/payloadcms/payload/commit/32ed95e1ee87409db234f1b7bd6d2e462fd9ed5d))
* only replace the drawer content with full edit component if it exists ([#5144](https://github.com/payloadcms/payload/issues/5144)) ([0a07f60](https://github.com/payloadcms/payload/commit/0a07f607b9fb1217ad956cd05b2a84a4042a19ca))
* transaction error from access endpoint ([#5156](https://github.com/payloadcms/payload/issues/5156)) ([ad42d54](https://github.com/payloadcms/payload/commit/ad42d541b342ed56463b81cee6d6307df6f06d7f))
## [2.11.1](https://github.com/payloadcms/payload/compare/v2.11.0...v2.11.1) (2024-02-16)
### ⚠ BREAKING CHANGES
* **richtext-lexical:** Update lexical from 0.12.6 to 0.13.1, port over all useful changes from playground (#5066)
### Features
* **db-postgres:** adds idType to use uuid or serial id columns ([#3864](https://github.com/payloadcms/payload/issues/3864)) ([d6c2578](https://github.com/payloadcms/payload/commit/d6c25783cfa97983bf9db27ceb5ccd39a62c62f1))
@@ -25,6 +39,14 @@
* **richtext-lexical:** do not remove adjacent paragraph node when inserting certain nodes in empty editor ([#5061](https://github.com/payloadcms/payload/issues/5061)) ([6323965](https://github.com/payloadcms/payload/commit/6323965c652ea68dffeb716957b124d165b9ce96))
* **uploads:** account for serverURL when retrieving external file ([#5102](https://github.com/payloadcms/payload/issues/5102)) ([25cee8b](https://github.com/payloadcms/payload/commit/25cee8bb102bf80b3a4bfb4b4e46712722cc7f0d))
### ⚠ BREAKING CHANGES: @payloadcms/richtext-lexical
* **richtext-lexical:** Update lexical from 0.12.6 to 0.13.1, port over all useful changes from playground (#5066)
- You HAVE to make sure that any versions of the lexical packages (IF you have any installed) match the lexical version which richtext-lexical uses: v0.13.1. If you do not do this, you may be plagued by React useContext / "cannot find active editor state" errors
- Updates to lexical's API, e.g. the removal of INTERNAL_isPointSelection, could be breaking depending on your code. Please consult the [lexical changelog](https://github.com/facebook/lexical/blob/main/CHANGELOG.md).
## [2.11.0](https://github.com/payloadcms/payload/compare/v2.10.1...v2.11.0) (2024-02-09)

View File

@@ -2,7 +2,7 @@
title: Postgres
label: Postgres
order: 50
desc: Payload supports Postgres through an officially supported Drizzle database adapter.
desc: Payload supports Postgres through an officially supported Drizzle database adapter.
keywords: Postgres, documentation, typescript, Content Management System, cms, headless, javascript, node, react, express
---
@@ -37,11 +37,12 @@ export default buildConfig({
### Options
| Option | Description |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pool` | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres`. |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| Option | Description |
|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `pool` | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres`. |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| `schemaName` | A string for the postgres schema to use, defaults to 'public'. |
### Access to Drizzle
@@ -65,7 +66,7 @@ In addition to exposing Drizzle directly, all of the tables, Drizzle relations,
Drizzle exposes two ways to work locally in development mode.
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
You will be warned if any changes that you make will entail data loss while in development mode. Push is enabled by default, but you can opt out if you'd like.
@@ -77,11 +78,11 @@ Migrations are extremely powerful thanks to the seamless way that Payload and Dr
1. You are building your Payload config locally, with a local database used for testing.
1. You have left the default setting of `push` enabled, so every time you change your Payload config (add or remove fields, collections, etc.), Drizzle will automatically push changes to your local DB.
1. Once you're done with your changes, or have completed a feature, you can run `npm run payload migrate:create`.
1. Once you're done with your changes, or have completed a feature, you can run `npm run payload migrate:create`.
1. Payload and Drizzle will look for any existing migrations, and automatically generate all SQL changes necessary to convert your schema from its prior state into the state of your current Payload config, and store the resulting DDL in a newly created migration.
1. Once you're ready to go to production, you will be able to run `npm run payload migrate` against your production database, which will apply any new migrations that have not yet run.
1. Now your production database is in sync with your Payload config!
<Banner type="warning">
Warning: do not mix "push" and migrations with your local development database. If you use "push" locally, and then try to migrate, Payload will throw a warning, telling you that these two methods are not meant to be used interchangeably.
</Banner>
</Banner>

View File

@@ -36,7 +36,7 @@ If your Hook simply performs a side-effect, such as updating a CRM, it might be
#### Server-only execution
Payload Hooks do not have any effect within the Payload Admin panel. You can safely [remove your hooks](/docs/admin/webpack#aliasing-server-only-modules) from your Admin panel's code by customizing the Webpack config, which not only keeps your Admin bundles' filesize small but also ensures that any server-side only code does not cause problems within browser environments.
Payload Hooks are only triggered on the server. You can safely [remove your hooks](/docs/admin/webpack#aliasing-server-only-modules) from your Admin panel's client-side code by customizing the Webpack config, which not only keeps your Admin bundles' filesize small but also ensures that any server-side only code does not cause problems within browser environments.
## Hook Types

View File

@@ -4508,9 +4508,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4701,9 +4701,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4508,9 +4508,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4258,14 +4258,14 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^1.1.5:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48"
integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==
version "1.1.9"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396"
integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -3924,9 +3924,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4347,9 +4347,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4508,9 +4508,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4625,9 +4625,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4599,9 +4599,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4513,9 +4513,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -4835,9 +4835,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -3748,9 +3748,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-mongodb",
"version": "1.4.2",
"version": "1.4.3",
"description": "The officially supported MongoDB database adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -49,6 +49,8 @@ export interface Args {
/** Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false */
disableIndexHints?: boolean
migrationDir?: string
/** Set to true to evaluate null field values as existing */
nullFieldValuesNotExist?: boolean
transactionOptions?: TransactionOptions | false
/** The URL to connect to MongoDB or false to start payload and prevent connecting */
url: false | string
@@ -93,6 +95,7 @@ export function mongooseAdapter({
connectOptions,
disableIndexHints = false,
migrationDir: migrationDirArg,
nullFieldValuesNotExist = true,
transactionOptions = {},
url,
}: Args): MongooseAdapterResult {
@@ -103,6 +106,8 @@ export function mongooseAdapter({
return createDatabaseAdapter<MongooseAdapter>({
name: 'mongoose',
nullFieldValuesNotExist,
// Mongoose-specific
autoPluralization,
collections: {},

View File

@@ -14,8 +14,10 @@ import type {
DateField,
EmailField,
Field,
FieldAffectingData,
GroupField,
JSONField,
NonPresentationalField,
NumberField,
PointField,
RadioField,
@@ -23,12 +25,12 @@ import type {
RichTextField,
RowField,
SelectField,
Tab,
TabsField,
TextField,
TextareaField,
UploadField,
} from 'payload/types'
import type { FieldAffectingData, NonPresentationalField, Tab, UnnamedTab } from 'payload/types'
import { Schema } from 'mongoose'
import {
@@ -61,7 +63,15 @@ const formatBaseSchema = (field: FieldAffectingData, buildSchemaOptions: BuildSc
unique: (!disableUnique && field.unique) || false,
}
if (schema.unique && (field.localized || draftsEnabled)) {
if (
schema.unique &&
(field.localized ||
draftsEnabled ||
(fieldAffectsData(field) &&
field.type !== 'group' &&
field.type !== 'tab' &&
field.required !== true))
) {
schema.sparse = true
}
@@ -79,7 +89,6 @@ const localizeSchema = (
) => {
if (fieldIsLocalized(entity) && localization && Array.isArray(localization.locales)) {
return {
localized: true,
type: localization.localeCodes.reduce(
(localeSchema, locale) => ({
...localeSchema,
@@ -89,6 +98,7 @@ const localizeSchema = (
_id: false,
},
),
localized: true,
}
}
return schema
@@ -140,7 +150,6 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
) => {
const baseSchema = {
...formatBaseSchema(field, buildSchemaOptions),
default: undefined,
type: [
buildSchema(config, field.fields, {
allowIDField: true,
@@ -153,6 +162,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
},
}),
],
default: undefined,
}
schema.add({
@@ -166,8 +176,8 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
buildSchemaOptions: BuildSchemaOptions,
): void => {
const fieldSchema = {
default: undefined,
type: [new Schema({}, { _id: false, discriminatorKey: 'blockType' })],
default: undefined,
}
schema.add({
@@ -187,12 +197,12 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
if (field.localized && config.localization) {
config.localization.localeCodes.forEach((localeCode) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Possible incorrect typing in mongoose types, this works
// @ts-expect-error Possible incorrect typing in mongoose types, this works
schema.path(`${field.name}.${localeCode}`).discriminator(blockItem.slug, blockSchema)
})
} else {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore Possible incorrect typing in mongoose types, this works
// @ts-expect-error Possible incorrect typing in mongoose types, this works
schema.path(field.name).discriminator(blockItem.slug, blockSchema)
}
})
@@ -325,14 +335,14 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
buildSchemaOptions: BuildSchemaOptions,
): void => {
const baseSchema: SchemaTypeOptions<unknown> = {
type: {
type: String,
enum: ['Point'],
},
coordinates: {
type: [Number],
default: field.defaultValue || undefined,
required: false,
type: [Number],
},
type: {
enum: ['Point'],
type: String,
},
}
if (buildSchemaOptions.disableUnique && field.unique && field.localized) {
@@ -366,11 +376,11 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
): void => {
const baseSchema = {
...formatBaseSchema(field, buildSchemaOptions),
type: String,
enum: field.options.map((option) => {
if (typeof option === 'object') return option.value
return option
}),
type: String,
}
schema.add({
@@ -388,7 +398,6 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
if (field.localized && config.localization) {
schemaToReturn = {
localized: true,
type: config.localization.localeCodes.reduce((locales, locale) => {
let localeSchema: { [key: string]: any } = {}
@@ -396,56 +405,57 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
localeSchema = {
...formatBaseSchema(field, buildSchemaOptions),
_id: false,
relationTo: { enum: field.relationTo, type: String },
type: Schema.Types.Mixed,
relationTo: { type: String, enum: field.relationTo },
value: {
refPath: `${field.name}.${locale}.relationTo`,
type: Schema.Types.Mixed,
refPath: `${field.name}.${locale}.relationTo`,
},
}
} else {
localeSchema = {
...formatBaseSchema(field, buildSchemaOptions),
ref: field.relationTo,
type: Schema.Types.Mixed,
ref: field.relationTo,
}
}
return {
...locales,
[locale]: field.hasMany ? { default: undefined, type: [localeSchema] } : localeSchema,
[locale]: field.hasMany ? { type: [localeSchema], default: undefined } : localeSchema,
}
}, {}),
localized: true,
}
} else if (hasManyRelations) {
schemaToReturn = {
...formatBaseSchema(field, buildSchemaOptions),
_id: false,
relationTo: { enum: field.relationTo, type: String },
type: Schema.Types.Mixed,
relationTo: { type: String, enum: field.relationTo },
value: {
refPath: `${field.name}.relationTo`,
type: Schema.Types.Mixed,
refPath: `${field.name}.relationTo`,
},
}
if (field.hasMany) {
schemaToReturn = {
default: undefined,
type: [schemaToReturn],
default: undefined,
}
}
} else {
schemaToReturn = {
...formatBaseSchema(field, buildSchemaOptions),
ref: field.relationTo,
type: Schema.Types.Mixed,
ref: field.relationTo,
}
if (field.hasMany) {
schemaToReturn = {
default: undefined,
type: [schemaToReturn],
default: undefined,
}
}
}
@@ -488,11 +498,11 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
): void => {
const baseSchema = {
...formatBaseSchema(field, buildSchemaOptions),
type: String,
enum: field.options.map((option) => {
if (typeof option === 'object') return option.value
return option
}),
type: String,
}
if (buildSchemaOptions.draftsEnabled || !field.required) {
@@ -576,8 +586,8 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
): void => {
const baseSchema = {
...formatBaseSchema(field, buildSchemaOptions),
ref: field.relationTo,
type: Schema.Types.Mixed,
ref: field.relationTo,
}
schema.add({

View File

@@ -102,6 +102,7 @@ export async function buildSearchParam({
hasCustomID,
operator,
path,
payload,
val,
})

View File

@@ -1,3 +1,4 @@
import type { Payload } from 'payload'
import type { Field, TabAsField } from 'payload/types'
import mongoose from 'mongoose'
@@ -8,6 +9,7 @@ type SanitizeQueryValueArgs = {
hasCustomID: boolean
operator: string
path: string
payload: Payload
val: any
}
@@ -16,6 +18,7 @@ export const sanitizeQueryValue = ({
hasCustomID,
operator,
path,
payload,
val,
}: SanitizeQueryValueArgs): {
operator?: string
@@ -174,6 +177,14 @@ export const sanitizeQueryValue = ({
}
}
}
if (!payload.db.nullFieldValuesNotExist) {
return {
rawQuery: {
$or: [{ [path]: { $exists: true } }, { [path]: { $eq: null } }],
},
}
}
}
return { operator: formattedOperator, val: formattedValue }

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "0.6.0",
"version": "0.7.0",
"description": "The officially supported Postgres database adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -3,7 +3,7 @@ import type { Connect } from 'payload/database'
import { eq, sql } from 'drizzle-orm'
import { drizzle } from 'drizzle-orm/node-postgres'
import { numeric, pgTable, timestamp, varchar } from 'drizzle-orm/pg-core'
import { numeric, timestamp, varchar } from 'drizzle-orm/pg-core'
import { Pool } from 'pg'
import prompts from 'prompts'
@@ -61,9 +61,13 @@ export const connect: Connect = async function connect(this: PostgresAdapter, pa
this.drizzle = drizzle(this.pool, { logger, schema: this.schema })
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
this.payload.logger.info('---- DROPPING TABLES ----')
await this.drizzle.execute(sql`drop schema public cascade;
create schema public;`)
this.payload.logger.info(`---- DROPPING TABLES SCHEMA(${this.schemaName || 'public'}) ----`)
await this.drizzle.execute(
sql.raw(`
drop schema if exists ${this.schemaName || 'public'} cascade;
create schema ${this.schemaName || 'public'};
`),
)
this.payload.logger.info('---- DROPPED TABLES ----')
}
} catch (err) {
@@ -120,7 +124,7 @@ export const connect: Connect = async function connect(this: PostgresAdapter, pa
await apply()
// Migration table def in order to use query using drizzle
const migrationsSchema = pgTable('payload_migrations', {
const migrationsSchema = this.pgSchema.table('payload_migrations', {
name: varchar('name'),
batch: numeric('batch'),
created_at: timestamp('created_at'),

View File

@@ -78,7 +78,7 @@ export const traverseFields = ({
with: {},
}
const arrayTableName = `${currentTableName}_${toSnakeCase(field.name)}`
const arrayTableName = `${currentTableName}_${path}${toSnakeCase(field.name)}`
if (adapter.tables[`${arrayTableName}_locales`]) withArray.with._locales = _locales
currentArgs.with[`${path}${field.name}`] = withArray

View File

@@ -52,11 +52,13 @@ export function postgresAdapter(args: Args): PostgresAdapterResult {
fieldConstraints: {},
idType,
logger: args.logger,
pgSchema: undefined,
pool: undefined,
poolOptions: args.pool,
push: args.push,
relations: {},
schema: {},
schemaName: args.schemaName,
sessions: {},
tables: {},

View File

@@ -2,7 +2,7 @@
import type { Init } from 'payload/database'
import type { SanitizedCollectionConfig } from 'payload/types'
import { pgEnum } from 'drizzle-orm/pg-core'
import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'
import { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload/versions'
import toSnakeCase from 'to-snake-case'
@@ -11,6 +11,12 @@ import type { PostgresAdapter } from './types'
import { buildTable } from './schema/build'
export const init: Init = async function init(this: PostgresAdapter) {
if (this.schemaName) {
this.pgSchema = pgSchema(this.schemaName)
} else {
this.pgSchema = { table: pgTable }
}
if (this.payload.config.localization) {
this.enums.enum__locales = pgEnum(
'_locales',

View File

@@ -39,7 +39,7 @@ export async function migrate(this: PostgresAdapter): Promise<void> {
latestBatch = Number(migrationsInDB[0]?.batch)
}
} else {
await createMigrationTable(this.drizzle)
await createMigrationTable(this)
}
if (migrationsInDB.find((m) => m.batch === -1)) {

View File

@@ -44,8 +44,10 @@ export async function migrateFresh(
msg: `Dropping database.`,
})
await this.drizzle.execute(sql`drop schema public cascade;
create schema public;`)
await this.drizzle.execute(
sql.raw(`drop schema ${this.schemaName || 'public'} cascade;
create schema ${this.schemaName || 'public'};`),
)
const migrationFiles = await readMigrationFiles({ payload })
payload.logger.debug({

View File

@@ -1,4 +1,5 @@
import type { SQL } from 'drizzle-orm'
import type { PgTableWithColumns } from 'drizzle-orm/pg-core'
import type { Field, Where } from 'payload/types'
import { asc, desc } from 'drizzle-orm'
@@ -12,7 +13,7 @@ export type BuildQueryJoins = Record<string, SQL>
export type BuildQueryJoinAliases = {
condition: SQL
table: GenericTable
table: GenericTable | PgTableWithColumns<any>
}[]
type BuildQueryArgs = {

View File

@@ -1,6 +1,7 @@
/* eslint-disable no-param-reassign */
import type { SQL } from 'drizzle-orm'
import type { Field, FieldAffectingData, NumberField, TabAsField, TextField } from 'payload/types'
import type { PgTableWithColumns } from 'drizzle-orm/pg-core'
import type { Field, FieldAffectingData, NumberField, TabAsField, TextField } from 'payload/types'
import { and, eq, like, sql } from 'drizzle-orm'
import { alias } from 'drizzle-orm/pg-core'
@@ -15,7 +16,7 @@ import type { BuildQueryJoinAliases, BuildQueryJoins } from './buildQuery'
type Constraint = {
columnName: string
table: GenericTable
table: GenericTable | PgTableWithColumns<any>
value: unknown
}
@@ -26,12 +27,12 @@ type TableColumn = {
getNotNullColumnByValue?: (val: unknown) => string
pathSegments?: string[]
rawColumn?: SQL
table: GenericTable
table: GenericTable | PgTableWithColumns<any>
}
type Args = {
adapter: PostgresAdapter
aliasTable?: GenericTable
aliasTable?: GenericTable | PgTableWithColumns<any>
collectionPath: string
columnPrefix?: string
constraintPath?: string

View File

@@ -1,19 +1,15 @@
/* eslint-disable no-param-reassign */
import type { Relation } from 'drizzle-orm'
import type { IndexBuilder, PgColumnBuilder, UniqueConstraintBuilder } from 'drizzle-orm/pg-core'
import type {
IndexBuilder,
PgColumnBuilder,
PgTableWithColumns,
UniqueConstraintBuilder,
} from 'drizzle-orm/pg-core'
import type { Field } from 'payload/types'
import { relations } from 'drizzle-orm'
import {
index,
integer,
numeric,
pgTable,
serial,
timestamp,
unique,
varchar,
} from 'drizzle-orm/pg-core'
import { index, integer, numeric, serial, timestamp, unique, varchar } from 'drizzle-orm/pg-core'
import { fieldAffectsData } from 'payload/types'
import toSnakeCase from 'to-snake-case'
@@ -77,14 +73,14 @@ export const buildTable = ({
const localesColumns: Record<string, PgColumnBuilder> = {}
const localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder> = {}
let localesTable: GenericTable
let textsTable: GenericTable
let numbersTable: GenericTable
let localesTable: GenericTable | PgTableWithColumns<any>
let textsTable: GenericTable | PgTableWithColumns<any>
let numbersTable: GenericTable | PgTableWithColumns<any>
// Relationships to the base collection
const relationships: Set<string> = rootRelationships || new Set()
let relationshipsTable: GenericTable
let relationshipsTable: GenericTable | PgTableWithColumns<any>
// Drizzle relations
const relationsToBuild: Map<string, string> = new Map()
@@ -136,7 +132,7 @@ export const buildTable = ({
.notNull()
}
const table = pgTable(tableName, columns, (cols) => {
const table = adapter.pgSchema.table(tableName, columns, (cols) => {
const extraConfig = Object.entries(baseExtraConfig).reduce((config, [key, func]) => {
config[key] = func(cols)
return config
@@ -158,7 +154,7 @@ export const buildTable = ({
.references(() => table.id, { onDelete: 'cascade' })
.notNull()
localesTable = pgTable(localeTableName, localesColumns, (cols) => {
localesTable = adapter.pgSchema.table(localeTableName, localesColumns, (cols) => {
return Object.entries(localesIndexes).reduce(
(acc, [colName, func]) => {
acc[colName] = func(cols)
@@ -201,7 +197,7 @@ export const buildTable = ({
columns.locale = adapter.enums.enum__locales('locale')
}
textsTable = pgTable(textsTableName, columns, (cols) => {
textsTable = adapter.pgSchema.table(textsTableName, columns, (cols) => {
const indexes: Record<string, IndexBuilder> = {
orderParentIdx: index(`${textsTableName}_order_parent_idx`).on(cols.order, cols.parent),
}
@@ -245,7 +241,7 @@ export const buildTable = ({
columns.locale = adapter.enums.enum__locales('locale')
}
numbersTable = pgTable(numbersTableName, columns, (cols) => {
numbersTable = adapter.pgSchema.table(numbersTableName, columns, (cols) => {
const indexes: Record<string, IndexBuilder> = {
orderParentIdx: index(`${numbersTableName}_order_parent_idx`).on(cols.order, cols.parent),
}
@@ -307,19 +303,23 @@ export const buildTable = ({
const relationshipsTableName = `${tableName}_rels`
relationshipsTable = pgTable(relationshipsTableName, relationshipColumns, (cols) => {
const result: Record<string, unknown> = {
order: index(`${relationshipsTableName}_order_idx`).on(cols.order),
parentIdx: index(`${relationshipsTableName}_parent_idx`).on(cols.parent),
pathIdx: index(`${relationshipsTableName}_path_idx`).on(cols.path),
}
relationshipsTable = adapter.pgSchema.table(
relationshipsTableName,
relationshipColumns,
(cols) => {
const result: Record<string, unknown> = {
order: index(`${relationshipsTableName}_order_idx`).on(cols.order),
parentIdx: index(`${relationshipsTableName}_parent_idx`).on(cols.parent),
pathIdx: index(`${relationshipsTableName}_path_idx`).on(cols.path),
}
if (hasLocalizedRelationshipField) {
result.localeIdx = index(`${relationshipsTableName}_locale_idx`).on(cols.locale)
}
if (hasLocalizedRelationshipField) {
result.localeIdx = index(`${relationshipsTableName}_locale_idx`).on(cols.locale)
}
return result
})
return result
},
)
adapter.tables[relationshipsTableName] = relationshipsTable

View File

@@ -7,7 +7,14 @@ import type {
Relations,
} from 'drizzle-orm'
import type { NodePgDatabase, NodePgQueryResultHKT } from 'drizzle-orm/node-postgres'
import type { PgColumn, PgEnum, PgTableWithColumns, PgTransaction } from 'drizzle-orm/pg-core'
import type {
PgColumn,
PgEnum,
PgSchema,
PgTableWithColumns,
PgTransaction,
} from 'drizzle-orm/pg-core'
import type { PgTableFn } from 'drizzle-orm/pg-core/table'
import type { Payload } from 'payload'
import type { BaseDatabaseAdapter } from 'payload/database'
import type { PayloadRequest } from 'payload/types'
@@ -21,6 +28,7 @@ export type Args = {
migrationDir?: string
pool: PoolConfig
push?: boolean
schemaName?: string
}
export type GenericColumn = PgColumn<
@@ -59,11 +67,13 @@ export type PostgresAdapter = BaseDatabaseAdapter & {
fieldConstraints: Record<string, Record<string, string>>
idType: Args['idType']
logger: DrizzleConfig['logger']
pgSchema?: { table: PgTableFn } | PgSchema
pool: Pool
poolOptions: Args['pool']
push: boolean
relations: Record<string, GenericRelation>
schema: Record<string, GenericEnum | GenericRelation | GenericTable>
schemaName?: Args['schemaName']
sessions: {
[id: string]: {
db: DrizzleTransaction
@@ -71,7 +81,7 @@ export type PostgresAdapter = BaseDatabaseAdapter & {
resolve: () => Promise<void>
}
}
tables: Record<string, GenericTable>
tables: Record<string, GenericTable | PgTableWithColumns<any>>
}
export type IDType = 'integer' | 'numeric' | 'uuid' | 'varchar'

View File

@@ -40,7 +40,7 @@ export const insertArrays = async ({ adapter, arrays, db, parentRows }: Args): P
// Add any sub arrays that need to be created
// We will call this recursively below
arrayRows.forEach((arrayRow) => {
arrayRows.forEach((arrayRow, i) => {
if (Object.keys(arrayRow.arrays).length > 0) {
rowsByTable[tableName].arrays.push(arrayRow.arrays)
}
@@ -53,6 +53,9 @@ export const insertArrays = async ({ adapter, arrays, db, parentRows }: Args): P
arrayRowLocaleData._parentID = arrayRow.row.id
arrayRowLocaleData._locale = arrayRowLocale
rowsByTable[tableName].locales.push(arrayRowLocaleData)
if (!arrayRow.row.id) {
arrayRowLocaleData._getParentID = (rows) => rows[i].id
}
})
})
})
@@ -69,6 +72,15 @@ export const insertArrays = async ({ adapter, arrays, db, parentRows }: Args): P
// Insert locale rows
if (adapter.tables[`${tableName}_locales`] && row.locales.length > 0) {
if (!row.locales[0]._parentID) {
row.locales = row.locales.map((localeRow, i) => {
if (typeof localeRow._getParentID === 'function') {
localeRow._parentID = localeRow._getParentID(insertedRows)
delete localeRow._getParentID
}
return localeRow
})
}
await db.insert(adapter.tables[`${tableName}_locales`]).values(row.locales).returning()
}

View File

@@ -1,13 +1,17 @@
import { sql } from 'drizzle-orm'
import type { DrizzleDB } from '../types'
import type { PostgresAdapter } from '../types'
export const createMigrationTable = async (db: DrizzleDB): Promise<void> => {
await db.execute(sql`CREATE TABLE IF NOT EXISTS "payload_migrations" (
export const createMigrationTable = async (adapter: PostgresAdapter): Promise<void> => {
const prependSchema = adapter.schemaName ? `"${adapter.schemaName}".` : ''
await adapter.drizzle.execute(
sql.raw(`CREATE TABLE IF NOT EXISTS ${prependSchema}"payload_migrations" (
"id" serial PRIMARY KEY NOT NULL,
"name" varchar,
"batch" numeric,
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
);`)
);`),
)
}

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "2.11.1",
"version": "2.11.2",
"description": "Node, React and MongoDB Headless CMS and Application Framework",
"license": "MIT",
"main": "./dist/index.js",

View File

@@ -52,21 +52,9 @@ const Content: React.FC<DocumentDrawerProps> = ({
const { id, docPermissions, getDocPreferences } = useDocumentInfo()
// The component definition could come from multiple places in the config
// we need to cascade into the proper component from the top-down
// 1. "components.Edit"
// 2. "components.Edit.Default"
// 3. "components.Edit.Default.Component"
const CustomEditView =
typeof Edit === 'function'
? Edit
: typeof Edit === 'object' && typeof Edit.Default === 'function'
? Edit.Default
: typeof Edit?.Default === 'object' &&
'Component' in Edit.Default &&
typeof Edit.Default.Component === 'function'
? Edit.Default.Component
: undefined
// If they are replacing the entire edit view, use that.
// Else let the DefaultEdit determine what to render.
const CustomEditView = typeof Edit === 'function' ? Edit : undefined
const [fields, setFields] = useState(() => formatFields(collectionConfig, true))

View File

@@ -13,6 +13,7 @@ import { fieldTypes } from '../../forms/field-types'
import X from '../../icons/X'
import { useAuth } from '../../utilities/Auth'
import { useConfig } from '../../utilities/Config'
import { DocumentInfoProvider } from '../../utilities/DocumentInfo'
import { OperationContext } from '../../utilities/OperationProvider'
import { SelectAllStatus, useSelection } from '../../views/collections/List/SelectionProvider'
import { Drawer, DrawerToggler } from '../Drawer'
@@ -120,53 +121,55 @@ const EditMany: React.FC<Props> = (props) => {
{t('edit')}
</DrawerToggler>
<Drawer header={null} slug={drawerSlug}>
<OperationContext.Provider value="update">
<Form className={`${baseClass}__form`} onSuccess={onSuccess}>
<div className={`${baseClass}__main`}>
<div className={`${baseClass}__header`}>
<h2 className={`${baseClass}__header__title`}>
{t('editingLabel', { count, label: getTranslation(plural, i18n) })}
</h2>
<button
aria-label={t('close')}
className={`${baseClass}__header__close`}
id={`close-drawer__${drawerSlug}`}
onClick={() => closeModal(drawerSlug)}
type="button"
>
<X />
</button>
</div>
<FieldSelect fields={fields} setSelected={setSelected} />
<RenderFields fieldSchema={selected} fieldTypes={fieldTypes} />
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-sticky-wrap`}>
<div className={`${baseClass}__document-actions`}>
{collection.versions ? (
<React.Fragment>
<Publish
<DocumentInfoProvider collection={collection}>
<OperationContext.Provider value="update">
<Form className={`${baseClass}__form`} onSuccess={onSuccess}>
<div className={`${baseClass}__main`}>
<div className={`${baseClass}__header`}>
<h2 className={`${baseClass}__header__title`}>
{t('editingLabel', { count, label: getTranslation(plural, i18n) })}
</h2>
<button
aria-label={t('close')}
className={`${baseClass}__header__close`}
id={`close-drawer__${drawerSlug}`}
onClick={() => closeModal(drawerSlug)}
type="button"
>
<X />
</button>
</div>
<FieldSelect fields={fields} setSelected={setSelected} />
<RenderFields fieldSchema={selected} fieldTypes={fieldTypes} />
<div className={`${baseClass}__sidebar-wrap`}>
<div className={`${baseClass}__sidebar`}>
<div className={`${baseClass}__sidebar-sticky-wrap`}>
<div className={`${baseClass}__document-actions`}>
{collection.versions ? (
<React.Fragment>
<Publish
action={`${serverURL}${api}/${slug}${getQueryParams()}`}
disabled={selected.length === 0}
/>
<SaveDraft
action={`${serverURL}${api}/${slug}${getQueryParams()}`}
disabled={selected.length === 0}
/>
</React.Fragment>
) : (
<Submit
action={`${serverURL}${api}/${slug}${getQueryParams()}`}
disabled={selected.length === 0}
/>
<SaveDraft
action={`${serverURL}${api}/${slug}${getQueryParams()}`}
disabled={selected.length === 0}
/>
</React.Fragment>
) : (
<Submit
action={`${serverURL}${api}/${slug}${getQueryParams()}`}
disabled={selected.length === 0}
/>
)}
)}
</div>
</div>
</div>
</div>
</div>
</div>
</Form>
</OperationContext.Provider>
</Form>
</OperationContext.Provider>
</DocumentInfoProvider>
</Drawer>
</div>
)

View File

@@ -7,13 +7,14 @@ import { extractTranslations } from '../../translations/extractTranslations'
const labels = extractTranslations(['authentication:enableAPIKey', 'authentication:apiKey'])
const encryptKey: FieldHook = ({ req, value }) =>
value ? req.payload.encrypt(value as string) : undefined
value ? req.payload.encrypt(value as string) : null
const decryptKey: FieldHook = ({ req, value }) =>
value ? req.payload.decrypt(value as string) : undefined
export default [
{
name: 'enableAPIKey',
type: 'checkbox',
admin: {
components: {
Field: () => null,
@@ -21,10 +22,10 @@ export default [
},
defaultValue: false,
label: labels['authentication:enableAPIKey'],
type: 'checkbox',
},
{
name: 'apiKey',
type: 'text',
admin: {
components: {
Field: () => null,
@@ -35,10 +36,10 @@ export default [
beforeChange: [encryptKey],
},
label: labels['authentication:apiKey'],
type: 'text',
},
{
name: 'apiKeyIndex',
type: 'text',
admin: {
disabled: true,
},
@@ -59,6 +60,5 @@ export default [
},
],
},
type: 'text',
},
] as Field[]

View File

@@ -72,6 +72,8 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
overrideAccess,
req,
req: {
fallbackLocale,
locale,
payload,
payload: { config, secret },
},
@@ -196,7 +198,9 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
context: req.context,
depth,
doc: user,
fallbackLocale,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -56,30 +56,33 @@ const args = minimist(process.argv.slice(2))
const scriptIndex = args._.findIndex((x) => x === 'build')
const script = scriptIndex === -1 ? args._[0] : args._[scriptIndex]
if (script) {
if (script.startsWith('migrate')) {
migrate(args).then(() => process.exit(0))
} else {
switch (script.toLowerCase()) {
case 'build': {
build()
break
}
if (script.startsWith('migrate')) {
migrate(args).then(() => process.exit(0))
} else {
switch (script.toLowerCase()) {
case 'build': {
build()
break
case 'generate:types': {
generateTypes()
break
}
case 'generate:graphqlschema': {
generateGraphQLSchema()
break
}
default:
console.log(`Unknown script "${script}".`)
break
}
case 'generate:types': {
generateTypes()
break
}
case 'generate:graphqlschema': {
generateGraphQLSchema()
break
}
default:
console.log(`Unknown script "${script}".`)
break
}
} else {
console.error('No payload script specified. Did you mean to run `payload migrate`?')
}
/**

View File

@@ -17,7 +17,6 @@ import type {
import executeAccess from '../../auth/executeAccess'
import sendVerificationEmail from '../../auth/sendVerificationEmail'
import { registerLocalStrategy } from '../../auth/strategies/local/register'
import { fieldAffectsData } from '../../fields/config/types'
import { afterChange } from '../../fields/hooks/afterChange'
import { afterRead } from '../../fields/hooks/afterRead'
import { beforeChange } from '../../fields/hooks/beforeChange'
@@ -26,12 +25,12 @@ import { generateFileData } from '../../uploads/generateFileData'
import { unlinkTempFiles } from '../../uploads/unlinkTempFiles'
import { uploadFiles } from '../../uploads/uploadFiles'
import { commitTransaction } from '../../utilities/commitTransaction'
import flattenFields from '../../utilities/flattenTopLevelFields'
import { initTransaction } from '../../utilities/initTransaction'
import { killTransaction } from '../../utilities/killTransaction'
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields'
import { saveVersion } from '../../versions/saveVersion'
import { buildAfterOperation } from './utils'
import flattenFields from '../../utilities/flattenTopLevelFields'
const unlinkFile = promisify(fs.unlink)
@@ -88,6 +87,8 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
overrideAccess,
overwriteExistingFiles = false,
req: {
fallbackLocale,
locale,
payload,
payload: { config, emailOptions },
},
@@ -289,7 +290,9 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
context: req.context,
depth,
doc: result,
fallbackLocale,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -66,6 +66,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
depth,
overrideAccess,
req: {
fallbackLocale,
locale,
payload: { config },
payload,
@@ -149,9 +150,9 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
if (collectionConfig.versions) {
await deleteCollectionVersions({
id,
slug: collectionConfig.slug,
payload,
req,
slug: collectionConfig.slug,
})
}
@@ -178,7 +179,9 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
context: req.context,
depth,
doc: result || doc,
fallbackLocale,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -59,6 +59,8 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
depth,
overrideAccess,
req: {
fallbackLocale,
locale,
payload: { config },
payload,
t,
@@ -120,9 +122,9 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
if (collectionConfig.versions) {
await deleteCollectionVersions({
id,
slug: collectionConfig.slug,
payload,
req,
slug: collectionConfig.slug,
})
}
@@ -156,7 +158,9 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
context: req.context,
depth,
doc: result,
fallbackLocale,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -68,7 +68,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
overrideAccess,
page,
pagination = true,
req: { locale, payload },
req: { fallbackLocale, locale, payload },
req,
showHiddenFields,
sort,
@@ -196,8 +196,10 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
currentDepth,
depth,
doc,
fallbackLocale,
findMany: true,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -56,7 +56,7 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
disableErrors,
draft: draftEnabled = false,
overrideAccess = false,
req: { locale, t },
req: { fallbackLocale, locale, t },
req,
showHiddenFields,
} = args
@@ -139,7 +139,9 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
currentDepth,
depth,
doc: result,
fallbackLocale,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -34,7 +34,7 @@ async function findVersionByID<T extends TypeWithID = any>(
depth,
disableErrors,
overrideAccess,
req: { locale, payload, t },
req: { fallbackLocale, locale, payload, t },
req,
showHiddenFields,
} = args
@@ -112,7 +112,9 @@ async function findVersionByID<T extends TypeWithID = any>(
currentDepth,
depth,
doc: result.version,
fallbackLocale,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -37,7 +37,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
overrideAccess,
page,
pagination = true,
req: { locale, payload },
req: { fallbackLocale, locale, payload },
req,
showHiddenFields,
sort,
@@ -125,8 +125,10 @@ async function findVersions<T extends TypeWithVersion<T>>(
context: req.context,
depth,
doc: data.version,
fallbackLocale,
findMany: true,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -34,7 +34,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
depth,
overrideAccess = false,
req,
req: { locale, payload, t },
req: { fallbackLocale, locale, payload, t },
showHiddenFields,
} = args
@@ -140,7 +140,9 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
context: req.context,
depth,
doc: result,
fallbackLocale,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -75,6 +75,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
overrideAccess,
overwriteExistingFiles = false,
req: {
fallbackLocale,
locale,
payload: { config },
payload,
@@ -176,7 +177,9 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
context: req.context,
depth: 0,
doc,
fallbackLocale,
global: null,
locale,
overrideAccess: true,
req,
showHiddenFields: true,
@@ -309,7 +312,9 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
context: req.context,
depth,
doc: result,
fallbackLocale: null,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -76,6 +76,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
overrideAccess,
overwriteExistingFiles = false,
req: {
fallbackLocale,
locale,
payload: { config },
payload,
@@ -130,7 +131,9 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
context: req.context,
depth: 0,
doc: docWithLocales,
fallbackLocale: null,
global: null,
locale,
overrideAccess: true,
req,
showHiddenFields: true,
@@ -297,7 +300,9 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
context: req.context,
depth,
doc: result,
fallbackLocale,
global: null,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -56,7 +56,7 @@ const errorHandler =
err,
response,
req.context,
req.collection.config,
null,
)) || {
response,
status,

View File

@@ -11,9 +11,11 @@ type Args = {
currentDepth?: number
depth: number
doc: Record<string, unknown>
fallbackLocale: null | string
findMany?: boolean
flattenLocales?: boolean
global: SanitizedGlobalConfig | null
locale: string
overrideAccess: boolean
req: PayloadRequest
showHiddenFields: boolean
@@ -26,9 +28,11 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
currentDepth: incomingCurrentDepth,
depth: incomingDepth,
doc: incomingDoc,
fallbackLocale,
findMany,
flattenLocales = true,
global,
locale,
overrideAccess,
req,
showHiddenFields,
@@ -52,11 +56,13 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: collection?.fields || global?.fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,

View File

@@ -16,11 +16,13 @@ type Args = {
currentDepth: number
depth: number
doc: Record<string, unknown>
fallbackLocale: null | string
field: Field | TabAsField
fieldPromises: Promise<void>[]
findMany: boolean
flattenLocales: boolean
global: SanitizedGlobalConfig | null
locale: null | string
overrideAccess: boolean
populationPromises: Promise<void>[]
req: PayloadRequest
@@ -44,11 +46,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
field,
fieldPromises,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -72,18 +76,13 @@ export const promise = async ({
typeof siblingDoc[field.name] === 'object' &&
siblingDoc[field.name] !== null &&
field.localized &&
req.locale !== 'all' &&
locale !== 'all' &&
req.payload.config.localization
if (shouldHoistLocalizedValue) {
// replace actual value with localized value before sanitizing
// { [locale]: fields } -> fields
const { locale } = req
const value = siblingDoc[field.name][locale]
const fallbackLocale =
req.payload.config.localization &&
req.payload.config.localization?.fallback &&
req.fallbackLocale
let hoistedValue = value
@@ -201,7 +200,7 @@ export const promise = async ({
const shouldRunHookOnAllLocales =
field.localized &&
(req.locale === 'all' || !flattenLocales) &&
(locale === 'all' || !flattenLocales) &&
typeof siblingDoc[field.name] === 'object'
if (shouldRunHookOnAllLocales) {
@@ -277,7 +276,7 @@ export const promise = async ({
) {
siblingDoc[field.name] = await getValueWithDefault({
defaultValue: field.defaultValue,
locale: req.locale,
locale,
user: req.user,
value: siblingDoc[field.name],
})
@@ -288,7 +287,9 @@ export const promise = async ({
relationshipPopulationPromise({
currentDepth,
depth,
fallbackLocale,
field,
locale,
overrideAccess,
req,
showHiddenFields,
@@ -309,11 +310,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: field.fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -337,11 +340,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: field.fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -361,11 +366,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: field.fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -397,11 +404,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: block.fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -425,11 +434,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: block.fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -457,11 +468,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: field.fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -487,11 +500,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: field.fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -511,11 +526,13 @@ export const promise = async ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,

View File

@@ -8,9 +8,11 @@ type PopulateArgs = {
data: Record<string, unknown>
dataReference: Record<string, any>
depth: number
fallbackLocale: null | string
field: RelationshipField | UploadField
index?: number
key?: string
locale: null | string
overrideAccess: boolean
req: PayloadRequest
showHiddenFields: boolean
@@ -21,9 +23,11 @@ const populate = async ({
data,
dataReference,
depth,
fallbackLocale,
field,
index,
key,
locale,
overrideAccess,
req,
showHiddenFields,
@@ -54,8 +58,8 @@ const populate = async ({
id,
depth,
currentDepth + 1,
req.locale,
req.fallbackLocale,
locale,
fallbackLocale,
overrideAccess,
showHiddenFields,
]),
@@ -90,7 +94,9 @@ const populate = async ({
type PromiseArgs = {
currentDepth: number
depth: number
fallbackLocale: null | string
field: RelationshipField | UploadField
locale: null | string
overrideAccess: boolean
req: PayloadRequest
showHiddenFields: boolean
@@ -100,7 +106,9 @@ type PromiseArgs = {
const relationshipPopulationPromise = async ({
currentDepth,
depth,
fallbackLocale,
field,
locale,
overrideAccess,
req,
showHiddenFields,
@@ -112,7 +120,7 @@ const relationshipPopulationPromise = async ({
if (fieldSupportsMany(field) && field.hasMany) {
if (
req.locale === 'all' &&
locale === 'all' &&
typeof siblingDoc[field.name] === 'object' &&
siblingDoc[field.name] !== null
) {
@@ -125,9 +133,11 @@ const relationshipPopulationPromise = async ({
data: siblingDoc[field.name][key][index],
dataReference: resultingDoc,
depth: populateDepth,
fallbackLocale,
field,
index,
key,
locale,
overrideAccess,
req,
showHiddenFields,
@@ -146,8 +156,10 @@ const relationshipPopulationPromise = async ({
data: relatedDoc,
dataReference: resultingDoc,
depth: populateDepth,
fallbackLocale,
field,
index,
locale,
overrideAccess,
req,
showHiddenFields,
@@ -161,7 +173,7 @@ const relationshipPopulationPromise = async ({
} else if (
typeof siblingDoc[field.name] === 'object' &&
siblingDoc[field.name] !== null &&
req.locale === 'all'
locale === 'all'
) {
Object.keys(siblingDoc[field.name]).forEach((key) => {
const rowPromise = async () => {
@@ -170,8 +182,10 @@ const relationshipPopulationPromise = async ({
data: siblingDoc[field.name][key],
dataReference: resultingDoc,
depth: populateDepth,
fallbackLocale,
field,
key,
locale,
overrideAccess,
req,
showHiddenFields,
@@ -187,7 +201,9 @@ const relationshipPopulationPromise = async ({
data: siblingDoc[field.name],
dataReference: resultingDoc,
depth: populateDepth,
fallbackLocale,
field,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -11,11 +11,13 @@ type Args = {
currentDepth: number
depth: number
doc: Record<string, unknown>
fallbackLocale: null | string
fieldPromises: Promise<void>[]
fields: (Field | TabAsField)[]
findMany: boolean
flattenLocales: boolean
global: SanitizedGlobalConfig | null
locale: null | string
overrideAccess: boolean
populationPromises: Promise<void>[]
req: PayloadRequest
@@ -31,11 +33,13 @@ export const traverseFields = ({
currentDepth,
depth,
doc,
fallbackLocale,
fieldPromises,
fields,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,
@@ -52,11 +56,13 @@ export const traverseFields = ({
currentDepth,
depth,
doc,
fallbackLocale,
field,
fieldPromises,
findMany,
flattenLocales,
global,
locale,
overrideAccess,
populationPromises,
req,

View File

@@ -23,14 +23,14 @@ type Args = {
async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T> {
const {
slug,
depth,
draft: draftEnabled = false,
globalConfig,
overrideAccess = false,
req: { locale, payload },
req: { fallbackLocale, locale, payload },
req,
showHiddenFields,
slug,
} = args
try {
@@ -51,9 +51,9 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
// /////////////////////////////////////
let doc = await req.payload.db.findGlobal({
slug,
locale,
req,
slug,
where: overrideAccess ? undefined : (accessResult as Where),
})
if (!doc) {
@@ -100,7 +100,9 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
context: req.context,
depth,
doc,
fallbackLocale,
global: globalConfig,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -31,7 +31,7 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
disableErrors,
globalConfig,
overrideAccess,
req: { locale, payload, t },
req: { fallbackLocale, locale, payload, t },
req,
showHiddenFields,
} = args
@@ -108,7 +108,9 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
currentDepth,
depth,
doc: result.version,
fallbackLocale,
global: globalConfig,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -35,7 +35,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
limit,
overrideAccess,
page,
req: { locale, payload },
req: { fallbackLocale, locale, payload },
req,
showHiddenFields,
sort,
@@ -97,8 +97,10 @@ async function findVersions<T extends TypeWithVersion<T>>(
// Patch globalType onto version doc
globalType: globalConfig.slug,
},
fallbackLocale,
findMany: true,
global: globalConfig,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -25,7 +25,7 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
depth,
globalConfig,
overrideAccess,
req: { payload, t },
req: { fallbackLocale, locale, payload, t },
req,
showHiddenFields,
} = args
@@ -66,9 +66,9 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
// /////////////////////////////////////
const previousDoc = await payload.findGlobal({
slug: globalConfig.slug,
depth,
req,
slug: globalConfig.slug,
})
// /////////////////////////////////////
@@ -76,23 +76,23 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
// /////////////////////////////////////
const global = await payload.db.findGlobal({
req,
slug: globalConfig.slug,
req,
})
let result = rawVersion.version
if (global) {
result = await payload.db.updateGlobal({
slug: globalConfig.slug,
data: result,
req,
slug: globalConfig.slug,
})
} else {
result = await payload.db.createGlobal({
slug: globalConfig.slug,
data: result,
req,
slug: globalConfig.slug,
})
}
@@ -105,7 +105,9 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
context: req.context,
depth,
doc: result,
fallbackLocale,
global: globalConfig,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -32,15 +32,15 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
args: Args<GeneratedTypes['globals'][TSlug]>,
): Promise<GeneratedTypes['globals'][TSlug]> {
const {
slug,
autosave,
depth,
draft: draftArg,
globalConfig,
overrideAccess,
req: { locale, payload },
req: { fallbackLocale, locale, payload },
req,
showHiddenFields,
slug,
} = args
try {
@@ -74,11 +74,11 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
// 2. Retrieve document
// /////////////////////////////////////
const { global, globalExists } = await getLatestGlobalVersion({
slug,
config: globalConfig,
locale,
payload,
req,
slug,
where: query,
})
@@ -97,7 +97,9 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
context: req.context,
depth: 0,
doc: globalJSON,
fallbackLocale,
global: globalConfig,
locale,
overrideAccess: true,
req,
showHiddenFields,
@@ -175,15 +177,15 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
if (!shouldSaveDraft) {
if (globalExists) {
result = await payload.db.updateGlobal({
slug,
data: result,
req,
slug,
})
} else {
result = await payload.db.createGlobal({
slug,
data: result,
req,
slug,
})
}
}
@@ -218,7 +220,9 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
context: req.context,
depth,
doc: result,
fallbackLocale: null,
global: globalConfig,
locale,
overrideAccess,
req,
showHiddenFields,

View File

@@ -274,7 +274,7 @@
"near": "nær"
},
"upload": {
"crop": "Avling",
"crop": "Beskjær",
"cropToolDescription": "Dra hjørnene av det valgte området, tegn et nytt område eller juster verdiene nedenfor.",
"dragAndDrop": "Dra og slipp en fil",
"dragAndDropHere": "eller dra og slipp en fil her",

View File

@@ -57,8 +57,10 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
if (typeof where === 'object') {
const paginatedRes = await req.payload.find({
collection: entity.slug,
depth: 0,
limit: 1,
overrideAccess: true,
pagination: false,
req,
where: {
...where,
@@ -79,6 +81,7 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
return req.payload.findByID({
id,
collection: entity.slug,
depth: 0,
overrideAccess: true,
req,
})
@@ -98,8 +101,13 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
const mutablePolicies = policiesObj
if (accessLevel === 'field' && docBeingAccessed === undefined) {
docBeingAccessed = await getEntityDoc()
// assign docBeingAccessed first as the promise to avoid multiple calls to getEntityDoc
docBeingAccessed = getEntityDoc().then((doc) => {
docBeingAccessed = doc
})
}
// awaiting the promise to ensure docBeingAccessed is assigned before it is used
await docBeingAccessed
const data = req?.body

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-nested-docs",
"version": "1.0.11",
"version": "1.0.12",
"description": "The official Nested Docs plugin for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",
@@ -20,6 +20,9 @@
"@payloadcms/eslint-config": "workspace:*",
"payload": "workspace:*"
},
"peerDependencies": {
"payload": "^0.18.5 || ^1.0.0 || ^2.0.0"
},
"exports": {
".": {
"default": "./src/index.ts",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/plugin-search",
"version": "1.0.1",
"version": "1.1.0",
"homepage:": "https://payloadcms.com",
"repository": "git@github.com:payloadcms/plugin-search.git",
"description": "Search plugin for Payload",

View File

@@ -2,10 +2,12 @@ import en from './en.json'
import es from './es.json'
import fa from './fa.json'
import fr from './fr.json'
import pl from './pl.json'
export default {
en,
es,
fa,
fr,
pl,
}

View File

@@ -0,0 +1,22 @@
{
"$schema": "./translation-schema.json",
"plugin-seo": {
"autoGenerate": "Wygeneruj automatycznie",
"imageAutoGenerationTip": "Automatyczne generowanie pobierze wybrany główny obraz.",
"bestPractices": "najlepsze praktyki",
"lengthTipTitle": "Długość powinna wynosić od {{minLength}} do {{maxLength}} znaków. Po porady dotyczące pisania wysokiej jakości meta tytułów zobacz ",
"lengthTipDescription": "Długość powinna wynosić od {{minLength}} do {{maxLength}} znaków. Po porady dotyczące pisania wysokiej jakości meta opisów zobacz ",
"good": "Dobrze",
"tooLong": "Zbyt długie",
"tooShort": "Zbyt krótkie",
"almostThere": "Prawie gotowe",
"characterCount": "{{current}}/{{minLength}}-{{maxLength}} znaków, ",
"charactersToGo": "pozostało {{characters}} znaków",
"charactersLeftOver": "zostało {{characters}} znaków",
"charactersTooMany": "{{characters}} znaków za dużo",
"noImage": "Brak obrazu",
"checksPassing": "{{current}}/{{max}} testów zakończonych pomyślnie",
"preview": "Podgląd",
"previewDescription": "Dokładne wyniki listowania mogą się różnić w zależności od treści i zgodności z kryteriami wyszukiwania."
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-lexical",
"version": "0.6.1",
"version": "0.7.0",
"description": "The officially supported Lexical richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -46,11 +46,13 @@ export const recurseNestedFields = ({
currentDepth,
depth,
doc: data as any, // Looks like it's only needed for hooks and access control, so doesn't matter what we pass here right now
fallbackLocale: req.fallbackLocale,
fieldPromises: promises, // Not sure if what I pass in here makes sense. But it doesn't seem like it's used at all anyways
fields,
findMany,
flattenLocales,
global: null, // Pass from core? This is only needed for hooks, so we can leave this null for now
locale: req.locale,
overrideAccess,
populationPromises, // This is not the same as populationPromises passed into this recurseNestedFields. These are just promises resolved at the very end.
req,

View File

@@ -1332,11 +1332,6 @@
slate-hyperscript "0.81.3"
slate-react "0.92.0"
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@polka/url@^1.0.0-next.20":
version "1.0.0-next.23"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.23.tgz#498e41218ab3b6a1419c735e5c6ae2c5ed609b6c"
@@ -2750,15 +2745,6 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -4260,9 +4246,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"
@@ -4515,15 +4501,6 @@ isomorphic-unfetch@^3.0.0:
node-fetch "^2.6.1"
unfetch "^4.2.0"
jackspeak@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd"
integrity sha512-juf9stUEwUaILepraGOWIJTLwg48bUnBmRqd2ln2Os1sW987zeoj/hzhbvRB95oMuS2ZTpjULmdwHNX4rzZIZw==
dependencies:
cliui "^8.0.1"
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
jest-util@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc"

View File

@@ -1540,11 +1540,6 @@
slate-hyperscript "0.81.3"
slate-react "0.92.0"
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@polka/url@^1.0.0-next.20":
version "1.0.0-next.24"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3"
@@ -3188,15 +3183,6 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -5120,9 +5106,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"
@@ -5385,15 +5371,6 @@ isomorphic-unfetch@^3.0.0:
node-fetch "^2.6.1"
unfetch "^4.2.0"
jackspeak@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd"
integrity sha512-juf9stUEwUaILepraGOWIJTLwg48bUnBmRqd2ln2Os1sW987zeoj/hzhbvRB95oMuS2ZTpjULmdwHNX4rzZIZw==
dependencies:
cliui "^8.0.1"
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
jest-util@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc"

View File

@@ -1749,11 +1749,6 @@
slate-hyperscript "0.81.3"
slate-react "0.92.0"
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@polka/url@^1.0.0-next.20":
version "1.0.0-next.24"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3"
@@ -3415,15 +3410,6 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
cliui@^8.0.1:
version "8.0.1"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
dependencies:
string-width "^4.2.0"
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -5485,9 +5471,9 @@ interpret@^2.2.0:
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
ip@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
version "2.0.1"
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
ipaddr.js@1.9.1:
version "1.9.1"
@@ -5750,15 +5736,6 @@ isomorphic-unfetch@^3.0.0:
node-fetch "^2.6.1"
unfetch "^4.2.0"
jackspeak@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd"
integrity sha512-juf9stUEwUaILepraGOWIJTLwg48bUnBmRqd2ln2Os1sW987zeoj/hzhbvRB95oMuS2ZTpjULmdwHNX4rzZIZw==
dependencies:
cliui "^8.0.1"
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
jest-util@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc"

View File

@@ -4,7 +4,7 @@ import { mapAsync } from '../../packages/payload/src/utilities/mapAsync'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
import { devUser } from '../credentials'
import { AuthDebug } from './AuthDebug'
import { namedSaveToJWTValue, saveToJWTKey, slug } from './shared'
import { apiKeysSlug, namedSaveToJWTValue, saveToJWTKey, slug } from './shared'
export default buildConfigWithDefaults({
admin: {
@@ -171,11 +171,7 @@ export default buildConfigWithDefaults({
],
},
{
slug: 'api-keys',
labels: {
singular: 'API Key',
plural: 'API Keys',
},
slug: apiKeysSlug,
access: {
read: ({ req: { user } }) => {
if (user.collection === 'api-keys') {
@@ -193,6 +189,10 @@ export default buildConfigWithDefaults({
useAPIKey: true,
},
fields: [],
labels: {
plural: 'API Keys',
singular: 'API Key',
},
},
{
slug: 'public-users',

View File

@@ -2,28 +2,34 @@ import type { Page } from '@playwright/test'
import { expect, test } from '@playwright/test'
import payload from '../../packages/payload/src'
import { initPageConsoleErrorCatch, login, saveDocAndAssert } from '../helpers'
import { AdminUrlUtil } from '../helpers/adminUrlUtil'
import { initPayloadE2E } from '../helpers/configHelpers'
import { slug } from './shared'
import { apiKeysSlug, slug } from './shared'
/**
* TODO: Auth
* create first user
* unlock
* generate api key
* log out
*/
const { beforeAll, describe } = test
const headers = {
'Content-Type': 'application/json',
}
describe('auth', () => {
let page: Page
let url: AdminUrlUtil
let serverURL: string
let apiURL: string
beforeAll(async ({ browser }) => {
const { serverURL } = await initPayloadE2E(__dirname)
url = new AdminUrlUtil(serverURL, slug)
serverURL = (await initPayloadE2E(__dirname)).serverURL
apiURL = `${serverURL}/api`
const context = await browser.newContext()
page = await context.newPage()
@@ -36,6 +42,10 @@ describe('auth', () => {
})
describe('authenticated users', () => {
beforeAll(async ({ browser }) => {
url = new AdminUrlUtil(serverURL, slug)
})
test('should allow change password', async () => {
await page.goto(url.account)
const emailBeforeSave = await page.locator('#field-email').inputValue()
@@ -62,4 +72,56 @@ describe('auth', () => {
await expect(page.locator('#use-auth-result')).toHaveText('Goodbye, world!')
})
})
describe('api-keys', () => {
let user
beforeAll(async () => {
url = new AdminUrlUtil(serverURL, apiKeysSlug)
user = await payload.create({
collection: apiKeysSlug,
data: {
enableAPIKey: true,
},
})
})
test('should enable api key', async () => {
await page.goto(url.create)
// click enable api key checkbox
await page.locator('#field-enableAPIKey').click()
// assert that the value is set
const apiKey = await page.locator('#apiKey').inputValue()
expect(apiKey).toBeDefined()
await saveDocAndAssert(page)
expect(await page.locator('#apiKey').inputValue()).toStrictEqual(apiKey)
})
test('should disable api key', async () => {
await page.goto(url.edit(user.id))
// click enable api key checkbox
await page.locator('#field-enableAPIKey').click()
// assert that the apiKey field is hidden
await expect(page.locator('#apiKey')).toBeHidden()
await saveDocAndAssert(page)
// use the api key in a fetch to assert that it is disabled
const response = await fetch(`${apiURL}/${apiKeysSlug}/me`, {
headers: {
...headers,
Authorization: `${slug} API-Key ${user.apiKey}`,
},
}).then((res) => res.json())
expect(response.user).toBeNull()
})
})
})

View File

@@ -1,4 +1,5 @@
export const slug = 'users'
export const apiKeysSlug = 'api-keys'
export const namedSaveToJWTValue = 'namedSaveToJWT value'

View File

@@ -35,6 +35,13 @@ const databaseAdapters = {
connectionString: process.env.POSTGRES_URL || 'postgres://127.0.0.1:5432/payloadtests',
},
}),
'postgres-custom-schema': postgresAdapter({
migrationDir,
pool: {
connectionString: process.env.POSTGRES_URL || 'postgres://127.0.0.1:5432/payloadtests',
},
schemaName: 'custom',
}),
'postgres-uuid': postgresAdapter({
idType: 'uuid',
migrationDir,

View File

@@ -3,7 +3,7 @@ import fs from 'fs'
import { GraphQLClient } from 'graphql-request'
import path from 'path'
import type { DrizzleDB } from '../../packages/db-postgres/src/types'
import type { PostgresAdapter } from '../../packages/db-postgres/src/types'
import type { TypeWithID } from '../../packages/payload/src/collections/config/types'
import type { PayloadRequest } from '../../packages/payload/src/express/types'
@@ -44,10 +44,14 @@ describe('database', () => {
describe('migrations', () => {
beforeAll(async () => {
if (process.env.PAYLOAD_DROP_DATABASE === 'true' && 'drizzle' in payload.db) {
const drizzle = payload.db.drizzle as DrizzleDB
// @ts-expect-error drizzle raw sql typing
await drizzle.execute(sql`drop schema public cascade;
create schema public;`)
const db = payload.db as unknown as PostgresAdapter
const drizzle = db.drizzle
const schemaName = db.schemaName || 'public'
await drizzle.execute(
sql.raw(`drop schema ${schemaName} cascade;
create schema ${schemaName};`),
)
}
})

View File

@@ -21,8 +21,13 @@ const ArrayFields: CollectionConfig = {
fields: [
{
name: 'text',
required: true,
type: 'text',
required: true,
},
{
name: 'localizedText',
type: 'text',
localized: true,
},
{
name: 'subArray',

View File

@@ -32,26 +32,34 @@ const IndexedFields: CollectionConfig = {
fields: [
{
name: 'text',
type: 'text',
index: true,
required: true,
type: 'text',
},
{
name: 'uniqueText',
type: 'text',
unique: true,
},
{
name: 'uniqueRequiredText',
type: 'text',
defaultValue: 'uniqueRequired',
required: true,
unique: true,
},
{
name: 'point',
type: 'point',
},
{
name: 'group',
type: 'group',
fields: [
{
name: 'localizedUnique',
localized: true,
type: 'text',
localized: true,
unique: true,
},
{
@@ -64,25 +72,24 @@ const IndexedFields: CollectionConfig = {
type: 'point',
},
],
type: 'group',
},
{
type: 'collapsible',
fields: [
{
name: 'collapsibleLocalizedUnique',
localized: true,
type: 'text',
localized: true,
unique: true,
},
{
name: 'collapsibleTextUnique',
label: 'collapsibleTextUnique',
type: 'text',
label: 'collapsibleTextUnique',
unique: true,
},
],
label: 'Collapsible',
type: 'collapsible',
},
],
versions: true,

View File

@@ -249,6 +249,7 @@ describe('fields', () => {
unique: uniqueText,
},
text: 'text',
uniqueRequiredText: 'text',
uniqueText,
},
})
@@ -814,6 +815,95 @@ describe('fields', () => {
).toHaveValue(`${assertGroupText3} duplicate`)
})
})
test('should bulk update', async () => {
await Promise.all([
payload.create({
collection: 'array-fields',
data: {
title: 'for test 1',
items: [
{
text: 'test 1',
},
{
text: 'test 2',
},
],
},
}),
payload.create({
collection: 'array-fields',
data: {
title: 'for test 2',
items: [
{
text: 'test 3',
},
],
},
}),
payload.create({
collection: 'array-fields',
data: {
title: 'for test 3',
items: [
{
text: 'test 4',
},
{
text: 'test 5',
},
{
text: 'test 6',
},
],
},
}),
])
const bulkText = 'Bulk update text'
await page.goto(url.list)
await page.waitForSelector('.table > table > tbody > tr td.cell-title')
const rows = page.locator('.table > table > tbody > tr', {
has: page.locator('td.cell-title span', {
hasText: 'for test',
}),
})
const count = await rows.count()
for (let i = 0; i < count; i++) {
await rows
.nth(i)
.locator('td.cell-_select .checkbox-input__input > input[type="checkbox"]')
.check()
}
await page.locator('.edit-many__toggle').click()
await page.locator('.field-select .rs__control').click()
const arrayOption = page.locator('.rs__option', {
hasText: exactText('Items'),
})
await expect(arrayOption).toBeVisible()
await arrayOption.click()
const addRowButton = page.locator('#field-items > .btn.array-field__add-row')
await expect(addRowButton).toBeVisible()
await addRowButton.click()
const targetInput = page.locator('#field-items__0__text')
await expect(targetInput).toBeVisible()
await targetInput.fill(bulkText)
await page.locator('.form-submit button[type="submit"].edit-many__publish').click()
await expect(page.locator('.Toastify__toast--success')).toContainText(
'Updated 3 Array Fields successfully.',
)
})
})
describe('tabs', () => {

View File

@@ -424,7 +424,7 @@ describe('Fields', () => {
const definitions: Record<string, IndexDirection> = {}
const options: Record<string, IndexOptions> = {}
beforeEach(() => {
beforeAll(() => {
indexes = (payload.db as MongooseAdapter).collections[
'indexed-fields'
].schema.indexes() as [Record<string, IndexDirection>, IndexOptions]
@@ -441,8 +441,13 @@ describe('Fields', () => {
expect(definitions.text).toEqual(1)
})
it('should have unique indexes', () => {
it('should have unique sparse indexes when field is not required', () => {
expect(definitions.uniqueText).toEqual(1)
expect(options.uniqueText).toMatchObject({ sparse: true, unique: true })
})
it('should have unique indexes that are not sparse when field is required', () => {
expect(definitions.uniqueRequiredText).toEqual(1)
expect(options.uniqueText).toMatchObject({ unique: true })
})
@@ -594,6 +599,25 @@ describe('Fields', () => {
return result.error
}).toBeDefined()
})
it('should not throw validation error saving multiple null values for unique fields', async () => {
const data = {
text: 'a',
uniqueRequiredText: 'a',
// uniqueText omitted on purpose
}
await payload.create({
collection: 'indexed-fields',
data,
})
data.uniqueRequiredText = 'b'
const result = await payload.create({
collection: 'indexed-fields',
data,
})
expect(result.id).toBeDefined()
})
})
describe('array', () => {
@@ -620,6 +644,51 @@ describe('Fields', () => {
expect(doc.localized).toMatchObject(arrayDefaultValue)
})
it('should create and update localized subfields with versions', async () => {
const doc = await payload.create({
collection,
data: {
items: [
{
localizedText: 'test',
text: 'required',
},
],
localized: [
{
text: 'english',
},
],
},
})
const spanish = await payload.update({
id: doc.id,
collection,
data: {
items: [
{
id: doc.items[0].id,
localizedText: 'spanish',
text: 'required',
},
],
},
locale: 'es',
})
const result = await payload.findByID({
id: doc.id,
collection,
locale: 'all',
})
expect(doc.items[0].localizedText).toStrictEqual('test')
expect(spanish.items[0].localizedText).toStrictEqual('spanish')
expect(result.items[0].localizedText.en).toStrictEqual('test')
expect(result.items[0].localizedText.es).toStrictEqual('spanish')
})
it('should create with nested array', async () => {
const subArrayText = 'something expected'
const doc = await payload.create({

View File

@@ -20,7 +20,7 @@ export async function resetDB(_payload: Payload, collectionSlugs: string[]) {
return
}
const queries = Object.values(schema).map((table: any) => {
return sql.raw(`DELETE FROM ${table.dbName}`)
return sql.raw(`DELETE FROM ${db.schemaName ? db.schemaName + '.' : ''}${table.dbName}`)
})
await db.drizzle.transaction(async (trx) => {

View File

@@ -1,5 +1,6 @@
import type { SanitizedConfig } from '../../packages/payload/src/config/types'
import { APIError } from '../../packages/payload/errors'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
import AfterOperation from './collections/AfterOperation'
import ChainingHooks from './collections/ChainingHooks'
@@ -24,6 +25,18 @@ export const HooksConfig: Promise<SanitizedConfig> = buildConfigWithDefaults({
DataHooks,
],
globals: [DataHooksGlobal],
endpoints: [
{
path: '/throw-to-after-error',
method: 'get',
handler: () => {
throw new APIError("I'm a teapot", 418)
},
},
],
hooks: {
afterError: () => console.log('Running afterError hook'),
},
onInit: async (payload) => {
await seedHooksUsers(payload)
await payload.create({

View File

@@ -462,4 +462,13 @@ describe('Hooks', () => {
expect(doc.field_globalAndField).toStrictEqual(globalAndFieldString + globalAndFieldString)
})
})
describe('config level after error hook', () => {
it('should handle error', async () => {
const response = await fetch(`${apiUrl}/throw-to-after-error`)
const body = await response.json()
expect(response.status).toEqual(418)
expect(body).toEqual({ errors: [{ message: "I'm a teapot" }] })
})
})
})

View File

@@ -157,6 +157,7 @@ describe('Localization', () => {
id,
collection: localizedPostsSlug,
data: {
localizedCheckbox: false,
title: spanishTitle,
},
locale: spanishLocale,
@@ -174,8 +175,6 @@ describe('Localization', () => {
await changeLocale(page, spanishLocale)
await expect(page.locator('#field-title')).toHaveValue(spanishTitle)
// click checkbox manually
await page.locator('#field-localizedCheckbox').click()
await expect(page.locator('#field-localizedCheckbox')).not.toBeChecked()
})