medusa-product-helper 0.0.13 → 0.0.18

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.
Files changed (29) hide show
  1. package/.medusa/server/src/admin/index.js +59 -117
  2. package/.medusa/server/src/admin/index.mjs +59 -117
  3. package/.medusa/server/src/api/store/product-helper/products/route.js +112 -0
  4. package/.medusa/server/src/api/store/product-helper/products/validators.js +3 -1
  5. package/.medusa/server/src/config/product-helper-options.js +15 -1
  6. package/.medusa/server/src/index.js +101 -0
  7. package/.medusa/server/src/providers/filter-providers/availability-provider.js +82 -0
  8. package/.medusa/server/src/providers/filter-providers/base-filter-provider.js +14 -0
  9. package/.medusa/server/src/providers/filter-providers/base-product-provider.js +59 -0
  10. package/.medusa/server/src/providers/filter-providers/category-provider.js +36 -0
  11. package/.medusa/server/src/providers/filter-providers/collection-provider.js +36 -0
  12. package/.medusa/server/src/providers/filter-providers/index.js +58 -0
  13. package/.medusa/server/src/providers/filter-providers/metadata-provider.js +69 -0
  14. package/.medusa/server/src/providers/filter-providers/price-range-provider.js +95 -0
  15. package/.medusa/server/src/providers/filter-providers/promotion-provider.js +134 -0
  16. package/.medusa/server/src/providers/filter-providers/promotion-window-provider.js +85 -0
  17. package/.medusa/server/src/providers/filter-providers/rating-provider.js +69 -0
  18. package/.medusa/server/src/services/dynamic-filter-service.js +525 -0
  19. package/.medusa/server/src/services/filter-provider-loader.js +107 -0
  20. package/.medusa/server/src/services/filter-provider-registry.js +43 -0
  21. package/.medusa/server/src/services/product-filter-service.js +183 -0
  22. package/.medusa/server/src/shared/product-metadata/utils.js +66 -116
  23. package/.medusa/server/src/utils/query-builders/product-filters.js +89 -111
  24. package/.medusa/server/src/utils/query-parser.js +51 -0
  25. package/.medusa/server/src/workflows/add-to-wishlist.js +12 -26
  26. package/.medusa/server/src/workflows/get-wishlist.js +53 -51
  27. package/.medusa/server/src/workflows/remove-from-wishlist.js +3 -8
  28. package/README.md +89 -0
  29. package/package.json +3 -3
@@ -0,0 +1,525 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DynamicFilterService = void 0;
4
+ const utils_1 = require("@medusajs/framework/utils");
5
+ const filter_provider_registry_1 = require("./filter-provider-registry");
6
+ class DynamicFilterService {
7
+ constructor(container) {
8
+ this.registry = this.resolveRegistry(container);
9
+ this.query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
10
+ }
11
+ getRegistry() {
12
+ return this.registry;
13
+ }
14
+ async applyFilters(options) {
15
+ const { filterParams, options: pluginOptions, pagination, projection, context = {} } = options;
16
+ const filterContext = { ...context, options: pluginOptions };
17
+ const { queryFilters, priceRangeFilter, promotionFilter } = await this.processFilters(filterParams, filterContext);
18
+ const fields = this.buildFields(projection?.fields);
19
+ const queryContext = this.buildQueryContext(context);
20
+ const queryOptions = this.buildQueryOptions(queryFilters, fields, pagination, queryContext);
21
+ const result = await this.query.graph(queryOptions);
22
+ const { data: productsRaw = [], metadata } = result;
23
+ let products = this.normalizeProducts(productsRaw);
24
+ products = await this.applyPostQueryFilters(products, priceRangeFilter, promotionFilter);
25
+ // Count should reflect filtered products, not initial query count
26
+ // If post-query filters were applied, use filtered products length
27
+ // Otherwise, use metadata count or products length
28
+ const hasPostQueryFilters = priceRangeFilter || promotionFilter;
29
+ const count = hasPostQueryFilters
30
+ ? products.length
31
+ : await this.getCount(queryFilters, metadata, products.length);
32
+ return {
33
+ products,
34
+ count,
35
+ metadata: {
36
+ count,
37
+ skip: pagination?.offset,
38
+ take: pagination?.limit || (hasPostQueryFilters ? undefined : 20),
39
+ },
40
+ };
41
+ }
42
+ resolveRegistry(container) {
43
+ try {
44
+ return container.resolve("filterProviderRegistry");
45
+ }
46
+ catch {
47
+ const registry = new filter_provider_registry_1.FilterProviderRegistry();
48
+ this.autoRegisterBuiltInProviders(registry);
49
+ return registry;
50
+ }
51
+ }
52
+ autoRegisterBuiltInProviders(registry) {
53
+ try {
54
+ const { registerBuiltInProviders } = require("../providers/filter-providers");
55
+ registerBuiltInProviders(registry);
56
+ }
57
+ catch (error) {
58
+ console.warn("[DynamicFilterService] Failed to auto-register built-in providers:", error);
59
+ }
60
+ }
61
+ async processFilters(filterParams, filterContext) {
62
+ let queryFilters = {};
63
+ let priceRangeFilter;
64
+ let promotionFilter;
65
+ for (const [identifier, value] of Object.entries(filterParams)) {
66
+ if (value == null)
67
+ continue;
68
+ const provider = this.registry.get(identifier);
69
+ if (!provider) {
70
+ console.warn(`[DynamicFilterService] No filter provider found for: "${identifier}"`);
71
+ continue;
72
+ }
73
+ try {
74
+ this.validateWithProvider(provider, value);
75
+ const result = await Promise.resolve(provider.apply(queryFilters, value, filterContext));
76
+ queryFilters = result;
77
+ priceRangeFilter = queryFilters.__price_range_filter__;
78
+ promotionFilter = queryFilters.__promotion_filter__;
79
+ delete queryFilters.__price_range_filter__;
80
+ delete queryFilters.__promotion_filter__;
81
+ }
82
+ catch (error) {
83
+ throw new Error(`Error applying filter "${identifier}": ${error}`);
84
+ }
85
+ }
86
+ return { queryFilters, priceRangeFilter, promotionFilter };
87
+ }
88
+ validateWithProvider(provider, value) {
89
+ if (provider.validate) {
90
+ const validationResult = provider.validate(value);
91
+ if (Array.isArray(validationResult)) {
92
+ const errors = validationResult.map(err => `${err.path ? `${err.path}: ` : ""}${err.message}`).join(", ");
93
+ throw new Error(errors);
94
+ }
95
+ }
96
+ }
97
+ buildFields(requestedFields) {
98
+ const essentialRelations = [
99
+ "variants.*", "variants.prices.*",
100
+ "options.*", "options.values.*",
101
+ "images.*", "collection.*", "type.*"
102
+ ];
103
+ if (!requestedFields?.length || requestedFields.includes("*")) {
104
+ return ["*", ...essentialRelations];
105
+ }
106
+ const fields = [...requestedFields];
107
+ const has = (prefix) => fields.some(f => f.startsWith(prefix));
108
+ if (!has("variants"))
109
+ fields.push("variants.*", "variants.prices.*");
110
+ if (!has("options"))
111
+ fields.push("options.*", "options.values.*");
112
+ if (!has("images"))
113
+ fields.push("images.*");
114
+ if (!has("collection"))
115
+ fields.push("collection.*");
116
+ if (!has("type"))
117
+ fields.push("type.*");
118
+ return fields;
119
+ }
120
+ buildQueryContext(context) {
121
+ if (context?.pricingContext) {
122
+ return { variants: { calculated_price: context.pricingContext } };
123
+ }
124
+ return {};
125
+ }
126
+ buildQueryOptions(filters, fields, pagination, queryContext) {
127
+ const options = {
128
+ entity: "product",
129
+ fields,
130
+ ...(Object.keys(filters).length > 0 && { filters }),
131
+ };
132
+ if (pagination) {
133
+ options.pagination = {};
134
+ // Ensure default limit if limit is 0 or undefined
135
+ if (pagination.limit !== undefined && pagination.limit > 0) {
136
+ options.pagination.take = pagination.limit;
137
+ }
138
+ else {
139
+ // Default limit when limit is 0 or undefined
140
+ options.pagination.take = 20;
141
+ }
142
+ if (pagination.offset !== undefined) {
143
+ options.pagination.skip = pagination.offset;
144
+ }
145
+ }
146
+ else {
147
+ // If no pagination provided, set default
148
+ options.pagination = {
149
+ take: 20,
150
+ skip: 0
151
+ };
152
+ }
153
+ if (queryContext && Object.keys(queryContext).length > 0) {
154
+ options.context = queryContext;
155
+ }
156
+ return options;
157
+ }
158
+ normalizeProducts(productsRaw) {
159
+ if (Array.isArray(productsRaw)) {
160
+ return productsRaw.filter(p => p != null);
161
+ }
162
+ console.warn("[DynamicFilterService] Unexpected data structure from query.graph()");
163
+ return [];
164
+ }
165
+ async applyPostQueryFilters(products, priceRangeFilter, promotionFilter) {
166
+ let filteredProducts = products;
167
+ if (priceRangeFilter && filteredProducts.length > 0) {
168
+ filteredProducts = this.filterByPriceRange(filteredProducts, priceRangeFilter);
169
+ }
170
+ if (promotionFilter && filteredProducts.length > 0) {
171
+ filteredProducts = await this.filterByPromotion(filteredProducts, promotionFilter);
172
+ }
173
+ return filteredProducts;
174
+ }
175
+ filterByPriceRange(products, priceRangeFilter) {
176
+ return products.filter(product => {
177
+ if (!product.variants?.length)
178
+ return false;
179
+ return product.variants.some((variant) => {
180
+ const priceInfo = this.getPriceInfo(variant);
181
+ if (!priceInfo.price)
182
+ return false;
183
+ if (priceRangeFilter.currency_code && priceInfo.currency !== priceRangeFilter.currency_code) {
184
+ return false;
185
+ }
186
+ const { min, max } = priceRangeFilter;
187
+ if (min !== undefined && priceInfo.price < min)
188
+ return false;
189
+ if (max !== undefined && priceInfo.price > max)
190
+ return false;
191
+ return true;
192
+ });
193
+ });
194
+ }
195
+ getPriceInfo(variant) {
196
+ if (variant.calculated_price?.calculated_amount !== undefined) {
197
+ return {
198
+ price: variant.calculated_price.calculated_amount,
199
+ currency: variant.calculated_price.currency_code
200
+ };
201
+ }
202
+ if (variant.prices?.[0]) {
203
+ const price = variant.prices[0];
204
+ return { price: price.amount, currency: price.currency_code };
205
+ }
206
+ return {};
207
+ }
208
+ async filterByPromotion(products, promotionFilter) {
209
+ try {
210
+ const promotions = await this.fetchPromotions(promotionFilter);
211
+ // Debug logging
212
+ console.log(`[DynamicFilterService] Found ${promotions.length} promotions matching filter`);
213
+ if (promotions.length === 0) {
214
+ console.warn("[DynamicFilterService] No promotions found - returning empty array");
215
+ return [];
216
+ }
217
+ const productPromotionData = await this.extractProductPromotionData(promotions);
218
+ // Debug logging
219
+ console.log(`[DynamicFilterService] Extracted ${productPromotionData.productIds.size} unique product IDs from promotions`);
220
+ console.log(`[DynamicFilterService] Found discounts for ${productPromotionData.discounts.size} products`);
221
+ console.log(`[DynamicFilterService] Has universal promotions (no rules): ${productPromotionData.hasUniversalPromotions}`);
222
+ // If we have universal promotions (no rules = applies to all products)
223
+ // or if we have product IDs, filter accordingly
224
+ const hasProductIds = productPromotionData.productIds.size > 0;
225
+ const hasUniversalPromotions = productPromotionData.hasUniversalPromotions;
226
+ if (!hasProductIds && !hasUniversalPromotions) {
227
+ console.warn("[DynamicFilterService] No product IDs found and no universal promotions - returning empty array");
228
+ return [];
229
+ }
230
+ const filtered = products.filter(product => {
231
+ const productId = product?.id;
232
+ if (!productId)
233
+ return false;
234
+ // If promotion has no rules (universal), it applies to all products
235
+ // Otherwise, check if product is in the promotion's product list
236
+ if (hasProductIds && !productPromotionData.productIds.has(productId)) {
237
+ return false;
238
+ }
239
+ // Get discount for this product (from specific promotion or universal promotion)
240
+ let discount = productPromotionData.discounts.get(productId) || 0;
241
+ // If no specific discount found but we have universal promotions, use the universal discount
242
+ if (discount === 0 && hasUniversalPromotions) {
243
+ // Use the discount from the first universal promotion
244
+ discount = productPromotionData.universalDiscount || 0;
245
+ }
246
+ const meetsCriteria = this.meetsDiscountCriteria(discount, promotionFilter);
247
+ if (!meetsCriteria) {
248
+ console.log(`[DynamicFilterService] Product ${productId} discount ${discount}% does not meet criteria (min: ${promotionFilter.min_discount_percentage}, max: ${promotionFilter.max_discount_percentage})`);
249
+ }
250
+ return meetsCriteria;
251
+ });
252
+ console.log(`[DynamicFilterService] Filtered ${products.length} products down to ${filtered.length} matching promotion criteria`);
253
+ return filtered;
254
+ }
255
+ catch (error) {
256
+ console.warn("[DynamicFilterService] Error filtering by promotions:", error);
257
+ return products;
258
+ }
259
+ }
260
+ async fetchPromotions(promotionFilter) {
261
+ const queryOptions = {
262
+ entity: "promotion",
263
+ fields: [
264
+ "id", "code", "type", "application_method.*", "campaign.*",
265
+ "rules.*", "rules.values.*", "starts_at", "ends_at", "status", "metadata"
266
+ ],
267
+ };
268
+ const filters = {};
269
+ // Status filter (default to active if not specified)
270
+ if (promotionFilter.status) {
271
+ filters.status = promotionFilter.status;
272
+ }
273
+ else {
274
+ // Default to active promotions
275
+ filters.status = "active";
276
+ }
277
+ if (promotionFilter.promotion_type) {
278
+ filters.type = promotionFilter.promotion_type;
279
+ }
280
+ if (Object.keys(filters).length > 0) {
281
+ queryOptions.filters = filters;
282
+ }
283
+ // Fetch all promotions matching status/type filters
284
+ // Date filtering will be done in code since Medusa query API
285
+ // may not support complex date range queries
286
+ const result = await this.query.graph(queryOptions);
287
+ let promotions = Array.isArray(result.data) ? result.data : [];
288
+ // Filter by date ranges in code
289
+ const now = new Date();
290
+ promotions = promotions.filter((promo) => {
291
+ // Check starts_at
292
+ if (promo.starts_at) {
293
+ const startsAt = new Date(promo.starts_at);
294
+ if (promotionFilter.starts_at) {
295
+ // If specific starts_at filter provided, check if promotion starts at or before it
296
+ const filterStartsAt = new Date(promotionFilter.starts_at);
297
+ if (startsAt > filterStartsAt)
298
+ return false;
299
+ }
300
+ else {
301
+ // Default: only include promotions that have started
302
+ if (startsAt > now)
303
+ return false;
304
+ }
305
+ }
306
+ // Check ends_at
307
+ if (promo.ends_at) {
308
+ const endsAt = new Date(promo.ends_at);
309
+ if (promotionFilter.ends_at) {
310
+ // If specific ends_at filter provided, check if promotion ends at or after it
311
+ const filterEndsAt = new Date(promotionFilter.ends_at);
312
+ if (endsAt < filterEndsAt)
313
+ return false;
314
+ }
315
+ else {
316
+ // Default: only include promotions that haven't ended yet
317
+ if (endsAt < now)
318
+ return false;
319
+ }
320
+ }
321
+ else {
322
+ // Open-ended promotion (no ends_at)
323
+ // Include if include_open_ended is true (default) or not explicitly false
324
+ if (promotionFilter.include_open_ended === false) {
325
+ return false;
326
+ }
327
+ }
328
+ return true;
329
+ });
330
+ return promotions;
331
+ }
332
+ async extractProductPromotionData(promotions) {
333
+ const productIds = new Set();
334
+ const discounts = new Map();
335
+ let hasUniversalPromotions = false;
336
+ let universalDiscount = 0;
337
+ for (const promotion of promotions) {
338
+ const discount = this.calculateDiscountPercentage(promotion);
339
+ // Debug: Log full promotion structure for first promotion
340
+ if (promotions.indexOf(promotion) === 0) {
341
+ console.log(`[DynamicFilterService] Promotion structure:`, JSON.stringify({
342
+ id: promotion.id,
343
+ code: promotion.code,
344
+ type: promotion.type,
345
+ rules: promotion.rules,
346
+ application_method: promotion.application_method,
347
+ metadata: promotion.metadata
348
+ }, null, 2));
349
+ }
350
+ // Check if promotion has no rules (universal promotion - applies to all products)
351
+ const hasNoRules = !promotion.rules || promotion.rules.length === 0;
352
+ if (hasNoRules) {
353
+ console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code} has no rules - applies to all products`);
354
+ hasUniversalPromotions = true;
355
+ if (discount !== undefined && discount > universalDiscount) {
356
+ universalDiscount = discount;
357
+ }
358
+ }
359
+ const ids = await this.extractProductIdsFromPromotion(promotion);
360
+ // Debug logging for first promotion
361
+ if (promotions.indexOf(promotion) === 0) {
362
+ console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: discount=${discount}%, productIds=${ids.length}, universal=${hasNoRules}`);
363
+ if (ids.length > 0) {
364
+ console.log(`[DynamicFilterService] Sample product IDs: ${ids.slice(0, 3).join(", ")}`);
365
+ }
366
+ else if (!hasNoRules) {
367
+ console.warn(`[DynamicFilterService] No product IDs extracted from promotion ${promotion.id || promotion.code}`);
368
+ }
369
+ }
370
+ // Only add product IDs if promotion has rules
371
+ // Universal promotions (no rules) apply to all products
372
+ if (!hasNoRules) {
373
+ ids.forEach(id => {
374
+ productIds.add(id);
375
+ if (discount !== undefined) {
376
+ const currentMax = discounts.get(id) || 0;
377
+ discounts.set(id, Math.max(currentMax, discount));
378
+ }
379
+ });
380
+ }
381
+ }
382
+ return { productIds, discounts, hasUniversalPromotions, universalDiscount };
383
+ }
384
+ calculateDiscountPercentage(promotion) {
385
+ const appMethod = promotion.application_method;
386
+ if (!appMethod || typeof appMethod !== "object") {
387
+ console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: No application_method`);
388
+ return undefined;
389
+ }
390
+ // Try to get discount from application_method.type === "percentage"
391
+ if (appMethod.type === "percentage" && "value" in appMethod) {
392
+ const value = typeof appMethod.value === "number" ? appMethod.value : Number(appMethod.value);
393
+ if (!Number.isNaN(value)) {
394
+ console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: Found percentage discount ${value}% from application_method.type=percentage`);
395
+ return value;
396
+ }
397
+ }
398
+ // Try to get discount from promotion type
399
+ if (promotion.type === "percentage_off_product" || promotion.type === "percentage_off_order") {
400
+ if ("value" in appMethod) {
401
+ const value = typeof appMethod.value === "number" ? appMethod.value : Number(appMethod.value);
402
+ if (!Number.isNaN(value)) {
403
+ console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: Found percentage discount ${value}% from promotion.type=${promotion.type}`);
404
+ return value;
405
+ }
406
+ }
407
+ }
408
+ console.log(`[DynamicFilterService] Promotion ${promotion.id || promotion.code}: Could not calculate discount percentage. type=${promotion.type}, appMethod.type=${appMethod.type}, appMethod.value=${appMethod.value}`);
409
+ return undefined;
410
+ }
411
+ async extractProductIdsFromPromotion(promotion) {
412
+ const productIds = new Set();
413
+ // Debug: Log rule structure
414
+ if (promotion.rules?.length) {
415
+ console.log(`[DynamicFilterService] Processing ${promotion.rules.length} rules for promotion ${promotion.id || promotion.code}`);
416
+ for (const rule of promotion.rules) {
417
+ const ruleType = rule.type || rule.attribute || "";
418
+ const normalizedType = String(ruleType).toLowerCase();
419
+ console.log(`[DynamicFilterService] Rule: type=${ruleType}, attribute=${rule.attribute}, values=`, rule.values);
420
+ // Skip rules that definitely don't contain product IDs
421
+ if (normalizedType &&
422
+ (normalizedType === "customer_groups" ||
423
+ normalizedType === "regions" ||
424
+ normalizedType === "currency" ||
425
+ normalizedType === "customer_group" ||
426
+ normalizedType === "region")) {
427
+ console.log(`[DynamicFilterService] Skipping non-product rule: ${ruleType}`);
428
+ continue;
429
+ }
430
+ // Process all other rules (including product-related ones)
431
+ // In Medusa v2, rules.values can be:
432
+ // - An array of strings (product IDs)
433
+ // - An array of objects with id/value fields
434
+ // - A single value
435
+ let values = [];
436
+ if (Array.isArray(rule.values)) {
437
+ values = rule.values;
438
+ }
439
+ else if (rule.values !== undefined && rule.values !== null) {
440
+ values = [rule.values];
441
+ }
442
+ console.log(`[DynamicFilterService] Processing ${values.length} values from rule ${ruleType}`);
443
+ for (const value of values) {
444
+ if (typeof value === "string") {
445
+ // String values could be product IDs
446
+ if (value.length > 0) {
447
+ console.log(`[DynamicFilterService] Adding product ID from string: ${value}`);
448
+ productIds.add(value);
449
+ }
450
+ }
451
+ else if (typeof value === "object" && value !== null) {
452
+ // Handle object values - could be { id: "prod_123" } or similar
453
+ console.log(`[DynamicFilterService] Processing object value:`, value);
454
+ if ("id" in value && typeof value.id === "string") {
455
+ console.log(`[DynamicFilterService] Adding product ID from object.id: ${value.id}`);
456
+ productIds.add(value.id);
457
+ }
458
+ else if ("value" in value && typeof value.value === "string") {
459
+ console.log(`[DynamicFilterService] Adding product ID from object.value: ${value.value}`);
460
+ productIds.add(value.value);
461
+ }
462
+ else if ("product_id" in value && typeof value.product_id === "string") {
463
+ console.log(`[DynamicFilterService] Adding product ID from object.product_id: ${value.product_id}`);
464
+ productIds.add(value.product_id);
465
+ }
466
+ else {
467
+ // Try to extract any string field that looks like an ID
468
+ for (const [key, val] of Object.entries(value)) {
469
+ if (typeof val === "string" && val.length > 0 && (val.startsWith("prod_") || key.toLowerCase().includes("id"))) {
470
+ console.log(`[DynamicFilterService] Adding product ID from object.${key}: ${val}`);
471
+ productIds.add(val);
472
+ }
473
+ }
474
+ }
475
+ }
476
+ }
477
+ }
478
+ }
479
+ else {
480
+ console.log(`[DynamicFilterService] No rules found in promotion ${promotion.id || promotion.code}`);
481
+ }
482
+ // Also check metadata for product IDs (fallback)
483
+ if (promotion.metadata?.product_ids?.length) {
484
+ console.log(`[DynamicFilterService] Found product IDs in metadata:`, promotion.metadata.product_ids);
485
+ promotion.metadata.product_ids.forEach((id) => {
486
+ if (typeof id === "string") {
487
+ productIds.add(id);
488
+ }
489
+ });
490
+ }
491
+ const result = Array.from(productIds);
492
+ console.log(`[DynamicFilterService] Extracted ${result.length} product IDs:`, result);
493
+ return result;
494
+ }
495
+ meetsDiscountCriteria(discount, promotionFilter) {
496
+ if (promotionFilter.min_discount_percentage !== undefined &&
497
+ discount < promotionFilter.min_discount_percentage) {
498
+ return false;
499
+ }
500
+ if (promotionFilter.max_discount_percentage !== undefined &&
501
+ discount > promotionFilter.max_discount_percentage) {
502
+ return false;
503
+ }
504
+ return true;
505
+ }
506
+ async getCount(queryFilters, metadata, productsLength) {
507
+ if (metadata?.count !== undefined)
508
+ return metadata.count;
509
+ try {
510
+ const countResult = await this.query.graph({
511
+ entity: "product",
512
+ fields: ["id"],
513
+ ...(Object.keys(queryFilters).length > 0 && { filters: queryFilters }),
514
+ });
515
+ return countResult.metadata?.count ||
516
+ (Array.isArray(countResult.data) ? countResult.data.length : productsLength);
517
+ }
518
+ catch (error) {
519
+ console.warn("[DynamicFilterService] Could not determine count:", error);
520
+ return productsLength;
521
+ }
522
+ }
523
+ }
524
+ exports.DynamicFilterService = DynamicFilterService;
525
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHluYW1pYy1maWx0ZXItc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9keW5hbWljLWZpbHRlci1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLHFEQUFxRTtBQUNyRSx5RUFBbUU7QUFrQm5FLE1BQWEsb0JBQW9CO0lBSS9CLFlBQVksU0FBMEI7UUFDcEMsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQyxDQUFBO1FBQy9DLElBQUksQ0FBQyxLQUFLLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBUSxpQ0FBeUIsQ0FBQyxLQUFLLENBQUMsQ0FBQTtJQUN4RSxDQUFDO0lBRUQsV0FBVztRQUNULE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQTtJQUN0QixDQUFDO0lBRUQsS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUE0QjtRQUM3QyxNQUFNLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxPQUFPLEdBQUcsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFBO1FBQzlGLE1BQU0sYUFBYSxHQUFrQixFQUFFLEdBQUcsT0FBTyxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsQ0FBQTtRQUUzRSxNQUFNLEVBQUUsWUFBWSxFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxZQUFZLEVBQUUsYUFBYSxDQUFDLENBQUE7UUFFbEgsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUE7UUFDbkQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3BELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFF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