# Setup

FastSQLA provides two ways to configure your SQLAlchemy database connection:

- **Environment variables** (lifespan): Simple configuration following [12-factor app](https://12factor.net/config) principles, ideal for most use cases.
- **Programmatic** (new_lifespan): Direct SQLAlchemy engine configuration for advanced customization needs

## `fastsqla.lifespan`

Use `fastsqla.lifespan` to set up SQLAlchemy directly from environment variables.

In an ASGI application, [lifespan events](https://asgi.readthedocs.io/en/latest/specs/lifespan.html) are used to communicate startup & shutdown events.

The [`lifespan`](https://fastapi.tiangolo.com/advanced/events/#lifespan) parameter of the `FastAPI` app can be assigned to a context manager, which is opened when the app starts and closed when the app stops.

In order for `FastSQLA` to setup `SQLAlchemy` before the app is started, set `lifespan` parameter to `fastsqla.lifespan`:

```
from fastapi import FastAPI
from fastsqla import lifespan


app = FastAPI(lifespan=lifespan)

```

If multiple lifespan contexts are required, create an async context manager function to handle them and set it as the app's lifespan:

```
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastsqla import lifespan as fastsqla_lifespan
from this_other_library import another_lifespan


@asynccontextmanager
async def lifespan(app:FastAPI) -> AsyncGenerator[dict, None]:
    async with AsyncExitStack() as stack:
        yield {
            **stack.enter_async_context(lifespan(app)),
            **stack.enter_async_context(another_lifespan(app)),
        }


app = FastAPI(lifespan=lifespan)

```

To learn more about lifespan protocol:

- [Lifespan Protocol](https://asgi.readthedocs.io/en/latest/specs/lifespan.html)
- [Use Lifespan State instead of `app.state`](https://github.com/Kludex/fastapi-tips?tab=readme-ov-file#6-use-lifespan-state-instead-of-appstate)
- [FastAPI lifespan documentation](https://fastapi.tiangolo.com/advanced/events/)

### Lifespan configuration

Configuration is done exclusively via environment variables, adhering to the [**Twelve-Factor App methodology**](https://12factor.net/config).

The only required key is **`SQLALCHEMY_URL`**, which defines the database URL. It specifies the database driver in the URL's scheme and allows embedding driver parameters in the query string. Example:

```
sqlite+aiosqlite:////tmp/test.db

```

All parameters of sqlalchemy.create_engine can be configured by setting environment variables, with each parameter name prefixed by **`SQLALCHEMY_`**.

Note

FastSQLA is **case-insensitive** when reading environment variables, so parameter names prefixed with **`SQLALCHEMY_`** can be provided in any letter case.

#### Examples

1. PostgreSQL url using asyncpg driver with a pool_recycle of 30 minutes:

   ```
   export SQLALCHEMY_URL=postgresql+asyncpg://postgres@localhost/postgres
   export SQLALCHEMY_POOL_RECYCLE=1800

   ```

1. SQLite db file using aiosqlite driver with a pool_size of 50:

   ```
   export sqlalchemy_url=sqlite+aiosqlite:///tmp/test.db
   export sqlalchemy_pool_size=50

   ```

1. MariaDB url using aiomysql driver with echo parameter set to `True`

   ```
   export sqlalchemy_url=mysql+aiomysql://bob:password!@db.example.com/app
   export sqlalchemy_echo=true

   ```

## `fastsqla.new_lifespan`

Create a new lifespan async context manager.

It expects the exact same parameters as sqlalchemy.ext.asyncio.create_async_engine

Example:

```
from fastapi import FastAPI
from fastsqla import new_lifespan

lifespan = new_lifespan(
    "sqlite+aiosqlite:///app/db.sqlite", connect_args={"autocommit": False}
)

app = FastAPI(lifespan=lifespan)

```

Parameters:

| Name  | Type   | Description                                                                        | Default |
| ----- | ------ | ---------------------------------------------------------------------------------- | ------- |
| `url` | `str`  | Database url.                                                                      | `None`  |
| `kw`  | `dict` | Configuration parameters as expected by sqlalchemy.ext.asyncio.create_async_engine | `{}`    |

Raises:

| Type                        | Description                                  |
| --------------------------- | -------------------------------------------- |
| `MissingConfigurationError` | If a required SQLAlchemy setting is missing. |
