fix: ensures nested querying works when querying across collections
This commit is contained in:
@@ -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('.');
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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 });
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user