const sdk = require('node-appwrite');
const elid = require('../../pkg-node/elid');
module.exports = async function ({ req, res, log, error }) {
try {
const body = JSON.parse(req.bodyRaw || '{}');
const {
query,
candidates = [],
threshold = 0.5,
algorithm = 'best',
limit = 10,
caseSensitive = false
} = body;
if (!query) {
return res.json({
success: false,
error: 'Query parameter is required'
}, 400);
}
if (!Array.isArray(candidates) || candidates.length === 0) {
return res.json({
success: false,
error: 'Candidates array is required and must not be empty'
}, 400);
}
log(`Fuzzy search: "${query}" in ${candidates.length} candidates`);
const processedQuery = caseSensitive ? query : query.toLowerCase();
const processedCandidates = candidates.map(c =>
caseSensitive ? c : (typeof c === 'string' ? c.toLowerCase() : c)
);
let results;
switch (algorithm) {
case 'levenshtein':
results = processedCandidates.map((candidate, i) => ({
index: i,
value: candidates[i],
score: elid.normalizedLevenshtein(processedQuery, candidate)
}));
break;
case 'jaro-winkler':
results = processedCandidates.map((candidate, i) => ({
index: i,
value: candidates[i],
score: elid.jaroWinkler(processedQuery, candidate)
}));
break;
case 'best':
default:
results = processedCandidates.map((candidate, i) => ({
index: i,
value: candidates[i],
score: elid.bestMatch(processedQuery, candidate)
}));
break;
}
results = results
.filter(r => r.score >= threshold)
.sort((a, b) => b.score - a.score)
.slice(0, limit);
log(`Found ${results.length} matches above threshold ${threshold}`);
return res.json({
success: true,
query,
algorithm,
threshold,
results,
metadata: {
totalCandidates: candidates.length,
matchesFound: results.length,
processingTime: Date.now()
}
});
} catch (err) {
error(`Error in fuzzy search function: ${err.message}`);
return res.json({
success: false,
error: err.message
}, 500);
}
};
async function fuzzySearchDatabase({ query, collectionId, searchField, threshold = 0.5 }) {
const client = new sdk.Client();
const database = new sdk.Databases(client);
client
.setEndpoint(process.env.APPWRITE_FUNCTION_ENDPOINT)
.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID)
.setKey(process.env.APPWRITE_API_KEY);
try {
const documents = await database.listDocuments(
process.env.DATABASE_ID,
collectionId,
[]
);
const candidates = documents.documents.map(doc => ({
id: doc.$id,
value: doc[searchField],
document: doc
}));
const processedQuery = query.toLowerCase();
const scored = candidates.map(candidate => ({
...candidate,
score: elid.bestMatch(
processedQuery,
candidate.value.toLowerCase()
)
}));
const results = scored
.filter(r => r.score >= threshold)
.sort((a, b) => b.score - a.score);
return {
success: true,
query,
results: results.map(r => ({
documentId: r.id,
value: r.value,
score: r.score,
document: r.document
}))
};
} catch (err) {
return {
success: false,
error: err.message
};
}
}
module.exports.fuzzySearchDatabase = fuzzySearchDatabase;