audit_trail.migrations¶
Alembic helpers and DDL for the partitioned audit tables.
Alembic's autogenerate does not understand partitioning, so the audit tables are created from this module instead. Nothing here imports Alembic; in a migration::
from audit_trail import migrations
from audit_trail.tables import build_tables
tables = build_tables(schema="audit")
def upgrade() -> None:
migrations.create_audit_tables(op.get_bind(), tables, MySeverity)
def downgrade() -> None:
migrations.drop_audit_tables(op.get_bind(), tables)
create_sql renders the same DDL as a plain SQL script. Passing
create_statements to op.execute also works, unless a schema or table
name contains :, which op.execute would read as a bind parameter.
The DDL creates the partitioned parents, one partition per severity and the
indexes, but no monthly partitions: those depend on the date the code runs,
not the date the migration was written. Run
audit_trail.maintenance.ensure_partitions (or PartitionManager) after
migrating and before the first write; until then every insert fails with
SQLSTATE 23514.
Naming:
- severity partition:
<activity table>_<severity value>, for exampleaudit_activity_10; - monthly partition:
<parent>_pYYYY_MM, where the parent is the transaction table or a severity partition, for exampleaudit_transaction_p2026_09andaudit_activity_10_p2026_09.
Monthly bounds are UTC-anchored timestamptz literals: the partition for
September 2026 holds ['2026-09-01 00:00:00+00', '2026-10-01 00:00:00+00')
whatever the session or server time zone.
severity_values ¶
Return the distinct severity values, sorted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
severities
|
Iterable[int]
|
A severity |
required |
Returns:
| Type | Description |
|---|---|
list[int]
|
The values as plain ints. |
Source code in audit_trail/migrations.py
severity_partition_name ¶
Name of the partition holding one severity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
activity_table
|
str
|
Name of the activity table. |
required |
severity
|
int
|
Severity value. |
required |
Returns:
| Type | Description |
|---|---|
str
|
|
Source code in audit_trail/migrations.py
month_partition_name ¶
Name of a monthly partition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
parent
|
str
|
Name of the partitioned parent: the transaction table or a severity partition. |
required |
month
|
date
|
Any day of the month. |
required |
Returns:
| Type | Description |
|---|---|
str
|
|
Source code in audit_trail/migrations.py
month_bounds ¶
UTC bounds of a month.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
month
|
date
|
Any day of the month. |
required |
Returns:
| Type | Description |
|---|---|
tuple[datetime, datetime]
|
The first instant of the month and of the next one, both in UTC. |
Source code in audit_trail/migrations.py
qualified_name ¶
Quote schema.name for use in DDL.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema
|
str | None
|
Schema name, or |
required |
name
|
str
|
Table name. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The quoted, schema-qualified name. |
Source code in audit_trail/migrations.py
create_severity_partition_sql ¶
create_severity_partition_sql(
tables: AuditTables,
severity: int,
name: str | None = None,
) -> str
DDL for one severity partition of the activity table.
The partition is itself partitioned by created_at and holds no rows
until its monthly partitions exist.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tables
|
AuditTables
|
The audit tables. |
required |
severity
|
int
|
Severity value. |
required |
name
|
str | None
|
Partition name. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
A |
Source code in audit_trail/migrations.py
create_month_partition_sql ¶
create_month_partition_sql(
schema: str | None,
parent: str,
month: date,
name: str | None = None,
) -> str
DDL for one monthly partition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schema
|
str | None
|
Schema of the parent; the partition goes in the same one. |
required |
parent
|
str
|
Name of the partitioned parent: the transaction table or a severity partition. |
required |
month
|
date
|
Any day of the month. |
required |
name
|
str | None
|
Partition name. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
A |
str
|
statement with UTC bounds. |
Source code in audit_trail/migrations.py
create_statements ¶
DDL creating the audit tables, their severity partitions and indexes.
No monthly partition is created: run
audit_trail.maintenance.ensure_partitions before the first write, or
every insert fails with SQLSTATE 23514. Indexes are created on the
partitioned parents, so PostgreSQL adds them to every partition, including
the ones created later.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tables
|
AuditTables
|
The audit tables, from |
required |
severities
|
Iterable[int]
|
A severity |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
The statements, in order, without trailing semicolons. |
Source code in audit_trail/migrations.py
drop_statements ¶
DDL dropping the audit tables with all their partitions.
The schema itself is kept.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tables
|
AuditTables
|
The audit tables. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
The statements, in order, without trailing semicolons. |
Source code in audit_trail/migrations.py
create_sql ¶
create_statements as one SQL script.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tables
|
AuditTables
|
The audit tables, from |
required |
severities
|
Iterable[int]
|
A severity |
required |
Returns:
| Type | Description |
|---|---|
str
|
The statements, each terminated by a semicolon. |
Source code in audit_trail/migrations.py
drop_sql ¶
drop_statements as one SQL script.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tables
|
AuditTables
|
The audit tables. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The statements, each terminated by a semicolon. |
create_audit_tables ¶
create_audit_tables(
connection: Connection,
tables: AuditTables,
severities: Iterable[int],
) -> None
Execute create_statements on connection.
Runs in the connection's current transaction; the caller commits. Run
audit_trail.maintenance.ensure_partitions before the first write.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
Connection
|
Connection to run on, such as Alembic's |
required |
tables
|
AuditTables
|
The audit tables, from |
required |
severities
|
Iterable[int]
|
A severity |
required |
Source code in audit_trail/migrations.py
drop_audit_tables ¶
Execute drop_statements on connection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connection
|
Connection
|
Connection to run on, such as Alembic's |
required |
tables
|
AuditTables
|
The audit tables. |
required |