Skip to main content

Executor

Struct Executor 

Source
pub struct Executor<A: DatabaseAdapter> { /* private fields */ }
Expand description

Query executor - executes compiled GraphQL queries.

This is the main entry point for runtime query execution. It coordinates matching, planning, execution, and projection.

§Type Parameters

  • A - The database adapter type (implements DatabaseAdapter trait)

§Ownership and Lifetimes

The executor holds owned references to schema and runtime data, with no borrowed pointers:

  • schema: Owned CompiledSchema (immutable after construction)
  • adapter: Shared via Arc<A> to allow multiple executors/tasks to use the same connection pool
  • introspection: Owned cached GraphQL schema responses
  • config: Owned runtime configuration

No explicit lifetimes required - all data is either owned or wrapped in Arc, so the executor can be stored in long-lived structures without lifetime annotations or borrow-checker issues.

§Concurrency

Executor<A> is Send + Sync when A is Send + Sync. It can be safely shared across threads and tasks without cloning:

let executor = Arc::new(Executor::new(schema, adapter, config));
// Can be cloned into multiple tasks
let exec_clone = executor.clone();
tokio::spawn(async move {
    let result = exec_clone.execute(query, vars).await;
});

§Query Timeout

Queries are protected by the query_timeout_ms configuration in RuntimeConfig (default: 30s). When a query exceeds this timeout, it returns FraiseQLError::Timeout without panicking. Set query_timeout_ms to 0 to disable timeout enforcement.

Implementations§

Source§

impl<A: DatabaseAdapter> Executor<A>

Source

pub fn new(schema: CompiledSchema, adapter: Arc<A>) -> Self

Create new executor.

§Arguments
  • schema - Compiled schema
  • adapter - Database adapter
§Example
let schema = CompiledSchema::from_json(schema_json)?;
let adapter = PostgresAdapter::new(connection_string).await?;
let executor = Executor::new(schema, Arc::new(adapter));
Source

pub fn with_config( schema: CompiledSchema, adapter: Arc<A>, config: RuntimeConfig, ) -> Self

Create new executor with custom configuration.

§Arguments
  • schema - Compiled schema
  • adapter - Database adapter
  • config - Runtime configuration
Source

pub async fn execute( &self, query: &str, variables: Option<&Value>, ) -> Result<String>

Execute a GraphQL query.

§Arguments
  • query - GraphQL query string
  • variables - Query variables (optional)
§Returns

GraphQL response as JSON string

§Errors

Returns error if:

  • Query is malformed
  • Query references undefined operations
  • Database execution fails
  • Result projection fails
§Example
let query = r#"query { users { id name } }"#;
let result = executor.execute(query, None).await?;
println!("{}", result);
Source

pub async fn execute_with_scopes( &self, query: &str, variables: Option<&Value>, user_scopes: &[String], ) -> Result<String>

Execute a GraphQL query with user context for field-level access control.

This method validates that the user has permission to access all requested fields before executing the query. If field filtering is enabled in the RuntimeConfig and the user lacks required scopes, this returns an error.

§Arguments
  • query - GraphQL query string
  • variables - Query variables (optional)
  • user_scopes - User’s scopes from JWT token (pass empty slice if unauthenticated)
§Returns

GraphQL response as JSON string, or error if access denied

§Example
let query = r#"query { users { id name salary } }"#;
let user_scopes = user.scopes.iter().map(|s| s.as_str()).collect::<Vec<_>>();
let result = executor.execute_with_scopes(query, None, &user_scopes).await?;
Source

pub async fn execute_with_context( &self, query: &str, variables: Option<&Value>, ctx: &ExecutionContext, ) -> Result<String>

Execute a GraphQL query with cancellation support via ExecutionContext.

This method allows graceful cancellation of long-running queries through a cancellation token. If the token is cancelled during execution, the query returns a FraiseQLError::Cancelled error.

§Arguments
  • query - GraphQL query string
  • variables - Query variables (optional)
  • ctx - ExecutionContext with cancellation token
§Returns

GraphQL response as JSON string, or error if cancelled or execution fails

§Example
let ctx = ExecutionContext::new("user-query-123".to_string());
let cancel_token = ctx.cancellation_token().clone();

// Spawn a task to cancel after 5 seconds
tokio::spawn(async move {
    tokio::time::sleep(Duration::from_secs(5)).await;
    cancel_token.cancel();
});

let result = executor.execute_with_context(query, None, &ctx).await;
match result {
    Err(FraiseQLError::Cancelled { reason, .. }) => {
        eprintln!("Query cancelled: {}", reason);
    }
    Ok(response) => println!("{}", response),
    Err(e) => eprintln!("Error: {}", e),
}
Source

pub async fn execute_with_security( &self, query: &str, variables: Option<&Value>, security_context: &SecurityContext, ) -> Result<String>

Execute a GraphQL query with row-level security (RLS) context.

This method applies RLS filtering based on the user’s SecurityContext before executing the query. If an RLS policy is configured in RuntimeConfig, it will be evaluated to determine what rows the user can access.

§Arguments
  • query - GraphQL query string
  • variables - Query variables (optional)
  • security_context - User’s security context (authentication + permissions)
§Returns

GraphQL response as JSON string, or error if access denied by RLS

§Example
let query = r#"query { posts { id title } }"#;
let context = SecurityContext {
    user_id: "user1".to_string(),
    roles: vec!["user".to_string()],
    tenant_id: None,
    scopes: vec![],
    attributes: HashMap::new(),
    request_id: "req-1".to_string(),
    ip_address: None,
    authenticated_at: Utc::now(),
    expires_at: Utc::now() + Duration::hours(1),
    issuer: None,
    audience: None,
};
let result = executor.execute_with_security(query, None, &context).await?;
Source

pub fn check_field_access( &self, type_name: &str, field_name: &str, user_scopes: &[String], ) -> Result<(), FieldAccessError>

Check if a specific field can be accessed with given scopes.

This is a convenience method for checking field access without executing a query.

§Arguments
  • type_name - The GraphQL type name
  • field_name - The field name
  • user_scopes - User’s scopes from JWT token
§Returns

Ok(()) if access is allowed, Err(FieldAccessError) if denied

Source

pub async fn execute_window_query( &self, query_json: &Value, query_name: &str, metadata: &FactTableMetadata, ) -> Result<String>

Execute a window query.

§Arguments
  • query_json - JSON representation of the window query
  • query_name - GraphQL field name (e.g., “sales_window”)
  • metadata - Fact table metadata
§Returns

GraphQL response as JSON string

§Errors

Returns error if:

  • Query parsing fails
  • Execution plan generation fails
  • SQL generation fails
  • Database execution fails
  • Result projection fails
§Example
let query_json = json!({
    "table": "tf_sales",
    "select": [{"type": "measure", "name": "revenue", "alias": "revenue"}],
    "windows": [{
        "function": {"type": "row_number"},
        "alias": "rank",
        "partitionBy": [{"type": "dimension", "path": "category"}],
        "orderBy": [{"field": "revenue", "direction": "DESC"}]
    }]
});

let metadata = /* fact table metadata */;
let result = executor.execute_window_query(&query_json, "sales_window", &metadata).await?;
Source

pub async fn execute_json( &self, query: &str, variables: Option<&Value>, ) -> Result<Value>

Execute a query and return parsed JSON.

Same as execute() but returns parsed serde_json::Value instead of string.

Source

pub async fn execute_aggregate_query( &self, query_json: &Value, query_name: &str, metadata: &FactTableMetadata, ) -> Result<String>

Execute an aggregate query.

§Arguments
  • query_json - JSON representation of the aggregate query
  • query_name - GraphQL field name (e.g., “sales_aggregate”)
  • metadata - Fact table metadata
§Returns

GraphQL response as JSON string

§Errors

Returns error if:

  • Query parsing fails
  • Execution plan generation fails
  • SQL generation fails
  • Database execution fails
  • Result projection fails
§Example
let query_json = json!({
    "table": "tf_sales",
    "groupBy": { "category": true },
    "aggregates": [{"count": {}}]
});

let metadata = /* fact table metadata */;
let result = executor.execute_aggregate_query(&query_json, "sales_aggregate", &metadata).await?;
Source

pub const fn schema(&self) -> &CompiledSchema

Get the compiled schema.

Source

pub const fn config(&self) -> &RuntimeConfig

Get runtime configuration.

Source

pub fn adapter(&self) -> &Arc<A>

Get database adapter reference.

Auto Trait Implementations§

§

impl<A> Freeze for Executor<A>

§

impl<A> !RefUnwindSafe for Executor<A>

§

impl<A> Send for Executor<A>

§

impl<A> Sync for Executor<A>

§

impl<A> Unpin for Executor<A>

§

impl<A> UnsafeUnpin for Executor<A>

§

impl<A> !UnwindSafe for Executor<A>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more