fix: ensures nested querying works when querying across collections

This commit is contained in:
Jarrod Flesch
2023-05-08 12:20:06 -04:00
parent 2c36468431
commit 09974fa686
4 changed files with 139 additions and 60 deletions

View File

@@ -502,7 +502,6 @@ export class ParamParser {
} }
} else { } else {
lastIncompletePath.complete = true; lastIncompletePath.complete = true;
lastIncompletePath.collectionSlug = matchedField.relationTo;
lastIncompletePath.path = currentPath; lastIncompletePath.path = currentPath;
const nestedPathToQuery = pathSegments.slice(nextSegmentIsLocale ? i + 2 : i + 1).join('.'); const nestedPathToQuery = pathSegments.slice(nextSegmentIsLocale ? i + 2 : i + 1).join('.');

View File

@@ -1,8 +1,6 @@
import type { CollectionConfig } from '../../src/collections/config/types'; import type { CollectionConfig } from '../../src/collections/config/types';
import { devUser } from '../credentials'; import { devUser } from '../credentials';
import { buildConfig } from '../buildConfig'; import { buildConfig } from '../buildConfig';
import type { CustomIdNumberRelation, CustomIdRelation, Post, Relation } from './payload-types';
import { ChainedRelation } from './payload-types';
const openAccess = { const openAccess = {
create: () => true, 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) => { onInit: async (payload) => {
await payload.create({ await payload.create({
@@ -167,35 +202,35 @@ export default buildConfig({
}, },
}); });
const rel1 = await payload.create<Relation>({ const rel1 = await payload.create({
collection: relationSlug, collection: relationSlug,
data: { data: {
name: 'name', name: 'name',
}, },
}); });
const filteredRelation = await payload.create<Relation>({ const filteredRelation = await payload.create({
collection: relationSlug, collection: relationSlug,
data: { data: {
name: 'filtered', name: 'filtered',
}, },
}); });
const defaultAccessRelation = await payload.create<Relation>({ const defaultAccessRelation = await payload.create({
collection: defaultAccessRelSlug, collection: defaultAccessRelSlug,
data: { data: {
name: 'name', name: 'name',
}, },
}); });
const chained3 = await payload.create<ChainedRelation>({ const chained3 = await payload.create({
collection: chainedRelSlug, collection: chainedRelSlug,
data: { data: {
name: 'chain3', name: 'chain3',
}, },
}); });
const chained2 = await payload.create<ChainedRelation>({ const chained2 = await payload.create({
collection: chainedRelSlug, collection: chainedRelSlug,
data: { data: {
name: 'chain2', name: 'chain2',
@@ -203,7 +238,7 @@ export default buildConfig({
}, },
}); });
const chained = await payload.create<ChainedRelation>({ const chained = await payload.create({
collection: chainedRelSlug, collection: chainedRelSlug,
data: { data: {
name: 'chain1', name: 'chain1',
@@ -211,7 +246,7 @@ export default buildConfig({
}, },
}); });
await payload.update<ChainedRelation>({ await payload.update({
collection: chainedRelSlug, collection: chainedRelSlug,
id: chained3.id, id: chained3.id,
data: { data: {
@@ -220,7 +255,7 @@ export default buildConfig({
}, },
}); });
const customIdRelation = await payload.create<CustomIdRelation>({ const customIdRelation = await payload.create({
collection: customIdSlug, collection: customIdSlug,
data: { data: {
id: 'custommmm', id: 'custommmm',
@@ -228,7 +263,7 @@ export default buildConfig({
}, },
}); });
const customIdNumberRelation = await payload.create<CustomIdNumberRelation>({ const customIdNumberRelation = await payload.create({
collection: customIdNumberSlug, collection: customIdNumberSlug,
data: { data: {
id: 908234892340, id: 908234892340,
@@ -236,9 +271,8 @@ export default buildConfig({
}, },
}); });
// Relationship // Relationship
await payload.create<Post>({ await payload.create({
collection: slug, collection: slug,
data: { data: {
title: 'with relationship', title: 'with relationship',

View File

@@ -4,7 +4,7 @@ import { initPayloadTest } from '../helpers/configHelpers';
import config, { customIdSlug, chainedRelSlug, defaultAccessRelSlug, slug, relationSlug, customIdNumberSlug } from './config'; import config, { customIdSlug, chainedRelSlug, defaultAccessRelSlug, slug, relationSlug, customIdNumberSlug } from './config';
import payload from '../../src'; import payload from '../../src';
import { RESTClient } from '../helpers/rest'; 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'; import { mapAsync } from '../../src/utilities/mapAsync';
let client: RESTClient; let client: RESTClient;
@@ -239,8 +239,6 @@ describe('Relationships', () => {
thirdLevelID = thirdLevelDoc.id; thirdLevelID = thirdLevelDoc.id;
console.log({ thirdLevelID });
const secondLevelDoc = await payload.create({ const secondLevelDoc = await payload.create({
collection: 'chained-relation', collection: 'chained-relation',
data: { data: {
@@ -251,8 +249,6 @@ describe('Relationships', () => {
secondLevelID = secondLevelDoc.id; secondLevelID = secondLevelDoc.id;
console.log({ secondLevelID });
const firstLevelDoc = await payload.create({ const firstLevelDoc = await payload.create({
collection: 'chained-relation', collection: 'chained-relation',
data: { data: {
@@ -262,8 +258,6 @@ describe('Relationships', () => {
}); });
firstLevelID = firstLevelDoc.id; firstLevelID = firstLevelDoc.id;
console.log({ firstLevelID });
}); });
it('should allow querying one level deep', async () => { it('should allow querying one level deep', async () => {
@@ -306,15 +300,60 @@ describe('Relationships', () => {
expect(query.docs[0].id).toStrictEqual(firstLevelID); 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<Post>) { async function createPost(overrides?: Partial<Post>) {
return payload.create<Post>({ collection: slug, data: { title: 'title', ...overrides } }); return payload.create({ collection: slug, data: { title: 'title', ...overrides } });
} }
async function clearDocs(): Promise<void> { async function clearDocs(): Promise<void> {
const allDocs = await payload.find<Post>({ collection: slug, limit: 100 }); const allDocs = await payload.find({ collection: slug, limit: 100 });
const ids = allDocs.docs.map((doc) => doc.id); const ids = allDocs.docs.map((doc) => doc.id);
await mapAsync(ids, async (id) => { await mapAsync(ids, async (id) => {
await payload.delete({ collection: slug, id }); await payload.delete({ collection: slug, id });

View File

@@ -5,11 +5,21 @@
* and re-run `payload generate:types` to regenerate this file. * and re-run `payload generate:types` to regenerate this file.
*/ */
export interface Config {} export interface Config {
/** collections: {
* This interface was referenced by `Config`'s JSON-Schema posts: Post;
* via the `definition` "posts". 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 { export interface Post {
id: string; id: string;
title?: string; title?: string;
@@ -22,73 +32,70 @@ export interface Post {
customIdRelation?: string | CustomIdRelation; customIdRelation?: string | CustomIdRelation;
customIdNumberRelation?: number | CustomIdNumberRelation; customIdNumberRelation?: number | CustomIdNumberRelation;
filteredRelation?: string | Relation; filteredRelation?: string | Relation;
createdAt: string;
updatedAt: string; updatedAt: string;
createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "relation".
*/
export interface Relation { export interface Relation {
id: string; id: string;
name?: string; name?: string;
disableRelation: boolean; disableRelation: boolean;
createdAt: string;
updatedAt: string; updatedAt: string;
createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "strict-access".
*/
export interface StrictAccess { export interface StrictAccess {
id: string; id: string;
name?: string; name?: string;
disableRelation: boolean; disableRelation: boolean;
createdAt: string;
updatedAt: string; updatedAt: string;
createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "chained-relation".
*/
export interface ChainedRelation { export interface ChainedRelation {
id: string; id: string;
name?: string; name?: string;
relation?: string | ChainedRelation; relation?: string | ChainedRelation;
createdAt: string;
updatedAt: string; updatedAt: string;
createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "custom-id-relation".
*/
export interface CustomIdRelation { export interface CustomIdRelation {
id: string; id: string;
name?: string; name?: string;
createdAt: string;
updatedAt: string; updatedAt: string;
createdAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "custom-id-number-relation".
*/
export interface CustomIdNumberRelation { export interface CustomIdNumberRelation {
id: number; id: number;
name?: string; name?: string;
createdAt: string;
updatedAt: 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 { export interface User {
id: string; id: string;
updatedAt: string;
createdAt: string;
email?: string; email?: string;
resetPasswordToken?: string; resetPasswordToken?: string;
resetPasswordExpiration?: string; resetPasswordExpiration?: string;
loginAttempts?: number; loginAttempts?: number;
lockUntil?: string; lockUntil?: string;
createdAt: string; password?: string;
updatedAt: string;
} }