Metadata-Version: 2.4
Name: fraiseql
Version: 1.26.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Framework :: FastAPI
Classifier: Topic :: Database
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Typing :: Typed
Classifier: Operating System :: OS Independent
Requires-Dist: fastapi>=0.129.0
Requires-Dist: starlette>=1.3.1
Requires-Dist: graphql-core>=3.2.11
Requires-Dist: psycopg[pool]>=3.3.3
Requires-Dist: psycopg-pool>=3.3.1
Requires-Dist: uvicorn>=0.52.0
Requires-Dist: pydantic>=2.12.0
Requires-Dist: pydantic-settings>=2.14.2
Requires-Dist: httpx>=0.28.0
Requires-Dist: pyjwt[crypto]>=2.13.0
Requires-Dist: cryptography>=50.0.0
Requires-Dist: python-dateutil>=2.9.0
Requires-Dist: click>=8.3.3
Requires-Dist: python-dotenv>=1.2.2
Requires-Dist: structlog>=25.5.0
Requires-Dist: passlib[argon2]>=1.7.4
Requires-Dist: typer>=0.24.0
Requires-Dist: rich>=14.0.0
Requires-Dist: pyyaml>=6.0.2
Requires-Dist: fraiseql-confiture>=0.44.0
Requires-Dist: jinja2>=3.1.6
Requires-Dist: urllib3>=2.7.0
Requires-Dist: protobuf>=7.36.1,<8.0 ; extra == 'all'
Requires-Dist: wrapt>=1.16.0 ; extra == 'all'
Requires-Dist: opentelemetry-api>=1.41.1 ; extra == 'all'
Requires-Dist: opentelemetry-sdk>=1.41.1 ; extra == 'all'
Requires-Dist: opentelemetry-instrumentation-psycopg>=0.63b1 ; extra == 'all'
Requires-Dist: opentelemetry-exporter-otlp>=1.44.0 ; extra == 'all'
Requires-Dist: pyjwt[crypto]>=2.13.0 ; extra == 'all'
Requires-Dist: httpx>=0.28.0 ; extra == 'all'
Requires-Dist: cyclonedx-python-lib>=11.11.0,<12.0 ; extra == 'all'
Requires-Dist: packageurl-python>=0.17.0 ; extra == 'all'
Requires-Dist: boto3>=1.38.0 ; extra == 'all'
Requires-Dist: cryptography>=50.0.0 ; extra == 'all'
Requires-Dist: aioboto3>=15.5.0 ; extra == 'all'
Requires-Dist: google-cloud-kms>=3.16.0 ; extra == 'all'
Requires-Dist: fraiseql[langchain] ; extra == 'all'
Requires-Dist: fraiseql[llamaindex] ; extra == 'all'
Requires-Dist: pyjwt[crypto]>=2.13.0 ; extra == 'auth0'
Requires-Dist: httpx>=0.28.0 ; extra == 'auth0'
Requires-Dist: boto3>=1.38.0 ; extra == 'aws'
Requires-Dist: black>=26.5.1 ; extra == 'dev'
Requires-Dist: pre-commit>=4.6.0 ; extra == 'dev'
Requires-Dist: pytest>=9.0.3 ; extra == 'dev'
Requires-Dist: pytest-asyncio>=1.4.0 ; extra == 'dev'
Requires-Dist: pytest-timeout>=2.4.0 ; extra == 'dev'
Requires-Dist: faker>=40.23.0 ; extra == 'dev'
Requires-Dist: testcontainers[postgres]>=4.14.2 ; extra == 'dev'
Requires-Dist: testcontainers[vault]>=4.14.2 ; extra == 'dev'
Requires-Dist: docker>=7.1.0 ; extra == 'dev'
Requires-Dist: pytest-xdist>=3.8.0 ; extra == 'dev'
Requires-Dist: pytest-watch>=4.2.0 ; extra == 'dev'
Requires-Dist: pytest-cov>=7.1.0 ; extra == 'dev'
Requires-Dist: pytest-mock>=3.15.0 ; extra == 'dev'
Requires-Dist: pytest-benchmark>=5.2.3 ; extra == 'dev'
Requires-Dist: tox>=4.58.0 ; extra == 'dev'
Requires-Dist: ruff>=0.15.12 ; extra == 'dev'
Requires-Dist: ty>=0.0.35 ; extra == 'dev'
Requires-Dist: build>=1.4.0 ; extra == 'dev'
Requires-Dist: twine>=7.0.0 ; extra == 'dev'
Requires-Dist: pyyaml>=6.0.2 ; extra == 'dev'
Requires-Dist: prometheus-client>=0.24.0 ; extra == 'dev'
Requires-Dist: email-validator>=2.3.0 ; extra == 'dev'
Requires-Dist: hvac>=2.4.0 ; extra == 'dev'
Requires-Dist: moto[kms]>=5.1.21 ; extra == 'dev'
Requires-Dist: aiohttp>=3.14.3 ; extra == 'dev'
Requires-Dist: filelock>=3.24.0 ; extra == 'dev'
Requires-Dist: werkzeug>=3.1.6 ; extra == 'dev'
Requires-Dist: mkdocs>=1.6.1 ; extra == 'docs'
Requires-Dist: mkdocs-material>=9.7.7 ; extra == 'docs'
Requires-Dist: mkdocs-redirects>=1.2.2 ; extra == 'docs'
Requires-Dist: pymdown-extensions>=11.0.2 ; extra == 'docs'
Requires-Dist: cryptography>=50.0.0 ; extra == 'kms'
Requires-Dist: cryptography>=50.0.0 ; extra == 'kms-all'
Requires-Dist: httpx>=0.28.0 ; extra == 'kms-all'
Requires-Dist: aioboto3>=15.5.0 ; extra == 'kms-all'
Requires-Dist: google-cloud-kms>=3.16.0 ; extra == 'kms-all'
Requires-Dist: aioboto3>=15.5.0 ; extra == 'kms-aws'
Requires-Dist: google-cloud-kms>=3.16.0 ; extra == 'kms-gcp'
Requires-Dist: httpx>=0.28.0 ; extra == 'kms-vault'
Requires-Dist: langchain>=1.3.9 ; extra == 'langchain'
Requires-Dist: langchain-community>=0.4.1 ; extra == 'langchain'
Requires-Dist: langchain-core>=1.3.3 ; extra == 'langchain'
Requires-Dist: langchain-text-splitters>=1.1.2 ; extra == 'langchain'
Requires-Dist: langsmith>=0.11.2 ; extra == 'langchain'
Requires-Dist: llama-index>=0.14.21 ; extra == 'llamaindex'
Requires-Dist: llama-index-core>=0.14.21 ; extra == 'llamaindex'
Requires-Dist: banks>=2.4.5 ; extra == 'llamaindex'
Requires-Dist: pillow>=12.3.0 ; extra == 'llamaindex'
Requires-Dist: pypdf>=6.15.0 ; extra == 'llamaindex'
Requires-Dist: nltk>=3.10.0 ; extra == 'llamaindex'
Requires-Dist: fraiseql[langchain] ; extra == 'llm'
Requires-Dist: fraiseql[llamaindex] ; extra == 'llm'
Requires-Dist: cyclonedx-python-lib>=11.11.0,<12.0 ; extra == 'sbom'
Requires-Dist: packageurl-python>=0.17.0 ; extra == 'sbom'
Requires-Dist: protobuf>=7.36.1,<8.0 ; extra == 'tracing'
Requires-Dist: wrapt>=1.16.0 ; extra == 'tracing'
Requires-Dist: opentelemetry-api>=1.39.0 ; extra == 'tracing'
Requires-Dist: opentelemetry-sdk>=1.39.0 ; extra == 'tracing'
Requires-Dist: opentelemetry-instrumentation-psycopg>=0.63b1 ; extra == 'tracing'
Requires-Dist: opentelemetry-exporter-otlp>=1.44.0 ; extra == 'tracing'
Provides-Extra: all
Provides-Extra: auth0
Provides-Extra: aws
Provides-Extra: dev
Provides-Extra: docs
Provides-Extra: kms
Provides-Extra: kms-all
Provides-Extra: kms-aws
Provides-Extra: kms-gcp
Provides-Extra: kms-vault
Provides-Extra: langchain
Provides-Extra: llamaindex
Provides-Extra: llm
Provides-Extra: sbom
Provides-Extra: tracing
Summary: GraphQL for the LLM era. Simple. Powerful. Rust-fast. Production-ready GraphQL API framework for PostgreSQL with CQRS, JSONB optimization, and type-safe mutations
Keywords: graphql,postgresql,api,database,jsonb,fastapi,async,orm
Author-email: Lionel Hamayon <lionel.hamayon@evolution-digitale.fr>
Requires-Python: >=3.13, <3.14
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Changelog, https://github.com/fraiseql/fraiseql-python/blob/dev/CHANGELOG.md
Project-URL: Documentation, https://fraiseql.github.io/fraiseql-python/
Project-URL: Homepage, https://github.com/fraiseql/fraiseql-python
Project-URL: Issues, https://github.com/fraiseql/fraiseql-python/issues
Project-URL: Repository, https://github.com/fraiseql/fraiseql-python

# FraiseQL

[![Quality Gate](https://github.com/fraiseql/fraiseql-python/actions/workflows/ci.yml/badge.svg?branch=dev)](https://github.com/fraiseql/fraiseql-python/actions/workflows/ci.yml)
[![Documentation](https://github.com/fraiseql/fraiseql-python/actions/workflows/docs.yml/badge.svg?branch=dev)](https://github.com/fraiseql/fraiseql-python/actions/workflows/docs.yml)
[![Release](https://img.shields.io/github/v/release/fraiseql/fraiseql-python)](https://github.com/fraiseql/fraiseql-python/releases/latest)
[![Python](https://img.shields.io/badge/Python-3.13+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**A Python GraphQL framework for PostgreSQL.** Declare types and operations with
decorators, point them at PostgreSQL views and functions, and FraiseQL serves a
typed GraphQL API over FastAPI — no build step, no code generation.

PostgreSQL returns JSONB. An integrated Rust pipeline (`fraiseql_rs`) transforms it
into the HTTP response. You write Python; the hot path runs in Rust.

**Requires:** Python 3.13 (3.14 not yet supported) · PostgreSQL 13+

```python
import fraiseql
from fraiseql.fastapi import create_fraiseql_app

@fraiseql.type(sql_source="v_user", jsonb_column="data")
class User:
    """A user in the system.

    Fields:
        id: Unique user identifier
        name: User's full name
        email: User's email address
    """
    id: int
    name: str
    email: str

@fraiseql.query
async def users(info) -> list[User]:
    """Get all users."""
    db = info.context["db"]
    return await db.find("v_user")

app = create_fraiseql_app(
    database_url="postgresql://localhost/mydb",
    types=[User],
    queries=[users],
)
```

Attribute docstrings become GraphQL descriptions. List queries get `where`,
`orderBy`, `limit` and `offset` wired in automatically.

---

## How it works

```
Typical ORM stack:  PostgreSQL → rows → ORM objects → Python dicts → JSON → HTTP
FraiseQL:           PostgreSQL → JSONB → Rust field selection → HTTP
```

The view composes the whole response shape in one query, so there is no N+1 problem
and no Python serialization in the hot path. On the
[transformation benchmark](benchmarks/rust_vs_python_benchmark.py) the JSON step runs
3.6–5.9x faster than the equivalent pure-Python path — 4.1x on a 7 KB nested payload,
4.0x on a 32 KB one.

It also makes the security model structural rather than defensive:

```sql
CREATE VIEW v_user AS
SELECT id, jsonb_build_object('id', id, 'email', email) AS data
FROM tb_user;
-- password_hash and api_key are not in the JSONB, so they cannot leak
```

With an ORM-backed schema, forgetting to exclude a column is a data leak. Here the
view *is* the contract. Reads go through `v_*` views and `tv_*` projection tables;
writes go through `fn_*` PostgreSQL functions ([CQRS](docs/core/concepts-glossary.md)).

---

## v1 vs v2 — which repo do you want?

This repository is **v1 (`fraiseql-python`)**. There is a separate v2 project with a
different architecture. Both are actively maintained.

| | **v1 — this repo** | **v2 — [fraiseql/fraiseql](https://github.com/fraiseql/fraiseql)** |
|---|---|---|
| Status | Stable (1.26.0) | Active (2.14.1; breaking changes ship in minor releases) |
| Engine | Python + Rust pipeline | Compiled Rust engine |
| Schema authoring | Python decorators | 16+ languages |
| Databases | **PostgreSQL only** | PostgreSQL, MySQL, SQLite, SQL Server |
| Deployment | Runtime (FastAPI, hot reload) | Build-time (`fraiseql-cli compile`) |

Pick v1 for a Python codebase already invested in PostgreSQL, with fast iteration and
no build step. Pick v2 for polyglot teams, multiple databases, or compile-time
guarantees.

---

## Is this for you?

**Good fit if you** run PostgreSQL and are comfortable writing views and functions,
want a database-first API, need multi-tenant isolation, care about JSON throughput,
or lean on LLMs for code generation — SQL and Python are well-trained, and there is
no proprietary DSL in the way.

**Look elsewhere if you** need a database other than PostgreSQL (that is v2), do not
want JSONB in your schema, are building your first GraphQL API, or want an ORM to
model your data for you.

See [Choosing FraiseQL](docs/guides/choosing-fraiseql.md) for a longer comparison.

---

## Quick start

```bash
pip install "fraiseql<2"        # or: pip install "fraiseql[all]<2"
fraiseql init my-api
cd my-api
fraiseql dev
```

v1 and v2 share the `fraiseql` name on PyPI, and the bare name now resolves to v2 —
hence the `<2` pin. Your API is live at `http://localhost:8000/graphql`.

- [5-Minute Quickstart](docs/getting-started/quickstart.md) — copy, paste, run
- [First Hour Guide](docs/getting-started/first-hour.md) — build a complete blog API
- [Understanding FraiseQL](docs/guides/understanding-fraiseql.md) — architecture in 10 minutes
- [Installation](docs/getting-started/installation.md) — platform notes and troubleshooting

---

## Features

- **[GraphQL Cascade](docs/features/graphql-cascade.md)** — mutations report what they
  changed and which queries to invalidate; clients request as much or as little of it
  as they want.
- **[Mutations without boilerplate](docs/core/mutation-success-error.md)** —
  `@fraiseql.success` auto-injects `status`, `message`, `updated_fields` and `id`; the
  SQL function holds the business logic.
- **[Specialized scalars](docs/core/types-and-schema.md)** — 50+ validated types
  (`EmailAddress`, `Money`, `IpAddress`, `LTree`, `CUSIP`, `DateRange`, …) with
  type-aware SQL operators.
- **[Advanced filtering](docs/advanced/filter-operators.md)** — full-text search, JSONB
  paths, array operators, regex, ranges, and
  [nested array filters](docs/advanced/nested-array-filtering.md) with `AND`/`OR`/`NOT`.
- **[Vector search](docs/features/pgvector.md)** — pgvector integration for semantic
  search and RAG, with 6 distance operators.
- **[Trinity identifiers](docs/core/trinity-pattern.md)** — `pk_*` integer keys for fast
  joins (never exposed), `id` UUIDs for a stable public API, `identifier` slugs for URLs.
- **[Security](docs/production/security.md)** — RLS, rate limiting, CSRF, security
  headers, field-level authorization, KMS backends (Vault/AWS/GCP), audit logging, and
  SBOM generation via `fraiseql sbom generate`. Enforcement maturity varies per feature:
  security *profiles* enforce 7 of their 14 settings, and query depth, query complexity,
  introspection policy and audit level are configured but not enforced by the profile
  (see the module docstring in `src/fraiseql/security/profiles/definitions.py`). Check a
  given control before relying on it in production.
- **[Everything in PostgreSQL](docs/features/in-postgresql-everything.md)** — caching
  (`UNLOGGED` tables), error tracking and OpenTelemetry traces live in the same
  database, so a small deployment needs no Redis, Sentry or APM service.
- **[Automatic Persisted Queries](docs/performance/apq-optimization-guide.md)** — memory
  or PostgreSQL-backed storage for multi-instance coordination.
- **Resilience testing** — a separate, informational workflow runs the 71 failure-injection
  tests marked `chaos_real_db` (of 145 in `tests/chaos/`) against real PostgreSQL, apart from
  the per-PR suite ([strategy](docs/archive/testing/chaos-engineering-strategy.md)).

---

## Docs and tooling

- [Full documentation](docs/index.md) · [Concepts & glossary](docs/core/concepts-glossary.md)
- [API reference](docs/reference/README.md) · [CLI reference](docs/reference/cli.md)
- [Performance guide](docs/performance/index.md) · [Production deployment](docs/guides/production-deployment.md)
- [Examples](examples/README.md) — blog, e-commerce, multi-tenant SaaS, RAG, and more

The `fraiseql` CLI covers `init`, `dev`, `check`, `doctor`, `generate`, `sql`,
`migrate`, `turbo`, `sbom` and `query-stats`. Run `fraiseql --help` or see the
[CLI reference](docs/reference/cli.md).

---

## Contributing

```bash
git clone https://github.com/fraiseql/fraiseql-python
cd fraiseql-python
uv sync                     # runtime + dev deps, builds the Rust extension
uv run pre-commit install
```

Requires a Rust toolchain for `fraiseql_rs`. The runtime floor is PostgreSQL 13; the
integration tests want 14+, and CI runs them on 16.
See the [Contributing Guide](CONTRIBUTING.md).

---

## About

FraiseQL is created by **Lionel Hamayon** ([@evoludigit](https://github.com/evoludigit)).
The idea: let PostgreSQL return the JSON, let Rust shape it, and keep Python out of
the hot path.

MIT licensed — see [LICENSE](LICENSE).

