@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,5 +1,3 @@
1
- import { dset } from "dset/merge";
2
- import delve from "dlv";
3
1
  import { klona } from "klona/json";
4
2
  import require$$1 from "crypto";
5
3
  import require$$0$1 from "child_process";
@@ -13,6 +11,208 @@ import require$$0$6 from "stream";
13
11
  import require$$2$1 from "util";
14
12
  import require$$0$8 from "constants";
15
13
  import "node:stream";
14
+ import delve from "dlv";
15
+ import { dset } from "dset/merge";
16
+ const config = {
17
+ default: ({ env: env2 }) => ({ cachePopulate: true, augmentPopulateStar: true }),
18
+ validator: (config2) => {
19
+ }
20
+ };
21
+ const schema$1 = {
22
+ kind: "collectionType",
23
+ collectionName: "caches",
24
+ info: {
25
+ singularName: "cache",
26
+ pluralName: "caches",
27
+ displayName: "Cache",
28
+ description: "Holds cached deep populate object"
29
+ },
30
+ options: {},
31
+ pluginOptions: {
32
+ "content-manager": {
33
+ visible: false
34
+ },
35
+ "content-type-builder": {
36
+ visible: false
37
+ }
38
+ },
39
+ attributes: {
40
+ hash: {
41
+ type: "string",
42
+ configurable: false,
43
+ required: true
44
+ },
45
+ params: {
46
+ type: "json",
47
+ configurable: false,
48
+ required: true
49
+ },
50
+ populate: {
51
+ type: "json",
52
+ configurable: false
53
+ },
54
+ dependencies: { type: "string", configurable: false }
55
+ },
56
+ // experimental feature:
57
+ indexes: [
58
+ {
59
+ name: "caches_hash_idx",
60
+ columns: ["hash"],
61
+ type: "unique"
62
+ }
63
+ ]
64
+ };
65
+ const cache$1 = { schema: schema$1 };
66
+ const contentTypes$1 = { cache: cache$1 };
67
+ async function hasDeepPopulateCacheFullTextIndex(db, tableName, columnName) {
68
+ const knex = db.connection;
69
+ const client = db.dialect.client;
70
+ if (client === "sqlite") {
71
+ return (await db.dialect.schemaInspector.getTables()).includes(`${tableName}_fts`);
72
+ }
73
+ if (client === "mysql" || client === "mysql2") {
74
+ return (await db.dialect.schemaInspector.getIndexes(tableName)).find(
75
+ ({ name }) => name === `${tableName}_${columnName}_fulltext`
76
+ ) !== void 0;
77
+ }
78
+ if (client === "pg" || client === "postgres") {
79
+ const result = await knex.raw(
80
+ `SELECT * FROM pg_indexes WHERE tablename = '${tableName}' AND indexname = '${tableName}_${columnName}_gin'`
81
+ );
82
+ return result.rows.length > 0;
83
+ }
84
+ console.log(`Full-text index not supported for this database engine (${client})`);
85
+ return false;
86
+ }
87
+ async function addDeepPopulateCacheFullTextIndex(db, tableName, columnName) {
88
+ const knex = db.connection;
89
+ const hasTable = await knex.schema.hasTable(tableName);
90
+ if (!hasTable) return;
91
+ const hasColumn = await knex.schema.hasColumn(tableName, columnName);
92
+ if (!hasColumn) return;
93
+ const client = db.dialect.client;
94
+ if (client === "sqlite") {
95
+ await knex.raw(`CREATE VIRTUAL TABLE ${tableName}_fts USING fts3(${columnName})`);
96
+ await knex.raw(`INSERT INTO ${tableName}_fts (${columnName}) SELECT ${columnName} FROM ${tableName}`);
97
+ } else if (client === "mysql" || client === "mysql2") {
98
+ await knex.raw(`ALTER TABLE ${tableName} ADD FULLTEXT INDEX ${tableName}_${columnName}_fulltext (${columnName})`);
99
+ } else if (client === "pg" || client === "postgres") {
100
+ await knex.raw(
101
+ `CREATE INDEX ${tableName}_${columnName}_gin ON ${tableName} USING GIN (to_tsvector('english', ${columnName}))`
102
+ );
103
+ } else {
104
+ console.log(`Full-text index not supported for this database engine (${client})`);
105
+ }
106
+ }
107
+ async function removeDeepPopulateCacheFullTextIndex(db, tableName, columnName) {
108
+ const knex = db.connection;
109
+ const hasTable = await knex.schema.hasTable(tableName);
110
+ if (!hasTable) return;
111
+ const hasColumn = await knex.schema.hasColumn(tableName, columnName);
112
+ if (!hasColumn) return;
113
+ const client = db.dialect.client;
114
+ if (client === "sqlite") {
115
+ await knex.raw(`DROP TABLE ${tableName}_fts`);
116
+ } else if (client === "mysql" || client === "mysql2") {
117
+ await knex.raw(`ALTER TABLE ${tableName} DROP INDEX ${tableName}_${columnName}_fulltext`);
118
+ } else if (client === "pg" || client === "postgres") {
119
+ await knex.raw(`DROP INDEX ${tableName}_${columnName}_gin`);
120
+ } else {
121
+ console.log(`Full-text index not supported for this database engine (${client})`);
122
+ }
123
+ }
124
+ const register = async ({ strapi: strapi2 }) => {
125
+ strapi2.hook("strapi::content-types.afterSync").register(async () => {
126
+ const tableName = "caches";
127
+ const columnName = "dependencies";
128
+ const hasIndex = await hasDeepPopulateCacheFullTextIndex(strapi2.db, tableName, columnName);
129
+ if (strapi2.config.get("plugin::deep-populate").cachePopulate === true) {
130
+ if (!hasIndex) {
131
+ await addDeepPopulateCacheFullTextIndex(strapi2.db, tableName, columnName);
132
+ }
133
+ } else if (hasIndex) {
134
+ await removeDeepPopulateCacheFullTextIndex(strapi2.db, tableName, columnName);
135
+ }
136
+ });
137
+ strapi2.documents.use(async (context, next) => {
138
+ const { cachePopulate, augmentPopulateStar } = strapi2.config.get("plugin::deep-populate");
139
+ if (
140
+ // do nothing if not configured
141
+ !cachePopulate && !augmentPopulateStar || context.uid === "plugin::deep-populate.cache"
142
+ )
143
+ return await next();
144
+ const populateService = strapi2.plugin("deep-populate").service("populate");
145
+ const cacheService = strapi2.plugin("deep-populate").service("cache");
146
+ const { populate: populate2 } = context.params;
147
+ const returnDeeplyPopulated = augmentPopulateStar && populate2 === "*";
148
+ if (cachePopulate && context.action === "delete")
149
+ await cacheService.clear({ ...context.params, contentType: context.uid });
150
+ const originalFields = klona(context.fields);
151
+ if (returnDeeplyPopulated && ["findOne", "findFirst", "findMany"].includes(context.action))
152
+ context.fields = ["documentId", "status", "locale"];
153
+ const result = await next();
154
+ if (["create", "update"].includes(context.action)) {
155
+ const { documentId, status: status2, locale: locale2 } = result;
156
+ if (cachePopulate && context.action === "update")
157
+ await cacheService.clear({ ...context.params, contentType: context.uid });
158
+ if (cachePopulate || returnDeeplyPopulated) {
159
+ const deepPopulate = await populateService.get({ contentType: context.uid, documentId, status: status2, locale: locale2 });
160
+ if (returnDeeplyPopulated)
161
+ return await strapi2.documents(context.uid).findOne({ documentId, status: status2, locale: locale2, fields: originalFields, populate: deepPopulate });
162
+ }
163
+ }
164
+ if (returnDeeplyPopulated && ["findOne", "findFirst"].includes(context.action)) {
165
+ const { documentId, status: status2, locale: locale2 } = result;
166
+ const deepPopulate = await populateService.get({ contentType: context.uid, documentId, status: status2, locale: locale2 });
167
+ return await strapi2.documents(context.uid).findOne({ documentId, status: status2, locale: locale2, fields: originalFields, populate: deepPopulate });
168
+ }
169
+ if (returnDeeplyPopulated && context.action === "findMany") {
170
+ return await Promise.all(
171
+ result.map(async ({ documentId, status: status2, locale: locale2 }) => {
172
+ const deepPopulate = await populateService.get({ contentType: context.uid, documentId, status: status2, locale: locale2 });
173
+ return await strapi2.documents(context.uid).findOne({ documentId, status: status2, locale: locale2, fields: originalFields, populate: deepPopulate });
174
+ })
175
+ );
176
+ }
177
+ return result;
178
+ });
179
+ };
180
+ const getHash = (params) => {
181
+ return `${params.contentType}-${params.documentId}-${params.locale}-${params.status}-${params.omitEmpty ? "sparse" : "full"}`;
182
+ };
183
+ const cache = ({ strapi: strapi2 }) => ({
184
+ async get(params) {
185
+ const entry = await strapi2.documents("plugin::deep-populate.cache").findFirst({ filters: { hash: { $eq: getHash(params) } } });
186
+ return entry ? entry.populate : null;
187
+ },
188
+ async set({ populate: populate2, dependencies, ...params }) {
189
+ return await strapi2.documents("plugin::deep-populate.cache").create({ data: { hash: getHash(params), params, populate: populate2, dependencies: dependencies.join(",") } });
190
+ },
191
+ async clear(params) {
192
+ const entry = await strapi2.documents("plugin::deep-populate.cache").findFirst({ filters: { hash: { $eq: getHash(params) } } });
193
+ let retval = null;
194
+ if (entry) {
195
+ retval = await strapi2.documents("plugin::deep-populate.cache").delete({ documentId: entry.documentId });
196
+ }
197
+ await this.refreshDependents(params.documentId);
198
+ return retval;
199
+ },
200
+ async refreshDependents(documentId) {
201
+ const entries = await strapi2.documents("plugin::deep-populate.cache").findMany({ filters: { dependencies: { $contains: documentId } }, fields: ["documentId", "params"] });
202
+ const deleted = await strapi2.db.query("plugin::deep-populate.cache").deleteMany({
203
+ where: {
204
+ documentId: { $in: entries.map((x) => x.documentId) }
205
+ }
206
+ });
207
+ if (deleted.count !== entries.length)
208
+ console.error(`Deleted count ${deleted.count} does not match entries count ${entries.length}`);
209
+ const batchSize = 5;
210
+ for (let i = 0; i < entries.length; i += batchSize) {
211
+ const batch = entries.slice(i, i + batchSize);
212
+ await Promise.all(batch.map((entry) => strapi2.service("plugin::deep-populate.populate").get(entry.params)));
213
+ }
214
+ }
215
+ });
16
216
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
17
217
  function getDefaultExportFromCjs(x) {
18
218
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -588,8 +788,8 @@ lodash.exports;
588
788
  return object2[key];
589
789
  });
590
790
  }
591
- function cacheHas2(cache, key) {
592
- return cache.has(key);
791
+ function cacheHas2(cache2, key) {
792
+ return cache2.has(key);
593
793
  }
594
794
  function charsStartIndex(strSymbols, chrSymbols) {
595
795
  var index2 = -1, length = strSymbols.length;
@@ -1404,8 +1604,8 @@ lodash.exports;
1404
1604
  if (!(seen ? cacheHas2(seen, computed) : includes2(result2, computed, comparator))) {
1405
1605
  othIndex = othLength;
1406
1606
  while (--othIndex) {
1407
- var cache = caches[othIndex];
1408
- if (!(cache ? cacheHas2(cache, computed) : includes2(arrays[othIndex], computed, comparator))) {
1607
+ var cache2 = caches[othIndex];
1608
+ if (!(cache2 ? cacheHas2(cache2, computed) : includes2(arrays[othIndex], computed, comparator))) {
1409
1609
  continue outer;
1410
1610
  }
1411
1611
  }
@@ -2979,12 +3179,12 @@ lodash.exports;
2979
3179
  }
2980
3180
  function memoizeCapped2(func) {
2981
3181
  var result2 = memoize2(func, function(key) {
2982
- if (cache.size === MAX_MEMOIZE_SIZE2) {
2983
- cache.clear();
3182
+ if (cache2.size === MAX_MEMOIZE_SIZE2) {
3183
+ cache2.clear();
2984
3184
  }
2985
3185
  return key;
2986
3186
  });
2987
- var cache = result2.cache;
3187
+ var cache2 = result2.cache;
2988
3188
  return result2;
2989
3189
  }
2990
3190
  function mergeData(data, source) {
@@ -3938,12 +4138,12 @@ lodash.exports;
3938
4138
  throw new TypeError2(FUNC_ERROR_TEXT2);
3939
4139
  }
3940
4140
  var memoized = function() {
3941
- var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
3942
- if (cache.has(key)) {
3943
- return cache.get(key);
4141
+ var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache2 = memoized.cache;
4142
+ if (cache2.has(key)) {
4143
+ return cache2.get(key);
3944
4144
  }
3945
4145
  var result2 = func.apply(this, args);
3946
- memoized.cache = cache.set(key, result2) || cache;
4146
+ memoized.cache = cache2.set(key, result2) || cache2;
3947
4147
  return result2;
3948
4148
  };
3949
4149
  memoized.cache = new (memoize2.Cache || MapCache2)();
@@ -9205,7 +9405,7 @@ function baseConvert(util2, name, func, options) {
9205
9405
  throw new TypeError();
9206
9406
  }
9207
9407
  options || (options = {});
9208
- var config = {
9408
+ var config2 = {
9209
9409
  "cap": "cap" in options ? options.cap : true,
9210
9410
  "curry": "curry" in options ? options.curry : true,
9211
9411
  "fixed": "fixed" in options ? options.fixed : true,
@@ -9241,7 +9441,7 @@ function baseConvert(util2, name, func, options) {
9241
9441
  "iteratee": function(iteratee) {
9242
9442
  return function() {
9243
9443
  var func2 = arguments[0], arity = arguments[1], result = iteratee(func2, arity), length = result.length;
9244
- if (config.cap && typeof arity == "number") {
9444
+ if (config2.cap && typeof arity == "number") {
9245
9445
  arity = arity > 2 ? arity - 2 : 1;
9246
9446
  return length && length <= arity ? result : baseAry(result, arity);
9247
9447
  }
@@ -9291,7 +9491,7 @@ function baseConvert(util2, name, func, options) {
9291
9491
  }
9292
9492
  };
9293
9493
  function castCap(name2, func2) {
9294
- if (config.cap) {
9494
+ if (config2.cap) {
9295
9495
  var indexes = mapping.iterateeRearg[name2];
9296
9496
  if (indexes) {
9297
9497
  return iterateeRearg(func2, indexes);
@@ -9304,17 +9504,17 @@ function baseConvert(util2, name, func, options) {
9304
9504
  return func2;
9305
9505
  }
9306
9506
  function castCurry(name2, func2, n) {
9307
- return forceCurry || config.curry && n > 1 ? curry(func2, n) : func2;
9507
+ return forceCurry || config2.curry && n > 1 ? curry(func2, n) : func2;
9308
9508
  }
9309
9509
  function castFixed(name2, func2, n) {
9310
- if (config.fixed && (forceFixed || !mapping.skipFixed[name2])) {
9510
+ if (config2.fixed && (forceFixed || !mapping.skipFixed[name2])) {
9311
9511
  var data = mapping.methodSpread[name2], start = data && data.start;
9312
9512
  return start === void 0 ? ary(func2, n) : flatSpread(func2, start);
9313
9513
  }
9314
9514
  return func2;
9315
9515
  }
9316
9516
  function castRearg(name2, func2, n) {
9317
- return config.rearg && n > 1 && (forceRearg || !mapping.skipRearg[name2]) ? rearg(func2, mapping.methodRearg[name2] || mapping.aryRearg[n]) : func2;
9517
+ return config2.rearg && n > 1 && (forceRearg || !mapping.skipRearg[name2]) ? rearg(func2, mapping.methodRearg[name2] || mapping.aryRearg[n]) : func2;
9318
9518
  }
9319
9519
  function cloneByPath(object2, path2) {
9320
9520
  path2 = toPath(path2);
@@ -9359,7 +9559,7 @@ function baseConvert(util2, name, func, options) {
9359
9559
  while (length--) {
9360
9560
  args[length] = arguments[length];
9361
9561
  }
9362
- var index2 = config.rearg ? 0 : length - 1;
9562
+ var index2 = config2.rearg ? 0 : length - 1;
9363
9563
  args[index2] = transform2(args[index2]);
9364
9564
  return func2.apply(void 0, args);
9365
9565
  };
@@ -9368,7 +9568,7 @@ function baseConvert(util2, name, func, options) {
9368
9568
  var result, realName = mapping.aliasToReal[name2] || name2, wrapped = func2, wrapper = wrappers[realName];
9369
9569
  if (wrapper) {
9370
9570
  wrapped = wrapper(func2);
9371
- } else if (config.immutable) {
9571
+ } else if (config2.immutable) {
9372
9572
  if (mapping.mutate.array[realName]) {
9373
9573
  wrapped = wrapImmutable(func2, cloneArray);
9374
9574
  } else if (mapping.mutate.object[realName]) {
@@ -10660,12 +10860,12 @@ function memoize$1(func, resolver) {
10660
10860
  throw new TypeError(FUNC_ERROR_TEXT);
10661
10861
  }
10662
10862
  var memoized = function() {
10663
- var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache = memoized.cache;
10664
- if (cache.has(key)) {
10665
- return cache.get(key);
10863
+ var args = arguments, key = resolver ? resolver.apply(this, args) : args[0], cache2 = memoized.cache;
10864
+ if (cache2.has(key)) {
10865
+ return cache2.get(key);
10666
10866
  }
10667
10867
  var result = func.apply(this, args);
10668
- memoized.cache = cache.set(key, result) || cache;
10868
+ memoized.cache = cache2.set(key, result) || cache2;
10669
10869
  return result;
10670
10870
  };
10671
10871
  memoized.cache = new (memoize$1.Cache || MapCache$2)();
@@ -10677,12 +10877,12 @@ var memoize = memoize_1;
10677
10877
  var MAX_MEMOIZE_SIZE = 500;
10678
10878
  function memoizeCapped$1(func) {
10679
10879
  var result = memoize(func, function(key) {
10680
- if (cache.size === MAX_MEMOIZE_SIZE) {
10681
- cache.clear();
10880
+ if (cache2.size === MAX_MEMOIZE_SIZE) {
10881
+ cache2.clear();
10682
10882
  }
10683
10883
  return key;
10684
10884
  });
10685
- var cache = result.cache;
10885
+ var cache2 = result.cache;
10686
10886
  return result;
10687
10887
  }
10688
10888
  var _memoizeCapped = memoizeCapped$1;
@@ -11184,8 +11384,8 @@ function arraySome$1(array2, predicate) {
11184
11384
  return false;
11185
11385
  }
11186
11386
  var _arraySome = arraySome$1;
11187
- function cacheHas$1(cache, key) {
11188
- return cache.has(key);
11387
+ function cacheHas$1(cache2, key) {
11388
+ return cache2.has(key);
11189
11389
  }
11190
11390
  var _cacheHas = cacheHas$1;
11191
11391
  var SetCache = _SetCache, arraySome = _arraySome, cacheHas = _cacheHas;
@@ -11810,7 +12010,7 @@ function _objectWithoutPropertiesLoose(source, excluded) {
11810
12010
  }
11811
12011
  return target;
11812
12012
  }
11813
- function createValidation(config) {
12013
+ function createValidation(config2) {
11814
12014
  function validate(_ref, cb) {
11815
12015
  let {
11816
12016
  value,
@@ -11825,7 +12025,7 @@ function createValidation(config) {
11825
12025
  test,
11826
12026
  params,
11827
12027
  message
11828
- } = config;
12028
+ } = config2;
11829
12029
  let {
11830
12030
  parent,
11831
12031
  context
@@ -11880,7 +12080,7 @@ function createValidation(config) {
11880
12080
  else if (!result) cb(createError());
11881
12081
  else cb(null, result);
11882
12082
  }
11883
- validate.OPTIONS = config;
12083
+ validate.OPTIONS = config2;
11884
12084
  return validate;
11885
12085
  }
11886
12086
  let trim = (part) => part.substr(0, part.length - 1).substr(1);
@@ -24570,7 +24770,7 @@ const isPopulateString = (value) => {
24570
24770
  };
24571
24771
  const isStringArray$1 = (value) => fp.isArray(value) && value.every(fp.isString);
24572
24772
  const isObj = (value) => fp.isObject(value);
24573
- const populate$1 = traverseFactory().intercept(isPopulateString, async (visitor2, options, populate2, { recurse }) => {
24773
+ const populate$2 = traverseFactory().intercept(isPopulateString, async (visitor2, options, populate2, { recurse }) => {
24574
24774
  const populateObject = pathsToObjectPopulate([populate2]);
24575
24775
  const traversedPopulate = await recurse(visitor2, options, populateObject);
24576
24776
  const [result] = objectPopulateToPaths(traversedPopulate);
@@ -24738,7 +24938,7 @@ const populate$1 = traverseFactory().intercept(isPopulateString, async (visitor2
24738
24938
  }
24739
24939
  }
24740
24940
  );
24741
- const traverseQueryPopulate = fp.curry(populate$1.traverse);
24941
+ const traverseQueryPopulate = fp.curry(populate$2.traverse);
24742
24942
  const objectPopulateToPaths = (input) => {
24743
24943
  const paths = [];
24744
24944
  function traverse(currentObj, parentPath) {
@@ -25058,54 +25258,40 @@ const hasValue = (value) => {
25058
25258
  return !(value === null || value === void 0 || Array.isArray(value) && value.length === 0 || typeof value === "object" && isEmpty(value));
25059
25259
  };
25060
25260
  async function _populateComponent({
25061
- mainUid,
25062
- mainDocumentId,
25063
- schema: schema2,
25064
25261
  populate: populate2 = {},
25065
25262
  lookup,
25263
+ attrName,
25066
25264
  inDynamicZone = false,
25067
- resolvedRelations,
25068
- omitEmpty
25265
+ ...params
25069
25266
  }) {
25070
- const attrName = lookup.pop();
25071
25267
  const componentLookup = lookup.length === 0 ? [attrName] : [...lookup, inDynamicZone ? "on" : "populate", attrName];
25072
- const componentPopulate = klona(populate2);
25268
+ const componentPopulate = populate2;
25073
25269
  dset(componentPopulate, componentLookup, { populate: "*" });
25074
25270
  const nestedPopulate = await _populate({
25075
- mainUid,
25076
- mainDocumentId,
25077
- schema: schema2,
25078
25271
  populate: componentPopulate,
25079
25272
  lookup: componentLookup,
25080
- resolvedRelations,
25081
- omitEmpty
25273
+ ...params
25082
25274
  });
25083
25275
  return isEmpty(nestedPopulate) ? true : { populate: nestedPopulate };
25084
25276
  }
25085
25277
  async function _populateDynamicZone({
25086
- mainUid,
25087
- mainDocumentId,
25088
25278
  components,
25089
- populate: populate2,
25090
25279
  lookup,
25091
- resolvedRelations,
25092
- omitEmpty
25280
+ attrName,
25281
+ ...params
25093
25282
  }) {
25094
- const resolvedPopulate = await components.reduce(async (prev, cur) => {
25095
- const curPopulate = await _populateComponent({
25096
- mainUid,
25097
- mainDocumentId,
25098
- schema: cur,
25099
- populate: populate2,
25100
- lookup: [...lookup, cur],
25283
+ const dynamicZoneLookup = [...lookup, attrName];
25284
+ const resolvedPopulate = {};
25285
+ for (const component of components) {
25286
+ const componentPopulate = await _populateComponent({
25287
+ schema: component,
25288
+ lookup: dynamicZoneLookup,
25289
+ attrName: component,
25101
25290
  inDynamicZone: true,
25102
- resolvedRelations,
25103
- omitEmpty
25291
+ ...params
25104
25292
  });
25105
- const newPop = await prev;
25106
- dset(newPop, [cur], curPopulate);
25107
- return newPop;
25108
- }, Promise.resolve({}));
25293
+ dset(resolvedPopulate, [component], componentPopulate);
25294
+ }
25109
25295
  if (isEmpty(resolvedPopulate)) return void 0;
25110
25296
  return { on: resolvedPopulate };
25111
25297
  }
@@ -25116,18 +25302,23 @@ async function _populateRelation({
25116
25302
  contentType,
25117
25303
  relation,
25118
25304
  resolvedRelations,
25119
- omitEmpty
25305
+ omitEmpty,
25306
+ locale: locale2,
25307
+ status: status2
25120
25308
  }) {
25121
25309
  const isSingleRelation = !Array.isArray(relation);
25122
25310
  const relations = isSingleRelation ? [relation] : relation;
25123
- for (const relation2 of relations.filter(({ documentId }) => !resolvedRelations.has(documentId))) {
25311
+ const nonResolvedRelations = relations.filter(({ documentId }) => !resolvedRelations.has(documentId));
25312
+ for (const relation2 of nonResolvedRelations) {
25124
25313
  resolvedRelations.set(relation2.documentId, {});
25125
25314
  const relationPopulate = await _populate({
25126
- mainUid: contentType,
25127
- mainDocumentId: relation2.documentId,
25315
+ contentType,
25316
+ documentId: relation2.documentId,
25128
25317
  schema: contentType,
25129
25318
  resolvedRelations,
25130
- omitEmpty
25319
+ omitEmpty,
25320
+ locale: locale2,
25321
+ status: status2
25131
25322
  });
25132
25323
  resolvedRelations.set(relation2.documentId, relationPopulate);
25133
25324
  }
@@ -25157,7 +25348,7 @@ const _resolveValue = ({ document: document2, lookup, attrName }) => {
25157
25348
  const childLookup = lookup[populateIdx + 1];
25158
25349
  const parentValue2 = delve(document2, parentLookup);
25159
25350
  const childValue = (Array.isArray(parentValue2) ? parentValue2 : [parentValue2]).map(
25160
- (v) => _resolveValue({ document: parentValue2, lookup: childLookup, attrName })
25351
+ (v) => _resolveValue({ document: v, lookup: childLookup, attrName })
25161
25352
  );
25162
25353
  return childValue.find((v) => hasValue(v));
25163
25354
  }
@@ -25168,18 +25359,18 @@ const _resolveValue = ({ document: document2, lookup, attrName }) => {
25168
25359
  return parentValue?.[attrName];
25169
25360
  };
25170
25361
  async function _populate({
25171
- mainUid,
25172
- mainDocumentId,
25362
+ contentType,
25173
25363
  schema: schema2,
25174
25364
  populate: populate2 = {},
25175
25365
  lookup = [],
25176
- resolvedRelations = /* @__PURE__ */ new Map(),
25177
- omitEmpty = true
25366
+ resolvedRelations,
25367
+ omitEmpty,
25368
+ ...params
25178
25369
  }) {
25179
25370
  const newPopulate = {};
25180
- const model = strapi.getModel(schema2);
25181
- const relations = getRelations(model);
25182
- const currentPopulate = klona(populate2);
25371
+ let relations = getRelations(strapi.getModel(schema2));
25372
+ let currentPopulate = klona(populate2);
25373
+ resolvedRelations.set(params.documentId, true);
25183
25374
  for (const [attrName] of relations) {
25184
25375
  if (lookup.length > 0) {
25185
25376
  const parent = delve(currentPopulate, lookup);
@@ -25190,47 +25381,56 @@ async function _populate({
25190
25381
  dset(currentPopulate, attrName, { populate: "*" });
25191
25382
  }
25192
25383
  }
25193
- const document2 = await strapi.documents(mainUid).findOne({
25194
- documentId: mainDocumentId,
25384
+ let document2 = await strapi.documents(contentType).findOne({
25385
+ ...params,
25195
25386
  populate: currentPopulate ? currentPopulate : "*"
25196
25387
  });
25388
+ currentPopulate = null;
25389
+ const resolveRelations = [];
25197
25390
  for (const [attrName, attr] of relations) {
25198
25391
  const value = _resolveValue({ document: document2, attrName, lookup });
25199
25392
  if (!hasValue(value)) {
25200
25393
  if (!omitEmpty) newPopulate[attrName] = true;
25201
25394
  continue;
25202
25395
  }
25396
+ resolveRelations.push([attrName, attr, value]);
25397
+ }
25398
+ relations = null;
25399
+ document2 = null;
25400
+ for (const [attrName, attr, value] of resolveRelations) {
25203
25401
  if (contentTypes.isDynamicZoneAttribute(attr)) {
25204
25402
  const relComponents = value.map(
25205
25403
  (dataComponent) => attr.components.find((schemaComponent) => schemaComponent === dataComponent.__component)
25206
25404
  );
25207
25405
  newPopulate[attrName] = await _populateDynamicZone({
25208
- mainUid,
25209
- mainDocumentId,
25406
+ contentType,
25210
25407
  components: relComponents,
25211
- lookup: [...lookup, attrName],
25408
+ lookup,
25409
+ attrName,
25212
25410
  resolvedRelations,
25213
- omitEmpty
25411
+ omitEmpty,
25412
+ ...params
25214
25413
  });
25215
25414
  }
25216
25415
  if (contentTypes.isRelationalAttribute(attr)) {
25217
- const { target: relContentType } = attr;
25218
- resolvedRelations.set(mainDocumentId, true);
25219
25416
  newPopulate[attrName] = await _populateRelation({
25220
- contentType: relContentType,
25417
+ contentType: attr.target,
25221
25418
  relation: value,
25222
25419
  resolvedRelations,
25223
- omitEmpty
25420
+ omitEmpty,
25421
+ locale: params.locale,
25422
+ status: params.status
25224
25423
  });
25225
25424
  }
25226
25425
  if (contentTypes.isComponentAttribute(attr) && !contentTypes.isDynamicZoneAttribute(attr)) {
25227
25426
  newPopulate[attrName] = await _populateComponent({
25228
- mainUid,
25229
- mainDocumentId,
25427
+ contentType,
25230
25428
  schema: attr.component,
25231
- lookup: [...lookup, attrName],
25429
+ lookup,
25430
+ attrName,
25232
25431
  resolvedRelations,
25233
- omitEmpty
25432
+ omitEmpty,
25433
+ ...params
25234
25434
  });
25235
25435
  }
25236
25436
  if (contentTypes.isMediaAttribute(attr)) {
@@ -25239,43 +25439,31 @@ async function _populate({
25239
25439
  }
25240
25440
  return newPopulate;
25241
25441
  }
25442
+ async function populate$1(params) {
25443
+ const resolvedRelations = /* @__PURE__ */ new Map();
25444
+ const populated = await _populate({ ...params, schema: params.contentType, resolvedRelations });
25445
+ return { populate: populated, dependencies: [...resolvedRelations.keys()] };
25446
+ }
25242
25447
  const populate = ({ strapi: strapi2 }) => ({
25243
- async get({
25244
- contentType,
25245
- documentId,
25246
- omitEmpty = false
25247
- }) {
25248
- return await _populate({ mainUid: contentType, mainDocumentId: documentId, schema: contentType, omitEmpty });
25249
- },
25250
- documents(contentType) {
25251
- strapi2.documents(contentType);
25252
- const { findOne, ...wrapped } = strapi2.documents(contentType);
25253
- const wrappedFindOne = async (params) => {
25254
- const { documentId, populate: originalPopulate } = params;
25255
- const deepPopulate = await _populate({
25256
- mainUid: contentType,
25257
- mainDocumentId: documentId,
25258
- schema: contentType,
25259
- omitEmpty: originalPopulate !== "*"
25260
- });
25261
- if (originalPopulate && originalPopulate !== "*") {
25262
- strapi2.log.warn(
25263
- `passed "populate" will be merged with deepPopulate, which could result in unexpected behavior.`
25264
- );
25265
- if (typeof originalPopulate === "object")
25266
- Object.keys(originalPopulate).map((k) => dset(deepPopulate, k, originalPopulate[k]));
25267
- if (Array.isArray(originalPopulate)) originalPopulate.map((k) => dset(deepPopulate, k, true));
25268
- }
25269
- return await findOne({ ...params, populate: deepPopulate });
25270
- };
25271
- return { ...wrapped, findOne: wrappedFindOne };
25448
+ async get(params) {
25449
+ const { cachePopulate } = strapi2.config.get("plugin::deep-populate");
25450
+ if (!cachePopulate) return (await populate$1(params)).populate;
25451
+ const cachedEntry = await strapi2.service("plugin::deep-populate.cache").get(params);
25452
+ if (cachedEntry) return cachedEntry;
25453
+ const resolved = await populate$1(params);
25454
+ await strapi2.service("plugin::deep-populate.cache").set({ ...params, ...resolved });
25455
+ return resolved;
25272
25456
  }
25273
25457
  });
25274
25458
  const services = {
25275
- populate
25459
+ populate,
25460
+ cache
25276
25461
  };
25277
25462
  const index = {
25278
- services
25463
+ config,
25464
+ contentTypes: contentTypes$1,
25465
+ services,
25466
+ register
25279
25467
  };
25280
25468
  export {
25281
25469
  index as default