Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 152 additions & 22 deletions packages/drizzle/src/find/traverseFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
getFieldByPath,
getQueryDraftsSort,
type JoinQuery,
type RelationshipField,
type SelectMode,
type SelectType,
type Where,
Expand Down Expand Up @@ -134,20 +135,6 @@ export const traverseFields = ({
parentIsLocalized,
})

// handle simple relationship
if (
depth > 0 &&
(field.type === 'upload' || field.type === 'relationship') &&
!field.hasMany &&
typeof field.relationTo === 'string'
) {
if (isFieldLocalized) {
_locales.with[`${path}${field.name}`] = true
} else {
currentArgs.with[`${path}${field.name}`] = true
}
}

switch (field.type) {
case 'array': {
const arraySelect = selectAllOnCurrentLevel ? true : select?.[field.name]
Expand Down Expand Up @@ -809,6 +796,135 @@ export const traverseFields = ({
break
}

case 'relationship':
case 'upload': {
if (select && !selectAllOnCurrentLevel) {
if (
(selectMode === 'include' && !select[field.name]) ||
(selectMode === 'exclude' && select[field.name] === false)
) {
break
}
}

const fieldPath = `${path}${field.name}`
const isRelatedToManyCollections = Array.isArray(field.relationTo)
const relationshipSelect = isRelatedToManyCollections
? (select?.[field.name] as SelectType)?.value
: select?.[field.name]

if (depth > 0 && !field.hasMany && !isRelatedToManyCollections) {
if ((isFieldLocalized || parentIsLocalized) && _locales) {
_locales.with = _locales.with || {}
_locales.with[fieldPath] = true
} else {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use localization in my setup yet, so I'm not sure how correct this is.
I wrote it based on samples from other places in the file

currentArgs.with = currentArgs.with || {}
currentArgs.with[fieldPath] = true
}
}

if (field.inline) {
;(Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo]).forEach(
(relationTo) => {
const relationship = adapter.payload.collections[relationTo].config
const relationshipTableName = adapter.tableNameMap.get(toSnakeCase(relationTo))
const relationshipTableNameWithLocales = `${relationshipTableName}${adapter.localesSuffix}`
const selectAll = selectAllOnCurrentLevel || relationshipSelect === true

const withRelationship: Result = {
columns:
typeof relationshipSelect !== 'object'
? undefined
: Object.keys(relationshipSelect)
.filter((key) =>
selectMode === 'include'
? Boolean(relationshipSelect[key])
: relationshipSelect[key] === false,
)
.reduce((acc, key) => {
acc[key] = selectMode === 'include'
return acc
}, {}),
extras: {},
with: {},
}

if (field.hasMany || isRelatedToManyCollections) {
const _rels = adapter.relationshipsSuffix
const _with: Result = (currentArgs.with = currentArgs.with || {})
const _withRels: Result = (_with[_rels] =
typeof _with[_rels] === 'object' ? _with[_rels] : {})

_withRels.with = _withRels.with || {}
_withRels.with[`${relationTo}ID`] = selectAll ? true : withRelationship
} else {
const _with: Result = (currentArgs.with = currentArgs.with || {})

_with[fieldPath] = selectAll ? true : withRelationship
}

if (adapter.tables[relationshipTableNameWithLocales]) {
withRelationship.with = withRelationship.with || {}
withRelationship.with._locales = {
columns:
typeof relationshipSelect === 'object'
? { _locale: true }
: { id: false, _parentID: false },
with: {},
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use localization in my setup yet, so I'm not sure how correct this is.
I wrote it based on samples from other places in the file


// Needs a valid select to prevent an infinite loop in the case of inlined two-way relationships
if (typeof relationshipSelect === 'object') {
traverseFields({
_locales: withRelationship.with._locales,
adapter,
currentArgs: withRelationship,
currentTableName: relationshipTableName,
depth,
draftsEnabled,
fields: relationship.flattenedFields,
joinQuery: false,
locale,
parentIsLocalized: parentIsLocalized || field.localized,
path: '',
select: relationshipSelect,
selectAllOnCurrentLevel: selectAll,
selectMode,
tablePath: '',
topLevelArgs,
topLevelTableName,
withTabledFields,
})

if (
withRelationship.with._locales &&
Object.keys(withRelationship.with._locales.columns).length === 1
) {
delete withRelationship.with._locales
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use localization in my setup yet, so I'm not sure how correct this is.
I wrote it based on samples from other places in the file

}
},
)
} else {
if (relationshipSelect) {
if ((isFieldLocalized || parentIsLocalized) && _locales) {
_locales.columns = _locales.columns || ({} as Result['columns'])
_locales.columns[fieldPath] = true
} else if (adapter.tables[currentTableName]?.[fieldPath]) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use localization in my setup yet, so I'm not sure how correct this is.
I wrote it based on samples from other places in the file

currentArgs.columns = currentArgs.columns || {}
currentArgs.columns[fieldPath] = true
}

if (field.hasMany || isRelatedToManyCollections) {
withTabledFields.rels = true
}
}
}

break
}

case 'select': {
if (select && !selectAllOnCurrentLevel) {
if (
Expand Down Expand Up @@ -864,14 +980,6 @@ export const traverseFields = ({
currentArgs.columns[fieldPath] = true
}

if (
!withTabledFields.rels &&
(field.type === 'relationship' || field.type === 'upload') &&
(field.hasMany || Array.isArray(field.relationTo))
) {
withTabledFields.rels = true
}

if (!withTabledFields.numbers && field.type === 'number' && field.hasMany) {
withTabledFields.numbers = true
}
Expand All @@ -886,5 +994,27 @@ export const traverseFields = ({
}
})

// Don't select relationships that weren't selected
if (select && selectMode === 'include' && currentArgs.with?.[adapter.relationshipsSuffix]) {
const relationships = fields.filter(
(field) =>
field.type === 'relationship' && (field.hasMany || Array.isArray(field.relationTo)),
) as RelationshipField[]

relationships.forEach((field) =>
(Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo]).forEach(
(relationTo) => {
const _with = currentArgs.with
const _withRels = _with[adapter.relationshipsSuffix] as Result

if (_withRels.with?.[`${relationTo}ID`] === undefined) {
_withRels.columns = _withRels.columns || {}
_withRels.columns[`${relationTo}ID`] = false
}
},
),
)
}

return topLevelArgs
}
2 changes: 1 addition & 1 deletion packages/drizzle/src/transform/read/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createBlocksMap } from '../../utilities/createBlocksMap.js'
import { createPathMap } from '../../utilities/createRelationshipMap.js'
import { traverseFields } from './traverseFields.js'

type TransformArgs = {
export type TransformArgs = {
adapter: DrizzleAdapter
config: SanitizedConfig
data: Record<string, unknown>
Expand Down
66 changes: 62 additions & 4 deletions packages/drizzle/src/transform/read/relationship.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
import type { RelationshipField, UploadField } from 'payload'

import toSnakeCase from 'to-snake-case'

import type { TransformArgs } from './index.js'

import { transform } from './index.js'

type Args = {
field: RelationshipField | UploadField
locale?: string
ref: Record<string, unknown>
relations: Record<string, unknown>[]
withinArrayOrBlockLocale?: string
}
} & TransformArgsRecurve

type ArgsRecursive = {
data: unknown
relationTo: string
} & TransformArgsRecurve

type TransformArgsRecurve = Pick<
TransformArgs,
'adapter' | 'config' | 'joinQuery' | 'parentIsLocalized'
>

export const transformRelationship = ({
field,
locale,
ref,
relations,
withinArrayOrBlockLocale,
...args
}: Args) => {
let result: unknown

Expand All @@ -36,7 +53,11 @@ export const transformRelationship = ({

result = {
relationTo,
value: matchedRelation[1],
value: transformRecursive({
...args,
data: matchedRelation[1],
relationTo,
}),
}
}
}
Expand All @@ -54,9 +75,16 @@ export const transformRelationship = ({
// Handle hasMany
if (!Array.isArray(field.relationTo)) {
const relatedData = relation[`${field.relationTo}ID`]
const relationTo = field.relationTo

if (relatedData && matchedLocale) {
transformedRelations.push(relatedData)
transformedRelations.push(
transformRecursive({
...args,
data: relatedData,
relationTo,
}),
)
}
} else {
// Handle hasMany Poly
Expand All @@ -72,7 +100,11 @@ export const transformRelationship = ({

transformedRelations.push({
relationTo,
value: matchedRelation[1],
value: transformRecursive({
...args,
data: matchedRelation[1],
relationTo,
}),
})
}
}
Expand All @@ -87,3 +119,29 @@ export const transformRelationship = ({
ref[field.name] = result
}
}

const transformRecursive = ({
adapter,
config,
data,
joinQuery,
parentIsLocalized,
relationTo,
}: ArgsRecursive) => {
if (typeof data !== 'object') {
return data
}

const relationshipConfig = adapter.payload.collections[relationTo].config
const relationshipTableName = toSnakeCase(relationTo)

return transform({
adapter,
config,
data: data as Record<string, unknown>,
fields: relationshipConfig.flattenedFields,
joinQuery,
parentIsLocalized,
tableName: relationshipTableName,
})
}
9 changes: 9 additions & 0 deletions packages/drizzle/src/transform/read/traverseFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,15 +409,23 @@ export const traverseFields = <T extends Record<string, unknown>>({

Object.entries(relationsByLocale).forEach(([locale, relations]) => {
transformRelationship({
adapter,
config,
field,
joinQuery,
locale,
parentIsLocalized,
ref: result,
relations,
})
})
} else {
transformRelationship({
adapter,
config,
field,
joinQuery,
parentIsLocalized,
ref: result,
relations: relationPathMatch,
withinArrayOrBlockLocale,
Expand Down Expand Up @@ -690,6 +698,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
if (
val &&
typeof field.relationTo === 'string' &&
!field.inline &&
adapter.payload.collections[field.relationTo].customIDType === 'number'
) {
val = Number(val)
Expand Down
Loading
Loading