fix(plugin-search): delete does not also delete the search doc (#12148)
The plugin-search collection uses an `afterDelete` hook to remove search records from the database. Since a deleted document in postgres causes cascade updates for the foreign key, the query for the document by relationship was not returning the record to be deleted. The solution was to change the delete hook to `beforeDelete` for the search enabled collections. This way we purge records before the main document so the search document query can find and delete the record as expected. An alternative solution in #9623 would remove the `req` so the delete query could still find the document, however, this just works outside of transactions which isn't desirable. fixes https://github.com/payloadcms/payload/issues/9443
This commit is contained in:
@@ -1,43 +1,28 @@
|
|||||||
import type { DeleteFromSearch } from '../../types.js'
|
import type { DeleteFromSearch } from '../../types.js'
|
||||||
|
|
||||||
export const deleteFromSearch: DeleteFromSearch = async ({
|
export const deleteFromSearch: DeleteFromSearch =
|
||||||
collection,
|
(pluginConfig) =>
|
||||||
doc,
|
async ({ id, collection, req: { payload }, req }) => {
|
||||||
pluginConfig,
|
|
||||||
req: { payload },
|
|
||||||
req,
|
|
||||||
}) => {
|
|
||||||
const searchSlug = pluginConfig?.searchOverrides?.slug || 'search'
|
const searchSlug = pluginConfig?.searchOverrides?.slug || 'search'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const searchDocQuery = await payload.find({
|
await payload.delete({
|
||||||
collection: searchSlug,
|
collection: searchSlug,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
limit: 1,
|
|
||||||
pagination: false,
|
|
||||||
req,
|
req,
|
||||||
where: {
|
where: {
|
||||||
doc: {
|
'doc.relationTo': {
|
||||||
equals: {
|
equals: collection.slug,
|
||||||
relationTo: collection.slug,
|
|
||||||
value: doc.id,
|
|
||||||
},
|
},
|
||||||
|
'doc.value': {
|
||||||
|
equals: id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if (searchDocQuery?.docs?.[0]) {
|
|
||||||
await payload.delete({
|
|
||||||
id: searchDocQuery?.docs?.[0]?.id,
|
|
||||||
collection: searchSlug,
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
payload.logger.error({
|
payload.logger.error({
|
||||||
err,
|
err,
|
||||||
msg: `Error deleting ${searchSlug} doc.`,
|
msg: `Error deleting ${searchSlug} doc.`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return doc
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { CollectionAfterChangeHook, CollectionAfterDeleteHook, Config } from 'payload'
|
import type { CollectionAfterChangeHook, Config } from 'payload'
|
||||||
|
|
||||||
import type { SanitizedSearchPluginConfig, SearchPluginConfig } from './types.js'
|
import type { SanitizedSearchPluginConfig, SearchPluginConfig } from './types.js'
|
||||||
|
|
||||||
@@ -7,7 +7,6 @@ import { syncWithSearch } from './Search/hooks/syncWithSearch.js'
|
|||||||
import { generateSearchCollection } from './Search/index.js'
|
import { generateSearchCollection } from './Search/index.js'
|
||||||
|
|
||||||
type CollectionAfterChangeHookArgs = Parameters<CollectionAfterChangeHook>[0]
|
type CollectionAfterChangeHookArgs = Parameters<CollectionAfterChangeHook>[0]
|
||||||
type CollectionAfterDeleteHookArgs = Parameters<CollectionAfterDeleteHook>[0]
|
|
||||||
|
|
||||||
export const searchPlugin =
|
export const searchPlugin =
|
||||||
(incomingPluginConfig: SearchPluginConfig) =>
|
(incomingPluginConfig: SearchPluginConfig) =>
|
||||||
@@ -67,14 +66,9 @@ export const searchPlugin =
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
afterDelete: [
|
beforeDelete: [
|
||||||
...(existingHooks?.afterDelete || []),
|
...(existingHooks?.beforeDelete || []),
|
||||||
async (args: CollectionAfterDeleteHookArgs) => {
|
deleteFromSearch(pluginConfig),
|
||||||
await deleteFromSearch({
|
|
||||||
...args,
|
|
||||||
pluginConfig,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type {
|
import type {
|
||||||
CollectionAfterChangeHook,
|
CollectionAfterChangeHook,
|
||||||
CollectionAfterDeleteHook,
|
CollectionBeforeDeleteHook,
|
||||||
CollectionConfig,
|
CollectionConfig,
|
||||||
Field,
|
Field,
|
||||||
Locale,
|
Locale,
|
||||||
@@ -96,8 +96,4 @@ export type SyncDocArgs = {
|
|||||||
// Convert the `collection` arg from `SanitizedCollectionConfig` to a string
|
// Convert the `collection` arg from `SanitizedCollectionConfig` to a string
|
||||||
export type SyncWithSearch = (Args: SyncWithSearchArgs) => ReturnType<CollectionAfterChangeHook>
|
export type SyncWithSearch = (Args: SyncWithSearchArgs) => ReturnType<CollectionAfterChangeHook>
|
||||||
|
|
||||||
export type DeleteFromSearch = (
|
export type DeleteFromSearch = (args: SearchPluginConfig) => CollectionBeforeDeleteHook
|
||||||
Args: {
|
|
||||||
pluginConfig: SearchPluginConfig
|
|
||||||
} & Parameters<CollectionAfterDeleteHook>[0],
|
|
||||||
) => ReturnType<CollectionAfterDeleteHook>
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import type { Payload } from 'payload'
|
||||||
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { NotFound, type Payload } from 'payload'
|
|
||||||
import { wait } from 'payload/shared'
|
import { wait } from 'payload/shared'
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
@@ -300,8 +301,8 @@ describe('@payloadcms/plugin-search', () => {
|
|||||||
collection: 'search',
|
collection: 'search',
|
||||||
depth: 0,
|
depth: 0,
|
||||||
where: {
|
where: {
|
||||||
'doc.value': {
|
id: {
|
||||||
equals: page.id,
|
equals: results[0].id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user