modkit-sdk
Security Context Scoping and Typed OData Query Builder for Clients
Overview
This crate provides two main features:
- Security Context Scoping: A lightweight, zero-allocation wrapper that binds a
SecurityContextto any client type - Typed OData Query Builder: A generic, reusable query builder that produces type-safe OData queries with automatic filter hashing
Security Context Scoping
Example
use WithSecurityContext;
use SecurityContext;
let client = new;
let ctx = root;
// Bind the security context to the client
let secured = client.security_ctx;
// Access the client and context
let client_ref = secured.client;
let ctx_ref = secured.ctx;
Typed OData Query Builder
The typed OData query builder provides a type-safe way to construct OData queries without manually building ODataQuery instances. It ensures compile-time type checking for field references and operations.
Features
- Type-safe field references: Field types are checked at compile time
- Schema trait: Define field enums and their string mappings
- Typed filter constructors: Comparison and string operations with type safety
- Fluent API: Chain methods to build complex queries
- Automatic filter hashing: Stable, deterministic hashing for cursor pagination
- No proc macros: Pure Rust implementation without code generation
Quick Start
1. Define Your Schema
use ;
// Define field enum
// Define schema struct
;
// Implement Schema trait
2. Create Typed Field References
// Define typed field constants
const ID: = new;
const NAME: = new;
const EMAIL: = new;
const AGE: = new;
3. Build Queries
use ;
use SortDir;
// Simple equality filter
let user_id = new_v4;
let query = new
.filter
.build;
// Complex filter with AND/OR
let query = new
.filter
.order_by
.page_size
.build;
// Full query with all features
let query = new
.filter
.order_by
.order_by
.select
.page_size
.build;
Supported Operations
Comparison Operators (All Field Types)
eq(value)- Equality:field eq valuene(value)- Not equal:field ne valuegt(value)- Greater than:field gt valuege(value)- Greater or equal:field ge valuelt(value)- Less than:field lt valuele(value)- Less or equal:field le value
String Operations (String Fields Only)
contains(value)- Contains:contains(field, 'value')startswith(value)- Starts with:startswith(field, 'value')endswith(value)- Ends with:endswith(field, 'value')
Logical Combinators
and(expr)- Logical AND:expr1 and expr2or(expr)- Logical OR:expr1 or expr2not()- Logical NOT:not expr
Query Builder Methods
filter(expr)- Set the filter expressionorder_by(field, dir)- Add an order-by clause (can be called multiple times)select(fields)- Set field projection (pass&[&field1, &field2, ...])page_size(limit)- Set the page size limitbuild()- Build the finalODataQuerywith computed filter hash
Type Safety
The query builder enforces type safety at compile time:
// ✅ Correct: String field with string operations
let query = new
.filter
.build;
// ❌ Compile error: contains() only available for String fields
let query = new
.filter // Won't compile!
.build;
// ✅ Correct: Comparison operations work on all types
let query = new
.filter
.build;
Filter Hash Stability
The query builder automatically computes a stable, deterministic hash for filter expressions using the same algorithm as modkit_odata::pagination::short_filter_hash. This ensures cursor pagination consistency:
let user_id = new_v4;
let query1 = new
.filter
.build;
let query2 = new
.filter
.build;
// Same filter produces same hash
assert_eq!;
Supported Value Types
The following Rust types can be used in filter expressions:
booluuid::UuidStringand&stri32,i64,u32,u64
Additional types can be supported by implementing the IntoODataValue trait.
Examples
See examples/typed_odata_query.rs for comprehensive examples demonstrating:
- Simple equality filters
- String operations (contains, startswith, endswith)
- Complex filters with AND/OR/NOT
- Ordering and field selection
- Page size limits
- Full queries with all features
- Filter hash stability
Run the example:
Design Constraints
- No proc macros: Pure Rust implementation without code generation
- Small footprint: Minimal API surface with no large facades
- No DB concepts: Does not expose database or SeaORM concepts
- AST-based: Produces
modkit_odata::ast::Exprfor maximum flexibility - Stable hashing: Deterministic filter hashing for cursor pagination
Testing
The query builder includes comprehensive unit tests verifying:
- Field name mapping works correctly
- Building queries sets order/limit/filter properly
- Filter hash is stable for identical filters
- All comparison and string operations work
- Logical combinators (AND/OR/NOT) function correctly
- Field selection handles heterogeneous field types
Run tests:
License
See workspace license.