Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
venv/
.env

test.db

__pycache__/
*.py[cod]
*.so
2 changes: 1 addition & 1 deletion database.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
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)
Expand Down
91 changes: 90 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from fastapi import FastAPI, HTTPException, Depends
from typing import List, Optional
from fastapi import FastAPI, HTTPException, Depends,Query
from sqlalchemy.orm import Session
from database import SessionLocal, engine, Base
import models, schemas
Expand All @@ -14,8 +15,14 @@ def get_db():
finally:
db.close()



@app.post("/users/", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_email = db.query(models.User).filter(models.User.email == user.email).first()
if db_email:
raise HTTPException(status_code=400, detail="Email already registered")

db_user = models.User(**user.dict())
db.add(db_user)
db.commit()
Expand All @@ -34,3 +41,85 @@ def read_user(user_id: int, db: Session = Depends(get_db)):
raise HTTPException(status_code=404, detail="User not found")
return user

@app.delete("/users/{user_id}",response_model=schemas.DeleteResponse)
def delete_user(user_id:int,db:Session=Depends(get_db)):
db_user=db.query(models.User).filter(models.User.id==user_id).first()
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")

db.delete(db_user)
db.commit()

return schemas.DeleteResponse(
status_code=200,
detail=f"Successfully deleted user { db_user.name}"
)



@app.put("/users/{user_id}", response_model=schemas.UpdateResponse)
def update_user(user_id: int, user: schemas.UserBase, db: Session = Depends(get_db)):
db_user = db.query(models.User).filter(models.User.id == user_id).first()
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")


if user.email and user.email != db_user.email:
email_exists = db.query(models.User).filter(models.User.email == user.email).first()
if email_exists:
raise HTTPException(status_code=400, detail="Email already registered")


update_data = user.dict(exclude_unset=True)
for key, value in update_data.items():
setattr(db_user, key, value)

db.commit()
db.refresh(db_user)


return schemas.UpdateResponse(
status_code=200,
content={"message": f"Successfully updated user {db_user.name}"}
)


@app.get("/matches", response_model=List[schemas.User])
def find_matches(
city: str = Query(..., description="City to match within"),
user_age: int = Query(..., ge=18, description="User's age to determine age range"),

age_range: int = Query(18, ge=0, description="Age range around user's age"),
preferred_gender: Optional[str] = Query(None, description="Preferred gender to filter by"),
interests: List[str] = Query(..., description="List of interests to match"),
db: Session = Depends(get_db)
) -> List[schemas.User]:

min_age = max(user_age - age_range, 18)
max_age = user_age + age_range


query = db.query(models.User).filter(
models.User.city == city,
models.User.age >= min_age,
models.User.age <= max_age
)


if preferred_gender:
query = query.filter(models.User.gender == preferred_gender)

potential_matches = query.all()


user_interests = set(interests)
matches = []
for person in potential_matches:
person_interests = set(person.interests or [])
if user_interests & person_interests:
matches.append(person)


return matches


4 changes: 2 additions & 2 deletions models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from sqlalchemy import Column, Integer, String, ARRAY
from sqlalchemy.dialects.sqlite import JSON
from database import Base

class User(Base):
Expand All @@ -10,5 +11,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)
76 changes: 76 additions & 0 deletions report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
Overview
This FastAPI-based system implements CRUD operations for user management and a matchmaking feature. It uses SQLAlchemy as the ORM and a PostgreSQL/MySQL database. The endpoints ensure data integrity, efficient querying, and optimal filtering mechanisms.

Endpoints Explanation:
1. Create User - POST /users/
Description
This endpoint allows the creation of a new user while ensuring the uniqueness of email addresses.

Implementation Details
The endpoint accepts a UserCreate schema (which contains user details).
It first checks if the email already exists in the database.
If an existing email is found, an HTTPException (status code 400) is raised.
Otherwise, the user data is inserted into the database.
The user object is committed and refreshed before returning the response.

2. Read Users - GET /users/
Description
Retrieves a paginated list of users.

Implementation Details
Uses query parameters skip (default: 0) and limit (default: 10) for pagination.
Queries the database with offset(skip).limit(limit).
Returns the list of users.

3. Read a Single User - GET /users/{user_id}
Description
Fetches details of a user by their ID.

Implementation Details
The endpoint receives user_id as a path parameter.
Queries the database for the user with the given ID.
If no user is found, it raises an HTTPException (404).
Returns the user object if found.


4. Delete User - DELETE /users/{user_id}
Description
Deletes a user from the database.

Implementation Details
Retrieves the user based on user_id.
If the user does not exist, an HTTPException (404) is raised.
If the user exists, they are deleted from the database.
Returns a success message in a structured response (schemas.DeleteResponse).



5. Update User - PUT /users/{user_id}
Description
Updates user details while ensuring email uniqueness.

Implementation Details
Retrieves the user by user_id.
If the user does not exist, an HTTPException (404) is raised.
If the email field is updated, it ensures the new email is not already registered.
Uses exclude_unset=True to update only the provided fields.
Updates the database and returns a success response.

6. Matchmaking API - GET /matches
Description
Finds users who match based on city, age range, gender, and interests.

Implementation Details
Filters users based on:
City (Exact match).
Age Range (Between user_age - age_range and user_age + age_range).
Preferred Gender (Optional filter).
Interests (Returns users with at least one matching interest).
Uses set intersection to determine if users share common interests.

RECORDER URL:
https://go.screenpal.com/watch/cTeefon1FWT


Conclusion
This implementation provides a scalable, efficient, and secure system for managing users and finding matches. Future improvements could include indexing for performance, caching, and advanced search algorithms
14 changes: 11 additions & 3 deletions schemas.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from pydantic import BaseModel
from pydantic import BaseModel, EmailStr, Field
from typing import List

class UserBase(BaseModel):
name: str
age: int
gender: str
email: str
email: EmailStr # Using EmailStr for validation
city: str
interests: List[str]

Expand All @@ -16,5 +16,13 @@ class User(UserBase):
id: int

class Config:
orm_mode = True
from_attributes = True


class DeleteResponse(BaseModel):
status_code: int
detail: str

class UpdateResponse(BaseModel):
status_code: int
content: dict