Files
sqlalchemy-pgview/tests/test_metadata_integration.py
2026-02-08 10:09:48 +01:00

291 lines
8.9 KiB
Python

"""Tests for metadata integration and auto-registration."""
from decimal import Decimal
from sqlalchemy import (
Column,
ForeignKey,
Integer,
MetaData,
Numeric,
String,
Table,
func,
insert,
select,
)
from sqlalchemy.engine import Engine
from sqlalchemy_pgview import (
MaterializedView,
View,
get_materialized_views,
get_views,
)
class TestAutoRegistration:
"""Tests for auto-registration of views with metadata."""
def test_view_auto_registers_with_metadata(self) -> None:
"""Test that View is auto-registered when metadata is provided."""
metadata = MetaData()
# Dummy table for selectable
users = Table("users", metadata, Column("id", Integer, primary_key=True))
# View should be auto-registered
user_view = View(
"user_view",
select(users.c.id),
metadata=metadata,
)
registered = get_views(metadata)
assert "user_view" in registered
assert registered["user_view"] is user_view
def test_materialized_view_auto_registers_with_metadata(self) -> None:
"""Test that MaterializedView is auto-registered when metadata is provided."""
metadata = MetaData()
users = Table("users", metadata, Column("id", Integer, primary_key=True))
mv = MaterializedView(
"user_mv",
select(users.c.id),
metadata=metadata,
with_data=True,
)
registered = get_materialized_views(metadata)
assert "user_mv" in registered
assert registered["user_mv"] is mv
def test_view_with_schema_registers_correctly(self) -> None:
"""Test that views with schema are registered with correct key."""
metadata = MetaData()
users = Table("users", metadata, Column("id", Integer, primary_key=True))
view = View(
"stats_view",
select(users.c.id),
schema="analytics",
metadata=metadata,
)
registered = get_views(metadata)
assert "analytics.stats_view" in registered
assert registered["analytics.stats_view"] is view
def test_view_without_metadata_not_registered(self) -> None:
"""Test that views without metadata are not auto-registered."""
metadata = MetaData()
users = Table("users", metadata, Column("id", Integer, primary_key=True))
# No metadata provided - should not be registered
View("orphan_view", select(users.c.id))
registered = get_views(metadata)
assert "orphan_view" not in registered
def test_multiple_views_registered(self) -> None:
"""Test that multiple views can be registered."""
metadata = MetaData()
users = Table("users", metadata, Column("id", Integer, primary_key=True))
View("view1", select(users.c.id), metadata=metadata)
View("view2", select(users.c.id), metadata=metadata)
MaterializedView("mv1", select(users.c.id), metadata=metadata)
views = get_views(metadata)
mviews = get_materialized_views(metadata)
assert len(views) == 2
assert "view1" in views
assert "view2" in views
assert len(mviews) == 1
assert "mv1" in mviews
class TestMetadataCreateAll:
"""Tests for metadata.create_all() with views."""
def test_create_all_creates_views(self, pg_engine: Engine) -> None:
"""Test that metadata.create_all() creates registered views."""
metadata = MetaData()
users = Table(
"test_users_ca",
metadata,
Column("id", Integer, primary_key=True),
Column("name", String(100)),
)
orders = Table(
"test_orders_ca",
metadata,
Column("id", Integer, primary_key=True),
Column("user_id", Integer, ForeignKey("test_users_ca.id")),
Column("total", Numeric(10, 2)),
)
# Define view - auto-registered
user_stats = View(
"test_user_stats_ca",
select(
users.c.id,
users.c.name,
func.count(orders.c.id).label("order_count"),
)
.select_from(users.outerjoin(orders, users.c.id == orders.c.user_id))
.group_by(users.c.id, users.c.name),
metadata=metadata,
)
try:
# Create all - should create tables AND views
metadata.create_all(pg_engine)
# Insert test data
with pg_engine.begin() as conn:
conn.execute(insert(users).values(id=1, name="Alice"))
conn.execute(insert(users).values(id=2, name="Bob"))
conn.execute(insert(orders).values(id=1, user_id=1, total=100))
conn.execute(insert(orders).values(id=2, user_id=1, total=200))
# Query the view
with pg_engine.connect() as conn:
result = conn.execute(
select(user_stats.as_table()).order_by(user_stats.as_table().c.name)
).fetchall()
assert len(result) == 2
assert result[0].name == "Alice"
assert result[0].order_count == 2
assert result[1].name == "Bob"
assert result[1].order_count == 0
finally:
metadata.drop_all(pg_engine)
def test_create_all_creates_materialized_views(self, pg_engine: Engine) -> None:
"""Test that metadata.create_all() creates materialized views."""
metadata = MetaData()
orders = Table(
"test_orders_mv",
metadata,
Column("id", Integer, primary_key=True),
Column("total", Numeric(10, 2)),
)
# Define materialized view - auto-registered
order_summary = MaterializedView(
"test_order_summary_mv",
select(
func.count(orders.c.id).label("order_count"),
func.sum(orders.c.total).label("total_revenue"),
),
metadata=metadata,
with_data=True,
)
try:
metadata.create_all(pg_engine)
# Insert test data
with pg_engine.begin() as conn:
conn.execute(insert(orders).values(id=1, total=100))
conn.execute(insert(orders).values(id=2, total=200))
# Query the materialized view (shows data at creation time = 0)
with pg_engine.connect() as conn:
result = conn.execute(select(order_summary.as_table())).fetchone()
# MV was created before data, so shows 0
assert result.order_count == 0
# Refresh to see actual data
order_summary.refresh(conn)
result = conn.execute(select(order_summary.as_table())).fetchone()
assert result.order_count == 2
assert result.total_revenue == Decimal("300")
finally:
metadata.drop_all(pg_engine)
def test_drop_all_drops_views(self, pg_engine: Engine) -> None:
"""Test that metadata.drop_all() drops registered views."""
from sqlalchemy import text
metadata = MetaData()
users = Table(
"test_users_drop",
metadata,
Column("id", Integer, primary_key=True),
)
View(
"test_view_drop",
select(users.c.id),
metadata=metadata,
)
MaterializedView(
"test_mv_drop",
select(users.c.id),
metadata=metadata,
)
# Create all
metadata.create_all(pg_engine)
# Verify views exist
with pg_engine.connect() as conn:
result = conn.execute(
text(
"SELECT COUNT(*) FROM pg_class WHERE relname IN ('test_view_drop', 'test_mv_drop')"
)
).scalar()
assert result == 2
# Drop all
metadata.drop_all(pg_engine)
# Verify views are gone
with pg_engine.connect() as conn:
result = conn.execute(
text(
"SELECT COUNT(*) FROM pg_class WHERE relname IN ('test_view_drop', 'test_mv_drop')"
)
).scalar()
assert result == 0
def test_views_created_after_tables(self, pg_engine: Engine) -> None:
"""Test that views are created after tables (dependencies work)."""
metadata = MetaData()
# Table
users = Table(
"test_users_order",
metadata,
Column("id", Integer, primary_key=True),
Column("name", String(100)),
)
# View that depends on table
View(
"test_users_view_order",
select(users.c.id, users.c.name),
metadata=metadata,
)
# This should not raise - tables created before views
metadata.create_all(pg_engine)
metadata.drop_all(pg_engine)