use-filter-criteria
v1.0.89
Published
A TypeScript-based filtering engine that provides a flexible, type-safe way to filter complex data structures using declarative criteria. Perfect for building advanced search interfaces, data filtering systems, or query builders.
Readme
use-filter-criteria
A TypeScript-based filtering engine that provides a flexible, type-safe way to filter complex data structures using declarative criteria. Perfect for building advanced search interfaces, data filtering systems, or query builders.
Features
- 🎯 Type-Safe: Built with TypeScript and Zod for runtime type validation
- 🔄 Multiple Data Types: Support for arrays, booleans, dates, geographic coordinates, maps, numbers, objects, sets, and strings
- 🎨 Rich Operators: Comprehensive set of comparison and logical operators
- 🌐 Internationalization-Ready: Built-in string normalization (accents, case, etc.)
- 🔍 Complex Queries: Support for nested AND/OR logic combinations
- 🌳 Deep Path Resolution: Supports searching through arrays and nested structures with automatic path resolution (e.g.
['users', 'addresses', 'location']will search through all user addresses) - 📍 Geospatial: Built-in support for geographic radius searches, with flexible coordinate formats (object or tuple notation) and array traversal support for finding coordinates in nested data structures
- 🛠️ Criteria Mapping: Dynamic criteria modification during evaluation through the criteriaMapper function
- ⚡ Aliases: Save and reuse criteria configurations with the ability to override properties when referenced
- 🎛️ Flexible: Customizable default values and source path resolution
- 🔄 Dynamic Values: Support for dynamic value resolution using
$pathand custom functions - 📊 Detailed Logging: Detailed diagnostics for understanding filter results
- 🎯 Array Matching Control: Fine-grained control over array matching behavior with
matchInArrayoption
Installation
npm install use-filter-criteria
# or
yarn add use-filter-criteriaQuick Start
import FilterCriteria from 'use-filter-criteria';
const filter = new FilterCriteria();
// Example data
const users = [
{
id: 1,
name: 'John Doe',
age: 30,
addresses: [
{ type: 'home', location: { lat: 40.7128, lng: -74.006 } },
{ type: 'work', location: { lat: 40.758, lng: -73.9855 } }
],
skills: new Set(['typescript', 'react']),
roles: ['admin', 'developer'],
active: true,
lastLogin: '2024-01-01T00:00:00Z',
location: { lat: 40.7128, lng: -74.006 }, // location can also be specified as tuple: [40.7128, -74.006],
metadata: new Map([['level', 'senior']])
}
// ... more users
];
// Simple number comparison
const ageCriteria = FilterCriteria.criteria({
type: 'NUMBER',
operator: 'GREATER',
valuePath: ['age'],
matchValue: 25
});
// Example using path inside array
const locationCriteria = FilterCriteria.criteria({
type: 'GEO',
operator: 'IN-RADIUS',
valuePath: ['addresses', 'location'], // Will check all locations in the addresses array
matchValue: {
lat: 40.7128,
lng: -74.006,
radius: 5,
unit: 'km'
}
});
// Example using matchInArray: true (default)
const rolesStartsWithCriteria = FilterCriteria.criteria({
type: 'STRING',
matchInArray: true,
operator: 'STARTS-WITH',
valuePath: ['roles'],
matchValue: 'adm'
});
// Example using matchInArray: false
const rolesEqualsCriteria = FilterCriteria.criteria({
type: 'STRING',
matchInArray: false,
operator: 'EQUALS',
valuePath: ['roles'],
matchValue: 'adm'
});
// Complex multi-criteria filter
const complexFilterGroup = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'SET',
operator: 'INCLUDES-ANY',
valuePath: ['skills'],
matchValue: ['typescript', 'python']
}),
FilterCriteria.criteria({
type: 'BOOLEAN',
operator: 'EQUALS',
valuePath: ['active'],
matchValue: true
})
]
}),
FilterCriteria.filter({
operator: 'OR',
criterias: [
FilterCriteria.criteria({
type: 'STRING',
operator: 'CONTAINS',
valuePath: ['name'],
matchValue: 'john'
}),
FilterCriteria.criteria({
type: 'ARRAY',
operator: 'INCLUDES-ANY',
valuePath: ['roles'],
matchValue: ['admin']
})
]
})
]
});
// Match many
const matchingUsers = await filter.matchMany(users, complexFilterGroup);
console.log(matchingUsers);
// Match many multiple
const results = await filter.matchManyMultiple(users, {
developers: FilterCriteria.criteria({
type: 'SET',
operator: 'HAS',
valuePath: ['tagsSet'],
matchValue: 'developer'
}),
activeUsers: FilterCriteria.criteria({
type: 'BOOLEAN',
operator: 'EQUALS',
valuePath: ['active'],
matchValue: true
})
});
// With detailed logging
const detailedResult = await filter.match(users[0], complexFilterGroup);
console.log(detailedResult);Input Formats
The library supports three levels of filter complexity to match your needs:
1. Simple Criteria Input
For basic, single-condition filtering:
const ageCriteria = FilterCriteria.criteria({
type: 'NUMBER',
operator: 'GREATER',
valuePath: ['age'],
matchValue: 25
});
const result = await filter.match(data, ageCriteria);2. Filter Input
For grouping multiple criteria with a logical operator:
const userFilterCriteria = FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'NUMBER',
operator: 'GREATER',
valuePath: ['age'],
matchValue: 25
}),
FilterCriteria.criteria({
type: 'STRING',
operator: 'CONTAINS',
valuePath: ['name'],
matchValue: 'john'
})
]
});
const result = await filter.match(data, userFilterCriteria);3. Filter Group Input
For complex filtering with multiple filters and nested logic:
const complexFilterCriteria = FilterCriteria.filterGroup({
operator: 'OR',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'NUMBER',
operator: 'GREATER',
valuePath: ['age'],
matchValue: 25
}),
FilterCriteria.criteria({
type: 'SET',
operator: 'INCLUDES-ALL',
valuePath: ['skills'],
matchValue: ['typescript']
})
]
}),
FilterCriteria.filter({
operator: 'OR',
criterias: [
FilterCriteria.criteria({
type: 'STRING',
operator: 'MATCHES-REGEX',
valuePath: ['name'],
matchValue: /^john/i
})
]
})
]
});
const result = await filter.match(data, complexFilterCriteria);Each input format supports all the filter types and operators described in the "Supported Filter Types" section. The choice between them depends on your filtering complexity needs:
- Use Criteria Input for simple, single-condition checks
- Use Filter Input when you need to combine multiple criteria with AND/OR logic
- Use Filter Group Input for complex scenarios requiring multiple filters and nested logic combinations
Detailed Logging
The match function returns detailed logging that provides comprehensive information about why filters passed or failed:
const result = await filter.match(data, filter);The detailed output includes:
- Filter group level information showing overall filter results
- Filter level results showing how each filter was evaluated
- Criteria level details showing:
- The actual value found at the specified path
- The match value being compared against
- The operator used
- Whether the check passed or failed
- A human-readable reason for the result
This detailed output is invaluable for:
- Debugging complex filters
- Understanding why certain records were included/excluded
- Validating filter logic
- Troubleshooting unexpected results
Detailed Logging Examples
Here are examples showing how to use detailed logging with different filter types:
// String filter with detailed logging
const stringFilterCriteria = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'STRING',
operator: 'CONTAINS',
valuePath: ['name'],
matchValue: 'john'
})
]
})
]
});
const stringResult = await filter.match(users[0], stringFilterCriteria);
/* Output:
{
operator: 'AND',
passed: true,
reason: 'Filter group "AND" check PASSED',
results: [{
operator: 'AND',
passed: true,
reason: 'Filter "AND" check PASSED',
results: [{
matchValue: 'john',
passed: true,
reason: 'String criteria "CONTAINS" check PASSED',
value: 'john-doe'
}]
}]
}
*/
// Geographic filter with detailed logging
const geoFilterCriteria = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'GEO',
operator: 'IN-RADIUS',
valuePath: ['location'],
matchValue: {
lat: 40.7128,
lng: -74.006,
radius: 10,
unit: 'km'
}
})
]
})
]
});
const geoResult = await filter.match(users[0], geoFilterCriteria);
/* Output shows detailed radius check results:
{
operator: 'AND',
passed: true,
reason: 'Filter group "AND" check PASSED',
results: [{
operator: 'AND',
passed: true,
reason: 'Filter "AND" check PASSED',
results: [{
matchValue: {
lat: 40.7128,
lng: -74.006,
radius: 10,
unit: 'km'
},
passed: true,
reason: 'Geo criteria "IN-RADIUS" check PASSED',
value: { lat: 40.7128, lng: -74.006 }
}]
}]
}
*/
// Complex nested filter with detailed logging
const nestedFilterCriteria = FilterCriteria.filterGroup({
operator: 'OR',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'NUMBER',
operator: 'GREATER',
valuePath: ['age'],
matchValue: 25
}),
FilterCriteria.criteria({
type: 'SET',
operator: 'INCLUDES-ALL',
valuePath: ['skills'],
matchValue: ['typescript']
})
]
}),
FilterCriteria.filter({
operator: 'OR',
criterias: [
FilterCriteria.criteria({
type: 'STRING',
operator: 'MATCHES-REGEX',
valuePath: ['name'],
matchValue: /^john/i
})
]
})
]
});
const nestedResult = await filter.match(users[0], nestedFilter);
/* Output shows the complete evaluation tree:
{
operator: 'OR',
passed: true,
reason: 'Filter group "OR" check PASSED',
results: [
{
operator: 'AND',
passed: true,
reason: 'Filter "AND" check PASSED',
results: [
{
matchValue: 25,
passed: true,
reason: 'Number criteria "GREATER" check PASSED',
value: 30
},
{
matchValue: ['typescript'],
passed: true,
reason: 'Set criteria "INCLUDES-ALL" check PASSED',
value: Set(['typescript', 'react'])
}
]
},
{
operator: 'OR',
passed: true,
reason: 'Filter "OR" check PASSED',
results: [
{
matchValue: /^john/i,
passed: true,
reason: 'String criteria "MATCHES-REGEX" check PASSED',
value: 'John Doe'
}
]
}
]
}
*/Multiple Simultaneous Filters with matchManyMultiple
The matchManyMultiple function allows you to apply multiple different filters to the same dataset simultaneously, returning matched items for each filter in a single operation. This is particularly useful when you need to categorize data into multiple groups based on different criteria.
const filters = {
developers: FilterCriteria.criteria({
type: 'SET',
operator: 'HAS',
valuePath: ['tagsSet'],
matchValue: 'developer'
}),
activeUsers: FilterCriteria.criteria({
type: 'BOOLEAN',
operator: 'EQUALS',
valuePath: ['active'],
matchValue: true
}),
usPhones: FilterCriteria.criteria({
type: 'STRING',
operator: 'EQUALS',
valuePath: ['phones', 'country'],
matchValue: 'us'
})
};
// Apply all filters simultaneously
const results = await filter.matchManyMultiple(users, filters);
// Results contains an object with the same keys as the filters
console.log(results.developers); // Users with 'developer' tag
console.log(results.activeUsers); // Active users
console.log(results.usPhones); // Users with US phone numbersKey features of matchManyMultiple:
- Process multiple filters in a single pass through the data
- Return separate result sets for each filter
- Support for concurrency control via the optional concurrency parameter
- Each filter can use any supported criteria type and complexity level
- Results maintain the original filter keys for easy access
This is more efficient than running multiple separate matchMany operations when you need to apply multiple filters to the same dataset.
Supported Filter Types
Array Operators
EXACTLY-MATCHES: Arrays contain the same elements (order independent)HAS: Array has the specified elementINCLUDES-ALL: Array contains ALL filter valuesINCLUDES-ANY: Array contains AT LEAST ONE filter valueIS-EMPTY: Array is emptyNOT-EMPTY: Array is not emptyNOT-INCLUDES-ALL: Array is missing AT LEAST ONE filter valueNOT-INCLUDES-ANY: Array contains NONE of the filter valuesSIZE-EQUALS: Array size equals the filter valueSIZE-GREATER: Array size is greater than the filter valueSIZE-GREATER-OR-EQUALS: Array size is greater than or equal to the filter valueSIZE-LESS: Array size is less than the filter valueSIZE-LESS-OR-EQUALS: Array size is less than or equal to the filter value
Boolean Operators
EQUALS: Value equals the filter valueIS-FALSE: Value isfalseIS-FALSY: Value is falsyIS-NIL: Value isnullorundefinedIS-NULL: Value isnullIS-TRUE: Value istrueIS-TRUTHY: Value is truthyIS-UNDEFINED: Value isundefinedNOT-EQUALS: Value does not equal the filter valueNOT-NIL: Value is notnullorundefinedNOT-NULL: Value is notnullNOT-UNDEFINED: Value is notundefinedSTRICT-EQUAL: Value is strictly equal to the filter valueSTRICT-NOT-EQUAL: Value is not strictly equal to the filter value
Date Operators
AFTER: Date is after the filter valueAFTER-OR-EQUALS: Date is after or equal to the filter valueBEFORE: Date is before the filter valueBEFORE-OR-EQUALS: Date is before or equal to the filter valueBETWEEN: Date is between two filter values (inclusive)
Relative Dates
The library supports relative date calculations, allowing you to filter dates dynamically based on the current time. Instead of hardcoding specific dates, you can use relative date objects that calculate dates relative to "now".
Basic Syntax:
// Events created in the last 7 days
const last7Days = FilterCriteria.criteria({
type: 'DATE',
operator: 'AFTER',
matchValue: { days: -7 },
valuePath: ['createdAt']
});
// Events older than 5 days
const olderThan5Days = FilterCriteria.criteria({
type: 'DATE',
operator: 'BEFORE',
matchValue: { days: -5 },
valuePath: ['createdAt']
});
// Future events
const futureEvents = FilterCriteria.criteria({
type: 'DATE',
operator: 'AFTER',
matchValue: { hours: 0 }, // Now
valuePath: ['createdAt']
});Supported Time Units:
years: Number of years to add/subtractmonths: Number of months to add/subtractdays: Number of days to add/subtracthours: Number of hours to add/subtractminutes: Number of minutes to add/subtractseconds: Number of seconds to add/subtractmilliseconds: Number of milliseconds to add/subtract
Timezone Support:
You can specify a timezone using the gmt property:
// Events in the last 7 days (UTC timezone)
const last7DaysUTC = FilterCriteria.criteria({
type: 'DATE',
operator: 'AFTER',
matchValue: {
days: -7,
gmt: 'UTC' // or '+00:00', '-03:00', etc.
},
valuePath: ['createdAt']
});Supported GMT formats: 'UTC', 'GMT', '+00:00', 'Z', or offset strings like '+03:00', '-05:00'.
Start/End of Day:
Use startOfDay and endOfDay to set the time to the beginning or end of the day:
// Events created today (from start to end of day)
const todayEvents = FilterCriteria.criteria({
type: 'DATE',
operator: 'BETWEEN',
matchValue: [
{ days: 0, startOfDay: true }, // Start of today (00:00:00.000)
{ days: 0, endOfDay: true } // End of today (23:59:59.999)
],
valuePath: ['createdAt']
});
// Events created at start of today or later
const fromStartOfToday = FilterCriteria.criteria({
type: 'DATE',
operator: 'AFTER-OR-EQUALS',
matchValue: { days: 0, startOfDay: true },
valuePath: ['createdAt']
});Ignore Year (Month/Day Matching):
Use ignoreYear: true to compare dates ignoring the year (useful for recurring dates like birthdays):
// People with birthdays today (any year)
const birthdayToday = FilterCriteria.criteria({
type: 'DATE',
operator: 'BETWEEN',
matchValue: [
{ days: 0, startOfDay: true, ignoreYear: true },
{ days: 0, endOfDay: true, ignoreYear: true }
],
valuePath: ['birthdate']
});All Date Operators Support Relative Dates:
All date operators (AFTER, BEFORE, BETWEEN, AFTER-OR-EQUALS, BEFORE-OR-EQUALS, EQUALS) work with relative dates, making it easy to create dynamic date filters that always stay current.
Geographic Operators
IN-RADIUS: Point is within the specified radiusNOT-IN-RADIUS: Point is outside the specified radius
Map Operators
CONTAINS: Map's values object contains the specified value (using deep object comparison)HAS-KEY: Map contains the specified keyHAS-VALUE: Map contains the specified valueIS-EMPTY: Map is emptyNOT-EMPTY: Map is not emptySIZE-EQUALS: Map size equals the filter valueSIZE-GREATER: Map size is greater than the filter valueSIZE-GREATER-OR-EQUALS: Map size is greater than or equal to the filter valueSIZE-LESS: Map size is less than the filter valueSIZE-LESS-OR-EQUALS: Map size is less than or equal to the filter value
Number Operators
BETWEEN: Number is between two values (inclusive)EQUALS: Number equals the filter valueGREATER: Number is greater than the filter valueGREATER-OR-EQUALS: Number is greater than or equal to the filter valueIN: Number is in the filter valuesLESS: Number is less than the filter valueLESS-OR-EQUALS: Number is less than or equal to the filter valueNOT-EQUALS: Number does not equal the filter value
Object Operators
CONTAINS: Object contains the specified value (using deep object comparison)HAS-KEY: Object contains the specified keyHAS-VALUE: Object contains the specified valueIS-EMPTY: Object is emptyNOT-EMPTY: Object is not emptySIZE-EQUALS: Object size equals the filter valueSIZE-GREATER: Object size is greater than the filter valueSIZE-GREATER-OR-EQUALS: Object size is greater than or equal to the filter valueSIZE-LESS: Object size is less than the filter valueSIZE-LESS-OR-EQUALS: Object size is less than or equal to the filter value
Set Operators
EXACTLY-MATCHES: Set contains the exact same elements (order independent)HAS: Set contains the specific elementINCLUDES-ALL: Set contains ALL filter valuesINCLUDES-ANY: Set contains AT LEAST ONE filter valueIS-EMPTY: Set is emptyNOT-EMPTY: Set is not emptyNOT-INCLUDES-ALL: Set is missing AT LEAST ONE filter valueNOT-INCLUDES-ANY: Set contains NONE of the filter valuesSIZE-EQUALS: Set size equals the filter valueSIZE-GREATER: Set size is greater than the filter valueSIZE-GREATER-OR-EQUALS: Set size is greater than or equal to the filter valueSIZE-LESS: Set size is less than the filter valueSIZE-LESS-OR-EQUALS: Set size is less than or equal to the filter value
String Operators
CONTAINS: String contains the filter valueENDS-WITH: String ends with the filter valueEQUALS: String equals the filter valueIN: String is in the filter valuesIS-EMPTY: String is emptyMATCHES-REGEX: String matches the regular expression patternSTARTS-WITH: String starts with the filter value
Custom Operators
There are several ways to use custom criteria with support for batching and concurrency optimization:
1. Using DataLoader for Efficient Batching
You can use DataLoader to batch multiple criteria checks efficiently:
import DataLoader from 'use-data-loader';
// Create a loader that batches user checks
const userLoader = new DataLoader(async userIds => {
// Batch process multiple users at once
return userIds.map(() => true); // Your batch logic here
});
// Create a filter using the loader
const batchedCriteria = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'CUSTOM',
predicate: async user => userLoader.load(user.id)
}),
FilterCriteria.criteria({
type: 'CUSTOM',
predicate: async user => userLoader.load(user.id)
})
]
})
]
});
// Apply the filter with concurrency control
const results = await filter.matchMany(users, batchedCriteria, 2);2. Inline Custom Functions
You can define custom filter functions directly in your criteria:
const customFunctionCriteria = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'CUSTOM',
predicate: async (item, matchValue) => {
// Your custom logic here
return item.someProperty > matchValue;
},
matchValue: 10
})
]
})
]
});3. Saved Criteria
You can save reusable criteria that can be referenced later by alias. This is useful for common filtering patterns that you want to reuse across your application:
// Save a criteria for high-value users
FilterCriteria.saveCriteria(
FilterCriteria.criteria({
alias: 'isHighValueUser',
type: 'CUSTOM',
predicate: async ({ value, matchValue }) => {
return value.purchases > matchValue && value.membershipLevel === 'premium';
},
matchValue: 1000
})
);
// Save a string criteria with normalize option
FilterCriteria.saveCriteria(
FilterCriteria.criteria({
alias: 'containsKeyword',
type: 'STRING',
operator: 'CONTAINS',
valuePath: ['description'],
normalize: true,
matchValue: 'premium'
})
);
// Reference saved criteria using an alias
const filterCriteria = FilterCriteria.alias('isHighValueUser');
// Override properties when using saved criteria
const customizedCriteria = FilterCriteria.alias('containsKeyword', {
type: 'STRING',
matchValue: 'special-offer', // Override the default matchValue
normalize: true,
operator: 'STARTS-WITH', // Override the default operator
valueMapper: ({ value }) => value.name.toLowerCase(),
valuePath: ['title'] // Override the default path
});
// You can combine multiple criteria in a filter
const combinedFilter = FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.alias('isHighValueUser', {
type: 'CUSTOM',
matchValue: 2000 // Override matchValue for this instance
}),
FilterCriteria.alias('containsKeyword', {
type: 'STRING',
valuePath: ['tags'],
matchValue: 'vip'
})
]
});When using saved criteria, you can:
- Reference saved criteria by providing its alias
- Override any of their properties (valuePath, normalize, operator, matchValue, etc.)
- Combine multiple saved criteria in a single filter
- Mix saved criteria with regular criteria in the same filter
The saved criteria system provides a way to:
- Create reusable filtering patterns
- Maintain consistent filtering logic across your application
- Reduce code duplication
- Easily modify common filtering patterns in one place
Advanced Usage
Working with Sets and Maps
const data = [
{
id: 1,
skills: new Set(['typescript', 'react']),
metadata: new Map([
['level', 'senior'],
['department', 'engineering']
])
}
];
// Filter by Set contents
const setFilter = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'SET',
operator: 'INCLUDES-ALL',
valuePath: ['skills'],
matchValue: ['typescript', 'react'],
normalize: true // Optional: normalize string values
})
]
})
]
});
// Filter by Map contents
const mapFilter = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'MAP',
operator: 'HAS-KEY',
valuePath: ['metadata'],
matchValue: 'level'
})
]
})
]
});Using Criteria Mappers
The library supports criteria mapping through the criteriaMapper option. This allows you to dynamically modify criteria during evaluation:
const filter = FilterCriteria.criteria({
type: 'STRING',
operator: 'CONTAINS',
valuePath: ['name'],
matchValue: 'john',
criteriaMapper: ({ criteria, value }) => {
// You can return a modified criteria based on the current value
return {
...criteria,
normalize: value.shouldNormalize || false,
matchValue: value.searchTerm || criteria.matchValue
};
}
});The criteriaMapper function receives:
- The current criteria configuration
- The value being evaluated
- Must return a modified criteria object
This is useful for:
- Dynamically adjusting criteria based on the data being evaluated
- Implementing complex filtering logic
- Creating adaptive filters that change behavior based on context
Note: The criteriaMapper function can return any valid criteria type, including changing the criteria type entirely.
Dynamic Values Using $path
const data = [
{
id: 1,
requiredSkills: new Set(['typescript', 'react']),
actualSkills: new Set(['typescript', 'react', 'node'])
}
];
const filter = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'SET',
operator: 'INCLUDES-ALL',
valuePath: ['actualSkills'],
matchValue: { $path: ['requiredSkills'] } // Compare actualSkills with requiredSkills
})
]
})
]
});Dynamic Values Using Custom Functions
const data = [
{
id: 1,
name: 'John Doe',
createdAt: '2024-01-01T00:00:00Z'
}
];
const filter = FilterCriteria.filterGroup({
operator: 'AND',
filters: [
FilterCriteria.filter({
operator: 'AND',
criterias: [
FilterCriteria.criteria({
type: 'DATE',
operator: 'BETWEEN',
valuePath: ['createdAt'],
matchValue: item => {
// Calculate the date range dynamically based on the item
const oneMonthAgo = new Date(item.createdAt);
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
return [oneMonthAgo.toISOString(), item.createdAt];
}
})
]
})
]
});TypeScript Support
Full TypeScript support is provided out of the box. The library exports all necessary types and interfaces:
import FilterCriteria, { FilterCriteria } from 'use-filter-criteria';
type Criteria = FilterCriteria.Criteria;
type Filter = FilterCriteria.Filter;
type FilterGroup = FilterCriteria.FilterGroup;Inspect Functionality
The FilterCriteria.inspect() method provides a way to introspect the current state of the filter criteria system:
- All available operators for each data type
- All currently saved criteria
Usage
// Get information about available operators and saved criteria
const info = FilterCriteria.inspect();
console.log(info);
/* Example output:
{
"operators": {
"array": [
"EXACTLY-MATCHES",
"INCLUDES-ALL",
"INCLUDES-ANY",
"HAS",
"IS-EMPTY",
"NOT-EMPTY",
"NOT-INCLUDES-ALL",
"NOT-INCLUDES-ANY",
"SIZE-EQUALS",
"SIZE-GREATER",
"SIZE-GREATER-OR-EQUALS",
"SIZE-LESS",
"SIZE-LESS-OR-EQUALS"
],
"boolean": [
"EQUALS",
"IS-FALSE",
"IS-FALSY",
"IS-NIL",
"IS-NULL",
"IS-TRUE",
"IS-TRUTHY",
"IS-UNDEFINED",
"NOT-EQUALS",
"NOT-NIL",
"NOT-NULL",
"NOT-UNDEFINED",
"STRICT-EQUAL",
"STRICT-NOT-EQUAL"
],
// ... other operator types
},
"savedCriteria": {
"isHighValueUser / CUSTOM": {
"type": "CUSTOM",
"predicate": [Function],
"matchValue": 1000,
"alias": "isHighValueUser"
},
"containsKeyword / STRING": {
"type": "STRING",
"operator": "CONTAINS",
"valuePath": ["description"],
"normalize": true,
"matchValue": "premium",
"alias": "containsKeyword"
}
}
}
*/Use Cases
The inspect functionality is particularly useful for:
- Debugging: Understanding what operators are available for each data type
- Documentation: Generating dynamic documentation of available operators
- UI Building: Creating dynamic filter builders that show available options
- Validation: Verifying that saved criteria are properly registered
- Development: Exploring the current state of the filtering system
Output Structure
The returned JSON object contains two main sections:
operators: An object where each key is a data type (array, boolean, date, etc.) and the value is an array of available operators for that type.savedCriteria: An object containing all criteria that have been saved usingFilterCriteria.saveCriteria(). Each key is the criteria name, and the value is the criteria configuration.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT © Felipe Rohde
Author
Felipe Rohde
- Twitter: @felipe_rohde
- Github: @feliperohdee
- Email: [email protected]
