fix(classes.doc (convertFilterForMongoDb)): Improve filter conversion: handle logical operators, merge operator objects, add nested filter tests and docs, and fix test script

This commit is contained in:
2025-08-18 20:24:16 +00:00
parent 8b37ebc8f9
commit 0dbaa1bc5d
6 changed files with 462 additions and 24 deletions

202
readme.md
View File

@@ -144,40 +144,130 @@ await foundUser.delete();
SmartData provides the most advanced type-safe filtering system for MongoDB, supporting all operators while maintaining full IntelliSense:
#### Basic Filtering
```typescript
// Simple equality
const john = await User.getInstances({ name: 'John Doe' });
// Multiple fields (implicit AND)
const activeAdults = await User.getInstances({
status: 'active',
age: { $gte: 18 }
});
// Union types work perfectly
const users = await User.getInstances({
status: { $in: ['active', 'pending'] } // TypeScript validates these values!
});
```
// Comparison operators with type checking
#### Deep Nested Object Filtering
SmartData supports **both** nested object notation and dot notation for querying nested fields, with intelligent merging when both are used:
```typescript
// Nested object notation - natural TypeScript syntax
const users = await User.getInstances({
metadata: {
loginCount: { $gte: 5 }
}
});
// Dot notation - MongoDB style
const sameUsers = await User.getInstances({
'metadata.loginCount': { $gte: 5 }
});
// POWERFUL: Combine both notations - operators are merged!
const filtered = await User.getInstances({
metadata: { loginCount: { $gte: 3 } }, // Object notation
'metadata.loginCount': { $lte: 10 } // Dot notation
// Result: metadata.loginCount between 3 and 10
});
// Deep nesting with full type safety
const deepQuery = await User.getInstances({
profile: {
settings: {
notifications: {
email: true,
frequency: { $in: ['daily', 'weekly'] }
}
}
}
});
// Mix styles for complex queries
const advanced = await User.getInstances({
// Object notation for structure
profile: {
age: { $gte: 21 },
verified: true
},
// Dot notation for specific overrides
'profile.settings.theme': 'dark',
'profile.lastSeen': { $gte: new Date('2024-01-01') }
});
```
#### Comparison Operators
```typescript
// Numeric comparisons with type checking
const adults = await User.getInstances({
age: { $gte: 18, $lt: 65 } // Type-safe numeric comparisons
});
// Date comparisons
const recentUsers = await User.getInstances({
createdAt: { $gte: new Date('2024-01-01') }
});
// Not equal
const nonAdmins = await User.getInstances({
role: { $ne: 'admin' }
});
```
#### Array Operations
```typescript
// Array operations with full type safety
const experts = await User.getInstances({
tags: { $all: ['typescript', 'mongodb'] }, // Must have all tags
skills: { $size: 5 } // Exactly 5 skills
});
// Complex nested queries
// Array element matching
const results = await Order.getInstances({
items: {
$elemMatch: { // Match array elements
product: 'laptop',
quantity: { $gte: 2 }
}
}
});
// Check if value exists in array field
const nodeUsers = await User.getInstances({
skills: { $in: ['nodejs'] } // Has nodejs in skills array
});
```
#### Logical Operators
```typescript
// Complex nested queries with $and
const results = await Order.getInstances({
$and: [
{ status: { $in: ['pending', 'processing'] } },
{ 'items.price': { $gte: 100 } }, // Dot notation for nested fields
{
items: {
$elemMatch: { // Array element matching
product: 'laptop',
quantity: { $gte: 2 }
}
}
}
{ 'items.price': { $gte: 100 } },
{ customer: { verified: true } }
]
});
// Logical operators
// $or operator
const urgentOrHighValue = await Order.getInstances({
$or: [
{ priority: 'urgent' },
@@ -185,8 +275,94 @@ const urgentOrHighValue = await Order.getInstances({
]
});
// Security: $where is automatically blocked
// $nor operator - none of the conditions
const excluded = await User.getInstances({
$nor: [
{ status: 'banned' },
{ role: 'guest' }
]
});
// Combine logical operators
const complex = await Order.getInstances({
$and: [
{ status: 'active' },
{
$or: [
{ priority: 'high' },
{ value: { $gte: 1000 } }
]
}
]
});
```
#### Element Operators
```typescript
// Check field existence
const withEmail = await User.getInstances({
email: { $exists: true }
});
// Check for null or missing nested fields
const noPreferences = await User.getInstances({
'profile.preferences': { $exists: false }
});
```
#### Text and Pattern Matching
```typescript
// Regex patterns
const gmailUsers = await User.getInstances({
email: { $regex: '@gmail\\.com$', $options: 'i' }
});
// Starts with pattern
const johnUsers = await User.getInstances({
name: { $regex: '^John' }
});
```
#### Security Features
```typescript
// Security: $where is automatically blocked for injection protection
// await User.getInstances({ $where: '...' }); // ❌ Throws security error
// Invalid operators are caught
// await User.getInstances({ $badOp: 'value' }); // ⚠️ Warning logged
```
#### Advanced Patterns
```typescript
// Combine multiple filtering approaches
const advancedQuery = await User.getInstances({
// Direct field matching
status: 'active',
// Nested object with operators
profile: {
age: { $gte: 18, $lte: 65 },
verified: true
},
// Dot notation for deep paths
'settings.notifications.email': true,
'metadata.lastLogin': { $gte: new Date(Date.now() - 30*24*60*60*1000) },
// Array operations
roles: { $in: ['admin', 'moderator'] },
tags: { $all: ['verified', 'premium'] },
// Logical grouping
$or: [
{ 'subscription.plan': 'premium' },
{ 'subscription.trial': true }
]
});
```
### 🔎 Powerful Search Engine