Learn how to migrate SQLAlchemy 1.4 codebases to 2.0 using Codegen
Migrating from SQLAlchemy 1.4 to 2.0 involves several API changes to support the new 2.0-style query interface. This guide will walk you through using Graph-sitter to automate this migration, handling query syntax, session usage, and ORM patterns.
First, we need to convert legacy Query-style operations to the new select() syntax:
Copy
Ask AI
def convert_query_to_select(file): """Convert Query-style operations to select() statements""" for call in file.function_calls: if call.name == "query": # Convert query(Model) to select(Model) call.set_name("select") # Update method chains if call.parent and call.parent.is_method_chain: chain = call.parent if "filter" in chain.source: # Convert .filter() to .where() chain.source = chain.source.replace(".filter(", ".where(") if "filter_by" in chain.source: # Convert .filter_by(name='x') to .where(Model.name == 'x') model = call.args[0].value conditions = chain.source.split("filter_by(")[1].split(")")[0] new_conditions = [] for cond in conditions.split(","): if "=" in cond: key, value = cond.split("=") new_conditions.append(f"{model}.{key.strip()} == {value.strip()}") chain.edit(f".where({' & '.join(new_conditions)})")
Next, we update how queries are executed with the Session:
Copy
Ask AI
def update_session_execution(file): """Update session execution patterns for 2.0 style""" for call in file.function_calls: if call.name == "query": # Find the full query chain chain = call while chain.parent and chain.parent.is_method_chain: chain = chain.parent # Wrap in session.execute() if needed if not chain.parent or "execute" not in chain.parent.source: chain.edit(f"execute(select{chain.source[5:]})") # Add .scalars() for single-entity queries if len(call.args) == 1: chain.edit(f"{chain.source}.scalars()")
This converts patterns like:
Copy
Ask AI
# Old styleusers = session.query(User).all()first_user = session.query(User).first()
to:
Copy
Ask AI
# New styleusers = session.execute(select(User)).scalars().all()first_user = session.execute(select(User)).scalars().first()
The new execution pattern is more explicit about what’s being returned, making
it easier to understand and maintain type safety.