Skip to main content

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

# Define a GraphQL type
@fraiseql.type
class User:
    id: int
    name: str
    email: str
    created_at: str

# Define a query
@fraiseql.query(sql_source="v_user")
def users(limit: int = 10) -> list[User]:
    """Get all users with pagination."""
    pass

# Define a mutation
@fraiseql.mutation(sql_source="fn_create_user", operation="CREATE")
def create_user(name: str, email: str) -> User:
    """Create a new user."""
    pass

# Export schema to JSON
if __name__ == "__main__":
    fraiseql.export_schema("schema.json")

Compile Schema

# Compile schema.json to optimized schema.compiled.json
fraiseql-cli compile schema.json -o schema.compiled.json

# Start server with compiled schema
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

# Define a fact table
@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  # Measure (aggregatable)
    quantity: int   # Measure
    cost: float     # Measure
    customer_id: str  # Denormalized filter (indexed)
    occurred_at: str  # Denormalized filter (indexed)

# Define an aggregate query
@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

-- Table name starts with tf_ (table fact)
CREATE TABLE tf_sales (
    id BIGSERIAL PRIMARY KEY,
    -- Measures: Numeric columns for fast aggregation
    revenue DECIMAL(10,2) NOT NULL,
    quantity INT NOT NULL,
    cost DECIMAL(10,2) NOT NULL,
    -- Dimensions: JSONB column for flexible GROUP BY
    data JSONB NOT NULL,
    -- Denormalized filters: Indexed columns for fast WHERE
    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

Localized Fields

A field whose label exists in several languages is stored as a map of locale to label and returned to each client as the label of its request locale:

@fraiseql.type(sql_source="tv_product")
class Product:
    id: ID
    name: fraiseql.Localized[str]                # data->'name' = {"fr-FR": "Pomme", "en-US": "Apple"}
    description: fraiseql.Localized[str] | None

@fraiseql.mutation(sql_source="fn_rename_product", operation="update")
def rename_product(id: ID, name: fraiseql.Localized[str]) -> Product: ...

The project's fraiseql.toml declares the locales ([locale] with default and allowed). A mutation argument or input field marked Localized accepts a label for the request locale, {translations: [...]}, or the map, and the SQL function receives the map. Only str can be localized; Localized[int] raises when the class is decorated.

Type Mapping

Python Type GraphQL Type
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

Metadata

Release files for fraiseql 2.17.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fraiseql 2.17.1
File Size Uploaded Provenance
fraiseql-2.17.1.tar.gz 379.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for fraiseql 2.17.1
File Interpreter ABI Platform
fraiseql-2.17.1-py3-none-any.whl Python 3 none any Details

Total release size: 467.2 kB

Release files / fraiseql-2.17.1.tar.gz

Download URL fraiseql-2.17.1.tar.gz
Size 379.6 kB
Tags Source
SHA-256 checksum
How to use checksums
3e82790a37e50d87477f2498f65b704539bea9f70466f997787e1e7a70b90a8a
BLAKE2b-256 checksum
How to use checksums
cc981f287393df6d08e3e02606c8cdbbf13f4f5f410f20e226bb962ac64c643e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / fraiseql-2.17.1-py3-none-any.whl

Download URL fraiseql-2.17.1-py3-none-any.whl
Size 87.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b9a652764b19dfca46693550b446f4603d3298a5ec509ac63216b02cc09d0be
BLAKE2b-256 checksum
How to use checksums
2430919d75ffc36ae44e7e28588a5b2261a3b0300008950ec99514d98fde2297
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Security for fraiseql 2.17.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

2.17.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page