Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 31 additions & 40 deletions sqlalchemy_1.6_to_2.0/README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,61 @@
# SQLAlchemy 1.6 to 2.0 Migration Example

[![Documentation](https://img.shields.io/badge/docs-docs.codegen.com-blue)](https://docs.codegen.com/tutorials/sqlalchemy-1.6-to-2.0)
This codemod demonstrates how to use Codegen to automatically migrate SQLAlchemy 1.6 code to the new 2.0-style query interface. For a complete walkthrough, check out our [tutorial](https://docs.codegen.com/tutorials/sqlalchemy-1.6-to-2.0).

This example demonstrates how to use Codegen to automatically migrate SQLAlchemy 1.6 code to the new 2.0-style query interface. For a complete walkthrough, check out our [tutorial](https://docs.codegen.com/tutorials/sqlalchemy-1.6-to-2.0).
## How the Migration Script Works

## What This Example Does
The codemod script handles four key transformations:

The migration script handles four key transformations:

1. **Convert Query to Select**
1. **Update Base Class and Imports**
```python
# From:
session.query(User).filter_by(name='john').all()
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

# To:
session.execute(
select(User).where(User.name == 'john')
).scalars().all()
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
```
Updates the Base class to use the new DeclarativeBase style.

2. **Update Session Execution**
2. **Modernize ORM Relationships**
```python
# From:
users = session.query(User).all()
first_user = session.query(User).first()
class User(Base):
addresses = relationship("Address", backref="user")

# To:
users = session.execute(select(User)).scalars().all()
first_user = session.execute(select(User)).scalars().first()
class User(Base):
addresses = relationship("Address", back_populates="user")
```
Relationships are modernized to use explicit back_populates instead of backref. If no back reference is specified, it defaults to None.

3. **Modernize ORM Relationships**
3. **Update Query Method Names**
```python
# From:
class User(Base):
addresses = relationship("Address", backref="user")
db.session.query(User).filter(User.name == 'john').all()
db.session.query(User).first()

# To:
class User(Base):
addresses = relationship("Address", back_populates="user", use_list=True)
class Address(Base):
user = relationship("User", back_populates="addresses")
db.session.select(User).where(User.name == 'john').scalars().all()
db.session.select(User).scalar_one_or_none()
```
Updates query method names to their 2.0 equivalents: `query` → `select`, `filter` → `where`, `all` → `scalars().all`, and `first` → `scalar_one_or_none`.

4. **Add Type Annotations**
4. **Update Configurations**
```python
# From:
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship("Address")
create_engine(url)
sessionmaker(bind=engine)
relationship("Address")

# To:
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column()
addresses: Mapped[List["Address"]] = relationship()
create_engine(url, future=True, pool_pre_ping=True)
sessionmaker(bind=engine, future=True)
relationship("Address", lazy="select")
```
Adds future-compatible configurations and default lazy loading settings. Also updates Pydantic configs from `orm_mode` to `from_attributes`.

## Running the Example

Expand All @@ -70,13 +67,7 @@ pip install codegen
python run.py
```

The script will process all Python files in the `repo-before` directory and apply the transformations in the correct order.

## Understanding the Code

- `run.py` - The migration script
- `repo-before/` - Sample SQLAlchemy 1.6 application to migrate
- `guide.md` - Additional notes and explanations
The script will process all Python files in the `input_repo` directory and apply the transformations in the correct order.

## Learn More

Expand Down
96 changes: 0 additions & 96 deletions sqlalchemy_1.6_to_2.0/guide.md

This file was deleted.

4 changes: 3 additions & 1 deletion sqlalchemy_1.6_to_2.0/input_repo/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/dbname" # Change to your database URL
SQLALCHEMY_DATABASE_URL = (
"postgresql://user:password@localhost/dbname" # Change to your database URL
)

engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Expand Down
5 changes: 3 additions & 2 deletions sqlalchemy_1.6_to_2.0/input_repo/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from sqlalchemy import Column, Integer, String, ForeignKey, Index
from sqlalchemy.orm import relationship, backref
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from database import Base


class Publisher(Base):
__tablename__ = "publishers"

Expand Down
11 changes: 0 additions & 11 deletions sqlalchemy_1.6_to_2.0/output_repo/database.py

This file was deleted.

101 changes: 0 additions & 101 deletions sqlalchemy_1.6_to_2.0/output_repo/main.py

This file was deleted.

32 changes: 0 additions & 32 deletions sqlalchemy_1.6_to_2.0/output_repo/models.py

This file was deleted.

Loading