Repository: Altmerian/learn-python
Pull request #2: Data Types
Author: login: Altmerian
Labels: name: Review effort 4/5
Created: 2025-03-28T21:16:18Z | Merged: 2025-03-28T21:31:14Z

### **PR Type**
- Enhancement



___

### **Description**
- Add queuing modules for barbershop and canteen

- Introduce billing, sorting and duplicate detection functions

- Implement inventory updates and common words analysis

- Establish SQLite database setup, queries, and updates


___



### **Changes walkthrough** 📝
<table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>14 files</summary><table>
<tr>
  <td><strong>barber_queue.py</strong><dd><code>Introduces barbershop queue management class</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-c6333140809903abfa64c72f0cb651f90ce55a670c6dbd47dc4331b33a1cf5f4">+27/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>bill_generator.py</strong><dd><code>Creates bill generator with formatted receipt output</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-aa7979bb684051cbc7a30423bbfbb523ef21510b009998d43d4167663d16d579">+44/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>canteen_queue.py</strong><dd><code>Implements queueing logic for canteen service</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-8fa10ab6a95855d3b3f022606b927ebb341c598dc4e8fc042f61ef3135030012">+24/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>common_words.py</strong><dd><code>Provides common words analysis from text input</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-9766f3fc544820b7acabba417650d2669a2c4d8473a4616319e0de9ade7d3971">+18/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>first_duplicate.py</strong><dd><code>Optimizes duplicate detection in number array</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-93f290b6da78aa78de7cf182b54c193c566d5ce844a7bcf9bd29a96a86dac52b">+17/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>heap_sort.py</strong><dd><code>Implements heap sort algorithm functions</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-c8ccd91430562ef2731e897f6ef3d62dc1d732b1548cf4be67c861ab4c83145d">+22/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>insertion_sort.py</strong><dd><code>Implements insertion sort using bisect module</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-8752304b20bb0ee3dc45fc82215fabb667545ec25d0f2d5058b8d181c86de87e">+15/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>inventory.py</strong><dd><code>Manages inventory updates using Counter subtraction</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-512fefbd85f40f3d3b9135e4a4366ccc6892922657639d574b82dcb680787c29">+19/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>missing_number.py</strong><dd><code>Finds missing numbers in a sequence array</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-f3cea7782a684b6ccc1e529a95ddd5ddf1a99f3c86ce4b1644d47b2fce0f1713">+15/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>create_db.py</strong><dd><code>Creates university database tables for departments and students</code></dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-c62b49831055294f02f1b3b6210ab4f66bce38e42923f2e8058472185160d996">+24/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>insert.py</strong><dd><code>Inserts department and student records into database</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-7f7d73dc5ec025c11d94c1f90d1fd2449ed117ec0d0c20293090e7b5e61669a6">+51/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>query.py</strong><dd><code>Performs various queries on university database</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-280f397ae42668fa012eb6d1b8ff782e8efc3a5c0da986a3b624be5e51b9f63a">+49/-0</a>&nbsp; &nbsp; </td>

</tr>

<tr>
  <td><strong>shop.py</strong><dd><code>Sets up shop database with tables and SQL queries</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-ca6dfa5091c0984a66a35578603de86dc52618539cec4aff29951b67bb1e9afd">+162/-0</a>&nbsp; </td>

</tr>

<tr>
  <td><strong>update_delete.py</strong><dd><code>Updates departments and deletes records in database</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-044cbe20ff961d448f2afe95000995b1ce9d2f2350da6d414eb19bad252d43c8">+15/-0</a>&nbsp; &nbsp; </td>

</tr>
</table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>1 files</summary><table>
<tr>
  <td><strong>sample_text.txt</strong><dd><code>Provides sample text for word analysis testing</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td>
  <td><a href="https://github.com/Altmerian/learn-python/pull/2/files#diff-4fc58d73618f8602149d5c0874beadce8225b0b505e974cdddec431cb74ccfc9">+5/-0</a>&nbsp; &nbsp; &nbsp; </td>

</tr>
</table></details></td></tr></tr></tbody></table>

___

> <details> <summary>  Need help?</summary><li>Type <code>/help how to ...</code> in the comments thread for any questions about PR-Agent usage.</li><li>Check out the <a href="https://qodo-merge-docs.qodo.ai/usage-guide/">documentation</a> for more information.</li></details>


Diff:
diff --git a/README.md b/README.md
index e4507b3..9d1e1a9 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@ This repository contains examples and exercises covering fundamental Python prog
 learn-python/
 ├── classes/           # Object-oriented programming examples
 ├── cond_statements/   # Conditional statements examples
+├── data_types/        # Data structures and algorithms implementations
 ├── date_time/         # Date and time manipulation examples
 ├── dictionaries/      # Dictionary data structure examples
 ├── exceptions/        # Exception handling examples
@@ -58,6 +59,10 @@ learn-python/
   - Inheritance
   - Polymorphism
   - Abstraction
+- Algorithms and Data Structures
+  - Sorting Algorithms (Heap Sort, Insertion Sort)
+  - Queue Implementations
+  - Problem Solving Algorithms
 - Date and Time Operations
 - Concurrent Programming with Threads
 - File Operations
diff --git a/data_types/barber_queue.py b/data_types/barber_queue.py
new file mode 100644
index 0000000..baddf91
--- /dev/null
+++ b/data_types/barber_queue.py
@@ -0,0 +1,27 @@
+from collections import deque
+
+class BarberQueue:
+    def __init__(self):
+        self.queue = deque()
+
+    def walk_in(self, customer: str):
+        self.queue.append(customer)
+
+    def service_customer(self) -> str:
+        return self.queue.popleft()
+    
+    def __str__(self) -> str:
+        return f"Barbershop queue: {list(self.queue)}"
+    
+if __name__ == "__main__":
+    barber_queue = BarberQueue()
+    barber_queue.walk_in("John")
+    barber_queue.walk_in("Jane")
+    barber_queue.walk_in("Jim")
+    print(barber_queue)
+    print(barber_queue.service_customer())
+    print(barber_queue)
+    barber_queue.walk_in("Jill")
+    print(barber_queue)
+    print(barber_queue.service_customer())
+    print(barber_queue)
diff --git a/data_types/bill_generator.py b/data_types/bill_generator.py
new file mode 100644
index 0000000..75c7860
--- /dev/null
+++ b/data_types/bill_generator.py
@@ -0,0 +1,44 @@
+from collections import Counter
+
+
+class BillGenerator:
+    def __init__(self, price_list: dict):
+        self.price_list = price_list
+
+    def generate_bill(self, order: dict[str, int]) -> str:
+        # Header for the bill
+        bill = "BILL\n"
+        bill += "=" * 50 + "\n"
+        bill += f"{'Product':<20}{'Price':^10}{'Quantity':^10}{'Subtotal':>10}\n"
+        bill += "-" * 50 + "\n"
+
+        total = 0.0
+
+        # Add each product to the bill
+        for product, quantity in order.items():
+            if product in self.price_list:
+                price = self.price_list[product]
+                subtotal = price * quantity
+                total += subtotal
+
+                bill += f"{product:<20}{price:^10.2f}{quantity:^10}{subtotal:>10.2f}\n"
+            else:
+                bill += f"{product:<20}{'N/A':^10}{quantity:^10}{'N/A':>10}\n"
+
+        # Add the total
+        bill += "-" * 50 + "\n"
+        bill += f"{'TOTAL':<40}{total:>10.2f}\n"
+        bill += "=" * 50 + "\n"
+
+        return bill
+
+
+if __name__ == "__main__":
+    price_list = {"Soap": 10.5, "Shampoo": 20.0, "Conditioner": 30.15, "Lotion": 40.05}
+    bill_generator = BillGenerator(price_list)
+    order = {"Soap": 2, "Shampoo": 1, "Conditioner": 3, "Lotion": 2}
+    print(bill_generator.generate_bill(order))
+
+    # Test with a product not in the price list
+    order = {"Soap": 2, "Shampoo": 1, "Conditioner": 3, "Lotion": 2, "Pen": 1}
+    print(bill_generator.generate_bill(order))
diff --git a/data_types/canteen_queue.py b/data_types/canteen_queue.py
new file mode 100644
index 0000000..de58bdd
--- /dev/null
+++ b/data_types/canteen_queue.py
@@ -0,0 +1,24 @@
+from collections import deque
+
+
+class CanteenQueue:
+    def __init__(self, students: list[str]):
+        self.queue = deque(students)
+
+    def serve_student(self):
+        print(f"Students are served in order: {self.queue}")
+        self.queue.rotate(-1)
+
+    def __str__(self) -> str:
+        return f"Canteen queue: {list(self.queue)}"
+
+
+if __name__ == "__main__":
+    students = ["Alice", "Bob", "Charlie", "David", "Eve"]
+    canteen_queue = CanteenQueue(students)
+    print("Breakfast time!")
+    canteen_queue.serve_student()
+    print("Lunch time!")
+    canteen_queue.serve_student()
+    print("Dinner time!")
+    canteen_queue.serve_student()
diff --git a/data_types/common_words.py b/data_types/common_words.py
new file mode 100644
index 0000000..2534d52
--- /dev/null
+++ b/data_types/common_words.py
@@ -0,0 +1,18 @@
+from collections import Counter
+import os
+import re
+
+def get_common_words(text: str, n: int = 1) -> list[tuple[str, int]]:
+    words = re.findall(r'[a-zA-Z0-9]+', text.lower())
+    word_counts = Counter(w for w in words if len(w) > 2)
+    return word_counts.most_common(n)
+
+
+if __name__ == "__main__":
+    current_dir = os.path.dirname(os.path.abspath(__file__))
+    text_file_path = os.path.join(current_dir, "sample_text.txt")
+    
+    with open(text_file_path, 'r') as file:
+        text = file.read()
+    
+    print(get_common_words(text, 3))
diff --git a/data_types/first_duplicate.py b/data_types/first_duplicate.py
new file mode 100644
index 0000000..b79230a
--- /dev/null
+++ b/data_types/first_duplicate.py
@@ -0,0 +1,17 @@
+from array import array
+
+
+def find_first_duplicate(numbers: array) -> int:
+    seen = set()
+    for n in numbers:
+        if n in seen:
+            return n
+        seen.add(n)
+    return -1
+
+
+if __name__ == "__main__":
+    numbers = array("i", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 2, 1, 3, 4, 5])
+    print(find_first_duplicate(numbers))  # Output: 2
+    numbers = array("i", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+    print(find_first_duplicate(numbers))  # Output: -1
diff --git a/data_types/heap_sort.py b/data_types/heap_sort.py
new file mode 100644
index 0000000..78b178b
--- /dev/null
+++ b/data_types/heap_sort.py
@@ -0,0 +1,22 @@
+import heapq
+from array import array
+from typing import Any
+
+
+def heap_sort(elements):
+    elements_copy = elements.copy()
+    heapq.heapify(elements_copy)
+    return [heapq.heappop(elements_copy) for _ in range(len(elements_copy))]
+
+
+def heap_sort_array(arr: array[Any]) -> array[Any]:
+    elements = list(arr)
+    return array(arr.typecode, heap_sort(elements))
+
+
+if __name__ == "__main__":
+    elements = [9, 3, 7, 1, 5, 10, 8, 4, 6]
+    print(heap_sort(elements))
+
+    arr = array("i", [4, 5, 2, 1, 54, 34, 2, -2])
+    print(heap_sort_array(arr).tolist())
diff --git a/data_types/insertion_sort.py b/data_types/insertion_sort.py
new file mode 100644
index 0000000..ea2b4ed
--- /dev/null
+++ b/data_types/insertion_sort.py
@@ -0,0 +1,15 @@
+import bisect
+from typing import Any
+
+
+def insertion_sort(elements: list[Any]) -> list[Any]:
+    result = []
+    for i in range(0, len(elements)):
+        key = elements[i]
+        bisect.insort(result, key)
+    return result
+
+
+if __name__ == "__main__":
+    elements = [9, 3, 7, 1, 5, 10, 8, 4, 6]
+    print(insertion_sort(elements))
diff --git a/data_types/inventory.py b/data_types/inventory.py
new file mode 100644
index 0000000..0406295
--- /dev/null
+++ b/data_types/inventory.py
@@ -0,0 +1,19 @@
+from collections import Counter
+
+
+class Inventory:
+    def __init__(self, items: dict[str, int]):
+        self.items = items
+
+    def update_inventory(self, order: dict[str, int]) -> None:
+        self.items = Counter(self.items) - Counter(order)
+    
+    def __str__(self) -> str:
+        return f"Inventory: {dict(self.items)}"
+    
+if __name__ == "__main__":
+    inventory = Inventory({"apple": 50, "mango": 100, "banana": 120, "orange": 70})
+    print(inventory)
+    inventory.update_inventory({"apple": 10, "mango": 12, "banana": 15, "orange": 5})
+    print(inventory)
+
diff --git a/data_types/missing_number.py b/data_types/missing_number.py
new file mode 100644
index 0000000..f8803cd
--- /dev/null
+++ b/data_types/missing_number.py
@@ -0,0 +1,15 @@
+from array import array
+
+
+def find_missing_number(numbers: array) -> int:
+    missing_number = sum(range(numbers[0], numbers[-1] + 1)) - sum(numbers)
+    return missing_number if missing_number != 0 else -1
+
+
+if __name__ == "__main__":
+    numbers = array("i", [1, 2, 3, 4, 5, 6, 7, 8, 10])
+    print(f"Missing number: {find_missing_number(numbers)}")
+    numbers = array("i", [11, 12, 13, 14, 16, 17, 18, 19, 20])
+    print(f"Missing number: {find_missing_number(numbers)}")
+    numbers = array("i", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+    print(f"Missing number: {find_missing_number(numbers)}")
diff --git a/data_types/sample_text.txt b/data_types/sample_text.txt
new file mode 100644
index 0000000..1a20e73
--- /dev/null
+++ b/data_types/sample_text.txt
@@ -0,0 +1,5 @@
+Python is an easy programmers language. 
+Python syntax is like the English language. 
+Python language is easy to learn and adapt compared to Java and C. 
+In Python language the same task can be performed using fewer lines of code. 
+It's easy learning and easy to code. 
\ No newline at end of file
diff --git a/database/create_db.py b/database/create_db.py
new file mode 100644
index 0000000..67192fc
--- /dev/null
+++ b/database/create_db.py
@@ -0,0 +1,24 @@
+import sqlite3
+
+
+with sqlite3.connect("university.db") as conn:
+    cursor = conn.cursor()
+    cursor.execute(
+        """
+        CREATE TABLE IF NOT EXISTS Departments (
+            depno INTEGER PRIMARY KEY, 
+            name TEXT NOT NULL
+        );
+        """
+    )
+    cursor.execute(
+        """
+        CREATE TABLE IF NOT EXISTS Students (
+            roll INTEGER PRIMARY KEY, 
+            name TEXT NOT NULL, 
+            city TEXT, 
+            depno INTEGER, 
+            FOREIGN KEY (depno) REFERENCES Departments(depno)
+        );
+        """
+    )
diff --git a/database/insert.py b/database/insert.py
new file mode 100644
index 0000000..78aa0a8
--- /dev/null
+++ b/database/insert.py
@@ -0,0 +1,51 @@
+import sqlite3
+
+
+departments = [
+    (10, "CSE"),
+    (20, "ECE"),
+    (30, "Civil"),
+    (40, "Mech"),
+]
+
+students = [
+    (1, "Ajay", "Delhi", 10),
+    (2, "Vijay", "Kolkata", 10),
+    (3, "Ajay", "Mumbai", 20),
+    (4, "Ramesh", "Delhi", 30),
+    (5, "Suneeta", "Lucknow", 40),
+    (6, "Anita", "Kolkata", 30),
+    (7, "Raj", "Jaipur", 30),
+    (8, "Ali", "Lucknow", 40),
+    (9, "Michael", "Cochin", 10),
+    (10, "Pavan", "Vijaywada", 20),
+    (11, "Suraj", "Hyderabad", 10),
+    (12, "Altaf", "Bangaluru", 40),
+    (13, "Ravi", "Indore", 20),
+    (14, "Verma", "Delhi", 20),
+    (15, "Sharma", "Vizag", 10),
+]
+
+with sqlite3.connect("university.db") as conn:
+    cursor = conn.cursor()
+
+    # Insert departments data
+    cursor.executemany(
+        """
+        INSERT OR REPLACE INTO Departments (depno, name)
+        VALUES (?, ?);
+        """,
+        departments,
+    )
+
+    # Insert students data
+    cursor.executemany(
+        """
+        INSERT OR REPLACE INTO Students (roll, name, city, depno)
+        VALUES (?, ?, ?, ?);
+        """,
+        students,
+    )
+
+print(f"{len(departments)} department records inserted.")
+print(f"{len(students)} student records inserted.")
diff --git a/database/query.py b/database/query.py
new file mode 100644
index 0000000..f635e6a
--- /dev/null
+++ b/database/query.py
@@ -0,0 +1,49 @@
+import sqlite3
+
+
+with sqlite3.connect("university.db") as conn:
+    cursor = conn.cursor()
+
+    cursor.execute("SELECT * FROM Students")
+    print(cursor.fetchone(), end="\n\n")
+    print(cursor.fetchmany(4), end="\n\n")
+    print(cursor.fetchall(), end="\n\n")
+
+    cursor.execute("SELECT DISTINCT name FROM Students")
+    for row in cursor:
+        print(row[0])
+    print()
+
+    cursor.execute("SELECT name FROM Students WHERE name like 'a%'")
+    print([t[0] for t in cursor.fetchall()], end="\n\n")
+
+    cursor.execute("SELECT roll, name FROM Students WHERE city NOT IN ('Delhi', 'Mumbai')")
+    print(cursor.fetchall(), end="\n\n")
+
+    cursor.execute("""
+        SELECT 
+            S.roll,
+            S.name,
+            D.name
+        FROM Students S
+        JOIN Departments D ON S.depno = D.depno;
+    """)
+    print(cursor.fetchall(), end="\n\n")
+
+    cursor.execute("""
+        SELECT 
+            city,
+            COUNT(*)
+        FROM Students
+        GROUP BY city
+        HAVING COUNT(*) > 1;
+    """)
+    print(cursor.fetchall(), end="\n\n")
+
+    cursor.execute("""
+        SELECT
+            name
+        FROM Students
+        WHERE city IN (SELECT city FROM Students WHERE name = 'Verma');
+    """)
+    print(cursor.fetchall(), end="\n\n")
diff --git a/database/shop.py b/database/shop.py
new file mode 100644
index 0000000..2ddd6b9
--- /dev/null
+++ b/database/shop.py
@@ -0,0 +1,162 @@
+import sqlite3
+
+
+with sqlite3.connect("shop.db") as conn:
+    cursor = conn.cursor()
+    
+    # Create tables if they don't exist
+    cursor.execute('''
+    CREATE TABLE IF NOT EXISTS customer (
+        cust_id TEXT PRIMARY KEY,
+        cust_name TEXT NOT NULL,
+        address TEXT
+    )
+    ''')
+    
+    cursor.execute('''
+    CREATE TABLE IF NOT EXISTS product (
+        prod_no TEXT PRIMARY KEY,
+        prod_name TEXT NOT NULL,
+        price REAL NOT NULL
+    )
+    ''')
+    
+    cursor.execute('''
+    CREATE TABLE IF NOT EXISTS orders (
+        order_no INTEGER,
+        cust_id TEXT NOT NULL,
+        prod_no TEXT NOT NULL,
+        quantity INTEGER NOT NULL,
+        PRIMARY KEY (order_no, prod_no),
+        FOREIGN KEY (cust_id) REFERENCES customer (cust_id),
+        FOREIGN KEY (prod_no) REFERENCES product (prod_no)
+    )
+    ''')
+    
+    # Check if customer table is empty before inserting data
+    cursor.execute("SELECT COUNT(*) FROM customer")
+    if cursor.fetchone()[0] == 0:
+        # Insert data into customer table
+        customers = [
+            ('C101', 'Anita', 'Delhi'),
+            ('C102', 'Raj', 'Hyderabad'),
+            ('C103', 'Michael', 'Kolkata'),
+            ('C107', 'Ali', 'Delhi'),
+            ('C109', 'Sharma', 'Chennai')
+        ]
+        cursor.executemany("INSERT INTO customer VALUES (?, ?, ?)", customers)
+        print("Customer data inserted.")
+    
+    # Check if product table is empty before inserting data
+    cursor.execute("SELECT COUNT(*) FROM product")
+    if cursor.fetchone()[0] == 0:
+        # Insert data into product table
+        products = [
+            ('P10', 'Toothpaste', 20),
+            ('P11', 'Toothbrush', 10),
+            ('P12', 'Lotion', 30),
+            ('P13', 'Shampoo', 25),
+            ('P14', 'Soap', 10)
+        ]
+        cursor.executemany("INSERT INTO product VALUES (?, ?, ?)", products)
+        print("Product data inserted.")
+    
+    # Check if orders table is empty before inserting data
+    cursor.execute("SELECT COUNT(*) FROM orders")
+    if cursor.fetchone()[0] == 0:
+        # Insert data into orders table
+        orders = [
+            (10005, 'C101', 'P10', 1),
+            (10005, 'C101', 'P11', 2),
+            (12389, 'C109', 'P12', 1),
+            (12389, 'C109', 'P14', 1),
+            (12389, 'C109', 'P11', 2),
+            (63017, 'C103', 'P13', 4),
+            (63017, 'C103', 'P10', 1),
+            (63017, 'C103', 'P11', 4),
+            (71222, 'C101', 'P12', 2),
+            (71222, 'C101', 'P13', 1),
+            (96351, 'C102', 'P14', 1)
+        ]
+        cursor.executemany("INSERT INTO orders VALUES (?, ?, ?, ?)", orders)
+        print("Order data inserted.")
+    
+    # Commit changes
+    conn.commit()
+    
+    print("Database setup completed.\n")
+    
+    # Execute the 10 queries from the image
+    print("Query 1: Find all Customers")
+    query1 = "SELECT * FROM customer"
+    for row in cursor.execute(query1):
+        print(row)
+    
+    print("\nQuery 2: Find all Customers from Delhi")
+    query2 = "SELECT * FROM customer WHERE address = 'Delhi'"
+    for row in cursor.execute(query2):
+        print(row)
+    
+    print("\nQuery 3: Find all Products with price greater than 20")
+    query3 = "SELECT * FROM product WHERE price > 20"
+    for row in cursor.execute(query3):
+        print(row)
+    
+    print("\nQuery 4: Find Names of the Products starting with letter 'S'")
+    query4 = "SELECT prod_name FROM product WHERE prod_name LIKE 'S%'"
+    for row in cursor.execute(query4):
+        print(row[0])
+    
+    print("\nQuery 5: Find Names of Customers either living in Delhi or Chennai")
+    query5 = "SELECT cust_name FROM customer WHERE address IN ('Delhi', 'Chennai')"
+    for row in cursor.execute(query5):
+        print(row[0])
+    
+    print("\nQuery 6: Find Order No and Product Number with Quantity greater than 1")
+    query6 = "SELECT order_no, prod_no FROM orders WHERE quantity > 1"
+    for row in cursor.execute(query6):
+        print(row)
+    
+    print("\nQuery 7: Find Name of the Customer with Order number 10005")
+    query7 = """
+    SELECT DISTINCT c.cust_name 
+    FROM customer c
+    JOIN orders o ON c.cust_id = o.cust_id
+    WHERE o.order_no = 10005
+    """
+    for row in cursor.execute(query7):
+        print(row[0])
+    
+    print("\nQuery 8: Find Product Names and Quantity in Order number 63017")
+    query8 = """
+    SELECT p.prod_name, o.quantity
+    FROM product p
+    JOIN orders o ON p.prod_no = o.prod_no
+    WHERE o.order_no = 63017
+    """
+    for row in cursor.execute(query8):
+        print(row)
+    
+    print("\nQuery 9: Find Order numbers which contains Toothpaste")
+    query9 = """
+    SELECT DISTINCT o.order_no
+    FROM orders o
+    JOIN product p ON o.prod_no = p.prod_no
+    WHERE p.prod_name = 'Toothpaste'
+    """
+    for row in cursor.execute(query9):
+        print(row[0])
+    
+    print("\nQuery 10: Find Names of the Customers who purchased Lotion")
+    query10 = """
+    SELECT DISTINCT c.cust_name
+    FROM customer c
+    JOIN orders o ON c.cust_id = o.cust_id
+    JOIN product p ON o.prod_no = p.prod_no
+    WHERE p.prod_name = 'Lotion'
+    """
+    for row in cursor.execute(query10):
+        print(row[0])
+    
+    
+    
\ No newline at end of file
diff --git a/database/update_delete.py b/database/update_delete.py
new file mode 100644
index 0000000..4b00cc2
--- /dev/null
+++ b/database/update_delete.py
@@ -0,0 +1,15 @@
+import sqlite3
+
+
+with sqlite3.connect("university.db") as conn:
+    cursor = conn.cursor()
+    cursor.execute("PRAGMA foreign_keys = ON")
+
+    cursor.execute("UPDATE Departments SET name = 'Chem' where name = 'Mech'")
+    print(cursor.execute("SELECT * FROM Departments").fetchall())
+
+    cursor.execute("DELETE FROM Students WHERE roll = 15")
+    print(cursor.execute("SELECT COUNT(*) FROM Students").fetchall()[0][0])
+
+    cursor.execute("DELETE FROM Departments WHERE depno = 40")  # now this should throw an error if constraints exist
+    print(cursor.execute("SELECT COUNT(*) FROM Departments").fetchall()[0][0])


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR introduces multiple modules demonstrating various data type operations along with database update, query, and insertion functionalities.  
- Implements new database operations for university and shop databases.  
- Adds several utility modules to perform tasks like sorting, finding duplicates, processing text, and simulating queues.

### Reviewed Changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 2 comments.

<details>
<summary>Show a summary per file</summary>

| File                           | Description                                                                                 |
|--------------------------------|---------------------------------------------------------------------------------------------|
| database/update_delete.py      | Adds update and delete operations on the university database for Departments and Students.  |
| database/shop.py               | Establishes shop database schema with customer, product, and orders tables and sample queries. |
| database/query.py              | Provides various queries to retrieve and display data from the university database.         |
| database/insert.py             | Inserts sample records into Departments and Students tables in the university database.     |
| database/create_db.py          | Creates schema for the university database with Departments and Students tables.            |
| data_types/missing_number.py   | Implements an algorithm to find a missing number in a sequence.                             |
| data_types/inventory.py        | Provides an Inventory class that updates inventory using collections.Counter.               |
| data_types/insertion_sort.py   | Implements an insertion sort using the bisect module (contains a bug in element inclusion).    |
| data_types/heap_sort.py        | Implements heap sort for lists and arrays using heapq.                                      |
| data_types/first_duplicate.py  | Finds the first duplicate in an array.                                                      |
| data_types/common_words.py     | Extracts common words from a text using regex and Counter.                                  |
| data_types/canteen_queue.py    | Simulates canteen queue management using deque.                                             |
| data_types/bill_generator.py   | Generates formatted bills based on an order and a price list.                               |
| data_types/barber_queue.py     | Simulates a barber shop queue using deque.                                                  |
</details>


<details>
<summary>Files not reviewed (1)</summary>

* **data_types/sample_text.txt**: Language not supported
</details>



state: COMMENTED
author_association: NONE
submitted_at: 2025-03-28T21:16:59Z

Review comments:
diff_hunk: @@ -0,0 +1,15 @@
+import bisect
+from typing import Any
+
+
+def insertion_sort(elements: list[Any]) -> list[Any]:
+    result = []
path: data_types/insertion_sort.py
user: login: Copilot
body: The insertion_sort function omits the first element of the input list since it initializes an empty result list and starts inserting from the second element. Initialize result with the first element (e.g., result = [elements[0]]) before iterating from index 1.
```suggestion
    result = [elements[0]]
```
created_at: 2025-03-28T21:16:58Z
author_association: NONE
diff_hunk: @@ -0,0 +1,24 @@
+from collections import deque
+from re import L
+
path: data_types/canteen_queue.py
user: login: Copilot
body: The import 'from re import L' appears to be unused and should be removed to clean up the code.
```suggestion

```
created_at: 2025-03-28T21:16:58Z
author_association: NONE

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-28T21:17:58Z
body: ## PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

<table>
<tr><td>⏱️&nbsp;<strong>Estimated effort to review</strong>: 4 🔵🔵🔵🔵⚪</td></tr>
<tr><td>🧪&nbsp;<strong>PR contains tests</strong></td></tr>
<tr><td>🔒&nbsp;<strong>No security concerns identified</strong></td></tr>
<tr><td>⚡&nbsp;<strong>Recommended focus areas for review</strong><br><br>

<details><summary><a href='https://github.com/Altmerian/learn-python/pull/2/files#diff-8752304b20bb0ee3dc45fc82215fabb667545ec25d0f2d5058b8d181c86de87eR5-R10'><strong>Possible Issue</strong></a>

The insertion_sort function builds the sorted list starting from the second element only, omitting the first element. This may lead to incomplete sorting.
</summary>

```python
def insertion_sort(elements: list[Any]) -> list[Any]:
    result = []
    for i in range(1, len(elements)):
        key = elements[i]
        bisect.insort(result, key)
    return result
```

</details>

<details><summary><a href='https://github.com/Altmerian/learn-python/pull/2/files#diff-8fa10ab6a95855d3b3f022606b927ebb341c598dc4e8fc042f61ef3135030012R2-R2'><strong>Code Cleanup</strong></a>

The import `L` from the re module appears to be unused. Removing it will clean up the code.
</summary>

```python
from re import L
```

</details>

<details><summary><a href='https://github.com/Altmerian/learn-python/pull/2/files#diff-4fc58d73618f8602149d5c0874beadce8225b0b505e974cdddec431cb74ccfc9R1-R1'><strong>Minor Text Issue</strong></a>

The sample text contains a minor grammatical error ("an easy programmers language"). Consider updating it to "an easy programming language" for clarity.
</summary>

```text
Python is an easy programmers language. 
```

</details>

</td></tr>
</table>

author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-28T21:18:31Z
body: ## PR Code Suggestions ✨

<!-- b8b032c -->

Explore these optional code suggestions:

<table><thead><tr><td><strong>Category</strong></td><td align=left><strong>Suggestion&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </strong></td><td align=center><strong>Impact</strong></td></tr><tbody><tr><td rowspan=2>Possible issue</td>
<td>



<details><summary>Handle empty queue</summary>

___


**Add a check for an empty queue before calling popleft to prevent runtime errors.**

[data_types/barber_queue.py [10-11]](https://github.com/Altmerian/learn-python/pull/2/files#diff-c6333140809903abfa64c72f0cb651f90ce55a670c6dbd47dc4331b33a1cf5f4R10-R11)

```diff
 def service_customer(self) -> str:
-    return self.queue.popleft()
+    if self.queue:
+        return self.queue.popleft()
+    raise Exception("No customers in queue.")
```
<details><summary>Suggestion importance[1-10]: 8</summary>

__

Why: The suggestion introduces an error-handling check that prevents a runtime error when the queue is empty, addressing a potential bug effectively.


</details></details></td><td align=center>Medium

</td></tr><tr><td>



<details><summary>Include all elements</summary>

___


**Initialize the result with the first element to ensure all elements are included in <br>the sorted output.**

[data_types/insertion_sort.py [5-10]](https://github.com/Altmerian/learn-python/pull/2/files#diff-8752304b20bb0ee3dc45fc82215fabb667545ec25d0f2d5058b8d181c86de87eR5-R10)

```diff
 def insertion_sort(elements: list[Any]) -> list[Any]:
-    result = []
+    if not elements:
+        return []
+    result = [elements[0]]
     for i in range(1, len(elements)):
-        key = elements[i]
-        bisect.insort(result, key)
+        bisect.insort(result, elements[i])
     return result
```
<details><summary>Suggestion importance[1-10]: 8</summary>

__

Why: The fix corrects a critical bug by ensuring the first element is included in the sorted list and adds a safeguard for empty inputs, improving overall correctness.


</details></details></td><td align=center>Medium

</td></tr></tr></tbody></table>


author_association: NONE
user: login: Altmerian
created_at: 2025-03-28T21:24:27Z
body: /improve
author_association: OWNER
user: login: github-actions[bot]
created_at: 2025-03-28T21:25:06Z
body: ## PR Code Suggestions ✨

No code suggestions found for the PR.
author_association: NONE