strapi-plugin-bulk-updater 1.2.13 → 1.3.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/README.md +10 -4
- package/dist/_chunks/{BulkUpdater-CWJYmuGU.js → BulkUpdater-CRvwX326.js} +261 -33
- package/dist/_chunks/BulkUpdater-CRvwX326.js.map +1 -0
- package/dist/_chunks/{BulkUpdater-Cfig2f7d.mjs → BulkUpdater-DowSmA56.mjs} +261 -33
- package/dist/_chunks/BulkUpdater-DowSmA56.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +250 -125
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +250 -125
- package/dist/server/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/_chunks/BulkUpdater-CWJYmuGU.js.map +0 -1
- package/dist/_chunks/BulkUpdater-Cfig2f7d.mjs.map +0 -1
package/dist/admin/index.js
CHANGED
|
@@ -10,7 +10,7 @@ const index = {
|
|
|
10
10
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
11
11
|
defaultMessage: "Bulk Attribute Updater"
|
|
12
12
|
},
|
|
13
|
-
Component: () => Promise.resolve().then(() => require("../_chunks/BulkUpdater-
|
|
13
|
+
Component: () => Promise.resolve().then(() => require("../_chunks/BulkUpdater-CRvwX326.js")),
|
|
14
14
|
permissions: [],
|
|
15
15
|
position: 3
|
|
16
16
|
});
|
package/dist/admin/index.mjs
CHANGED
|
@@ -9,7 +9,7 @@ const index = {
|
|
|
9
9
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
10
10
|
defaultMessage: "Bulk Attribute Updater"
|
|
11
11
|
},
|
|
12
|
-
Component: () => import("../_chunks/BulkUpdater-
|
|
12
|
+
Component: () => import("../_chunks/BulkUpdater-DowSmA56.mjs"),
|
|
13
13
|
permissions: [],
|
|
14
14
|
position: 3
|
|
15
15
|
});
|
package/dist/server/index.js
CHANGED
|
@@ -328,12 +328,13 @@ const bulkUpdaterController = ({ strapi: strapi2 }) => ({
|
|
|
328
328
|
async getCollectionEntries(ctx) {
|
|
329
329
|
try {
|
|
330
330
|
const { uid } = ctx.params;
|
|
331
|
-
const { page, pageSize, attribute, filterOperator, filterQuery, search, sortField, sortOrder } = ctx.query;
|
|
331
|
+
const { page, pageSize, attribute, searchAttribute, filterOperator, filterQuery, search, sortField, sortOrder } = ctx.query;
|
|
332
332
|
const service = strapi2.plugin("bulk-updater").service("bulkUpdater");
|
|
333
333
|
const data = await service.getCollectionEntries(uid, {
|
|
334
334
|
page: page ? Number(page) : 1,
|
|
335
335
|
pageSize: pageSize ? Number(pageSize) : 10,
|
|
336
336
|
attribute: attribute ? String(attribute) : void 0,
|
|
337
|
+
searchAttribute: searchAttribute ? String(searchAttribute) : void 0,
|
|
337
338
|
filterOperator: filterOperator ? String(filterOperator) : void 0,
|
|
338
339
|
filterQuery: filterQuery !== void 0 ? String(filterQuery) : void 0,
|
|
339
340
|
search: search ? String(search) : void 0,
|
|
@@ -692,6 +693,132 @@ const modelsCache = /* @__PURE__ */ new Map();
|
|
|
692
693
|
const MAX_QUERY_CACHE_SIZE = 500;
|
|
693
694
|
const CACHE_TTL_MS = 60 * 1e3;
|
|
694
695
|
let staticSchemaCache = null;
|
|
696
|
+
function buildDeepPopulate$1(attributes, allComponents, depth2 = 0) {
|
|
697
|
+
if (depth2 > 5) return void 0;
|
|
698
|
+
const populate2 = {};
|
|
699
|
+
for (const [key, def] of Object.entries(attributes || {})) {
|
|
700
|
+
if (def.type === "component" && def.component) {
|
|
701
|
+
const comp = allComponents[def.component];
|
|
702
|
+
if (comp?.attributes) {
|
|
703
|
+
const subPopulate = buildDeepPopulate$1(comp.attributes, allComponents, depth2 + 1);
|
|
704
|
+
if (subPopulate && Object.keys(subPopulate).length > 0) {
|
|
705
|
+
populate2[key] = {
|
|
706
|
+
populate: subPopulate
|
|
707
|
+
};
|
|
708
|
+
} else {
|
|
709
|
+
populate2[key] = true;
|
|
710
|
+
}
|
|
711
|
+
} else {
|
|
712
|
+
populate2[key] = true;
|
|
713
|
+
}
|
|
714
|
+
} else if (def.type === "dynamiczone") {
|
|
715
|
+
populate2[key] = true;
|
|
716
|
+
} else if (def.type === "relation" || def.type === "media") {
|
|
717
|
+
populate2[key] = true;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return Object.keys(populate2).length > 0 ? populate2 : void 0;
|
|
721
|
+
}
|
|
722
|
+
function discoverComponentAttributes(strapi2, compUid, prefix, currentDepth, maxDepth, systemFields, allContentTypes, relationsByAttr, allRelationsMeta, attributesMeta) {
|
|
723
|
+
if (currentDepth > maxDepth || !compUid) return [];
|
|
724
|
+
const compSchema = strapi2.components[compUid];
|
|
725
|
+
if (!compSchema?.attributes) return [];
|
|
726
|
+
const discoveredAttrs = [];
|
|
727
|
+
for (const [subKey, subAttr] of Object.entries(compSchema.attributes)) {
|
|
728
|
+
if (systemFields.includes(subKey)) continue;
|
|
729
|
+
if (subAttr.type === "dynamiczone") continue;
|
|
730
|
+
const fullPath = prefix ? `${prefix}.${subKey}` : subKey;
|
|
731
|
+
if (subAttr.type === "component") {
|
|
732
|
+
if (!subAttr.repeatable && subAttr.component) {
|
|
733
|
+
const deeper = discoverComponentAttributes(
|
|
734
|
+
strapi2,
|
|
735
|
+
subAttr.component,
|
|
736
|
+
fullPath,
|
|
737
|
+
currentDepth + 1,
|
|
738
|
+
maxDepth,
|
|
739
|
+
systemFields,
|
|
740
|
+
allContentTypes,
|
|
741
|
+
relationsByAttr,
|
|
742
|
+
allRelationsMeta,
|
|
743
|
+
attributesMeta
|
|
744
|
+
);
|
|
745
|
+
discoveredAttrs.push(...deeper);
|
|
746
|
+
}
|
|
747
|
+
} else if (subAttr.type === "relation") {
|
|
748
|
+
const targetUid = subAttr.target;
|
|
749
|
+
if (targetUid && allContentTypes[targetUid]) {
|
|
750
|
+
const targetInfo = allContentTypes[targetUid]?.info;
|
|
751
|
+
const isMulti = subAttr.relation === "oneToMany" || subAttr.relation === "manyToMany";
|
|
752
|
+
const relMeta = {
|
|
753
|
+
isRelation: true,
|
|
754
|
+
relationType: subAttr.relation,
|
|
755
|
+
targetUid,
|
|
756
|
+
targetDisplayName: targetInfo?.displayName || targetUid,
|
|
757
|
+
isMulti
|
|
758
|
+
};
|
|
759
|
+
relationsByAttr[fullPath] = relMeta;
|
|
760
|
+
allRelationsMeta[fullPath] = relMeta;
|
|
761
|
+
attributesMeta[fullPath] = { depth: currentDepth, type: "relation", component: compUid, isRelation: true };
|
|
762
|
+
discoveredAttrs.push(fullPath);
|
|
763
|
+
}
|
|
764
|
+
} else {
|
|
765
|
+
attributesMeta[fullPath] = { depth: currentDepth, type: subAttr.type, component: compUid };
|
|
766
|
+
discoveredAttrs.push(fullPath);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return discoveredAttrs;
|
|
770
|
+
}
|
|
771
|
+
function isDeepComponentField(contentType, allComponents, attribute) {
|
|
772
|
+
if (!attribute || !attribute.includes(".")) return false;
|
|
773
|
+
const parts = attribute.split(".");
|
|
774
|
+
let currentSchema = contentType;
|
|
775
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
776
|
+
const part = parts[i];
|
|
777
|
+
const attrDef = currentSchema?.attributes?.[part];
|
|
778
|
+
if (!attrDef || attrDef.type !== "component" || !attrDef.component) return false;
|
|
779
|
+
currentSchema = allComponents[attrDef.component];
|
|
780
|
+
if (!currentSchema) return false;
|
|
781
|
+
}
|
|
782
|
+
const leafField = parts[parts.length - 1];
|
|
783
|
+
return Boolean(currentSchema?.attributes?.[leafField]);
|
|
784
|
+
}
|
|
785
|
+
function getLeafAttributeSchema(contentType, allComponents, attribute) {
|
|
786
|
+
if (!attribute) return null;
|
|
787
|
+
if (!attribute.includes(".")) return contentType?.attributes?.[attribute] || null;
|
|
788
|
+
const parts = attribute.split(".");
|
|
789
|
+
let currentSchema = contentType;
|
|
790
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
791
|
+
const part = parts[i];
|
|
792
|
+
const attrDef = currentSchema?.attributes?.[part];
|
|
793
|
+
if (!attrDef || attrDef.type !== "component" || !attrDef.component) return null;
|
|
794
|
+
currentSchema = allComponents[attrDef.component];
|
|
795
|
+
if (!currentSchema) return null;
|
|
796
|
+
}
|
|
797
|
+
return currentSchema?.attributes?.[parts[parts.length - 1]] || null;
|
|
798
|
+
}
|
|
799
|
+
function setDeepProperty(obj, pathParts, value) {
|
|
800
|
+
if (pathParts.length === 0) return value;
|
|
801
|
+
const current = { ...obj || {} };
|
|
802
|
+
const [head, ...tail] = pathParts;
|
|
803
|
+
if (tail.length === 0) {
|
|
804
|
+
current[head] = value;
|
|
805
|
+
} else {
|
|
806
|
+
current[head] = setDeepProperty(current[head] || {}, tail, value);
|
|
807
|
+
}
|
|
808
|
+
return current;
|
|
809
|
+
}
|
|
810
|
+
function getDeepProperty(obj, path2) {
|
|
811
|
+
if (!obj || !path2) return void 0;
|
|
812
|
+
if (!path2.includes(".")) return obj[path2];
|
|
813
|
+
return path2.split(".").reduce((acc, part) => acc && typeof acc === "object" ? acc[part] : void 0, obj);
|
|
814
|
+
}
|
|
815
|
+
function buildDeepFilter(pathParts, condition) {
|
|
816
|
+
if (pathParts.length === 0) return condition;
|
|
817
|
+
const [head, ...tail] = pathParts;
|
|
818
|
+
return {
|
|
819
|
+
[head]: buildDeepFilter(tail, condition)
|
|
820
|
+
};
|
|
821
|
+
}
|
|
695
822
|
function getSafeTimezone(timeZone) {
|
|
696
823
|
if (!timeZone || typeof timeZone !== "string") {
|
|
697
824
|
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
@@ -900,43 +1027,30 @@ async function executeBatchInternal(strapi2, {
|
|
|
900
1027
|
const currentEntry = await getDocumentDeduplicated(target.uid, target.documentId);
|
|
901
1028
|
const entryLabel = currentEntry?.name || currentEntry?.title || currentEntry?.email || `Entry #${target.documentId}`;
|
|
902
1029
|
const isNested = attribute.includes(".");
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
if (isNested) {
|
|
907
|
-
const parts = attribute.split(".");
|
|
908
|
-
parentKey = parts[0];
|
|
909
|
-
childKey = parts[1];
|
|
910
|
-
const parentAttrDef = contentType?.attributes?.[parentKey];
|
|
911
|
-
if (parentAttrDef?.type === "component" && !parentAttrDef.repeatable && parentAttrDef.component) {
|
|
912
|
-
const compSchema = strapi2.components[parentAttrDef.component];
|
|
913
|
-
if (compSchema?.attributes?.[childKey]) {
|
|
914
|
-
isComponentNested = true;
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
}
|
|
1030
|
+
const isComponentNested = isNested && isDeepComponentField(contentType, strapi2.components, attribute);
|
|
1031
|
+
const parts = isNested ? attribute.split(".") : [];
|
|
1032
|
+
const rootKey = isNested ? parts[0] : "";
|
|
918
1033
|
const attrDef = contentType?.attributes?.[attribute];
|
|
919
1034
|
const hasAttribute = Boolean(attrDef) || isComponentNested;
|
|
920
1035
|
if (hasAttribute) {
|
|
921
1036
|
if (isComponentNested) {
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
const
|
|
1037
|
+
const populateOption = buildDeepPopulate$1(contentType.attributes, strapi2.components);
|
|
1038
|
+
const findOneArgs = { documentId: target.documentId };
|
|
1039
|
+
if (populateOption) {
|
|
1040
|
+
findOneArgs.populate = populateOption;
|
|
1041
|
+
}
|
|
1042
|
+
const currentEntryWithPopulate = await strapi2.documents(target.uid).findOne(findOneArgs);
|
|
1043
|
+
const existingRoot = currentEntryWithPopulate?.[rootKey] || {};
|
|
1044
|
+
const currentVal2 = getDeepProperty(existingRoot, parts.slice(1).join("."));
|
|
928
1045
|
let newValue2 = value;
|
|
929
1046
|
if (regexObj && typeof currentVal2 === "string") {
|
|
930
1047
|
newValue2 = currentVal2.replace(regexObj, value);
|
|
931
1048
|
}
|
|
932
|
-
const
|
|
933
|
-
...existingParent,
|
|
934
|
-
[childKey]: newValue2
|
|
935
|
-
};
|
|
1049
|
+
const updatedRoot = setDeepProperty(existingRoot, parts.slice(1), newValue2);
|
|
936
1050
|
await strapi2.documents(target.uid).update({
|
|
937
1051
|
documentId: target.documentId,
|
|
938
1052
|
data: {
|
|
939
|
-
[
|
|
1053
|
+
[rootKey]: updatedRoot
|
|
940
1054
|
}
|
|
941
1055
|
});
|
|
942
1056
|
const isDraftAndPublishComp = Boolean(contentType?.options?.draftAndPublish);
|
|
@@ -1371,12 +1485,14 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1371
1485
|
}
|
|
1372
1486
|
const metaByUid = {};
|
|
1373
1487
|
const allRelationsMeta = {};
|
|
1488
|
+
const allAttributesMeta = {};
|
|
1374
1489
|
for (const uid of targetUids) {
|
|
1375
1490
|
const contentType = allContentTypes[uid];
|
|
1376
1491
|
if (!contentType || contentType.kind !== "collectionType" && contentType.kind !== "singleType") continue;
|
|
1377
1492
|
const isSingleType = contentType.kind === "singleType";
|
|
1378
1493
|
const rawAttrs = contentType.attributes || {};
|
|
1379
1494
|
const relationsByAttr = {};
|
|
1495
|
+
const colAttributesMeta = {};
|
|
1380
1496
|
const nestedComponentAttrs = [];
|
|
1381
1497
|
const validAttrs = Object.keys(rawAttrs).filter((attrKey) => {
|
|
1382
1498
|
if (systemFields.includes(attrKey)) return false;
|
|
@@ -1384,14 +1500,19 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1384
1500
|
if (rawAttrs[attrKey].type === "component") {
|
|
1385
1501
|
const compDef = rawAttrs[attrKey];
|
|
1386
1502
|
if (!compDef.repeatable && compDef.component) {
|
|
1387
|
-
const
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1503
|
+
const compAttrs = discoverComponentAttributes(
|
|
1504
|
+
strapi2,
|
|
1505
|
+
compDef.component,
|
|
1506
|
+
attrKey,
|
|
1507
|
+
1,
|
|
1508
|
+
5,
|
|
1509
|
+
systemFields,
|
|
1510
|
+
allContentTypes,
|
|
1511
|
+
relationsByAttr,
|
|
1512
|
+
allRelationsMeta,
|
|
1513
|
+
colAttributesMeta
|
|
1514
|
+
);
|
|
1515
|
+
nestedComponentAttrs.push(...compAttrs);
|
|
1395
1516
|
}
|
|
1396
1517
|
return false;
|
|
1397
1518
|
}
|
|
@@ -1410,12 +1531,19 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1410
1531
|
};
|
|
1411
1532
|
relationsByAttr[attrKey] = relMeta;
|
|
1412
1533
|
allRelationsMeta[attrKey] = relMeta;
|
|
1534
|
+
colAttributesMeta[attrKey] = { depth: 0, type: "relation", isRelation: true };
|
|
1413
1535
|
return true;
|
|
1414
1536
|
}
|
|
1537
|
+
colAttributesMeta[attrKey] = { depth: 0, type: rawAttrs[attrKey].type };
|
|
1415
1538
|
return true;
|
|
1416
1539
|
});
|
|
1417
1540
|
const allColAttrs = [...validAttrs, ...nestedComponentAttrs];
|
|
1418
|
-
allColAttrs.forEach((attr) =>
|
|
1541
|
+
allColAttrs.forEach((attr) => {
|
|
1542
|
+
allAttributesSet.add(attr);
|
|
1543
|
+
if (colAttributesMeta[attr]) {
|
|
1544
|
+
allAttributesMeta[attr] = colAttributesMeta[attr];
|
|
1545
|
+
}
|
|
1546
|
+
});
|
|
1419
1547
|
metaByUid[uid] = {
|
|
1420
1548
|
uid,
|
|
1421
1549
|
kind: contentType.kind,
|
|
@@ -1425,11 +1553,13 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1425
1553
|
pluralName: contentType.info?.pluralName || uid,
|
|
1426
1554
|
displayName: contentType.info?.displayName || uid,
|
|
1427
1555
|
attributes: allColAttrs,
|
|
1556
|
+
attributesMeta: colAttributesMeta,
|
|
1428
1557
|
relations: relationsByAttr
|
|
1429
1558
|
};
|
|
1430
1559
|
}
|
|
1431
1560
|
staticSchemaCache = {
|
|
1432
1561
|
attributes: Array.from(allAttributesSet),
|
|
1562
|
+
attributesMeta: allAttributesMeta,
|
|
1433
1563
|
targetUids: Object.keys(metaByUid),
|
|
1434
1564
|
metaByUid,
|
|
1435
1565
|
relationsMeta: allRelationsMeta
|
|
@@ -1460,32 +1590,27 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1460
1590
|
let entries = [];
|
|
1461
1591
|
let totalCount = 0;
|
|
1462
1592
|
try {
|
|
1463
|
-
const
|
|
1464
|
-
const relKeys = Object.keys(meta.relations || {});
|
|
1465
|
-
const compKeys = Object.keys(ctAttrs).filter((k) => ctAttrs[k].type === "component");
|
|
1466
|
-
const populateOptionObj = {};
|
|
1467
|
-
relKeys.forEach((k) => {
|
|
1468
|
-
populateOptionObj[k] = true;
|
|
1469
|
-
});
|
|
1470
|
-
compKeys.forEach((k) => {
|
|
1471
|
-
populateOptionObj[k] = true;
|
|
1472
|
-
});
|
|
1473
|
-
const populateOption = Object.keys(populateOptionObj).length > 0 ? populateOptionObj : void 0;
|
|
1593
|
+
const populateOption = buildDeepPopulate$1(allContentTypes[uid]?.attributes || {}, strapi2.components);
|
|
1474
1594
|
if (meta.isSingleType) {
|
|
1475
|
-
const
|
|
1476
|
-
|
|
1477
|
-
|
|
1595
|
+
const singleArgs = {};
|
|
1596
|
+
if (populateOption) {
|
|
1597
|
+
singleArgs.populate = populateOption;
|
|
1598
|
+
}
|
|
1599
|
+
const singleDoc = await strapi2.documents(uid).findFirst(singleArgs);
|
|
1478
1600
|
if (singleDoc) {
|
|
1479
1601
|
entries = [singleDoc];
|
|
1480
1602
|
totalCount = 1;
|
|
1481
1603
|
}
|
|
1482
1604
|
} else {
|
|
1483
1605
|
totalCount = await strapi2.documents(uid).count();
|
|
1484
|
-
|
|
1606
|
+
const findArgs = {
|
|
1485
1607
|
limit: 10,
|
|
1486
|
-
sort: { createdAt: "desc" }
|
|
1487
|
-
|
|
1488
|
-
|
|
1608
|
+
sort: { createdAt: "desc" }
|
|
1609
|
+
};
|
|
1610
|
+
if (populateOption) {
|
|
1611
|
+
findArgs.populate = populateOption;
|
|
1612
|
+
}
|
|
1613
|
+
entries = await strapi2.documents(uid).findMany(findArgs);
|
|
1489
1614
|
}
|
|
1490
1615
|
} catch (err) {
|
|
1491
1616
|
strapi2.log.error(`[bulk-updater] Failed to fetch entries for ${uid}:`, err);
|
|
@@ -1529,8 +1654,10 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1529
1654
|
return {
|
|
1530
1655
|
success: true,
|
|
1531
1656
|
attributes: staticSchemaCache.attributes,
|
|
1657
|
+
attributesMeta: staticSchemaCache.attributesMeta,
|
|
1532
1658
|
collections,
|
|
1533
1659
|
relationsMeta: staticSchemaCache.relationsMeta,
|
|
1660
|
+
maxDiscoveredDepth: 5,
|
|
1534
1661
|
executionWindow: {
|
|
1535
1662
|
...executionConfig,
|
|
1536
1663
|
...windowStatus
|
|
@@ -1549,6 +1676,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1549
1676
|
page = 1,
|
|
1550
1677
|
pageSize = 10,
|
|
1551
1678
|
attribute,
|
|
1679
|
+
searchAttribute,
|
|
1552
1680
|
filterOperator,
|
|
1553
1681
|
filterQuery,
|
|
1554
1682
|
search,
|
|
@@ -1563,8 +1691,9 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1563
1691
|
const currentPage = Math.max(Number(page) || 1, 1);
|
|
1564
1692
|
const start = (currentPage - 1) * limit;
|
|
1565
1693
|
const isSingleType = contentType.kind === "singleType";
|
|
1694
|
+
const targetFilterAttr = searchAttribute || attribute;
|
|
1566
1695
|
const signature = await getCollectionSignature(strapi2, uid);
|
|
1567
|
-
const cacheKey = `${uid}:${limit}:${start}:${attribute || ""}:${filterOperator || ""}:${filterQuery || ""}:${search || ""}:${sortField || ""}:${sortOrder}`;
|
|
1696
|
+
const cacheKey = `${uid}:${limit}:${start}:${attribute || ""}:${searchAttribute || ""}:${filterOperator || ""}:${filterQuery || ""}:${search || ""}:${sortField || ""}:${sortOrder}`;
|
|
1568
1697
|
const cached = queryCache.get(cacheKey);
|
|
1569
1698
|
const etag = `W/"entry-${crypto__default.default.createHash("md5").update(`${cacheKey}:${signature}`).digest("hex")}"`;
|
|
1570
1699
|
if (cached && cached.signature === signature && Date.now() - cached.timestamp < CACHE_TTL_MS) {
|
|
@@ -1579,19 +1708,15 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1579
1708
|
const attrs = contentType.attributes || {};
|
|
1580
1709
|
let colHasAttribute = false;
|
|
1581
1710
|
let isNestedAttr = false;
|
|
1582
|
-
let
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
if (compSchema?.attributes?.[childKey]) {
|
|
1590
|
-
colHasAttribute = true;
|
|
1591
|
-
isNestedAttr = true;
|
|
1592
|
-
}
|
|
1711
|
+
let parts = [];
|
|
1712
|
+
if (targetFilterAttr) {
|
|
1713
|
+
if (targetFilterAttr.includes(".")) {
|
|
1714
|
+
isNestedAttr = isDeepComponentField(contentType, strapi2.components, targetFilterAttr);
|
|
1715
|
+
if (isNestedAttr) {
|
|
1716
|
+
colHasAttribute = true;
|
|
1717
|
+
parts = targetFilterAttr.split(".");
|
|
1593
1718
|
}
|
|
1594
|
-
} else if (attrs[
|
|
1719
|
+
} else if (attrs[targetFilterAttr]) {
|
|
1595
1720
|
colHasAttribute = true;
|
|
1596
1721
|
}
|
|
1597
1722
|
}
|
|
@@ -1616,7 +1741,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1616
1741
|
}
|
|
1617
1742
|
let condition = void 0;
|
|
1618
1743
|
const q = (filterQuery || "").trim();
|
|
1619
|
-
const targetAttrSchema = isNestedAttr ? strapi2.components
|
|
1744
|
+
const targetAttrSchema = isNestedAttr ? getLeafAttributeSchema(contentType, strapi2.components, targetFilterAttr) : attrs[targetFilterAttr];
|
|
1620
1745
|
const isStringLike = ["string", "text", "email", "richtext", "uid"].includes(targetAttrSchema?.type);
|
|
1621
1746
|
if (normOp === "empty") {
|
|
1622
1747
|
condition = isStringLike ? { $or: [{ $null: true }, { $eq: "" }] } : { $null: true };
|
|
@@ -1646,19 +1771,18 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1646
1771
|
}
|
|
1647
1772
|
if (condition !== void 0) {
|
|
1648
1773
|
if (isNestedAttr) {
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
};
|
|
1774
|
+
const deepFilter = buildDeepFilter(parts, condition);
|
|
1775
|
+
Object.assign(filters2, deepFilter);
|
|
1652
1776
|
} else {
|
|
1653
1777
|
if (normOp === "empty" && isStringLike) {
|
|
1654
1778
|
filters2.$or = [
|
|
1655
|
-
{ [
|
|
1656
|
-
{ [
|
|
1779
|
+
{ [targetFilterAttr]: { $null: true } },
|
|
1780
|
+
{ [targetFilterAttr]: { $eq: "" } }
|
|
1657
1781
|
];
|
|
1658
1782
|
} else if (normOp === "notempty" && isStringLike) {
|
|
1659
|
-
filters2[
|
|
1783
|
+
filters2[targetFilterAttr] = { $notNull: true, $ne: "" };
|
|
1660
1784
|
} else {
|
|
1661
|
-
filters2[
|
|
1785
|
+
filters2[targetFilterAttr] = condition;
|
|
1662
1786
|
}
|
|
1663
1787
|
}
|
|
1664
1788
|
}
|
|
@@ -1681,12 +1805,17 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1681
1805
|
}
|
|
1682
1806
|
}
|
|
1683
1807
|
}
|
|
1808
|
+
const populateOption = buildDeepPopulate$1(contentType.attributes, strapi2.components);
|
|
1684
1809
|
if (isSingleType) {
|
|
1685
1810
|
let singleDoc = null;
|
|
1686
1811
|
try {
|
|
1687
|
-
|
|
1812
|
+
const singleArgs = {
|
|
1688
1813
|
filters: Object.keys(filters2).length > 0 ? filters2 : void 0
|
|
1689
|
-
}
|
|
1814
|
+
};
|
|
1815
|
+
if (populateOption) {
|
|
1816
|
+
singleArgs.populate = populateOption;
|
|
1817
|
+
}
|
|
1818
|
+
singleDoc = await strapi2.documents(uid).findFirst(singleArgs);
|
|
1690
1819
|
} catch {
|
|
1691
1820
|
singleDoc = null;
|
|
1692
1821
|
}
|
|
@@ -1704,11 +1833,11 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1704
1833
|
}
|
|
1705
1834
|
};
|
|
1706
1835
|
} else {
|
|
1707
|
-
|
|
1836
|
+
let sortClause = {};
|
|
1708
1837
|
if (sortField && sortField.includes(".")) {
|
|
1709
|
-
const
|
|
1710
|
-
if (contentType.
|
|
1711
|
-
sortClause
|
|
1838
|
+
const sortParts = sortField.split(".");
|
|
1839
|
+
if (isDeepComponentField(contentType, strapi2.components, sortField)) {
|
|
1840
|
+
sortClause = buildDeepFilter(sortParts, sortOrder);
|
|
1712
1841
|
} else {
|
|
1713
1842
|
sortClause["createdAt"] = "desc";
|
|
1714
1843
|
}
|
|
@@ -1717,18 +1846,17 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1717
1846
|
} else {
|
|
1718
1847
|
sortClause["createdAt"] = "desc";
|
|
1719
1848
|
}
|
|
1720
|
-
const
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1849
|
+
const findManyArgs = {
|
|
1850
|
+
start,
|
|
1851
|
+
limit,
|
|
1852
|
+
filters: Object.keys(filters2).length > 0 ? filters2 : void 0,
|
|
1853
|
+
sort: sortClause
|
|
1854
|
+
};
|
|
1855
|
+
if (populateOption) {
|
|
1856
|
+
findManyArgs.populate = populateOption;
|
|
1857
|
+
}
|
|
1724
1858
|
const [entries, totalEntries] = await Promise.all([
|
|
1725
|
-
strapi2.documents(uid).findMany(
|
|
1726
|
-
start,
|
|
1727
|
-
limit,
|
|
1728
|
-
filters: Object.keys(filters2).length > 0 ? filters2 : void 0,
|
|
1729
|
-
sort: sortClause,
|
|
1730
|
-
populate: populateOption
|
|
1731
|
-
}),
|
|
1859
|
+
strapi2.documents(uid).findMany(findManyArgs),
|
|
1732
1860
|
strapi2.documents(uid).count({
|
|
1733
1861
|
filters: Object.keys(filters2).length > 0 ? filters2 : void 0
|
|
1734
1862
|
})
|
|
@@ -1842,21 +1970,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1842
1970
|
const displayName = contentType?.info?.displayName || target.uid;
|
|
1843
1971
|
try {
|
|
1844
1972
|
const isNested = attribute.includes(".");
|
|
1845
|
-
|
|
1846
|
-
let parentKey = "";
|
|
1847
|
-
let childKey = "";
|
|
1848
|
-
if (isNested) {
|
|
1849
|
-
const parts = attribute.split(".");
|
|
1850
|
-
parentKey = parts[0];
|
|
1851
|
-
childKey = parts[1];
|
|
1852
|
-
const parentAttrDef = contentType?.attributes?.[parentKey];
|
|
1853
|
-
if (parentAttrDef?.type === "component" && !parentAttrDef.repeatable && parentAttrDef.component) {
|
|
1854
|
-
const compSchema = strapi2.components[parentAttrDef.component];
|
|
1855
|
-
if (compSchema?.attributes?.[childKey]) {
|
|
1856
|
-
isComponentNested = true;
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1973
|
+
const isComponentNested = isNested && isDeepComponentField(contentType, strapi2.components, attribute);
|
|
1860
1974
|
const attrDef = contentType?.attributes?.[attribute];
|
|
1861
1975
|
const hasAttribute = Boolean(attrDef) || isComponentNested;
|
|
1862
1976
|
if (!hasAttribute) {
|
|
@@ -1879,10 +1993,12 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1879
1993
|
}
|
|
1880
1994
|
let currentEntry;
|
|
1881
1995
|
if (isComponentNested) {
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1996
|
+
const findOneArgs = { documentId: target.documentId };
|
|
1997
|
+
const populateOption = buildDeepPopulate$1(contentType.attributes, strapi2.components);
|
|
1998
|
+
if (populateOption) {
|
|
1999
|
+
findOneArgs.populate = populateOption;
|
|
2000
|
+
}
|
|
2001
|
+
currentEntry = await strapi2.documents(target.uid).findOne(findOneArgs);
|
|
1886
2002
|
} else if (attrDef?.type === "relation") {
|
|
1887
2003
|
currentEntry = await strapi2.documents(target.uid).findOne({
|
|
1888
2004
|
documentId: target.documentId,
|
|
@@ -1895,8 +2011,7 @@ const bulkUpdaterService = ({ strapi: strapi2 }) => {
|
|
|
1895
2011
|
}
|
|
1896
2012
|
const entryLabel = currentEntry?.name || currentEntry?.title || currentEntry?.email || `Entry #${target.documentId}`;
|
|
1897
2013
|
if (isComponentNested) {
|
|
1898
|
-
const
|
|
1899
|
-
const currentVal2 = existingParent?.[childKey];
|
|
2014
|
+
const currentVal2 = getDeepProperty(currentEntry, attribute);
|
|
1900
2015
|
let newValue2 = value;
|
|
1901
2016
|
if (regexObj && typeof currentVal2 === "string") {
|
|
1902
2017
|
newValue2 = currentVal2.replace(regexObj, value);
|
|
@@ -3632,15 +3747,20 @@ function discoverExportFields(ct, allComponents, maxDepth = 4) {
|
|
|
3632
3747
|
return fields2;
|
|
3633
3748
|
}
|
|
3634
3749
|
function buildDeepPopulate(attributes, allComponents, depth2 = 0) {
|
|
3635
|
-
if (depth2 >
|
|
3750
|
+
if (depth2 > 5) return void 0;
|
|
3636
3751
|
const populate2 = {};
|
|
3637
3752
|
for (const [key, def] of Object.entries(attributes || {})) {
|
|
3638
3753
|
if (def.type === "component" && def.component) {
|
|
3639
3754
|
const comp = allComponents[def.component];
|
|
3640
3755
|
if (comp?.attributes) {
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3756
|
+
const subPopulate = buildDeepPopulate(comp.attributes, allComponents, depth2 + 1);
|
|
3757
|
+
if (subPopulate && Object.keys(subPopulate).length > 0) {
|
|
3758
|
+
populate2[key] = {
|
|
3759
|
+
populate: subPopulate
|
|
3760
|
+
};
|
|
3761
|
+
} else {
|
|
3762
|
+
populate2[key] = true;
|
|
3763
|
+
}
|
|
3644
3764
|
} else {
|
|
3645
3765
|
populate2[key] = true;
|
|
3646
3766
|
}
|
|
@@ -3650,7 +3770,7 @@ function buildDeepPopulate(attributes, allComponents, depth2 = 0) {
|
|
|
3650
3770
|
populate2[key] = true;
|
|
3651
3771
|
}
|
|
3652
3772
|
}
|
|
3653
|
-
return Object.keys(populate2).length > 0 ? populate2 :
|
|
3773
|
+
return Object.keys(populate2).length > 0 ? populate2 : void 0;
|
|
3654
3774
|
}
|
|
3655
3775
|
function getNestedExportValue(entry, path2) {
|
|
3656
3776
|
if (!entry || !path2) return "";
|
|
@@ -3817,17 +3937,22 @@ const csvService = ({ strapi: strapi2 }) => ({
|
|
|
3817
3937
|
const deepPopulate = buildDeepPopulate(ct.attributes || {}, allComponents);
|
|
3818
3938
|
let entries = [];
|
|
3819
3939
|
if (ct.kind === "singleType") {
|
|
3820
|
-
const
|
|
3821
|
-
|
|
3822
|
-
|
|
3940
|
+
const findFirstArgs = {};
|
|
3941
|
+
if (deepPopulate) {
|
|
3942
|
+
findFirstArgs.populate = deepPopulate;
|
|
3943
|
+
}
|
|
3944
|
+
const doc = await strapi2.documents(uid).findFirst(findFirstArgs);
|
|
3823
3945
|
entries = doc ? [doc] : [];
|
|
3824
3946
|
} else {
|
|
3825
|
-
|
|
3947
|
+
const findManyArgs = {
|
|
3826
3948
|
filters: Object.keys(filters2).length > 0 ? filters2 : void 0,
|
|
3827
3949
|
limit: options.limit || 5e3,
|
|
3828
|
-
sort: { createdAt: "desc" }
|
|
3829
|
-
|
|
3830
|
-
|
|
3950
|
+
sort: { createdAt: "desc" }
|
|
3951
|
+
};
|
|
3952
|
+
if (deepPopulate) {
|
|
3953
|
+
findManyArgs.populate = deepPopulate;
|
|
3954
|
+
}
|
|
3955
|
+
entries = await strapi2.documents(uid).findMany(findManyArgs);
|
|
3831
3956
|
}
|
|
3832
3957
|
const lines = [];
|
|
3833
3958
|
lines.push(fields2.map((f) => escapeCsvValue(f.key)).join(","));
|