diff --git a/__pycache__/database.cpython-311.pyc b/__pycache__/database.cpython-311.pyc new file mode 100644 index 0000000..26ea935 Binary files /dev/null and b/__pycache__/database.cpython-311.pyc differ diff --git a/__pycache__/main.cpython-311.pyc b/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000..1e6bdf1 Binary files /dev/null and b/__pycache__/main.cpython-311.pyc differ diff --git a/__pycache__/models.cpython-311.pyc b/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000..abec11b Binary files /dev/null and b/__pycache__/models.cpython-311.pyc differ diff --git a/__pycache__/schemas.cpython-311.pyc b/__pycache__/schemas.cpython-311.pyc new file mode 100644 index 0000000..2a85b88 Binary files /dev/null and b/__pycache__/schemas.cpython-311.pyc differ diff --git a/database.py b/database.py index accf2f5..7d45777 100644 --- a/database.py +++ b/database.py @@ -2,10 +2,10 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker -// Free to use remote db or create a local database. Modify the URl appropriately +# Free to use remote db or create a local database. Modify the URl appropriately SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" -engine = create_engine(SQLALCHEMY_DATABASE_URL) +engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() diff --git a/main.py b/main.py index f83e868..585f3bf 100644 --- a/main.py +++ b/main.py @@ -2,7 +2,8 @@ from sqlalchemy.orm import Session from database import SessionLocal, engine, Base import models, schemas - +import json +from sqlalchemy import text app = FastAPI() Base.metadata.create_all(bind=engine) @@ -34,3 +35,69 @@ def read_user(user_id: int, db: Session = Depends(get_db)): raise HTTPException(status_code=404, detail="User not found") return user +# this is a update user endpoint +@app.patch("/users/{user_id}", response_model=schemas.User) +def update_user(user_id: int, user_data: schemas.UserUpdate, db: Session = Depends(get_db)): + user = db.query(models.User).filter(models.User.id == user_id).first() + if not user: + raise HTTPException(status_code=404, detail="User not found") + + update_data = user_data.dict(exclude_unset=True) + for key, value in update_data.items(): + setattr(user, key, value) + + db.commit() + db.refresh(user) + return user + + +# this is a delete user endpoint +@app.delete("/users/{user_id}", response_model=dict) +def delete_user(user_id: int, db: Session = Depends(get_db)): + user = db.query(models.User).filter(models.User.id == user_id).first() + if not user: + raise HTTPException(status_code=404, detail="User not found") + db.delete(user) + db.commit() + return {"detail": "User deleted"} + +# this is a find matches for a user endpoint +@app.get("/users/{user_id}/matches", response_model=list[schemas.User]) +def find_matches(user_id: int, db: Session = Depends(get_db)): + # Retrieve the given user's profile + user = db.query(models.User).filter(models.User.id == user_id).first() + if not user: + raise HTTPException(status_code=404, detail="User not found") + matches = [] + # Retrieve all other users + all_users = db.query(models.User).filter(models.User.id != user_id).all() + for other in all_users: + # If there's at least one common interest, consider it a match + if set(user.interests).intersection(set(other.interests)): + matches.append(other) + return matches + +# this is a upgraded matchmaking endpoint that returns a match score 😅 +@app.get("/users/{user_id}/matches_score", response_model=list[schemas.UserMatch]) +def find_matches_score(user_id: int, db: Session = Depends(get_db)): + user = db.query(models.User).filter(models.User.id == user_id).first() + if not user: + raise HTTPException(status_code=404, detail="User not found") + + matches = [] + all_users = db.query(models.User).filter(models.User.id != user_id).all() + for other in all_users: + # here we are calculating common interests score + common_interests = set(user.interests).intersection(set(other.interests)) + score = len(common_interests) + # here we are adding bonus if both users are in the same city + if user.city.lower() == other.city.lower(): + score += 1 + + # Only consider matches with a score greater than 0 + if score > 0: + matches.append({"user": other, "match_score": score}) + + # Sort matches by score in descending order + matches.sort(key=lambda x: x["match_score"], reverse=True) + return matches diff --git a/models.py b/models.py index 0e42748..0a010f6 100644 --- a/models.py +++ b/models.py @@ -1,6 +1,6 @@ -from sqlalchemy import Column, Integer, String, ARRAY +from sqlalchemy import Column, Integer, String from database import Base - +from sqlalchemy.dialects.sqlite import JSON class User(Base): __tablename__ = "users" @@ -10,5 +10,4 @@ class User(Base): gender = Column(String) email = Column(String, unique=True, index=True) city = Column(String, index=True) - interests = Column(ARRAY(String)) - + interests = Column(JSON) diff --git a/schemas.py b/schemas.py index 5872710..3f675b6 100644 --- a/schemas.py +++ b/schemas.py @@ -1,20 +1,32 @@ -from pydantic import BaseModel -from typing import List +from pydantic import BaseModel, EmailStr +from typing import List, Optional class UserBase(BaseModel): name: str age: int gender: str - email: str + email: EmailStr # EmailStr validates email itself (i dont need to write a custom validator) city: str interests: List[str] class UserCreate(UserBase): pass +class UserUpdate(BaseModel): + name: Optional[str] = None + age: Optional[int] = None + gender: Optional[str] = None + email: Optional[EmailStr] = None + city: Optional[str] = None + interests: Optional[List[str]] = None + class User(UserBase): id: int class Config: orm_mode = True +class UserMatch(BaseModel): + user: User + match_score: float + diff --git a/test.db b/test.db new file mode 100644 index 0000000..1a2185b Binary files /dev/null and b/test.db differ