Compare commits
70 Commits
db-postgre
...
mongodb/nu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
501022991f | ||
|
|
53600c7352 | ||
|
|
76c1b23729 | ||
|
|
8104fac5ed | ||
|
|
59ef1263a5 | ||
|
|
813e3dbc98 | ||
|
|
12a23092e1 | ||
|
|
4a49beb552 | ||
|
|
80530c666e | ||
|
|
f53e2df951 | ||
|
|
db58e2bab2 | ||
|
|
d88e97e123 | ||
|
|
bb72e506e6 | ||
|
|
b1f727fd6a | ||
|
|
72af18229b | ||
|
|
af52b526c8 | ||
|
|
60525623bf | ||
|
|
0fba582926 | ||
|
|
5d1cad3adb | ||
|
|
e31f72da8e | ||
|
|
7aa058d604 | ||
|
|
64e80d242e | ||
|
|
e8f2ca484e | ||
|
|
ceca5c4e97 | ||
|
|
ee13736288 | ||
|
|
815bdfac0b | ||
|
|
7a7f0ed7e8 | ||
|
|
ad42d541b3 | ||
|
|
32ed95e1ee | ||
|
|
70e57fef18 | ||
|
|
0a07f607b9 | ||
|
|
3918fc7c21 | ||
|
|
13f71ac475 | ||
|
|
07720e777a | ||
|
|
efff47e400 | ||
|
|
453ac218ea | ||
|
|
d4b09bd9cd | ||
|
|
dd67e03fc1 | ||
|
|
548de80bee | ||
|
|
2c05fbbb5e | ||
|
|
9b54659818 | ||
|
|
e9f550406e | ||
|
|
98b87e2278 | ||
|
|
5f3d0169be | ||
|
|
35c2a085ef | ||
|
|
1ac943ed5e | ||
|
|
25cee8bb10 | ||
|
|
419aef452d | ||
|
|
ea52489126 | ||
|
|
e80c70acae | ||
|
|
70b0064d0b | ||
|
|
9636bf6efd | ||
|
|
8f4d0da4e0 | ||
|
|
f0f1dbdcb0 | ||
|
|
a895aee8b1 | ||
|
|
aa1dac08c1 | ||
|
|
b8cd1c6ba4 | ||
|
|
6344464bc6 | ||
|
|
5d4022f144 | ||
|
|
bf942fdfa6 | ||
|
|
d6c25783cf | ||
|
|
82e9d31127 | ||
|
|
399e606b34 | ||
|
|
0d18822062 | ||
|
|
00fc0343da | ||
|
|
6323965c65 | ||
|
|
6d6823c3e5 | ||
|
|
ca70298436 | ||
|
|
4f565759f6 | ||
|
|
df39602758 |
20
.github/workflows/main.yml
vendored
20
.github/workflows/main.yml
vendored
@@ -85,11 +85,15 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
database: [mongoose, postgres, supabase]
|
database: [mongoose, postgres, postgres-custom-schema, postgres-uuid, supabase]
|
||||||
env:
|
env:
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
POSTGRES_DB: payloadtests
|
POSTGRES_DB: payloadtests
|
||||||
|
AWS_ENDPOINT_URL: http://127.0.0.1:4566
|
||||||
|
AWS_ACCESS_KEY_ID: localstack
|
||||||
|
AWS_SECRET_ACCESS_KEY: localstack
|
||||||
|
AWS_REGION: us-east-1
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Use Node.js 18
|
- name: Use Node.js 18
|
||||||
@@ -109,6 +113,9 @@ jobs:
|
|||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
|
- name: Start LocalStack
|
||||||
|
run: pnpm docker:start
|
||||||
|
|
||||||
- name: Start PostgreSQL
|
- name: Start PostgreSQL
|
||||||
uses: CasperWA/postgresql-action@v1.2
|
uses: CasperWA/postgresql-action@v1.2
|
||||||
with:
|
with:
|
||||||
@@ -116,7 +123,7 @@ jobs:
|
|||||||
postgresql db: ${{ env.POSTGRES_DB }}
|
postgresql db: ${{ env.POSTGRES_DB }}
|
||||||
postgresql user: ${{ env.POSTGRES_USER }}
|
postgresql user: ${{ env.POSTGRES_USER }}
|
||||||
postgresql password: ${{ env.POSTGRES_PASSWORD }}
|
postgresql password: ${{ env.POSTGRES_PASSWORD }}
|
||||||
if: matrix.database == 'postgres'
|
if: startsWith(matrix.database, 'postgres')
|
||||||
|
|
||||||
- name: Install Supabase CLI
|
- name: Install Supabase CLI
|
||||||
uses: supabase/setup-cli@v1
|
uses: supabase/setup-cli@v1
|
||||||
@@ -132,14 +139,19 @@ jobs:
|
|||||||
|
|
||||||
- name: Wait for PostgreSQL
|
- name: Wait for PostgreSQL
|
||||||
run: sleep 30
|
run: sleep 30
|
||||||
if: matrix.database == 'postgres'
|
if: startsWith(matrix.database, 'postgres')
|
||||||
|
|
||||||
- name: Configure PostgreSQL
|
- name: Configure PostgreSQL
|
||||||
run: |
|
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 "CREATE ROLE runner SUPERUSER LOGIN;"
|
||||||
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "SELECT version();"
|
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
|
echo "POSTGRES_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV
|
||||||
if: matrix.database == 'postgres'
|
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
|
- name: Configure Supabase
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,7 +6,9 @@ dist
|
|||||||
|
|
||||||
test-results
|
test-results
|
||||||
.devcontainer
|
.devcontainer
|
||||||
|
.localstack
|
||||||
/migrations
|
/migrations
|
||||||
|
.localstack
|
||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,webstorm,sublimetext,visualstudiocode
|
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||||
|
|||||||
2
.idea/runConfigurations/Run_Dev_Fields.xml
generated
2
.idea/runConfigurations/Run_Dev_Fields.xml
generated
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run Dev Fields" type="NodeJSConfigurationType" application-parameters="fields" path-to-js-file="node_modules/.pnpm/nodemon@3.0.1/node_modules/nodemon/bin/nodemon.js" working-dir="$PROJECT_DIR$">
|
<configuration default="false" name="Run Dev Fields" type="NodeJSConfigurationType" application-parameters="fields" path-to-js-file="node_modules/.pnpm/nodemon@3.0.3/node_modules/nodemon/bin/nodemon.js" working-dir="$PROJECT_DIR$">
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
2
.idea/runConfigurations/Run_Dev__community.xml
generated
2
.idea/runConfigurations/Run_Dev__community.xml
generated
@@ -1,5 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run Dev _community" type="NodeJSConfigurationType" application-parameters="_community" path-to-js-file="node_modules/.pnpm/nodemon@3.0.1/node_modules/nodemon/bin/nodemon.js" working-dir="$PROJECT_DIR$">
|
<configuration default="false" name="Run Dev _community" type="NodeJSConfigurationType" application-parameters="_community" path-to-js-file="node_modules/.pnpm/nodemon@3.0.3/node_modules/nodemon/bin/nodemon.js" working-dir="$PROJECT_DIR$">
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
56
CHANGELOG.md
56
CHANGELOG.md
@@ -1,3 +1,59 @@
|
|||||||
|
## [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)
|
||||||
|
|
||||||
|
|
||||||
|
### 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))
|
||||||
|
* **db-postgres:** reconnect after disconnection from database ([#5086](https://github.com/payloadcms/payload/issues/5086)) ([bf942fd](https://github.com/payloadcms/payload/commit/bf942fdfa6ea9c26cf05295cc9db646bf31fa622))
|
||||||
|
* **plugin-search:** add req to beforeSync args for transactions ([#5068](https://github.com/payloadcms/payload/issues/5068)) ([98b87e2](https://github.com/payloadcms/payload/commit/98b87e22782c0a788f79326f22be05a6b176ad74))
|
||||||
|
* **richtext-lexical:** add justify aligment to AlignFeature ([#4035](https://github.com/payloadcms/payload/issues/4035)) ([#4868](https://github.com/payloadcms/payload/issues/4868)) ([6d6823c](https://github.com/payloadcms/payload/commit/6d6823c3e5609a58eeeeb8d043945a762f9463df))
|
||||||
|
* **richtext-lexical:** AddBlock handle for all nodes, even if they aren't empty paragraphs ([#5063](https://github.com/payloadcms/payload/issues/5063)) ([00fc034](https://github.com/payloadcms/payload/commit/00fc0343dabf184d5bab418d47c403b3ad11698f))
|
||||||
|
* **richtext-lexical:** Update lexical from 0.12.6 to 0.13.1, port over all useful changes from playground ([#5066](https://github.com/payloadcms/payload/issues/5066)) ([0d18822](https://github.com/payloadcms/payload/commit/0d18822062275c1826c8e2c3da2571a2b3483310))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **db-mongodb:** find versions pagination ([#5091](https://github.com/payloadcms/payload/issues/5091)) ([5d4022f](https://github.com/payloadcms/payload/commit/5d4022f1445e2809c01cb1dd599280f0a56cdc6e))
|
||||||
|
* **db-postgres:** query using blockType ([#5044](https://github.com/payloadcms/payload/issues/5044)) ([35c2a08](https://github.com/payloadcms/payload/commit/35c2a085efa6d5ad59779960874bc9728a17e3a0))
|
||||||
|
* filterOptions errors cause transaction to abort ([#5079](https://github.com/payloadcms/payload/issues/5079)) ([5f3d016](https://github.com/payloadcms/payload/commit/5f3d0169bee21e1c0963dbd7ede9fe5f1c46a5a5))
|
||||||
|
* **plugin-form-builder:** hooks do not respect transactions ([#5069](https://github.com/payloadcms/payload/issues/5069)) ([82e9d31](https://github.com/payloadcms/payload/commit/82e9d31127c8df83c5bed92a5ffdab76d331900f))
|
||||||
|
* remove collection findByID caching ([#5034](https://github.com/payloadcms/payload/issues/5034)) ([1ac943e](https://github.com/payloadcms/payload/commit/1ac943ed5e8416883b863147fdf3c23380955559))
|
||||||
|
* **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)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* exposes collapsible provider with more functionality ([#5043](https://github.com/payloadcms/payload/issues/5043)) ([df39602](https://github.com/payloadcms/payload/commit/df39602758ae8dc3765bb48e51f7a657babfa559))
|
||||||
|
|
||||||
## [2.10.1](https://github.com/payloadcms/payload/compare/v2.10.0...v2.10.1) (2024-02-09)
|
## [2.10.1](https://github.com/payloadcms/payload/compare/v2.10.0...v2.10.1) (2024-02-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -635,6 +635,37 @@ export const CustomArrayManager = () => {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
### useCollapsible
|
||||||
|
|
||||||
|
The `useCollapsible` hook allows you to control parent collapsibles:
|
||||||
|
|
||||||
|
| Property | Description |
|
||||||
|
|---------------------------|--------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| **`collapsed`** | State of the collapsible. `true` if open, `false` if collapsed |
|
||||||
|
| **`isVisible`** | If nested, determine if the nearest collapsible is visible. `true` if no parent is closed, `false` otherwise |
|
||||||
|
| **`toggle`** | Toggles the state of the nearest collapsible |
|
||||||
|
| **`withinCollapsible`** | Determine when you are within another collaspible | |
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import { useCollapsible } from 'payload/components/utilities'
|
||||||
|
|
||||||
|
const CustomComponent: React.FC = () => {
|
||||||
|
const { collapsed, toggle } = useCollapsible()
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p className="field-type">I am {collapsed ? 'closed' : 'open'}</p>
|
||||||
|
<button onClick={toggle} type="button">
|
||||||
|
Toggle
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### useDocumentInfo
|
### useDocumentInfo
|
||||||
|
|
||||||
The `useDocumentInfo` hook provides lots of information about the document currently being edited, including the following:
|
The `useDocumentInfo` hook provides lots of information about the document currently being edited, including the following:
|
||||||
|
|||||||
@@ -38,10 +38,11 @@ export default buildConfig({
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `pool` | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres`. |
|
| `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. |
|
| `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. |
|
| `migrationDir` | Customize the directory that migrations are stored. |
|
||||||
|
| `schemaName` | A string for the postgres schema to use, defaults to 'public'. |
|
||||||
|
|
||||||
### Access to Drizzle
|
### Access to Drizzle
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ If your Hook simply performs a side-effect, such as updating a CRM, it might be
|
|||||||
|
|
||||||
#### Server-only execution
|
#### 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
|
## Hook Types
|
||||||
|
|
||||||
|
|||||||
@@ -4508,9 +4508,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4701,9 +4701,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4508,9 +4508,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4258,14 +4258,14 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^1.1.5:
|
ip@^1.1.5:
|
||||||
version "1.1.8"
|
version "1.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396"
|
||||||
integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==
|
integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -3924,9 +3924,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4347,9 +4347,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4508,9 +4508,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4625,9 +4625,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4599,9 +4599,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4513,9 +4513,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -4835,9 +4835,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
@@ -3748,9 +3748,9 @@ interpret@^2.2.0:
|
|||||||
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
|
||||||
|
|
||||||
ip@^2.0.0:
|
ip@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
|
||||||
integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==
|
integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
24
package.json
24
package.json
@@ -15,9 +15,13 @@
|
|||||||
"dev:generate-graphql-schema": "ts-node -T ./test/generateGraphQLSchema.ts",
|
"dev:generate-graphql-schema": "ts-node -T ./test/generateGraphQLSchema.ts",
|
||||||
"dev:generate-types": "ts-node -T ./test/generateTypes.ts",
|
"dev:generate-types": "ts-node -T ./test/generateTypes.ts",
|
||||||
"dev:postgres": "pnpm --filter payload run dev:postgres",
|
"dev:postgres": "pnpm --filter payload run dev:postgres",
|
||||||
|
"docker:restart": "pnpm docker:stop --remove-orphans && pnpm docker:start",
|
||||||
|
"docker:start": "docker-compose -f packages/plugin-cloud-storage/docker-compose.yml up -d",
|
||||||
|
"docker:stop": "docker-compose -f packages/plugin-cloud-storage/docker-compose.yml down",
|
||||||
"fix": "eslint \"packages/**/*.ts\" --fix",
|
"fix": "eslint \"packages/**/*.ts\" --fix",
|
||||||
"lint": "eslint \"packages/**/*.ts\"",
|
"lint": "eslint \"packages/**/*.ts\"",
|
||||||
"lint-staged": "lint-staged",
|
"lint-staged": "lint-staged",
|
||||||
|
"prepare": "husky install",
|
||||||
"pretest": "pnpm build",
|
"pretest": "pnpm build",
|
||||||
"reinstall": "pnpm clean:unix && pnpm install",
|
"reinstall": "pnpm clean:unix && pnpm install",
|
||||||
"script:list-packages": "tsx ./scripts/list-packages.ts",
|
"script:list-packages": "tsx ./scripts/list-packages.ts",
|
||||||
@@ -29,10 +33,10 @@
|
|||||||
"test:e2e:headed": "cross-env DISABLE_LOGGING=true playwright test --headed",
|
"test:e2e:headed": "cross-env DISABLE_LOGGING=true playwright test --headed",
|
||||||
"test:int:postgres": "cross-env PAYLOAD_DATABASE=postgres DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
|
"test:int:postgres": "cross-env PAYLOAD_DATABASE=postgres DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
|
||||||
"test:int": "cross-env DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
|
"test:int": "cross-env DISABLE_LOGGING=true jest --forceExit --detectOpenHandles",
|
||||||
"translateNewKeys": "pnpm --filter payload run translateNewKeys",
|
"translateNewKeys": "pnpm --filter payload run translateNewKeys"
|
||||||
"prepare": "husky install"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@aws-sdk/client-s3": "^3.142.0",
|
||||||
"@payloadcms/eslint-config": "workspace:*",
|
"@payloadcms/eslint-config": "workspace:*",
|
||||||
"@playwright/test": "1.40.1",
|
"@playwright/test": "1.40.1",
|
||||||
"@swc/cli": "^0.1.62",
|
"@swc/cli": "^0.1.62",
|
||||||
@@ -77,12 +81,12 @@
|
|||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-environment-jsdom": "29.7.0",
|
"jest-environment-jsdom": "29.7.0",
|
||||||
"jwt-decode": "3.1.2",
|
"jwt-decode": "3.1.2",
|
||||||
"lexical": "0.12.5",
|
"lexical": "0.13.1",
|
||||||
"lint-staged": "^14.0.1",
|
"lint-staged": "^14.0.1",
|
||||||
"minimist": "1.2.8",
|
"minimist": "1.2.8",
|
||||||
"mongodb-memory-server": "^9",
|
"mongodb-memory-server": "^9",
|
||||||
"node-fetch": "2.6.12",
|
"node-fetch": "2.6.12",
|
||||||
"nodemon": "3.0.2",
|
"nodemon": "3.0.3",
|
||||||
"prettier": "^3.0.3",
|
"prettier": "^3.0.3",
|
||||||
"prompts": "2.4.2",
|
"prompts": "2.4.2",
|
||||||
"qs": "6.11.2",
|
"qs": "6.11.2",
|
||||||
@@ -106,12 +110,12 @@
|
|||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"copyfiles": "2.4.1",
|
"copyfiles": "$copyfiles",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "$cross-env",
|
||||||
"dotenv": "8.6.0",
|
"dotenv": "$dotenv",
|
||||||
"drizzle-orm": "0.29.3",
|
"drizzle-orm": "$drizzle-orm",
|
||||||
"ts-node": "10.9.2",
|
"ts-node": "$ts-node",
|
||||||
"typescript": "5.2.2"
|
"typescript": "$typescript"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/db-mongodb",
|
"name": "@payloadcms/db-mongodb",
|
||||||
"version": "1.4.1",
|
"version": "1.4.3",
|
||||||
"description": "The officially supported MongoDB database adapter for Payload",
|
"description": "The officially supported MongoDB database adapter for Payload",
|
||||||
"repository": "https://github.com/payloadcms/payload",
|
"repository": "https://github.com/payloadcms/payload",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ export const findVersions: FindVersions = async function findVersions(
|
|||||||
lean: true,
|
lean: true,
|
||||||
leanWithId: true,
|
leanWithId: true,
|
||||||
limit,
|
limit,
|
||||||
offset: skip || 0,
|
|
||||||
options,
|
options,
|
||||||
page,
|
page,
|
||||||
pagination,
|
pagination,
|
||||||
|
|||||||
@@ -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 */
|
/** 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
|
disableIndexHints?: boolean
|
||||||
migrationDir?: string
|
migrationDir?: string
|
||||||
|
/** Set to true to evaluate null field values as existing */
|
||||||
|
nullFieldValuesNotExist?: boolean
|
||||||
transactionOptions?: TransactionOptions | false
|
transactionOptions?: TransactionOptions | false
|
||||||
/** The URL to connect to MongoDB or false to start payload and prevent connecting */
|
/** The URL to connect to MongoDB or false to start payload and prevent connecting */
|
||||||
url: false | string
|
url: false | string
|
||||||
@@ -93,6 +95,7 @@ export function mongooseAdapter({
|
|||||||
connectOptions,
|
connectOptions,
|
||||||
disableIndexHints = false,
|
disableIndexHints = false,
|
||||||
migrationDir: migrationDirArg,
|
migrationDir: migrationDirArg,
|
||||||
|
nullFieldValuesNotExist = true,
|
||||||
transactionOptions = {},
|
transactionOptions = {},
|
||||||
url,
|
url,
|
||||||
}: Args): MongooseAdapterResult {
|
}: Args): MongooseAdapterResult {
|
||||||
@@ -103,6 +106,8 @@ export function mongooseAdapter({
|
|||||||
return createDatabaseAdapter<MongooseAdapter>({
|
return createDatabaseAdapter<MongooseAdapter>({
|
||||||
name: 'mongoose',
|
name: 'mongoose',
|
||||||
|
|
||||||
|
nullFieldValuesNotExist,
|
||||||
|
|
||||||
// Mongoose-specific
|
// Mongoose-specific
|
||||||
autoPluralization,
|
autoPluralization,
|
||||||
collections: {},
|
collections: {},
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ import type {
|
|||||||
DateField,
|
DateField,
|
||||||
EmailField,
|
EmailField,
|
||||||
Field,
|
Field,
|
||||||
|
FieldAffectingData,
|
||||||
GroupField,
|
GroupField,
|
||||||
JSONField,
|
JSONField,
|
||||||
|
NonPresentationalField,
|
||||||
NumberField,
|
NumberField,
|
||||||
PointField,
|
PointField,
|
||||||
RadioField,
|
RadioField,
|
||||||
@@ -23,12 +25,12 @@ import type {
|
|||||||
RichTextField,
|
RichTextField,
|
||||||
RowField,
|
RowField,
|
||||||
SelectField,
|
SelectField,
|
||||||
|
Tab,
|
||||||
TabsField,
|
TabsField,
|
||||||
TextField,
|
TextField,
|
||||||
TextareaField,
|
TextareaField,
|
||||||
UploadField,
|
UploadField,
|
||||||
} from 'payload/types'
|
} from 'payload/types'
|
||||||
import type { FieldAffectingData, NonPresentationalField, Tab, UnnamedTab } from 'payload/types'
|
|
||||||
|
|
||||||
import { Schema } from 'mongoose'
|
import { Schema } from 'mongoose'
|
||||||
import {
|
import {
|
||||||
@@ -61,7 +63,15 @@ const formatBaseSchema = (field: FieldAffectingData, buildSchemaOptions: BuildSc
|
|||||||
unique: (!disableUnique && field.unique) || false,
|
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
|
schema.sparse = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +89,6 @@ const localizeSchema = (
|
|||||||
) => {
|
) => {
|
||||||
if (fieldIsLocalized(entity) && localization && Array.isArray(localization.locales)) {
|
if (fieldIsLocalized(entity) && localization && Array.isArray(localization.locales)) {
|
||||||
return {
|
return {
|
||||||
localized: true,
|
|
||||||
type: localization.localeCodes.reduce(
|
type: localization.localeCodes.reduce(
|
||||||
(localeSchema, locale) => ({
|
(localeSchema, locale) => ({
|
||||||
...localeSchema,
|
...localeSchema,
|
||||||
@@ -89,6 +98,7 @@ const localizeSchema = (
|
|||||||
_id: false,
|
_id: false,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
localized: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return schema
|
return schema
|
||||||
@@ -140,7 +150,6 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
) => {
|
) => {
|
||||||
const baseSchema = {
|
const baseSchema = {
|
||||||
...formatBaseSchema(field, buildSchemaOptions),
|
...formatBaseSchema(field, buildSchemaOptions),
|
||||||
default: undefined,
|
|
||||||
type: [
|
type: [
|
||||||
buildSchema(config, field.fields, {
|
buildSchema(config, field.fields, {
|
||||||
allowIDField: true,
|
allowIDField: true,
|
||||||
@@ -153,6 +162,7 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
default: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.add({
|
schema.add({
|
||||||
@@ -166,8 +176,8 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
buildSchemaOptions: BuildSchemaOptions,
|
buildSchemaOptions: BuildSchemaOptions,
|
||||||
): void => {
|
): void => {
|
||||||
const fieldSchema = {
|
const fieldSchema = {
|
||||||
default: undefined,
|
|
||||||
type: [new Schema({}, { _id: false, discriminatorKey: 'blockType' })],
|
type: [new Schema({}, { _id: false, discriminatorKey: 'blockType' })],
|
||||||
|
default: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.add({
|
schema.add({
|
||||||
@@ -187,12 +197,12 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
if (field.localized && config.localization) {
|
if (field.localized && config.localization) {
|
||||||
config.localization.localeCodes.forEach((localeCode) => {
|
config.localization.localeCodes.forEach((localeCode) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// 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)
|
schema.path(`${field.name}.${localeCode}`).discriminator(blockItem.slug, blockSchema)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// 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)
|
schema.path(field.name).discriminator(blockItem.slug, blockSchema)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -325,14 +335,14 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
buildSchemaOptions: BuildSchemaOptions,
|
buildSchemaOptions: BuildSchemaOptions,
|
||||||
): void => {
|
): void => {
|
||||||
const baseSchema: SchemaTypeOptions<unknown> = {
|
const baseSchema: SchemaTypeOptions<unknown> = {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: ['Point'],
|
||||||
|
},
|
||||||
coordinates: {
|
coordinates: {
|
||||||
|
type: [Number],
|
||||||
default: field.defaultValue || undefined,
|
default: field.defaultValue || undefined,
|
||||||
required: false,
|
required: false,
|
||||||
type: [Number],
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
enum: ['Point'],
|
|
||||||
type: String,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if (buildSchemaOptions.disableUnique && field.unique && field.localized) {
|
if (buildSchemaOptions.disableUnique && field.unique && field.localized) {
|
||||||
@@ -366,11 +376,11 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
): void => {
|
): void => {
|
||||||
const baseSchema = {
|
const baseSchema = {
|
||||||
...formatBaseSchema(field, buildSchemaOptions),
|
...formatBaseSchema(field, buildSchemaOptions),
|
||||||
|
type: String,
|
||||||
enum: field.options.map((option) => {
|
enum: field.options.map((option) => {
|
||||||
if (typeof option === 'object') return option.value
|
if (typeof option === 'object') return option.value
|
||||||
return option
|
return option
|
||||||
}),
|
}),
|
||||||
type: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.add({
|
schema.add({
|
||||||
@@ -388,7 +398,6 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
|
|
||||||
if (field.localized && config.localization) {
|
if (field.localized && config.localization) {
|
||||||
schemaToReturn = {
|
schemaToReturn = {
|
||||||
localized: true,
|
|
||||||
type: config.localization.localeCodes.reduce((locales, locale) => {
|
type: config.localization.localeCodes.reduce((locales, locale) => {
|
||||||
let localeSchema: { [key: string]: any } = {}
|
let localeSchema: { [key: string]: any } = {}
|
||||||
|
|
||||||
@@ -396,56 +405,57 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
localeSchema = {
|
localeSchema = {
|
||||||
...formatBaseSchema(field, buildSchemaOptions),
|
...formatBaseSchema(field, buildSchemaOptions),
|
||||||
_id: false,
|
_id: false,
|
||||||
relationTo: { enum: field.relationTo, type: String },
|
|
||||||
type: Schema.Types.Mixed,
|
type: Schema.Types.Mixed,
|
||||||
|
relationTo: { type: String, enum: field.relationTo },
|
||||||
value: {
|
value: {
|
||||||
refPath: `${field.name}.${locale}.relationTo`,
|
|
||||||
type: Schema.Types.Mixed,
|
type: Schema.Types.Mixed,
|
||||||
|
refPath: `${field.name}.${locale}.relationTo`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
localeSchema = {
|
localeSchema = {
|
||||||
...formatBaseSchema(field, buildSchemaOptions),
|
...formatBaseSchema(field, buildSchemaOptions),
|
||||||
ref: field.relationTo,
|
|
||||||
type: Schema.Types.Mixed,
|
type: Schema.Types.Mixed,
|
||||||
|
ref: field.relationTo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...locales,
|
...locales,
|
||||||
[locale]: field.hasMany ? { default: undefined, type: [localeSchema] } : localeSchema,
|
[locale]: field.hasMany ? { type: [localeSchema], default: undefined } : localeSchema,
|
||||||
}
|
}
|
||||||
}, {}),
|
}, {}),
|
||||||
|
localized: true,
|
||||||
}
|
}
|
||||||
} else if (hasManyRelations) {
|
} else if (hasManyRelations) {
|
||||||
schemaToReturn = {
|
schemaToReturn = {
|
||||||
...formatBaseSchema(field, buildSchemaOptions),
|
...formatBaseSchema(field, buildSchemaOptions),
|
||||||
_id: false,
|
_id: false,
|
||||||
relationTo: { enum: field.relationTo, type: String },
|
|
||||||
type: Schema.Types.Mixed,
|
type: Schema.Types.Mixed,
|
||||||
|
relationTo: { type: String, enum: field.relationTo },
|
||||||
value: {
|
value: {
|
||||||
refPath: `${field.name}.relationTo`,
|
|
||||||
type: Schema.Types.Mixed,
|
type: Schema.Types.Mixed,
|
||||||
|
refPath: `${field.name}.relationTo`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.hasMany) {
|
if (field.hasMany) {
|
||||||
schemaToReturn = {
|
schemaToReturn = {
|
||||||
default: undefined,
|
|
||||||
type: [schemaToReturn],
|
type: [schemaToReturn],
|
||||||
|
default: undefined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
schemaToReturn = {
|
schemaToReturn = {
|
||||||
...formatBaseSchema(field, buildSchemaOptions),
|
...formatBaseSchema(field, buildSchemaOptions),
|
||||||
ref: field.relationTo,
|
|
||||||
type: Schema.Types.Mixed,
|
type: Schema.Types.Mixed,
|
||||||
|
ref: field.relationTo,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.hasMany) {
|
if (field.hasMany) {
|
||||||
schemaToReturn = {
|
schemaToReturn = {
|
||||||
default: undefined,
|
|
||||||
type: [schemaToReturn],
|
type: [schemaToReturn],
|
||||||
|
default: undefined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -488,11 +498,11 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
): void => {
|
): void => {
|
||||||
const baseSchema = {
|
const baseSchema = {
|
||||||
...formatBaseSchema(field, buildSchemaOptions),
|
...formatBaseSchema(field, buildSchemaOptions),
|
||||||
|
type: String,
|
||||||
enum: field.options.map((option) => {
|
enum: field.options.map((option) => {
|
||||||
if (typeof option === 'object') return option.value
|
if (typeof option === 'object') return option.value
|
||||||
return option
|
return option
|
||||||
}),
|
}),
|
||||||
type: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buildSchemaOptions.draftsEnabled || !field.required) {
|
if (buildSchemaOptions.draftsEnabled || !field.required) {
|
||||||
@@ -576,8 +586,8 @@ const fieldToSchemaMap: Record<string, FieldSchemaGenerator> = {
|
|||||||
): void => {
|
): void => {
|
||||||
const baseSchema = {
|
const baseSchema = {
|
||||||
...formatBaseSchema(field, buildSchemaOptions),
|
...formatBaseSchema(field, buildSchemaOptions),
|
||||||
ref: field.relationTo,
|
|
||||||
type: Schema.Types.Mixed,
|
type: Schema.Types.Mixed,
|
||||||
|
ref: field.relationTo,
|
||||||
}
|
}
|
||||||
|
|
||||||
schema.add({
|
schema.add({
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ export async function buildSearchParam({
|
|||||||
hasCustomID,
|
hasCustomID,
|
||||||
operator,
|
operator,
|
||||||
path,
|
path,
|
||||||
|
payload,
|
||||||
val,
|
val,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { Payload } from 'payload'
|
||||||
import type { Field, TabAsField } from 'payload/types'
|
import type { Field, TabAsField } from 'payload/types'
|
||||||
|
|
||||||
import mongoose from 'mongoose'
|
import mongoose from 'mongoose'
|
||||||
@@ -8,6 +9,7 @@ type SanitizeQueryValueArgs = {
|
|||||||
hasCustomID: boolean
|
hasCustomID: boolean
|
||||||
operator: string
|
operator: string
|
||||||
path: string
|
path: string
|
||||||
|
payload: Payload
|
||||||
val: any
|
val: any
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,6 +18,7 @@ export const sanitizeQueryValue = ({
|
|||||||
hasCustomID,
|
hasCustomID,
|
||||||
operator,
|
operator,
|
||||||
path,
|
path,
|
||||||
|
payload,
|
||||||
val,
|
val,
|
||||||
}: SanitizeQueryValueArgs): {
|
}: SanitizeQueryValueArgs): {
|
||||||
operator?: string
|
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 }
|
return { operator: formattedOperator, val: formattedValue }
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ export const rollbackTransaction: RollbackTransaction = async function rollbackT
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the first call for rollback should be aborted and deleted causing any other operations with the same transaction to fail
|
// the first call for rollback should be aborted and deleted causing any other operations with the same transaction to fail
|
||||||
|
try {
|
||||||
await this.sessions[id].abortTransaction()
|
await this.sessions[id].abortTransaction()
|
||||||
await this.sessions[id].endSession()
|
await this.sessions[id].endSession()
|
||||||
|
} catch (error) {
|
||||||
|
// ignore the error as it is likely a race condition from multiple errors
|
||||||
|
}
|
||||||
delete this.sessions[id]
|
delete this.sessions[id]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/db-postgres",
|
"name": "@payloadcms/db-postgres",
|
||||||
"version": "0.5.2",
|
"version": "0.7.0",
|
||||||
"description": "The officially supported Postgres database adapter for Payload",
|
"description": "The officially supported Postgres database adapter for Payload",
|
||||||
"repository": "https://github.com/payloadcms/payload",
|
"repository": "https://github.com/payloadcms/payload",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -1,13 +1,51 @@
|
|||||||
|
import type { Payload } from 'payload'
|
||||||
import type { Connect } from 'payload/database'
|
import type { Connect } from 'payload/database'
|
||||||
|
|
||||||
import { eq, sql } from 'drizzle-orm'
|
import { eq, sql } from 'drizzle-orm'
|
||||||
import { drizzle } from 'drizzle-orm/node-postgres'
|
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 { Pool } from 'pg'
|
||||||
import prompts from 'prompts'
|
import prompts from 'prompts'
|
||||||
|
|
||||||
import type { PostgresAdapter } from './types'
|
import type { PostgresAdapter } from './types'
|
||||||
|
|
||||||
|
const connectWithReconnect = async function ({
|
||||||
|
adapter,
|
||||||
|
payload,
|
||||||
|
reconnect = false,
|
||||||
|
}: {
|
||||||
|
adapter: PostgresAdapter
|
||||||
|
payload: Payload
|
||||||
|
reconnect?: boolean
|
||||||
|
}) {
|
||||||
|
let result
|
||||||
|
|
||||||
|
if (!reconnect) {
|
||||||
|
result = await adapter.pool.connect()
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
result = await adapter.pool.connect()
|
||||||
|
} catch (err) {
|
||||||
|
setTimeout(() => {
|
||||||
|
payload.logger.info('Reconnecting to postgres')
|
||||||
|
void connectWithReconnect({ adapter, payload, reconnect: true })
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.prependListener('error', (err) => {
|
||||||
|
try {
|
||||||
|
if (err.code === 'ECONNRESET') {
|
||||||
|
void connectWithReconnect({ adapter, payload, reconnect: true })
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// swallow error
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const connect: Connect = async function connect(this: PostgresAdapter, payload) {
|
export const connect: Connect = async function connect(this: PostgresAdapter, payload) {
|
||||||
this.schema = {
|
this.schema = {
|
||||||
...this.tables,
|
...this.tables,
|
||||||
@@ -17,14 +55,19 @@ export const connect: Connect = async function connect(this: PostgresAdapter, pa
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this.pool = new Pool(this.poolOptions)
|
this.pool = new Pool(this.poolOptions)
|
||||||
await this.pool.connect()
|
await connectWithReconnect({ adapter: this, payload })
|
||||||
|
|
||||||
const logger = this.logger || false
|
const logger = this.logger || false
|
||||||
|
|
||||||
this.drizzle = drizzle(this.pool, { schema: this.schema, logger })
|
this.drizzle = drizzle(this.pool, { logger, schema: this.schema })
|
||||||
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
||||||
this.payload.logger.info('---- DROPPING TABLES ----')
|
this.payload.logger.info(`---- DROPPING TABLES SCHEMA(${this.schemaName || 'public'}) ----`)
|
||||||
await this.drizzle.execute(sql`drop schema public cascade;
|
await this.drizzle.execute(
|
||||||
create schema public;`)
|
sql.raw(`
|
||||||
|
drop schema if exists ${this.schemaName || 'public'} cascade;
|
||||||
|
create schema ${this.schemaName || 'public'};
|
||||||
|
`),
|
||||||
|
)
|
||||||
this.payload.logger.info('---- DROPPED TABLES ----')
|
this.payload.logger.info('---- DROPPED TABLES ----')
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -81,7 +124,7 @@ export const connect: Connect = async function connect(this: PostgresAdapter, pa
|
|||||||
await apply()
|
await apply()
|
||||||
|
|
||||||
// Migration table def in order to use query using drizzle
|
// 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'),
|
name: varchar('name'),
|
||||||
batch: numeric('batch'),
|
batch: numeric('batch'),
|
||||||
created_at: timestamp('created_at'),
|
created_at: timestamp('created_at'),
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export const traverseFields = ({
|
|||||||
with: {},
|
with: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
const arrayTableName = `${currentTableName}_${toSnakeCase(field.name)}`
|
const arrayTableName = `${currentTableName}_${path}${toSnakeCase(field.name)}`
|
||||||
|
|
||||||
if (adapter.tables[`${arrayTableName}_locales`]) withArray.with._locales = _locales
|
if (adapter.tables[`${arrayTableName}_locales`]) withArray.with._locales = _locales
|
||||||
currentArgs.with[`${path}${field.name}`] = withArray
|
currentArgs.with[`${path}${field.name}`] = withArray
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export type { MigrateDownArgs, MigrateUpArgs } from './types'
|
|||||||
export function postgresAdapter(args: Args): PostgresAdapterResult {
|
export function postgresAdapter(args: Args): PostgresAdapterResult {
|
||||||
function adapter({ payload }: { payload: Payload }) {
|
function adapter({ payload }: { payload: Payload }) {
|
||||||
const migrationDir = findMigrationDir(args.migrationDir)
|
const migrationDir = findMigrationDir(args.migrationDir)
|
||||||
|
const idType = args.idType || 'serial'
|
||||||
return createDatabaseAdapter<PostgresAdapter>({
|
return createDatabaseAdapter<PostgresAdapter>({
|
||||||
name: 'postgres',
|
name: 'postgres',
|
||||||
|
|
||||||
@@ -50,12 +50,15 @@ export function postgresAdapter(args: Args): PostgresAdapterResult {
|
|||||||
drizzle: undefined,
|
drizzle: undefined,
|
||||||
enums: {},
|
enums: {},
|
||||||
fieldConstraints: {},
|
fieldConstraints: {},
|
||||||
|
idType,
|
||||||
logger: args.logger,
|
logger: args.logger,
|
||||||
|
pgSchema: undefined,
|
||||||
pool: undefined,
|
pool: undefined,
|
||||||
poolOptions: args.pool,
|
poolOptions: args.pool,
|
||||||
push: args.push,
|
push: args.push,
|
||||||
relations: {},
|
relations: {},
|
||||||
schema: {},
|
schema: {},
|
||||||
|
schemaName: args.schemaName,
|
||||||
sessions: {},
|
sessions: {},
|
||||||
tables: {},
|
tables: {},
|
||||||
|
|
||||||
@@ -68,7 +71,10 @@ export function postgresAdapter(args: Args): PostgresAdapterResult {
|
|||||||
createGlobalVersion,
|
createGlobalVersion,
|
||||||
createMigration,
|
createMigration,
|
||||||
createVersion,
|
createVersion,
|
||||||
defaultIDType: 'number',
|
/**
|
||||||
|
* This represents how a default ID is treated in Payload as were a field type
|
||||||
|
*/
|
||||||
|
defaultIDType: idType === 'serial' ? 'number' : 'text',
|
||||||
deleteMany,
|
deleteMany,
|
||||||
deleteOne,
|
deleteOne,
|
||||||
deleteVersions,
|
deleteVersions,
|
||||||
|
|||||||
@@ -2,16 +2,21 @@
|
|||||||
import type { Init } from 'payload/database'
|
import type { Init } from 'payload/database'
|
||||||
import type { SanitizedCollectionConfig } from 'payload/types'
|
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 { buildVersionCollectionFields, buildVersionGlobalFields } from 'payload/versions'
|
||||||
import toSnakeCase from 'to-snake-case'
|
import toSnakeCase from 'to-snake-case'
|
||||||
|
|
||||||
import type { PostgresAdapter } from './types'
|
import type { PostgresAdapter } from './types'
|
||||||
|
|
||||||
import { buildTable } from './schema/build'
|
import { buildTable } from './schema/build'
|
||||||
import { getConfigIDType } from './schema/getConfigIDType'
|
|
||||||
|
|
||||||
export const init: Init = async function init(this: PostgresAdapter) {
|
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) {
|
if (this.payload.config.localization) {
|
||||||
this.enums.enum__locales = pgEnum(
|
this.enums.enum__locales = pgEnum(
|
||||||
'_locales',
|
'_locales',
|
||||||
@@ -24,9 +29,9 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
|||||||
|
|
||||||
buildTable({
|
buildTable({
|
||||||
adapter: this,
|
adapter: this,
|
||||||
buildTexts: true,
|
|
||||||
buildNumbers: true,
|
buildNumbers: true,
|
||||||
buildRelationships: true,
|
buildRelationships: true,
|
||||||
|
buildTexts: true,
|
||||||
disableNotNull: !!collection?.versions?.drafts,
|
disableNotNull: !!collection?.versions?.drafts,
|
||||||
disableUnique: false,
|
disableUnique: false,
|
||||||
fields: collection.fields,
|
fields: collection.fields,
|
||||||
@@ -38,13 +43,11 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
|||||||
const versionsTableName = `_${tableName}_v`
|
const versionsTableName = `_${tableName}_v`
|
||||||
const versionFields = buildVersionCollectionFields(collection)
|
const versionFields = buildVersionCollectionFields(collection)
|
||||||
|
|
||||||
const versionsParentIDColType = getConfigIDType(collection.fields)
|
|
||||||
|
|
||||||
buildTable({
|
buildTable({
|
||||||
adapter: this,
|
adapter: this,
|
||||||
buildTexts: true,
|
|
||||||
buildNumbers: true,
|
buildNumbers: true,
|
||||||
buildRelationships: true,
|
buildRelationships: true,
|
||||||
|
buildTexts: true,
|
||||||
disableNotNull: !!collection.versions?.drafts,
|
disableNotNull: !!collection.versions?.drafts,
|
||||||
disableUnique: true,
|
disableUnique: true,
|
||||||
fields: versionFields,
|
fields: versionFields,
|
||||||
@@ -59,9 +62,9 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
|||||||
|
|
||||||
buildTable({
|
buildTable({
|
||||||
adapter: this,
|
adapter: this,
|
||||||
buildTexts: true,
|
|
||||||
buildNumbers: true,
|
buildNumbers: true,
|
||||||
buildRelationships: true,
|
buildRelationships: true,
|
||||||
|
buildTexts: true,
|
||||||
disableNotNull: !!global?.versions?.drafts,
|
disableNotNull: !!global?.versions?.drafts,
|
||||||
disableUnique: false,
|
disableUnique: false,
|
||||||
fields: global.fields,
|
fields: global.fields,
|
||||||
@@ -75,9 +78,9 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
|||||||
|
|
||||||
buildTable({
|
buildTable({
|
||||||
adapter: this,
|
adapter: this,
|
||||||
buildTexts: true,
|
|
||||||
buildNumbers: true,
|
buildNumbers: true,
|
||||||
buildRelationships: true,
|
buildRelationships: true,
|
||||||
|
buildTexts: true,
|
||||||
disableNotNull: !!global.versions?.drafts,
|
disableNotNull: !!global.versions?.drafts,
|
||||||
disableUnique: true,
|
disableUnique: true,
|
||||||
fields: versionFields,
|
fields: versionFields,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export async function migrate(this: PostgresAdapter): Promise<void> {
|
|||||||
latestBatch = Number(migrationsInDB[0]?.batch)
|
latestBatch = Number(migrationsInDB[0]?.batch)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await createMigrationTable(this.drizzle)
|
await createMigrationTable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (migrationsInDB.find((m) => m.batch === -1)) {
|
if (migrationsInDB.find((m) => m.batch === -1)) {
|
||||||
|
|||||||
@@ -44,8 +44,10 @@ export async function migrateFresh(
|
|||||||
msg: `Dropping database.`,
|
msg: `Dropping database.`,
|
||||||
})
|
})
|
||||||
|
|
||||||
await this.drizzle.execute(sql`drop schema public cascade;
|
await this.drizzle.execute(
|
||||||
create schema public;`)
|
sql.raw(`drop schema ${this.schemaName || 'public'} cascade;
|
||||||
|
create schema ${this.schemaName || 'public'};`),
|
||||||
|
)
|
||||||
|
|
||||||
const migrationFiles = await readMigrationFiles({ payload })
|
const migrationFiles = await readMigrationFiles({ payload })
|
||||||
payload.logger.debug({
|
payload.logger.debug({
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { SQL } from 'drizzle-orm'
|
import type { SQL } from 'drizzle-orm'
|
||||||
|
import type { PgTableWithColumns } from 'drizzle-orm/pg-core'
|
||||||
import type { Field, Where } from 'payload/types'
|
import type { Field, Where } from 'payload/types'
|
||||||
|
|
||||||
import { asc, desc } from 'drizzle-orm'
|
import { asc, desc } from 'drizzle-orm'
|
||||||
@@ -12,7 +13,7 @@ export type BuildQueryJoins = Record<string, SQL>
|
|||||||
|
|
||||||
export type BuildQueryJoinAliases = {
|
export type BuildQueryJoinAliases = {
|
||||||
condition: SQL
|
condition: SQL
|
||||||
table: GenericTable
|
table: GenericTable | PgTableWithColumns<any>
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
type BuildQueryArgs = {
|
type BuildQueryArgs = {
|
||||||
@@ -75,6 +76,7 @@ const buildQuery = async function buildQuery({
|
|||||||
pathSegments: sortPath.replace(/__/g, '.').split('.'),
|
pathSegments: sortPath.replace(/__/g, '.').split('.'),
|
||||||
selectFields,
|
selectFields,
|
||||||
tableName,
|
tableName,
|
||||||
|
value: sortPath,
|
||||||
})
|
})
|
||||||
orderBy.column = sortTable?.[sortTableColumnName]
|
orderBy.column = sortTable?.[sortTableColumnName]
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import type { SQL } from 'drizzle-orm'
|
import type { SQL } from 'drizzle-orm'
|
||||||
import type { Field, FieldAffectingData, TabAsField } 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 { and, eq, like, sql } from 'drizzle-orm'
|
||||||
import { alias } from 'drizzle-orm/pg-core'
|
import { alias } from 'drizzle-orm/pg-core'
|
||||||
@@ -15,7 +16,7 @@ import type { BuildQueryJoinAliases, BuildQueryJoins } from './buildQuery'
|
|||||||
|
|
||||||
type Constraint = {
|
type Constraint = {
|
||||||
columnName: string
|
columnName: string
|
||||||
table: GenericTable
|
table: GenericTable | PgTableWithColumns<any>
|
||||||
value: unknown
|
value: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,12 +27,12 @@ type TableColumn = {
|
|||||||
getNotNullColumnByValue?: (val: unknown) => string
|
getNotNullColumnByValue?: (val: unknown) => string
|
||||||
pathSegments?: string[]
|
pathSegments?: string[]
|
||||||
rawColumn?: SQL
|
rawColumn?: SQL
|
||||||
table: GenericTable
|
table: GenericTable | PgTableWithColumns<any>
|
||||||
}
|
}
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
adapter: PostgresAdapter
|
adapter: PostgresAdapter
|
||||||
aliasTable?: GenericTable
|
aliasTable?: GenericTable | PgTableWithColumns<any>
|
||||||
collectionPath: string
|
collectionPath: string
|
||||||
columnPrefix?: string
|
columnPrefix?: string
|
||||||
constraintPath?: string
|
constraintPath?: string
|
||||||
@@ -48,6 +49,10 @@ type Args = {
|
|||||||
* If creating a new table name for arrays and blocks, this suffix should be appended to the table name
|
* If creating a new table name for arrays and blocks, this suffix should be appended to the table name
|
||||||
*/
|
*/
|
||||||
tableNameSuffix?: string
|
tableNameSuffix?: string
|
||||||
|
/**
|
||||||
|
* The raw value of the query before sanitization
|
||||||
|
*/
|
||||||
|
value: unknown
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Transforms path to table and column name
|
* Transforms path to table and column name
|
||||||
@@ -70,6 +75,7 @@ export const getTableColumnFromPath = ({
|
|||||||
selectFields,
|
selectFields,
|
||||||
tableName,
|
tableName,
|
||||||
tableNameSuffix = '',
|
tableNameSuffix = '',
|
||||||
|
value,
|
||||||
}: Args): TableColumn => {
|
}: Args): TableColumn => {
|
||||||
const fieldPath = incomingSegments[0]
|
const fieldPath = incomingSegments[0]
|
||||||
let locale = incomingLocale
|
let locale = incomingLocale
|
||||||
@@ -88,8 +94,8 @@ export const getTableColumnFromPath = ({
|
|||||||
constraints,
|
constraints,
|
||||||
field: {
|
field: {
|
||||||
name: 'id',
|
name: 'id',
|
||||||
type: 'number',
|
type: adapter.idType === 'uuid' ? 'text' : 'number',
|
||||||
},
|
} as TextField | NumberField,
|
||||||
table: adapter.tables[newTableName],
|
table: adapter.tables[newTableName],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,6 +137,7 @@ export const getTableColumnFromPath = ({
|
|||||||
selectFields,
|
selectFields,
|
||||||
tableName: newTableName,
|
tableName: newTableName,
|
||||||
tableNameSuffix,
|
tableNameSuffix,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
case 'tab': {
|
case 'tab': {
|
||||||
@@ -151,6 +158,7 @@ export const getTableColumnFromPath = ({
|
|||||||
selectFields,
|
selectFields,
|
||||||
tableName: newTableName,
|
tableName: newTableName,
|
||||||
tableNameSuffix: `${tableNameSuffix}${toSnakeCase(field.name)}_`,
|
tableNameSuffix: `${tableNameSuffix}${toSnakeCase(field.name)}_`,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return getTableColumnFromPath({
|
return getTableColumnFromPath({
|
||||||
@@ -169,6 +177,7 @@ export const getTableColumnFromPath = ({
|
|||||||
selectFields,
|
selectFields,
|
||||||
tableName: newTableName,
|
tableName: newTableName,
|
||||||
tableNameSuffix,
|
tableNameSuffix,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +213,7 @@ export const getTableColumnFromPath = ({
|
|||||||
selectFields,
|
selectFields,
|
||||||
tableName: newTableName,
|
tableName: newTableName,
|
||||||
tableNameSuffix: `${tableNameSuffix}${toSnakeCase(field.name)}_`,
|
tableNameSuffix: `${tableNameSuffix}${toSnakeCase(field.name)}_`,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,12 +251,39 @@ export const getTableColumnFromPath = ({
|
|||||||
rootTableName,
|
rootTableName,
|
||||||
selectFields,
|
selectFields,
|
||||||
tableName: newTableName,
|
tableName: newTableName,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'blocks': {
|
case 'blocks': {
|
||||||
let blockTableColumn: TableColumn
|
let blockTableColumn: TableColumn
|
||||||
let newTableName: string
|
let newTableName: string
|
||||||
|
|
||||||
|
// handle blockType queries
|
||||||
|
if (pathSegments[1] === 'blockType') {
|
||||||
|
// find the block config using the value
|
||||||
|
const blockTypes = Array.isArray(value) ? value : [value]
|
||||||
|
blockTypes.forEach((blockType) => {
|
||||||
|
const block = field.blocks.find((block) => block.slug === blockType)
|
||||||
|
newTableName = `${tableName}_blocks_${toSnakeCase(block.slug)}`
|
||||||
|
joins[newTableName] = eq(
|
||||||
|
adapter.tables[tableName].id,
|
||||||
|
adapter.tables[newTableName]._parentID,
|
||||||
|
)
|
||||||
|
constraints.push({
|
||||||
|
columnName: '_path',
|
||||||
|
table: adapter.tables[newTableName],
|
||||||
|
value: pathSegments[0],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
constraints,
|
||||||
|
field,
|
||||||
|
getNotNullColumnByValue: () => 'id',
|
||||||
|
table: adapter.tables[tableName],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const hasBlockField = field.blocks.some((block) => {
|
const hasBlockField = field.blocks.some((block) => {
|
||||||
newTableName = `${tableName}_blocks_${toSnakeCase(block.slug)}`
|
newTableName = `${tableName}_blocks_${toSnakeCase(block.slug)}`
|
||||||
constraintPath = `${constraintPath}${field.name}.%.`
|
constraintPath = `${constraintPath}${field.name}.%.`
|
||||||
@@ -267,6 +304,7 @@ export const getTableColumnFromPath = ({
|
|||||||
rootTableName,
|
rootTableName,
|
||||||
selectFields: blockSelectFields,
|
selectFields: blockSelectFields,
|
||||||
tableName: newTableName,
|
tableName: newTableName,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// this is fine, not every block will have the field
|
// this is fine, not every block will have the field
|
||||||
@@ -307,9 +345,6 @@ export const getTableColumnFromPath = ({
|
|||||||
table: blockTableColumn.table,
|
table: blockTableColumn.table,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pathSegments[1] === 'blockType') {
|
|
||||||
throw new APIError('Querying on blockType is not supported')
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,6 +432,7 @@ export const getTableColumnFromPath = ({
|
|||||||
rootTableName: newTableName,
|
rootTableName: newTableName,
|
||||||
selectFields,
|
selectFields,
|
||||||
tableName: newTableName,
|
tableName: newTableName,
|
||||||
|
value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,12 +63,8 @@ export async function parseParams({
|
|||||||
where: condition,
|
where: condition,
|
||||||
})
|
})
|
||||||
if (builtConditions.length > 0) {
|
if (builtConditions.length > 0) {
|
||||||
if (result) {
|
|
||||||
result = operatorMap[conditionOperator](result, ...builtConditions)
|
|
||||||
} else {
|
|
||||||
result = operatorMap[conditionOperator](...builtConditions)
|
result = operatorMap[conditionOperator](...builtConditions)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// It's a path - and there can be multiple comparisons on a single path.
|
// It's a path - and there can be multiple comparisons on a single path.
|
||||||
// For example - title like 'test' and title not equal to 'tester'
|
// For example - title like 'test' and title not equal to 'tester'
|
||||||
@@ -77,6 +73,7 @@ export async function parseParams({
|
|||||||
if (typeof pathOperators === 'object') {
|
if (typeof pathOperators === 'object') {
|
||||||
for (const operator of Object.keys(pathOperators)) {
|
for (const operator of Object.keys(pathOperators)) {
|
||||||
if (validOperators.includes(operator as Operator)) {
|
if (validOperators.includes(operator as Operator)) {
|
||||||
|
const val = where[relationOrPath][operator]
|
||||||
const {
|
const {
|
||||||
columnName,
|
columnName,
|
||||||
constraints: queryConstraints,
|
constraints: queryConstraints,
|
||||||
@@ -95,10 +92,9 @@ export async function parseParams({
|
|||||||
pathSegments: relationOrPath.replace(/__/g, '.').split('.'),
|
pathSegments: relationOrPath.replace(/__/g, '.').split('.'),
|
||||||
selectFields,
|
selectFields,
|
||||||
tableName,
|
tableName,
|
||||||
|
value: val,
|
||||||
})
|
})
|
||||||
|
|
||||||
const val = where[relationOrPath][operator]
|
|
||||||
|
|
||||||
queryConstraints.forEach(({ columnName: col, table: constraintTable, value }) => {
|
queryConstraints.forEach(({ columnName: col, table: constraintTable, value }) => {
|
||||||
if (typeof value === 'string' && value.indexOf('%') > -1) {
|
if (typeof value === 'string' && value.indexOf('%') > -1) {
|
||||||
constraints.push(operatorMap.like(constraintTable[col], value))
|
constraints.push(operatorMap.like(constraintTable[col], value))
|
||||||
@@ -169,6 +165,7 @@ export async function parseParams({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sanitizedQueryValue = sanitizeQueryValue({
|
const sanitizedQueryValue = sanitizeQueryValue({
|
||||||
|
adapter,
|
||||||
field,
|
field,
|
||||||
operator,
|
operator,
|
||||||
relationOrPath,
|
relationOrPath,
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { APIError } from 'payload/errors'
|
|||||||
import { type Field, type TabAsField, fieldAffectsData } from 'payload/types'
|
import { type Field, type TabAsField, fieldAffectsData } from 'payload/types'
|
||||||
import { createArrayFromCommaDelineated } from 'payload/utilities'
|
import { createArrayFromCommaDelineated } from 'payload/utilities'
|
||||||
|
|
||||||
|
import type { PostgresAdapter } from '../types'
|
||||||
|
|
||||||
type SanitizeQueryValueArgs = {
|
type SanitizeQueryValueArgs = {
|
||||||
|
adapter: PostgresAdapter
|
||||||
field: Field | TabAsField
|
field: Field | TabAsField
|
||||||
operator: string
|
operator: string
|
||||||
relationOrPath: string
|
relationOrPath: string
|
||||||
@@ -10,6 +13,7 @@ type SanitizeQueryValueArgs = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const sanitizeQueryValue = ({
|
export const sanitizeQueryValue = ({
|
||||||
|
adapter,
|
||||||
field,
|
field,
|
||||||
operator: operatorArg,
|
operator: operatorArg,
|
||||||
relationOrPath,
|
relationOrPath,
|
||||||
@@ -27,8 +31,10 @@ export const sanitizeQueryValue = ({
|
|||||||
) {
|
) {
|
||||||
const allPossibleIDTypes: (number | string)[] = []
|
const allPossibleIDTypes: (number | string)[] = []
|
||||||
formattedValue.forEach((val) => {
|
formattedValue.forEach((val) => {
|
||||||
if (typeof val === 'string') {
|
if (adapter.idType !== 'uuid' && typeof val === 'string') {
|
||||||
allPossibleIDTypes.push(val, parseInt(val))
|
allPossibleIDTypes.push(val, parseInt(val))
|
||||||
|
} else if (typeof val === 'string') {
|
||||||
|
allPossibleIDTypes.push(val)
|
||||||
} else {
|
} else {
|
||||||
allPossibleIDTypes.push(val, String(val))
|
allPossibleIDTypes.push(val, String(val))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,22 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import type { Relation } from 'drizzle-orm'
|
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 type { Field } from 'payload/types'
|
||||||
|
|
||||||
import { relations } from 'drizzle-orm'
|
import { relations } from 'drizzle-orm'
|
||||||
import {
|
import { index, integer, numeric, serial, timestamp, unique, varchar } from 'drizzle-orm/pg-core'
|
||||||
index,
|
|
||||||
integer,
|
|
||||||
numeric,
|
|
||||||
pgTable,
|
|
||||||
serial,
|
|
||||||
timestamp,
|
|
||||||
unique,
|
|
||||||
varchar,
|
|
||||||
} from 'drizzle-orm/pg-core'
|
|
||||||
import { fieldAffectsData } from 'payload/types'
|
import { fieldAffectsData } from 'payload/types'
|
||||||
import toSnakeCase from 'to-snake-case'
|
import toSnakeCase from 'to-snake-case'
|
||||||
|
|
||||||
import type { GenericColumns, GenericTable, PostgresAdapter } from '../types'
|
import type { GenericColumns, GenericTable, IDType, PostgresAdapter } from '../types'
|
||||||
|
|
||||||
import { getConfigIDType } from './getConfigIDType'
|
|
||||||
import { parentIDColumnMap } from './parentIDColumnMap'
|
import { parentIDColumnMap } from './parentIDColumnMap'
|
||||||
|
import { setColumnID } from './setColumnID'
|
||||||
import { traverseFields } from './traverseFields'
|
import { traverseFields } from './traverseFields'
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
@@ -77,27 +73,20 @@ export const buildTable = ({
|
|||||||
|
|
||||||
const localesColumns: Record<string, PgColumnBuilder> = {}
|
const localesColumns: Record<string, PgColumnBuilder> = {}
|
||||||
const localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder> = {}
|
const localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder> = {}
|
||||||
let localesTable: GenericTable
|
let localesTable: GenericTable | PgTableWithColumns<any>
|
||||||
let textsTable: GenericTable
|
let textsTable: GenericTable | PgTableWithColumns<any>
|
||||||
let numbersTable: GenericTable
|
let numbersTable: GenericTable | PgTableWithColumns<any>
|
||||||
|
|
||||||
// Relationships to the base collection
|
// Relationships to the base collection
|
||||||
const relationships: Set<string> = rootRelationships || new Set()
|
const relationships: Set<string> = rootRelationships || new Set()
|
||||||
|
|
||||||
let relationshipsTable: GenericTable
|
let relationshipsTable: GenericTable | PgTableWithColumns<any>
|
||||||
|
|
||||||
// Drizzle relations
|
// Drizzle relations
|
||||||
const relationsToBuild: Map<string, string> = new Map()
|
const relationsToBuild: Map<string, string> = new Map()
|
||||||
|
|
||||||
const idColType = getConfigIDType(fields)
|
const idColType: IDType = setColumnID({ adapter, columns, fields })
|
||||||
|
|
||||||
const idColTypeMap = {
|
|
||||||
integer: serial,
|
|
||||||
numeric,
|
|
||||||
varchar,
|
|
||||||
}
|
|
||||||
|
|
||||||
columns.id = idColTypeMap[idColType]('id').primaryKey()
|
|
||||||
;({
|
;({
|
||||||
hasLocalizedField,
|
hasLocalizedField,
|
||||||
hasLocalizedManyNumberField,
|
hasLocalizedManyNumberField,
|
||||||
@@ -143,7 +132,7 @@ export const buildTable = ({
|
|||||||
.notNull()
|
.notNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
const table = pgTable(tableName, columns, (cols) => {
|
const table = adapter.pgSchema.table(tableName, columns, (cols) => {
|
||||||
const extraConfig = Object.entries(baseExtraConfig).reduce((config, [key, func]) => {
|
const extraConfig = Object.entries(baseExtraConfig).reduce((config, [key, func]) => {
|
||||||
config[key] = func(cols)
|
config[key] = func(cols)
|
||||||
return config
|
return config
|
||||||
@@ -165,7 +154,7 @@ export const buildTable = ({
|
|||||||
.references(() => table.id, { onDelete: 'cascade' })
|
.references(() => table.id, { onDelete: 'cascade' })
|
||||||
.notNull()
|
.notNull()
|
||||||
|
|
||||||
localesTable = pgTable(localeTableName, localesColumns, (cols) => {
|
localesTable = adapter.pgSchema.table(localeTableName, localesColumns, (cols) => {
|
||||||
return Object.entries(localesIndexes).reduce(
|
return Object.entries(localesIndexes).reduce(
|
||||||
(acc, [colName, func]) => {
|
(acc, [colName, func]) => {
|
||||||
acc[colName] = func(cols)
|
acc[colName] = func(cols)
|
||||||
@@ -208,7 +197,7 @@ export const buildTable = ({
|
|||||||
columns.locale = adapter.enums.enum__locales('locale')
|
columns.locale = adapter.enums.enum__locales('locale')
|
||||||
}
|
}
|
||||||
|
|
||||||
textsTable = pgTable(textsTableName, columns, (cols) => {
|
textsTable = adapter.pgSchema.table(textsTableName, columns, (cols) => {
|
||||||
const indexes: Record<string, IndexBuilder> = {
|
const indexes: Record<string, IndexBuilder> = {
|
||||||
orderParentIdx: index(`${textsTableName}_order_parent_idx`).on(cols.order, cols.parent),
|
orderParentIdx: index(`${textsTableName}_order_parent_idx`).on(cols.order, cols.parent),
|
||||||
}
|
}
|
||||||
@@ -252,7 +241,7 @@ export const buildTable = ({
|
|||||||
columns.locale = adapter.enums.enum__locales('locale')
|
columns.locale = adapter.enums.enum__locales('locale')
|
||||||
}
|
}
|
||||||
|
|
||||||
numbersTable = pgTable(numbersTableName, columns, (cols) => {
|
numbersTable = adapter.pgSchema.table(numbersTableName, columns, (cols) => {
|
||||||
const indexes: Record<string, IndexBuilder> = {
|
const indexes: Record<string, IndexBuilder> = {
|
||||||
orderParentIdx: index(`${numbersTableName}_order_parent_idx`).on(cols.order, cols.parent),
|
orderParentIdx: index(`${numbersTableName}_order_parent_idx`).on(cols.order, cols.parent),
|
||||||
}
|
}
|
||||||
@@ -300,7 +289,7 @@ export const buildTable = ({
|
|||||||
|
|
||||||
relationships.forEach((relationTo) => {
|
relationships.forEach((relationTo) => {
|
||||||
const formattedRelationTo = toSnakeCase(relationTo)
|
const formattedRelationTo = toSnakeCase(relationTo)
|
||||||
let colType = 'integer'
|
let colType = adapter.idType === 'uuid' ? 'uuid' : 'integer'
|
||||||
const relatedCollectionCustomID = adapter.payload.collections[
|
const relatedCollectionCustomID = adapter.payload.collections[
|
||||||
relationTo
|
relationTo
|
||||||
].config.fields.find((field) => fieldAffectsData(field) && field.name === 'id')
|
].config.fields.find((field) => fieldAffectsData(field) && field.name === 'id')
|
||||||
@@ -314,7 +303,10 @@ export const buildTable = ({
|
|||||||
|
|
||||||
const relationshipsTableName = `${tableName}_rels`
|
const relationshipsTableName = `${tableName}_rels`
|
||||||
|
|
||||||
relationshipsTable = pgTable(relationshipsTableName, relationshipColumns, (cols) => {
|
relationshipsTable = adapter.pgSchema.table(
|
||||||
|
relationshipsTableName,
|
||||||
|
relationshipColumns,
|
||||||
|
(cols) => {
|
||||||
const result: Record<string, unknown> = {
|
const result: Record<string, unknown> = {
|
||||||
order: index(`${relationshipsTableName}_order_idx`).on(cols.order),
|
order: index(`${relationshipsTableName}_order_idx`).on(cols.order),
|
||||||
parentIdx: index(`${relationshipsTableName}_parent_idx`).on(cols.parent),
|
parentIdx: index(`${relationshipsTableName}_parent_idx`).on(cols.parent),
|
||||||
@@ -326,7 +318,8 @@ export const buildTable = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
adapter.tables[relationshipsTableName] = relationshipsTable
|
adapter.tables[relationshipsTableName] = relationshipsTable
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { type Field, fieldAffectsData } from 'payload/types'
|
|
||||||
|
|
||||||
export const getConfigIDType = (fields: Field[]): string => {
|
|
||||||
const idField = fields.find((field) => fieldAffectsData(field) && field.name === 'id')
|
|
||||||
|
|
||||||
if (idField) {
|
|
||||||
if (idField.type === 'number') {
|
|
||||||
return 'numeric'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idField.type === 'text') {
|
|
||||||
return 'varchar'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'integer'
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,13 @@
|
|||||||
import { integer, numeric, varchar } from 'drizzle-orm/pg-core'
|
import { integer, numeric, uuid, varchar } from 'drizzle-orm/pg-core'
|
||||||
|
|
||||||
export const parentIDColumnMap = {
|
import type { IDType } from '../types'
|
||||||
|
|
||||||
|
export const parentIDColumnMap: Record<
|
||||||
|
IDType,
|
||||||
|
typeof integer<string> | typeof numeric<string> | typeof uuid<string> | typeof varchar
|
||||||
|
> = {
|
||||||
integer,
|
integer,
|
||||||
numeric,
|
numeric,
|
||||||
|
uuid,
|
||||||
varchar,
|
varchar,
|
||||||
}
|
}
|
||||||
|
|||||||
33
packages/db-postgres/src/schema/setColumnID.ts
Normal file
33
packages/db-postgres/src/schema/setColumnID.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import type { PgColumnBuilder } from 'drizzle-orm/pg-core'
|
||||||
|
|
||||||
|
import { numeric, serial, uuid, varchar } from 'drizzle-orm/pg-core'
|
||||||
|
import { type Field, fieldAffectsData } from 'payload/types'
|
||||||
|
import { flattenTopLevelFields } from 'payload/utilities'
|
||||||
|
|
||||||
|
import type { IDType, PostgresAdapter } from '../types'
|
||||||
|
|
||||||
|
type Args = { adapter: PostgresAdapter; columns: Record<string, PgColumnBuilder>; fields: Field[] }
|
||||||
|
export const setColumnID = ({ adapter, columns, fields }: Args): IDType => {
|
||||||
|
const idField = flattenTopLevelFields(fields).find(
|
||||||
|
(field) => fieldAffectsData(field) && field.name === 'id',
|
||||||
|
)
|
||||||
|
if (idField) {
|
||||||
|
if (idField.type === 'number') {
|
||||||
|
columns.id = numeric('id').primaryKey()
|
||||||
|
return 'numeric'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idField.type === 'text') {
|
||||||
|
columns.id = varchar('id').primaryKey()
|
||||||
|
return 'varchar'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adapter.idType === 'uuid') {
|
||||||
|
columns.id = uuid('id').defaultRandom().primaryKey()
|
||||||
|
return 'uuid'
|
||||||
|
}
|
||||||
|
|
||||||
|
columns.id = serial('id').primaryKey()
|
||||||
|
return 'integer'
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import type { Field, TabAsField } from 'payload/types'
|
|||||||
import { relations } from 'drizzle-orm'
|
import { relations } from 'drizzle-orm'
|
||||||
import {
|
import {
|
||||||
PgNumericBuilder,
|
PgNumericBuilder,
|
||||||
|
PgUUIDBuilder,
|
||||||
PgVarcharBuilder,
|
PgVarcharBuilder,
|
||||||
boolean,
|
boolean,
|
||||||
index,
|
index,
|
||||||
@@ -21,7 +22,7 @@ import { InvalidConfiguration } from 'payload/errors'
|
|||||||
import { fieldAffectsData, optionIsObject } from 'payload/types'
|
import { fieldAffectsData, optionIsObject } from 'payload/types'
|
||||||
import toSnakeCase from 'to-snake-case'
|
import toSnakeCase from 'to-snake-case'
|
||||||
|
|
||||||
import type { GenericColumns, PostgresAdapter } from '../types'
|
import type { GenericColumns, IDType, PostgresAdapter } from '../types'
|
||||||
|
|
||||||
import { hasLocalesTable } from '../utilities/hasLocalesTable'
|
import { hasLocalesTable } from '../utilities/hasLocalesTable'
|
||||||
import { buildTable } from './build'
|
import { buildTable } from './build'
|
||||||
@@ -93,7 +94,8 @@ export const traverseFields = ({
|
|||||||
let hasManyNumberField: 'index' | boolean = false
|
let hasManyNumberField: 'index' | boolean = false
|
||||||
let hasLocalizedManyNumberField = false
|
let hasLocalizedManyNumberField = false
|
||||||
|
|
||||||
let parentIDColType = 'integer'
|
let parentIDColType: IDType = 'integer'
|
||||||
|
if (columns.id instanceof PgUUIDBuilder) parentIDColType = 'uuid'
|
||||||
if (columns.id instanceof PgNumericBuilder) parentIDColType = 'numeric'
|
if (columns.id instanceof PgNumericBuilder) parentIDColType = 'numeric'
|
||||||
if (columns.id instanceof PgVarcharBuilder) parentIDColType = 'varchar'
|
if (columns.id instanceof PgVarcharBuilder) parentIDColType = 'varchar'
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,14 @@ import type {
|
|||||||
Relations,
|
Relations,
|
||||||
} from 'drizzle-orm'
|
} from 'drizzle-orm'
|
||||||
import type { NodePgDatabase, NodePgQueryResultHKT } from 'drizzle-orm/node-postgres'
|
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 { Payload } from 'payload'
|
||||||
import type { BaseDatabaseAdapter } from 'payload/database'
|
import type { BaseDatabaseAdapter } from 'payload/database'
|
||||||
import type { PayloadRequest } from 'payload/types'
|
import type { PayloadRequest } from 'payload/types'
|
||||||
@@ -16,10 +23,12 @@ import type { Pool, PoolConfig } from 'pg'
|
|||||||
export type DrizzleDB = NodePgDatabase<Record<string, unknown>>
|
export type DrizzleDB = NodePgDatabase<Record<string, unknown>>
|
||||||
|
|
||||||
export type Args = {
|
export type Args = {
|
||||||
|
idType?: 'serial' | 'uuid'
|
||||||
logger?: DrizzleConfig['logger']
|
logger?: DrizzleConfig['logger']
|
||||||
migrationDir?: string
|
migrationDir?: string
|
||||||
pool: PoolConfig
|
pool: PoolConfig
|
||||||
push?: boolean
|
push?: boolean
|
||||||
|
schemaName?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GenericColumn = PgColumn<
|
export type GenericColumn = PgColumn<
|
||||||
@@ -56,12 +65,15 @@ export type PostgresAdapter = BaseDatabaseAdapter & {
|
|||||||
* Used for returning properly formed errors from unique fields
|
* Used for returning properly formed errors from unique fields
|
||||||
*/
|
*/
|
||||||
fieldConstraints: Record<string, Record<string, string>>
|
fieldConstraints: Record<string, Record<string, string>>
|
||||||
|
idType: Args['idType']
|
||||||
logger: DrizzleConfig['logger']
|
logger: DrizzleConfig['logger']
|
||||||
|
pgSchema?: { table: PgTableFn } | PgSchema
|
||||||
pool: Pool
|
pool: Pool
|
||||||
poolOptions: Args['pool']
|
poolOptions: Args['pool']
|
||||||
push: boolean
|
push: boolean
|
||||||
relations: Record<string, GenericRelation>
|
relations: Record<string, GenericRelation>
|
||||||
schema: Record<string, GenericEnum | GenericRelation | GenericTable>
|
schema: Record<string, GenericEnum | GenericRelation | GenericTable>
|
||||||
|
schemaName?: Args['schemaName']
|
||||||
sessions: {
|
sessions: {
|
||||||
[id: string]: {
|
[id: string]: {
|
||||||
db: DrizzleTransaction
|
db: DrizzleTransaction
|
||||||
@@ -69,9 +81,11 @@ export type PostgresAdapter = BaseDatabaseAdapter & {
|
|||||||
resolve: () => Promise<void>
|
resolve: () => Promise<void>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tables: Record<string, GenericTable>
|
tables: Record<string, GenericTable | PgTableWithColumns<any>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type IDType = 'integer' | 'numeric' | 'uuid' | 'varchar'
|
||||||
|
|
||||||
export type PostgresAdapterResult = (args: { payload: Payload }) => PostgresAdapter
|
export type PostgresAdapterResult = (args: { payload: Payload }) => PostgresAdapter
|
||||||
|
|
||||||
export type MigrateUpArgs = { payload: Payload; req?: Partial<PayloadRequest> }
|
export type MigrateUpArgs = { payload: Payload; req?: Partial<PayloadRequest> }
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ export const insertArrays = async ({ adapter, arrays, db, parentRows }: Args): P
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentID = parentRows[parentRowIndex].id || parentRows[parentRowIndex]._parentID
|
const parentID = parentRows[parentRowIndex].id
|
||||||
|
|
||||||
// Add any sub arrays that need to be created
|
// Add any sub arrays that need to be created
|
||||||
// We will call this recursively below
|
// We will call this recursively below
|
||||||
arrayRows.forEach((arrayRow) => {
|
arrayRows.forEach((arrayRow, i) => {
|
||||||
if (Object.keys(arrayRow.arrays).length > 0) {
|
if (Object.keys(arrayRow.arrays).length > 0) {
|
||||||
rowsByTable[tableName].arrays.push(arrayRow.arrays)
|
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._parentID = arrayRow.row.id
|
||||||
arrayRowLocaleData._locale = arrayRowLocale
|
arrayRowLocaleData._locale = arrayRowLocale
|
||||||
rowsByTable[tableName].locales.push(arrayRowLocaleData)
|
rowsByTable[tableName].locales.push(arrayRowLocaleData)
|
||||||
|
if (!arrayRow.row.id) {
|
||||||
|
arrayRowLocaleData._getParentID = (rows) => rows[i].id
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -61,12 +64,23 @@ export const insertArrays = async ({ adapter, arrays, db, parentRows }: Args): P
|
|||||||
// Insert all corresponding arrays
|
// Insert all corresponding arrays
|
||||||
// (one insert per array table)
|
// (one insert per array table)
|
||||||
for (const [tableName, row] of Object.entries(rowsByTable)) {
|
for (const [tableName, row] of Object.entries(rowsByTable)) {
|
||||||
|
// the nested arrays need the ID for the parentID foreign key
|
||||||
|
let insertedRows: Args['parentRows']
|
||||||
if (row.rows.length > 0) {
|
if (row.rows.length > 0) {
|
||||||
await db.insert(adapter.tables[tableName]).values(row.rows).returning()
|
insertedRows = await db.insert(adapter.tables[tableName]).values(row.rows).returning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert locale rows
|
// Insert locale rows
|
||||||
if (adapter.tables[`${tableName}_locales`] && row.locales.length > 0) {
|
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()
|
await db.insert(adapter.tables[`${tableName}_locales`]).values(row.locales).returning()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +90,7 @@ export const insertArrays = async ({ adapter, arrays, db, parentRows }: Args): P
|
|||||||
adapter,
|
adapter,
|
||||||
arrays: row.arrays,
|
arrays: row.arrays,
|
||||||
db,
|
db,
|
||||||
parentRows: row.rows,
|
parentRows: insertedRows,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import { sql } from 'drizzle-orm'
|
import { sql } from 'drizzle-orm'
|
||||||
|
|
||||||
import type { DrizzleDB } from '../types'
|
import type { PostgresAdapter } from '../types'
|
||||||
|
|
||||||
export const createMigrationTable = async (db: DrizzleDB): Promise<void> => {
|
export const createMigrationTable = async (adapter: PostgresAdapter): Promise<void> => {
|
||||||
await db.execute(sql`CREATE TABLE IF NOT EXISTS "payload_migrations" (
|
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,
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
"name" varchar,
|
"name" varchar,
|
||||||
"batch" numeric,
|
"batch" numeric,
|
||||||
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||||
);`)
|
);`),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "payload",
|
"name": "payload",
|
||||||
"version": "2.10.1",
|
"version": "2.11.2",
|
||||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
@@ -101,7 +101,6 @@
|
|||||||
"jwt-decode": "3.1.2",
|
"jwt-decode": "3.1.2",
|
||||||
"md5": "2.3.0",
|
"md5": "2.3.0",
|
||||||
"method-override": "3.0.0",
|
"method-override": "3.0.0",
|
||||||
"micro-memoize": "4.1.2",
|
|
||||||
"minimist": "1.2.8",
|
"minimist": "1.2.8",
|
||||||
"mkdirp": "1.0.4",
|
"mkdirp": "1.0.4",
|
||||||
"monaco-editor": "0.38.0",
|
"monaco-editor": "0.38.0",
|
||||||
@@ -193,7 +192,7 @@
|
|||||||
"get-port": "5.1.1",
|
"get-port": "5.1.1",
|
||||||
"mini-css-extract-plugin": "1.6.2",
|
"mini-css-extract-plugin": "1.6.2",
|
||||||
"node-fetch": "2.6.12",
|
"node-fetch": "2.6.12",
|
||||||
"nodemon": "3.0.1",
|
"nodemon": "3.0.3",
|
||||||
"object.assign": "4.1.4",
|
"object.assign": "4.1.4",
|
||||||
"object.entries": "1.1.6",
|
"object.entries": "1.1.6",
|
||||||
"passport-strategy": "1.0.0",
|
"passport-strategy": "1.0.0",
|
||||||
|
|||||||
@@ -24,11 +24,16 @@ export const Collapsible: React.FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [collapsedLocal, setCollapsedLocal] = useState(Boolean(initCollapsed))
|
const [collapsedLocal, setCollapsedLocal] = useState(Boolean(initCollapsed))
|
||||||
const [hoveringToggle, setHoveringToggle] = useState(false)
|
const [hoveringToggle, setHoveringToggle] = useState(false)
|
||||||
const isNested = useCollapsible()
|
const { withinCollapsible } = useCollapsible()
|
||||||
const { t } = useTranslation('fields')
|
const { t } = useTranslation('fields')
|
||||||
|
|
||||||
const collapsed = typeof collapsedFromProps === 'boolean' ? collapsedFromProps : collapsedLocal
|
const collapsed = typeof collapsedFromProps === 'boolean' ? collapsedFromProps : collapsedLocal
|
||||||
|
|
||||||
|
const toggleCollapsible = React.useCallback(() => {
|
||||||
|
if (typeof onToggle === 'function') onToggle(!collapsed)
|
||||||
|
setCollapsedLocal(!collapsed)
|
||||||
|
}, [onToggle, collapsed])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={[
|
className={[
|
||||||
@@ -36,14 +41,14 @@ export const Collapsible: React.FC<Props> = ({
|
|||||||
className,
|
className,
|
||||||
dragHandleProps && `${baseClass}--has-drag-handle`,
|
dragHandleProps && `${baseClass}--has-drag-handle`,
|
||||||
collapsed && `${baseClass}--collapsed`,
|
collapsed && `${baseClass}--collapsed`,
|
||||||
isNested && `${baseClass}--nested`,
|
withinCollapsible && `${baseClass}--nested`,
|
||||||
hoveringToggle && `${baseClass}--hovered`,
|
hoveringToggle && `${baseClass}--hovered`,
|
||||||
`${baseClass}--style-${collapsibleStyle}`,
|
`${baseClass}--style-${collapsibleStyle}`,
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' ')}
|
.join(' ')}
|
||||||
>
|
>
|
||||||
<CollapsibleProvider>
|
<CollapsibleProvider collapsed={collapsed} toggle={toggleCollapsible}>
|
||||||
<div
|
<div
|
||||||
className={`${baseClass}__toggle-wrap`}
|
className={`${baseClass}__toggle-wrap`}
|
||||||
onMouseEnter={() => setHoveringToggle(true)}
|
onMouseEnter={() => setHoveringToggle(true)}
|
||||||
@@ -65,10 +70,7 @@ export const Collapsible: React.FC<Props> = ({
|
|||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' ')}
|
.join(' ')}
|
||||||
onClick={() => {
|
onClick={toggleCollapsible}
|
||||||
if (typeof onToggle === 'function') onToggle(!collapsed)
|
|
||||||
setCollapsedLocal(!collapsed)
|
|
||||||
}}
|
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<span>{t('toggleBlock')}</span>
|
<span>{t('toggleBlock')}</span>
|
||||||
|
|||||||
@@ -1,14 +1,35 @@
|
|||||||
import React, { createContext, useContext } from 'react'
|
import React, { createContext, useContext } from 'react'
|
||||||
|
|
||||||
const Context = createContext(false)
|
type ContextType = {
|
||||||
|
collapsed: boolean
|
||||||
|
isVisible: boolean
|
||||||
|
toggle: () => void
|
||||||
|
withinCollapsible: boolean
|
||||||
|
}
|
||||||
|
const Context = createContext({
|
||||||
|
collapsed: false,
|
||||||
|
isVisible: true,
|
||||||
|
toggle: () => {},
|
||||||
|
withinCollapsible: true,
|
||||||
|
})
|
||||||
|
|
||||||
export const CollapsibleProvider: React.FC<{
|
export const CollapsibleProvider: React.FC<{
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
|
collapsed?: boolean
|
||||||
|
toggle: () => void
|
||||||
withinCollapsible?: boolean
|
withinCollapsible?: boolean
|
||||||
}> = ({ children, withinCollapsible = true }) => {
|
}> = ({ children, collapsed, toggle, withinCollapsible = true }) => {
|
||||||
return <Context.Provider value={withinCollapsible}>{children}</Context.Provider>
|
const { collapsed: parentIsCollapsed, isVisible } = useCollapsible()
|
||||||
|
|
||||||
|
const contextValue = React.useMemo((): ContextType => {
|
||||||
|
return {
|
||||||
|
collapsed: Boolean(collapsed),
|
||||||
|
isVisible: isVisible && !parentIsCollapsed,
|
||||||
|
toggle,
|
||||||
|
withinCollapsible,
|
||||||
|
}
|
||||||
|
}, [collapsed, withinCollapsible, toggle, parentIsCollapsed, isVisible])
|
||||||
|
return <Context.Provider value={contextValue}>{children}</Context.Provider>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useCollapsible = (): boolean => useContext(Context)
|
export const useCollapsible = (): ContextType => useContext(Context)
|
||||||
|
|
||||||
export default Context
|
|
||||||
|
|||||||
@@ -52,21 +52,9 @@ const Content: React.FC<DocumentDrawerProps> = ({
|
|||||||
|
|
||||||
const { id, docPermissions, getDocPreferences } = useDocumentInfo()
|
const { id, docPermissions, getDocPreferences } = useDocumentInfo()
|
||||||
|
|
||||||
// The component definition could come from multiple places in the config
|
// If they are replacing the entire edit view, use that.
|
||||||
// we need to cascade into the proper component from the top-down
|
// Else let the DefaultEdit determine what to render.
|
||||||
// 1. "components.Edit"
|
const CustomEditView = typeof Edit === 'function' ? Edit : undefined
|
||||||
// 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
|
|
||||||
|
|
||||||
const [fields, setFields] = useState(() => formatFields(collectionConfig, true))
|
const [fields, setFields] = useState(() => formatFields(collectionConfig, true))
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { fieldTypes } from '../../forms/field-types'
|
|||||||
import X from '../../icons/X'
|
import X from '../../icons/X'
|
||||||
import { useAuth } from '../../utilities/Auth'
|
import { useAuth } from '../../utilities/Auth'
|
||||||
import { useConfig } from '../../utilities/Config'
|
import { useConfig } from '../../utilities/Config'
|
||||||
|
import { DocumentInfoProvider } from '../../utilities/DocumentInfo'
|
||||||
import { OperationContext } from '../../utilities/OperationProvider'
|
import { OperationContext } from '../../utilities/OperationProvider'
|
||||||
import { SelectAllStatus, useSelection } from '../../views/collections/List/SelectionProvider'
|
import { SelectAllStatus, useSelection } from '../../views/collections/List/SelectionProvider'
|
||||||
import { Drawer, DrawerToggler } from '../Drawer'
|
import { Drawer, DrawerToggler } from '../Drawer'
|
||||||
@@ -120,6 +121,7 @@ const EditMany: React.FC<Props> = (props) => {
|
|||||||
{t('edit')}
|
{t('edit')}
|
||||||
</DrawerToggler>
|
</DrawerToggler>
|
||||||
<Drawer header={null} slug={drawerSlug}>
|
<Drawer header={null} slug={drawerSlug}>
|
||||||
|
<DocumentInfoProvider collection={collection}>
|
||||||
<OperationContext.Provider value="update">
|
<OperationContext.Provider value="update">
|
||||||
<Form className={`${baseClass}__form`} onSuccess={onSuccess}>
|
<Form className={`${baseClass}__form`} onSuccess={onSuccess}>
|
||||||
<div className={`${baseClass}__main`}>
|
<div className={`${baseClass}__main`}>
|
||||||
@@ -167,6 +169,7 @@ const EditMany: React.FC<Props> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</OperationContext.Provider>
|
</OperationContext.Provider>
|
||||||
|
</DocumentInfoProvider>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const Group: React.FC<Props> = (props) => {
|
|||||||
permissions,
|
permissions,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const isWithinCollapsible = useCollapsible()
|
const { withinCollapsible } = useCollapsible()
|
||||||
const isWithinGroup = useGroup()
|
const isWithinGroup = useGroup()
|
||||||
const isWithinRow = useRow()
|
const isWithinRow = useRow()
|
||||||
const isWithinTab = useTabs()
|
const isWithinTab = useTabs()
|
||||||
@@ -43,7 +43,7 @@ const Group: React.FC<Props> = (props) => {
|
|||||||
const groupHasErrors = submitted && errorCount > 0
|
const groupHasErrors = submitted && errorCount > 0
|
||||||
|
|
||||||
const path = pathFromProps || name
|
const path = pathFromProps || name
|
||||||
const isTopLevel = !(isWithinCollapsible || isWithinGroup || isWithinRow)
|
const isTopLevel = !(withinCollapsible || isWithinGroup || isWithinRow)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -51,7 +51,7 @@ const Group: React.FC<Props> = (props) => {
|
|||||||
fieldBaseClass,
|
fieldBaseClass,
|
||||||
baseClass,
|
baseClass,
|
||||||
isTopLevel && `${baseClass}--top-level`,
|
isTopLevel && `${baseClass}--top-level`,
|
||||||
isWithinCollapsible && `${baseClass}--within-collapsible`,
|
withinCollapsible && `${baseClass}--within-collapsible`,
|
||||||
isWithinGroup && `${baseClass}--within-group`,
|
isWithinGroup && `${baseClass}--within-group`,
|
||||||
isWithinRow && `${baseClass}--within-row`,
|
isWithinRow && `${baseClass}--within-row`,
|
||||||
isWithinTab && `${baseClass}--within-tab`,
|
isWithinTab && `${baseClass}--within-tab`,
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ const TabsField: React.FC<Props> = (props) => {
|
|||||||
const { preferencesKey } = useDocumentInfo()
|
const { preferencesKey } = useDocumentInfo()
|
||||||
const { i18n } = useTranslation()
|
const { i18n } = useTranslation()
|
||||||
|
|
||||||
const isWithinCollapsible = useCollapsible()
|
const { withinCollapsible } = useCollapsible()
|
||||||
const [activeTabIndex, setActiveTabIndex] = useState<number>(0)
|
const [activeTabIndex, setActiveTabIndex] = useState<number>(0)
|
||||||
const tabsPrefKey = `tabs-${indexPath}`
|
const tabsPrefKey = `tabs-${indexPath}`
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ const TabsField: React.FC<Props> = (props) => {
|
|||||||
fieldBaseClass,
|
fieldBaseClass,
|
||||||
className,
|
className,
|
||||||
baseClass,
|
baseClass,
|
||||||
isWithinCollapsible && `${baseClass}--within-collapsible`,
|
withinCollapsible && `${baseClass}--within-collapsible`,
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' ')}
|
.join(' ')}
|
||||||
|
|||||||
@@ -7,13 +7,14 @@ import { extractTranslations } from '../../translations/extractTranslations'
|
|||||||
const labels = extractTranslations(['authentication:enableAPIKey', 'authentication:apiKey'])
|
const labels = extractTranslations(['authentication:enableAPIKey', 'authentication:apiKey'])
|
||||||
|
|
||||||
const encryptKey: FieldHook = ({ req, value }) =>
|
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 }) =>
|
const decryptKey: FieldHook = ({ req, value }) =>
|
||||||
value ? req.payload.decrypt(value as string) : undefined
|
value ? req.payload.decrypt(value as string) : undefined
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
name: 'enableAPIKey',
|
name: 'enableAPIKey',
|
||||||
|
type: 'checkbox',
|
||||||
admin: {
|
admin: {
|
||||||
components: {
|
components: {
|
||||||
Field: () => null,
|
Field: () => null,
|
||||||
@@ -21,10 +22,10 @@ export default [
|
|||||||
},
|
},
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
label: labels['authentication:enableAPIKey'],
|
label: labels['authentication:enableAPIKey'],
|
||||||
type: 'checkbox',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'apiKey',
|
name: 'apiKey',
|
||||||
|
type: 'text',
|
||||||
admin: {
|
admin: {
|
||||||
components: {
|
components: {
|
||||||
Field: () => null,
|
Field: () => null,
|
||||||
@@ -35,10 +36,10 @@ export default [
|
|||||||
beforeChange: [encryptKey],
|
beforeChange: [encryptKey],
|
||||||
},
|
},
|
||||||
label: labels['authentication:apiKey'],
|
label: labels['authentication:apiKey'],
|
||||||
type: 'text',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'apiKeyIndex',
|
name: 'apiKeyIndex',
|
||||||
|
type: 'text',
|
||||||
admin: {
|
admin: {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
@@ -59,6 +60,5 @@ export default [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
type: 'text',
|
|
||||||
},
|
},
|
||||||
] as Field[]
|
] as Field[]
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
req: {
|
req: {
|
||||||
|
fallbackLocale,
|
||||||
|
locale,
|
||||||
payload,
|
payload,
|
||||||
payload: { config, secret },
|
payload: { config, secret },
|
||||||
},
|
},
|
||||||
@@ -196,7 +198,9 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: user,
|
doc: user,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const args = minimist(process.argv.slice(2))
|
|||||||
const scriptIndex = args._.findIndex((x) => x === 'build')
|
const scriptIndex = args._.findIndex((x) => x === 'build')
|
||||||
|
|
||||||
const script = scriptIndex === -1 ? args._[0] : args._[scriptIndex]
|
const script = scriptIndex === -1 ? args._[0] : args._[scriptIndex]
|
||||||
|
if (script) {
|
||||||
if (script.startsWith('migrate')) {
|
if (script.startsWith('migrate')) {
|
||||||
migrate(args).then(() => process.exit(0))
|
migrate(args).then(() => process.exit(0))
|
||||||
} else {
|
} else {
|
||||||
@@ -81,6 +81,9 @@ if (script.startsWith('migrate')) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.error('No payload script specified. Did you mean to run `payload migrate`?')
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to find user's .env and load it
|
* Try to find user's .env and load it
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import type {
|
|||||||
import executeAccess from '../../auth/executeAccess'
|
import executeAccess from '../../auth/executeAccess'
|
||||||
import sendVerificationEmail from '../../auth/sendVerificationEmail'
|
import sendVerificationEmail from '../../auth/sendVerificationEmail'
|
||||||
import { registerLocalStrategy } from '../../auth/strategies/local/register'
|
import { registerLocalStrategy } from '../../auth/strategies/local/register'
|
||||||
import { fieldAffectsData } from '../../fields/config/types'
|
|
||||||
import { afterChange } from '../../fields/hooks/afterChange'
|
import { afterChange } from '../../fields/hooks/afterChange'
|
||||||
import { afterRead } from '../../fields/hooks/afterRead'
|
import { afterRead } from '../../fields/hooks/afterRead'
|
||||||
import { beforeChange } from '../../fields/hooks/beforeChange'
|
import { beforeChange } from '../../fields/hooks/beforeChange'
|
||||||
@@ -26,12 +25,12 @@ import { generateFileData } from '../../uploads/generateFileData'
|
|||||||
import { unlinkTempFiles } from '../../uploads/unlinkTempFiles'
|
import { unlinkTempFiles } from '../../uploads/unlinkTempFiles'
|
||||||
import { uploadFiles } from '../../uploads/uploadFiles'
|
import { uploadFiles } from '../../uploads/uploadFiles'
|
||||||
import { commitTransaction } from '../../utilities/commitTransaction'
|
import { commitTransaction } from '../../utilities/commitTransaction'
|
||||||
|
import flattenFields from '../../utilities/flattenTopLevelFields'
|
||||||
import { initTransaction } from '../../utilities/initTransaction'
|
import { initTransaction } from '../../utilities/initTransaction'
|
||||||
import { killTransaction } from '../../utilities/killTransaction'
|
import { killTransaction } from '../../utilities/killTransaction'
|
||||||
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields'
|
import sanitizeInternalFields from '../../utilities/sanitizeInternalFields'
|
||||||
import { saveVersion } from '../../versions/saveVersion'
|
import { saveVersion } from '../../versions/saveVersion'
|
||||||
import { buildAfterOperation } from './utils'
|
import { buildAfterOperation } from './utils'
|
||||||
import flattenFields from '../../utilities/flattenTopLevelFields'
|
|
||||||
|
|
||||||
const unlinkFile = promisify(fs.unlink)
|
const unlinkFile = promisify(fs.unlink)
|
||||||
|
|
||||||
@@ -88,6 +87,8 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
overwriteExistingFiles = false,
|
overwriteExistingFiles = false,
|
||||||
req: {
|
req: {
|
||||||
|
fallbackLocale,
|
||||||
|
locale,
|
||||||
payload,
|
payload,
|
||||||
payload: { config, emailOptions },
|
payload: { config, emailOptions },
|
||||||
},
|
},
|
||||||
@@ -289,7 +290,9 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
|||||||
depth,
|
depth,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req: {
|
req: {
|
||||||
|
fallbackLocale,
|
||||||
locale,
|
locale,
|
||||||
payload: { config },
|
payload: { config },
|
||||||
payload,
|
payload,
|
||||||
@@ -149,9 +150,9 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
|||||||
if (collectionConfig.versions) {
|
if (collectionConfig.versions) {
|
||||||
await deleteCollectionVersions({
|
await deleteCollectionVersions({
|
||||||
id,
|
id,
|
||||||
|
slug: collectionConfig.slug,
|
||||||
payload,
|
payload,
|
||||||
req,
|
req,
|
||||||
slug: collectionConfig.slug,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +179,9 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: result || doc,
|
doc: result || doc,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
depth,
|
depth,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req: {
|
req: {
|
||||||
|
fallbackLocale,
|
||||||
|
locale,
|
||||||
payload: { config },
|
payload: { config },
|
||||||
payload,
|
payload,
|
||||||
t,
|
t,
|
||||||
@@ -120,9 +122,9 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
if (collectionConfig.versions) {
|
if (collectionConfig.versions) {
|
||||||
await deleteCollectionVersions({
|
await deleteCollectionVersions({
|
||||||
id,
|
id,
|
||||||
|
slug: collectionConfig.slug,
|
||||||
payload,
|
payload,
|
||||||
req,
|
req,
|
||||||
slug: collectionConfig.slug,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +158,9 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
page,
|
page,
|
||||||
pagination = true,
|
pagination = true,
|
||||||
req: { locale, payload },
|
req: { fallbackLocale, locale, payload },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
sort,
|
sort,
|
||||||
@@ -196,8 +196,10 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
findMany: true,
|
findMany: true,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
/* eslint-disable no-underscore-dangle */
|
/* eslint-disable no-underscore-dangle */
|
||||||
import memoize from 'micro-memoize'
|
|
||||||
|
|
||||||
import type { FindOneArgs } from '../../database/types'
|
import type { FindOneArgs } from '../../database/types'
|
||||||
import type { PayloadRequest } from '../../express/types'
|
import type { PayloadRequest } from '../../express/types'
|
||||||
import type { Collection, TypeWithID } from '../config/types'
|
import type { Collection, TypeWithID } from '../config/types'
|
||||||
@@ -32,7 +30,6 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const shouldCommit = await initTransaction(args.req)
|
const shouldCommit = await initTransaction(args.req)
|
||||||
const { transactionID } = args.req
|
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
// beforeOperation - Collection
|
// beforeOperation - Collection
|
||||||
@@ -59,7 +56,7 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
|||||||
disableErrors,
|
disableErrors,
|
||||||
draft: draftEnabled = false,
|
draft: draftEnabled = false,
|
||||||
overrideAccess = false,
|
overrideAccess = false,
|
||||||
req: { locale, t },
|
req: { fallbackLocale, locale, t },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
} = args
|
} = args
|
||||||
@@ -90,25 +87,7 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
|||||||
|
|
||||||
if (!findOneArgs.where.and[0].id) throw new NotFound(t)
|
if (!findOneArgs.where.and[0].id) throw new NotFound(t)
|
||||||
|
|
||||||
if (!req.findByID) {
|
let result: T = await req.payload.db.findOne(findOneArgs)
|
||||||
req.findByID = { [transactionID]: {} }
|
|
||||||
} else if (!req.findByID[transactionID]) {
|
|
||||||
req.findByID[transactionID] = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req.findByID[transactionID][collectionConfig.slug]) {
|
|
||||||
const nonMemoizedFindByID = async (query: FindOneArgs) => req.payload.db.findOne(query)
|
|
||||||
|
|
||||||
req.findByID[transactionID][collectionConfig.slug] = memoize(nonMemoizedFindByID, {
|
|
||||||
isPromise: true,
|
|
||||||
maxSize: 100,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore This is straight from their docs, bad typings
|
|
||||||
transformKey: JSON.stringify,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = (await req.findByID[transactionID][collectionConfig.slug](findOneArgs)) as T
|
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
if (!disableErrors) {
|
if (!disableErrors) {
|
||||||
@@ -118,9 +97,6 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone the result - it may have come back memoized
|
|
||||||
result = JSON.parse(JSON.stringify(result))
|
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
// Replace document with draft if available
|
// Replace document with draft if available
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -163,7 +139,9 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ async function findVersionByID<T extends TypeWithID = any>(
|
|||||||
depth,
|
depth,
|
||||||
disableErrors,
|
disableErrors,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req: { locale, payload, t },
|
req: { fallbackLocale, locale, payload, t },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
} = args
|
} = args
|
||||||
@@ -112,7 +112,9 @@ async function findVersionByID<T extends TypeWithID = any>(
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc: result.version,
|
doc: result.version,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
page,
|
page,
|
||||||
pagination = true,
|
pagination = true,
|
||||||
req: { locale, payload },
|
req: { fallbackLocale, locale, payload },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
sort,
|
sort,
|
||||||
@@ -125,8 +125,10 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: data.version,
|
doc: data.version,
|
||||||
|
fallbackLocale,
|
||||||
findMany: true,
|
findMany: true,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
|||||||
depth,
|
depth,
|
||||||
overrideAccess = false,
|
overrideAccess = false,
|
||||||
req,
|
req,
|
||||||
req: { locale, payload, t },
|
req: { fallbackLocale, locale, payload, t },
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
} = args
|
} = args
|
||||||
|
|
||||||
@@ -140,7 +140,9 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
overwriteExistingFiles = false,
|
overwriteExistingFiles = false,
|
||||||
req: {
|
req: {
|
||||||
|
fallbackLocale,
|
||||||
locale,
|
locale,
|
||||||
payload: { config },
|
payload: { config },
|
||||||
payload,
|
payload,
|
||||||
@@ -176,7 +177,9 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
req,
|
req,
|
||||||
showHiddenFields: true,
|
showHiddenFields: true,
|
||||||
@@ -309,7 +312,9 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
fallbackLocale: null,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
overrideAccess,
|
overrideAccess,
|
||||||
overwriteExistingFiles = false,
|
overwriteExistingFiles = false,
|
||||||
req: {
|
req: {
|
||||||
|
fallbackLocale,
|
||||||
locale,
|
locale,
|
||||||
payload: { config },
|
payload: { config },
|
||||||
payload,
|
payload,
|
||||||
@@ -130,7 +131,9 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
doc: docWithLocales,
|
doc: docWithLocales,
|
||||||
|
fallbackLocale: null,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
req,
|
req,
|
||||||
showHiddenFields: true,
|
showHiddenFields: true,
|
||||||
@@ -297,7 +300,9 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
fallbackLocale,
|
||||||
global: null,
|
global: null,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export { useCollapsible } from '../../admin/components/elements/Collapsible/provider'
|
||||||
export { default as buildStateFromSchema } from '../../admin/components/forms/Form/buildStateFromSchema'
|
export { default as buildStateFromSchema } from '../../admin/components/forms/Form/buildStateFromSchema'
|
||||||
export { useAuth } from '../../admin/components/utilities/Auth'
|
export { useAuth } from '../../admin/components/utilities/Auth'
|
||||||
export { useConfig } from '../../admin/components/utilities/Config'
|
export { useConfig } from '../../admin/components/utilities/Config'
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const errorHandler =
|
|||||||
err,
|
err,
|
||||||
response,
|
response,
|
||||||
req.context,
|
req.context,
|
||||||
req.collection.config,
|
null,
|
||||||
)) || {
|
)) || {
|
||||||
response,
|
response,
|
||||||
status,
|
status,
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ type Args = {
|
|||||||
currentDepth?: number
|
currentDepth?: number
|
||||||
depth: number
|
depth: number
|
||||||
doc: Record<string, unknown>
|
doc: Record<string, unknown>
|
||||||
|
fallbackLocale: null | string
|
||||||
findMany?: boolean
|
findMany?: boolean
|
||||||
flattenLocales?: boolean
|
flattenLocales?: boolean
|
||||||
global: SanitizedGlobalConfig | null
|
global: SanitizedGlobalConfig | null
|
||||||
|
locale: string
|
||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
showHiddenFields: boolean
|
showHiddenFields: boolean
|
||||||
@@ -26,9 +28,11 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
|
|||||||
currentDepth: incomingCurrentDepth,
|
currentDepth: incomingCurrentDepth,
|
||||||
depth: incomingDepth,
|
depth: incomingDepth,
|
||||||
doc: incomingDoc,
|
doc: incomingDoc,
|
||||||
|
fallbackLocale,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales = true,
|
flattenLocales = true,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
@@ -52,11 +56,13 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: collection?.fields || global?.fields,
|
fields: collection?.fields || global?.fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
|
|||||||
@@ -16,11 +16,13 @@ type Args = {
|
|||||||
currentDepth: number
|
currentDepth: number
|
||||||
depth: number
|
depth: number
|
||||||
doc: Record<string, unknown>
|
doc: Record<string, unknown>
|
||||||
|
fallbackLocale: null | string
|
||||||
field: Field | TabAsField
|
field: Field | TabAsField
|
||||||
fieldPromises: Promise<void>[]
|
fieldPromises: Promise<void>[]
|
||||||
findMany: boolean
|
findMany: boolean
|
||||||
flattenLocales: boolean
|
flattenLocales: boolean
|
||||||
global: SanitizedGlobalConfig | null
|
global: SanitizedGlobalConfig | null
|
||||||
|
locale: null | string
|
||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
populationPromises: Promise<void>[]
|
populationPromises: Promise<void>[]
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
@@ -44,11 +46,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -72,18 +76,13 @@ export const promise = async ({
|
|||||||
typeof siblingDoc[field.name] === 'object' &&
|
typeof siblingDoc[field.name] === 'object' &&
|
||||||
siblingDoc[field.name] !== null &&
|
siblingDoc[field.name] !== null &&
|
||||||
field.localized &&
|
field.localized &&
|
||||||
req.locale !== 'all' &&
|
locale !== 'all' &&
|
||||||
req.payload.config.localization
|
req.payload.config.localization
|
||||||
|
|
||||||
if (shouldHoistLocalizedValue) {
|
if (shouldHoistLocalizedValue) {
|
||||||
// replace actual value with localized value before sanitizing
|
// replace actual value with localized value before sanitizing
|
||||||
// { [locale]: fields } -> fields
|
// { [locale]: fields } -> fields
|
||||||
const { locale } = req
|
|
||||||
const value = siblingDoc[field.name][locale]
|
const value = siblingDoc[field.name][locale]
|
||||||
const fallbackLocale =
|
|
||||||
req.payload.config.localization &&
|
|
||||||
req.payload.config.localization?.fallback &&
|
|
||||||
req.fallbackLocale
|
|
||||||
|
|
||||||
let hoistedValue = value
|
let hoistedValue = value
|
||||||
|
|
||||||
@@ -201,7 +200,7 @@ export const promise = async ({
|
|||||||
|
|
||||||
const shouldRunHookOnAllLocales =
|
const shouldRunHookOnAllLocales =
|
||||||
field.localized &&
|
field.localized &&
|
||||||
(req.locale === 'all' || !flattenLocales) &&
|
(locale === 'all' || !flattenLocales) &&
|
||||||
typeof siblingDoc[field.name] === 'object'
|
typeof siblingDoc[field.name] === 'object'
|
||||||
|
|
||||||
if (shouldRunHookOnAllLocales) {
|
if (shouldRunHookOnAllLocales) {
|
||||||
@@ -277,7 +276,7 @@ export const promise = async ({
|
|||||||
) {
|
) {
|
||||||
siblingDoc[field.name] = await getValueWithDefault({
|
siblingDoc[field.name] = await getValueWithDefault({
|
||||||
defaultValue: field.defaultValue,
|
defaultValue: field.defaultValue,
|
||||||
locale: req.locale,
|
locale,
|
||||||
user: req.user,
|
user: req.user,
|
||||||
value: siblingDoc[field.name],
|
value: siblingDoc[field.name],
|
||||||
})
|
})
|
||||||
@@ -288,7 +287,9 @@ export const promise = async ({
|
|||||||
relationshipPopulationPromise({
|
relationshipPopulationPromise({
|
||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
@@ -309,11 +310,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -337,11 +340,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -361,11 +366,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -397,11 +404,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: block.fields,
|
fields: block.fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -425,11 +434,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: block.fields,
|
fields: block.fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -457,11 +468,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -487,11 +500,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: field.fields,
|
fields: field.fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -511,11 +526,13 @@ export const promise = async ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ type PopulateArgs = {
|
|||||||
data: Record<string, unknown>
|
data: Record<string, unknown>
|
||||||
dataReference: Record<string, any>
|
dataReference: Record<string, any>
|
||||||
depth: number
|
depth: number
|
||||||
|
fallbackLocale: null | string
|
||||||
field: RelationshipField | UploadField
|
field: RelationshipField | UploadField
|
||||||
index?: number
|
index?: number
|
||||||
key?: string
|
key?: string
|
||||||
|
locale: null | string
|
||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
showHiddenFields: boolean
|
showHiddenFields: boolean
|
||||||
@@ -21,9 +23,11 @@ const populate = async ({
|
|||||||
data,
|
data,
|
||||||
dataReference,
|
dataReference,
|
||||||
depth,
|
depth,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
index,
|
index,
|
||||||
key,
|
key,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
@@ -54,8 +58,8 @@ const populate = async ({
|
|||||||
id,
|
id,
|
||||||
depth,
|
depth,
|
||||||
currentDepth + 1,
|
currentDepth + 1,
|
||||||
req.locale,
|
locale,
|
||||||
req.fallbackLocale,
|
fallbackLocale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
]),
|
]),
|
||||||
@@ -90,7 +94,9 @@ const populate = async ({
|
|||||||
type PromiseArgs = {
|
type PromiseArgs = {
|
||||||
currentDepth: number
|
currentDepth: number
|
||||||
depth: number
|
depth: number
|
||||||
|
fallbackLocale: null | string
|
||||||
field: RelationshipField | UploadField
|
field: RelationshipField | UploadField
|
||||||
|
locale: null | string
|
||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
showHiddenFields: boolean
|
showHiddenFields: boolean
|
||||||
@@ -100,7 +106,9 @@ type PromiseArgs = {
|
|||||||
const relationshipPopulationPromise = async ({
|
const relationshipPopulationPromise = async ({
|
||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
@@ -112,7 +120,7 @@ const relationshipPopulationPromise = async ({
|
|||||||
|
|
||||||
if (fieldSupportsMany(field) && field.hasMany) {
|
if (fieldSupportsMany(field) && field.hasMany) {
|
||||||
if (
|
if (
|
||||||
req.locale === 'all' &&
|
locale === 'all' &&
|
||||||
typeof siblingDoc[field.name] === 'object' &&
|
typeof siblingDoc[field.name] === 'object' &&
|
||||||
siblingDoc[field.name] !== null
|
siblingDoc[field.name] !== null
|
||||||
) {
|
) {
|
||||||
@@ -125,9 +133,11 @@ const relationshipPopulationPromise = async ({
|
|||||||
data: siblingDoc[field.name][key][index],
|
data: siblingDoc[field.name][key][index],
|
||||||
dataReference: resultingDoc,
|
dataReference: resultingDoc,
|
||||||
depth: populateDepth,
|
depth: populateDepth,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
index,
|
index,
|
||||||
key,
|
key,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
@@ -146,8 +156,10 @@ const relationshipPopulationPromise = async ({
|
|||||||
data: relatedDoc,
|
data: relatedDoc,
|
||||||
dataReference: resultingDoc,
|
dataReference: resultingDoc,
|
||||||
depth: populateDepth,
|
depth: populateDepth,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
index,
|
index,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
@@ -161,7 +173,7 @@ const relationshipPopulationPromise = async ({
|
|||||||
} else if (
|
} else if (
|
||||||
typeof siblingDoc[field.name] === 'object' &&
|
typeof siblingDoc[field.name] === 'object' &&
|
||||||
siblingDoc[field.name] !== null &&
|
siblingDoc[field.name] !== null &&
|
||||||
req.locale === 'all'
|
locale === 'all'
|
||||||
) {
|
) {
|
||||||
Object.keys(siblingDoc[field.name]).forEach((key) => {
|
Object.keys(siblingDoc[field.name]).forEach((key) => {
|
||||||
const rowPromise = async () => {
|
const rowPromise = async () => {
|
||||||
@@ -170,8 +182,10 @@ const relationshipPopulationPromise = async ({
|
|||||||
data: siblingDoc[field.name][key],
|
data: siblingDoc[field.name][key],
|
||||||
dataReference: resultingDoc,
|
dataReference: resultingDoc,
|
||||||
depth: populateDepth,
|
depth: populateDepth,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
key,
|
key,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
@@ -187,7 +201,9 @@ const relationshipPopulationPromise = async ({
|
|||||||
data: siblingDoc[field.name],
|
data: siblingDoc[field.name],
|
||||||
dataReference: resultingDoc,
|
dataReference: resultingDoc,
|
||||||
depth: populateDepth,
|
depth: populateDepth,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ type Args = {
|
|||||||
currentDepth: number
|
currentDepth: number
|
||||||
depth: number
|
depth: number
|
||||||
doc: Record<string, unknown>
|
doc: Record<string, unknown>
|
||||||
|
fallbackLocale: null | string
|
||||||
fieldPromises: Promise<void>[]
|
fieldPromises: Promise<void>[]
|
||||||
fields: (Field | TabAsField)[]
|
fields: (Field | TabAsField)[]
|
||||||
findMany: boolean
|
findMany: boolean
|
||||||
flattenLocales: boolean
|
flattenLocales: boolean
|
||||||
global: SanitizedGlobalConfig | null
|
global: SanitizedGlobalConfig | null
|
||||||
|
locale: null | string
|
||||||
overrideAccess: boolean
|
overrideAccess: boolean
|
||||||
populationPromises: Promise<void>[]
|
populationPromises: Promise<void>[]
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
@@ -31,11 +33,13 @@ export const traverseFields = ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
fields,
|
fields,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
@@ -52,11 +56,13 @@ export const traverseFields = ({
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
field,
|
field,
|
||||||
fieldPromises,
|
fieldPromises,
|
||||||
findMany,
|
findMany,
|
||||||
flattenLocales,
|
flattenLocales,
|
||||||
global,
|
global,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
populationPromises,
|
populationPromises,
|
||||||
req,
|
req,
|
||||||
|
|||||||
@@ -275,6 +275,7 @@ const validateFilterOptions: Validate = async (
|
|||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
collections.map(async (collection) => {
|
collections.map(async (collection) => {
|
||||||
|
try {
|
||||||
let optionFilter =
|
let optionFilter =
|
||||||
typeof filterOptions === 'function'
|
typeof filterOptions === 'function'
|
||||||
? await filterOptions({
|
? await filterOptions({
|
||||||
@@ -313,12 +314,12 @@ const validateFilterOptions: Validate = async (
|
|||||||
falseCollections.push(optionFilter)
|
falseCollections.push(optionFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `req` omitted to prevent transaction errors from aborting the entire transaction
|
||||||
const result = await payload.find({
|
const result = await payload.find({
|
||||||
collection,
|
collection,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
limit: 0,
|
limit: 0,
|
||||||
pagination: false,
|
pagination: false,
|
||||||
req,
|
|
||||||
where: findWhere,
|
where: findWhere,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -326,6 +327,13 @@ const validateFilterOptions: Validate = async (
|
|||||||
} else {
|
} else {
|
||||||
options[collection] = []
|
options[collection] = []
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
req.payload.logger.error({
|
||||||
|
err,
|
||||||
|
msg: `Error validating filter options for collection ${collection}`,
|
||||||
|
})
|
||||||
|
options[collection] = []
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ type Args = {
|
|||||||
|
|
||||||
async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T> {
|
async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T> {
|
||||||
const {
|
const {
|
||||||
|
slug,
|
||||||
depth,
|
depth,
|
||||||
draft: draftEnabled = false,
|
draft: draftEnabled = false,
|
||||||
globalConfig,
|
globalConfig,
|
||||||
overrideAccess = false,
|
overrideAccess = false,
|
||||||
req: { locale, payload },
|
req: { fallbackLocale, locale, payload },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
slug,
|
|
||||||
} = args
|
} = args
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -51,9 +51,9 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
|
|||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
let doc = await req.payload.db.findGlobal({
|
let doc = await req.payload.db.findGlobal({
|
||||||
|
slug,
|
||||||
locale,
|
locale,
|
||||||
req,
|
req,
|
||||||
slug,
|
|
||||||
where: overrideAccess ? undefined : (accessResult as Where),
|
where: overrideAccess ? undefined : (accessResult as Where),
|
||||||
})
|
})
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
@@ -100,7 +100,9 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc,
|
doc,
|
||||||
|
fallbackLocale,
|
||||||
global: globalConfig,
|
global: globalConfig,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
|||||||
disableErrors,
|
disableErrors,
|
||||||
globalConfig,
|
globalConfig,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req: { locale, payload, t },
|
req: { fallbackLocale, locale, payload, t },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
} = args
|
} = args
|
||||||
@@ -108,7 +108,9 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
|||||||
currentDepth,
|
currentDepth,
|
||||||
depth,
|
depth,
|
||||||
doc: result.version,
|
doc: result.version,
|
||||||
|
fallbackLocale,
|
||||||
global: globalConfig,
|
global: globalConfig,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
|||||||
limit,
|
limit,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
page,
|
page,
|
||||||
req: { locale, payload },
|
req: { fallbackLocale, locale, payload },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
sort,
|
sort,
|
||||||
@@ -97,8 +97,10 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
|||||||
// Patch globalType onto version doc
|
// Patch globalType onto version doc
|
||||||
globalType: globalConfig.slug,
|
globalType: globalConfig.slug,
|
||||||
},
|
},
|
||||||
|
fallbackLocale,
|
||||||
findMany: true,
|
findMany: true,
|
||||||
global: globalConfig,
|
global: globalConfig,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
|||||||
depth,
|
depth,
|
||||||
globalConfig,
|
globalConfig,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req: { payload, t },
|
req: { fallbackLocale, locale, payload, t },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
} = args
|
} = args
|
||||||
@@ -66,9 +66,9 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
|||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const previousDoc = await payload.findGlobal({
|
const previousDoc = await payload.findGlobal({
|
||||||
|
slug: globalConfig.slug,
|
||||||
depth,
|
depth,
|
||||||
req,
|
req,
|
||||||
slug: globalConfig.slug,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
@@ -76,23 +76,23 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
|||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
|
|
||||||
const global = await payload.db.findGlobal({
|
const global = await payload.db.findGlobal({
|
||||||
req,
|
|
||||||
slug: globalConfig.slug,
|
slug: globalConfig.slug,
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
|
|
||||||
let result = rawVersion.version
|
let result = rawVersion.version
|
||||||
|
|
||||||
if (global) {
|
if (global) {
|
||||||
result = await payload.db.updateGlobal({
|
result = await payload.db.updateGlobal({
|
||||||
|
slug: globalConfig.slug,
|
||||||
data: result,
|
data: result,
|
||||||
req,
|
req,
|
||||||
slug: globalConfig.slug,
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
result = await payload.db.createGlobal({
|
result = await payload.db.createGlobal({
|
||||||
|
slug: globalConfig.slug,
|
||||||
data: result,
|
data: result,
|
||||||
req,
|
req,
|
||||||
slug: globalConfig.slug,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,9 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
fallbackLocale,
|
||||||
global: globalConfig,
|
global: globalConfig,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -32,15 +32,15 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
args: Args<GeneratedTypes['globals'][TSlug]>,
|
args: Args<GeneratedTypes['globals'][TSlug]>,
|
||||||
): Promise<GeneratedTypes['globals'][TSlug]> {
|
): Promise<GeneratedTypes['globals'][TSlug]> {
|
||||||
const {
|
const {
|
||||||
|
slug,
|
||||||
autosave,
|
autosave,
|
||||||
depth,
|
depth,
|
||||||
draft: draftArg,
|
draft: draftArg,
|
||||||
globalConfig,
|
globalConfig,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req: { locale, payload },
|
req: { fallbackLocale, locale, payload },
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
slug,
|
|
||||||
} = args
|
} = args
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -74,11 +74,11 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
// 2. Retrieve document
|
// 2. Retrieve document
|
||||||
// /////////////////////////////////////
|
// /////////////////////////////////////
|
||||||
const { global, globalExists } = await getLatestGlobalVersion({
|
const { global, globalExists } = await getLatestGlobalVersion({
|
||||||
|
slug,
|
||||||
config: globalConfig,
|
config: globalConfig,
|
||||||
locale,
|
locale,
|
||||||
payload,
|
payload,
|
||||||
req,
|
req,
|
||||||
slug,
|
|
||||||
where: query,
|
where: query,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -97,7 +97,9 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
doc: globalJSON,
|
doc: globalJSON,
|
||||||
|
fallbackLocale,
|
||||||
global: globalConfig,
|
global: globalConfig,
|
||||||
|
locale,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
@@ -175,15 +177,15 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
if (!shouldSaveDraft) {
|
if (!shouldSaveDraft) {
|
||||||
if (globalExists) {
|
if (globalExists) {
|
||||||
result = await payload.db.updateGlobal({
|
result = await payload.db.updateGlobal({
|
||||||
|
slug,
|
||||||
data: result,
|
data: result,
|
||||||
req,
|
req,
|
||||||
slug,
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
result = await payload.db.createGlobal({
|
result = await payload.db.createGlobal({
|
||||||
|
slug,
|
||||||
data: result,
|
data: result,
|
||||||
req,
|
req,
|
||||||
slug,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,7 +220,9 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
|||||||
context: req.context,
|
context: req.context,
|
||||||
depth,
|
depth,
|
||||||
doc: result,
|
doc: result,
|
||||||
|
fallbackLocale: null,
|
||||||
global: globalConfig,
|
global: globalConfig,
|
||||||
|
locale,
|
||||||
overrideAccess,
|
overrideAccess,
|
||||||
req,
|
req,
|
||||||
showHiddenFields,
|
showHiddenFields,
|
||||||
|
|||||||
@@ -274,7 +274,7 @@
|
|||||||
"near": "nær"
|
"near": "nær"
|
||||||
},
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"crop": "Avling",
|
"crop": "Beskjær",
|
||||||
"cropToolDescription": "Dra hjørnene av det valgte området, tegn et nytt område eller juster verdiene nedenfor.",
|
"cropToolDescription": "Dra hjørnene av det valgte området, tegn et nytt område eller juster verdiene nedenfor.",
|
||||||
"dragAndDrop": "Dra og slipp en fil",
|
"dragAndDrop": "Dra og slipp en fil",
|
||||||
"dragAndDropHere": "eller dra og slipp en fil her",
|
"dragAndDropHere": "eller dra og slipp en fil her",
|
||||||
|
|||||||
@@ -1,25 +1,31 @@
|
|||||||
|
import type { Request } from 'express'
|
||||||
|
|
||||||
import type { File, FileData } from './types'
|
import type { File, FileData } from './types'
|
||||||
import { Request } from 'express'
|
|
||||||
import { APIError } from '../errors'
|
import { APIError } from '../errors'
|
||||||
|
|
||||||
type Args = {
|
type Args = {
|
||||||
req: Request
|
|
||||||
data: FileData
|
data: FileData
|
||||||
|
req: Request
|
||||||
}
|
}
|
||||||
export const getExternalFile = async ({ req, data }: Args): Promise<File> => {
|
export const getExternalFile = async ({ data, req }: Args): Promise<File> => {
|
||||||
const baseUrl = req.get('origin') || `${req.protocol}://${req.get('host')}`
|
const { filename, url } = data
|
||||||
const { url, filename } = data
|
|
||||||
|
|
||||||
if (typeof url === 'string') {
|
if (typeof url === 'string') {
|
||||||
const fileURL = `${baseUrl}${url}`
|
let fileURL = url
|
||||||
|
if (!url.startsWith('http')) {
|
||||||
|
const baseUrl = req.get('origin') || `${req.protocol}://${req.get('host')}`
|
||||||
|
fileURL = `${baseUrl}${url}`
|
||||||
|
}
|
||||||
|
|
||||||
const { default: fetch } = (await import('node-fetch')) as any
|
const { default: fetch } = (await import('node-fetch')) as any
|
||||||
|
|
||||||
const res = await fetch(fileURL, {
|
const res = await fetch(fileURL, {
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
headers: {
|
||||||
...req.headers,
|
...req.headers,
|
||||||
},
|
},
|
||||||
|
method: 'GET',
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!res.ok) throw new APIError(`Failed to fetch file from ${fileURL}`, res.status)
|
if (!res.ok) throw new APIError(`Failed to fetch file from ${fileURL}`, res.status)
|
||||||
|
|||||||
@@ -57,8 +57,10 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
|
|||||||
if (typeof where === 'object') {
|
if (typeof where === 'object') {
|
||||||
const paginatedRes = await req.payload.find({
|
const paginatedRes = await req.payload.find({
|
||||||
collection: entity.slug,
|
collection: entity.slug,
|
||||||
|
depth: 0,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
|
pagination: false,
|
||||||
req,
|
req,
|
||||||
where: {
|
where: {
|
||||||
...where,
|
...where,
|
||||||
@@ -79,6 +81,7 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
|
|||||||
return req.payload.findByID({
|
return req.payload.findByID({
|
||||||
id,
|
id,
|
||||||
collection: entity.slug,
|
collection: entity.slug,
|
||||||
|
depth: 0,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
req,
|
req,
|
||||||
})
|
})
|
||||||
@@ -98,8 +101,13 @@ export async function getEntityPolicies<T extends Args>(args: T): Promise<Return
|
|||||||
const mutablePolicies = policiesObj
|
const mutablePolicies = policiesObj
|
||||||
|
|
||||||
if (accessLevel === 'field' && docBeingAccessed === undefined) {
|
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
|
const data = req?.body
|
||||||
|
|
||||||
|
|||||||
51
packages/plugin-cloud-storage/docker-compose.yml
Normal file
51
packages/plugin-cloud-storage/docker-compose.yml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
version: '3.2'
|
||||||
|
services:
|
||||||
|
localstack:
|
||||||
|
image: localstack/localstack:latest
|
||||||
|
container_name: localstack_demo
|
||||||
|
ports:
|
||||||
|
- '4563-4599:4563-4599'
|
||||||
|
- '8055:8080'
|
||||||
|
environment:
|
||||||
|
- SERVICES=s3
|
||||||
|
- DEBUG=1
|
||||||
|
- DATA_DIR=/tmp/localstack/data
|
||||||
|
volumes:
|
||||||
|
- './.localstack:/var/lib/localstack'
|
||||||
|
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||||
|
|
||||||
|
azure-storage:
|
||||||
|
image: mcr.microsoft.com/azure-storage/azurite:3.18.0
|
||||||
|
restart: always
|
||||||
|
command: 'azurite --loose --blobHost 0.0.0.0 --tableHost 0.0.0.0 --queueHost 0.0.0.0'
|
||||||
|
ports:
|
||||||
|
- '10000:10000'
|
||||||
|
- '10001:10001'
|
||||||
|
- '10002:10002'
|
||||||
|
volumes:
|
||||||
|
- ./azurestoragedata:/data"
|
||||||
|
|
||||||
|
google-cloud-storage:
|
||||||
|
image: fsouza/fake-gcs-server
|
||||||
|
restart: always
|
||||||
|
command:
|
||||||
|
[
|
||||||
|
'-scheme',
|
||||||
|
'http',
|
||||||
|
'-port',
|
||||||
|
'4443',
|
||||||
|
'-public-host',
|
||||||
|
'http://localhost:4443',
|
||||||
|
'-external-url',
|
||||||
|
'http://localhost:4443',
|
||||||
|
'-backend',
|
||||||
|
'memory',
|
||||||
|
]
|
||||||
|
ports:
|
||||||
|
- '4443:4443'
|
||||||
|
volumes:
|
||||||
|
- ./google-cloud-storage/payload-bucket:/data/payload-bucket
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
google-cloud-storage:
|
||||||
|
azurestoragedata:
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
"@types/find-node-modules": "^2.1.2",
|
"@types/find-node-modules": "^2.1.2",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"nodemon": "^2.0.6",
|
"nodemon": "3.0.3",
|
||||||
"payload": "workspace:*",
|
"payload": "workspace:*",
|
||||||
"rimraf": "^4.1.2",
|
"rimraf": "^4.1.2",
|
||||||
"ts-node": "^9.1.1",
|
"ts-node": "^9.1.1",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-form-builder",
|
"name": "@payloadcms/plugin-form-builder",
|
||||||
"description": "Form builder plugin for Payload CMS",
|
"description": "Form builder plugin for Payload CMS",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"homepage:": "https://payloadcms.com",
|
"homepage:": "https://payloadcms.com",
|
||||||
"repository": "git@github.com:payloadcms/plugin-form-builder.git",
|
"repository": "git@github.com:payloadcms/plugin-form-builder.git",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"@types/react": "18.2.15",
|
"@types/react": "18.2.15",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"nodemon": "^3.0.2",
|
"nodemon": "3.0.3",
|
||||||
"payload": "workspace:*",
|
"payload": "workspace:*",
|
||||||
"react": "^18.0.0",
|
"react": "^18.0.0",
|
||||||
"ts-node": "10.9.1"
|
"ts-node": "10.9.1"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { replaceDoubleCurlys } from '../../../utilities/replaceDoubleCurlys'
|
|||||||
import { serializeSlate } from '../../../utilities/slate/serializeSlate'
|
import { serializeSlate } from '../../../utilities/slate/serializeSlate'
|
||||||
|
|
||||||
const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
|
const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
|
||||||
const { data, operation } = beforeChangeData
|
const { data, operation, req } = beforeChangeData
|
||||||
|
|
||||||
if (operation === 'create') {
|
if (operation === 'create') {
|
||||||
const {
|
const {
|
||||||
@@ -22,6 +22,7 @@ const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promi
|
|||||||
id: formID,
|
id: formID,
|
||||||
collection: formOverrides?.slug || 'forms',
|
collection: formOverrides?.slug || 'forms',
|
||||||
locale,
|
locale,
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { emails } = form
|
const { emails } = form
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
|||||||
|
|
||||||
const newConfig: CollectionConfig = {
|
const newConfig: CollectionConfig = {
|
||||||
...(formConfig?.formSubmissionOverrides || {}),
|
...(formConfig?.formSubmissionOverrides || {}),
|
||||||
|
slug: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',
|
||||||
access: {
|
access: {
|
||||||
create: () => true,
|
create: () => true,
|
||||||
read: ({ req: { user } }) => !!user, // logged-in users,
|
read: ({ req: { user } }) => !!user, // logged-in users,
|
||||||
@@ -24,13 +25,13 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
|||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'form',
|
name: 'form',
|
||||||
|
type: 'relationship',
|
||||||
admin: {
|
admin: {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
},
|
},
|
||||||
relationTo: formSlug,
|
relationTo: formSlug,
|
||||||
required: true,
|
required: true,
|
||||||
type: 'relationship',
|
validate: async (value, { payload, req }) => {
|
||||||
validate: async (value, { payload }) => {
|
|
||||||
/* Don't run in the client side */
|
/* Don't run in the client side */
|
||||||
if (!payload) return true
|
if (!payload) return true
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
|||||||
existingForm = await payload.findByID({
|
existingForm = await payload.findByID({
|
||||||
id: value,
|
id: value,
|
||||||
collection: formSlug,
|
collection: formSlug,
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -52,19 +54,20 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'submissionData',
|
name: 'submissionData',
|
||||||
|
type: 'array',
|
||||||
admin: {
|
admin: {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
required: true,
|
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'value',
|
name: 'value',
|
||||||
required: true,
|
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
required: true,
|
||||||
validate: (value: unknown) => {
|
validate: (value: unknown) => {
|
||||||
// TODO:
|
// TODO:
|
||||||
// create a validation function that dynamically
|
// create a validation function that dynamically
|
||||||
@@ -84,7 +87,6 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
type: 'array',
|
|
||||||
},
|
},
|
||||||
...(formConfig?.formSubmissionOverrides?.fields || []),
|
...(formConfig?.formSubmissionOverrides?.fields || []),
|
||||||
],
|
],
|
||||||
@@ -96,7 +98,6 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
|||||||
],
|
],
|
||||||
...(formConfig?.formSubmissionOverrides?.hooks || {}),
|
...(formConfig?.formSubmissionOverrides?.hooks || {}),
|
||||||
},
|
},
|
||||||
slug: formConfig?.formSubmissionOverrides?.slug || 'form-submissions',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const paymentFieldConfig = formConfig?.fields?.payment
|
const paymentFieldConfig = formConfig?.fields?.payment
|
||||||
@@ -104,26 +105,27 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
|||||||
if (paymentFieldConfig) {
|
if (paymentFieldConfig) {
|
||||||
newConfig.fields.push({
|
newConfig.fields.push({
|
||||||
name: 'payment',
|
name: 'payment',
|
||||||
|
type: 'group',
|
||||||
admin: {
|
admin: {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'field',
|
name: 'field',
|
||||||
label: 'Field',
|
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
label: 'Field',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'status',
|
name: 'status',
|
||||||
label: 'Status',
|
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
label: 'Status',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'amount',
|
name: 'amount',
|
||||||
|
type: 'number',
|
||||||
admin: {
|
admin: {
|
||||||
description: 'Amount in cents',
|
description: 'Amount in cents',
|
||||||
},
|
},
|
||||||
type: 'number',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'paymentProcessor',
|
name: 'paymentProcessor',
|
||||||
@@ -131,28 +133,27 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'creditCard',
|
name: 'creditCard',
|
||||||
|
type: 'group',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
name: 'token',
|
name: 'token',
|
||||||
label: 'token',
|
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
label: 'token',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'brand',
|
name: 'brand',
|
||||||
label: 'Brand',
|
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
label: 'Brand',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'number',
|
name: 'number',
|
||||||
label: 'Number',
|
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
label: 'Number',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: 'Credit Card',
|
label: 'Credit Card',
|
||||||
type: 'group',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
type: 'group',
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-nested-docs",
|
"name": "@payloadcms/plugin-nested-docs",
|
||||||
"version": "1.0.11",
|
"version": "1.0.12",
|
||||||
"description": "The official Nested Docs plugin for Payload",
|
"description": "The official Nested Docs plugin for Payload",
|
||||||
"repository": "https://github.com/payloadcms/payload",
|
"repository": "https://github.com/payloadcms/payload",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -20,6 +20,9 @@
|
|||||||
"@payloadcms/eslint-config": "workspace:*",
|
"@payloadcms/eslint-config": "workspace:*",
|
||||||
"payload": "workspace:*"
|
"payload": "workspace:*"
|
||||||
},
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"payload": "^0.18.5 || ^1.0.0 || ^2.0.0"
|
||||||
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"default": "./src/index.ts",
|
"default": "./src/index.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/plugin-search",
|
"name": "@payloadcms/plugin-search",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"homepage:": "https://payloadcms.com",
|
"homepage:": "https://payloadcms.com",
|
||||||
"repository": "git@github.com:payloadcms/plugin-search.git",
|
"repository": "git@github.com:payloadcms/plugin-search.git",
|
||||||
"description": "Search plugin for Payload",
|
"description": "Search plugin for Payload",
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import type { CollectionAfterDeleteHook } from 'payload/types'
|
import type { CollectionAfterDeleteHook } from 'payload/types'
|
||||||
|
|
||||||
const deleteFromSearch: CollectionAfterDeleteHook = ({ doc, req: { payload } }) => {
|
const deleteFromSearch: CollectionAfterDeleteHook = async ({ doc, req: { payload }, req }) => {
|
||||||
try {
|
try {
|
||||||
const deleteSearchDoc = async (): Promise<any> => {
|
|
||||||
const searchDocQuery = await payload.find({
|
const searchDocQuery = await payload.find({
|
||||||
collection: 'search',
|
collection: 'search',
|
||||||
depth: 0,
|
depth: 0,
|
||||||
|
req,
|
||||||
where: {
|
where: {
|
||||||
'doc.value': {
|
'doc.value': {
|
||||||
equals: doc.id,
|
equals: doc.id,
|
||||||
@@ -14,14 +14,12 @@ const deleteFromSearch: CollectionAfterDeleteHook = ({ doc, req: { payload } })
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (searchDocQuery?.docs?.[0]) {
|
if (searchDocQuery?.docs?.[0]) {
|
||||||
payload.delete({
|
await payload.delete({
|
||||||
id: searchDocQuery?.docs?.[0]?.id,
|
id: searchDocQuery?.docs?.[0]?.id,
|
||||||
collection: 'search',
|
collection: 'search',
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
deleteSearchDoc()
|
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
payload.logger.error({
|
payload.logger.error({
|
||||||
err: `Error deleting search doc: ${err}`,
|
err: `Error deleting search doc: ${err}`,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
|||||||
doc,
|
doc,
|
||||||
operation,
|
operation,
|
||||||
req: { payload },
|
req: { payload },
|
||||||
|
req,
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
searchConfig,
|
searchConfig,
|
||||||
} = args
|
} = args
|
||||||
@@ -26,6 +27,7 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
|||||||
dataToSave = await beforeSync({
|
dataToSave = await beforeSync({
|
||||||
originalDoc: doc,
|
originalDoc: doc,
|
||||||
payload,
|
payload,
|
||||||
|
req,
|
||||||
searchDoc: dataToSave,
|
searchDoc: dataToSave,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -53,13 +55,13 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
|||||||
try {
|
try {
|
||||||
if (operation === 'create') {
|
if (operation === 'create') {
|
||||||
if (doSync) {
|
if (doSync) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
await payload.create({
|
||||||
payload.create({
|
|
||||||
collection: 'search',
|
collection: 'search',
|
||||||
data: {
|
data: {
|
||||||
...dataToSave,
|
...dataToSave,
|
||||||
priority: defaultPriority,
|
priority: defaultPriority,
|
||||||
},
|
},
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,6 +72,7 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
|||||||
const searchDocQuery = await payload.find({
|
const searchDocQuery = await payload.find({
|
||||||
collection: 'search',
|
collection: 'search',
|
||||||
depth: 0,
|
depth: 0,
|
||||||
|
req,
|
||||||
where: {
|
where: {
|
||||||
'doc.value': {
|
'doc.value': {
|
||||||
equals: id,
|
equals: id,
|
||||||
@@ -88,15 +91,12 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
|||||||
// to ensure the same, out-of-date result does not appear twice (where only syncing the first found doc)
|
// to ensure the same, out-of-date result does not appear twice (where only syncing the first found doc)
|
||||||
if (duplicativeDocs.length > 0) {
|
if (duplicativeDocs.length > 0) {
|
||||||
try {
|
try {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
const duplicativeDocIDs = duplicativeDocs.map(({ id }) => id)
|
||||||
Promise.all(
|
await payload.delete({
|
||||||
duplicativeDocs.map(({ id: duplicativeDocID }) =>
|
|
||||||
payload.delete({
|
|
||||||
id: duplicativeDocID,
|
|
||||||
collection: 'search',
|
collection: 'search',
|
||||||
}),
|
req,
|
||||||
), // eslint-disable-line function-paren-newline
|
where: { id: { in: duplicativeDocIDs } },
|
||||||
)
|
})
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
payload.logger.error(`Error deleting duplicative search documents.`)
|
payload.logger.error(`Error deleting duplicative search documents.`)
|
||||||
}
|
}
|
||||||
@@ -108,14 +108,14 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
|||||||
if (doSync) {
|
if (doSync) {
|
||||||
// update the doc normally
|
// update the doc normally
|
||||||
try {
|
try {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
await payload.update({
|
||||||
payload.update({
|
|
||||||
id: searchDocID,
|
id: searchDocID,
|
||||||
collection: 'search',
|
collection: 'search',
|
||||||
data: {
|
data: {
|
||||||
...dataToSave,
|
...dataToSave,
|
||||||
priority: foundDoc.priority || defaultPriority,
|
priority: foundDoc.priority || defaultPriority,
|
||||||
},
|
},
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
payload.logger.error(`Error updating search document.`)
|
payload.logger.error(`Error updating search document.`)
|
||||||
@@ -124,10 +124,10 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
|||||||
if (deleteDrafts && status === 'draft') {
|
if (deleteDrafts && status === 'draft') {
|
||||||
// do not include draft docs in search results, so delete the record
|
// do not include draft docs in search results, so delete the record
|
||||||
try {
|
try {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
await payload.delete({
|
||||||
payload.delete({
|
|
||||||
id: searchDocID,
|
id: searchDocID,
|
||||||
collection: 'search',
|
collection: 'search',
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
payload.logger.error(`Error deleting search document: ${err}`)
|
payload.logger.error(`Error deleting search document: ${err}`)
|
||||||
@@ -135,13 +135,13 @@ const syncWithSearch: SyncWithSearch = async (args) => {
|
|||||||
}
|
}
|
||||||
} else if (doSync) {
|
} else if (doSync) {
|
||||||
try {
|
try {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
await payload.create({
|
||||||
payload.create({
|
|
||||||
collection: 'search',
|
collection: 'search',
|
||||||
data: {
|
data: {
|
||||||
...dataToSave,
|
...dataToSave,
|
||||||
priority: defaultPriority,
|
priority: defaultPriority,
|
||||||
},
|
},
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
payload.logger.error(`Error creating search document: ${err}`)
|
payload.logger.error(`Error creating search document: ${err}`)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const Search =
|
|||||||
afterChange: [
|
afterChange: [
|
||||||
...(existingHooks?.afterChange || []),
|
...(existingHooks?.afterChange || []),
|
||||||
async (args: any) => {
|
async (args: any) => {
|
||||||
syncWithSearch({
|
await syncWithSearch({
|
||||||
...args,
|
...args,
|
||||||
collection: collection.slug,
|
collection: collection.slug,
|
||||||
searchConfig,
|
searchConfig,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Payload } from 'payload'
|
import type { Payload } from 'payload'
|
||||||
import type { CollectionAfterChangeHook, CollectionConfig } from 'payload/types'
|
import type { CollectionAfterChangeHook, CollectionConfig, PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
export interface DocToSync {
|
export interface DocToSync {
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
@@ -15,6 +15,7 @@ export type BeforeSync = (args: {
|
|||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
payload: Payload
|
payload: Payload
|
||||||
|
req: PayloadRequest
|
||||||
searchDoc: DocToSync
|
searchDoc: DocToSync
|
||||||
}) => DocToSync | Promise<DocToSync>
|
}) => DocToSync | Promise<DocToSync>
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"nodemon": "^2.0.6",
|
"nodemon": "3.0.3",
|
||||||
"payload": "workspace:*",
|
"payload": "workspace:*",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"webpack": "^5.78.0"
|
"webpack": "^5.78.0"
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import en from './en.json'
|
|||||||
import es from './es.json'
|
import es from './es.json'
|
||||||
import fa from './fa.json'
|
import fa from './fa.json'
|
||||||
import fr from './fr.json'
|
import fr from './fr.json'
|
||||||
|
import pl from './pl.json'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
en,
|
en,
|
||||||
es,
|
es,
|
||||||
fa,
|
fa,
|
||||||
fr,
|
fr,
|
||||||
|
pl,
|
||||||
}
|
}
|
||||||
|
|||||||
22
packages/plugin-seo/src/translations/pl.json
Normal file
22
packages/plugin-seo/src/translations/pl.json
Normal 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."
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@payloadcms/richtext-lexical",
|
"name": "@payloadcms/richtext-lexical",
|
||||||
"version": "0.6.1",
|
"version": "0.7.0",
|
||||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||||
"repository": "https://github.com/payloadcms/payload",
|
"repository": "https://github.com/payloadcms/payload",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -19,31 +19,31 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@faceless-ui/modal": "2.0.1",
|
"@faceless-ui/modal": "2.0.1",
|
||||||
"@lexical/headless": "0.12.6",
|
"@lexical/headless": "0.13.1",
|
||||||
"@lexical/link": "0.12.6",
|
"@lexical/link": "0.13.1",
|
||||||
"@lexical/list": "0.12.6",
|
"@lexical/list": "0.13.1",
|
||||||
"@lexical/mark": "0.12.6",
|
"@lexical/mark": "0.13.1",
|
||||||
"@lexical/markdown": "0.12.6",
|
"@lexical/markdown": "0.13.1",
|
||||||
"@lexical/react": "0.12.6",
|
"@lexical/react": "0.13.1",
|
||||||
"@lexical/rich-text": "0.12.6",
|
"@lexical/rich-text": "0.13.1",
|
||||||
"@lexical/selection": "0.12.6",
|
"@lexical/selection": "0.13.1",
|
||||||
"@lexical/utils": "0.12.6",
|
"@lexical/utils": "0.13.1",
|
||||||
"bson-objectid": "2.0.4",
|
"bson-objectid": "2.0.4",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"deep-equal": "2.2.3",
|
"deep-equal": "2.2.3",
|
||||||
"i18next": "22.5.1",
|
"i18next": "22.5.1",
|
||||||
"json-schema": "^0.4.0",
|
"json-schema": "^0.4.0",
|
||||||
"lexical": "0.12.6",
|
"lexical": "0.13.1",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-error-boundary": "^4.0.11",
|
"react-error-boundary": "4.0.12",
|
||||||
"react-i18next": "11.18.6",
|
"react-i18next": "11.18.6",
|
||||||
"ts-essentials": "7.0.3"
|
"ts-essentials": "7.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@payloadcms/eslint-config": "workspace:*",
|
"@payloadcms/eslint-config": "workspace:*",
|
||||||
"@types/json-schema": "7.0.12",
|
"@types/json-schema": "7.0.15",
|
||||||
"@types/node": "20.6.2",
|
"@types/node": "20.6.2",
|
||||||
"@types/react": "18.2.15",
|
"@types/react": "18.2.15",
|
||||||
"payload": "workspace:*"
|
"payload": "workspace:*"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { SerializedQuoteNode } from '@lexical/rich-text'
|
|||||||
|
|
||||||
import { $createQuoteNode, QuoteNode } from '@lexical/rich-text'
|
import { $createQuoteNode, QuoteNode } from '@lexical/rich-text'
|
||||||
import { $setBlocksType } from '@lexical/selection'
|
import { $setBlocksType } from '@lexical/selection'
|
||||||
import { $INTERNAL_isPointSelection, $getSelection } from 'lexical'
|
import { $getSelection } from 'lexical'
|
||||||
|
|
||||||
import type { HTMLConverter } from '../converters/html/converter/types'
|
import type { HTMLConverter } from '../converters/html/converter/types'
|
||||||
import type { FeatureProvider } from '../types'
|
import type { FeatureProvider } from '../types'
|
||||||
@@ -31,9 +31,7 @@ export const BlockQuoteFeature = (): FeatureProvider => {
|
|||||||
onClick: ({ editor }) => {
|
onClick: ({ editor }) => {
|
||||||
editor.update(() => {
|
editor.update(() => {
|
||||||
const selection = $getSelection()
|
const selection = $getSelection()
|
||||||
if ($INTERNAL_isPointSelection(selection)) {
|
|
||||||
$setBlocksType(selection, () => $createQuoteNode())
|
$setBlocksType(selection, () => $createQuoteNode())
|
||||||
}
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
order: 20,
|
order: 20,
|
||||||
@@ -44,6 +42,7 @@ export const BlockQuoteFeature = (): FeatureProvider => {
|
|||||||
markdownTransformers: [MarkdownTransformer],
|
markdownTransformers: [MarkdownTransformer],
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
|
type: QuoteNode.getType(),
|
||||||
converters: {
|
converters: {
|
||||||
html: {
|
html: {
|
||||||
converter: async ({ converters, node, parent }) => {
|
converter: async ({ converters, node, parent }) => {
|
||||||
@@ -62,7 +61,6 @@ export const BlockQuoteFeature = (): FeatureProvider => {
|
|||||||
} as HTMLConverter<SerializedQuoteNode>,
|
} as HTMLConverter<SerializedQuoteNode>,
|
||||||
},
|
},
|
||||||
node: QuoteNode,
|
node: QuoteNode,
|
||||||
type: QuoteNode.getType(),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
props: null,
|
props: null,
|
||||||
@@ -82,9 +80,7 @@ export const BlockQuoteFeature = (): FeatureProvider => {
|
|||||||
keywords: ['quote', 'blockquote'],
|
keywords: ['quote', 'blockquote'],
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
const selection = $getSelection()
|
const selection = $getSelection()
|
||||||
if ($INTERNAL_isPointSelection(selection)) {
|
|
||||||
$setBlocksType(selection, () => $createQuoteNode())
|
$setBlocksType(selection, () => $createQuoteNode())
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -39,8 +39,16 @@ export function BlocksPlugin(): JSX.Element | null {
|
|||||||
const { focus } = selection
|
const { focus } = selection
|
||||||
const focusNode = focus.getNode()
|
const focusNode = focus.getNode()
|
||||||
|
|
||||||
// First, delete currently selected node if it's an empty paragraph
|
// First, delete currently selected node if it's an empty paragraph and if there are sufficient
|
||||||
if ($isParagraphNode(focusNode) && focusNode.getTextContentSize() === 0) {
|
// paragraph nodes (more than 1) left in the parent node, so that we don't "trap" the user
|
||||||
|
if (
|
||||||
|
$isParagraphNode(focusNode) &&
|
||||||
|
focusNode.getTextContentSize() === 0 &&
|
||||||
|
focusNode
|
||||||
|
.getParent()
|
||||||
|
.getChildren()
|
||||||
|
.filter((node) => $isParagraphNode(node)).length > 1
|
||||||
|
) {
|
||||||
focusNode.remove()
|
focusNode.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { HeadingTagType, SerializedHeadingNode } from '@lexical/rich-text'
|
|||||||
|
|
||||||
import { $createHeadingNode, HeadingNode } from '@lexical/rich-text'
|
import { $createHeadingNode, HeadingNode } from '@lexical/rich-text'
|
||||||
import { $setBlocksType } from '@lexical/selection'
|
import { $setBlocksType } from '@lexical/selection'
|
||||||
import { $INTERNAL_isPointSelection, $getSelection } from 'lexical'
|
import { $getSelection } from 'lexical'
|
||||||
|
|
||||||
import type { HTMLConverter } from '../converters/html/converter/types'
|
import type { HTMLConverter } from '../converters/html/converter/types'
|
||||||
import type { FeatureProvider } from '../types'
|
import type { FeatureProvider } from '../types'
|
||||||
@@ -14,10 +14,8 @@ import { MarkdownTransformer } from './markdownTransformer'
|
|||||||
|
|
||||||
const setHeading = (headingSize: HeadingTagType) => {
|
const setHeading = (headingSize: HeadingTagType) => {
|
||||||
const selection = $getSelection()
|
const selection = $getSelection()
|
||||||
if ($INTERNAL_isPointSelection(selection)) {
|
|
||||||
$setBlocksType(selection, () => $createHeadingNode(headingSize))
|
$setBlocksType(selection, () => $createHeadingNode(headingSize))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
enabledHeadingSizes?: HeadingTagType[]
|
enabledHeadingSizes?: HeadingTagType[]
|
||||||
@@ -67,6 +65,7 @@ export const HeadingFeature = (props: Props): FeatureProvider => {
|
|||||||
markdownTransformers: [MarkdownTransformer(enabledHeadingSizes)],
|
markdownTransformers: [MarkdownTransformer(enabledHeadingSizes)],
|
||||||
nodes: [
|
nodes: [
|
||||||
{
|
{
|
||||||
|
type: HeadingNode.getType(),
|
||||||
converters: {
|
converters: {
|
||||||
html: {
|
html: {
|
||||||
converter: async ({ converters, node, parent }) => {
|
converter: async ({ converters, node, parent }) => {
|
||||||
@@ -85,7 +84,6 @@ export const HeadingFeature = (props: Props): FeatureProvider => {
|
|||||||
} as HTMLConverter<SerializedHeadingNode>,
|
} as HTMLConverter<SerializedHeadingNode>,
|
||||||
},
|
},
|
||||||
node: HeadingNode,
|
node: HeadingNode,
|
||||||
type: HeadingNode.getType(),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
props,
|
props,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user