From ee209d1684815048e29897c51149ea5fe5f3e944 Mon Sep 17 00:00:00 2001 From: manvith Date: Mon, 3 Mar 2025 09:56:30 +0530 Subject: [PATCH] updated the code file --- .gitignore | 8 +++++ database.py | 2 +- main.py | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++- models.py | 4 +-- report.md | 76 ++++++++++++++++++++++++++++++++++++++++++++ schemas.py | 14 +++++++-- 6 files changed, 188 insertions(+), 7 deletions(-) create mode 100644 .gitignore create mode 100644 report.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a05a9e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +venv/ +.env + +test.db + +__pycache__/ +*.py[cod] +*.so \ No newline at end of file diff --git a/database.py b/database.py index accf2f5..7a22d80 100644 --- a/database.py +++ b/database.py @@ -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) diff --git a/main.py b/main.py index f83e868..86eb30a 100644 --- a/main.py +++ b/main.py @@ -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 @@ -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() @@ -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 + + diff --git a/models.py b/models.py index 0e42748..66f6aeb 100644 --- a/models.py +++ b/models.py @@ -1,4 +1,5 @@ from sqlalchemy import Column, Integer, String, ARRAY +from sqlalchemy.dialects.sqlite import JSON from database import Base class User(Base): @@ -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) diff --git a/report.md b/report.md new file mode 100644 index 0000000..a4eef89 --- /dev/null +++ b/report.md @@ -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 \ No newline at end of file diff --git a/schemas.py b/schemas.py index 5872710..92d5f70 100644 --- a/schemas.py +++ b/schemas.py @@ -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] @@ -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 \ No newline at end of file