-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstorage.py
More file actions
113 lines (87 loc) · 3.4 KB
/
storage.py
File metadata and controls
113 lines (87 loc) · 3.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import threading
from typing import Optional
from uuid import UUID
from models import Event, Booking
class TicketingStorage:
"""
Our in-memory database.
Simple explanation:
- We use Python dictionaries to store events and bookings
- Dictionary key = ID (UUID), value = Event or Booking object
- We use locks to make sure two requests don't interfere with each other
"""
def __init__(self):
"""Initialize empty storage"""
# Where we store data (like a simple database)
self.events = {} # {event_id: Event object}
self.bookings = {} # {booking_id: Booking object}
# Locks to prevent race conditions
self.event_lock = threading.Lock()
self.booking_lock = threading.Lock()
# ========== EVENT OPERATIONS ==========
def save_event(self, event: Event) -> Event:
"""Save a new event"""
with self.event_lock:
self.events[event.id] = event
return event
def get_event(self, event_id: UUID) -> Optional[Event]:
"""Get an event by ID"""
with self.event_lock:
return self.events.get(event_id)
def get_all_events(self) -> list[Event]:
"""Get all events"""
with self.event_lock:
return list(self.events.values())
def update_seats(self, event_id: UUID, change: int) -> bool:
"""
Change available seats for an event.
change = -5 means remove 5 seats (someone booked)
change = +5 means add 5 seats (someone cancelled)
"""
with self.event_lock:
event = self.events.get(event_id)
if not event:
return False
new_count = event.available_seats + change
# Make sure we don't go negative or above total
if new_count < 0 or new_count > event.total_seats:
return False
event.available_seats = new_count
return True
# ========== BOOKING OPERATIONS ==========
def save_booking(self, booking: Booking) -> Booking:
"""Save a new booking"""
with self.booking_lock:
self.bookings[booking.booking_id] = booking
return booking
def get_booking(self, booking_id: UUID) -> Optional[Booking]:
"""Get a booking by ID"""
with self.booking_lock:
return self.bookings.get(booking_id)
def update_booking(self, booking: Booking) -> bool:
"""Update an existing booking (for cancellations)"""
with self.booking_lock:
if booking.booking_id not in self.bookings:
return False
self.bookings[booking.booking_id] = booking
return True
# ========== UTILITY ==========
def clear_all(self):
"""Clear everything (useful for testing)"""
with self.event_lock, self.booking_lock:
self.events.clear()
self.bookings.clear()
# Global storage instance (our "database" for the app)
_storage = None
_storage_lock = threading.Lock()
def get_storage() -> TicketingStorage:
"""
Get the global storage instance.
We use a single storage for the entire app.
"""
global _storage
if _storage is None:
with _storage_lock:
if _storage is None:
_storage = TicketingStorage()
return _storage