# 06 - Repository Layer (`app/repositories/tenant_repository.py`)

Is document me hum `app/repositories/tenant_repository.py` file ko line-by-line samjhenge aur Repository Pattern ke benefits dekhenge.

---

## 1. What is the Repository Pattern? (The "WHY")

Software Architecture me **Repository Pattern** ka matlab hota hai: **"Database interactions ko API / Business Logic se completely isolate karna."**

### Without Repository Pattern:
Router handler me direct database query likhna:
```python
@router.post("/register")
async def register(tenant: TenantCreate):
    db = get_database()
    await db["tenants"].insert_one({...})  # Coupled directly to MongoDB
```

### With Repository Pattern:
Router repository function call karta hai:
```python
@router.post("/register")
async def register(tenant: TenantCreate):
    db = get_database()
    return await create_tenant(db, tenant)  # Clean abstraction!
```

### Advantages:
1. **Testability:** Mocking repository functions in unit tests is extremely easy.
2. **Maintainability:** Agar tomorrow MongoDB update hoti hai ya schema change hota hai, toh hume poore codebase me search karke update nahi karna padega, sirf single repository file change hogi.

---

## 2. Line-by-Line Code Breakdown of `tenant_repository.py`

Here is the exact code in `app/repositories/tenant_repository.py`:

```python
 1: import uuid
 2: from datetime import datetime, timezone
 3: from pymongo.asynchronous.database import AsyncDatabase
 4: from app.models.tenant import TenantCreate
 5: 
 6: async def create_tenant(db: AsyncDatabase, tenant_data: TenantCreate) -> dict:
 7:     site_id = f"site_{uuid.uuid4().hex[:12]}"
 8:     now = datetime.now(timezone.utc)
 9:     
10:     tenant_doc = {
11:         "siteId": site_id,
12:         "domain": tenant_data.domain,
13:         "name": tenant_data.name,
14:         "createdAt": now
15:     }
16:     
17:     await db["tenants"].insert_one(tenant_doc)
18:     return tenant_doc
19: 
20: async def get_tenant_by_site_id(db: AsyncDatabase, site_id: str) -> dict | None:
21:     return await db["tenants"].find_one({"siteId": site_id})
22: 
23: async def get_tenant_by_domain(db: AsyncDatabase, domain: str) -> dict | None:
24:     return await db["tenants"].find_one({"domain": domain})
```

---

### Line 6-18: `create_tenant()` Function

```python
async def create_tenant(db: AsyncDatabase, tenant_data: TenantCreate) -> dict:
    site_id = f"site_{uuid.uuid4().hex[:12]}"
    now = datetime.now(timezone.utc)
```
- **`uuid.uuid4().hex[:12]`:** Generates a random 12-character hex string.
- **`site_id` format:** `site_` + random string (e.g. `site_8f3a1b9c4d2e`).
- **`now = datetime.now(timezone.utc)`:** Generates UTC timezone timestamp. Always use UTC for servers to prevent timezone conversion issues across countries!

```python
    tenant_doc = {
        "siteId": site_id,
        "domain": tenant_data.domain,
        "name": tenant_data.name,
        "createdAt": now
    }
```
- MongoDB BSON document dictionary create karta hai.

```python
    await db["tenants"].insert_one(tenant_doc)
    return tenant_doc
```
- **`insert_one(tenant_doc)`:** PyMongo function jo `tenants` collection me single document insert karti hai.
- When `insert_one` executes, MongoDB automatically adds an `_id` field (ObjectId) to `tenant_doc`.
- `tenant_doc` (which now contains `siteId`, `domain`, `name`, `createdAt`, and `_id`) is returned back to the caller.

---

### Line 20-21: `get_tenant_by_site_id()` Function
```python
async def get_tenant_by_site_id(db: AsyncDatabase, site_id: str) -> dict | None:
    return await db["tenants"].find_one({"siteId": site_id})
```
- Searches `tenants` collection by key `"siteId"`. Returns document dict if found, or `None` if not found.

---

### Line 23-24: `get_tenant_by_domain()` Function
```python
async def get_tenant_by_domain(db: AsyncDatabase, domain: str) -> dict | None:
    return await db["tenants"].find_one({"domain": domain})
```
- Searches `tenants` collection by key `"domain"`. Used by the router to check if a domain has already been registered before inserting a new one.

---

## 3. What is a MongoDB Document & ObjectId?

- **Document:** MongoDB me data JSON / BSON format me store hota hai jise Document bolte hain.
- **ObjectId (`_id`):** MongoDB har inserted document ko ek 12-byte unique identifier `_id` automatically assign karta hai.
- **Why we use `siteId` alongside `_id`:** `_id` internal MongoDB key hai. We use `siteId` as the application-level public identifier for tenants because it has a clean format (`site_...`) and doesn't leak database implementation details.
