# 04 - MongoDB Database Layer (`app/database.py`)

Is document me hum `app/database.py` file ko line-by-line samjhenge aur sikhenge ki MongoDB Async connection kaise work karta hai.

---

## 1. Important Database Concepts for Beginners

Before jumping into the code, let's clarify key terminology:

1. **MongoDB Client (`AsyncMongoClient`):**
   - Application aur MongoDB Server ke beech ki main network pipeline/connector object.
2. **Database:**
   - Data containers ka group (Humara database name: `chatbot_db`).
3. **Collection:**
   - Database ke andar individual tables/groups (Humari primary collection for M1.1: `tenants`).
4. **Document:**
   - JSON-like BSON record jo collection me store hota hai (Har tenant registration ek document hai).
5. **Why Asynchronous (`AsyncMongoClient`)?**
   - Traditional synchronous database calls execution thread ko freeze kar dete hain jab tak database disk read/write complete na kar le.
   - `AsyncMongoClient` (introduced natively in PyMongo 4.7+) allows FastAPI to handle thousands of concurrent client requests while waiting for MongoDB network I/O.

---

## 2. Line-by-Line Code Breakdown of `app/database.py`

Here is the exact implementation in `app/database.py`:

```python
 1: import certifi
 2: from pymongo import AsyncMongoClient
 3: from app.config import settings
 4: 
 5: class Database:
 6:     client: AsyncMongoClient | None = None
 7: 
 8: db_helper = Database()
 9: 
10: def get_database():
11:     if db_helper.client is None:
12:         db_helper.client = AsyncMongoClient(
13:             settings.mongodb_uri,
14:             tlsCAFile=certifi.where(),
15:         )
16:     return db_helper.client[settings.database_name]
17: 
18: def close_database():
19:     if db_helper.client is not None:
20:         db_helper.client.close()
21:         db_helper.client = None
```

---

### Line 1-3: Imports
```python
import certifi
from pymongo import AsyncMongoClient
from app.config import settings
```
- **`certifi`:** Mozilla ka curated SSL/TLS Root Certificates package.
- **`AsyncMongoClient`:** PyMongo ka asynchronous database client driver.
- **`settings`:** `app/config.py` se load hone wala configuration object.

---

### Line 5-8: `Database` Helper Class & Singleton Instance
```python
class Database:
    client: AsyncMongoClient | None = None

db_helper = Database()
```
- **`client: AsyncMongoClient | None = None`:** Starting me client connection open nahi hota (`None`).
- **`db_helper = Database()`:** Ek global instance (`db_helper`) create karta hai jo Client reference ko hold karta hai. Is pattern se application re-use kar pati hai ek single client pipeline (Connection Pooling).

---

### Line 10-16: `get_database()` Function
```python
def get_database():
    if db_helper.client is None:
        db_helper.client = AsyncMongoClient(
            settings.mongodb_uri,
            tlsCAFile=certifi.where(),
        )
    return db_helper.client[settings.database_name]
```
- **Lazy Initialization (`if db_helper.client is None`):** Pehli baar jab kisi API call ko database ki zaroorat hoti hai, tabhi `AsyncMongoClient` connect karta hai.
- **Why `tlsCAFile=certifi.where()`?**
  MongoDB Atlas (Cloud database) mandatory SSL/TLS encryption enforce karta hai. Windows ya Python environments me default OS SSL certificates out-of-date hone ki waja se `SSL: CERTIFICATE_VERIFY_FAILED` error aata hai. `certifi.where()` secure and updated CA certificates pass karta hai.
- **`return db_helper.client[settings.database_name]`:** Specified database (e.g. `chatbot_db`) object return kar deta hai.

---

### Line 18-21: `close_database()` Function
```python
def close_database():
    if db_helper.client is not None:
        db_helper.client.close()
        db_helper.client = None
```
- **Clean Shutdown:** Jab FastAPI server stop ya restart hota hai, `close_database()` open sockets aur database connections ko safely close karke memory leak hone se bachata hai.

---

## 3. Data Connection Architecture Summary

```text
[FastAPI Router]
       │ calls get_database()
       ▼
[app/database.py]
  - Checks db_helper.client
  - If None -> Creates AsyncMongoClient(mongodb_uri, tlsCAFile=certifi.where())
  - Returns database object: client["chatbot_db"]
```
