Files
shopApiNg/src/server/utils/search-helper.js

78 lines
2.4 KiB
JavaScript

import fs from 'fs/promises';
import path from 'path';
export async function findMatches(query, cacheDir) {
if (!query || !query.trim()) return [];
const terms = query.toLowerCase().split(/\s+/).filter(t => t);
// Load category tree
const treePath = path.join(cacheDir, 'category_tree.json');
let tree = [];
try {
const treeData = await fs.readFile(treePath, 'utf-8');
tree = JSON.parse(treeData);
} catch (e) {
console.error("Failed to load category tree for search", e);
return [];
}
const matchingCategoryIds = new Set();
// Helper to check text match
const isMatch = (text) => {
if (!text) return false;
const lower = text.toLowerCase();
return terms.every(t => lower.includes(t));
};
// Flatten tree to linear list for easier iteration
const queue = [...tree];
const nodes = [];
while (queue.length > 0) {
const node = queue.shift();
nodes.push(node);
if (node.children) {
queue.push(...node.children);
}
}
// Process in chunks to avoid too many open files
const CHUNK_SIZE = 50;
for (let i = 0; i < nodes.length; i += CHUNK_SIZE) {
const chunk = nodes.slice(i, i + CHUNK_SIZE);
await Promise.all(chunk.map(async (node) => {
let nodeMatches = false;
// Check category name
if (isMatch(node.cName)) {
nodeMatches = true;
} else {
// Check products
try {
const prodPath = path.join(cacheDir, 'products', `category_${node.kKategorie}.json`);
// Check if file exists before reading to avoid throwing too many errors
// Actually readFile throws ENOENT which is fine
const prodData = await fs.readFile(prodPath, 'utf-8');
const products = JSON.parse(prodData);
if (products.some(p => isMatch(p.cName))) {
nodeMatches = true;
}
} catch (e) {
// Ignore missing files
}
}
if (nodeMatches) {
matchingCategoryIds.add(node.kKategorie);
}
}));
if (matchingCategoryIds.size >= 20) {
break;
}
}
return Array.from(matchingCategoryIds);
}