"""All non-nullable columns with a Python-side default must also have a server_default so that raw SQL inserts (migrations, scripts, bulk loads) produce a valid row without specifying the value. This covers the two most impactful categories: - Booleans — always has a well-defined safe value (true / false) - String enums / sentinel strings — open, pending, public, human, etc. """ from __future__ import annotations import typing import pytest from sqlalchemy.orm import DeclarativeBase from musehub.db.coord_models import MusehubCoordTask from musehub.db.musehub_collaborator_models import MusehubCollaborator from musehub.db.musehub_domain_models import MusehubDomain from musehub.db.musehub_identity_models import MusehubIdentity, MusehubProfileSnapshot from musehub.db.musehub_intel_models import MusehubIntelApiSurface, MusehubIntelBreakageIssue, MusehubIntelClones, MusehubIntelEntangle, MusehubIntelResult, MusehubIntelStable, MusehubIntelType from musehub.db.musehub_jobs_models import MusehubBackgroundJob from musehub.db.musehub_release_models import MusehubRelease from musehub.db.musehub_repo_models import MusehubBridgeMirror, MusehubMist, MusehubRepo, MusehubSession from musehub.db.musehub_social_models import MusehubIssue, MusehubIssueComment, MusehubProposal, MusehubProposalReview from musehub.db.musehub_webhook_models import MusehubWebhook, MusehubWebhookDelivery def _server_default(model: type[DeclarativeBase], col_name: str) -> typing.Any: return model.__table__.columns[col_name].server_default def _assert_has_server_default(model: type[DeclarativeBase], col_name: str) -> None: sd = _server_default(model, col_name) assert sd is not None, ( f"{model.__name__}.{col_name} has no server_default — " "raw SQL inserts will fail or produce NULL" ) # --------------------------------------------------------------------------- # Booleans # --------------------------------------------------------------------------- BOOL_COLS = [ (MusehubRepo, "training_opt_out"), (MusehubIdentity, "is_verified"), (MusehubIssueComment, "is_deleted"), (MusehubRelease, "is_draft"), (MusehubWebhook, "active"), (MusehubWebhookDelivery, "success"), (MusehubSession, "is_active"), (MusehubIntelEntangle, "structurally_linked"), (MusehubIntelStable, "since_start"), (MusehubIntelType, "return_is_any"), (MusehubBridgeMirror, "auto_export"), (MusehubProfileSnapshot, "is_stale"), (MusehubDomain, "is_verified"), (MusehubDomain, "is_deprecated"), ] @pytest.mark.parametrize("model,col", BOOL_COLS, ids=[f"{m.__name__}.{c}" for m, c in BOOL_COLS]) def test_bool_has_server_default(model: type[DeclarativeBase], col: str) -> None: _assert_has_server_default(model, col) # --------------------------------------------------------------------------- # String enums / sentinel strings # --------------------------------------------------------------------------- STR_ENUM_COLS = [ (MusehubRepo, "visibility"), (MusehubIdentity, "identity_type"), (MusehubIssue, "state"), (MusehubProposal, "state"), (MusehubProposalReview, "state"), (MusehubRelease, "channel"), (MusehubSession, "schema_version"), (MusehubBackgroundJob, "status"), (MusehubIntelApiSurface, "visibility"), (MusehubMist, "visibility"), (MusehubIntelBreakageIssue, "severity"), (MusehubBridgeMirror, "git_branch"), (MusehubCollaborator, "permission"), (MusehubCoordTask, "queue"), (MusehubCoordTask, "status"), (MusehubDomain, "version"), (MusehubDomain, "viewer_type"), ] @pytest.mark.parametrize("model,col", STR_ENUM_COLS, ids=[f"{m.__name__}.{c}" for m, c in STR_ENUM_COLS]) def test_str_enum_has_server_default(model: type[DeclarativeBase], col: str) -> None: _assert_has_server_default(model, col)