fix(search): Improve implicit AND logic for mixed free term and field queries in search and enhance wildcard field handling.
This commit is contained in:
@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartdata',
|
||||
version: '5.12.0',
|
||||
version: '5.12.1',
|
||||
description: 'An advanced library for NoSQL data organization and manipulation using TypeScript with support for MongoDB, data validation, collections, and custom data types.'
|
||||
}
|
||||
|
@ -414,31 +414,35 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
||||
const orConds = searchableFields.map((f) => ({ [f]: { $regex: pattern, $options: 'i' } }));
|
||||
return await (this as any).execQuery({ $or: orConds }, opts);
|
||||
}
|
||||
// implicit AND for mixed simple term + field:value queries (no explicit operators)
|
||||
// implicit AND: combine free terms and field:value terms (with or without wildcards)
|
||||
const parts = q.split(/\s+/);
|
||||
const hasColon = parts.some((t) => t.includes(':'));
|
||||
// implicit AND for mixed simple term + field:value queries (no explicit operators or range syntax)
|
||||
if (
|
||||
parts.length > 1 && hasColon &&
|
||||
!q.includes(' AND ') && !q.includes(' OR ') && !q.includes(' NOT ') &&
|
||||
!q.includes('(') && !q.includes(')') && !q.includes('[') && !q.includes(']') &&
|
||||
!q.includes('"') && !q.includes("'") &&
|
||||
!q.includes('*') && !q.includes('?')
|
||||
!q.includes('(') && !q.includes(')') &&
|
||||
!q.includes('[') && !q.includes(']')
|
||||
) {
|
||||
const andConds = parts.map((term) => {
|
||||
const m = term.match(/^(\\w+):([^"'\\*\\?\\s]+)$/);
|
||||
const m = term.match(/^(\w+):(.+)$/);
|
||||
if (m) {
|
||||
const field = m[1];
|
||||
const value = m[2];
|
||||
if (!searchableFields.includes(field)) {
|
||||
throw new Error(`Field '${field}' is not searchable for class ${this.name}`);
|
||||
}
|
||||
if (value.includes('*') || value.includes('?')) {
|
||||
// wildcard field search
|
||||
const escaped = value.replace(/([.+^${}()|[\\]\\])/g, '\\$1');
|
||||
const pattern = escaped.replace(/\*/g, '.*').replace(/\?/g, '.');
|
||||
return { [field]: { $regex: pattern, $options: 'i' } };
|
||||
}
|
||||
// exact field:value
|
||||
return { [field]: value };
|
||||
} else {
|
||||
const esc = escapeForRegex(term);
|
||||
const ors = searchableFields.map((f) => ({ [f]: { $regex: esc, $options: 'i' } }));
|
||||
return { $or: ors };
|
||||
}
|
||||
// free term -> regex across all searchable fields
|
||||
const esc = escapeForRegex(term);
|
||||
return { $or: searchableFields.map((f) => ({ [f]: { $regex: esc, $options: 'i' } })) };
|
||||
});
|
||||
return await (this as any).execQuery({ $and: andConds }, opts);
|
||||
}
|
||||
|
Reference in New Issue
Block a user