Metadata-Version: 2.5
Name: db-graphql-gateway
Version: 0.1.1
Summary: Automatically generate a secure, production-ready GraphQL API from a database connection.
Author-email: Mukesh M Lohar <mukesh1lohar@gmail.com>
License: MIT
License-File: LICENSE
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.11
Requires-Dist: click>=8.1.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: pyjwt[crypto]>=2.8.0
Requires-Dist: pyyaml>=6.0.0
Requires-Dist: strawberry-graphql>=0.200.0
Provides-Extra: dev
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pre-commit; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-asyncio; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Requires-Dist: testcontainers[postgres]>=4.4.1; extra == 'dev'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.141.1; extra == 'fastapi'
Requires-Dist: httpx>=0.28.1; extra == 'fastapi'
Provides-Extra: mysql
Requires-Dist: asyncmy>=0.2.14; extra == 'mysql'
Provides-Extra: postgres
Requires-Dist: asyncpg>=0.28.0; extra == 'postgres'
Provides-Extra: sqlite
Requires-Dist: aiosqlite>=0.22.1; extra == 'sqlite'
Description-Content-Type: text/markdown

# db-graphql-gateway

A production-grade, reusable Python package that automatically generates a secure, optimized GraphQL API directly from your database connection. 

It acts as a bridge between your database and GraphQL, translating GraphQL queries into efficient, parameterized SQL without requiring you to manually write resolvers, define schemas, or worry about the typical pitfalls of database-to-API integrations.

## 📦 Installation

Available on PyPI. Install via `pip` or `uv`:

```bash
pip install "db-graphql-gateway[fastapi]"
```

## ✨ Features

- **No ORM Required**: The database itself is the source of truth. You don't need to define models in SQLAlchemy, SQLModel, Django, or Prisma just to get a GraphQL API.
- **Security First**: Authentication and Authorization are treated as separate concerns. Authorization is implemented as **SQL predicates**, meaning data filtering happens deep at the database engine level.
- **N+1 Prevention Guarantee**: A sophisticated, request-scoped DataLoader pattern is wired up automatically. Combined with integrated authorization predicates, it guarantees **O(1) database queries per relationship depth**.
- **Zero Raw SQL Exposure**: Clients never provide SQL fragments. All filters, sorting rules, and pagination constraints are strictly typed GraphQL arguments, protecting you from SQL injection.
- **AST Security Limits**: Configured `max_depth` and `max_aliases` protections via `QueryDepthLimiter` and `MaxAliasesLimiter` to harden the gateway against expansive query attacks.

## ⚡ Quickstart Example

Here is a complete example of connecting to your database, building the GraphQL schema dynamically, and mounting it in FastAPI.

```python
import asyncio
import uvicorn
from fastapi import FastAPI
from db_graphql_gateway.database.adapters.postgres.adapter import PostgresAdapter
from db_graphql_gateway.schema.config import GatewayConfig
from db_graphql_gateway.graphql.builder import GraphQLSchemaBuilder
from db_graphql_gateway.auth.authorization import AuthorizationEngine
from db_graphql_gateway.auth.providers import JWTAuthenticationProvider
import strawberry
from strawberry.fastapi import GraphQLRouter

# 1. Initialize the Database Adapter
# Other adapters (MySQLAdapter, SQLiteAdapter) are also available.
db_adapter = PostgresAdapter(dsn="postgresql://user:password@localhost:5432/my_db")

# 2. Configure Security & Authorization
auth_engine = AuthorizationEngine()
auth_provider = JWTAuthenticationProvider(secret_key="super-secret")
config = GatewayConfig()

async def lifespan(app: FastAPI):
    # Connect to the database on startup
    await db_adapter.connect()
    yield
    # Cleanup on shutdown
    await db_adapter.close()

app = FastAPI(lifespan=lifespan)

@app.on_event("startup")
async def setup_graphql():
    # 3. Build the GraphQL Schema dynamically from the database
    schema_builder = GraphQLSchemaBuilder(
        db_adapter=db_adapter, 
        config=config, 
        auth_engine=auth_engine
    )
    schema = await schema_builder.build_schema()
    
    # 4. Mount the Strawberry Router onto FastAPI
    graphql_app = GraphQLRouter(
        schema, 
        context_getter=lambda req: {"request": req, "auth_provider": auth_provider}
    )
    app.include_router(graphql_app, prefix="/graphql")

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

### Example GraphQL Query

Once running, you can hit `http://localhost:8000/graphql` and execute complex relational queries:

```graphql
query {
  users(first: 10, filter: { isActive: { eq: true } }) {
    edges {
      node {
        id
        username
        posts {
          title
        }
      }
    }
  }
}
```

## 🏗 Architecture Highlights

The system is decoupled into three primary layers, giving you total control before the schema is ever exposed to the client.

1. **Introspection**: Connects to PostgreSQL, MySQL, or SQLite and introspects tables, columns, primary keys, foreign keys, and views.
2. **Intermediate Representation (IR)**: Converts the raw DB schema into a database-agnostic IR. This is where your YAML configurations override names or hide sensitive fields.
3. **GraphQL Generation**: The IR dynamically builds a fully-typed Strawberry GraphQL schema.
4. **Query Execution**: ASTs are parsed, authorization policies are merged, and highly optimized SQL (`EXISTS`, `JOIN`, `IN`) is generated to fulfill the request.
