strapi-plugin-meilisearch 0.15.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{App-DEDEzxD1.mjs → App-sobdRlxo.mjs} +1 -1
- package/dist/_chunks/{App-DqXRl-ux.js → App-zelJ7Obw.js} +1 -1
- package/dist/_chunks/{index-DuX8ujje.mjs → index-CajY83vq.mjs} +3 -2
- package/dist/_chunks/{index-D_Ao_M3T.js → index-KTMW2G6w.js} +3 -2
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +237 -36
- package/dist/server/index.mjs +237 -36
- package/package.json +2 -1
|
@@ -3,7 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import { useState, useEffect, memo } from "react";
|
|
4
4
|
import { Routes, Route } from "react-router-dom";
|
|
5
5
|
import { useNotification, useFetchClient, useRBAC, private_useAutoReloadOverlayBlocker, private_AutoReloadOverlayBlockerProvider, Page, Layouts, BackButton } from "@strapi/strapi/admin";
|
|
6
|
-
import { p as pluginId, P as PERMISSIONS } from "./index-
|
|
6
|
+
import { p as pluginId, P as PERMISSIONS } from "./index-CajY83vq.mjs";
|
|
7
7
|
import { Tr, Td, Checkbox, Typography, Flex, Box, Button, Thead, Th, VisuallyHidden, Table, Tbody, Field, Link, Tabs } from "@strapi/design-system";
|
|
8
8
|
var __assign = function() {
|
|
9
9
|
__assign = Object.assign || function __assign2(t) {
|
|
@@ -4,7 +4,7 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
|
4
4
|
const React = require("react");
|
|
5
5
|
const reactRouterDom = require("react-router-dom");
|
|
6
6
|
const admin = require("@strapi/strapi/admin");
|
|
7
|
-
const index = require("./index-
|
|
7
|
+
const index = require("./index-KTMW2G6w.js");
|
|
8
8
|
const designSystem = require("@strapi/design-system");
|
|
9
9
|
function _interopNamespace(e) {
|
|
10
10
|
if (e && e.__esModule) return e;
|
|
@@ -18,7 +18,7 @@ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
20
|
const name$1 = "strapi-plugin-meilisearch";
|
|
21
|
-
const version = "0.
|
|
21
|
+
const version = "0.16.1";
|
|
22
22
|
const description = "Synchronise and search in your Strapi content-types with Meilisearch";
|
|
23
23
|
const scripts = {
|
|
24
24
|
build: "strapi-plugin build",
|
|
@@ -82,6 +82,7 @@ const devDependencies = {
|
|
|
82
82
|
"@strapi/strapi": "^5.6.0",
|
|
83
83
|
"@types/jest": "^30.0.0",
|
|
84
84
|
"babel-jest": "^30.2.0",
|
|
85
|
+
"better-sqlite3": "^12.8.0",
|
|
85
86
|
concurrently: "^9.2.1",
|
|
86
87
|
cypress: "^15.11.0",
|
|
87
88
|
eslint: "^10.0.2",
|
|
@@ -214,7 +215,7 @@ const index = {
|
|
|
214
215
|
defaultMessage: name
|
|
215
216
|
},
|
|
216
217
|
Component: async () => {
|
|
217
|
-
const { App } = await import("./App-
|
|
218
|
+
const { App } = await import("./App-sobdRlxo.mjs");
|
|
218
219
|
return App;
|
|
219
220
|
},
|
|
220
221
|
permissions: PERMISSIONS.main
|
|
@@ -19,7 +19,7 @@ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
|
|
19
19
|
});
|
|
20
20
|
};
|
|
21
21
|
const name$1 = "strapi-plugin-meilisearch";
|
|
22
|
-
const version = "0.
|
|
22
|
+
const version = "0.16.1";
|
|
23
23
|
const description = "Synchronise and search in your Strapi content-types with Meilisearch";
|
|
24
24
|
const scripts = {
|
|
25
25
|
build: "strapi-plugin build",
|
|
@@ -83,6 +83,7 @@ const devDependencies = {
|
|
|
83
83
|
"@strapi/strapi": "^5.6.0",
|
|
84
84
|
"@types/jest": "^30.0.0",
|
|
85
85
|
"babel-jest": "^30.2.0",
|
|
86
|
+
"better-sqlite3": "^12.8.0",
|
|
86
87
|
concurrently: "^9.2.1",
|
|
87
88
|
cypress: "^15.11.0",
|
|
88
89
|
eslint: "^10.0.2",
|
|
@@ -215,7 +216,7 @@ const index = {
|
|
|
215
216
|
defaultMessage: name
|
|
216
217
|
},
|
|
217
218
|
Component: async () => {
|
|
218
|
-
const { App } = await Promise.resolve().then(() => require("./App-
|
|
219
|
+
const { App } = await Promise.resolve().then(() => require("./App-zelJ7Obw.js"));
|
|
219
220
|
return App;
|
|
220
221
|
},
|
|
221
222
|
permissions: PERMISSIONS.main
|
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -94,6 +94,84 @@ async function registerDocumentMiddleware({ strapi: strapi2 }) {
|
|
|
94
94
|
if (!strapi2?.documents || typeof strapi2.documents.use !== "function") {
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
|
+
const extractEntryCandidates = (result) => {
|
|
98
|
+
if (result == null) return [];
|
|
99
|
+
const candidates = [];
|
|
100
|
+
const appendCandidate = (data, source) => {
|
|
101
|
+
if (data != null && typeof data === "object") {
|
|
102
|
+
candidates.push({ data, source });
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
if (Array.isArray(result)) {
|
|
106
|
+
result.forEach((data) => appendCandidate(data, "root"));
|
|
107
|
+
return candidates;
|
|
108
|
+
}
|
|
109
|
+
appendCandidate(result, "root");
|
|
110
|
+
if (Array.isArray(result.versions)) {
|
|
111
|
+
result.versions.forEach((data) => appendCandidate(data, "versions"));
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(result.entries)) {
|
|
114
|
+
result.entries.forEach((data) => appendCandidate(data, "entries"));
|
|
115
|
+
}
|
|
116
|
+
if (result.entry != null) {
|
|
117
|
+
appendCandidate(result.entry, "entry");
|
|
118
|
+
}
|
|
119
|
+
return candidates;
|
|
120
|
+
};
|
|
121
|
+
const isPublishedEntry = (entry) => !(entry?.publishedAt === void 0 || entry?.publishedAt === null);
|
|
122
|
+
const rankEntryCandidates = (candidates) => {
|
|
123
|
+
return [...candidates].sort((a, b) => {
|
|
124
|
+
const aHasPrimaryKey = a.data?.id != null;
|
|
125
|
+
const bHasPrimaryKey = b.data?.id != null;
|
|
126
|
+
if (aHasPrimaryKey && !bHasPrimaryKey) return -1;
|
|
127
|
+
if (!aHasPrimaryKey && bHasPrimaryKey) return 1;
|
|
128
|
+
const aIsRoot = a.source === "root";
|
|
129
|
+
const bIsRoot = b.source === "root";
|
|
130
|
+
if (!aIsRoot && bIsRoot) return -1;
|
|
131
|
+
if (aIsRoot && !bIsRoot) return 1;
|
|
132
|
+
return 0;
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
const getEntryFromResult = ({
|
|
136
|
+
resultCandidates,
|
|
137
|
+
documentId,
|
|
138
|
+
entriesQuery
|
|
139
|
+
}) => {
|
|
140
|
+
const documentCandidates = (resultCandidates || []).filter(
|
|
141
|
+
(candidate) => candidate?.data?.documentId === documentId
|
|
142
|
+
);
|
|
143
|
+
if (documentCandidates.length === 0) return null;
|
|
144
|
+
const rankedCandidates = rankEntryCandidates(documentCandidates);
|
|
145
|
+
if (entriesQuery?.status === "draft") {
|
|
146
|
+
const draftCandidate = rankedCandidates.find(
|
|
147
|
+
(candidate) => !isPublishedEntry(candidate.data)
|
|
148
|
+
);
|
|
149
|
+
return draftCandidate?.data || rankedCandidates[0]?.data || null;
|
|
150
|
+
}
|
|
151
|
+
const publishedCandidate = rankedCandidates.find(
|
|
152
|
+
(candidate) => isPublishedEntry(candidate.data)
|
|
153
|
+
);
|
|
154
|
+
return publishedCandidate?.data || null;
|
|
155
|
+
};
|
|
156
|
+
const getEntryOutsideTransaction = ({
|
|
157
|
+
contentTypeService: contentTypeService2,
|
|
158
|
+
contentType: contentType2,
|
|
159
|
+
documentId,
|
|
160
|
+
entriesQuery
|
|
161
|
+
}) => new Promise((resolve, reject) => {
|
|
162
|
+
setImmediate(async () => {
|
|
163
|
+
try {
|
|
164
|
+
const entry = await contentTypeService2.getEntry({
|
|
165
|
+
contentType: contentType2,
|
|
166
|
+
documentId,
|
|
167
|
+
entriesQuery: { ...entriesQuery }
|
|
168
|
+
});
|
|
169
|
+
resolve(entry);
|
|
170
|
+
} catch (error2) {
|
|
171
|
+
reject(error2);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
});
|
|
97
175
|
strapi2.documents.use(async (ctx, next) => {
|
|
98
176
|
let result;
|
|
99
177
|
try {
|
|
@@ -115,31 +193,72 @@ async function registerDocumentMiddleware({ strapi: strapi2 }) {
|
|
|
115
193
|
"unpublish",
|
|
116
194
|
"discardDraft"
|
|
117
195
|
];
|
|
196
|
+
const entriesQuery = meilisearch2.entriesQuery({ contentType: contentType2 });
|
|
197
|
+
const shouldDeleteByLocale = entriesQuery.locale === "*" || entriesQuery.locale === "all";
|
|
198
|
+
const { status } = entriesQuery || {};
|
|
199
|
+
const statusFilter = typeof status === "string" && status.length > 0 ? { status } : {};
|
|
118
200
|
const preDeleteDocumentId = deleteActions.includes(ctx.action) && ctx?.params?.documentId ? ctx.params.documentId : null;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
201
|
+
let preDeleteEntry = null;
|
|
202
|
+
let preDeleteLocales = [];
|
|
203
|
+
if (preDeleteDocumentId != null) {
|
|
204
|
+
preDeleteEntry = await contentTypeService2.getEntry({
|
|
205
|
+
contentType: contentType2,
|
|
206
|
+
documentId: preDeleteDocumentId,
|
|
207
|
+
entriesQuery: { ...statusFilter }
|
|
208
|
+
});
|
|
209
|
+
if (shouldDeleteByLocale) {
|
|
210
|
+
const localeVariants = await contentTypeService2.getEntries({
|
|
211
|
+
contentType: contentType2,
|
|
212
|
+
fields: ["documentId", "locale"],
|
|
213
|
+
locale: "*",
|
|
214
|
+
...statusFilter,
|
|
215
|
+
filters: {
|
|
216
|
+
documentId: preDeleteDocumentId
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
preDeleteLocales = [
|
|
220
|
+
...new Set(
|
|
221
|
+
localeVariants.map((entry) => entry?.locale).filter(
|
|
222
|
+
(locale) => typeof locale === "string" && locale.length > 0
|
|
223
|
+
)
|
|
224
|
+
)
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
}
|
|
124
228
|
result = await next();
|
|
125
|
-
const
|
|
229
|
+
const contextDocumentId = typeof ctx?.params?.documentId === "string" && ctx.params.documentId.length > 0 ? ctx.params.documentId : null;
|
|
230
|
+
const documentId = contextDocumentId ?? result?.documentId ?? preDeleteEntry?.documentId ?? preDeleteDocumentId ?? null;
|
|
126
231
|
if (updateActions.includes(ctx.action) && documentId != null) {
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
232
|
+
const resultCandidates = extractEntryCandidates(result);
|
|
233
|
+
let entry = getEntryFromResult({
|
|
234
|
+
resultCandidates,
|
|
130
235
|
documentId,
|
|
131
|
-
entriesQuery
|
|
236
|
+
entriesQuery
|
|
132
237
|
});
|
|
238
|
+
if (!entry) {
|
|
239
|
+
entry = await getEntryOutsideTransaction({
|
|
240
|
+
contentTypeService: contentTypeService2,
|
|
241
|
+
contentType: contentType2,
|
|
242
|
+
documentId,
|
|
243
|
+
entriesQuery
|
|
244
|
+
});
|
|
245
|
+
}
|
|
133
246
|
if (entry) {
|
|
247
|
+
const normalizedEntry = entry.documentId === documentId ? entry : { ...entry, documentId };
|
|
134
248
|
await meilisearch2.updateEntriesInMeilisearch({
|
|
135
249
|
contentType: contentType2,
|
|
136
|
-
entries: [
|
|
250
|
+
entries: [normalizedEntry]
|
|
137
251
|
});
|
|
138
|
-
} else {
|
|
252
|
+
} else if (ctx.action === "create" || ctx.action === "publish") {
|
|
139
253
|
await meilisearch2.deleteEntriesFromMeiliSearch({
|
|
140
254
|
contentType: contentType2,
|
|
141
|
-
documentIds: [documentId]
|
|
255
|
+
documentIds: [documentId],
|
|
256
|
+
entriesQuery
|
|
142
257
|
});
|
|
258
|
+
} else {
|
|
259
|
+
strapi2.log.info(
|
|
260
|
+
`Meilisearch document middleware skipped indexing ${contentType2} documentId=${documentId} for action ${ctx.action}: no indexable entry in result payload`
|
|
261
|
+
);
|
|
143
262
|
}
|
|
144
263
|
} else if (deleteActions.includes(ctx.action)) {
|
|
145
264
|
if (documentId != null) {
|
|
@@ -148,7 +267,9 @@ async function registerDocumentMiddleware({ strapi: strapi2 }) {
|
|
|
148
267
|
);
|
|
149
268
|
await meilisearch2.deleteEntriesFromMeiliSearch({
|
|
150
269
|
contentType: contentType2,
|
|
151
|
-
documentIds: [documentId]
|
|
270
|
+
documentIds: [documentId],
|
|
271
|
+
entriesQuery,
|
|
272
|
+
locales: shouldDeleteByLocale && preDeleteLocales.length > 0 ? preDeleteLocales : void 0
|
|
152
273
|
});
|
|
153
274
|
} else {
|
|
154
275
|
strapi2.log.info(
|
|
@@ -1233,6 +1354,7 @@ const store = ({ strapi: strapi2 }) => {
|
|
|
1233
1354
|
...createStoreConnector({ strapi: strapi2 })
|
|
1234
1355
|
};
|
|
1235
1356
|
};
|
|
1357
|
+
const isWildcardLocale = (locale) => locale === "all" || locale === "*";
|
|
1236
1358
|
const aborted = ({ contentType: contentType2, action }) => {
|
|
1237
1359
|
strapi.log.error(
|
|
1238
1360
|
`Indexing of ${contentType2} aborted as the data could not be ${action}`
|
|
@@ -1441,7 +1563,7 @@ const configurationService = ({ strapi: strapi2 }) => {
|
|
|
1441
1563
|
const collection = contentTypeService2.getCollectionName({ contentType: contentType2 });
|
|
1442
1564
|
const contentTypeConfig = meilisearchConfig[collection] || {};
|
|
1443
1565
|
const entriesQuery = contentTypeConfig.entriesQuery || {};
|
|
1444
|
-
if (!entriesQuery.locale || entriesQuery.locale
|
|
1566
|
+
if (!entriesQuery.locale || isWildcardLocale(entriesQuery.locale)) {
|
|
1445
1567
|
return entries;
|
|
1446
1568
|
} else {
|
|
1447
1569
|
return entries.filter((entry) => entry.locale === entriesQuery.locale);
|
|
@@ -1449,7 +1571,7 @@ const configurationService = ({ strapi: strapi2 }) => {
|
|
|
1449
1571
|
}
|
|
1450
1572
|
};
|
|
1451
1573
|
};
|
|
1452
|
-
const version = "0.
|
|
1574
|
+
const version = "0.16.1";
|
|
1453
1575
|
const Meilisearch = (config2) => {
|
|
1454
1576
|
return new meilisearch$1.MeiliSearch({
|
|
1455
1577
|
...config2,
|
|
@@ -1516,26 +1638,82 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
|
|
|
1516
1638
|
* @param {object} options
|
|
1517
1639
|
* @param {string} options.contentType - ContentType name.
|
|
1518
1640
|
* @param {string[]} options.documentIds - Entry documentIds.
|
|
1641
|
+
* @param {object} options.entriesQuery - Entries query.
|
|
1519
1642
|
*
|
|
1520
1643
|
* @returns { Promise<import("meilisearch").Task>} p - Task body returned by Meilisearch API.
|
|
1521
1644
|
*/
|
|
1522
1645
|
deleteEntriesFromMeiliSearch: async function({
|
|
1523
1646
|
contentType: contentType2,
|
|
1524
|
-
documentIds
|
|
1647
|
+
documentIds,
|
|
1648
|
+
entriesQuery = {},
|
|
1649
|
+
locales
|
|
1525
1650
|
}) {
|
|
1526
1651
|
const { apiKey, host } = await store2.getCredentials();
|
|
1527
1652
|
const client = Meilisearch({ apiKey, host });
|
|
1528
1653
|
const indexUids = config2.getIndexNamesOfContentType({ contentType: contentType2 });
|
|
1529
|
-
const validDocumentIds =
|
|
1654
|
+
const validDocumentIds = [
|
|
1655
|
+
...new Set(documentIds.filter((id) => id != null))
|
|
1656
|
+
];
|
|
1530
1657
|
if (validDocumentIds.length === 0) return [];
|
|
1531
|
-
const
|
|
1532
|
-
|
|
1658
|
+
const resolvedEntriesQuery = Object.keys(entriesQuery).length > 0 ? entriesQuery : config2.entriesQuery({ contentType: contentType2 });
|
|
1659
|
+
const shouldDeleteAllLocaleVariants = isWildcardLocale(
|
|
1660
|
+
resolvedEntriesQuery.locale
|
|
1661
|
+
);
|
|
1662
|
+
const resolvedLocales = Array.isArray(locales) ? [
|
|
1663
|
+
...new Set(
|
|
1664
|
+
locales.filter(
|
|
1665
|
+
(locale) => typeof locale === "string" && locale.trim().length > 0
|
|
1666
|
+
).map((locale) => locale.trim())
|
|
1667
|
+
)
|
|
1668
|
+
] : [];
|
|
1669
|
+
const meilisearchDocumentIds = shouldDeleteAllLocaleVariants && resolvedLocales.length > 0 ? validDocumentIds.flatMap(
|
|
1670
|
+
(entryDocumentId) => resolvedLocales.map(
|
|
1671
|
+
(resolvedLocale) => adapter.addCollectionNamePrefixToId({
|
|
1672
|
+
contentType: contentType2,
|
|
1673
|
+
entryDocumentId,
|
|
1674
|
+
locale: resolvedLocale
|
|
1675
|
+
})
|
|
1676
|
+
)
|
|
1677
|
+
) : shouldDeleteAllLocaleVariants ? (await Promise.all(
|
|
1678
|
+
validDocumentIds.map(async (entryDocumentId) => {
|
|
1679
|
+
const baseFilters = resolvedEntriesQuery.filters != null ? resolvedEntriesQuery.filters : {};
|
|
1680
|
+
const localizedEntries = await contentTypeService2.getEntries({
|
|
1681
|
+
contentType: contentType2,
|
|
1682
|
+
fields: ["documentId", "locale"],
|
|
1683
|
+
locale: "*",
|
|
1684
|
+
...resolvedEntriesQuery.status ? { status: resolvedEntriesQuery.status } : {},
|
|
1685
|
+
filters: {
|
|
1686
|
+
...baseFilters,
|
|
1687
|
+
documentId: entryDocumentId
|
|
1688
|
+
}
|
|
1689
|
+
});
|
|
1690
|
+
return localizedEntries.length > 0 ? localizedEntries.map(
|
|
1691
|
+
(entry) => adapter.addCollectionNamePrefixToId({
|
|
1692
|
+
contentType: contentType2,
|
|
1693
|
+
entryDocumentId,
|
|
1694
|
+
locale: entry.locale
|
|
1695
|
+
})
|
|
1696
|
+
) : [
|
|
1697
|
+
// Fallback: delete the non-localized document when no localized variants exist.
|
|
1698
|
+
adapter.addCollectionNamePrefixToId({
|
|
1699
|
+
contentType: contentType2,
|
|
1700
|
+
entryDocumentId
|
|
1701
|
+
})
|
|
1702
|
+
];
|
|
1703
|
+
})
|
|
1704
|
+
)).flat() : validDocumentIds.map(
|
|
1705
|
+
(entryDocumentId) => adapter.addCollectionNamePrefixToId({
|
|
1706
|
+
entryDocumentId,
|
|
1707
|
+
contentType: contentType2,
|
|
1708
|
+
locale: resolvedEntriesQuery.locale
|
|
1709
|
+
})
|
|
1533
1710
|
);
|
|
1711
|
+
const uniqueDocumentIds = [...new Set(meilisearchDocumentIds)];
|
|
1534
1712
|
const tasks = await Promise.all(
|
|
1535
1713
|
indexUids.map(async (indexUid) => {
|
|
1536
|
-
const task = await client.index(indexUid).deleteDocuments(
|
|
1714
|
+
const task = await client.index(indexUid).deleteDocuments(uniqueDocumentIds);
|
|
1537
1715
|
strapi2.log.info(
|
|
1538
|
-
`A task to delete ${
|
|
1716
|
+
`A task to delete ${uniqueDocumentIds.length} documents of the index "${indexUid}" in Meilisearch has been enqueued (Task uid: ${task.taskUid}).`
|
|
1539
1717
|
);
|
|
1540
1718
|
return task;
|
|
1541
1719
|
})
|
|
@@ -1562,19 +1740,27 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
|
|
|
1562
1740
|
config: config2,
|
|
1563
1741
|
adapter
|
|
1564
1742
|
});
|
|
1565
|
-
const
|
|
1566
|
-
(
|
|
1743
|
+
const addDocumentIds = addDocuments.map(
|
|
1744
|
+
(document) => document._meilisearch_id
|
|
1745
|
+
);
|
|
1746
|
+
const deleteDocuments = entries.map((entry) => {
|
|
1747
|
+
if (entry.documentId == null) return null;
|
|
1748
|
+
return {
|
|
1749
|
+
...entry,
|
|
1750
|
+
_meilisearch_id: adapter.addCollectionNamePrefixToId({
|
|
1751
|
+
contentType: contentType2,
|
|
1752
|
+
entryDocumentId: entry.documentId,
|
|
1753
|
+
locale: entry.locale
|
|
1754
|
+
})
|
|
1755
|
+
};
|
|
1756
|
+
}).filter(
|
|
1757
|
+
(entry) => entry && entry._meilisearch_id != null && !addDocumentIds.includes(entry._meilisearch_id)
|
|
1567
1758
|
);
|
|
1568
1759
|
const deleteTasks = await Promise.all(
|
|
1569
1760
|
indexUids.map(async (indexUid) => {
|
|
1570
1761
|
const tasks = await Promise.all(
|
|
1571
1762
|
deleteDocuments.map(async (document) => {
|
|
1572
|
-
const task = await client.index(indexUid).deleteDocument(
|
|
1573
|
-
adapter.addCollectionNamePrefixToId({
|
|
1574
|
-
contentType: contentType2,
|
|
1575
|
-
entryDocumentId: document.documentId
|
|
1576
|
-
})
|
|
1577
|
-
);
|
|
1763
|
+
const task = await client.index(indexUid).deleteDocument(document._meilisearch_id);
|
|
1578
1764
|
strapi2.log.info(
|
|
1579
1765
|
`A task to delete one document from the Meilisearch index "${indexUid}" has been enqueued (Task uid: ${task.taskUid}).`
|
|
1580
1766
|
);
|
|
@@ -1796,7 +1982,8 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
|
|
|
1796
1982
|
const deleteEntries = async ({ entries, contentType: contentType3 }) => {
|
|
1797
1983
|
await this.deleteEntriesFromMeiliSearch({
|
|
1798
1984
|
contentType: contentType3,
|
|
1799
|
-
documentIds: entries.map((entry) => entry.documentId)
|
|
1985
|
+
documentIds: entries.map((entry) => entry.documentId),
|
|
1986
|
+
entriesQuery: config2.entriesQuery({ contentType: contentType3 })
|
|
1800
1987
|
});
|
|
1801
1988
|
};
|
|
1802
1989
|
await contentTypeService2.actionInBatches({
|
|
@@ -1839,12 +2026,18 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
|
|
|
1839
2026
|
};
|
|
1840
2027
|
const adapterService = ({ strapi: strapi2 }) => {
|
|
1841
2028
|
const contentTypeService2 = strapi2.plugin("meilisearch").service("contentType");
|
|
2029
|
+
const buildMeilisearchId = ({ collectionName, entryDocumentId, locale }) => {
|
|
2030
|
+
if (locale) return `${collectionName}-${entryDocumentId}-${locale}`;
|
|
2031
|
+
return `${collectionName}-${entryDocumentId}`;
|
|
2032
|
+
};
|
|
1842
2033
|
return {
|
|
1843
2034
|
/**
|
|
1844
2035
|
* Add the prefix of the contentType in front of the documentId of its entry.
|
|
1845
2036
|
*
|
|
1846
2037
|
* We do this to avoid id's conflict in case of composite indexes.
|
|
1847
|
-
* It returns the id in the following format:
|
|
2038
|
+
* It returns the id in the following format:
|
|
2039
|
+
* - `[collectionName]-[documentId]` for non-localized entries
|
|
2040
|
+
* - `[collectionName]-[documentId]-[locale]` for localized entries
|
|
1848
2041
|
*
|
|
1849
2042
|
* Uses documentId (stable across draft/published) instead of the internal
|
|
1850
2043
|
* database id to prevent duplicate entries in Meilisearch when Draft & Publish
|
|
@@ -1853,20 +2046,27 @@ const adapterService = ({ strapi: strapi2 }) => {
|
|
|
1853
2046
|
* @param {object} options
|
|
1854
2047
|
* @param {string} options.contentType - ContentType name.
|
|
1855
2048
|
* @param {string} options.entryDocumentId - Entry documentId.
|
|
2049
|
+
* @param {string} options.locale - Entry locale.
|
|
1856
2050
|
*
|
|
1857
2051
|
* @returns {string} - Formatted id
|
|
1858
2052
|
*/
|
|
1859
|
-
addCollectionNamePrefixToId: function({
|
|
2053
|
+
addCollectionNamePrefixToId: function({
|
|
2054
|
+
contentType: contentType2,
|
|
2055
|
+
entryDocumentId,
|
|
2056
|
+
locale
|
|
2057
|
+
}) {
|
|
1860
2058
|
const collectionName = contentTypeService2.getCollectionName({
|
|
1861
2059
|
contentType: contentType2
|
|
1862
2060
|
});
|
|
1863
|
-
return
|
|
2061
|
+
return buildMeilisearchId({ collectionName, entryDocumentId, locale });
|
|
1864
2062
|
},
|
|
1865
2063
|
/**
|
|
1866
2064
|
* Add the prefix of the contentType on a list of entries using documentId.
|
|
1867
2065
|
*
|
|
1868
2066
|
* We do this to avoid id's conflict in case of composite indexes.
|
|
1869
|
-
* The ids are transformed in the following format:
|
|
2067
|
+
* The ids are transformed in the following format:
|
|
2068
|
+
* - `[collectionName]-[documentId]` for non-localized entries
|
|
2069
|
+
* - `[collectionName]-[documentId]-[locale]` for localized entries
|
|
1870
2070
|
*
|
|
1871
2071
|
* @param {object} options
|
|
1872
2072
|
* @param {string} options.contentType - ContentType name.
|
|
@@ -1886,7 +2086,8 @@ const adapterService = ({ strapi: strapi2 }) => {
|
|
|
1886
2086
|
...entry,
|
|
1887
2087
|
_meilisearch_id: this.addCollectionNamePrefixToId({
|
|
1888
2088
|
entryDocumentId: entry.documentId,
|
|
1889
|
-
contentType: contentType2
|
|
2089
|
+
contentType: contentType2,
|
|
2090
|
+
locale: entry.locale
|
|
1890
2091
|
})
|
|
1891
2092
|
});
|
|
1892
2093
|
return acc;
|
package/dist/server/index.mjs
CHANGED
|
@@ -93,6 +93,84 @@ async function registerDocumentMiddleware({ strapi: strapi2 }) {
|
|
|
93
93
|
if (!strapi2?.documents || typeof strapi2.documents.use !== "function") {
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
|
+
const extractEntryCandidates = (result) => {
|
|
97
|
+
if (result == null) return [];
|
|
98
|
+
const candidates = [];
|
|
99
|
+
const appendCandidate = (data, source) => {
|
|
100
|
+
if (data != null && typeof data === "object") {
|
|
101
|
+
candidates.push({ data, source });
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
if (Array.isArray(result)) {
|
|
105
|
+
result.forEach((data) => appendCandidate(data, "root"));
|
|
106
|
+
return candidates;
|
|
107
|
+
}
|
|
108
|
+
appendCandidate(result, "root");
|
|
109
|
+
if (Array.isArray(result.versions)) {
|
|
110
|
+
result.versions.forEach((data) => appendCandidate(data, "versions"));
|
|
111
|
+
}
|
|
112
|
+
if (Array.isArray(result.entries)) {
|
|
113
|
+
result.entries.forEach((data) => appendCandidate(data, "entries"));
|
|
114
|
+
}
|
|
115
|
+
if (result.entry != null) {
|
|
116
|
+
appendCandidate(result.entry, "entry");
|
|
117
|
+
}
|
|
118
|
+
return candidates;
|
|
119
|
+
};
|
|
120
|
+
const isPublishedEntry = (entry) => !(entry?.publishedAt === void 0 || entry?.publishedAt === null);
|
|
121
|
+
const rankEntryCandidates = (candidates) => {
|
|
122
|
+
return [...candidates].sort((a, b) => {
|
|
123
|
+
const aHasPrimaryKey = a.data?.id != null;
|
|
124
|
+
const bHasPrimaryKey = b.data?.id != null;
|
|
125
|
+
if (aHasPrimaryKey && !bHasPrimaryKey) return -1;
|
|
126
|
+
if (!aHasPrimaryKey && bHasPrimaryKey) return 1;
|
|
127
|
+
const aIsRoot = a.source === "root";
|
|
128
|
+
const bIsRoot = b.source === "root";
|
|
129
|
+
if (!aIsRoot && bIsRoot) return -1;
|
|
130
|
+
if (aIsRoot && !bIsRoot) return 1;
|
|
131
|
+
return 0;
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
const getEntryFromResult = ({
|
|
135
|
+
resultCandidates,
|
|
136
|
+
documentId,
|
|
137
|
+
entriesQuery
|
|
138
|
+
}) => {
|
|
139
|
+
const documentCandidates = (resultCandidates || []).filter(
|
|
140
|
+
(candidate) => candidate?.data?.documentId === documentId
|
|
141
|
+
);
|
|
142
|
+
if (documentCandidates.length === 0) return null;
|
|
143
|
+
const rankedCandidates = rankEntryCandidates(documentCandidates);
|
|
144
|
+
if (entriesQuery?.status === "draft") {
|
|
145
|
+
const draftCandidate = rankedCandidates.find(
|
|
146
|
+
(candidate) => !isPublishedEntry(candidate.data)
|
|
147
|
+
);
|
|
148
|
+
return draftCandidate?.data || rankedCandidates[0]?.data || null;
|
|
149
|
+
}
|
|
150
|
+
const publishedCandidate = rankedCandidates.find(
|
|
151
|
+
(candidate) => isPublishedEntry(candidate.data)
|
|
152
|
+
);
|
|
153
|
+
return publishedCandidate?.data || null;
|
|
154
|
+
};
|
|
155
|
+
const getEntryOutsideTransaction = ({
|
|
156
|
+
contentTypeService: contentTypeService2,
|
|
157
|
+
contentType: contentType2,
|
|
158
|
+
documentId,
|
|
159
|
+
entriesQuery
|
|
160
|
+
}) => new Promise((resolve, reject) => {
|
|
161
|
+
setImmediate(async () => {
|
|
162
|
+
try {
|
|
163
|
+
const entry = await contentTypeService2.getEntry({
|
|
164
|
+
contentType: contentType2,
|
|
165
|
+
documentId,
|
|
166
|
+
entriesQuery: { ...entriesQuery }
|
|
167
|
+
});
|
|
168
|
+
resolve(entry);
|
|
169
|
+
} catch (error2) {
|
|
170
|
+
reject(error2);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
});
|
|
96
174
|
strapi2.documents.use(async (ctx, next) => {
|
|
97
175
|
let result;
|
|
98
176
|
try {
|
|
@@ -114,31 +192,72 @@ async function registerDocumentMiddleware({ strapi: strapi2 }) {
|
|
|
114
192
|
"unpublish",
|
|
115
193
|
"discardDraft"
|
|
116
194
|
];
|
|
195
|
+
const entriesQuery = meilisearch2.entriesQuery({ contentType: contentType2 });
|
|
196
|
+
const shouldDeleteByLocale = entriesQuery.locale === "*" || entriesQuery.locale === "all";
|
|
197
|
+
const { status } = entriesQuery || {};
|
|
198
|
+
const statusFilter = typeof status === "string" && status.length > 0 ? { status } : {};
|
|
117
199
|
const preDeleteDocumentId = deleteActions.includes(ctx.action) && ctx?.params?.documentId ? ctx.params.documentId : null;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
200
|
+
let preDeleteEntry = null;
|
|
201
|
+
let preDeleteLocales = [];
|
|
202
|
+
if (preDeleteDocumentId != null) {
|
|
203
|
+
preDeleteEntry = await contentTypeService2.getEntry({
|
|
204
|
+
contentType: contentType2,
|
|
205
|
+
documentId: preDeleteDocumentId,
|
|
206
|
+
entriesQuery: { ...statusFilter }
|
|
207
|
+
});
|
|
208
|
+
if (shouldDeleteByLocale) {
|
|
209
|
+
const localeVariants = await contentTypeService2.getEntries({
|
|
210
|
+
contentType: contentType2,
|
|
211
|
+
fields: ["documentId", "locale"],
|
|
212
|
+
locale: "*",
|
|
213
|
+
...statusFilter,
|
|
214
|
+
filters: {
|
|
215
|
+
documentId: preDeleteDocumentId
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
preDeleteLocales = [
|
|
219
|
+
...new Set(
|
|
220
|
+
localeVariants.map((entry) => entry?.locale).filter(
|
|
221
|
+
(locale) => typeof locale === "string" && locale.length > 0
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
123
227
|
result = await next();
|
|
124
|
-
const
|
|
228
|
+
const contextDocumentId = typeof ctx?.params?.documentId === "string" && ctx.params.documentId.length > 0 ? ctx.params.documentId : null;
|
|
229
|
+
const documentId = contextDocumentId ?? result?.documentId ?? preDeleteEntry?.documentId ?? preDeleteDocumentId ?? null;
|
|
125
230
|
if (updateActions.includes(ctx.action) && documentId != null) {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
231
|
+
const resultCandidates = extractEntryCandidates(result);
|
|
232
|
+
let entry = getEntryFromResult({
|
|
233
|
+
resultCandidates,
|
|
129
234
|
documentId,
|
|
130
|
-
entriesQuery
|
|
235
|
+
entriesQuery
|
|
131
236
|
});
|
|
237
|
+
if (!entry) {
|
|
238
|
+
entry = await getEntryOutsideTransaction({
|
|
239
|
+
contentTypeService: contentTypeService2,
|
|
240
|
+
contentType: contentType2,
|
|
241
|
+
documentId,
|
|
242
|
+
entriesQuery
|
|
243
|
+
});
|
|
244
|
+
}
|
|
132
245
|
if (entry) {
|
|
246
|
+
const normalizedEntry = entry.documentId === documentId ? entry : { ...entry, documentId };
|
|
133
247
|
await meilisearch2.updateEntriesInMeilisearch({
|
|
134
248
|
contentType: contentType2,
|
|
135
|
-
entries: [
|
|
249
|
+
entries: [normalizedEntry]
|
|
136
250
|
});
|
|
137
|
-
} else {
|
|
251
|
+
} else if (ctx.action === "create" || ctx.action === "publish") {
|
|
138
252
|
await meilisearch2.deleteEntriesFromMeiliSearch({
|
|
139
253
|
contentType: contentType2,
|
|
140
|
-
documentIds: [documentId]
|
|
254
|
+
documentIds: [documentId],
|
|
255
|
+
entriesQuery
|
|
141
256
|
});
|
|
257
|
+
} else {
|
|
258
|
+
strapi2.log.info(
|
|
259
|
+
`Meilisearch document middleware skipped indexing ${contentType2} documentId=${documentId} for action ${ctx.action}: no indexable entry in result payload`
|
|
260
|
+
);
|
|
142
261
|
}
|
|
143
262
|
} else if (deleteActions.includes(ctx.action)) {
|
|
144
263
|
if (documentId != null) {
|
|
@@ -147,7 +266,9 @@ async function registerDocumentMiddleware({ strapi: strapi2 }) {
|
|
|
147
266
|
);
|
|
148
267
|
await meilisearch2.deleteEntriesFromMeiliSearch({
|
|
149
268
|
contentType: contentType2,
|
|
150
|
-
documentIds: [documentId]
|
|
269
|
+
documentIds: [documentId],
|
|
270
|
+
entriesQuery,
|
|
271
|
+
locales: shouldDeleteByLocale && preDeleteLocales.length > 0 ? preDeleteLocales : void 0
|
|
151
272
|
});
|
|
152
273
|
} else {
|
|
153
274
|
strapi2.log.info(
|
|
@@ -1232,6 +1353,7 @@ const store = ({ strapi: strapi2 }) => {
|
|
|
1232
1353
|
...createStoreConnector({ strapi: strapi2 })
|
|
1233
1354
|
};
|
|
1234
1355
|
};
|
|
1356
|
+
const isWildcardLocale = (locale) => locale === "all" || locale === "*";
|
|
1235
1357
|
const aborted = ({ contentType: contentType2, action }) => {
|
|
1236
1358
|
strapi.log.error(
|
|
1237
1359
|
`Indexing of ${contentType2} aborted as the data could not be ${action}`
|
|
@@ -1440,7 +1562,7 @@ const configurationService = ({ strapi: strapi2 }) => {
|
|
|
1440
1562
|
const collection = contentTypeService2.getCollectionName({ contentType: contentType2 });
|
|
1441
1563
|
const contentTypeConfig = meilisearchConfig[collection] || {};
|
|
1442
1564
|
const entriesQuery = contentTypeConfig.entriesQuery || {};
|
|
1443
|
-
if (!entriesQuery.locale || entriesQuery.locale
|
|
1565
|
+
if (!entriesQuery.locale || isWildcardLocale(entriesQuery.locale)) {
|
|
1444
1566
|
return entries;
|
|
1445
1567
|
} else {
|
|
1446
1568
|
return entries.filter((entry) => entry.locale === entriesQuery.locale);
|
|
@@ -1448,7 +1570,7 @@ const configurationService = ({ strapi: strapi2 }) => {
|
|
|
1448
1570
|
}
|
|
1449
1571
|
};
|
|
1450
1572
|
};
|
|
1451
|
-
const version = "0.
|
|
1573
|
+
const version = "0.16.1";
|
|
1452
1574
|
const Meilisearch = (config2) => {
|
|
1453
1575
|
return new MeiliSearch({
|
|
1454
1576
|
...config2,
|
|
@@ -1515,26 +1637,82 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
|
|
|
1515
1637
|
* @param {object} options
|
|
1516
1638
|
* @param {string} options.contentType - ContentType name.
|
|
1517
1639
|
* @param {string[]} options.documentIds - Entry documentIds.
|
|
1640
|
+
* @param {object} options.entriesQuery - Entries query.
|
|
1518
1641
|
*
|
|
1519
1642
|
* @returns { Promise<import("meilisearch").Task>} p - Task body returned by Meilisearch API.
|
|
1520
1643
|
*/
|
|
1521
1644
|
deleteEntriesFromMeiliSearch: async function({
|
|
1522
1645
|
contentType: contentType2,
|
|
1523
|
-
documentIds
|
|
1646
|
+
documentIds,
|
|
1647
|
+
entriesQuery = {},
|
|
1648
|
+
locales
|
|
1524
1649
|
}) {
|
|
1525
1650
|
const { apiKey, host } = await store2.getCredentials();
|
|
1526
1651
|
const client = Meilisearch({ apiKey, host });
|
|
1527
1652
|
const indexUids = config2.getIndexNamesOfContentType({ contentType: contentType2 });
|
|
1528
|
-
const validDocumentIds =
|
|
1653
|
+
const validDocumentIds = [
|
|
1654
|
+
...new Set(documentIds.filter((id) => id != null))
|
|
1655
|
+
];
|
|
1529
1656
|
if (validDocumentIds.length === 0) return [];
|
|
1530
|
-
const
|
|
1531
|
-
|
|
1657
|
+
const resolvedEntriesQuery = Object.keys(entriesQuery).length > 0 ? entriesQuery : config2.entriesQuery({ contentType: contentType2 });
|
|
1658
|
+
const shouldDeleteAllLocaleVariants = isWildcardLocale(
|
|
1659
|
+
resolvedEntriesQuery.locale
|
|
1660
|
+
);
|
|
1661
|
+
const resolvedLocales = Array.isArray(locales) ? [
|
|
1662
|
+
...new Set(
|
|
1663
|
+
locales.filter(
|
|
1664
|
+
(locale) => typeof locale === "string" && locale.trim().length > 0
|
|
1665
|
+
).map((locale) => locale.trim())
|
|
1666
|
+
)
|
|
1667
|
+
] : [];
|
|
1668
|
+
const meilisearchDocumentIds = shouldDeleteAllLocaleVariants && resolvedLocales.length > 0 ? validDocumentIds.flatMap(
|
|
1669
|
+
(entryDocumentId) => resolvedLocales.map(
|
|
1670
|
+
(resolvedLocale) => adapter.addCollectionNamePrefixToId({
|
|
1671
|
+
contentType: contentType2,
|
|
1672
|
+
entryDocumentId,
|
|
1673
|
+
locale: resolvedLocale
|
|
1674
|
+
})
|
|
1675
|
+
)
|
|
1676
|
+
) : shouldDeleteAllLocaleVariants ? (await Promise.all(
|
|
1677
|
+
validDocumentIds.map(async (entryDocumentId) => {
|
|
1678
|
+
const baseFilters = resolvedEntriesQuery.filters != null ? resolvedEntriesQuery.filters : {};
|
|
1679
|
+
const localizedEntries = await contentTypeService2.getEntries({
|
|
1680
|
+
contentType: contentType2,
|
|
1681
|
+
fields: ["documentId", "locale"],
|
|
1682
|
+
locale: "*",
|
|
1683
|
+
...resolvedEntriesQuery.status ? { status: resolvedEntriesQuery.status } : {},
|
|
1684
|
+
filters: {
|
|
1685
|
+
...baseFilters,
|
|
1686
|
+
documentId: entryDocumentId
|
|
1687
|
+
}
|
|
1688
|
+
});
|
|
1689
|
+
return localizedEntries.length > 0 ? localizedEntries.map(
|
|
1690
|
+
(entry) => adapter.addCollectionNamePrefixToId({
|
|
1691
|
+
contentType: contentType2,
|
|
1692
|
+
entryDocumentId,
|
|
1693
|
+
locale: entry.locale
|
|
1694
|
+
})
|
|
1695
|
+
) : [
|
|
1696
|
+
// Fallback: delete the non-localized document when no localized variants exist.
|
|
1697
|
+
adapter.addCollectionNamePrefixToId({
|
|
1698
|
+
contentType: contentType2,
|
|
1699
|
+
entryDocumentId
|
|
1700
|
+
})
|
|
1701
|
+
];
|
|
1702
|
+
})
|
|
1703
|
+
)).flat() : validDocumentIds.map(
|
|
1704
|
+
(entryDocumentId) => adapter.addCollectionNamePrefixToId({
|
|
1705
|
+
entryDocumentId,
|
|
1706
|
+
contentType: contentType2,
|
|
1707
|
+
locale: resolvedEntriesQuery.locale
|
|
1708
|
+
})
|
|
1532
1709
|
);
|
|
1710
|
+
const uniqueDocumentIds = [...new Set(meilisearchDocumentIds)];
|
|
1533
1711
|
const tasks = await Promise.all(
|
|
1534
1712
|
indexUids.map(async (indexUid) => {
|
|
1535
|
-
const task = await client.index(indexUid).deleteDocuments(
|
|
1713
|
+
const task = await client.index(indexUid).deleteDocuments(uniqueDocumentIds);
|
|
1536
1714
|
strapi2.log.info(
|
|
1537
|
-
`A task to delete ${
|
|
1715
|
+
`A task to delete ${uniqueDocumentIds.length} documents of the index "${indexUid}" in Meilisearch has been enqueued (Task uid: ${task.taskUid}).`
|
|
1538
1716
|
);
|
|
1539
1717
|
return task;
|
|
1540
1718
|
})
|
|
@@ -1561,19 +1739,27 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
|
|
|
1561
1739
|
config: config2,
|
|
1562
1740
|
adapter
|
|
1563
1741
|
});
|
|
1564
|
-
const
|
|
1565
|
-
(
|
|
1742
|
+
const addDocumentIds = addDocuments.map(
|
|
1743
|
+
(document) => document._meilisearch_id
|
|
1744
|
+
);
|
|
1745
|
+
const deleteDocuments = entries.map((entry) => {
|
|
1746
|
+
if (entry.documentId == null) return null;
|
|
1747
|
+
return {
|
|
1748
|
+
...entry,
|
|
1749
|
+
_meilisearch_id: adapter.addCollectionNamePrefixToId({
|
|
1750
|
+
contentType: contentType2,
|
|
1751
|
+
entryDocumentId: entry.documentId,
|
|
1752
|
+
locale: entry.locale
|
|
1753
|
+
})
|
|
1754
|
+
};
|
|
1755
|
+
}).filter(
|
|
1756
|
+
(entry) => entry && entry._meilisearch_id != null && !addDocumentIds.includes(entry._meilisearch_id)
|
|
1566
1757
|
);
|
|
1567
1758
|
const deleteTasks = await Promise.all(
|
|
1568
1759
|
indexUids.map(async (indexUid) => {
|
|
1569
1760
|
const tasks = await Promise.all(
|
|
1570
1761
|
deleteDocuments.map(async (document) => {
|
|
1571
|
-
const task = await client.index(indexUid).deleteDocument(
|
|
1572
|
-
adapter.addCollectionNamePrefixToId({
|
|
1573
|
-
contentType: contentType2,
|
|
1574
|
-
entryDocumentId: document.documentId
|
|
1575
|
-
})
|
|
1576
|
-
);
|
|
1762
|
+
const task = await client.index(indexUid).deleteDocument(document._meilisearch_id);
|
|
1577
1763
|
strapi2.log.info(
|
|
1578
1764
|
`A task to delete one document from the Meilisearch index "${indexUid}" has been enqueued (Task uid: ${task.taskUid}).`
|
|
1579
1765
|
);
|
|
@@ -1795,7 +1981,8 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
|
|
|
1795
1981
|
const deleteEntries = async ({ entries, contentType: contentType3 }) => {
|
|
1796
1982
|
await this.deleteEntriesFromMeiliSearch({
|
|
1797
1983
|
contentType: contentType3,
|
|
1798
|
-
documentIds: entries.map((entry) => entry.documentId)
|
|
1984
|
+
documentIds: entries.map((entry) => entry.documentId),
|
|
1985
|
+
entriesQuery: config2.entriesQuery({ contentType: contentType3 })
|
|
1799
1986
|
});
|
|
1800
1987
|
};
|
|
1801
1988
|
await contentTypeService2.actionInBatches({
|
|
@@ -1838,12 +2025,18 @@ const connectorService = ({ strapi: strapi2, adapter, config: config2 }) => {
|
|
|
1838
2025
|
};
|
|
1839
2026
|
const adapterService = ({ strapi: strapi2 }) => {
|
|
1840
2027
|
const contentTypeService2 = strapi2.plugin("meilisearch").service("contentType");
|
|
2028
|
+
const buildMeilisearchId = ({ collectionName, entryDocumentId, locale }) => {
|
|
2029
|
+
if (locale) return `${collectionName}-${entryDocumentId}-${locale}`;
|
|
2030
|
+
return `${collectionName}-${entryDocumentId}`;
|
|
2031
|
+
};
|
|
1841
2032
|
return {
|
|
1842
2033
|
/**
|
|
1843
2034
|
* Add the prefix of the contentType in front of the documentId of its entry.
|
|
1844
2035
|
*
|
|
1845
2036
|
* We do this to avoid id's conflict in case of composite indexes.
|
|
1846
|
-
* It returns the id in the following format:
|
|
2037
|
+
* It returns the id in the following format:
|
|
2038
|
+
* - `[collectionName]-[documentId]` for non-localized entries
|
|
2039
|
+
* - `[collectionName]-[documentId]-[locale]` for localized entries
|
|
1847
2040
|
*
|
|
1848
2041
|
* Uses documentId (stable across draft/published) instead of the internal
|
|
1849
2042
|
* database id to prevent duplicate entries in Meilisearch when Draft & Publish
|
|
@@ -1852,20 +2045,27 @@ const adapterService = ({ strapi: strapi2 }) => {
|
|
|
1852
2045
|
* @param {object} options
|
|
1853
2046
|
* @param {string} options.contentType - ContentType name.
|
|
1854
2047
|
* @param {string} options.entryDocumentId - Entry documentId.
|
|
2048
|
+
* @param {string} options.locale - Entry locale.
|
|
1855
2049
|
*
|
|
1856
2050
|
* @returns {string} - Formatted id
|
|
1857
2051
|
*/
|
|
1858
|
-
addCollectionNamePrefixToId: function({
|
|
2052
|
+
addCollectionNamePrefixToId: function({
|
|
2053
|
+
contentType: contentType2,
|
|
2054
|
+
entryDocumentId,
|
|
2055
|
+
locale
|
|
2056
|
+
}) {
|
|
1859
2057
|
const collectionName = contentTypeService2.getCollectionName({
|
|
1860
2058
|
contentType: contentType2
|
|
1861
2059
|
});
|
|
1862
|
-
return
|
|
2060
|
+
return buildMeilisearchId({ collectionName, entryDocumentId, locale });
|
|
1863
2061
|
},
|
|
1864
2062
|
/**
|
|
1865
2063
|
* Add the prefix of the contentType on a list of entries using documentId.
|
|
1866
2064
|
*
|
|
1867
2065
|
* We do this to avoid id's conflict in case of composite indexes.
|
|
1868
|
-
* The ids are transformed in the following format:
|
|
2066
|
+
* The ids are transformed in the following format:
|
|
2067
|
+
* - `[collectionName]-[documentId]` for non-localized entries
|
|
2068
|
+
* - `[collectionName]-[documentId]-[locale]` for localized entries
|
|
1869
2069
|
*
|
|
1870
2070
|
* @param {object} options
|
|
1871
2071
|
* @param {string} options.contentType - ContentType name.
|
|
@@ -1885,7 +2085,8 @@ const adapterService = ({ strapi: strapi2 }) => {
|
|
|
1885
2085
|
...entry,
|
|
1886
2086
|
_meilisearch_id: this.addCollectionNamePrefixToId({
|
|
1887
2087
|
entryDocumentId: entry.documentId,
|
|
1888
|
-
contentType: contentType2
|
|
2088
|
+
contentType: contentType2,
|
|
2089
|
+
locale: entry.locale
|
|
1889
2090
|
})
|
|
1890
2091
|
});
|
|
1891
2092
|
return acc;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strapi-plugin-meilisearch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Synchronise and search in your Strapi content-types with Meilisearch",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "strapi-plugin build",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"@strapi/strapi": "^5.6.0",
|
|
65
65
|
"@types/jest": "^30.0.0",
|
|
66
66
|
"babel-jest": "^30.2.0",
|
|
67
|
+
"better-sqlite3": "^12.8.0",
|
|
67
68
|
"concurrently": "^9.2.1",
|
|
68
69
|
"cypress": "^15.11.0",
|
|
69
70
|
"eslint": "^10.0.2",
|