# Mengimpor modul Any untuk type hint fleksibel dari modul standar typing Python from typing import Any # Mengimpor fungsi create_engine dari SQLAlchemy untuk membuat engine penghubung ke database from sqlalchemy import create_engine # Mengimpor sessionmaker dari SQLAlchemy ORM untuk membuat factory pembentuk sesi transaksi database from sqlalchemy.orm import sessionmaker # Mengimpor objek konfigurasi global settings yang berisi DATABASE_URL from app.config.config import settings # Memeriksa apakah database yang digunakan adalah SQLite berdasarkan awalan protokol connection string is_sqlite = settings.DATABASE_URL.startswith("sqlite") # Jika database adalah SQLite, nonaktifkan check_same_thread agar session dapat digunakan lintas thread FastAPI; jika MySQL/PostgreSQL gunakan dictionary kosong connect_args = {"check_same_thread": False} if is_sqlite else {} # Menyiapkan dictionary parameter konfigurasi untuk SQLAlchemy engine engine_kwargs: dict[str, Any] = { # Argumen koneksi level driver (khusus SQLite atau kosong untuk MySQL) "connect_args": connect_args, # Menentukan apakah setiap query mentah dicetak ke terminal (False = dinonaktifkan demi performa dan kebersihan log) "echo": False, # Matikan SQL echo agar tidak memperlambat I/O console terminal } # Jika bukan SQLite (misal MySQL pada produksi atau pengembangan lokal), tambahkan konfigurasi connection pooling if not is_sqlite: engine_kwargs.update({ # pool_pre_ping: Memeriksa kesehatan koneksi sebelum query dijalankan untuk mencegah error koneksi mati (MySQL server has gone away) "pool_pre_ping": True, # pool_recycle: Mendaur ulang koneksi database setiap 1800 detik (30 menit) agar tidak diputus paksa oleh timeout server MySQL "pool_recycle": 1800, # pool_size: Jumlah koneksi database tetap yang dipertahankan dalam memory pool "pool_size": 15, # max_overflow: Jumlah koneksi tambahan maksimal yang diizinkan dibuat saat lalu lintas request sedang tinggi "max_overflow": 25, }) # Membuat instance Engine SQLAlchemy sebagai gerbang utama komunikasi antara aplikasi FastAPI dan server database engine = create_engine( # URL database (contoh: mysql+pymysql://root:@localhost:3306/tracerstudy_db) settings.DATABASE_URL, # Unpack dictionary argumen konfigurasi engine yang telah disesuaikan **engine_kwargs ) # Membuat class factory SessionLocal untuk menghasilkan sesi database baru pada setiap request # autocommit=False: Transaksi tidak langsung di-commit otomatis (memungkinkan commit/rollback manual demi konsistensi data) # autoflush=False: Mencegah perubahan di-flush ke database sebelum commit atau query eksplisit # bind=engine: Mengikat sesi ini ke engine database yang telah dibuat SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) # Fungsi Dependency Injection untuk FastAPI yang menyediakan sesi database ke setiap endpoint API def get_db(): """ Menghasilkan (yields) instance sesi database untuk satu request HTTP. Memastikan koneksi selalu ditutup (closed) di blok finally bahkan jika terjadi error selama eksekusi request. """ # Membuka sesi database baru dari factory SessionLocal db = SessionLocal() try: # Memberikan sesi database aktif ke controller/endpoint yang memanggilnya yield db finally: # Menutup sesi database setelah request selesai diproses agar koneksi dikembalikan ke connection pool dan tidak terjadi memory leak db.close()