fix(db-postgres): joins to self collection (#10182)
### What?
With Postgres, before join to self like:
```ts
import type { CollectionConfig } from 'payload'
export const SelfJoins: CollectionConfig = {
slug: 'self-joins',
fields: [
{
name: 'rel',
type: 'relationship',
relationTo: 'self-joins',
},
{
name: 'joins',
type: 'join',
on: 'rel',
collection: 'self-joins',
},
],
}
```
wasn't possible, even though it's a valid usage.
### How?
Now, to differentiate parent `self_joins` and children `self_joins` we
do additional alias for the nested select -
`"4d3cf2b6_1adf_46a8_b6d2_3e1c3809d737"`:
```sql
select
"id",
"rel_id",
"updated_at",
"created_at",
(
select
coalesce(
json_agg(
json_build_object('id', "joins_alias".id)
),
'[]' :: json
)
from
(
select
"created_at",
"rel_id",
"id"
from
"self_joins" "4d3cf2b6_1adf_46a8_b6d2_3e1c3809d737"
where
"4d3cf2b6_1adf_46a8_b6d2_3e1c3809d737"."rel_id" = "self_joins"."id"
order by
"4d3cf2b6_1adf_46a8_b6d2_3e1c3809d737"."created_at" desc
limit
$1
) "joins_alias"
) as "joins_alias"
from
"self_joins"
where
"self_joins"."id" = $2
order by
"self_joins"."created_at" desc
limit
$3
```
Fixes https://github.com/payloadcms/payload/issues/10144
-->
This commit is contained in:
18
test/joins/collections/SelfJoins.ts
Normal file
18
test/joins/collections/SelfJoins.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const SelfJoins: CollectionConfig = {
|
||||
slug: 'self-joins',
|
||||
fields: [
|
||||
{
|
||||
name: 'rel',
|
||||
type: 'relationship',
|
||||
relationTo: 'self-joins',
|
||||
},
|
||||
{
|
||||
name: 'joins',
|
||||
type: 'join',
|
||||
on: 'rel',
|
||||
collection: 'self-joins',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { Categories } from './collections/Categories.js'
|
||||
import { CategoriesVersions } from './collections/CategoriesVersions.js'
|
||||
import { HiddenPosts } from './collections/HiddenPosts.js'
|
||||
import { Posts } from './collections/Posts.js'
|
||||
import { SelfJoins } from './collections/SelfJoins.js'
|
||||
import { Singular } from './collections/Singular.js'
|
||||
import { Uploads } from './collections/Uploads.js'
|
||||
import { Versions } from './collections/Versions.js'
|
||||
@@ -37,6 +38,7 @@ export default buildConfigWithDefaults({
|
||||
Versions,
|
||||
CategoriesVersions,
|
||||
Singular,
|
||||
SelfJoins,
|
||||
{
|
||||
slug: localizedPostsSlug,
|
||||
admin: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Payload } from 'payload'
|
||||
import type { Payload, TypeWithID } from 'payload'
|
||||
|
||||
import path from 'path'
|
||||
import { getFileByPath } from 'payload'
|
||||
@@ -975,6 +975,15 @@ describe('Joins Field', () => {
|
||||
|
||||
await payload.delete({ collection: categoriesSlug, where: { name: { equals: 'totalDocs' } } })
|
||||
})
|
||||
|
||||
it('should self join', async () => {
|
||||
const doc_1 = await payload.create({ collection: 'self-joins', data: {} })
|
||||
const doc_2 = await payload.create({ collection: 'self-joins', data: { rel: doc_1 }, depth: 0 })
|
||||
|
||||
const data = await payload.findByID({ collection: 'self-joins', id: doc_1.id, depth: 1 })
|
||||
|
||||
expect((data.joins.docs[0] as TypeWithID).id).toBe(doc_2.id)
|
||||
})
|
||||
})
|
||||
|
||||
async function createPost(overrides?: Partial<Post>, locale?: Config['locale']) {
|
||||
|
||||
@@ -18,6 +18,7 @@ export interface Config {
|
||||
versions: Version;
|
||||
'categories-versions': CategoriesVersion;
|
||||
singular: Singular;
|
||||
'self-joins': SelfJoin;
|
||||
'localized-posts': LocalizedPost;
|
||||
'localized-categories': LocalizedCategory;
|
||||
'restricted-categories': RestrictedCategory;
|
||||
@@ -53,6 +54,9 @@ export interface Config {
|
||||
relatedVersions: 'versions';
|
||||
relatedVersionsMany: 'versions';
|
||||
};
|
||||
'self-joins': {
|
||||
joins: 'self-joins';
|
||||
};
|
||||
'localized-categories': {
|
||||
relatedPosts: 'localized-posts';
|
||||
};
|
||||
@@ -71,6 +75,7 @@ export interface Config {
|
||||
versions: VersionsSelect<false> | VersionsSelect<true>;
|
||||
'categories-versions': CategoriesVersionsSelect<false> | CategoriesVersionsSelect<true>;
|
||||
singular: SingularSelect<false> | SingularSelect<true>;
|
||||
'self-joins': SelfJoinsSelect<false> | SelfJoinsSelect<true>;
|
||||
'localized-posts': LocalizedPostsSelect<false> | LocalizedPostsSelect<true>;
|
||||
'localized-categories': LocalizedCategoriesSelect<false> | LocalizedCategoriesSelect<true>;
|
||||
'restricted-categories': RestrictedCategoriesSelect<false> | RestrictedCategoriesSelect<true>;
|
||||
@@ -355,6 +360,20 @@ export interface CategoriesVersion {
|
||||
createdAt: string;
|
||||
_status?: ('draft' | 'published') | null;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "self-joins".
|
||||
*/
|
||||
export interface SelfJoin {
|
||||
id: string;
|
||||
rel?: (string | null) | SelfJoin;
|
||||
joins?: {
|
||||
docs?: (string | SelfJoin)[] | null;
|
||||
hasNextPage?: boolean | null;
|
||||
} | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "localized-posts".
|
||||
@@ -467,6 +486,10 @@ export interface PayloadLockedDocument {
|
||||
relationTo: 'singular';
|
||||
value: string | Singular;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'self-joins';
|
||||
value: string | SelfJoin;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'localized-posts';
|
||||
value: string | LocalizedPost;
|
||||
@@ -666,6 +689,16 @@ export interface SingularSelect<T extends boolean = true> {
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "self-joins_select".
|
||||
*/
|
||||
export interface SelfJoinsSelect<T extends boolean = true> {
|
||||
rel?: T;
|
||||
joins?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "localized-posts_select".
|
||||
|
||||
Reference in New Issue
Block a user