Skip to content

Commit

Permalink
fix(db-mongodb): joins with singular collection name (#8933)
Browse files Browse the repository at this point in the history
### What?
Properly specifies `$lookup.from` when the collection name is singular.

### Why?
MongoDB can pluralize the collection name and so can be different for
singular ones.

### How?
Uses the collection name from the driver directly
`adapter.collections[slug].collection.name` instead of just `slug`.
  • Loading branch information
r1tsuu authored Oct 30, 2024
1 parent 1231251 commit f4041ce
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 3 deletions.
4 changes: 2 additions & 2 deletions packages/db-mongodb/src/utilities/buildJoinAggregation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export const buildJoinAggregation = async ({
$lookup: {
as: `${as}.docs`,
foreignField: `${join.field.on}${code}`,
from: slug,
from: adapter.collections[slug].collection.name,
localField: versions ? 'parent' : '_id',
pipeline,
},
Expand Down Expand Up @@ -147,7 +147,7 @@ export const buildJoinAggregation = async ({
$lookup: {
as: `${as}.docs`,
foreignField: `${join.field.on}${localeSuffix}`,
from: slug,
from: adapter.collections[slug].collection.name,
localField: versions ? 'parent' : '_id',
pipeline,
},
Expand Down
7 changes: 7 additions & 0 deletions test/joins/collections/Categories.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { CollectionConfig } from 'payload'

import { categoriesSlug, postsSlug } from '../shared.js'
import { singularSlug } from './Singular.js'

export const Categories: CollectionConfig = {
slug: categoriesSlug,
Expand Down Expand Up @@ -83,5 +84,11 @@ export const Categories: CollectionConfig = {
},
],
},
{
name: 'singulars',
type: 'join',
collection: singularSlug,
on: 'category',
},
],
}
14 changes: 14 additions & 0 deletions test/joins/collections/Singular.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { CollectionConfig } from 'payload'

export const singularSlug = 'singular'

export const Singular: CollectionConfig = {
slug: singularSlug,
fields: [
{
type: 'relationship',
relationTo: 'categories',
name: 'category',
},
],
}
2 changes: 2 additions & 0 deletions test/joins/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { Categories } from './collections/Categories.js'
import { CategoriesVersions } from './collections/CategoriesVersions.js'
import { Posts } from './collections/Posts.js'
import { Singular } from './collections/Singular.js'
import { Uploads } from './collections/Uploads.js'
import { Versions } from './collections/Versions.js'
import { seed } from './seed.js'
Expand All @@ -20,6 +21,7 @@ export default buildConfigWithDefaults({
Uploads,
Versions,
CategoriesVersions,
Singular,
{
slug: localizedPostsSlug,
admin: {
Expand Down
19 changes: 18 additions & 1 deletion test/joins/int.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getFileByPath } from 'payload'
import { fileURLToPath } from 'url'

import type { NextRESTClient } from '../helpers/NextRESTClient.js'
import type { Category, Config, Post } from './payload-types.js'
import type { Category, Config, Post, Singular } from './payload-types.js'

import { devUser } from '../credentials.js'
import { idToString } from '../helpers/idToString.js'
Expand Down Expand Up @@ -642,6 +642,8 @@ describe('Joins Field', () => {
}
}
}`

expect(true).toBeTruthy()
const response = await restClient
.GRAPHQL_POST({ body: JSON.stringify({ query }) })
.then((res) => res.json())
Expand All @@ -666,6 +668,21 @@ describe('Joins Field', () => {

expect(allCategories.totalDocs).toBe(allCategoriesByIds.totalDocs)
})

it('should join with singular collection name', async () => {
const {
docs: [category],
} = await payload.find({ collection: 'categories', limit: 1, depth: 0 })

const singular = await payload.create({
collection: 'singular',
data: { category: category.id },
})

const categoryWithJoins = await payload.findByID({ collection: 'categories', id: category.id })

expect((categoryWithJoins.singulars.docs[0] as Singular).id).toBe(singular.id)
})
})

async function createPost(overrides?: Partial<Post>, locale?: Config['locale']) {
Expand Down
19 changes: 19 additions & 0 deletions test/joins/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface Config {
uploads: Upload;
versions: Version;
'categories-versions': CategoriesVersion;
singular: Singular;
'localized-posts': LocalizedPost;
'localized-categories': LocalizedCategory;
users: User;
Expand Down Expand Up @@ -133,6 +134,20 @@ export interface Category {
hasNextPage?: boolean | null;
} | null;
};
singulars?: {
docs?: (string | Singular)[] | null;
hasNextPage?: boolean | null;
} | null;
updatedAt: string;
createdAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "singular".
*/
export interface Singular {
id: string;
category?: (string | null) | Category;
updatedAt: string;
createdAt: string;
}
Expand Down Expand Up @@ -231,6 +246,10 @@ export interface PayloadLockedDocument {
relationTo: 'categories-versions';
value: string | CategoriesVersion;
} | null)
| ({
relationTo: 'singular';
value: string | Singular;
} | null)
| ({
relationTo: 'localized-posts';
value: string | LocalizedPost;
Expand Down

0 comments on commit f4041ce

Please sign in to comment.