diff --git a/README.md b/README.md index 5571cfa..0845660 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ pip install -e . - String operations (`$contains`, `$startswith`, `$endswith`) - Regular expression matching - List membership testing (`$in`, `$nin`) +- Logical Operators (`$or`) ### 🔧 **Developer Friendly** - Verbose mode for debugging diff --git a/cafedb.py b/cafedb.py index f56b5ac..59d54af 100644 --- a/cafedb.py +++ b/cafedb.py @@ -113,19 +113,42 @@ def _match_condition(self, value: Any, condition: Union[Any, Dict[str, Any]]) -> else: return value == condition + def _build_condition_function(self, filters: Dict[str, Any]) -> Callable: + or_clause = filters.get('$or') + and_filters = {key: value for key, value in filters.items() if key != '$or'} + def condition_func(row: dict) -> bool: - for field, condition in filters.items(): + for field, condition in and_filters.items(): if field not in row: return False - if not self._match_condition(row[field], condition): return False - + + if or_clause: + if not isinstance(or_clause, list): + raise ValueError("$or operator requires a list of conditions.") + + or_match_found = False + for sub_filter in or_clause: + sub_filter_passes = True + for field, condition in sub_filter.items(): + if field not in row or not self._match_condition(row[field], condition): + sub_filter_passes = False + break + + if sub_filter_passes: + or_match_found = True + break + + if not or_match_found: + return False + return True return condition_func + def insert(self, table_name: str, row: dict): if table_name not in self._data: raise ValueError(f"Table '{table_name}' does not exist.") @@ -307,6 +330,16 @@ def stats(self, table_name: str): {"age": {"$gte": 45}}, {"category": "senior", "discount": 0.1} ) + print("\n8. Users from London who are either young or high-scorers:") + results = db.select("users", { + "city": "London", + "$or": [ + {"age": {"$lt": 30}}, + {"score": {"$gte": 85}} + ] + }) + for user in results: + print(f" - {user['name']} (Age: {user['age']}, Score: {user['score']})") print("\n=== TABLE STATISTICS ===") stats = db.stats("users") @@ -314,4 +347,4 @@ def stats(self, table_name: str): print(f"Total rows: {stats['total_rows']}") print("Fields:") for field, info in stats['fields'].items(): - print(f" {field}: {info['present_count']} present, {info['unique_count']} unique, types: {info['data_types']}") \ No newline at end of file + print(f" {field}: {info['present_count']} present, {info['unique_count']} unique, types: {info['data_types']}") diff --git a/usage.py b/usage.py index 7c6e4fc..8b88d10 100644 --- a/usage.py +++ b/usage.py @@ -1,84 +1,204 @@ from cafedb import CafeDB from datetime import datetime +import uuid +import os -# Initialize database -db = CafeDB("user_management.cdb", verbose=True) -db.create_table("users") -db.create_table("sessions") - -# User registration -def register_user(name, email, age, city): - # Check if user already exists - existing = db.select("users", {"email": email}) - if existing: - raise ValueError("User with this email already exists") - - user = { +db = CafeDB("student_grades.cdb", verbose=False) + +def clear_screen(): + """Clears the terminal screen.""" + os.system('cls' if os.name == 'nt' else 'clear') + +def print_header(title): + """Prints a formatted header.""" + print("=" * 40) + print(f"| {title.center(36)} |") + print("=" * 40) + +def press_enter_to_continue(): + """Pauses execution until the user presses Enter.""" + input("\nPress Enter to continue...") + +def setup_database(): + """Creates the necessary tables if they don't exist.""" + try: + db.create_table("students") + except ValueError: + pass + + try: + db.create_table("grades") + except ValueError: + pass + +def add_student_cli(): + """CLI function to add a new student.""" + print_header("Add New Student") + name = input("Enter student's full name: ") + email = input("Enter student's email: ") + while db.select("students", {"email": email}): + print("A student with this email already exists.") + email = input("Enter a different email: ") + + try: + enrollment_year = int(input("Enter enrollment year: ")) + except ValueError: + print("Invalid year. Please enter a number.") + return + + student = { + "student_id": str(uuid.uuid4())[:8], "name": name, "email": email, - "age": age, - "city": city, - "created_at": datetime.now().isoformat(), - "active": True, - "login_count": 0 + "enrollment_year": enrollment_year, + "created_at": datetime.now().isoformat() } - - db.insert("users", user) - return user - -# User authentication simulation -def login_user(email): - users = db.select("users", {"email": email, "active": True}) - if not users: - raise ValueError("User not found or inactive") - - user = users[0] - - # Update login count - db.update("users", - {"email": email}, - lambda u: {**u, "login_count": u.get("login_count", 0) + 1, - "last_login": datetime.now().isoformat()} - ) - - # Create session - session = { - "email": email, - "login_time": datetime.now().isoformat(), - "active": True - } - db.insert("sessions", session) - - return user - -# Analytics -def get_user_analytics(): - total_users = db.count("users") - active_users = db.count("users", {"active": True}) - recent_users = db.count("users", { - "created_at": {"$gte": "2024-01-01T00:00:00Z"} - }) - - # Most common cities - all_users = db.select("users") - city_count = {} - for user in all_users: - city = user.get("city", "Unknown") - city_count[city] = city_count.get(city, 0) + 1 - - return { - "total_users": total_users, - "active_users": active_users, - "recent_users": recent_users, - "cities": dict(sorted(city_count.items(), key=lambda x: x[1], reverse=True)) + db.insert("students", student) + print(f"\n Student '{name}' added successfully with ID: {student['student_id']}") + +def record_grade_cli(): + """CLI function to record a new grade.""" + print_header("Record a Grade") + student_id = input("Enter the student ID to record a grade for: ") + if not db.select("students", {"student_id": student_id}): + print(f" Error: Student with ID '{student_id}' not found.") + return + + subject = input("Enter the subject (e.g., Math, Science): ") + try: + score = float(input("Enter the score: ")) + if not 0 <= score <= 100: + raise ValueError("Score must be between 0 and 100.") + except ValueError as e: + print(f" Invalid score. {e}") + return + + grade = { + "grade_id": str(uuid.uuid4())[:8], + "student_id": student_id, + "subject": subject, + "score": score, + "date": datetime.now().date().isoformat() } + db.insert("grades", grade) + print(f"\n Grade of {score} in {subject} recorded for student {student_id}.") + +def view_student_grades_cli(): + """CLI function to view all grades for a specific student.""" + print_header("View Student Grades") + student_id = input("Enter the student ID: ") + student = db.select("students", {"student_id": student_id}) + if not student: + print(f" Error: Student with ID '{student_id}' not found.") + return + + grades = db.select("grades", {"student_id": student_id}) + print(f"\nGrades for {student[0]['name']} ({student_id}):") + if not grades: + print("No grades found for this student.") + else: + for grade in grades: + print(f" - Subject: {grade['subject']}, Score: {grade['score']}, Date: {grade['date']}") + +def find_top_performers_cli(): + """CLI function to find top performers in a subject.""" + print_header("Find Top Performers") + subject = input("Enter the subject to search in: ") + try: + min_score = float(input("Enter the minimum score to be considered a top performer (e.g., 90): ")) + except ValueError: + print(" Invalid score.") + return + + results = db.select("grades", {"subject": subject, "score": {"$gte": min_score}}) + print(f"\nTop Performers in {subject} (Score >= {min_score}):") + if not results: + print("No students met the criteria.") + else: + for grade in results: + student = db.select("students", {"student_id": grade['student_id']}) + if student: + print(f" - Student: {student[0]['name']}, Score: {grade['score']}") + +def list_all_students_cli(): + """Lists all students in the database.""" + print_header("All Students") + students = db.select("students") + if not students: + print("No students in the database.") + else: + for student in students: + print(f" - Name: {student['name']}, Email: {student['email']}, ID: {student['student_id']}") + +def delete_student_cli(): + """CLI function to delete a student.""" + print_header("Delete a Student") + student_id = input("Enter the ID of the student to delete: ") + student = db.select("students", {"student_id": student_id}) + if not student: + print(f" Error: Student with ID '{student_id}' not found.") + return + + confirm = input(f"Are you sure you want to delete {student[0]['name']} and all their grades? (y/n): ").lower() + if confirm == 'y': + db.delete("students", {"student_id": student_id}) + db.delete("grades", {"student_id": student_id}) + print(f" Student {student_id} has been deleted.") + else: + print("Deletion cancelled.") + +def get_database_stats_cli(): + """Displays statistics for all tables.""" + print_header("Database Statistics") + for table_name in db.list_tables(): + stats = db.stats(table_name) + print(f"\n--- Table: {stats['table']} ---") + print(f" Total Rows: {stats['total_rows']}") + if "fields" in stats and stats['fields']: + print(" Fields:") + for field, info in stats['fields'].items(): + print(f" - {field}: Present: {info['present_count']}, Unique: {info['unique_count']}") + else: + print(" No fields or data in this table.") + +def main_menu(): + """Displays the main menu and handles user input.""" + while True: + clear_screen() + print_header("Student Gradebook CLI") + print("1. Add New Student") + print("2. Record a Grade") + print("3. View a Student's Grades") + print("4. Find Top Performers in a Subject") + print("5. List All Students") + print("6. Delete a Student") + print("7. View Database Statistics") + print("0. Exit") + print("-" * 40) + choice = input("Enter your choice: ") -# Usage -register_user("Alice Johnson", "alice@example.com", 28, "Paris") -register_user("Bob Smith", "bob@example.com", 34, "London") + if choice == '1': + add_student_cli() + elif choice == '2': + record_grade_cli() + elif choice == '3': + view_student_grades_cli() + elif choice == '4': + find_top_performers_cli() + elif choice == '5': + list_all_students_cli() + elif choice == '6': + delete_student_cli() + elif choice == '7': + get_database_stats_cli() + elif choice == '0': + print("Goodbye!") + break + else: + print(" Invalid choice. Please try again.") -user = login_user("alice@example.com") -print(f"Welcome back, {user['name']}!") + press_enter_to_continue() -analytics = get_user_analytics() -print(f"Analytics: {analytics}") +if __name__ == "__main__": + setup_database() + main_menu()