From a77145e08ee1534e2bda1d014ff580a71675aff1 Mon Sep 17 00:00:00 2001 From: padreug Date: Sat, 3 Jan 2026 17:48:46 +0100 Subject: [PATCH] fix: Use db.insert() for ticket creation to fix SQLite serialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous implementation used db.execute() with a raw dict, which failed on SQLite because the 'extra' field (TicketExtra model) was passed as a Python dict that SQLite cannot serialize. Using db.insert() with the Pydantic model ensures proper JSON serialization of the extra field across all database backends (SQLite, PostgreSQL, CockroachDB). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- crud.py | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/crud.py b/crud.py index e92e47e..8996a2e 100644 --- a/crud.py +++ b/crud.py @@ -20,7 +20,12 @@ async def create_ticket( ) -> Ticket: now = datetime.now(timezone.utc) - # Handle database constraints: if user_id is provided, use empty strings for name/email + # TODO: Check if this empty string workaround is still needed. + # This converts None to empty strings for database storage because: + # 1. Database may have NOT NULL constraints on name/email columns + # 2. When user_id is provided, name/email are not used (mutually exclusive) + # 3. The get_ticket() functions convert empty strings back to None when reading + # Consider using nullable columns instead of this empty string pattern. if user_id: db_name = "" db_email = "" @@ -28,7 +33,28 @@ async def create_ticket( db_name = name or "" db_email = email or "" - ticket = Ticket( + # Create ticket with database-compatible values for insertion + # Using db.insert() ensures proper serialization of the extra field (TicketExtra) + # across all database backends (SQLite, PostgreSQL, CockroachDB) + db_ticket = Ticket( + id=payment_hash, + wallet=wallet, + event=event, + name=db_name, + email=db_email, + user_id=user_id, + registered=False, + paid=False, + reg_timestamp=now, + time=now, + extra=TicketExtra(**extra) if extra else TicketExtra(), + ) + + await db.insert("events.ticket", db_ticket) + + # Return ticket with original name/email values (not empty strings) + # This maintains consistency with how get_ticket() converts empty strings back to None + return Ticket( id=payment_hash, wallet=wallet, event=event, @@ -42,20 +68,6 @@ async def create_ticket( extra=TicketExtra(**extra) if extra else TicketExtra(), ) - # Create a dict for database insertion with proper handling of constraints - ticket_dict = ticket.dict() - ticket_dict["name"] = db_name - ticket_dict["email"] = db_email - - await db.execute( - """ - INSERT INTO events.ticket (id, wallet, event, name, email, user_id, registered, paid, time, reg_timestamp, extra) - VALUES (:id, :wallet, :event, :name, :email, :user_id, :registered, :paid, :time, :reg_timestamp, :extra) - """, - ticket_dict - ) - return ticket - async def update_ticket(ticket: Ticket) -> Ticket: # Create a new Ticket object with corrected values for database constraints