Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-48408: Fix documentation of database initialization #365

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions docs/user-guide/database/initialize.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ For applications using Click_ (the recommended way to implement a command-line i

.. code-block:: python

import asyncio
import click
import structlog
from safir.asyncio import run_with_asyncio
from safir.database import create_database_engine, initialize_database

from .config import config
Expand All @@ -81,18 +81,23 @@ For applications using Click_ (the recommended way to implement a command-line i
@click.option(
"--reset", is_flag=True, help="Delete all existing database data."
)
@run_with_asyncio
async def init(*, reset: bool) -> None:
def init(*, reset: bool) -> None:
logger = structlog.get_logger(config.logger_name)
engine = create_database_engine(
config.database_url, config.database_password
)
await initialize_database(
engine, logger, schema=Base.metadata, reset=reset
)
await engine.dispose()

async def _init_db() -> None:
await initialize_database(
engine, logger, schema=Base.metadata, reset=reset
)
await engine.dispose()

asyncio.run(_init_db())

This code assumes that ``main`` is the Click entry point and ``.config`` provides a ``config`` object that contains the settings for the application, including the database URL and password as well as the normal Safir configuration settings.
It uses an async helper function to initialize the database since this makes integration with Alembic management easier.
See :ref:`database-alembic-init` for more details.

The database URL may be a Pydantic ``Url`` type or a `str`.
The database password may be a ``pydantic.SecretStr``, a `str`, or `None` if no password is required by the database.
Expand Down
23 changes: 15 additions & 8 deletions docs/user-guide/database/schema.rst
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ In the :file:`Dockerfile` for the application Docker image, when constructing th
COPY --from=install-image /workdir/alembic /app/alembic
WORKDIR /app

.. _database-alembic-init:

Add Alembic to database initialization
--------------------------------------

Expand All @@ -117,11 +119,11 @@ To work properly with Alembic, that initialization should stamp the database wit
Modify that initialization code as follows:

.. code-block:: python
:emphasize-lines: 7,18-24,29,38
:emphasize-lines: 7,18-24,28,41

import asyncio
import click
import structlog
from safir.asyncio import run_with_asyncio
from safir.database import (
create_database_engine,
initialize_database,
Expand All @@ -146,20 +148,25 @@ Modify that initialization code as follows:
@click.option(
"--reset", is_flag=True, help="Delete all existing database data."
)
@run_with_asyncio
async def init(*, alembic_config_path: Path, reset: bool) -> None:
def init(*, alembic_config_path: Path, reset: bool) -> None:
logger = structlog.get_logger(config.logger_name)
engine = create_database_engine(
config.database_url, config.database_password
)
await initialize_database(
engine, logger, schema=Base.metadata, reset=reset
)
await engine.dispose()

async def _init_db() -> None:
await initialize_database(
engine, logger, schema=Base.metadata, reset=reset
)
await engine.dispose()

asyncio.run(_init_db())
stamp_database(alembic_config_path)

Change ``EXAMPLE`` to the environment variable prefix used for configuration settings for your application.

This code uses an async helper function instead of the `~safir.asyncio.run_with_asyncio` decorator because Alembic, as called by `~safir.database.stamp_database`, wants to manage the event loop and therefore must be called outside of an event loop.

.. _database-alembic-commands:

Add commands to update and validate schema
Expand Down
Loading