@fourlights/strapi-plugin-deep-populate 1.1.2 → 1.2.2

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.
@@ -1,6 +1,4 @@
1
1
  "use strict";
2
- const merge$1 = require("dset/merge");
3
- const delve = require("dlv");
4
2
  const json$1 = require("klona/json");
5
3
  const require$$1 = require("crypto");
6
4
  const require$$0$1 = require("child_process");
@@ -14,8 +12,9 @@ const require$$0$6 = require("stream");
14
12
  const require$$2$1 = require("util");
15
13
  const require$$0$8 = require("constants");
16
14
  require("node:stream");
15
+ const delve = require("dlv");
16
+ const merge$1 = require("dset/merge");
17
17
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
18
- const delve__default = /* @__PURE__ */ _interopDefault(delve);
19
18
  const require$$1__default = /* @__PURE__ */ _interopDefault(require$$1);
20
19
  const require$$0__default = /* @__PURE__ */ _interopDefault(require$$0$1);
21
20
  const require$$0__default$1 = /* @__PURE__ */ _interopDefault(require$$0$2);
@@ -27,6 +26,207 @@ const require$$0__default$6 = /* @__PURE__ */ _interopDefault(require$$0$7);
27
26
  const require$$0__default$5 = /* @__PURE__ */ _interopDefault(require$$0$6);
28
27
  const require$$2__default$1 = /* @__PURE__ */ _interopDefault(require$$2$1);
29
28
  const require$$0__default$7 = /* @__PURE__ */ _interopDefault(require$$0$8);
29
+ const delve__default = /* @__PURE__ */ _interopDefault(delve);
30
+ const config = {
31
+ default: ({ env: env2 }) => ({ cachePopulate: true, augmentPopulateStar: true }),
32
+ validator: (config2) => {
33
+ }
34
+ };
35
+ const schema$1 = {
36
+ kind: "collectionType",
37
+ collectionName: "caches",
38
+ info: {
39
+ singularName: "cache",
40
+ pluralName: "caches",
41
+ displayName: "Cache",
42
+ description: "Holds cached deep populate object"
43
+ },
44
+ options: {},
45
+ pluginOptions: {
46
+ "content-manager": {
47
+ visible: false
48
+ },
49
+ "content-type-builder": {
50
+ visible: false
51
+ }
52
+ },
53
+ attributes: {
54
+ hash: {
55
+ type: "string",
56
+ configurable: false,
57
+ required: true
58
+ },
59
+ params: {
60
+ type: "json",
61
+ configurable: false,
62
+ required: true
63
+ },
64
+ populate: {
65
+ type: "json",
66
+ configurable: false
67
+ },
68
+ dependencies: { type: "string", configurable: false }
69
+ },
70
+ // experimental feature:
71
+ indexes: [
72
+ {
73
+ name: "caches_hash_idx",
74
+ columns: ["hash"],
75
+ type: "unique"
76
+ }
77
+ ]
78
+ };
79
+ const cache$1 = { schema: schema$1 };
80
+ const contentTypes$1 = { cache: cache$1 };
81
+ async function hasDeepPopulateCacheFullTextIndex(db, tableName, columnName) {
82
+ const knex = db.connection;
83
+ const client = db.dialect.client;
84
+ if (client === "sqlite") {
85
+ return (await db.dialect.schemaInspector.getTables()).includes(`${tableName}_fts`);
86
+ }
87
+ if (client === "mysql" || client === "mysql2") {
88
+ return (await db.dialect.schemaInspector.getIndexes(tableName)).find(
89
+ ({ name }) => name === `${tableName}_${columnName}_fulltext`
90
+ ) !== void 0;
91
+ }
92
+ if (client === "pg" || client === "postgres") {
93
+ const result = await knex.raw(
94
+ `SELECT * FROM pg_indexes WHERE tablename = '${tableName}' AND indexname = '${tableName}_${columnName}_gin'`
95
+ );
96
+ return result.rows.length > 0;
97
+ }
98
+ console.log(`Full-text index not supported for this database engine (${client})`);
99
+ return false;
100
+ }
101
+ async function addDeepPopulateCacheFullTextIndex(db, tableName, columnName) {
102
+ const knex = db.connection;
103
+ const hasTable = await knex.schema.hasTable(tableName);
104
+ if (!hasTable) return;
105
+ const hasColumn = await knex.schema.hasColumn(tableName, columnName);
106
+ if (!hasColumn) return;
107
+ const client = db.dialect.client;
108
+ if (client === "sqlite") {
109
+ await knex.raw(`CREATE VIRTUAL TABLE ${tableName}_fts USING fts3(${columnName})`);
110
+ await knex.raw(`INSERT INTO ${tableName}_fts (${columnName}) SELECT ${columnName} FROM ${tableName}`);
111
+ } else if (client === "mysql" || client === "mysql2") {
112
+ await knex.raw(`ALTER TABLE ${tableName} ADD FULLTEXT INDEX ${tableName}_${columnName}_fulltext (${columnName})`);
113
+ } else if (client === "pg" || client === "postgres") {
114
+ await knex.raw(
115
+ `CREATE INDEX ${tableName}_${columnName}_gin ON ${tableName} USING GIN (to_tsvector('english', ${columnName}))`
116
+ );
117
+ } else {
118
+ console.log(`Full-text index not supported for this database engine (${client})`);
119
+ }
120
+ }
121
+ async function removeDeepPopulateCacheFullTextIndex(db, tableName, columnName) {
122
+ const knex = db.connection;
123
+ const hasTable = await knex.schema.hasTable(tableName);
124
+ if (!hasTable) return;
125
+ const hasColumn = await knex.schema.hasColumn(tableName, columnName);
126
+ if (!hasColumn) return;
127
+ const client = db.dialect.client;
128
+ if (client === "sqlite") {
129
+ await knex.raw(`DROP TABLE ${tableName}_fts`);
130
+ } else if (client === "mysql" || client === "mysql2") {
131
+ await knex.raw(`ALTER TABLE ${tableName} DROP INDEX ${tableName}_${columnName}_fulltext`);
132
+ } else if (client === "pg" || client === "postgres") {
133
+ await knex.raw(`DROP INDEX ${tableName}_${columnName}_gin`);
134
+ } else {
135
+ console.log(`Full-text index not supported for this database engine (${client})`);
136
+ }
137
+ }
138
+ const register = async ({ strapi: strapi2 }) => {
139
+ strapi2.hook("strapi::content-types.afterSync").register(async () => {
140
+ const tableName = "caches";
141
+ const columnName = "dependencies";
142
+ const hasIndex = await hasDeepPopulateCacheFullTextIndex(strapi2.db, tableName, columnName);
143
+ if (strapi2.config.get("plugin::deep-populate").cachePopulate === true) {
144
+ if (!hasIndex) {
145
+ await addDeepPopulateCacheFullTextIndex(strapi2.db, tableName, columnName);
146
+ }
147
+ } else if (hasIndex) {
148
+ await removeDeepPopulateCacheFullTextIndex(strapi2.db, tableName, columnName);
149
+ }
150
+ });
151
+ strapi2.documents.use(async (context, next) => {
152
+ const { cachePopulate, augmentPopulateStar } = strapi2.config.get("plugin::deep-populate");
153
+ if (
154
+ // do nothing if not configured
155
+ !cachePopulate && !augmentPopulateStar || context.uid === "plugin::deep-populate.cache"
156
+ )
157
+ return await next();
158
+ const populateService = strapi2.plugin("deep-populate").service("populate");
159
+ const cacheService = strapi2.plugin("deep-populate").service("cache");
160
+ const { populate: populate2 } = context.params;
161
+ const returnDeeplyPopulated = augmentPopulateStar && populate2 === "*";
162
+ if (cachePopulate && context.action === "delete")
163
+ await cacheService.clear({ ...context.params, contentType: context.uid });
164
+ const originalFields = json$1.klona(context.fields);
165
+ if (returnDeeplyPopulated && ["findOne", "findFirst", "findMany"].includes(context.action))
166
+ context.fields = ["documentId", "status", "locale"];
167
+ const result = await next();
168
+ if (["create", "update"].includes(context.action)) {
169
+ const { documentId, status: status2, locale: locale2 } = result;
170
+ if (cachePopulate && context.action === "update")
171
+ await cacheService.clear({ ...context.params, contentType: context.uid });
172
+ if (cachePopulate || returnDeeplyPopulated) {
173
+ const deepPopulate = await populateService.get({ contentType: context.uid, documentId, status: status2, locale: locale2 });
174
+ if (returnDeeplyPopulated)
175
+ return await strapi2.documents(context.uid).findOne({ documentId, status: status2, locale: locale2, fields: originalFields, populate: deepPopulate });
176
+ }
177
+ }
178
+ if (returnDeeplyPopulated && ["findOne", "findFirst"].includes(context.action)) {
179
+ const { documentId, status: status2, locale: locale2 } = result;
180
+ const deepPopulate = await populateService.get({ contentType: context.uid, documentId, status: status2, locale: locale2 });
181
+ return await strapi2.documents(context.uid).findOne({ documentId, status: status2, locale: locale2, fields: originalFields, populate: deepPopulate });
182
+ }
183
+ if (returnDeeplyPopulated && context.action === "findMany") {
184
+ return await Promise.all(
185
+ result.map(async ({ documentId, status: status2, locale: locale2 }) => {
186
+ const deepPopulate = await populateService.get({ contentType: context.uid, documentId, status: status2, locale: locale2 });
187
+ return await strapi2.documents(context.uid).findOne({ documentId, status: status2, locale: locale2, fields: originalFields, populate: deepPopulate });
188
+ })
189
+ );
190
+ }
191
+ return result;
192
+ });
193
+ };
194
+ const getHash = (params) => {
195
+ return `${params.contentType}-${params.documentId}-${params.locale}-${params.status}-${params.omitEmpty ? "sparse" : "full"}`;
196
+ };
197
+ const cache = ({ strapi: strapi2 }) => ({
198
+ async get(params) {
199
+ const entry = await strapi2.documents("plugin::deep-populate.cache").findFirst({ filters: { hash: { $eq: getHash(params) } } });
200
+ return entry ? entry.populate : null;
201
+ },
202
+ async set({ populate: populate2, dependencies, ...params }) {
203
+ return await strapi2.documents("plugin::deep-populate.cache").create({ data: { hash: getHash(params), params, populate: populate2, dependencies: dependencies.join(",") } });
204
+ },
205
+ async clear(params) {
206
+ const entry = await strapi2.documents("plugin::deep-populate.cache").findFirst({ filters: { hash: { $eq: getHash(params) } } });
207
+ let retval = null;
208
+ if (entry) {
209
+ retval = await strapi2.documents("plugin::deep-populate.cache").delete({ documentId: entry.documentId });
210
+ }
211
+ await this.refreshDependents(params.documentId);
212
+ return retval;
213
+ },
214
+ async refreshDependents(documentId) {
215
+ const entries = await strapi2.documents("plugin::deep-populate.cache").findMany({ filters: { dependencies: { $contains: documentId } }, fields: ["documentId", "params"] });
216
+ const deleted = await strapi2.db.query("plugin::deep-populate.cache").deleteMany({
217
+ where: {
218
+ documentId: { $in: entries.map((x) => x.documentId) }
219
+ }
220
+ });
221
+ if (deleted.count !== entries.length)
222
+ console.error(`Deleted count ${deleted.count} does not match entries count ${entries.length}`);
223
+ const batchSize = 5;
224
+ for (let i = 0; i < entries.length; i += batchSize) {
225
+ const batch = entries.slice(i, i + batchSize);
226
+ await Promise.all(batch.map((entry) => strapi2.service("plugin::deep-populate.populate").get(entry.params)));
227
+ }
228
+ }
229
+ });
30
230
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
31
231
  function getDefaultExportFromCjs(x) {
32
232
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -602,8 +802,8 @@ lodash.exports;
602
802
  return object2[key];
603
803
  });
604
804
  }
605
- function cacheHas2(cache, key) {
606
- return cache.has(key);
805
+ function cacheHas2(cache2, key) {
806
+ return cache2.has(key);
607
807
  }
608
808
  function charsStartIndex(strSymbols, chrSymbols) {
609
809
  var index2 = -1, length = strSymbols.length;
@@ -1418,8 +1618,8 @@ lodash.exports;
1418
1618
  if (!(seen ? cacheHas2(seen, computed) : includes2(result2, computed, comparator))) {
1419
1619
  othIndex = othLength;
1420
1620
  while (--othIndex) {
1421
- var cache = caches[othIndex];
1422
- if (!(cache ? cacheHas2(cache, computed) : includes2(arrays[othIndex], computed, comparator))) {
1621
+ var cache2 = caches[othIndex];
1622
+ if (!(cache2 ? cacheHas2(cache2, computed) : includes2(arrays[othIndex], computed, comparator))) {
1423
1623
  continue outer;
1424
1624
  }
1425
1625
  }
@@ -2993,12 +3193,12 @@ lodash.exports;
2993
3193
  }
2994
3194
  function memoizeCapped2(func) {
2995
3195
  var result2 = memoize2(func, function(key) {
2996
- if (cache.size === MAX_MEMOIZE_SIZE2) {
2997
- cache.clear();
3196
+ if (cache2.size === MAX_MEMOIZE_SIZE2) {
3197
+ cache2.clear();
2998
3198
  }
2999
3199
  return key;
3000
3200
  });
3001
- var cache = result2.cache;
3201
+ var cache2 = result2.cache;
3002
3202
  return result2;
3003
3203
  }
3004
3204
  function mergeData(data, source) {
@@ -3952,12 +4152,12 @@ lodash.exports;
3952
4152
  throw new TypeError2(FUNC_ERROR_TEXT2);
3953
4153
  }
3954
4154
  var memoized = function() {
3955
- var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
3956
- if (cache.has(key)) {
3957
- return cache.get(key);
4155
+ var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache2 = memoized.cache;
4156
+ if (cache2.has(key)) {
4157
+ return cache2.get(key);
3958
4158
  }
3959
4159
  var result2 = func.apply(this, args);
3960
- memoized.cache = cache.set(key, result2) || cache;
4160
+ memoized.cache = cache2.set(key, result2) || cache2;
3961
4161
  return result2;
3962
4162
  };
3963
4163
  memoized.cache = new (memoize2.Cache || MapCache2)();
@@ -9219,7 +9419,7 @@ function baseConvert(util2, name, func, options) {
9219
9419
  throw new TypeError();
9220
9420
  }
9221
9421
  options || (options = {});
9222
- var config = {
9422
+ var config2 = {
9223
9423
  "cap": "cap" in options ? options.cap : true,
9224
9424
  "curry": "curry" in options ? options.curry : true,
9225
9425
  "fixed": "fixed" in options ? options.fixed : true,
@@ -9255,7 +9455,7 @@ function baseConvert(util2, name, func, options) {
9255
9455
  "iteratee": function(iteratee) {
9256
9456
  return function() {
9257
9457
  var func2 = arguments[0], arity = arguments[1], result = iteratee(func2, arity), length = result.length;
9258
- if (config.cap && typeof arity == "number") {
9458
+ if (config2.cap && typeof arity == "number") {
9259
9459
  arity = arity > 2 ? arity - 2 : 1;
9260
9460
  return length && length <= arity ? result : baseAry(result, arity);
9261
9461
  }
@@ -9305,7 +9505,7 @@ function baseConvert(util2, name, func, options) {
9305
9505
  }
9306
9506
  };
9307
9507
  function castCap(name2, func2) {
9308
- if (config.cap) {
9508
+ if (config2.cap) {
9309
9509
  var indexes = mapping.iterateeRearg[name2];
9310
9510
  if (indexes) {
9311
9511
  return iterateeRearg(func2, indexes);
@@ -9318,17 +9518,17 @@ function baseConvert(util2, name, func, options) {
9318
9518
  return func2;
9319
9519
  }
9320
9520
  function castCurry(name2, func2, n) {
9321
- return forceCurry || config.curry && n > 1 ? curry(func2, n) : func2;
9521
+ return forceCurry || config2.curry && n > 1 ? curry(func2, n) : func2;
9322
9522
  }
9323
9523
  function castFixed(name2, func2, n) {
9324
- if (config.fixed && (forceFixed || !mapping.skipFixed[name2])) {
9524
+ if (config2.fixed && (forceFixed || !mapping.skipFixed[name2])) {
9325
9525
  var data = mapping.methodSpread[name2], start = data && data.start;
9326
9526
  return start === void 0 ? ary(func2, n) : flatSpread(func2, start);
9327
9527
  }
9328
9528
  return func2;
9329
9529
  }
9330
9530
  function castRearg(name2, func2, n) {
9331
- return config.rearg && n > 1 && (forceRearg || !mapping.skipRearg[name2]) ? rearg(func2, mapping.methodRearg[name2] || mapping.aryRearg[n]) : func2;
9531
+ return config2.rearg && n > 1 && (forceRearg || !mapping.skipRearg[name2]) ? rearg(func2, mapping.methodRearg[name2] || mapping.aryRearg[n]) : func2;
9332
9532
  }
9333
9533
  function cloneByPath(object2, path2) {
9334
9534
  path2 = toPath(path2);
@@ -9373,7 +9573,7 @@ function baseConvert(util2, name, func, options) {
9373
9573
  while (length--) {
9374
9574
  args[length] = arguments[length];
9375
9575
  }
9376
- var index2 = config.rearg ? 0 : length - 1;
9576
+ var index2 = config2.rearg ? 0 : length - 1;
9377
9577
  args[index2] = transform2(args[index2]);
9378
9578
  return func2.apply(void 0, args);
9379
9579
  };
@@ -9382,7 +9582,7 @@ function baseConvert(util2, name, func, options) {
9382
9582
  var result, realName = mapping.aliasToReal[name2] || name2, wrapped = func2, wrapper = wrappers[realName];
9383
9583
  if (wrapper) {
9384
9584
  wrapped = wrapper(func2);
9385
- } else if (config.immutable) {
9585
+ } else if (config2.immutable) {
9386
9586
  if (mapping.mutate.array[realName]) {
9387
9587
  wrapped = wrapImmutable(func2, cloneArray);
9388
9588
  } else if (mapping.mutate.object[realName]) {
@@ -10674,12 +10874,12 @@ function memoize$1(func, resolver) {
10674
10874
  throw new TypeError(FUNC_ERROR_TEXT);
10675
10875
  }
10676
10876
  var memoized = function() {
10677
- var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
10678
- if (cache.has(key)) {
10679
- return cache.get(key);
10877
+ var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache2 = memoized.cache;
10878
+ if (cache2.has(key)) {
10879
+ return cache2.get(key);
10680
10880
  }
10681
10881
  var result = func.apply(this, args);
10682
- memoized.cache = cache.set(key, result) || cache;
10882
+ memoized.cache = cache2.set(key, result) || cache2;
10683
10883
  return result;
10684
10884
  };
10685
10885
  memoized.cache = new (memoize$1.Cache || MapCache$2)();
@@ -10691,12 +10891,12 @@ var memoize = memoize_1;
10691
10891
  var MAX_MEMOIZE_SIZE = 500;
10692
10892
  function memoizeCapped$1(func) {
10693
10893
  var result = memoize(func, function(key) {
10694
- if (cache.size === MAX_MEMOIZE_SIZE) {
10695
- cache.clear();
10894
+ if (cache2.size === MAX_MEMOIZE_SIZE) {
10895
+ cache2.clear();
10696
10896
  }
10697
10897
  return key;
10698
10898
  });
10699
- var cache = result.cache;
10899
+ var cache2 = result.cache;
10700
10900
  return result;
10701
10901
  }
10702
10902
  var _memoizeCapped = memoizeCapped$1;
@@ -11198,8 +11398,8 @@ function arraySome$1(array2, predicate) {
11198
11398
  return false;
11199
11399
  }
11200
11400
  var _arraySome = arraySome$1;
11201
- function cacheHas$1(cache, key) {
11202
- return cache.has(key);
11401
+ function cacheHas$1(cache2, key) {
11402
+ return cache2.has(key);
11203
11403
  }
11204
11404
  var _cacheHas = cacheHas$1;
11205
11405
  var SetCache = _SetCache, arraySome = _arraySome, cacheHas = _cacheHas;
@@ -11824,7 +12024,7 @@ function _objectWithoutPropertiesLoose(source, excluded) {
11824
12024
  }
11825
12025
  return target;
11826
12026
  }
11827
- function createValidation(config) {
12027
+ function createValidation(config2) {
11828
12028
  function validate(_ref, cb) {
11829
12029
  let {
11830
12030
  value,
@@ -11839,7 +12039,7 @@ function createValidation(config) {
11839
12039
  test,
11840
12040
  params,
11841
12041
  message
11842
- } = config;
12042
+ } = config2;
11843
12043
  let {
11844
12044
  parent,
11845
12045
  context
@@ -11894,7 +12094,7 @@ function createValidation(config) {
11894
12094
  else if (!result) cb(createError());
11895
12095
  else cb(null, result);
11896
12096
  }
11897
- validate.OPTIONS = config;
12097
+ validate.OPTIONS = config2;
11898
12098
  return validate;
11899
12099
  }
11900
12100
  let trim = (part) => part.substr(0, part.length - 1).substr(1);
@@ -24584,7 +24784,7 @@ const isPopulateString = (value) => {
24584
24784
  };
24585
24785
  const isStringArray$1 = (value) => fp.isArray(value) && value.every(fp.isString);
24586
24786
  const isObj = (value) => fp.isObject(value);
24587
- const populate$1 = traverseFactory().intercept(isPopulateString, async (visitor2, options, populate2, { recurse }) => {
24787
+ const populate$2 = traverseFactory().intercept(isPopulateString, async (visitor2, options, populate2, { recurse }) => {
24588
24788
  const populateObject = pathsToObjectPopulate([populate2]);
24589
24789
  const traversedPopulate = await recurse(visitor2, options, populateObject);
24590
24790
  const [result] = objectPopulateToPaths(traversedPopulate);
@@ -24752,7 +24952,7 @@ const populate$1 = traverseFactory().intercept(isPopulateString, async (visitor2
24752
24952
  }
24753
24953
  }
24754
24954
  );
24755
- const traverseQueryPopulate = fp.curry(populate$1.traverse);
24955
+ const traverseQueryPopulate = fp.curry(populate$2.traverse);
24756
24956
  const objectPopulateToPaths = (input) => {
24757
24957
  const paths = [];
24758
24958
  function traverse(currentObj, parentPath) {
@@ -25072,54 +25272,40 @@ const hasValue = (value) => {
25072
25272
  return !(value === null || value === void 0 || Array.isArray(value) && value.length === 0 || typeof value === "object" && isEmpty(value));
25073
25273
  };
25074
25274
  async function _populateComponent({
25075
- mainUid,
25076
- mainDocumentId,
25077
- schema: schema2,
25078
25275
  populate: populate2 = {},
25079
25276
  lookup,
25277
+ attrName,
25080
25278
  inDynamicZone = false,
25081
- resolvedRelations,
25082
- omitEmpty
25279
+ ...params
25083
25280
  }) {
25084
- const attrName = lookup.pop();
25085
25281
  const componentLookup = lookup.length === 0 ? [attrName] : [...lookup, inDynamicZone ? "on" : "populate", attrName];
25086
- const componentPopulate = json$1.klona(populate2);
25282
+ const componentPopulate = populate2;
25087
25283
  merge$1.dset(componentPopulate, componentLookup, { populate: "*" });
25088
25284
  const nestedPopulate = await _populate({
25089
- mainUid,
25090
- mainDocumentId,
25091
- schema: schema2,
25092
25285
  populate: componentPopulate,
25093
25286
  lookup: componentLookup,
25094
- resolvedRelations,
25095
- omitEmpty
25287
+ ...params
25096
25288
  });
25097
25289
  return isEmpty(nestedPopulate) ? true : { populate: nestedPopulate };
25098
25290
  }
25099
25291
  async function _populateDynamicZone({
25100
- mainUid,
25101
- mainDocumentId,
25102
25292
  components,
25103
- populate: populate2,
25104
25293
  lookup,
25105
- resolvedRelations,
25106
- omitEmpty
25294
+ attrName,
25295
+ ...params
25107
25296
  }) {
25108
- const resolvedPopulate = await components.reduce(async (prev, cur) => {
25109
- const curPopulate = await _populateComponent({
25110
- mainUid,
25111
- mainDocumentId,
25112
- schema: cur,
25113
- populate: populate2,
25114
- lookup: [...lookup, cur],
25297
+ const dynamicZoneLookup = [...lookup, attrName];
25298
+ const resolvedPopulate = {};
25299
+ for (const component of components) {
25300
+ const componentPopulate = await _populateComponent({
25301
+ schema: component,
25302
+ lookup: dynamicZoneLookup,
25303
+ attrName: component,
25115
25304
  inDynamicZone: true,
25116
- resolvedRelations,
25117
- omitEmpty
25305
+ ...params
25118
25306
  });
25119
- const newPop = await prev;
25120
- merge$1.dset(newPop, [cur], curPopulate);
25121
- return newPop;
25122
- }, Promise.resolve({}));
25307
+ merge$1.dset(resolvedPopulate, [component], componentPopulate);
25308
+ }
25123
25309
  if (isEmpty(resolvedPopulate)) return void 0;
25124
25310
  return { on: resolvedPopulate };
25125
25311
  }
@@ -25130,18 +25316,23 @@ async function _populateRelation({
25130
25316
  contentType,
25131
25317
  relation,
25132
25318
  resolvedRelations,
25133
- omitEmpty
25319
+ omitEmpty,
25320
+ locale: locale2,
25321
+ status: status2
25134
25322
  }) {
25135
25323
  const isSingleRelation = !Array.isArray(relation);
25136
25324
  const relations = isSingleRelation ? [relation] : relation;
25137
- for (const relation2 of relations.filter(({ documentId }) => !resolvedRelations.has(documentId))) {
25325
+ const nonResolvedRelations = relations.filter(({ documentId }) => !resolvedRelations.has(documentId));
25326
+ for (const relation2 of nonResolvedRelations) {
25138
25327
  resolvedRelations.set(relation2.documentId, {});
25139
25328
  const relationPopulate = await _populate({
25140
- mainUid: contentType,
25141
- mainDocumentId: relation2.documentId,
25329
+ contentType,
25330
+ documentId: relation2.documentId,
25142
25331
  schema: contentType,
25143
25332
  resolvedRelations,
25144
- omitEmpty
25333
+ omitEmpty,
25334
+ locale: locale2,
25335
+ status: status2
25145
25336
  });
25146
25337
  resolvedRelations.set(relation2.documentId, relationPopulate);
25147
25338
  }
@@ -25171,7 +25362,7 @@ const _resolveValue = ({ document: document2, lookup, attrName }) => {
25171
25362
  const childLookup = lookup[populateIdx + 1];
25172
25363
  const parentValue2 = delve__default.default(document2, parentLookup);
25173
25364
  const childValue = (Array.isArray(parentValue2) ? parentValue2 : [parentValue2]).map(
25174
- (v) => _resolveValue({ document: parentValue2, lookup: childLookup, attrName })
25365
+ (v) => _resolveValue({ document: v, lookup: childLookup, attrName })
25175
25366
  );
25176
25367
  return childValue.find((v) => hasValue(v));
25177
25368
  }
@@ -25182,18 +25373,18 @@ const _resolveValue = ({ document: document2, lookup, attrName }) => {
25182
25373
  return parentValue?.[attrName];
25183
25374
  };
25184
25375
  async function _populate({
25185
- mainUid,
25186
- mainDocumentId,
25376
+ contentType,
25187
25377
  schema: schema2,
25188
25378
  populate: populate2 = {},
25189
25379
  lookup = [],
25190
- resolvedRelations = /* @__PURE__ */ new Map(),
25191
- omitEmpty = true
25380
+ resolvedRelations,
25381
+ omitEmpty,
25382
+ ...params
25192
25383
  }) {
25193
25384
  const newPopulate = {};
25194
- const model = strapi.getModel(schema2);
25195
- const relations = getRelations(model);
25196
- const currentPopulate = json$1.klona(populate2);
25385
+ let relations = getRelations(strapi.getModel(schema2));
25386
+ let currentPopulate = json$1.klona(populate2);
25387
+ resolvedRelations.set(params.documentId, true);
25197
25388
  for (const [attrName] of relations) {
25198
25389
  if (lookup.length > 0) {
25199
25390
  const parent = delve__default.default(currentPopulate, lookup);
@@ -25204,47 +25395,56 @@ async function _populate({
25204
25395
  merge$1.dset(currentPopulate, attrName, { populate: "*" });
25205
25396
  }
25206
25397
  }
25207
- const document2 = await strapi.documents(mainUid).findOne({
25208
- documentId: mainDocumentId,
25398
+ let document2 = await strapi.documents(contentType).findOne({
25399
+ ...params,
25209
25400
  populate: currentPopulate ? currentPopulate : "*"
25210
25401
  });
25402
+ currentPopulate = null;
25403
+ const resolveRelations = [];
25211
25404
  for (const [attrName, attr] of relations) {
25212
25405
  const value = _resolveValue({ document: document2, attrName, lookup });
25213
25406
  if (!hasValue(value)) {
25214
25407
  if (!omitEmpty) newPopulate[attrName] = true;
25215
25408
  continue;
25216
25409
  }
25410
+ resolveRelations.push([attrName, attr, value]);
25411
+ }
25412
+ relations = null;
25413
+ document2 = null;
25414
+ for (const [attrName, attr, value] of resolveRelations) {
25217
25415
  if (contentTypes.isDynamicZoneAttribute(attr)) {
25218
25416
  const relComponents = value.map(
25219
25417
  (dataComponent) => attr.components.find((schemaComponent) => schemaComponent === dataComponent.__component)
25220
25418
  );
25221
25419
  newPopulate[attrName] = await _populateDynamicZone({
25222
- mainUid,
25223
- mainDocumentId,
25420
+ contentType,
25224
25421
  components: relComponents,
25225
- lookup: [...lookup, attrName],
25422
+ lookup,
25423
+ attrName,
25226
25424
  resolvedRelations,
25227
- omitEmpty
25425
+ omitEmpty,
25426
+ ...params
25228
25427
  });
25229
25428
  }
25230
25429
  if (contentTypes.isRelationalAttribute(attr)) {
25231
- const { target: relContentType } = attr;
25232
- resolvedRelations.set(mainDocumentId, true);
25233
25430
  newPopulate[attrName] = await _populateRelation({
25234
- contentType: relContentType,
25431
+ contentType: attr.target,
25235
25432
  relation: value,
25236
25433
  resolvedRelations,
25237
- omitEmpty
25434
+ omitEmpty,
25435
+ locale: params.locale,
25436
+ status: params.status
25238
25437
  });
25239
25438
  }
25240
25439
  if (contentTypes.isComponentAttribute(attr) && !contentTypes.isDynamicZoneAttribute(attr)) {
25241
25440
  newPopulate[attrName] = await _populateComponent({
25242
- mainUid,
25243
- mainDocumentId,
25441
+ contentType,
25244
25442
  schema: attr.component,
25245
- lookup: [...lookup, attrName],
25443
+ lookup,
25444
+ attrName,
25246
25445
  resolvedRelations,
25247
- omitEmpty
25446
+ omitEmpty,
25447
+ ...params
25248
25448
  });
25249
25449
  }
25250
25450
  if (contentTypes.isMediaAttribute(attr)) {
@@ -25253,42 +25453,30 @@ async function _populate({
25253
25453
  }
25254
25454
  return newPopulate;
25255
25455
  }
25456
+ async function populate$1(params) {
25457
+ const resolvedRelations = /* @__PURE__ */ new Map();
25458
+ const populated = await _populate({ ...params, schema: params.contentType, resolvedRelations });
25459
+ return { populate: populated, dependencies: [...resolvedRelations.keys()] };
25460
+ }
25256
25461
  const populate = ({ strapi: strapi2 }) => ({
25257
- async get({
25258
- contentType,
25259
- documentId,
25260
- omitEmpty = false
25261
- }) {
25262
- return await _populate({ mainUid: contentType, mainDocumentId: documentId, schema: contentType, omitEmpty });
25263
- },
25264
- documents(contentType) {
25265
- strapi2.documents(contentType);
25266
- const { findOne, ...wrapped } = strapi2.documents(contentType);
25267
- const wrappedFindOne = async (params) => {
25268
- const { documentId, populate: originalPopulate } = params;
25269
- const deepPopulate = await _populate({
25270
- mainUid: contentType,
25271
- mainDocumentId: documentId,
25272
- schema: contentType,
25273
- omitEmpty: originalPopulate !== "*"
25274
- });
25275
- if (originalPopulate && originalPopulate !== "*") {
25276
- strapi2.log.warn(
25277
- `passed "populate" will be merged with deepPopulate, which could result in unexpected behavior.`
25278
- );
25279
- if (typeof originalPopulate === "object")
25280
- Object.keys(originalPopulate).map((k) => merge$1.dset(deepPopulate, k, originalPopulate[k]));
25281
- if (Array.isArray(originalPopulate)) originalPopulate.map((k) => merge$1.dset(deepPopulate, k, true));
25282
- }
25283
- return await findOne({ ...params, populate: deepPopulate });
25284
- };
25285
- return { ...wrapped, findOne: wrappedFindOne };
25462
+ async get(params) {
25463
+ const { cachePopulate } = strapi2.config.get("plugin::deep-populate");
25464
+ if (!cachePopulate) return (await populate$1(params)).populate;
25465
+ const cachedEntry = await strapi2.service("plugin::deep-populate.cache").get(params);
25466
+ if (cachedEntry) return cachedEntry;
25467
+ const resolved = await populate$1(params);
25468
+ await strapi2.service("plugin::deep-populate.cache").set({ ...params, ...resolved });
25469
+ return resolved;
25286
25470
  }
25287
25471
  });
25288
25472
  const services = {
25289
- populate
25473
+ populate,
25474
+ cache
25290
25475
  };
25291
25476
  const index = {
25292
- services
25477
+ config,
25478
+ contentTypes: contentTypes$1,
25479
+ services,
25480
+ register
25293
25481
  };
25294
25482
  module.exports = index;