Skip to content

Commit

Permalink
fix: filtering by non-poly relationships with not_equals operator (
Browse files Browse the repository at this point in the history
…#7573)

## Description

Fixes #5212

Fixes #6278 

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
  • Loading branch information
PatrikKozak authored Aug 8, 2024
1 parent 907d7d1 commit efa56ce
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 9 deletions.
18 changes: 13 additions & 5 deletions packages/db-mongodb/src/queries/buildSearchParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { PathToQuery } from 'payload/database'
import type { Field } from 'payload/types'
import type { Operator } from 'payload/types'

import objectID from 'bson-objectid'
import ObjectIdImport from 'bson-objectid'
import mongoose from 'mongoose'
import { getLocalizedPaths } from 'payload/database'
import { fieldAffectsData } from 'payload/types'
Expand All @@ -14,6 +14,8 @@ import type { MongooseAdapter } from '..'
import { operatorMap } from './operatorMap'
import { sanitizeQueryValue } from './sanitizeQueryValue'

const ObjectId = ObjectIdImport

type SearchParam = {
path?: string
rawQuery?: unknown
Expand Down Expand Up @@ -195,16 +197,20 @@ export async function buildSearchParam({

if (field.type === 'relationship' || field.type === 'upload') {
let hasNumberIDRelation
let multiIDCondition = '$or'
if (operatorKey === '$ne') multiIDCondition = '$and'

const result = {
value: {
$or: [{ [path]: { [operatorKey]: formattedValue } }],
[multiIDCondition]: [{ [path]: { [operatorKey]: formattedValue } }],
},
}

if (typeof formattedValue === 'string') {
if (mongoose.Types.ObjectId.isValid(formattedValue)) {
result.value.$or.push({ [path]: { [operatorKey]: objectID(formattedValue) } })
result.value[multiIDCondition].push({
[path]: { [operatorKey]: ObjectId(formattedValue) },
})
} else {
;(Array.isArray(field.relationTo) ? field.relationTo : [field.relationTo]).forEach(
(relationTo) => {
Expand All @@ -225,11 +231,13 @@ export async function buildSearchParam({
)

if (hasNumberIDRelation)
result.value.$or.push({ [path]: { [operatorKey]: parseFloat(formattedValue) } })
result.value[multiIDCondition].push({
[path]: { [operatorKey]: parseFloat(formattedValue) },
})
}
}

if (result.value.$or.length > 1) {
if (result.value[multiIDCondition].length > 1) {
return result
}
}
Expand Down
12 changes: 12 additions & 0 deletions test/fields/collections/Relationship/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ const RelationshipFields: CollectionConfig = {
},
},
},
{
name: 'relationNoHasManyNonPolymorphic',
relationTo: 'text-fields',
type: 'relationship',
hasMany: false,
},
{
name: 'relationHasManyNonPolymorphic',
relationTo: 'text-fields',
type: 'relationship',
hasMany: true,
},
{
name: 'relationToSelf',
relationTo: relationshipFieldsSlug,
Expand Down
64 changes: 60 additions & 4 deletions test/fields/int.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,6 @@ describe('Fields', () => {
},
})

const anyChildren = await payload.find({
collection: relationshipFieldsSlug,
})
const allChildren = await payload.find({
collection: relationshipFieldsSlug,
where: {
Expand Down Expand Up @@ -1557,7 +1554,47 @@ describe('Fields', () => {
})
})

describe('relationships', () => {
describe('relationship queries', () => {
let textDoc
let otherTextDoc
let relationshipDocWithNonPolyOne
let relationshipDocWithNonPolyTwo
const textDocText = 'text document'
const otherTextDocText = 'alt text'

beforeEach(async () => {
textDoc = await payload.create({
collection: 'text-fields',
data: {
text: textDocText,
},
})
otherTextDoc = await payload.create({
collection: 'text-fields',
data: {
text: otherTextDocText,
},
})
const relationship = { relationTo: 'text-fields', value: textDoc.id }
relationshipDocWithNonPolyOne = await payload.create({
collection: relationshipFieldsSlug,
data: {
relationship,
relationNoHasManyNonPolymorphic: textDoc.id,
relationHasManyNonPolymorphic: textDoc.id,
},
})

relationshipDocWithNonPolyTwo = await payload.create({
collection: relationshipFieldsSlug,
data: {
relationship,
relationNoHasManyNonPolymorphic: otherTextDoc.id,
relationHasManyNonPolymorphic: otherTextDoc.id,
},
})
})

it('should not crash if querying with empty in operator', async () => {
const query = await payload.find({
collection: 'relationship-fields',
Expand All @@ -1570,6 +1607,25 @@ describe('Fields', () => {

expect(query.docs).toBeDefined()
})

it('should properly query non-polymorphic relationship with not equals', async () => {
const withoutHasMany = await payload.find({
collection: relationshipFieldsSlug,
where: {
relationNoHasManyNonPolymorphic: { not_equals: otherTextDoc.id },
},
})

const withHasMany = await payload.find({
collection: relationshipFieldsSlug,
where: {
relationHasManyNonPolymorphic: { not_equals: textDoc.id },
},
})

expect(withoutHasMany.docs).toHaveLength(1)
expect(withHasMany.docs).toHaveLength(1)
})
})

describe('clearable fields - exists', () => {
Expand Down
2 changes: 2 additions & 0 deletions test/fields/payload-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,8 @@ export interface RelationshipField {
}
)[]
| null
relationNoHasManyNonPolymorphic?: (string | null) | TextField
relationHasManyNonPolymorphic?: (string | TextField)[] | null
relationToSelf?: (string | null) | RelationshipField
relationToSelfSelectOnly?: (string | null) | RelationshipField
relationWithDynamicDefault?: (string | null) | User
Expand Down

0 comments on commit efa56ce

Please sign in to comment.