filter.rs
Overview
This file implements filtering utilities designed to construct SQL-like WHERE clauses dynamically from structured filter inputs. It defines several typed filter structs (for booleans, floats, integers, and strings) that can be serialized and converted into SQL condition expressions. The core functionality is encapsulated in a trait that converts filter criteria into SQL condition strings, supports null-value pruning, and handles nested logical operators such as AND and OR.
The filtering constructs are intended for use in query-building contexts where dynamic query conditions are required based on user input or API parameters.
Core Components
Trait: WhereOp
Purpose
Provides methods to manipulate JSON-like filter data and convert it into SQL WHERE clause fragments.
Methods
skip_nulls(obj: &mut Value) -> &mut ValueRecursively removes entries with
nullvalues from a JSON object (serde_json::Value). It modifies the input in place to prune out any filter conditions that do not have meaningful values.obj: Mutable reference to a JSON Value expected to be an object.Returns: The same JSON Value with null entries removed.
This method is critical for cleaning up filter inputs before generating SQL conditions.
into_str(pair: (String, Value)) -> Option<String>Converts a key-value pair representing a filter condition into its corresponding SQL condition string.
pair: A tuple where the first element is the field name (e.g., column name) and the second is a JSON object defining the filter operations.
Returns: An optional SQL condition string representing the filter.
The method supports operators such as:
eq(equal)ne(not equal)gt,lt,ge,le(comparisons)include(SQLINclause)notIn(SQLNOT INclause)Logical operators like
or, represented by special key names.
Unsupported operators trigger a runtime error using tracing::error!.
to_where(&self) -> Option<String>Converts the implementing struct (which must be serializable) into a full SQL WHERE clause string.
self: The filter struct instance.
Returns: An optional string starting with
"WHERE "followed by the combined SQL conditions, or None if no conditions are present.
This method serializes the struct to JSON, prunes nulls, and then converts each filter field into SQL using
into_str.
Struct: Filter
An empty struct implementing the WhereOp trait to provide default behavior for filtering operations. It serves as the main utility to invoke filtering methods.
Filter Structs for Different Data Types
These structs represent typed filters that specify possible operations on fields of different primitive types. Each struct derives serialization traits and is compatible with GraphQL input objects.
BooleanFilterFields:
eq: Optional boolean for equality.ne: Optional boolean for inequality.
FloatFilterFields:
eq,ne: Optional floats for equality/inequality.gt,lt,ge,le: Optional floats for comparison.include(inin GraphQL): Optional list of floats for inclusion checks.notIn: Optional list of floats for exclusion checks.
IntFilterSame fields as
FloatFilter, but for 32-bit integers.StringFilterFields:
eq,ne: Optional strings for equality/inequality.ge,le: Optional strings for lexicographical comparisons.include(inin GraphQL): Optional list of strings for inclusion.notIn: Optional list of strings for exclusion.
Each filter type also has an associated optional alias type, e.g., OptBooleanFilter = Option<BooleanFilter>.
Important Implementation Details
The
skip_nullsmethod uses recursive traversal with cloning to remove null values deeply inside nested JSON objects.The
into_strmethod handles nested filter expressions by recursion, notably for logical operators like"or".SQL operators correspond directly to JSON field names, e.g.,
"eq"translates to"=","ne"to"<>"The method uses string formatting that handles arrays for SQL
INandNOT INclauses by joining elements with commas.Error handling for unsupported filters is done via tracing::error! and
unreachable!()to indicate programming errors.
Interaction with Other Parts of the System
The filter structs are designed as GraphQL input objects (
async_graphql::InputObject), indicating integration with GraphQL APIs for query filtering.Serialization is handled with serde to convert filter structs to JSON values.
The file imports from and is tested against other schema components, such as BlockFilter and ExtBlkRefFilter, indicating it is part of a larger schema filtering module.
The filtering trait and structs enable composable, reusable filtering logic that can be plugged into query resolvers or database query builders.
Usage Examples
// Create a filter to select rows where `age` is greater than 30
let int_filter = IntFilter {
gt: Some(30),
..Default::default()
};
let where_clause = int_filter.to_where(); // Some("WHERE age > 30")
// Create a filter to select rows where `status` is either "active" or "pending"
let string_filter = StringFilter {
include: Some(vec![Some("active".to_string()), Some("pending".to_string())]),
..Default::default()
};
let where_clause = string_filter.to_where(); // Some("WHERE status IN (\"active\",\"pending\")")
Testing
The included tests module contains unit tests validating:
Conversion of boolean, integer, and string filters into SQL strings.
The correct recursive pruning of null values in complex nested filter structures.
Behavior of logical operators like
orin filter JSON.
Diagram: Filter Module Structure
classDiagram
class WhereOp {
+skip_nulls()
+into_str()
+to_where()
}
class Filter {
}
Filter ..|> WhereOp
class BooleanFilter {
+eq: Option<bool>
+ne: Option<bool>
}
class FloatFilter {
+eq: Option<f64>
+ne: Option<f64>
+gt: Option<f64>
+lt: Option<f64>
+ge: Option<f64>
+le: Option<f64>
+include: Option<Vec<Option<f64>>>
+notIn: Option<Vec<Option<f64>>>
}
class IntFilter {
+eq: Option<i32>
+ne: Option<i32>
+gt: Option<i32>
+lt: Option<i32>
+ge: Option<i32>
+le: Option<i32>
+include: Option<Vec<Option<i32>>>
+notIn: Option<Vec<Option<i32>>>
}
class StringFilter {
+eq: Option<String>
+ne: Option<String>
+ge: Option<String>
+le: Option<String>
+include: Option<Vec<Option<String>>>
+notIn: Option<Vec<Option<String>>>
}
WhereOp <|.. Filter
This diagram illustrates the key trait and its implementation, along with the various filter types that provide the input data structure for query filtering.