Compare commits
23 Commits
db-postgre
...
db-postgre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b9e87bb4d | ||
|
|
ff5e174497 | ||
|
|
34017e1758 | ||
|
|
23d95526ab | ||
|
|
59b87fdb21 | ||
|
|
f2ac1f7d48 | ||
|
|
8d4f39af5e | ||
|
|
c4ac341d75 | ||
|
|
27589482dd | ||
|
|
d7ab4b7062 | ||
|
|
2c8fbf1be3 | ||
|
|
eec88f8f1b | ||
|
|
1481ef97b5 | ||
|
|
a89e89fb80 | ||
|
|
7e7eeb059d | ||
|
|
dc2a502dcc | ||
|
|
a9a5ba82d8 | ||
|
|
e6e8fae1c5 | ||
|
|
a05868a7f3 | ||
|
|
f27cd26575 | ||
|
|
b0083b7c07 | ||
|
|
21649537a6 | ||
|
|
2c67eff059 |
@@ -131,6 +131,7 @@ const result = await payload.find({
|
||||
depth: 2,
|
||||
page: 1,
|
||||
limit: 10,
|
||||
pagination: false, // If you want to disable pagination count, etc.
|
||||
where: {}, // pass a `where` query here
|
||||
sort: '-title',
|
||||
locale: 'en',
|
||||
|
||||
@@ -59,3 +59,7 @@ All Payload APIs support the pagination controls below. With them, you can creat
|
||||
| ------- | --------------------------------------- |
|
||||
| `limit` | Limits the number of documents returned |
|
||||
| `page` | Get a specific page number |
|
||||
|
||||
### Disabling pagination within Local API
|
||||
|
||||
For `find` operations within the Local API, you can disable pagination to retrieve all documents from a collection by passing `pagination: false` to the `find` local operation. This is not supported in REST or GraphQL, however, because it could potentially lead to malicious activity.
|
||||
@@ -59,6 +59,7 @@
|
||||
"fs-extra": "10.1.0",
|
||||
"get-port": "5.1.1",
|
||||
"glob": "8.1.0",
|
||||
"graphql-request": "6.1.0",
|
||||
"husky": "^8.0.3",
|
||||
"isomorphic-fetch": "3.0.0",
|
||||
"jest": "29.6.4",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.8",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
@@ -34,9 +34,6 @@
|
||||
"@types/to-snake-case": "1.0.0",
|
||||
"payload": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"better-sqlite3": "^8.5.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"main": "./dist/index.js",
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
|
||||
@@ -33,7 +33,7 @@ export const findMany = async function find({
|
||||
const db = adapter.sessions[req.transactionID]?.db || adapter.drizzle
|
||||
const table = adapter.tables[tableName]
|
||||
|
||||
let limit = limitArg
|
||||
let limit = limitArg ?? 10
|
||||
let totalDocs: number
|
||||
let totalPages: number
|
||||
let hasPrevPage: boolean
|
||||
@@ -119,7 +119,11 @@ export const findMany = async function find({
|
||||
findManyArgs.where = inArray(adapter.tables[tableName].id, Object.keys(orderedIDMap))
|
||||
} else {
|
||||
findManyArgs.limit = limitArg === 0 ? undefined : limitArg
|
||||
findManyArgs.offset = skip || (page - 1) * limitArg
|
||||
|
||||
const offset = skip || (page - 1) * limitArg
|
||||
|
||||
if (!Number.isNaN(offset)) findManyArgs.offset = offset
|
||||
|
||||
if (where) {
|
||||
findManyArgs.where = where
|
||||
}
|
||||
|
||||
@@ -34,12 +34,14 @@ type Args = {
|
||||
aliasTable?: GenericTable
|
||||
collectionPath: string
|
||||
columnPrefix?: string
|
||||
constraintPath?: string
|
||||
constraints?: Constraint[]
|
||||
fields: (Field | TabAsField)[]
|
||||
joinAliases: BuildQueryJoinAliases
|
||||
joins: BuildQueryJoins
|
||||
locale?: string
|
||||
pathSegments: string[]
|
||||
rootTableName?: string
|
||||
selectFields: Record<string, GenericColumn>
|
||||
tableName: string
|
||||
}
|
||||
@@ -53,17 +55,22 @@ export const getTableColumnFromPath = ({
|
||||
aliasTable,
|
||||
collectionPath,
|
||||
columnPrefix = '',
|
||||
constraintPath: incomingConstraintPath,
|
||||
constraints = [],
|
||||
fields,
|
||||
joinAliases,
|
||||
joins,
|
||||
locale: incomingLocale,
|
||||
pathSegments: incomingSegments,
|
||||
rootTableName: incomingRootTableName,
|
||||
selectFields,
|
||||
tableName,
|
||||
}: Args): TableColumn => {
|
||||
const fieldPath = incomingSegments[0]
|
||||
let locale = incomingLocale
|
||||
const rootTableName = incomingRootTableName || tableName
|
||||
let constraintPath = incomingConstraintPath || ''
|
||||
|
||||
const field = flattenTopLevelFields(fields as Field[]).find(
|
||||
(fieldToFind) => fieldAffectsData(fieldToFind) && fieldToFind.name === fieldPath,
|
||||
) as Field | TabAsField
|
||||
@@ -105,6 +112,7 @@ export const getTableColumnFromPath = ({
|
||||
aliasTable,
|
||||
collectionPath,
|
||||
columnPrefix,
|
||||
constraintPath,
|
||||
constraints,
|
||||
fields: field.tabs.map((tab) => ({
|
||||
...tab,
|
||||
@@ -114,6 +122,7 @@ export const getTableColumnFromPath = ({
|
||||
joins,
|
||||
locale,
|
||||
pathSegments: pathSegments.slice(1),
|
||||
rootTableName,
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
})
|
||||
@@ -125,12 +134,14 @@ export const getTableColumnFromPath = ({
|
||||
aliasTable,
|
||||
collectionPath,
|
||||
columnPrefix: `${columnPrefix}${field.name}_`,
|
||||
constraintPath,
|
||||
constraints,
|
||||
fields: field.fields,
|
||||
joinAliases,
|
||||
joins,
|
||||
locale,
|
||||
pathSegments: pathSegments.slice(1),
|
||||
rootTableName,
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
})
|
||||
@@ -140,12 +151,14 @@ export const getTableColumnFromPath = ({
|
||||
aliasTable,
|
||||
collectionPath,
|
||||
columnPrefix,
|
||||
constraintPath,
|
||||
constraints,
|
||||
fields: field.fields,
|
||||
joinAliases,
|
||||
joins,
|
||||
locale,
|
||||
pathSegments: pathSegments.slice(1),
|
||||
rootTableName,
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
})
|
||||
@@ -172,12 +185,14 @@ export const getTableColumnFromPath = ({
|
||||
aliasTable,
|
||||
collectionPath,
|
||||
columnPrefix: `${columnPrefix}${field.name}_`,
|
||||
constraintPath,
|
||||
constraints,
|
||||
fields: field.fields,
|
||||
joinAliases,
|
||||
joins,
|
||||
locale,
|
||||
pathSegments: pathSegments.slice(1),
|
||||
rootTableName,
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
})
|
||||
@@ -185,6 +200,7 @@ export const getTableColumnFromPath = ({
|
||||
|
||||
case 'array': {
|
||||
newTableName = `${tableName}_${toSnakeCase(field.name)}`
|
||||
constraintPath = `${constraintPath}${field.name}.%.`
|
||||
if (locale && field.localized && adapter.payload.config.localization) {
|
||||
joins[newTableName] = and(
|
||||
eq(adapter.tables[tableName].id, adapter.tables[newTableName]._parentID),
|
||||
@@ -206,12 +222,14 @@ export const getTableColumnFromPath = ({
|
||||
return getTableColumnFromPath({
|
||||
adapter,
|
||||
collectionPath,
|
||||
constraintPath,
|
||||
constraints,
|
||||
fields: field.fields,
|
||||
joinAliases,
|
||||
joins,
|
||||
locale,
|
||||
pathSegments: pathSegments.slice(1),
|
||||
rootTableName,
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
})
|
||||
@@ -229,12 +247,14 @@ export const getTableColumnFromPath = ({
|
||||
result = getTableColumnFromPath({
|
||||
adapter,
|
||||
collectionPath,
|
||||
constraintPath: '',
|
||||
constraints: blockConstraints,
|
||||
fields: block.fields,
|
||||
joinAliases,
|
||||
joins,
|
||||
locale,
|
||||
pathSegments: pathSegments.slice(1),
|
||||
rootTableName,
|
||||
selectFields: blockSelectFields,
|
||||
tableName: newTableName,
|
||||
})
|
||||
@@ -283,9 +303,8 @@ export const getTableColumnFromPath = ({
|
||||
case 'relationship':
|
||||
case 'upload': {
|
||||
let relationshipFields
|
||||
const relationTableName = `${tableName}_rels`
|
||||
const relationTableName = `${rootTableName}_rels`
|
||||
const newCollectionPath = pathSegments.slice(1).join('.')
|
||||
|
||||
const aliasRelationshipTableName = uuid()
|
||||
const aliasRelationshipTable = alias(
|
||||
adapter.tables[relationTableName],
|
||||
@@ -295,7 +314,7 @@ export const getTableColumnFromPath = ({
|
||||
// Join in the relationships table
|
||||
joinAliases.push({
|
||||
condition: eq(
|
||||
(aliasTable || adapter.tables[tableName]).id,
|
||||
(aliasTable || adapter.tables[rootTableName]).id,
|
||||
aliasRelationshipTable.parent,
|
||||
),
|
||||
table: aliasRelationshipTable,
|
||||
@@ -306,7 +325,7 @@ export const getTableColumnFromPath = ({
|
||||
constraints.push({
|
||||
columnName: 'path',
|
||||
table: aliasRelationshipTable,
|
||||
value: field.name,
|
||||
value: `${constraintPath}${field.name}`,
|
||||
})
|
||||
|
||||
let newAliasTable
|
||||
@@ -368,6 +387,7 @@ export const getTableColumnFromPath = ({
|
||||
joins,
|
||||
locale,
|
||||
pathSegments: pathSegments.slice(1),
|
||||
rootTableName: newTableName,
|
||||
selectFields,
|
||||
tableName: newTableName,
|
||||
})
|
||||
|
||||
@@ -100,7 +100,11 @@ export async function parseParams({
|
||||
const val = where[relationOrPath][operator]
|
||||
|
||||
queryConstraints.forEach(({ columnName: col, table: constraintTable, value }) => {
|
||||
constraints.push(operatorMap.equals(constraintTable[col], value))
|
||||
if (typeof value === 'string' && value.indexOf('%') > -1) {
|
||||
constraints.push(operatorMap.like(constraintTable[col], value))
|
||||
} else {
|
||||
constraints.push(operatorMap.equals(constraintTable[col], value))
|
||||
}
|
||||
})
|
||||
|
||||
if (['json', 'richText'].includes(field.type) && Array.isArray(pathSegments)) {
|
||||
@@ -144,13 +148,19 @@ export async function parseParams({
|
||||
break
|
||||
}
|
||||
|
||||
const { operator: queryOperator, value: queryValue } = sanitizeQueryValue({
|
||||
const sanitizedQueryValue = sanitizeQueryValue({
|
||||
field,
|
||||
operator,
|
||||
relationOrPath,
|
||||
val,
|
||||
})
|
||||
|
||||
if (sanitizedQueryValue === null) {
|
||||
break
|
||||
}
|
||||
|
||||
const { operator: queryOperator, value: queryValue } = sanitizedQueryValue
|
||||
|
||||
if (queryOperator === 'not_equals' && queryValue !== null) {
|
||||
constraints.push(
|
||||
or(
|
||||
@@ -159,7 +169,10 @@ export async function parseParams({
|
||||
ne<any>(rawColumn || table[columnName], queryValue),
|
||||
),
|
||||
)
|
||||
} else if (
|
||||
break
|
||||
}
|
||||
|
||||
if (
|
||||
(field.type === 'relationship' || field.type === 'upload') &&
|
||||
Array.isArray(queryValue) &&
|
||||
operator === 'not_in'
|
||||
@@ -170,11 +183,13 @@ export async function parseParams({
|
||||
IS
|
||||
NULL`,
|
||||
)
|
||||
} else {
|
||||
constraints.push(
|
||||
operatorMap[queryOperator](rawColumn || table[columnName], queryValue),
|
||||
)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
constraints.push(
|
||||
operatorMap[queryOperator](rawColumn || table[columnName], queryValue),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,11 +42,17 @@ export const sanitizeQueryValue = ({
|
||||
if (val.toLowerCase() === 'false') formattedValue = false
|
||||
}
|
||||
|
||||
if (['all', 'in', 'not_in'].includes(operator) && typeof formattedValue === 'string') {
|
||||
formattedValue = createArrayFromCommaDelineated(formattedValue)
|
||||
if (['all', 'in', 'not_in'].includes(operator)) {
|
||||
if (typeof formattedValue === 'string') {
|
||||
formattedValue = createArrayFromCommaDelineated(formattedValue)
|
||||
|
||||
if (field.type === 'number') {
|
||||
formattedValue = formattedValue.map((arrayVal) => parseFloat(arrayVal))
|
||||
if (field.type === 'number') {
|
||||
formattedValue = formattedValue.map((arrayVal) => parseFloat(arrayVal))
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.isArray(formattedValue) || formattedValue.length === 0) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "payload",
|
||||
"version": "2.0.6",
|
||||
"version": "2.0.7",
|
||||
"description": "Node, React and MongoDB Headless CMS and Application Framework",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -187,7 +187,6 @@
|
||||
"file-loader": "6.2.0",
|
||||
"form-data": "3.0.1",
|
||||
"get-port": "5.1.1",
|
||||
"graphql-request": "6.1.0",
|
||||
"mini-css-extract-plugin": "1.6.2",
|
||||
"node-fetch": "2.6.12",
|
||||
"nodemon": "3.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@payloadcms/richtext-lexical",
|
||||
"version": "0.1.10",
|
||||
"version": "0.1.11",
|
||||
"description": "The officially supported Lexical richtext adapter for Payload",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import type { SerializedEditorState } from 'lexical'
|
||||
import type { CellComponentProps, RichTextField } from 'payload/types'
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ const RichText: React.FC<FieldProps> = (props) => {
|
||||
validate: memoizedValidate,
|
||||
})
|
||||
|
||||
const { errorMessage, initialValue, setValue, showError, value } = fieldType
|
||||
const { errorMessage, setValue, showError, value } = fieldType
|
||||
|
||||
let valueToUse = value
|
||||
|
||||
@@ -87,7 +87,6 @@ const RichText: React.FC<FieldProps> = (props) => {
|
||||
<LexicalProvider
|
||||
editorConfig={editorConfig}
|
||||
fieldProps={props}
|
||||
initialState={initialValue}
|
||||
onChange={(editorState, editor, tags) => {
|
||||
let serializedEditorState = editorState.toJSON()
|
||||
|
||||
@@ -101,7 +100,6 @@ const RichText: React.FC<FieldProps> = (props) => {
|
||||
setValue(serializedEditorState)
|
||||
}}
|
||||
readOnly={readOnly}
|
||||
setValue={setValue}
|
||||
value={value}
|
||||
/>
|
||||
<FieldDescription description={description} value={value} />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client'
|
||||
import { ShimmerEffect } from 'payload/components'
|
||||
import React, { Suspense, lazy } from 'react'
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ import { AddBlockHandlePlugin } from './plugins/handles/AddBlockHandlePlugin'
|
||||
import { DraggableBlockPlugin } from './plugins/handles/DraggableBlockPlugin'
|
||||
import { LexicalContentEditable } from './ui/ContentEditable'
|
||||
|
||||
export const LexicalEditor: React.FC<LexicalProviderProps> = (props) => {
|
||||
export const LexicalEditor: React.FC<Pick<LexicalProviderProps, 'editorConfig' | 'onChange'>> = (
|
||||
props,
|
||||
) => {
|
||||
const { editorConfig, onChange } = props
|
||||
const [editor] = useLexicalComposerContext()
|
||||
|
||||
|
||||
@@ -14,28 +14,21 @@ import { getEnabledNodes } from './nodes'
|
||||
export type LexicalProviderProps = {
|
||||
editorConfig: SanitizedEditorConfig
|
||||
fieldProps: FieldProps
|
||||
initialState: SerializedEditorState
|
||||
onChange: (editorState: EditorState, editor: LexicalEditor, tags: Set<string>) => void
|
||||
readOnly: boolean
|
||||
setValue: (value: SerializedEditorState) => void
|
||||
value: SerializedEditorState
|
||||
}
|
||||
export const LexicalProvider: React.FC<LexicalProviderProps> = (props) => {
|
||||
const { editorConfig, fieldProps, onChange, readOnly, setValue } = props
|
||||
let { initialState, value } = props
|
||||
const { editorConfig, fieldProps, onChange, readOnly } = props
|
||||
let { value } = props
|
||||
|
||||
// Transform initialState through load hooks
|
||||
if (editorConfig?.features?.hooks?.load?.length) {
|
||||
editorConfig.features.hooks.load.forEach((hook) => {
|
||||
initialState = hook({ incomingEditorState: initialState })
|
||||
value = hook({ incomingEditorState: value })
|
||||
})
|
||||
}
|
||||
|
||||
if (
|
||||
(value && Array.isArray(value) && !('root' in value)) ||
|
||||
(initialState && Array.isArray(initialState) && !('root' in initialState))
|
||||
) {
|
||||
if (value && Array.isArray(value) && !('root' in value)) {
|
||||
throw new Error(
|
||||
'You have tried to pass in data from the old, Slate editor, to the new, Lexical editor. This is not supported. There is no automatic conversion from Slate to Lexical data available yet (coming soon). Please remove the data from the field and start again.',
|
||||
)
|
||||
@@ -49,7 +42,7 @@ export const LexicalProvider: React.FC<LexicalProviderProps> = (props) => {
|
||||
|
||||
const initialConfig: InitialConfigType = {
|
||||
editable: readOnly === true ? false : true,
|
||||
editorState: initialState != null ? JSON.stringify(initialState) : undefined,
|
||||
editorState: value != null ? JSON.stringify(value) : undefined,
|
||||
namespace: editorConfig.lexical.namespace,
|
||||
nodes: [...getEnabledNodes({ editorConfig })],
|
||||
onError: (error: Error) => {
|
||||
@@ -62,15 +55,7 @@ export const LexicalProvider: React.FC<LexicalProviderProps> = (props) => {
|
||||
<LexicalComposer initialConfig={initialConfig}>
|
||||
<EditorConfigProvider editorConfig={editorConfig} fieldProps={fieldProps}>
|
||||
<div className="editor-shell">
|
||||
<LexicalEditorComponent
|
||||
editorConfig={editorConfig}
|
||||
fieldProps={fieldProps}
|
||||
initialState={initialState}
|
||||
onChange={onChange}
|
||||
readOnly={readOnly}
|
||||
setValue={setValue}
|
||||
value={value}
|
||||
/>
|
||||
<LexicalEditorComponent editorConfig={editorConfig} onChange={onChange} />
|
||||
</div>
|
||||
</EditorConfigProvider>
|
||||
</LexicalComposer>
|
||||
|
||||
14
pnpm-lock.yaml
generated
14
pnpm-lock.yaml
generated
@@ -96,6 +96,9 @@ importers:
|
||||
glob:
|
||||
specifier: 8.1.0
|
||||
version: 8.1.0
|
||||
graphql-request:
|
||||
specifier: 6.1.0
|
||||
version: 6.1.0(graphql@16.8.1)
|
||||
husky:
|
||||
specifier: ^8.0.3
|
||||
version: 8.0.3
|
||||
@@ -418,9 +421,6 @@ importers:
|
||||
'@libsql/client':
|
||||
specifier: ^0.3.1
|
||||
version: 0.3.4
|
||||
better-sqlite3:
|
||||
specifier: ^8.5.0
|
||||
version: 8.6.0
|
||||
console-table-printer:
|
||||
specifier: 2.11.2
|
||||
version: 2.11.2
|
||||
@@ -429,7 +429,7 @@ importers:
|
||||
version: 0.19.13-e99bac1
|
||||
drizzle-orm:
|
||||
specifier: 0.28.5
|
||||
version: 0.28.5(@libsql/client@0.3.4)(@types/pg@8.10.2)(better-sqlite3@8.6.0)(pg@8.11.3)
|
||||
version: 0.28.5(@libsql/client@0.3.4)(@types/pg@8.10.2)(pg@8.11.3)
|
||||
pg:
|
||||
specifier: 8.11.3
|
||||
version: 8.11.3
|
||||
@@ -943,9 +943,6 @@ importers:
|
||||
get-port:
|
||||
specifier: 5.1.1
|
||||
version: 5.1.1
|
||||
graphql-request:
|
||||
specifier: 6.1.0
|
||||
version: 6.1.0(graphql@16.8.1)
|
||||
mini-css-extract-plugin:
|
||||
specifier: 1.6.2
|
||||
version: 1.6.2(webpack@5.88.2)
|
||||
@@ -8447,7 +8444,7 @@ packages:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/drizzle-orm@0.28.5(@libsql/client@0.3.4)(@types/pg@8.10.2)(better-sqlite3@8.6.0)(pg@8.11.3):
|
||||
/drizzle-orm@0.28.5(@libsql/client@0.3.4)(@types/pg@8.10.2)(pg@8.11.3):
|
||||
resolution: {integrity: sha512-6r6Iw4c38NAmW6TiKH3TUpGUQ1YdlEoLJOQptn8XPx3Z63+vFNKfAiANqrIiYZiMjKR9+NYAL219nFrmo1duXA==}
|
||||
peerDependencies:
|
||||
'@aws-sdk/client-rds-data': '>=3'
|
||||
@@ -8511,7 +8508,6 @@ packages:
|
||||
dependencies:
|
||||
'@libsql/client': 0.3.4
|
||||
'@types/pg': 8.10.2
|
||||
better-sqlite3: 8.6.0
|
||||
pg: 8.11.3
|
||||
dev: false
|
||||
|
||||
|
||||
79
scripts/lib/getPackageDetails.ts
Normal file
79
scripts/lib/getPackageDetails.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import path from 'path'
|
||||
import fse from 'fs-extra'
|
||||
import chalk from 'chalk'
|
||||
import chalkTemplate from 'chalk-template'
|
||||
import simpleGit from 'simple-git'
|
||||
|
||||
const git = simpleGit()
|
||||
const packagesDir = path.resolve(__dirname, '../../packages')
|
||||
|
||||
export type PackageDetails = {
|
||||
name: string
|
||||
newCommits: number
|
||||
shortName: string
|
||||
packagePath: string
|
||||
publishedVersion: string
|
||||
publishDate: string
|
||||
version: string
|
||||
}
|
||||
|
||||
export const getPackageDetails = async (): Promise<PackageDetails[]> => {
|
||||
const packageDirs = fse.readdirSync(packagesDir).filter((d) => d !== 'eslint-config-payload')
|
||||
const packageDetails = await Promise.all(
|
||||
packageDirs.map(async (dirName) => {
|
||||
const packageJson = await fse.readJson(`${packagesDir}/${dirName}/package.json`)
|
||||
const isPublic = packageJson.private !== true
|
||||
if (!isPublic) return null
|
||||
|
||||
// Get published version from npm
|
||||
const json = await fetch(`https://registry.npmjs.org/${packageJson.name}`).then((res) =>
|
||||
res.json(),
|
||||
)
|
||||
|
||||
const publishedVersion = json?.['dist-tags']?.latest
|
||||
const publishDate = json?.time?.[publishedVersion]
|
||||
|
||||
const prevGitTag = `${dirName}/${packageJson.version}`
|
||||
const prevGitTagHash = await git.revparse(prevGitTag)
|
||||
|
||||
const newCommits = await git.log({
|
||||
from: prevGitTagHash,
|
||||
file: `packages/${dirName}`,
|
||||
})
|
||||
|
||||
return {
|
||||
name: packageJson.name as string,
|
||||
newCommits: newCommits.total,
|
||||
shortName: dirName,
|
||||
packagePath: `packages/${dirName}`,
|
||||
publishedVersion,
|
||||
publishDate,
|
||||
version: packageJson.version,
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
return packageDetails.filter((p): p is Exclude<typeof p, null> => p !== null)
|
||||
}
|
||||
|
||||
export const showPackageDetails = (details: PackageDetails[]) => {
|
||||
console.log(chalkTemplate`
|
||||
|
||||
{bold Packages:}
|
||||
|
||||
${details
|
||||
.map((p) => {
|
||||
const name = p?.newCommits ? chalk.bold.green(p?.shortName.padEnd(28)) : p?.shortName.padEnd(28)
|
||||
const publishData = `${p?.publishedVersion} at ${p?.publishDate
|
||||
.split(':')
|
||||
.slice(0, 2)
|
||||
.join(':')
|
||||
.replace('T', ' ')}`
|
||||
const newCommits = `${p?.newCommits ? `${chalk.bold.green(p?.newCommits)} new commits` : ''}`
|
||||
|
||||
return ` ${name}${publishData} ${newCommits}`
|
||||
})
|
||||
.join('\n')}
|
||||
|
||||
`)
|
||||
}
|
||||
@@ -1,74 +1,10 @@
|
||||
import path from 'path'
|
||||
import fse from 'fs-extra'
|
||||
import chalk from 'chalk'
|
||||
import chalkTemplate from 'chalk-template'
|
||||
import simpleGit from 'simple-git'
|
||||
|
||||
const git = simpleGit()
|
||||
|
||||
const packagesDir = path.resolve(__dirname, '../packages')
|
||||
import { getPackageDetails, showPackageDetails } from './lib/getPackageDetails'
|
||||
|
||||
async function main() {
|
||||
// List all public packages excluding eslint-config-payload
|
||||
const packageDirs = fse.readdirSync(packagesDir).filter((d) => d !== 'eslint-config-payload')
|
||||
const packageDetails = await Promise.all(
|
||||
packageDirs.map(async (dirName) => {
|
||||
const packageJson = await fse.readJson(`${packagesDir}/${dirName}/package.json`)
|
||||
const isPublic = packageJson.private !== true
|
||||
if (!isPublic) return null
|
||||
|
||||
// Get published version from npm
|
||||
const json = await fetch(`https://registry.npmjs.org/${packageJson.name}`).then((res) =>
|
||||
res.json(),
|
||||
)
|
||||
|
||||
const publishedVersion = json?.['dist-tags']?.latest
|
||||
const publishDate = json?.time?.[publishedVersion]
|
||||
|
||||
const prevGitTag = `${dirName}/${packageJson.version}`
|
||||
const prevGitTagHash = await git.revparse(prevGitTag)
|
||||
|
||||
const newCommits = await git.log({
|
||||
from: prevGitTagHash,
|
||||
file: `packages/${dirName}`,
|
||||
})
|
||||
|
||||
return {
|
||||
name: packageJson.name,
|
||||
newCommits: newCommits.total,
|
||||
packageDir: dirName,
|
||||
packagePath: `packages/${dirName}`,
|
||||
publishedVersion,
|
||||
publishDate,
|
||||
version: packageJson.version,
|
||||
}
|
||||
}),
|
||||
)
|
||||
console.log(chalkTemplate`
|
||||
|
||||
{bold Packages:}
|
||||
|
||||
${packageDetails
|
||||
.map((p) => {
|
||||
const name = p?.newCommits
|
||||
? chalk.bold.green(p?.packageDir.padEnd(28))
|
||||
: p?.packageDir.padEnd(28)
|
||||
const publishData = `${p?.publishedVersion} at ${p?.publishDate
|
||||
.split(':')
|
||||
.slice(0, 2)
|
||||
.join(':')
|
||||
.replace('T', ' ')}`
|
||||
const newCommits = `${p?.newCommits ? `${chalk.bold.green(p?.newCommits)} new commits` : ''}`
|
||||
|
||||
return ` ${name}${publishData} ${newCommits}`
|
||||
})
|
||||
.join('\n')}
|
||||
|
||||
`)
|
||||
const packageDetails = await getPackageDetails()
|
||||
showPackageDetails(packageDetails)
|
||||
}
|
||||
|
||||
// console.log(packageNames)
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error)
|
||||
process.exit(1)
|
||||
|
||||
@@ -4,32 +4,49 @@ import chalk from 'chalk'
|
||||
import prompts from 'prompts'
|
||||
import minimist from 'minimist'
|
||||
import chalkTemplate from 'chalk-template'
|
||||
import { PackageDetails, getPackageDetails, showPackageDetails } from './lib/getPackageDetails'
|
||||
|
||||
const execOpts: ExecSyncOptions = { stdio: 'inherit' }
|
||||
const args = minimist(process.argv.slice(2))
|
||||
|
||||
async function main() {
|
||||
const { _: packageNames, tag = 'latest', bump = 'patch' } = args
|
||||
const { tag = 'latest', bump = 'patch' } = args
|
||||
|
||||
if (packageNames.length === 0) {
|
||||
const packageDetails = await getPackageDetails()
|
||||
showPackageDetails(packageDetails)
|
||||
|
||||
const { packagesToRelease } = (await prompts({
|
||||
type: 'multiselect',
|
||||
name: 'packagesToRelease',
|
||||
message: 'Select packages to release',
|
||||
instructions: 'Space to select. Enter to submit.',
|
||||
choices: packageDetails.map((p) => {
|
||||
const title = p?.newCommits ? chalk.bold.green(p?.shortName) : p?.shortName
|
||||
return {
|
||||
title,
|
||||
value: p.shortName,
|
||||
}
|
||||
}),
|
||||
})) as { packagesToRelease: string[] }
|
||||
|
||||
if (!packagesToRelease) {
|
||||
abort()
|
||||
}
|
||||
|
||||
if (packagesToRelease.length === 0) {
|
||||
abort('Please specify a package to publish')
|
||||
}
|
||||
|
||||
if (packageNames.find((p) => p === 'payload' && packageNames.length > 1)) {
|
||||
abort('Cannot publish payload with other packages')
|
||||
if (packagesToRelease.find((p) => p === 'payload' && packagesToRelease.length > 1)) {
|
||||
abort('Cannot publish payload with other packages. Release Payload first.')
|
||||
}
|
||||
|
||||
// Get current version of each package from package.json
|
||||
const packageDetails = await Promise.all(
|
||||
packageNames.map(async (packageName) => {
|
||||
const packageDir = `packages/${packageName}`
|
||||
if (!(await fse.pathExists(packageDir))) {
|
||||
abort(`Package path ${packageDir} does not exist`)
|
||||
}
|
||||
const packageObj = await fse.readJson(`${packageDir}/package.json`)
|
||||
|
||||
return { name: packageName, version: packageObj.version, dir: packageDir }
|
||||
}),
|
||||
const packageMap = packageDetails.reduce(
|
||||
(acc, p) => {
|
||||
acc[p.shortName] = p
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, PackageDetails>,
|
||||
)
|
||||
|
||||
console.log(chalkTemplate`
|
||||
@@ -38,10 +55,15 @@ async function main() {
|
||||
{bold.yellow Bump: ${bump}}
|
||||
{bold.yellow Tag: ${tag}}
|
||||
|
||||
${packageDetails.map((p) => ` ${p.name} - current: ${p.version}`).join('\n')}
|
||||
${packagesToRelease
|
||||
.map((p) => {
|
||||
const { shortName, version } = packageMap[p]
|
||||
return ` ${shortName.padEnd(24)} ${version}`
|
||||
})
|
||||
.join('\n')}
|
||||
`)
|
||||
|
||||
const confirmPublish = await confirm(`Publish ${packageNames.length} package(s)?`)
|
||||
const confirmPublish = await confirm(`Publish ${packagesToRelease.length} package(s)?`)
|
||||
|
||||
if (!confirmPublish) {
|
||||
abort()
|
||||
@@ -49,26 +71,26 @@ ${packageDetails.map((p) => ` ${p.name} - current: ${p.version}`).join('\n')}
|
||||
|
||||
const results: { name: string; success: boolean }[] = []
|
||||
|
||||
for (const pkg of packageDetails) {
|
||||
const { dir, name } = pkg
|
||||
for (const pkg of packagesToRelease) {
|
||||
const { packagePath, shortName } = packageMap[pkg]
|
||||
|
||||
try {
|
||||
console.log(chalk.bold(`\n\nPublishing ${name}...\n\n`))
|
||||
console.log(chalk.bold(`\n\nPublishing ${shortName}...\n\n`))
|
||||
|
||||
execSync(`npm --no-git-tag-version --prefix ${dir} version ${bump}`, execOpts)
|
||||
execSync(`git add ${dir}/package.json`, execOpts)
|
||||
execSync(`npm --no-git-tag-version --prefix ${packagePath} version ${bump}`, execOpts)
|
||||
execSync(`git add ${packagePath}/package.json`, execOpts)
|
||||
|
||||
const packageObj = await fse.readJson(`${dir}/package.json`)
|
||||
const packageObj = await fse.readJson(`${packagePath}/package.json`)
|
||||
const newVersion = packageObj.version
|
||||
|
||||
const tagName = `${name}/${newVersion}`
|
||||
const tagName = `${shortName}/${newVersion}`
|
||||
execSync(`git commit -m "chore(release): ${tagName}"`, execOpts)
|
||||
execSync(`git tag -a ${tagName} -m "${tagName}"`, execOpts)
|
||||
execSync(`pnpm publish -C ${dir} --no-git-checks`, execOpts)
|
||||
results.push({ name, success: true })
|
||||
execSync(`pnpm publish -C ${packagePath} --no-git-checks`, execOpts)
|
||||
results.push({ name: shortName, success: true })
|
||||
} catch (error) {
|
||||
console.error(chalk.bold.red(`ERROR: ${error.message}`))
|
||||
results.push({ name, success: false })
|
||||
results.push({ name: shortName, success: false })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,63 +3,81 @@ import type { CollectionConfig } from '../../../../packages/payload/src/collecti
|
||||
export const relationshipFieldsSlug = 'relationship-fields'
|
||||
|
||||
const RelationshipFields: CollectionConfig = {
|
||||
slug: relationshipFieldsSlug,
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'relationship',
|
||||
type: 'relationship',
|
||||
relationTo: ['text-fields', 'array-fields'],
|
||||
required: true,
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'relationToSelf',
|
||||
type: 'relationship',
|
||||
relationTo: relationshipFieldsSlug,
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'relationToSelfSelectOnly',
|
||||
type: 'relationship',
|
||||
relationTo: relationshipFieldsSlug,
|
||||
admin: {
|
||||
allowCreate: false,
|
||||
},
|
||||
relationTo: relationshipFieldsSlug,
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'relationWithDynamicDefault',
|
||||
type: 'relationship',
|
||||
defaultValue: ({ user }) => user?.id,
|
||||
relationTo: 'users',
|
||||
defaultValue: ({ user }) => user.id,
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'relationHasManyWithDynamicDefault',
|
||||
type: 'relationship',
|
||||
defaultValue: ({ user }) =>
|
||||
user
|
||||
? {
|
||||
relationTo: 'users',
|
||||
value: user.id,
|
||||
}
|
||||
: undefined,
|
||||
relationTo: ['users'],
|
||||
defaultValue: ({ user }) => ({
|
||||
relationTo: 'users',
|
||||
value: user.id,
|
||||
}),
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'relationshipWithMin',
|
||||
type: 'relationship',
|
||||
relationTo: 'text-fields',
|
||||
hasMany: true,
|
||||
minRows: 2,
|
||||
relationTo: 'text-fields',
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'relationshipWithMax',
|
||||
type: 'relationship',
|
||||
relationTo: 'text-fields',
|
||||
hasMany: true,
|
||||
maxRows: 2,
|
||||
relationTo: 'text-fields',
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'relationshipHasMany',
|
||||
type: 'relationship',
|
||||
relationTo: 'text-fields',
|
||||
hasMany: true,
|
||||
relationTo: 'text-fields',
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'relationship',
|
||||
relationTo: 'text-fields',
|
||||
type: 'relationship',
|
||||
},
|
||||
],
|
||||
type: 'array',
|
||||
},
|
||||
],
|
||||
slug: relationshipFieldsSlug,
|
||||
}
|
||||
|
||||
export default RelationshipFields
|
||||
|
||||
@@ -44,18 +44,18 @@ export default buildConfigWithDefaults({
|
||||
collections: [
|
||||
LexicalFields,
|
||||
{
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
admin: {
|
||||
useAsTitle: 'email',
|
||||
},
|
||||
auth: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'canViewConditionalField',
|
||||
type: 'checkbox',
|
||||
defaultValue: true,
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
slug: 'users',
|
||||
},
|
||||
ArrayFields,
|
||||
BlockFields,
|
||||
@@ -81,8 +81,8 @@ export default buildConfigWithDefaults({
|
||||
],
|
||||
localization: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en', 'es'],
|
||||
fallback: true,
|
||||
locales: ['en', 'es'],
|
||||
},
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
|
||||
@@ -1093,7 +1093,7 @@ describe('fields', () => {
|
||||
.locator('#field-relationship .relationship-add-new__relation-button--text-fields')
|
||||
.click()
|
||||
|
||||
const textField = page.locator('#field-text')
|
||||
const textField = page.locator('.drawer__content #field-text')
|
||||
const textValue = 'hello'
|
||||
|
||||
await textField.fill(textValue)
|
||||
@@ -1217,7 +1217,7 @@ describe('fields', () => {
|
||||
.locator('#field-relationship .relationship-add-new__relation-button--text-fields')
|
||||
.click()
|
||||
|
||||
await page.locator('#field-text').fill('something')
|
||||
await page.locator('.drawer__content #field-text').fill('something')
|
||||
|
||||
await page.locator('[id^=doc-drawer_text-fields_1_] #action-save').click()
|
||||
await expect(page.locator('.Toastify')).toContainText('successfully')
|
||||
@@ -1290,7 +1290,7 @@ describe('fields', () => {
|
||||
await page.getByRole('button', { name: 'Edit Seeded text document' }).click()
|
||||
|
||||
// Fill 'text' field of 'Seeded text document'
|
||||
await page.locator('#field-text').fill('some updated text value')
|
||||
await page.locator('.drawer__content #field-text').fill('some updated text value')
|
||||
|
||||
// Save drawer (not parent page) with hotkey
|
||||
await saveDocHotkeyAndAssert(page)
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
} from './collections/Group'
|
||||
import { defaultNumber, numberDoc } from './collections/Number'
|
||||
import { pointDoc } from './collections/Point'
|
||||
import { relationshipFieldsSlug } from './collections/Relationship'
|
||||
import { tabsDoc } from './collections/Tabs'
|
||||
import {
|
||||
localizedTextValue,
|
||||
@@ -73,6 +74,122 @@ describe('Fields', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('relationship', () => {
|
||||
let textDoc
|
||||
let otherTextDoc
|
||||
let selfReferencing
|
||||
let parent
|
||||
let child
|
||||
let grandChild
|
||||
let relationshipInArray
|
||||
const textDocText = 'text document'
|
||||
const otherTextDocText = 'alt text'
|
||||
const relationshipText = 'relationship text'
|
||||
|
||||
beforeAll(async () => {
|
||||
textDoc = await payload.create({
|
||||
collection: 'text-fields',
|
||||
data: {
|
||||
text: textDocText,
|
||||
},
|
||||
})
|
||||
otherTextDoc = await payload.create({
|
||||
collection: 'text-fields',
|
||||
data: {
|
||||
text: otherTextDocText,
|
||||
},
|
||||
})
|
||||
const relationship = { relationTo: 'text-fields', value: textDoc.id }
|
||||
parent = await payload.create({
|
||||
collection: relationshipFieldsSlug,
|
||||
data: {
|
||||
relationship,
|
||||
text: relationshipText,
|
||||
},
|
||||
})
|
||||
|
||||
child = await payload.create({
|
||||
collection: relationshipFieldsSlug,
|
||||
data: {
|
||||
relationToSelf: parent.id,
|
||||
relationship,
|
||||
text: relationshipText,
|
||||
},
|
||||
})
|
||||
|
||||
grandChild = await payload.create({
|
||||
collection: relationshipFieldsSlug,
|
||||
data: {
|
||||
relationToSelf: child.id,
|
||||
relationship,
|
||||
text: relationshipText,
|
||||
},
|
||||
})
|
||||
|
||||
selfReferencing = await payload.create({
|
||||
collection: relationshipFieldsSlug,
|
||||
data: {
|
||||
relationship,
|
||||
text: relationshipText,
|
||||
},
|
||||
})
|
||||
|
||||
relationshipInArray = await payload.create({
|
||||
collection: relationshipFieldsSlug,
|
||||
data: {
|
||||
array: [
|
||||
{
|
||||
relationship: otherTextDoc.id,
|
||||
},
|
||||
],
|
||||
relationship,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should query parent self-reference', async () => {
|
||||
const childResult = await payload.find({
|
||||
collection: relationshipFieldsSlug,
|
||||
where: {
|
||||
relationToSelf: { equals: parent.id },
|
||||
},
|
||||
})
|
||||
|
||||
const grandChildResult = await payload.find({
|
||||
collection: relationshipFieldsSlug,
|
||||
where: {
|
||||
relationToSelf: { equals: child.id },
|
||||
},
|
||||
})
|
||||
|
||||
const anyChildren = await payload.find({
|
||||
collection: relationshipFieldsSlug,
|
||||
})
|
||||
const allChildren = await payload.find({
|
||||
collection: relationshipFieldsSlug,
|
||||
where: {
|
||||
'relationToSelf.text': { equals: relationshipText },
|
||||
},
|
||||
})
|
||||
|
||||
expect(childResult.docs[0].id).toStrictEqual(child.id)
|
||||
expect(grandChildResult.docs[0].id).toStrictEqual(grandChild.id)
|
||||
expect(allChildren.docs).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('should query relationship inside array', async () => {
|
||||
const result = await payload.find({
|
||||
collection: relationshipFieldsSlug,
|
||||
where: {
|
||||
'array.relationship.text': { equals: otherTextDocText },
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.docs).toHaveLength(1)
|
||||
expect(result.docs[0]).toMatchObject(relationshipInArray)
|
||||
})
|
||||
})
|
||||
|
||||
describe('timestamps', () => {
|
||||
const tenMinutesAgo = new Date(Date.now() - 1000 * 60 * 10)
|
||||
let doc
|
||||
@@ -796,4 +913,19 @@ describe('Fields', () => {
|
||||
expect(uploadElement.value.media.filename).toStrictEqual('payload.png')
|
||||
})
|
||||
})
|
||||
|
||||
describe('relationships', () => {
|
||||
it('should not crash if querying with empty in operator', async () => {
|
||||
const query = await payload.find({
|
||||
collection: 'relationship-fields',
|
||||
where: {
|
||||
'relationship.value': {
|
||||
in: [],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(query.docs).toBeDefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user