Skip to content

Query Operators

FraiseQL generates filter operators for query arguments. This reference covers all available operators and their SQL mappings.

When you define a query with auto_params={"where": True}, FraiseQL generates filter input types:

@fraiseql.query(
sql_source="v_user",
auto_params={"where": True}
)
def users(where: UserWhereInput | None = None) -> list[User]:
pass

This generates:

input UserWhereInput {
id: IDFilter
name: StringFilter
email: StringFilter
is_active: BooleanFilter
created_at: DateTimeFilter
_and: [UserWhereInput!]
_or: [UserWhereInput!]
_not: UserWhereInput
}
OperatorDescriptionSQL
_eqEquals= $value
_neqNot equals<> $value
query {
users(where: { status: { _eq: "active" } }) {
id
name
}
}
SELECT data FROM v_user WHERE data->>'status' = 'active'
OperatorDescriptionSQL
_gtGreater than> $value
_gteGreater than or equal>= $value
_ltLess than< $value
_lteLess than or equal<= $value
query {
products(where: { price: { _gte: "100.00", _lte: "500.00" } }) {
id
name
price
}
}
SELECT data FROM v_product
WHERE (data->>'price')::numeric >= 100.00
AND (data->>'price')::numeric <= 500.00
OperatorDescriptionSQL
_is_nullIs nullIS NULL / IS NOT NULL
query {
users(where: { avatar_url: { _is_null: false } }) {
id
name
avatar_url
}
}
SELECT data FROM v_user WHERE data->>'avatar_url' IS NOT NULL
## String Operators
### Semantic substring operators
These operators treat the input as a **literal string**`%` and `_` in the value are not LIKE wildcards. Use these when you want straightforward substring or prefix/suffix matching without writing a LIKE pattern.
| Operator | Description | SQL | Database Support |
|----------|-------------|-----|-----------------|
| `_contains` | Contains substring | `LIKE '%value%'` (literal) | All |
| `_icontains` | Contains substring (case-insensitive) | `ILIKE '%value%'` (literal) | **PostgreSQL only** |
| `_startswith` | Starts with | `LIKE 'value%'` (literal) | All |
| `_istartswith` | Starts with (case-insensitive) | `ILIKE 'value%'` (literal) | **PostgreSQL only** |
| `_endswith` | Ends with | `LIKE '%value'` (literal) | All |
| `_iendswith` | Ends with (case-insensitive) | `ILIKE '%value'` (literal) | **PostgreSQL only** |
`%` and `_` in the value are automatically escaped with `ESCAPE '!'` so they match as literal characters. If you want them to act as wildcards, use `_like` / `_ilike` instead.
```graphql
query {
users(where: { name: { _startswith: "O'Brien" } }) {
id
name
}
}

_like / _ilike pass the value directly as a LIKE pattern — % and _ are wildcards.

OperatorDescriptionSQLDatabase Support
_likePattern match (case-sensitive)LIKE $patternAll
_ilikePattern match (case-insensitive)ILIKE $patternAll¹
_nlikeNot likeNOT LIKE $patternAll
_nilikeNot ilikeNOT ILIKE $patternAll¹
_regexRegular expression~ $pattern (pg) / REGEXP (mysql)PostgreSQL, MySQL
_iregexCase-insensitive regex~* $patternPostgreSQL only
_nregexNot regex!~ $pattern (pg) / NOT REGEXP (mysql)PostgreSQL, MySQL
_niregexNot iregex!~* $patternPostgreSQL only

¹ On MySQL, _ilike/_nilike emit (NOT) LIKE — case-sensitivity depends on the column collation (case-insensitive by default with utf8mb4_unicode_ci). On SQL Server, a COLLATE Latin1_General_CI_AI clause is appended. SQL Server and SQLite do not support ~*.

Use % for wildcard and _ for single character:

query {
users(where: { email: { _ilike: "%@example.com" } }) {
id
email
}
}
SELECT data FROM v_user WHERE data->>'email' ILIKE '%@example.com'
query {
posts(where: { title: { _regex: "^Getting Started" } }) {
id
title
}
}
SELECT data FROM v_post WHERE data->>'title' ~ '^Getting Started'
OperatorDescriptionSQL
_inIn listIN ($values)
_ninNot in listNOT IN ($values)
query {
users(where: { status: { _in: ["active", "pending"] } }) {
id
name
status
}
}
SELECT data FROM v_user WHERE data->>'status' IN ('active', 'pending')

For array fields (list[T]):

OperatorDescriptionSQLDatabase Support
_containsArray contains value@> ARRAY[$value]PostgreSQL only
_contained_inArray is contained in<@ $arrayPostgreSQL only
_has_anyHas any of values&& $arrayPostgreSQL only
_has_allHas all of values@> $arrayPostgreSQL only
_is_emptyArray is empty= '{}'PostgreSQL only
query {
posts(where: { tags: { _contains: "graphql" } }) {
id
title
tags
}
}
SELECT data FROM v_post
WHERE (data->'tags')::text[] @> ARRAY['graphql']
query {
posts(where: { tags: { _has_all: ["graphql", "tutorial"] } }) {
id
title
}
}
SELECT data FROM v_post
WHERE (data->'tags')::text[] @> ARRAY['graphql', 'tutorial']

For Json fields:

OperatorDescriptionSQLDatabase Support
_containsContains JSON@> $jsonPostgreSQL only
_contained_inContained in JSON<@ $jsonPostgreSQL only
_has_keyHas key? $keyPostgreSQL only
_has_keys_anyHas any key`?$keys`
_has_keys_allHas all keys?& $keysPostgreSQL only
query {
users(where: {
preferences: { _contains: { theme: "dark" } }
}) {
id
name
preferences
}
}
SELECT data FROM v_user
WHERE data->'preferences' @> '{"theme": "dark"}'::jsonb

DateTime fields support comparison operators:

query {
events(where: {
created_at: {
_gte: "2024-01-01T00:00:00Z"
_lt: "2024-02-01T00:00:00Z"
}
}) {
id
name
created_at
}
}

Special date operators:

OperatorDescriptionSQL
_yearExtract yearEXTRACT(YEAR FROM ...)
_monthExtract monthEXTRACT(MONTH FROM ...)
_dayExtract dayEXTRACT(DAY FROM ...)
_dowDay of week (0=Sun)EXTRACT(DOW FROM ...)
query {
orders(where: {
created_at: { _year: 2024, _month: 1 }
}) {
id
total
}
}

All conditions must match (default behavior):

query {
products(where: {
is_available: { _eq: true }
price: { _lte: "100.00" }
}) {
id
name
}
}

Explicit _and:

query {
products(where: {
_and: [
{ is_available: { _eq: true } }
{ price: { _lte: "100.00" } }
]
}) {
id
name
}
}

Any condition must match:

query {
users(where: {
_or: [
{ role: { _eq: "admin" } }
{ role: { _eq: "moderator" } }
]
}) {
id
name
role
}
}
SELECT data FROM v_user
WHERE data->>'role' = 'admin' OR data->>'role' = 'moderator'

Negate conditions:

query {
users(where: {
_not: { status: { _eq: "banned" } }
}) {
id
name
}
}
SELECT data FROM v_user WHERE NOT (data->>'status' = 'banned')

Combine operators for complex queries:

query {
products(where: {
_and: [
{ is_available: { _eq: true } }
{
_or: [
{ category: { _eq: "electronics" } }
{
_and: [
{ category: { _eq: "accessories" } }
{ price: { _lt: "50.00" } }
]
}
]
}
]
}) {
id
name
category
price
}
}
input IDFilter {
_eq: ID
_neq: ID
_in: [ID!]
_nin: [ID!]
_is_null: Boolean
}
input StringFilter {
_eq: String
_neq: String
_gt: String
_gte: String
_lt: String
_lte: String
_in: [String!]
_nin: [String!]
_contains: String # literal substring match — % and _ are not wildcards
_icontains: String # case-insensitive (PostgreSQL only)
_startswith: String # literal prefix match
_istartswith: String # case-insensitive (PostgreSQL only)
_endswith: String # literal suffix match
_iendswith: String # case-insensitive (PostgreSQL only)
_like: String # LIKE pattern — % and _ ARE wildcards
_ilike: String # case-insensitive LIKE (PostgreSQL only)
_nlike: String # NOT LIKE (all databases)
_nilike: String # NOT ILIKE / collation-based (all databases)
_regex: String # PostgreSQL ~, MySQL REGEXP
_iregex: String # PostgreSQL ~* only
_nregex: String # PostgreSQL !~, MySQL NOT REGEXP
_niregex: String # PostgreSQL !~* only
_is_null: Boolean
}
input IntFilter {
_eq: Int
_neq: Int
_gt: Int
_gte: Int
_lt: Int
_lte: Int
_in: [Int!]
_nin: [Int!]
_is_null: Boolean
}
input FloatFilter {
_eq: Float
_neq: Float
_gt: Float
_gte: Float
_lt: Float
_lte: Float
_in: [Float!]
_nin: [Float!]
_is_null: Boolean
}
input BooleanFilter {
_eq: Boolean
_neq: Boolean
_is_null: Boolean
}
input DateTimeFilter {
_eq: DateTime
_neq: DateTime
_gt: DateTime
_gte: DateTime
_lt: DateTime
_lte: DateTime
_in: [DateTime!]
_nin: [DateTime!]
_is_null: Boolean
_year: Int
_month: Int
_day: Int
_dow: Int
}
input DecimalFilter {
_eq: Decimal
_neq: Decimal
_gt: Decimal
_gte: Decimal
_lt: Decimal
_lte: Decimal
_in: [Decimal!]
_nin: [Decimal!]
_is_null: Boolean
}
input StringArrayFilter {
_contains: String
_contained_in: [String!]
_has_any: [String!]
_has_all: [String!]
_is_empty: Boolean
_is_null: Boolean
}
input JsonFilter {
_contains: JSON
_contained_in: JSON
_has_key: String
_has_keys_any: [String!]
_has_keys_all: [String!]
_is_null: Boolean
}

FraiseQL provides specialized filters for domain-specific scalar types. These filters offer operators tailored to each type’s semantics, enabling powerful queries that understand your data.


input EmailFilter {
# Basic
_eq: Email
_neq: Email
_in: [Email!]
_nin: [Email!]
_is_null: Boolean
# Domain extraction
_domain_eq: String # Match domain exactly
_domain_neq: String
_domain_in: [String!] # Domain in list
_domain_nin: [String!]
_domain_endswith: String # Domain ends with (e.g., ".edu")
_domain_contains: String # Domain contains substring
# Local part extraction
_local_eq: String # Match local part (before @)
_local_startswith: String
_local_contains: String
# Pattern detection
_is_freemail: Boolean # gmail.com, yahoo.com, hotmail.com, etc.
_is_corporate: Boolean # NOT freemail
_is_disposable: Boolean # Known disposable email domains
}
query {
# Find company emails
users(where: { email: { _domain_eq: "acme.com" } }) {
id email
}
# Find all .edu emails
users(where: { email: { _domain_endswith: ".edu" } }) {
id email
}
# Exclude freemail addresses
leads(where: { email: { _is_freemail: false } }) {
id email company
}
# Filter by local part pattern
users(where: { email: { _local_startswith: "sales." } }) {
id email
}
}
input PhoneNumberFilter {
# Basic
_eq: PhoneNumber
_neq: PhoneNumber
_in: [PhoneNumber!]
_nin: [PhoneNumber!]
_is_null: Boolean
# Country code extraction
_country_code_eq: String # +1, +44, +33
_country_code_in: [String!]
_country_code_nin: [String!]
# Geographic grouping
_country_eq: CountryCode # Derived from country code
_country_in: [CountryCode!]
_region_eq: String # North America, Europe, Asia
# Number type detection
_is_mobile: Boolean
_is_landline: Boolean
_is_toll_free: Boolean
_is_premium: Boolean
# Pattern matching
_national_startswith: String # Area code matching
_national_contains: String
}
query {
# Find US phone numbers
contacts(where: { phone: { _country_code_eq: "+1" } }) {
id phone
}
# Find mobile numbers in Europe
contacts(where: {
phone: {
_region_eq: "Europe"
_is_mobile: true
}
}) {
id phone
}
# Find toll-free numbers
support_lines(where: { phone: { _is_toll_free: true } }) {
id department phone
}
}
input URLFilter {
# Basic
_eq: URL
_neq: URL
_in: [URL!]
_nin: [URL!]
_is_null: Boolean
# Protocol
_protocol_eq: String # "https", "http", "ftp"
_protocol_in: [String!]
_is_secure: Boolean # protocol = "https"
# Host extraction
_host_eq: String # Full host: "api.example.com"
_host_in: [String!]
_host_endswith: String # ".example.com" (subdomain matching)
_host_contains: String
# Domain (excludes subdomain)
_domain_eq: String # "example.com"
_domain_in: [String!]
_tld_eq: String # "com", "org", "io"
_tld_in: [String!]
# Path
_path_eq: String
_path_startswith: String # "/api/v1/"
_path_contains: String
_path_matches: String # Regex
# Query parameters
_has_query_param: String # Has parameter "utm_source"
}
query {
# Find HTTPS links only
links(where: { url: { _is_secure: true } }) {
id url
}
# Find links to specific domain
links(where: { url: { _domain_eq: "github.com" } }) {
id url
}
# Find API endpoints
webhooks(where: { url: { _path_startswith: "/api/" } }) {
id url
}
# Find links with tracking params
links(where: { url: { _has_query_param: "utm_source" } }) {
id url campaign
}
}
input DomainNameFilter {
# Basic
_eq: DomainName
_neq: DomainName
_in: [DomainName!]
_nin: [DomainName!]
_is_null: Boolean
# TLD extraction
_tld_eq: String # "com", "org", "co.uk"
_tld_in: [String!]
_tld_category: TLDCategory # GENERIC, COUNTRY, SPONSORED
# Hierarchy
_parent_domain_eq: String # "example.com" matches "api.example.com"
_subdomain_of: String # Is subdomain of given domain
_depth_eq: Int # Number of labels (api.example.com = 3)
_depth_gte: Int
_depth_lte: Int
# Pattern
_endswith: String # ".example.com"
_contains: String
}

input CountryCodeFilter {
# Basic
_eq: CountryCode
_neq: CountryCode
_in: [CountryCode!]
_nin: [CountryCode!]
_is_null: Boolean
# Geographic grouping
_continent_eq: Continent # AF, AN, AS, EU, NA, OC, SA
_continent_in: [Continent!]
_region_eq: String # "Western Europe", "Southeast Asia"
_subregion_eq: String
# Political/Economic groupings
_in_eu: Boolean # European Union member
_in_eurozone: Boolean # Uses Euro
_in_schengen: Boolean # Schengen Area
_in_nato: Boolean
_in_g7: Boolean
_in_g20: Boolean
_in_oecd: Boolean
_in_commonwealth: Boolean
_in_brics: Boolean
# Regulatory
_gdpr_applicable: Boolean # EU + EEA + adequacy decisions
}
query {
# Find EU customers
customers(where: { country: { _in_eu: true } }) {
id name country
}
# Find customers in Asia
customers(where: { country: { _continent_eq: "AS" } }) {
id name country
}
# Find GDPR-applicable users
users(where: { country: { _gdpr_applicable: true } }) {
id email country
}
# Find G20 economies
companies(where: { country: { _in_g20: true } }) {
id name country
}
}
input CoordinatesFilter {
# Basic
_eq: Coordinates
_is_null: Boolean
# Geospatial (PostGIS)
_within_radius: RadiusInput # Center point + radius in km
_within_bounds: BoundsInput # Bounding box
_within_polygon: [[Float!]!] # GeoJSON polygon
_within_geojson: JSON # Arbitrary GeoJSON geometry
# Distance calculations
_distance_from_lt: DistanceInput
_distance_from_lte: DistanceInput
_distance_from_gt: DistanceInput
_distance_from_gte: DistanceInput
# Hemisphere
_hemisphere_lat: Hemisphere # NORTH, SOUTH
_hemisphere_lng: Hemisphere # EAST, WEST
# Named regions (with geocoding data)
_in_country: CountryCode
_in_timezone: Timezone
}
input RadiusInput {
lat: Float!
lng: Float!
radius_km: Float!
}
input BoundsInput {
min_lat: Float!
max_lat: Float!
min_lng: Float!
max_lng: Float!
}
input DistanceInput {
lat: Float!
lng: Float!
km: Float!
}
query {
# Find stores within 50km of NYC
stores(where: {
location: {
_within_radius: { lat: 40.7128, lng: -74.0060, radius_km: 50 }
}
}) {
id name location
}
# Find locations in bounding box
locations(where: {
coords: {
_within_bounds: {
min_lat: 40.0, max_lat: 41.0,
min_lng: -74.5, max_lng: -73.5
}
}
}) {
id name coords
}
# Find drivers less than 5km away
drivers(where: {
position: {
_distance_from_lt: { lat: 40.7128, lng: -74.0060, km: 5 }
}
}) {
id name position
}
}
input PostalCodeFilter {
# Basic
_eq: PostalCode
_neq: PostalCode
_in: [PostalCode!]
_nin: [PostalCode!]
_is_null: Boolean
# Pattern matching
_startswith: String # "90" for LA area
_matches: String # Regex
# Country-specific parsing
_country_eq: CountryCode
# US ZIP codes
_zip5_eq: String # First 5 digits
_zip3_eq: String # SCF (Sectional Center)
# UK postcodes
_outcode_eq: String # "SW1A" of "SW1A 1AA"
_area_eq: String # "SW" area
# Canadian postal codes
_fsa_eq: String # Forward Sortation Area
}
query {
# Find LA area customers (ZIP starts with 90)
customers(where: { postal_code: { _startswith: "90" } }) {
id name postal_code
}
# Find London customers
customers(where: { postal_code: { _area_eq: "SW" } }) {
id name postal_code
}
}
input TimezoneFilter {
# Basic
_eq: Timezone
_neq: Timezone
_in: [Timezone!]
_nin: [Timezone!]
_is_null: Boolean
# Offset-based
_offset_eq: Int # UTC offset in minutes
_offset_gte: Int
_offset_lte: Int
# DST handling
_observes_dst: Boolean
_current_offset_eq: Int # Current offset (DST-aware)
# Geographic
_continent_eq: String # "America", "Europe", "Asia"
}
input LanguageCodeFilter {
# Basic
_eq: LanguageCode
_neq: LanguageCode
_in: [LanguageCode!]
_nin: [LanguageCode!]
_is_null: Boolean
# Language families
_family_eq: String # "Indo-European", "Sino-Tibetan"
_branch_eq: String # "Germanic", "Romance", "Slavic"
# Script
_script_eq: ScriptCode # "Latn", "Cyrl", "Hans", "Arab"
_script_in: [ScriptCode!]
# Properties
_is_rtl: Boolean # Right-to-left script
}

input CurrencyCodeFilter {
# Basic
_eq: CurrencyCode
_neq: CurrencyCode
_in: [CurrencyCode!]
_nin: [CurrencyCode!]
_is_null: Boolean
# Classification
_is_fiat: Boolean
_is_crypto: Boolean
_is_commodity: Boolean # XAU (gold), XAG (silver)
# Properties
_decimals_eq: Int # Minor unit decimals (USD=2, JPY=0)
_country_eq: CountryCode # Primary country
# Groupings
_is_major: Boolean # G10 currencies
_is_pegged: Boolean # Pegged to another currency
_pegged_to: CurrencyCode
}
query {
# Find transactions in major currencies
transactions(where: { currency: { _is_major: true } }) {
id amount currency
}
# Find fiat currencies only
accounts(where: { currency: { _is_fiat: true } }) {
id balance currency
}
# Find currencies pegged to USD
currencies(where: { currency: { _pegged_to: "USD" } }) {
code name
}
}
input MoneyFilter {
# Basic
_eq: Money
_neq: Money
_is_null: Boolean
# Amount comparisons (same currency)
_amount_eq: Decimal
_amount_neq: Decimal
_amount_gt: Decimal
_amount_gte: Decimal
_amount_lt: Decimal
_amount_lte: Decimal
# Currency filtering
_currency_eq: CurrencyCode
_currency_in: [CurrencyCode!]
_currency_nin: [CurrencyCode!]
# Cross-currency (with exchange rate table)
_converted_gt: MoneyInput
_converted_gte: MoneyInput
_converted_lt: MoneyInput
_converted_lte: MoneyInput
}
query {
# Find high-value orders
orders(where: {
total: {
_amount_gte: "10000.00"
_currency_eq: "USD"
}
}) {
id total
}
# Find orders over $1000 USD equivalent
orders(where: {
total: {
_converted_gte: { amount: "1000.00", currency: "USD" }
}
}) {
id total
}
}
input IBANFilter {
# Basic
_eq: IBAN
_neq: IBAN
_in: [IBAN!]
_nin: [IBAN!]
_is_null: Boolean
# Country extraction
_country_eq: CountryCode # First 2 characters
_country_in: [CountryCode!]
_country_nin: [CountryCode!]
# Bank identification
_bank_code_eq: String
_bank_code_in: [String!]
_bank_code_startswith: String
# Branch identification
_branch_code_eq: String
# SEPA
_is_sepa: Boolean # SEPA zone country
# Validation
_is_valid: Boolean # Passes mod-97 check
}
query {
# Find German bank accounts
accounts(where: { iban: { _country_eq: "DE" } }) {
id iban holder_name
}
# Find SEPA accounts
accounts(where: { iban: { _is_sepa: true } }) {
id iban
}
# Find accounts at specific bank
accounts(where: { iban: { _bank_code_eq: "COBADEFF" } }) {
id iban
}
}
input CUSIPFilter {
_eq: CUSIP
_in: [CUSIP!]
_is_null: Boolean
_issuer_eq: String # First 6 characters
_issuer_startswith: String
_is_equity: Boolean
_is_fixed_income: Boolean
}
input ISINFilter {
_eq: ISIN
_in: [ISIN!]
_is_null: Boolean
_country_eq: CountryCode # First 2 characters
_country_in: [CountryCode!]
_nsin_eq: String # National Securities ID
_nsin_startswith: String
}
input LEIFilter {
_eq: LEI
_in: [LEI!]
_is_null: Boolean
_lou_eq: String # Local Operating Unit (first 4)
_lou_in: [String!]
_is_active: Boolean
}
query {
# Find US securities
securities(where: { isin: { _country_eq: "US" } }) {
id isin name
}
# Find active legal entities
entities(where: { lei: { _is_active: true } }) {
id lei name
}
}
input PercentageFilter {
# Basic
_eq: Percentage
_neq: Percentage
_is_null: Boolean
# Numeric comparisons
_gt: Float
_gte: Float
_lt: Float
_lte: Float
# Convenience
_is_zero: Boolean
_is_positive: Boolean
_is_negative: Boolean
}

input VINFilter {
# Basic
_eq: VIN
_neq: VIN
_in: [VIN!]
_nin: [VIN!]
_is_null: Boolean
# WMI - World Manufacturer Identifier (first 3)
_wmi_eq: String # "WVW" (Volkswagen Germany)
_wmi_in: [String!]
_wmi_startswith: String # "W" (Germany), "1" (USA), "J" (Japan)
# Manufacturer
_manufacturer_eq: String # Decoded manufacturer name
_manufacturer_in: [String!]
# Model year
_model_year_eq: Int # Decoded from position 10
_model_year_gte: Int
_model_year_lte: Int
# Plant code
_plant_code_eq: String # Position 11
# Country of origin
_country_eq: CountryCode
_country_in: [CountryCode!]
_region_eq: VINRegion # EUROPE, NORTH_AMERICA, ASIA
}
query {
# Find Volkswagen vehicles
vehicles(where: { vin: { _wmi_eq: "WVW" } }) {
id vin model
}
# Find vehicles from 2020+
vehicles(where: { vin: { _model_year_gte: 2020 } }) {
id vin model_year
}
# Find German-made vehicles
vehicles(where: { vin: { _wmi_startswith: "W" } }) {
id vin manufacturer
}
# Find Toyota or Honda
vehicles(where: {
vin: { _manufacturer_in: ["Toyota", "Honda"] }
}) {
id vin manufacturer model
}
}
input TrackingNumberFilter {
# Basic
_eq: TrackingNumber
_neq: TrackingNumber
_in: [TrackingNumber!]
_is_null: Boolean
# Carrier detection
_carrier_eq: Carrier # UPS, FEDEX, USPS, DHL
_carrier_in: [Carrier!]
# Pattern
_startswith: String
_matches: String
# Service type
_service_type_eq: String # "EXPRESS", "GROUND", "FREIGHT"
}
query {
# Find FedEx shipments
shipments(where: { tracking: { _carrier_eq: "FEDEX" } }) {
id tracking status
}
# Find express shipments
shipments(where: { tracking: { _service_type_eq: "EXPRESS" } }) {
id tracking carrier
}
# Find UPS shipments (1Z prefix)
shipments(where: { tracking: { _startswith: "1Z" } }) {
id tracking
}
}
input SemanticVersionFilter {
# Basic
_eq: SemanticVersion
_neq: SemanticVersion
_in: [SemanticVersion!]
_nin: [SemanticVersion!]
_is_null: Boolean
# Semver-aware comparison
_gt: SemanticVersion
_gte: SemanticVersion
_lt: SemanticVersion
_lte: SemanticVersion
# Component extraction
_major_eq: Int
_major_gte: Int
_major_lte: Int
_minor_eq: Int
_minor_gte: Int
_minor_lte: Int
_patch_eq: Int
_patch_gte: Int
_patch_lte: Int
# Pre-release / metadata
_prerelease_eq: String # "alpha", "beta.1", "rc.2"
_has_prerelease: Boolean
_is_stable: Boolean # No prerelease tag
# Range expressions (npm/cargo style)
_satisfies: String # "^1.2.0", "~1.2.0", ">=1.0.0 <2.0.0"
_compatible_with: SemanticVersion # ^version
}
query {
# Find packages on major version 2
packages(where: { version: { _major_eq: 2 } }) {
id name version
}
# Find stable releases only
releases(where: { version: { _is_stable: true } }) {
id version published_at
}
# Find compatible versions
dependencies(where: {
version: { _satisfies: "^1.2.0" }
}) {
id name version
}
# Find pre-release versions
packages(where: { version: { _has_prerelease: true } }) {
id name version
}
}
input SlugFilter {
# Basic
_eq: Slug
_neq: Slug
_in: [Slug!]
_nin: [Slug!]
_is_null: Boolean
# Pattern matching
_startswith: String
_endswith: String
_contains: String
# Path-like slugs
_path_startswith: String # "blog/" matches "blog/post-title"
_path_depth_eq: Int # Number of segments
_path_depth_gte: Int
}
query {
# Find blog posts
pages(where: { slug: { _path_startswith: "blog/" } }) {
id title slug
}
# Find top-level pages only
pages(where: { slug: { _path_depth_eq: 1 } }) {
id title slug
}
}
input APIKeyFilter {
# Basic
_eq: APIKey
_in: [APIKey!]
_is_null: Boolean
# Prefix matching
_prefix_eq: String # "sk_live", "pk_test"
_prefix_in: [String!]
_startswith: String
# Environment detection
_is_live: Boolean # Contains "live" or "prod"
_is_test: Boolean # Contains "test" or "dev"
# Key type
_is_secret: Boolean # Starts with "sk_"
_is_public: Boolean # Starts with "pk_"
}
query {
# Find live API keys
api_keys(where: { key: { _is_live: true } }) {
id key_prefix created_at
}
# Find secret keys
api_keys(where: { key: { _is_secret: true } }) {
id key_prefix scope
}
}

input AirportCodeFilter {
# Basic
_eq: AirportCode
_neq: AirportCode
_in: [AirportCode!]
_nin: [AirportCode!]
_is_null: Boolean
# Geographic
_country_eq: CountryCode
_country_in: [CountryCode!]
_region_eq: String # State/province
_city_eq: String
_continent_eq: Continent
# Airport properties
_type_eq: AirportType # INTERNATIONAL, DOMESTIC, REGIONAL
_size_eq: AirportSize # LARGE_HUB, MEDIUM_HUB, SMALL_HUB
_is_hub: Boolean # Major airline hub
# Geospatial
_within_radius: AirportRadiusInput
# Timezone
_timezone_eq: Timezone
}
query {
# Find flights from US airports
flights(where: {
departure: { _country_eq: "US" }
}) {
id flight_number departure arrival
}
# Find flights from major hubs
flights(where: {
departure: { _is_hub: true }
}) {
id flight_number departure
}
# Find airports near a location
airports(where: {
code: {
_within_radius: { lat: 40.7, lng: -74.0, radius_km: 100 }
}
}) {
code name city
}
}
input FlightNumberFilter {
# Basic
_eq: FlightNumber
_neq: FlightNumber
_in: [FlightNumber!]
_nin: [FlightNumber!]
_is_null: Boolean
# Component extraction
_airline_eq: String # IATA code: "AA", "UA", "DL"
_airline_in: [String!]
_flight_eq: Int # Numeric portion: 1234
_flight_gte: Int
_flight_lte: Int
# Airline properties
_airline_country_eq: CountryCode
_airline_alliance_eq: String # ONEWORLD, STAR_ALLIANCE, SKYTEAM
}
query {
# Find American Airlines flights
flights(where: { flight_number: { _airline_eq: "AA" } }) {
id flight_number departure arrival
}
# Find Star Alliance flights
flights(where: {
flight_number: { _airline_alliance_eq: "STAR_ALLIANCE" }
}) {
id flight_number airline
}
}
input PortCodeFilter {
# Basic
_eq: PortCode
_neq: PortCode
_in: [PortCode!]
_nin: [PortCode!]
_is_null: Boolean
# UN/LOCODE parsing
_country_eq: CountryCode
_country_in: [CountryCode!]
_location_eq: String # 3-char location
# Port properties
_type_eq: PortType # SEA, RIVER, RAIL, MULTIMODAL
_type_in: [PortType!]
_is_seaport: Boolean
_is_inland: Boolean
# Geographic
_continent_eq: Continent
}

input MimeTypeFilter {
# Basic
_eq: MimeType
_neq: MimeType
_in: [MimeType!]
_nin: [MimeType!]
_is_null: Boolean
# Type/subtype parsing
_type_eq: String # "application", "image", "video"
_type_in: [String!]
_subtype_eq: String # "json", "png", "mp4"
_subtype_in: [String!]
# Category grouping
_is_image: Boolean
_is_video: Boolean
_is_audio: Boolean
_is_text: Boolean
_is_document: Boolean # pdf, doc, docx
_is_archive: Boolean # zip, tar, gz
_is_binary: Boolean
}
query {
# Find image files
files(where: { mime_type: { _is_image: true } }) {
id name mime_type size
}
# Find documents
files(where: { mime_type: { _is_document: true } }) {
id name mime_type
}
# Find specific types
files(where: { mime_type: { _subtype_in: ["pdf", "docx"] } }) {
id name
}
}
input ColorFilter {
# Basic
_eq: Color
_neq: Color
_in: [Color!]
_is_null: Boolean
# Hex parsing
_hex_eq: String # "#FF5733"
_hex_startswith: String
# RGB components
_red_gte: Int
_red_lte: Int
_green_gte: Int
_green_lte: Int
_blue_gte: Int
_blue_lte: Int
# HSL components
_hue_gte: Int # 0-360
_hue_lte: Int
_saturation_gte: Float # 0-100
_saturation_lte: Float
_lightness_gte: Float # 0-100
_lightness_lte: Float
# Perceptual
_is_light: Boolean # Lightness > 50%
_is_dark: Boolean
_is_saturated: Boolean # Saturation > 50%
_is_grayscale: Boolean # Saturation = 0
}
query {
# Find dark theme assets
assets(where: { primary_color: { _is_dark: true } }) {
id name primary_color
}
# Find red-ish colors (hue 0-30 or 330-360)
themes(where: {
accent_color: { _hue_lte: 30 }
}) {
id name accent_color
}
# Find grayscale images
images(where: { dominant_color: { _is_grayscale: true } }) {
id url
}
}

input NetworkAddressFilter {
# Basic
_eq: IPAddress
_neq: IPAddress
_in: [IPAddress!]
_nin: [IPAddress!]
_is_null: Boolean
# Network matching
_in_subnet: CIDR # IP within CIDR range
_in_range: IPRangeInput # IP within range
# IP version
_is_ipv4: Boolean
_is_ipv6: Boolean
# Special ranges
_is_private: Boolean # RFC 1918
_is_public: Boolean
_is_loopback: Boolean
_is_multicast: Boolean
_is_link_local: Boolean
}
input CIDRFilter {
_eq: CIDR
_neq: CIDR
_contains: IPAddress # CIDR contains IP
_overlaps: CIDR # CIDRs overlap
_is_null: Boolean
}
query {
# Find requests from private IPs
requests(where: { ip_address: { _is_private: true } }) {
id ip_address path
}
# Find requests from specific subnet
requests(where: {
ip_address: { _in_subnet: "10.0.0.0/8" }
}) {
id ip_address
}
# Find IPv6 connections
connections(where: { ip: { _is_ipv6: true } }) {
id ip protocol
}
}
input PortFilter {
# Basic
_eq: Port
_neq: Port
_in: [Port!]
_nin: [Port!]
_is_null: Boolean
# Numeric comparison
_gt: Int
_gte: Int
_lt: Int
_lte: Int
# Port categories
_is_well_known: Boolean # 0-1023
_is_registered: Boolean # 1024-49151
_is_dynamic: Boolean # 49152-65535
_is_privileged: Boolean # < 1024
# Common services
_is_http: Boolean # 80, 8080
_is_https: Boolean # 443
_is_ssh: Boolean # 22
_is_database: Boolean # 3306, 5432, 27017
}
query {
# Find services on privileged ports
services(where: { port: { _is_privileged: true } }) {
id name port
}
# Find database connections
connections(where: { port: { _is_database: true } }) {
id host port protocol
}
# Find high ports
services(where: { port: { _gte: 8000 } }) {
id name port
}
}

input LTreeFilter {
# Basic
_eq: LTree
_neq: LTree
_in: [LTree!]
_is_null: Boolean
# Path comparison
_lt: LTree
_lte: LTree
_gt: LTree
_gte: LTree
# Hierarchy
_ancestor_of: LTree # Is ancestor of path
_descendant_of: LTree # Is descendant of path
_is_descendant: LTree
# Pattern matching
_matches_lquery: String # Matches lquery pattern
_matches_ltxtquery: String # Full-text search on path
# Depth
_nlevel_eq: Int # Exact depth
_nlevel_gte: Int
_nlevel_lte: Int
}
query {
# Find all electronics categories
categories(where: {
path: { _descendant_of: "root.electronics" }
}) {
id name path
}
# Find top-level categories
categories(where: { path: { _nlevel_eq: 2 } }) {
id name path
}
# Pattern matching
categories(where: {
path: { _matches_lquery: "root.*.phones" }
}) {
id name path
}
}
input DateRangeFilter {
# Basic
_eq: DateRange
_neq: DateRange
_is_null: Boolean
# Containment
_contains_date: Date # Range contains date
_contains_range: DateRange # Range contains range
# Overlap
_overlaps: DateRange # Ranges overlap
_adjacent: DateRange # Ranges are adjacent
# Position
_strictly_left: DateRange # Entirely before
_strictly_right: DateRange # Entirely after
_not_left: DateRange # Not entirely left
_not_right: DateRange # Not entirely right
}
query {
# Find bookings that include a date
bookings(where: {
period: { _contains_date: "2024-06-15" }
}) {
id room period
}
# Find overlapping reservations
reservations(where: {
dates: { _overlaps: "[2024-06-01,2024-06-30)" }
}) {
id guest dates
}
# Find available slots (no overlap)
slots(where: {
period: {
_not: { _overlaps: "[2024-06-10,2024-06-15)" }
}
}) {
id period
}
}
input DurationFilter {
# Basic
_eq: Duration
_neq: Duration
_is_null: Boolean
# Comparison
_gt: Duration
_gte: Duration
_lt: Duration
_lte: Duration
# Component extraction
_hours_gte: Int
_hours_lte: Int
_minutes_gte: Int
_minutes_lte: Int
# Total conversion
_total_seconds_gt: Float
_total_seconds_gte: Float
_total_seconds_lt: Float
_total_seconds_lte: Float
_total_minutes_gt: Float
_total_hours_gt: Float
}
query {
# Find long videos (over 1 hour)
videos(where: { duration: { _total_hours_gt: 1 } }) {
id title duration
}
# Find short tasks (under 30 minutes)
tasks(where: { estimated_time: { _total_minutes_lt: 30 } }) {
id name estimated_time
}
}

CategoryTypesKey Operators
ContactEmail_domain_eq, _domain_endswith, _is_freemail, _is_corporate
PhoneNumber_country_code_eq, _is_mobile, _region_eq
URL_domain_eq, _protocol_eq, _path_startswith, _is_secure
GeographyCountryCode_continent_eq, _in_eu, _gdpr_applicable, _in_g20
Coordinates_within_radius, _within_bounds, _distance_from_lt
PostalCode_startswith, _zip5_eq, _area_eq
FinancialCurrencyCode_is_fiat, _is_major, _is_crypto
Money_amount_gte, _currency_eq, _converted_gt
IBAN_country_eq, _bank_code_eq, _is_sepa
IdentifiersVIN_wmi_eq, _manufacturer_eq, _model_year_gte
SemanticVersion_major_eq, _satisfies, _is_stable
TrackingNumber_carrier_eq, _service_type_eq
TransportationAirportCode_country_eq, _is_hub, _within_radius
FlightNumber_airline_eq, _airline_alliance_eq
ContentMimeType_is_image, _is_document, _type_eq
Color_is_dark, _hue_gte, _is_grayscale
NetworkingIPAddress_in_subnet, _is_private, _is_ipv6
Port_is_privileged, _is_database
DatabaseLTree_ancestor_of, _descendant_of, _nlevel_eq
DateRange_contains_date, _overlaps, _adjacent

Ensure filtered fields are indexed:

CREATE INDEX idx_user_email ON tb_user(email);
CREATE INDEX idx_user_status ON tb_user(status);
CREATE INDEX idx_post_created ON tb_post(created_at DESC);

For JSONB filtering, create GIN indexes:

-- Full JSONB index
CREATE INDEX idx_user_data ON tv_user USING GIN (data);
-- Specific field index
CREATE INDEX idx_user_data_status ON tv_user ((data->>'status'));

Leading wildcards prevent index usage:

# Bad: Can't use index
{ email: { _like: "%@example.com" } }
# Good: Can use index
{ email: { _like: "john%" } }

Always use pagination with filters:

query {
users(
where: { is_active: { _eq: true } }
limit: 20
offset: 0
) {
id
name
}
}

Beyond these standard operators, FraiseQL supports rich filters for semantic scalar types like EmailAddress, Coordinates, IBAN, and 46 more. Rich filters provide domain-specific operators:

  • Email domain matching (domainEq)
  • Geographic distance queries (distanceWithin)
  • Financial code validation (ibanCountryEq)
  • And 140+ more specialized operators

See Rich Filters for complete documentation on semantic scalars and their operators.

Rich Filters

Rich Filters — Advanced operators for semantic types