From 09974fa68677586c727943cc234311f87bf6da75 Mon Sep 17 00:00:00 2001 From: Jarrod Flesch Date: Mon, 8 May 2023 12:20:06 -0400 Subject: [PATCH] fix: ensures nested querying works when querying across collections --- src/mongoose/buildQuery.ts | 1 - test/relationships/config.ts | 60 ++++++++++++++++----- test/relationships/int.spec.ts | 57 ++++++++++++++++---- test/relationships/payload-types.ts | 81 ++++++++++++++++------------- 4 files changed, 139 insertions(+), 60 deletions(-) diff --git a/src/mongoose/buildQuery.ts b/src/mongoose/buildQuery.ts index 928b8739c..49b4a4bcc 100644 --- a/src/mongoose/buildQuery.ts +++ b/src/mongoose/buildQuery.ts @@ -502,7 +502,6 @@ export class ParamParser { } } else { lastIncompletePath.complete = true; - lastIncompletePath.collectionSlug = matchedField.relationTo; lastIncompletePath.path = currentPath; const nestedPathToQuery = pathSegments.slice(nextSegmentIsLocale ? i + 2 : i + 1).join('.'); diff --git a/test/relationships/config.ts b/test/relationships/config.ts index ae304b43e..91869dba9 100644 --- a/test/relationships/config.ts +++ b/test/relationships/config.ts @@ -1,8 +1,6 @@ import type { CollectionConfig } from '../../src/collections/config/types'; import { devUser } from '../credentials'; import { buildConfig } from '../buildConfig'; -import type { CustomIdNumberRelation, CustomIdRelation, Post, Relation } from './payload-types'; -import { ChainedRelation } from './payload-types'; const openAccess = { create: () => true, @@ -157,6 +155,43 @@ export default buildConfig({ }, ], }, + { + slug: 'screenings', + fields: [ + { + name: 'name', + type: 'text', + }, + { + name: 'movie', + type: 'relationship', + relationTo: 'movies', + }, + ], + }, + { + slug: 'movies', + fields: [ + { + name: 'name', + type: 'text', + }, + { + name: 'director', + type: 'relationship', + relationTo: 'directors', + }, + ], + }, + { + slug: 'directors', + fields: [ + { + name: 'name', + type: 'text', + }, + ], + }, ], onInit: async (payload) => { await payload.create({ @@ -167,35 +202,35 @@ export default buildConfig({ }, }); - const rel1 = await payload.create({ + const rel1 = await payload.create({ collection: relationSlug, data: { name: 'name', }, }); - const filteredRelation = await payload.create({ + const filteredRelation = await payload.create({ collection: relationSlug, data: { name: 'filtered', }, }); - const defaultAccessRelation = await payload.create({ + const defaultAccessRelation = await payload.create({ collection: defaultAccessRelSlug, data: { name: 'name', }, }); - const chained3 = await payload.create({ + const chained3 = await payload.create({ collection: chainedRelSlug, data: { name: 'chain3', }, }); - const chained2 = await payload.create({ + const chained2 = await payload.create({ collection: chainedRelSlug, data: { name: 'chain2', @@ -203,7 +238,7 @@ export default buildConfig({ }, }); - const chained = await payload.create({ + const chained = await payload.create({ collection: chainedRelSlug, data: { name: 'chain1', @@ -211,7 +246,7 @@ export default buildConfig({ }, }); - await payload.update({ + await payload.update({ collection: chainedRelSlug, id: chained3.id, data: { @@ -220,7 +255,7 @@ export default buildConfig({ }, }); - const customIdRelation = await payload.create({ + const customIdRelation = await payload.create({ collection: customIdSlug, data: { id: 'custommmm', @@ -228,7 +263,7 @@ export default buildConfig({ }, }); - const customIdNumberRelation = await payload.create({ + const customIdNumberRelation = await payload.create({ collection: customIdNumberSlug, data: { id: 908234892340, @@ -236,9 +271,8 @@ export default buildConfig({ }, }); - // Relationship - await payload.create({ + await payload.create({ collection: slug, data: { title: 'with relationship', diff --git a/test/relationships/int.spec.ts b/test/relationships/int.spec.ts index 82864773e..c55d5694d 100644 --- a/test/relationships/int.spec.ts +++ b/test/relationships/int.spec.ts @@ -4,7 +4,7 @@ import { initPayloadTest } from '../helpers/configHelpers'; import config, { customIdSlug, chainedRelSlug, defaultAccessRelSlug, slug, relationSlug, customIdNumberSlug } from './config'; import payload from '../../src'; import { RESTClient } from '../helpers/rest'; -import type { ChainedRelation, CustomIdNumberRelation, CustomIdRelation, Post, Relation } from './payload-types'; +import type { ChainedRelation, CustomIdNumberRelation, CustomIdRelation, Director, Post, Relation } from './payload-types'; import { mapAsync } from '../../src/utilities/mapAsync'; let client: RESTClient; @@ -239,8 +239,6 @@ describe('Relationships', () => { thirdLevelID = thirdLevelDoc.id; - console.log({ thirdLevelID }); - const secondLevelDoc = await payload.create({ collection: 'chained-relation', data: { @@ -251,8 +249,6 @@ describe('Relationships', () => { secondLevelID = secondLevelDoc.id; - console.log({ secondLevelID }); - const firstLevelDoc = await payload.create({ collection: 'chained-relation', data: { @@ -262,8 +258,6 @@ describe('Relationships', () => { }); firstLevelID = firstLevelDoc.id; - - console.log({ firstLevelID }); }); it('should allow querying one level deep', async () => { @@ -306,15 +300,60 @@ describe('Relationships', () => { expect(query.docs[0].id).toStrictEqual(firstLevelID); }); }); + + describe('Nested Querying Separate Collections', () => { + let director: Director; + + beforeAll(async () => { + // 1. create a director + director = await payload.create({ + collection: 'directors', + data: { + name: 'test', + }, + }); + + // 2. create a movie + const movie = await payload.create({ + collection: 'movies', + data: { + name: 'movie1', + director: director.id, + }, + }); + + // 3. create a screening + await payload.create({ + collection: 'screenings', + data: { + movie: movie.id, + name: 'screening1', + }, + }); + }); + + it('should allow querying two levels deep', async () => { + const query = await payload.find({ + collection: 'screenings', + where: { + 'movie.director.name': { + equals: director.name, + }, + }, + }); + + expect(query.docs).toHaveLength(1); + }); + }); }); }); async function createPost(overrides?: Partial) { - return payload.create({ collection: slug, data: { title: 'title', ...overrides } }); + return payload.create({ collection: slug, data: { title: 'title', ...overrides } }); } async function clearDocs(): Promise { - const allDocs = await payload.find({ collection: slug, limit: 100 }); + const allDocs = await payload.find({ collection: slug, limit: 100 }); const ids = allDocs.docs.map((doc) => doc.id); await mapAsync(ids, async (id) => { await payload.delete({ collection: slug, id }); diff --git a/test/relationships/payload-types.ts b/test/relationships/payload-types.ts index 629a89fe5..7ae6fd8c6 100644 --- a/test/relationships/payload-types.ts +++ b/test/relationships/payload-types.ts @@ -5,11 +5,21 @@ * and re-run `payload generate:types` to regenerate this file. */ -export interface Config {} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "posts". - */ +export interface Config { + collections: { + posts: Post; + relation: Relation; + 'strict-access': StrictAccess; + 'chained-relation': ChainedRelation; + 'custom-id-relation': CustomIdRelation; + 'custom-id-number-relation': CustomIdNumberRelation; + screenings: Screening; + movies: Movie; + directors: Director; + users: User; + }; + globals: {}; +} export interface Post { id: string; title?: string; @@ -22,73 +32,70 @@ export interface Post { customIdRelation?: string | CustomIdRelation; customIdNumberRelation?: number | CustomIdNumberRelation; filteredRelation?: string | Relation; - createdAt: string; updatedAt: string; + createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "relation". - */ export interface Relation { id: string; name?: string; disableRelation: boolean; - createdAt: string; updatedAt: string; + createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "strict-access". - */ export interface StrictAccess { id: string; name?: string; disableRelation: boolean; - createdAt: string; updatedAt: string; + createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "chained-relation". - */ export interface ChainedRelation { id: string; name?: string; relation?: string | ChainedRelation; - createdAt: string; updatedAt: string; + createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "custom-id-relation". - */ export interface CustomIdRelation { id: string; name?: string; - createdAt: string; updatedAt: string; + createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "custom-id-number-relation". - */ export interface CustomIdNumberRelation { id: number; name?: string; - createdAt: string; updatedAt: string; + createdAt: string; +} +export interface Screening { + id: string; + name?: string; + movie?: string | Movie; + updatedAt: string; + createdAt: string; +} +export interface Movie { + id: string; + name?: string; + director?: string | Director; + updatedAt: string; + createdAt: string; +} +export interface Director { + id: string; + name?: string; + updatedAt: string; + createdAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "users". - */ export interface User { id: string; + updatedAt: string; + createdAt: string; email?: string; resetPasswordToken?: string; resetPasswordExpiration?: string; loginAttempts?: number; lockUntil?: string; - createdAt: string; - updatedAt: string; + password?: string; }