#[non_exhaustive]pub enum WhereClause {
Field {
path: Vec<String>,
operator: WhereOperator,
value: Value,
},
And(Vec<WhereClause>),
Or(Vec<WhereClause>),
Not(Box<WhereClause>),
NativeField {
column: String,
pg_cast: String,
operator: WhereOperator,
value: Value,
},
Typed {
types: Arc<FieldTypeMap>,
inner: Box<WhereClause>,
},
Guarded {
under: Vec<String>,
guard: Box<WhereClause>,
inner: Box<WhereClause>,
},
KeyIn {
path: Vec<String>,
key_type: ScalarFieldType,
view: String,
target_key: Vec<String>,
predicate: Box<WhereClause>,
},
}Expand description
WHERE clause abstract syntax tree.
Represents a type-safe WHERE condition that can be compiled to database-specific SQL.
§Example
use fraiseql_db::{WhereClause, WhereOperator};
use serde_json::json;
// Simple condition: email ILIKE '%example.com%'
let where_clause = WhereClause::Field {
path: vec!["email".to_string()],
operator: WhereOperator::Icontains,
value: json!("example.com"),
};
// Complex condition: (published = true) AND (views >= 100)
let where_clause = WhereClause::And(vec![
WhereClause::Field {
path: vec!["published".to_string()],
operator: WhereOperator::Eq,
value: json!(true),
},
WhereClause::Field {
path: vec!["views".to_string()],
operator: WhereOperator::Gte,
value: json!(100),
},
]);Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Field
Single field condition.
Fields
operator: WhereOperatorComparison operator.
And(Vec<WhereClause>)
Logical AND of multiple conditions.
Or(Vec<WhereClause>)
Logical OR of multiple conditions.
Not(Box<WhereClause>)
Logical NOT of a condition.
NativeField
Native column condition — bypasses JSONB extraction.
Used when a direct query argument maps to a native column on sql_source,
detected at compile time. Generates "column" = $N (with an optional
PostgreSQL type cast on the parameter, e.g. $1::uuid) instead of the
default data->>'column' = $N.
Fields
pg_cast: StringPostgreSQL parameter cast suffix (e.g., "uuid", "int4").
Empty string means no cast is applied.
operator: WhereOperatorComparison operator.
Typed
A subtree whose fields carry their declared scalar types.
The generator needs the field’s type to pick a SQL cast; deciding the
cast from the operator instead is what made every non-numeric range
filter a hard error (#798). The annotation is a node of the clause rather
than a parameter of the generator on purpose: a clause travels through
ProjectionRequest, the relay cursor path, the wire adapter, federation
and the cache key, and an extra argument on any one of those seams is an
extra place to drop it. Carried by the clause, it cannot be dropped
without deleting the clause.
Only the user-supplied filter is wrapped. RLS and injected-parameter conditions are composed separately and stay untyped — they compare tenant identifiers as text.
Fields
types: Arc<FieldTypeMap>Declared type per dotted snake_case field path.
inner: Box<WhereClause>The annotated subtree.
Guarded
A subtree whose values under under are visible only where guard holds.
Every path in inner that runs through under reads its value through the guard —
CASE WHEN <guard> THEN <value> END — so where the guard fails the value is NULL:
exactly what the response serves for a related row the caller may not read. The
guard’s paths are absolute (they start with under). The executor builds it for a
client filter through a relation into a row-gated type; like Typed, it is a
node of the clause so that no seam the clause travels through can drop it.
Fields
guard: Box<WhereClause>The row predicate the related document must meet, over absolute paths.
inner: Box<WhereClause>The guarded subtree.
KeyIn
Whether the key stored at path is among the target_key values of the rows of
view that satisfy predicate, both compared as key_type (ruling AL).
A related row’s visibility, decided over the related type’s own view: where a type’s
row predicate cannot be read off the document its parent’s view embedded, the related
level is read from its view through the declared relationship, and a filter through
the relation asks the same question here, as the guard of a Guarded. Rendered
as <key> IN (SELECT <target key> FROM <view> WHERE <predicate>) — uncorrelated, so
predicate reads the view’s rows and path this row. Built by the executor, never
parsed from a client. predicate is over the view’s rows: its native columns are the
view’s, not this row’s.
Fields
key_type: ScalarFieldTypeThe declared scalar type both keys are compared as.
predicate: Box<WhereClause>The related type’s row predicate, over the view’s rows.
Implementations§
Source§impl WhereClause
impl WhereClause
Sourcepub fn typed(self, types: Arc<FieldTypeMap>) -> WhereClause
pub fn typed(self, types: Arc<FieldTypeMap>) -> WhereClause
Annotate this clause with the declared scalar types of its fields.
Sourcepub fn native_column_names(&self) -> Vec<&str>
pub fn native_column_names(&self) -> Vec<&str>
Collect all native column names referenced in this WHERE clause.
Used to enrich error messages when a native column does not exist on the
target table — the caller can hint that the column was auto-inferred from
an ID/UUID-typed argument and suggest adding the column or using
explicit native_columns annotation.
Sourcepub fn from_graphql_json(
value: &Value,
schema: &WhereFieldSchema,
) -> Result<WhereClause, FraiseQLError>
pub fn from_graphql_json( value: &Value, schema: &WhereFieldSchema, ) -> Result<WhereClause, FraiseQLError>
Parse a WhereClause from a nested GraphQL JSON where variable.
Expected format (nested object with field → operator → value):
{
"status": { "eq": "active" },
"name": { "icontains": "john" },
"_and": [ { "age": { "gte": 18 } }, { "age": { "lte": 65 } } ],
"_or": [ { "role": { "eq": "admin" } } ],
"_not": { "deleted": { "eq": true } }
}Each top-level key is either a field name (mapped to WhereClause::Field
with operator sub-keys) or a logical combinator (_and, _or, _not).
Multiple top-level keys are combined with AND.
types carries the declared scalar type of each filterable field, taken
from the compiled schema. It is a required argument rather than an
optional enrichment step because the cast a filter needs is a property of
the field: a caller that has a schema and forgets to consult it produces
SQL that errors on dates and silently under-matches on numbers. Callers
that genuinely have no schema pass SharedFieldTypes::default and get
value-shape inference.
§Errors
Returns FraiseQLError::Validation if the JSON structure is invalid or
contains unknown operators.
§Panics
Cannot panic: the internal .expect("checked len == 1") is only reached
after verifying conditions.len() == 1.
Trait Implementations§
Source§impl Clone for WhereClause
impl Clone for WhereClause
Source§fn clone(&self) -> WhereClause
fn clone(&self) -> WhereClause
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more