summaryrefslogtreecommitdiff
path: root/src/lib/utils/batchSolrQueries.js
blob: 486f1778a2e506fe80756a45077ecf3ffcf6dc12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/**
 * Batch utility functions for handling large product ID arrays in Solr queries
 * Prevents URL length limit errors when querying with >100 product IDs
 */

/**
 * Split an array into chunks of specified size
 * @param {Array} array - Array to split
 * @param {number} size - Chunk size (default: 100)
 * @returns {Array<Array>} Array of chunks
 */
export const chunkArray = (array, size = 100) => {
  if (!Array.isArray(array) || array.length === 0) return [];

  const chunks = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
};

/**
 * Build a product ID OR clause for Solr query
 * @param {Array<string|number>} ids - Array of product IDs
 * @returns {string} Formatted OR clause: "product_id_i:123 OR product_id_i:456..."
 */
export const buildProductIdOrClause = (ids) => {
  if (!Array.isArray(ids) || ids.length === 0) {
    return '*:*';
  }
  return ids.map((id) => `product_id_i:${id}`).join(' OR ');
};

/**
 * Validate query size to prevent exceeding HTTP limits
 * @param {string} query - Query string to validate
 * @param {number} maxSize - Maximum allowed size in characters (default: 6000)
 * @returns {Object} { valid: boolean, message: string, size: number }
 */
export const validateQuerySize = (query, maxSize = 6000) => {
  const size = query.length;
  return {
    valid: size <= maxSize,
    message:
      size > maxSize
        ? `Query size ${size} exceeds limit of ${maxSize}`
        : `Query size ${size} is within limit`,
    size,
  };
};

/**
 * Build batched Solr query parameters for large ID arrays
 * Chunks IDs into groups and creates separate OR clauses
 * @param {Array<string|number>} ids - Product IDs to query
 * @param {number} chunkSize - How many IDs per chunk (default: 100)
 * @returns {Array<string>} Array of OR clauses, one per chunk
 */
export const buildBatchedOrClauses = (ids, chunkSize = 100) => {
  if (!Array.isArray(ids) || ids.length === 0) {
    return ['*:*'];
  }

  const chunks = chunkArray(ids, chunkSize);

  if (chunks.length === 1) {
    // Single chunk, return standard OR clause
    return [buildProductIdOrClause(ids)];
  }

  // Multiple chunks: return OR clauses wrapped with parentheses for combining
  return chunks.map((chunk) => `(${buildProductIdOrClause(chunk)})`);
};

/**
 * Combine multiple OR clauses into a single query (for Solr)
 * @param {Array<string>} orClauses - Array of OR clauses
 * @returns {string} Combined query with OR between clauses
 */
export const combineOrClauses = (orClauses) => {
  if (!Array.isArray(orClauses) || orClauses.length === 0) {
    return '*:*';
  }
  if (orClauses.length === 1) {
    return orClauses[0];
  }
  return orClauses.join(' OR ');
};

/**
 * Merge Solr response documents from multiple queries
 * Removes duplicates based on product_id_i
 * @param {Array<Array>} responseArrays - Array of response.docs arrays
 * @returns {Array} Merged and deduplicated docs
 */
export const mergeSolrResults = (responseArrays) => {
  const seen = new Set();
  const merged = [];

  responseArrays.forEach((docs) => {
    if (Array.isArray(docs)) {
      docs.forEach((doc) => {
        const id = doc.product_id_i;
        if (id && !seen.has(id)) {
          seen.add(id);
          merged.push(doc);
        }
      });
    }
  });

  return merged;
};