File size: 5,235 Bytes
74bf532 8bebe44 91f87e2 74bf532 8bebe44 74bf532 8bebe44 74bf532 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | """
Database Initialization Script
Creates all tables and seeds Communities and Collections based on UNILAG structure.
"""
import os
import sys
# Add project root to path (parent of scripts/)
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from uraas.database import Collection, Community, SessionLocal, init_db, sync_schema_columns
# Import citation tracker models so SQLAlchemy registers their tables with
# Base.metadata before create_all() runs β otherwise citations,
# citation_metrics, and author_metrics are never created.
import uraas.services.citation_tracker # noqa: F401
from uraas.utils.unilag_classifier import UNILAG_STRUCTURE
# Base.metadata.create_all() (called by init_db() below) only creates tables
# that don't exist yet β it never alters an EXISTING table to add a column a
# newer version of the ORM model expects. On a fresh DB that's a no-op (every
# table is new, so every column is already there); on a database that
# already existed before some column was added to the model (e.g. an HF
# Space's persistent /data/uraas.db surviving across deploys), the table is
# silently left on its old schema and the very next query touching that
# column crashes β confirmed live 2026-07-19: the Space failed to start
# entirely ("no such column: communities.unit_type") because its persistent
# DB predated that column and nothing ever ran the matching migration
# against it. Running every idempotent (column_exists()-guarded, ALTER-TABLE-
# only) migration here means any existing database β this one included β
# self-heals to the current schema on every startup, not just fresh ones.
# migrate_add_ror.py is deliberately excluded: unlike the others it also
# *writes* a default ROR value to existing NULL rows, and that default is
# the deprecated pre-2026 UNILAG ROR (03qcnxw14, since corrected to
# 05rk03822 by migrate_unilag_ror.py) β safe to run once by hand, not safe
# to run unconditionally on every boot.
_SCHEMA_MIGRATIONS = [
"migrate_add_pid_source",
"migrate_add_community_ace_columns",
"migrate_add_author_isni",
"migrate_add_item_funders",
"migrate_2026_upgrade",
"migrate_add_sc_columns",
]
def run_schema_migrations():
import importlib
print("Applying schema migrations (idempotent β safe to re-run)...")
print(" Generic column sync:")
sync_schema_columns()
for mod_name in _SCHEMA_MIGRATIONS:
try:
mod = importlib.import_module(mod_name)
mod.main()
except Exception as e:
# A migration failing shouldn't take down the whole app if the
# underlying tables/columns it depends on genuinely aren't there
# yet for some other reason β log and continue rather than abort
# startup entirely (seeding below will surface the real error if
# it still matters).
print(f" [WARN] {mod_name} failed (continuing): {e}")
print()
def seed_communities_and_collections():
"""Seed the database with UNILAG faculty and department structure."""
session = SessionLocal()
try:
print("Seeding Communities (Faculties) and Collections (Departments)...")
for faculty_name, departments in UNILAG_STRUCTURE.items():
# Check if community exists
community = session.query(Community).filter_by(name=faculty_name).first()
if not community:
community = Community(name=faculty_name)
session.add(community)
session.flush()
print(f" Created Community: {faculty_name}")
# Create collections (departments) under this community
for dept_name, keywords in departments.items():
collection = session.query(Collection).filter_by(name=dept_name).first()
if not collection:
collection = Collection(
community_id=community.id,
name=dept_name,
keywords=", ".join(keywords),
)
session.add(collection)
print(f" Created Collection: {dept_name}")
session.commit()
print("\n[OK] Database seeding completed successfully!")
print(f" Total Communities: {session.query(Community).count()}")
print(f" Total Collections: {session.query(Collection).count()}")
except Exception as e:
print(f"\n[ERR] Error seeding database: {e}")
session.rollback()
raise
finally:
session.close()
def main():
print("=" * 60)
print("URAAS Database Initialization")
print("=" * 60)
print()
# Create all tables
print("Creating database tables...")
init_db()
print("[OK] Tables created successfully!")
print()
# Heal any existing database (e.g. a persistent volume surviving across
# deploys) whose tables predate a column the current models expect.
run_schema_migrations()
# Seed communities and collections
seed_communities_and_collections()
print()
print("=" * 60)
print("Database is ready for use!")
print("=" * 60)
if __name__ == "__main__":
main()
|