Rich Filters
FraiseQL’s rich filters provide sophisticated query operators for 49 semantic scalar types, enabling domain-specific filtering beyond basic string matching and numeric comparisons.
What Are Rich Filters?
Section titled “What Are Rich Filters?”Rich filters are automatically-generated GraphQL query operators that specialize in semantic domains like emails, geographic locations, financial codes, and more. Each semantic type generates:
- Standard operators:
eq,neq,contains,isnull - Domain-specific operators: Email domain matching, geographic distance, financial validation, etc.
All operators compile to optimized SQL at build time — zero runtime overhead.
Quick Example
Section titled “Quick Example”query { # Find users at a specific company domain users(where: { email: { domainEq: "example.com" } }) { id email }
# Find restaurants within 5km restaurants(where: { location: { distanceWithin: { latitude: 40.7128 longitude: -74.0060 radiusKm: 5 } } }) { name }}Type Categories
Section titled “Type Categories”FraiseQL supports 49 semantic scalar types organized into 9 categories:
Contact Information (5 types)
Section titled “Contact Information (5 types)”Email · PhoneNumber · URL · DomainName · Hostname
Financial (11 types)
Section titled “Financial (11 types)”IBAN · CUSIP · ISIN · SEDOL · LEI · MIC · CurrencyCode · Money · ExchangeCode · ExchangeRate · StockSymbol
Location/Address (8 types)
Section titled “Location/Address (8 types)”PostalCode · Latitude · Longitude · Coordinates · Timezone · LocaleCode · LanguageCode · CountryCode
Identifiers (8 types)
Section titled “Identifiers (8 types)”Slug · SemanticVersion · HashSHA256 · APIKey · LicensePlate · VIN · TrackingNumber · ContainerNumber
Network (6 types)
Section titled “Network (6 types)”IPAddress · IPv4 · IPv6 · MACAddress · CIDR · Port
Transportation (3 types)
Section titled “Transportation (3 types)”AirportCode · PortCode · FlightNumber
Content (6 types)
Section titled “Content (6 types)”Markdown · HTML · MimeType · Color · Image · File
Ranges/Measurements (3 types)
Section titled “Ranges/Measurements (3 types)”DateRange · Duration · Percentage
Others
Section titled “Others”Plus additional types for UUIDs, hashes, encodings, and more.
See Semantic Scalars Reference for complete documentation of all 49 types.
Try It Yourself
Section titled “Try It Yourself”Execute queries with rich type filters in Apollo Sandbox below:
Common Use Cases
Section titled “Common Use Cases”1. Email Domain Filtering
Section titled “1. Email Domain Filtering”Find all users at a specific company:
query { users(where: { email: { domainEq: "acme.com" } }) { id email name }}Generates efficient database-specific SQL:
SELECT data FROM v_userWHERE SUBSTRING(data->>'email' FROM POSITION('@' IN data->>'email') + 1) = 'acme.com'SELECT data FROM v_userWHERE SUBSTRING_INDEX(JSON_UNQUOTE(JSON_EXTRACT(data, '$.email')), '@', -1) = 'acme.com'SELECT data FROM v_userWHERE substr(json_extract(data, '$.email'), instr(json_extract(data, '$.email'), '@') + 1) = 'acme.com'SELECT data FROM dbo.v_userWHERE SUBSTRING(JSON_VALUE(data, '$.email'), CHARINDEX('@', JSON_VALUE(data, '$.email')) + 1, LEN(JSON_VALUE(data, '$.email'))) = 'acme.com'2. Geographic Proximity
Section titled “2. Geographic Proximity”Find restaurants within 5 kilometers:
query { restaurants(where: { location: { distanceWithin: { latitude: 40.7128 longitude: -74.0060 radiusKm: 5 } } }) { id name location { latitude longitude } }}Works across all databases with database-specific optimizations:
SELECT data FROM v_restaurantWHERE ST_DWithin( ST_Point((data->'location'->>'longitude')::float, (data->'location'->>'latitude')::float)::geography, ST_Point(-74.0060, 40.7128)::geography, 5000 -- 5km in meters)SELECT data FROM v_restaurantWHERE ST_Distance_Sphere( POINT(json_extract(data, '$.location.longitude'), json_extract(data, '$.location.latitude')), POINT(-74.0060, 40.7128)) <= 5000SELECT data FROM v_restaurantWHERE ( 6371000 * acos( cos(radians(40.7128)) * cos(radians(CAST(json_extract(data, '$.location.latitude') AS REAL))) * cos(radians(CAST(json_extract(data, '$.location.longitude') AS REAL)) - radians(-74.0060)) + sin(radians(40.7128)) * sin(radians(CAST(json_extract(data, '$.location.latitude') AS REAL))) )) <= 5000SELECT data FROM dbo.v_restaurantWHERE CAST(json_value(data, '$.location') AS geography).STDistance( geography::Point(40.7128, -74.0060, 4326)) <= 50003. Financial Code Validation
Section titled “3. Financial Code Validation”Query by international bank account number:
query { accounts(where: { iban: { ibanCountryEq: "DE" } }) { id iban balance }}4. Date Range Queries
Section titled “4. Date Range Queries”Find projects lasting at least 90 days:
query { projects(where: { timeline: { durationGte: 90 overlaps: { start: "2024-06-01T00:00:00Z" end: "2024-08-31T23:59:59Z" } } }) { id name }}5. Network Range Queries
Section titled “5. Network Range Queries”Find devices on a specific network:
query { devices(where: { ipAddress: { cidrContains: "192.168.0.0/24" } }) { id hostname ipAddress }}Database Support Matrix
Section titled “Database Support Matrix”| Type | PostgreSQL | MySQL | SQLite | SQL Server |
|---|---|---|---|---|
| ✅ Native | ✅ Native | ✅ Native | ✅ Native | |
| PhoneNumber | ✅ Regex | ✅ REGEXP | ✅ GLOB | ✅ LIKE |
| Coordinates | ✅ PostGIS | ✅ ST_Distance | ⚠️ Approx | ✅ Geography |
| DateRange | ✅ Intervals | ✅ DATEDIFF | ✅ julianday | ✅ DATEDIFF |
| Duration | ✅ INTERVAL | ✅ Parse | ✅ Parse | ✅ Parse |
PostGIS for Geographic Queries
Section titled “PostGIS for Geographic Queries”Geographic queries on PostgreSQL require the PostGIS extension:
-- Enable PostGISCREATE EXTENSION IF NOT EXISTS postgis;
-- Create spatial index for performanceCREATE INDEX idx_tv_restaurant_location ON tv_restaurant USING GIST ((data->'location'));How Rich Filters Work
Section titled “How Rich Filters Work”1. Compile-Time Generation
Section titled “1. Compile-Time Generation”When you compile your schema with fraiseql compile:
@fraiseql.typeclass User: email: Email location: CoordinatesFraiseQL automatically generates:
input EmailWhereInput { eq: String neq: String contains: String domainEq: String domainIn: [String!] domainEndswith: String}2. SQL Template Embedding
Section titled “2. SQL Template Embedding”The compiler embeds database-specific SQL templates in the compiled schema:
{ "operators": { "domainEq": { "postgres": "SUBSTRING(email FROM POSITION('@' IN email) + 1) = $1", "mysql": "SUBSTRING_INDEX(email, '@', -1) = %s", "sqlite": "SUBSTR(email, INSTR(email, '@') + 1) = ?", "sqlserver": "SUBSTRING(email, CHARINDEX('@', email) + 1, LEN(email)) = @p1" } }}3. Zero Runtime Overhead
Section titled “3. Zero Runtime Overhead”Rich filters are resolved at compile time, not runtime:
- ✅ No reflection or dynamic generation
- ✅ No string parsing
- ✅ No database queries for metadata
- ✅ All operators pre-compiled
4. Embedded Lookup Data
Section titled “4. Embedded Lookup Data”Reference data is embedded in schema.compiled.json:
{ "lookup_data": { "countries": { "US": { "name": "United States", "continent": "North America" }, "FR": { "name": "France", "continent": "Europe" } }, "currencies": { "USD": { "symbol": "$", "decimal_places": 2 }, "EUR": { "symbol": "€", "decimal_places": 2 } } }}This ensures:
- Fast lookups with no database queries
- Consistent validation across instances
- Deterministic compilation
Validation with Rich Filters
Section titled “Validation with Rich Filters”Rich filters pre-validate parameters before SQL execution. Validation rules for each operator are compiled into the Rust runtime — for example, domainEq validates that the value is a well-formed domain name, ibanCountryEq validates the MOD-97 checksum, and distanceWithin enforces that radiusKm is a positive number. These rules are not user-configurable via TOML.
Performance Considerations
Section titled “Performance Considerations”Query Optimization
Section titled “Query Optimization”Rich filters generate optimized SQL:
- Index-friendly: Use GIST/BRIN indexes for geospatial queries
- String-optimized: Prefix indexes for domain matching
- Cached lookups: Reference data cached in schema, not queried
Example: Email Domain Filtering
Section titled “Example: Email Domain Filtering”This query:
users(where: { email: { domainEq: "example.com" } })Becomes a simple string comparison with good index support:
WHERE SUBSTRING(...) = 'example.com'Example: Geospatial Queries
Section titled “Example: Geospatial Queries”This query:
restaurants(where: { location: { distanceWithin: { latitude: 40.7128, longitude: -74.0060, radiusKm: 5 } }})Uses PostGIS efficiently:
WHERE ST_DWithin(location::geography, ST_Point(...)::geography, 5000)REST Bracket Notation
Section titled “REST Bracket Notation”Rich filter operators are available via REST query parameters using bracket notation. Each operator maps directly from the GraphQL where input to a ?field[operator]=value query parameter.
| GraphQL filter | REST bracket notation |
|---|---|
email: { domainEq: "example.com" } | ?email[domainEq]=example.com |
email: { domainIn: ["a.com", "b.com"] } | ?email[domainIn]=a.com,b.com |
iban: { ibanCountryEq: "DE" } | ?iban[ibanCountryEq]=DE |
ipAddress: { cidrContains: "192.168.0.0/24" } | ?ipAddress[cidrContains]=192.168.0.0/24 |
name: { icontains: "Ali" } | ?name[icontains]=Ali |
age: { gte: 18 } | ?age[gte]=18 |
For complex queries combining multiple rich filter operators, use the ?filter= JSON parameter which accepts the full FraiseQL where DSL:
GET /rest/v1/users?filter={"email":{"domainEq":"example.com"},"location":{"distanceWithin":{"latitude":40.7128,"longitude":-74.006,"radiusKm":5}}}Operators that accept structured input (like distanceWithin) are only available via the ?filter= JSON DSL, not via bracket notation.
See REST Transport for the full list of bracket operators and the JSON filter escape hatch.
gRPC Availability
Section titled “gRPC Availability”Rich filters are also available via gRPC request fields. Filters defined in your schema translate directly to protobuf request message fields for gRPC.
Next Steps
Section titled “Next Steps”- Semantic Scalars Reference — Detailed docs for all 49 types and their operators
- TOML Configuration — Full configuration reference
- Query Operators — All standard operators reference
- Automatic Where — Learn about automatic filter generation