APA-URAAS / scripts /init_db.py
Lordkiki's picture
Deploy URAAS β€” African Research Archival & Analytics System
8bebe44 verified
Raw
History Blame Contribute Delete
5.24 kB
"""
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()