55Create Date: 2025-05-02 20:55:00.000000
66
77"""
8+ import logging
89from alembic import op
910import sqlalchemy as sa
1011from sqlalchemy .dialects .postgresql import UUID , JSONB
3536# Get SCHEMA_NAME from the loaded module
3637SCHEMA_NAME = base_model .SCHEMA_NAME
3738
39+ def table_exists (connection , table_name , schema = 'public' ):
40+ """Check if a table exists in the database"""
41+ query = sa .text (
42+ """
43+ SELECT EXISTS (
44+ SELECT FROM information_schema.tables
45+ WHERE table_schema = :schema
46+ AND table_name = :table_name
47+ )
48+ """
49+ )
50+ result = connection .execute (query , {"schema" : schema , "table_name" : table_name }).scalar ()
51+ return bool (result )
52+
3853def upgrade () -> None :
3954 """Migrate data from old tables to new schema"""
4055
@@ -44,6 +59,14 @@ def upgrade() -> None:
4459 # Define tables for direct SQL operations
4560 metadata = sa .MetaData ()
4661
62+ # Check if the source tables exist
63+ canvas_data_exists = table_exists (connection , 'canvas_data' )
64+ canvas_backups_exists = table_exists (connection , 'canvas_backups' )
65+
66+ if not canvas_data_exists and not canvas_backups_exists :
67+ logging .info ("Source tables 'canvas_data' and 'canvas_backups' do not exist. Skipping data migration." )
68+ return
69+
4770 # Define the old tables in the public schema
4871 canvas_data = sa .Table (
4972 'canvas_data' ,
@@ -102,86 +125,107 @@ def upgrade() -> None:
102125 session = Session (connection )
103126
104127 try :
105- # Step 1: Get all canvas_data records
106- canvas_data_records = session .execute (sa .select (canvas_data )).fetchall ()
107-
108128 # Dictionary to store user_id -> pad_id mapping for later use with backups
109129 user_pad_mapping = {}
110130
111- # Step 2: For each canvas_data record, create a new pad
112- for record in canvas_data_records :
113- user_id = record .user_id
114-
115- # Check if the user exists in the new schema
116- user_exists = session .execute (
117- sa .select (users ).where (users .c .id == user_id )
118- ).fetchone ()
131+ # Step 1: Process canvas_data if it exists
132+ if canvas_data_exists :
133+ try :
134+ # Get all canvas_data records
135+ canvas_data_records = session .execute (sa .select (canvas_data )).fetchall ()
136+ logging .info (f"Found { len (canvas_data_records )} records in canvas_data table" )
137+
138+ # Step 2: For each canvas_data record, create a new pad
139+ for record in canvas_data_records :
140+ user_id = record .user_id
119141
120- if not user_exists :
121- print (f"User { user_id } not found in new schema, creating with placeholder data" )
122- # Create a new user with placeholder data
123- # The real data will be updated when the user accesses the /me route
124- session .execute (
125- users .insert ().values (
126- id = user_id ,
127- username = f"migrated_user_{ user_id } " ,
128- email = f"migrated_{ user_id } @example.com" ,
129- email_verified = False ,
130- name = "Migrated User" ,
131- given_name = "Migrated" ,
132- family_name = "User" ,
133- roles = [],
142+ # Check if the user exists in the new schema
143+ user_exists = session .execute (
144+ sa .select (users ).where (users .c .id == user_id )
145+ ).fetchone ()
146+
147+ if not user_exists :
148+ logging .info (f"User { user_id } not found in new schema, creating with placeholder data" )
149+ # Create a new user with placeholder data
150+ # The real data will be updated when the user accesses the /me route
151+ session .execute (
152+ users .insert ().values (
153+ id = user_id ,
154+ username = f"migrated_user_{ user_id } " ,
155+ email = f"migrated_{ user_id } @example.com" ,
156+ email_verified = False ,
157+ name = "Migrated User" ,
158+ given_name = "Migrated" ,
159+ family_name = "User" ,
160+ roles = [],
161+ )
162+ )
163+
164+ # Generate a new UUID for the pad
165+ pad_id = uuid .uuid4 ()
166+
167+ # Store the mapping for later use
168+ user_pad_mapping [user_id ] = pad_id
169+
170+ # Insert the pad record
171+ session .execute (
172+ pads .insert ().values (
173+ id = pad_id ,
174+ owner_id = user_id ,
175+ display_name = "Untitled" ,
176+ data = record .data ,
177+ )
134178 )
135- )
136-
137- # Generate a new UUID for the pad
138- pad_id = uuid .uuid4 ()
139-
140- # Store the mapping for later use
141- user_pad_mapping [user_id ] = pad_id
142-
143- # Insert the pad record
144- session .execute (
145- pads .insert ().values (
146- id = pad_id ,
147- owner_id = user_id ,
148- display_name = "Untitled" ,
149- data = record .data ,
150- )
151- )
179+ except Exception as e :
180+ logging .error (f"Error processing canvas_data: { e } " )
181+ session .rollback ()
182+ raise
152183
153- # Step 3: Get all canvas_backups records
154- canvas_backup_records = session .execute (sa .select (canvas_backups )).fetchall ()
155-
156- # Step 4: For each canvas_backup record, create a new backup
157- for record in canvas_backup_records :
158- user_id = record .user_id
159-
160- # Skip if we don't have a pad for this user
161- if user_id not in user_pad_mapping :
162- print (f"Warning: No pad found for user { user_id } , skipping backup" )
163- continue
164-
165- pad_id = user_pad_mapping [user_id ]
166-
167- # Insert the backup record
168- session .execute (
169- backups .insert ().values (
170- id = uuid .uuid4 (),
171- source_id = pad_id ,
172- data = record .canvas_data , # Note: using canvas_data field from the record
173- created_at = record .timestamp ,
174- )
175- )
184+ # Step 3: Process canvas_backups if it exists
185+ if canvas_backups_exists and user_pad_mapping : # Only process backups if we have pads
186+ try :
187+ # Get all canvas_backups records
188+ canvas_backup_records = session .execute (sa .select (canvas_backups )).fetchall ()
189+ logging .info (f"Found { len (canvas_backup_records )} records in canvas_backups table" )
190+
191+ # Step 4: For each canvas_backup record, create a new backup
192+ for record in canvas_backup_records :
193+ user_id = record .user_id
194+
195+ # Skip if we don't have a pad for this user
196+ if user_id not in user_pad_mapping :
197+ logging .warning (f"No pad found for user { user_id } , skipping backup" )
198+ continue
199+
200+ pad_id = user_pad_mapping [user_id ]
201+
202+ # Insert the backup record
203+ session .execute (
204+ backups .insert ().values (
205+ id = uuid .uuid4 (),
206+ source_id = pad_id ,
207+ data = record .canvas_data , # Note: using canvas_data field from the record
208+ created_at = record .timestamp ,
209+ )
210+ )
211+ except Exception as e :
212+ logging .error (f"Error processing canvas_backups: { e } " )
213+ session .rollback ()
214+ raise
176215
177216 # Commit the transaction
178217 session .commit ()
179218
180- print (f"Migration complete: { len (canvas_data_records )} pads and { len (canvas_backup_records )} backups migrated" )
219+ if canvas_data_exists or canvas_backups_exists :
220+ pad_count = len (user_pad_mapping ) if canvas_data_exists else 0
221+ backup_count = len (canvas_backup_records ) if canvas_backups_exists and 'canvas_backup_records' in locals () else 0
222+ logging .info (f"Migration complete: { pad_count } pads and { backup_count } backups migrated" )
223+ else :
224+ logging .info ("No data to migrate" )
181225
182226 except Exception as e :
183227 session .rollback ()
184- print (f"Error during migration: { e } " )
228+ logging . error (f"Error during migration: { e } " )
185229 raise
186230 finally :
187231 session .close ()
0 commit comments