FraiseQL v2 - Python Schema Authoring
Python decorators for authoring FraiseQL schemas
This package provides Python decorators to define GraphQL schemas that are compiled by the FraiseQL Rust engine.
Architecture
Python Decorators ā schema.json ā fraiseql-cli compile ā schema.compiled.json ā Rust Runtime
Important: This package is for schema authoring only. It does NOT provide runtime execution.
The compiled schema is executed by the standalone Rust server.
Installation
pip install fraiseql
Quick Start
import fraiseql
@fraiseql.type
class User:
id: int
name: str
email: str
created_at: str
@fraiseql.query(sql_source="v_user")
def users(limit: int = 10) -> list[User]:
"""Get all users with pagination."""
pass
@fraiseql.mutation(sql_source="fn_create_user", operation="CREATE")
def create_user(name: str, email: str) -> User:
"""Create a new user."""
pass
if __name__ == "__main__":
fraiseql.export_schema("schema.json")
Compile Schema
fraiseql-cli compile schema.json -o schema.compiled.json
fraiseql-server --schema schema.compiled.json
Features
- Type-safe: Python type hints map to GraphQL types
- Database-backed: Queries map to SQL views, mutations to functions
- Compile-time: All validation happens at compile time, zero runtime overhead
- No FFI: Pure JSON output, no Python-Rust bindings needed
- Analytics: Fact tables and aggregate queries for OLAP workloads
Analytics / Fact Tables
FraiseQL supports high-performance analytics via fact tables:
import fraiseql
@fraiseql.fact_table(
table_name="tf_sales",
measures=["revenue", "quantity", "cost"],
dimension_paths=[
{"name": "category", "json_path": "data->>'category'", "data_type": "text"},
{"name": "region", "json_path": "data->>'region'", "data_type": "text"}
]
)
@fraiseql.type
class Sale:
id: int
revenue: float
quantity: int
cost: float
customer_id: str
occurred_at: str
@fraiseql.aggregate_query(
fact_table="tf_sales",
auto_group_by=True,
auto_aggregates=True
)
@fraiseql.query
def sales_aggregate() -> list[dict]:
"""Aggregate sales with flexible grouping and filtering."""
This generates a GraphQL query that supports:
- GROUP BY: Dimensions (
category, region) and temporal buckets (occurred_at_day, occurred_at_month)
- Aggregates:
count, revenue_sum, revenue_avg, quantity_sum, etc.
- WHERE: Pre-aggregation filters (
customer_id, occurred_at range)
- HAVING: Post-aggregation filters (
revenue_sum_gt: 1000)
- ORDER BY: Any aggregate or dimension
- LIMIT/OFFSET: Pagination
Fact Table Pattern
CREATE TABLE tf_sales (
id BIGSERIAL PRIMARY KEY,
revenue DECIMAL(10,2) NOT NULL,
quantity INT NOT NULL,
cost DECIMAL(10,2) NOT NULL,
data JSONB NOT NULL,
customer_id UUID NOT NULL,
occurred_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX ON tf_sales(customer_id);
CREATE INDEX ON tf_sales(occurred_at);
Key Principles:
- Measures: SQL columns (numeric types) for fast aggregation
- Dimensions: JSONB
data column for flexible grouping
- Denormalized Filters: Indexed SQL columns for fast WHERE clauses
- No Joins: All dimensional data denormalized at ETL time
Type Mapping
int | Int |
float | Float |
str | String |
bool | Boolean |
list[T] | [T] |
T | None | T (nullable) |
| Custom class | Object type |
Documentation
Full documentation: https://fraiseql.readthedocs.io
License
MIT