This commit introduces a `use_pg_stat_statements` flag for targets, allowing users to enable or disable the use of `pg_stat_statements` for query insights. It includes database schema changes, backend logic, and UI updates to manage this setting in both creation and editing workflows.
102 lines
5.3 KiB
Python
102 lines
5.3 KiB
Python
from datetime import datetime
|
|
from sqlalchemy import JSON, Boolean, DateTime, Float, ForeignKey, Integer, String, Text, func
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from app.core.db import Base
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
email: Mapped[str] = mapped_column(String(255), unique=True, index=True, nullable=False)
|
|
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
role: Mapped[str] = mapped_column(String(20), nullable=False, default="viewer")
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
|
|
|
audit_logs: Mapped[list["AuditLog"]] = relationship(back_populates="user")
|
|
|
|
|
|
class Target(Base):
|
|
__tablename__ = "targets"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(120), unique=True, index=True, nullable=False)
|
|
host: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
port: Mapped[int] = mapped_column(Integer, nullable=False, default=5432)
|
|
dbname: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
username: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
encrypted_password: Mapped[str] = mapped_column(Text, nullable=False)
|
|
sslmode: Mapped[str] = mapped_column(String(20), nullable=False, default="prefer")
|
|
use_pg_stat_statements: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
|
tags: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
|
|
|
|
metrics: Mapped[list["Metric"]] = relationship(back_populates="target", cascade="all, delete-orphan")
|
|
query_stats: Mapped[list["QueryStat"]] = relationship(back_populates="target", cascade="all, delete-orphan")
|
|
alert_definitions: Mapped[list["AlertDefinition"]] = relationship(back_populates="target", cascade="all, delete-orphan")
|
|
|
|
|
|
class Metric(Base):
|
|
__tablename__ = "metrics"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
target_id: Mapped[int] = mapped_column(ForeignKey("targets.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
ts: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True)
|
|
metric_name: Mapped[str] = mapped_column(String(120), nullable=False, index=True)
|
|
value: Mapped[float] = mapped_column(Float, nullable=False)
|
|
labels: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
|
|
target: Mapped[Target] = relationship(back_populates="metrics")
|
|
|
|
|
|
class QueryStat(Base):
|
|
__tablename__ = "query_stats"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
target_id: Mapped[int] = mapped_column(ForeignKey("targets.id", ondelete="CASCADE"), nullable=False, index=True)
|
|
ts: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True)
|
|
queryid: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
calls: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
total_time: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
|
mean_time: Mapped[float] = mapped_column(Float, nullable=False, default=0.0)
|
|
rows: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
|
query_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
target: Mapped[Target] = relationship(back_populates="query_stats")
|
|
|
|
|
|
class AuditLog(Base):
|
|
__tablename__ = "audit_logs"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
ts: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True)
|
|
user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id"), nullable=True, index=True)
|
|
action: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
payload: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict)
|
|
|
|
user: Mapped[User | None] = relationship(back_populates="audit_logs")
|
|
|
|
|
|
class AlertDefinition(Base):
|
|
__tablename__ = "alert_definitions"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
name: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
target_id: Mapped[int | None] = mapped_column(ForeignKey("targets.id", ondelete="CASCADE"), nullable=True, index=True)
|
|
sql_text: Mapped[str] = mapped_column(Text, nullable=False)
|
|
comparison: Mapped[str] = mapped_column(String(10), nullable=False, default="gte")
|
|
warning_threshold: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
alert_threshold: Mapped[float] = mapped_column(Float, nullable=False)
|
|
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
|
|
created_by_user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id"), nullable=True, index=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False, server_default=func.now(), index=True)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
nullable=False,
|
|
server_default=func.now(),
|
|
onupdate=func.now(),
|
|
)
|
|
|
|
target: Mapped[Target | None] = relationship(back_populates="alert_definitions")
|