1
- import type { FlattenedField , SanitizedConfig , Sort } from 'payload '
1
+ import type { PipelineStage } from 'mongoose '
2
2
3
+ import {
4
+ APIError ,
5
+ type FlattenedField ,
6
+ getFieldByPath ,
7
+ type SanitizedConfig ,
8
+ type Sort ,
9
+ } from 'payload'
10
+
11
+ import type { MongooseAdapter } from '../index.js'
12
+
13
+ import { getCollection } from '../utilities/getEntity.js'
3
14
import { getLocalizedSortProperty } from './getLocalizedSortProperty.js'
4
15
5
16
type Args = {
17
+ adapter : MongooseAdapter
6
18
config : SanitizedConfig
7
19
fields : FlattenedField [ ]
8
20
locale ?: string
9
21
parentIsLocalized ?: boolean
10
22
sort : Sort
23
+ sortAggregation ?: PipelineStage [ ]
11
24
timestamps : boolean
25
+ versions ?: boolean
12
26
}
13
27
14
28
export type SortArgs = {
@@ -18,13 +32,111 @@ export type SortArgs = {
18
32
19
33
export type SortDirection = 'asc' | 'desc'
20
34
35
+ const relationshipSort = ( {
36
+ adapter,
37
+ fields,
38
+ locale,
39
+ path,
40
+ sort,
41
+ sortAggregation,
42
+ sortDirection,
43
+ versions,
44
+ } : {
45
+ adapter : MongooseAdapter
46
+ fields : FlattenedField [ ]
47
+ locale ?: string
48
+ path : string
49
+ sort : Record < string , string >
50
+ sortAggregation : PipelineStage [ ]
51
+ sortDirection : SortDirection
52
+ versions ?: boolean
53
+ } ) => {
54
+ let currentFields = fields
55
+ const segments = path . split ( '.' )
56
+ if ( segments . length < 2 ) {
57
+ return false
58
+ }
59
+
60
+ for ( const [ i , segment ] of segments . entries ( ) ) {
61
+ if ( versions && i === 0 && segment === 'version' ) {
62
+ segments . shift ( )
63
+ continue
64
+ }
65
+
66
+ const field = currentFields . find ( ( each ) => each . name === segment )
67
+
68
+ if ( ! field ) {
69
+ return false
70
+ }
71
+
72
+ if ( 'fields' in field ) {
73
+ currentFields = field . flattenedFields
74
+ } else if (
75
+ ( field . type === 'relationship' || field . type === 'upload' ) &&
76
+ i !== segments . length - 1
77
+ ) {
78
+ const relationshipPath = segments . slice ( 0 , i + 1 ) . join ( '.' )
79
+ let sortFieldPath = segments . slice ( i + 1 , segments . length ) . join ( '.' )
80
+ if ( Array . isArray ( field . relationTo ) ) {
81
+ throw new APIError ( 'Not supported' )
82
+ }
83
+
84
+ const foreignCollection = getCollection ( { adapter, collectionSlug : field . relationTo } )
85
+
86
+ const foreignFieldPath = getFieldByPath ( {
87
+ fields : foreignCollection . collectionConfig . flattenedFields ,
88
+ path : sortFieldPath ,
89
+ } )
90
+
91
+ if ( ! foreignFieldPath ) {
92
+ return false
93
+ }
94
+
95
+ if ( foreignFieldPath . pathHasLocalized && locale ) {
96
+ sortFieldPath = foreignFieldPath . localizedPath . replace ( '<locale>' , locale )
97
+ }
98
+
99
+ if (
100
+ ! sortAggregation . some ( ( each ) => {
101
+ return '$lookup' in each && each . $lookup . as === `__${ path } `
102
+ } )
103
+ ) {
104
+ sortAggregation . push ( {
105
+ $lookup : {
106
+ as : `__${ path } ` ,
107
+ foreignField : '_id' ,
108
+ from : foreignCollection . Model . collection . name ,
109
+ localField : relationshipPath ,
110
+ pipeline : [
111
+ {
112
+ $project : {
113
+ [ sortFieldPath ] : true ,
114
+ } ,
115
+ } ,
116
+ ] ,
117
+ } ,
118
+ } )
119
+
120
+ sort [ `__${ path } .${ sortFieldPath } ` ] = sortDirection
121
+
122
+ return true
123
+ }
124
+ }
125
+ }
126
+
127
+ return false
128
+ }
129
+
21
130
export const buildSortParam = ( {
131
+ adapter,
22
132
config,
23
133
fields,
24
134
locale,
25
135
parentIsLocalized = false ,
26
136
sort,
137
+ sortAggregation,
27
138
timestamps,
139
+ versions,
28
140
} : Args ) : Record < string , string > => {
29
141
if ( ! sort ) {
30
142
if ( timestamps ) {
@@ -52,6 +164,23 @@ export const buildSortParam = ({
52
164
acc [ '_id' ] = sortDirection
53
165
return acc
54
166
}
167
+
168
+ if (
169
+ sortAggregation &&
170
+ relationshipSort ( {
171
+ adapter,
172
+ fields,
173
+ locale,
174
+ path : sortProperty ,
175
+ sort : acc ,
176
+ sortAggregation,
177
+ sortDirection,
178
+ versions,
179
+ } )
180
+ ) {
181
+ return acc
182
+ }
183
+
55
184
const localizedProperty = getLocalizedSortProperty ( {
56
185
config,
57
186
fields,
@@ -60,6 +189,7 @@ export const buildSortParam = ({
60
189
segments : sortProperty . split ( '.' ) ,
61
190
} )
62
191
acc [ localizedProperty ] = sortDirection
192
+
63
193
return acc
64
194
} , { } )
65
195
0 commit comments