1
- import type { DBQueryConfig } from 'drizzle-orm'
1
+ import type { LibSQLDatabase } from 'drizzle-orm/libsql '
2
2
import type { Field , JoinQuery } from 'payload'
3
3
4
+ import { and , type DBQueryConfig , eq , sql } from 'drizzle-orm'
4
5
import { fieldAffectsData , fieldIsVirtual , tabHasName } from 'payload/shared'
5
6
import toSnakeCase from 'to-snake-case'
6
7
7
- import type { BuildQueryJoinAliases , DrizzleAdapter } from '../types.js'
8
+ import type { BuildQueryJoinAliases , ChainedMethods , DrizzleAdapter } from '../types.js'
8
9
import type { Result } from './buildFindManyArgs.js'
9
10
10
- import { buildOrderBy } from '../queries/buildOrderBy.js'
11
11
import buildQuery from '../queries/buildQuery.js'
12
+ import { chainMethods } from './chainMethods.js'
12
13
13
14
type TraverseFieldArgs = {
14
15
_locales : Result
@@ -241,24 +242,93 @@ export const traverseFields = ({
241
242
// get an additional document and slice it later to determine if there is a next page
242
243
limit += 1
243
244
}
245
+
244
246
const fields = adapter . payload . collections [ field . collection ] . config . fields
247
+ const joinCollectionTableName = adapter . tableNameMap . get ( toSnakeCase ( field . collection ) )
245
248
const joinTableName = `${ adapter . tableNameMap . get ( toSnakeCase ( field . collection ) ) } ${
246
249
field . localized && adapter . payload . config . localization ? adapter . localesSuffix : ''
247
250
} `
251
+
252
+ if ( ! adapter . tables [ joinTableName ] [ field . on ] ) {
253
+ const db = adapter . drizzle as LibSQLDatabase
254
+ const joinTable = `${ joinTableName } ${ adapter . relationshipsSuffix } `
255
+
256
+ const joins : BuildQueryJoinAliases = [
257
+ {
258
+ type : 'innerJoin' ,
259
+ condition : and (
260
+ eq ( adapter . tables [ joinTable ] . parent , adapter . tables [ joinTableName ] . id ) ,
261
+ eq (
262
+ sql . raw ( `"${ joinTable } "."${ topLevelTableName } _id"` ) ,
263
+ adapter . tables [ currentTableName ] . id ,
264
+ ) ,
265
+ ) ,
266
+ table : adapter . tables [ joinTable ] ,
267
+ } ,
268
+ ]
269
+
270
+ const { orderBy, where : subQueryWhere } = buildQuery ( {
271
+ adapter,
272
+ fields,
273
+ joins,
274
+ locale,
275
+ sort,
276
+ tableName : joinCollectionTableName ,
277
+ where : { } ,
278
+ } )
279
+
280
+ const chainedMethods : ChainedMethods = [ ]
281
+
282
+ joins . forEach ( ( { type, condition, table } ) => {
283
+ chainedMethods . push ( {
284
+ args : [ table , condition ] ,
285
+ method : type ?? 'leftJoin' ,
286
+ } )
287
+ } )
288
+
289
+ const subQuery = chainMethods ( {
290
+ methods : chainedMethods ,
291
+ query : db
292
+ . select ( {
293
+ id : adapter . tables [ joinTableName ] . id ,
294
+ } )
295
+ . from ( adapter . tables [ joinTableName ] )
296
+ . where ( subQueryWhere )
297
+ . orderBy ( orderBy . order ( orderBy . column ) )
298
+ . limit ( 11 ) ,
299
+ } )
300
+
301
+ const columnName = `${ path . replaceAll ( '.' , '_' ) } ${ field . name } `
302
+
303
+ const extras = field . localized ? _locales . extras : currentArgs . extras
304
+
305
+ if ( adapter . name === 'sqlite' ) {
306
+ extras [ columnName ] = sql `
307
+ COALESCE((
308
+ SELECT json_group_array("id")
309
+ FROM (
310
+ ${ subQuery }
311
+ ) AS ${ sql . raw ( `${ columnName } _sub` ) }
312
+ ), '[]')
313
+ ` . as ( columnName )
314
+ } else {
315
+ extras [ columnName ] = sql `
316
+ COALESCE((
317
+ SELECT json_agg("id")
318
+ FROM (
319
+ ${ subQuery }
320
+ ) AS ${ sql . raw ( `${ columnName } _sub` ) }
321
+ ), '[]'::json)
322
+ ` . as ( columnName )
323
+ }
324
+
325
+ break
326
+ }
327
+
248
328
const selectFields = { }
249
329
250
- const orderBy = buildOrderBy ( {
251
- adapter,
252
- fields,
253
- joins : [ ] ,
254
- locale,
255
- selectFields,
256
- sort,
257
- tableName : joinTableName ,
258
- } )
259
330
const withJoin : DBQueryConfig < 'many' , true , any , any > = {
260
331
columns : selectFields ,
261
- orderBy : ( ) => [ orderBy . order ( orderBy . column ) ] ,
262
332
}
263
333
if ( limit ) {
264
334
withJoin . limit = limit
@@ -269,20 +339,21 @@ export const traverseFields = ({
269
339
withJoin . columns . _parentID = true
270
340
} else {
271
341
withJoin . columns . id = true
342
+ withJoin . columns . parent = true
272
343
}
273
-
274
- if ( where ) {
275
- const { where : joinWhere } = buildQuery ( {
276
- adapter,
277
- fields,
278
- joins,
279
- locale,
280
- sort,
281
- tableName : joinTableName ,
282
- where,
283
- } )
344
+ const { orderBy, where : joinWhere } = buildQuery ( {
345
+ adapter,
346
+ fields,
347
+ joins,
348
+ locale,
349
+ sort,
350
+ tableName : joinTableName ,
351
+ where,
352
+ } )
353
+ if ( joinWhere ) {
284
354
withJoin . where = ( ) => joinWhere
285
355
}
356
+ withJoin . orderBy = orderBy . order ( orderBy . column )
286
357
currentArgs . with [ `${ path . replaceAll ( '.' , '_' ) } ${ field . name } ` ] = withJoin
287
358
break
288
359
}
0 commit comments