Skip to content

Commit 6cc85a2

Browse files
committed
.
1 parent e16750d commit 6cc85a2

File tree

5 files changed

+89
-175
lines changed

5 files changed

+89
-175
lines changed

examples/sqlalchemy_1.6_to_2.0/output_repo/database.py

Lines changed: 0 additions & 10 deletions
This file was deleted.

examples/sqlalchemy_1.6_to_2.0/output_repo/main.py

Lines changed: 0 additions & 102 deletions
This file was deleted.

examples/sqlalchemy_1.6_to_2.0/output_repo/models.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

examples/sqlalchemy_1.6_to_2.0/output_repo/schemas.py

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import codegen
2+
from codegen import Codebase
3+
from codegen.sdk.core.detached_symbols.function_call import FunctionCall
4+
from codegen.sdk.core.expressions.chained_attribute import ChainedAttribute
5+
6+
7+
@codegen.function("sqlalchemy-1.6-to-2.0")
8+
def run(codebase: Codebase):
9+
"""
10+
Convert SQLAlchemy 1.6 codebases to 2.0.
11+
"""
12+
files_modified = 0
13+
functions_modified = 0
14+
15+
print("\nStarting SQLAlchemy 1.6 to 2.0 migration...")
16+
17+
for file in codebase.files:
18+
file_modified = False
19+
print(f"\nProcessing file: {file.path}")
20+
21+
# Step 1: Convert Query to Select
22+
for call in file.function_calls:
23+
if call.name == "query":
24+
chain = call
25+
while chain.parent and isinstance(chain.parent, ChainedAttribute):
26+
chain = chain.parent
27+
28+
original_code = chain.source
29+
new_query = chain.source.replace("query(", "select(")
30+
if "filter(" in new_query:
31+
new_query = new_query.replace(".filter(", ".where(")
32+
if "filter_by(" in new_query:
33+
model = call.args[0].value
34+
conditions = chain.source.split("filter_by(")[1].split(")")[0]
35+
new_conditions = [f"{model}.{cond.strip().replace('=', ' == ')}" for cond in conditions.split(",")]
36+
new_query = f".where({' & '.join(new_conditions)})"
37+
if "execute" not in chain.parent.source:
38+
new_query = f"execute({new_query}).scalars()"
39+
print("\nConverting query:")
40+
print("Original:", original_code)
41+
print("New:", new_query)
42+
chain.edit(new_query)
43+
file_modified = True
44+
functions_modified += 1
45+
46+
# Step 2: Modernize ORM Relationships
47+
for cls in file.classes:
48+
for attr in cls.attributes:
49+
if isinstance(attr.value, FunctionCall) and attr.value.name == "relationship":
50+
if "lazy=" not in attr.value.source:
51+
original_rel = attr.value.source
52+
new_rel = original_rel + ', lazy="selectin"'
53+
if "backref" in new_rel:
54+
new_rel = new_rel.replace("backref", "back_populates")
55+
print("\nUpdating relationship:")
56+
print("Original:", original_rel)
57+
print("New:", new_rel)
58+
attr.value.edit(new_rel)
59+
file_modified = True
60+
functions_modified += 1
61+
62+
# Step 3: Convert Column Definitions to Type Annotations
63+
for cls in file.classes:
64+
for attr in cls.attributes:
65+
if "Column(" in attr.source:
66+
original_attr = attr.source
67+
new_attr = original_attr.replace("Column", "mapped_column")
68+
type_hint = "Mapped" + original_attr.split("= Column")[1]
69+
new_attr = f"{attr.name}: {type_hint}"
70+
print("\nUpdating column definition:")
71+
print("Original:", original_attr)
72+
print("New:", new_attr)
73+
attr.edit(new_attr)
74+
file_modified = True
75+
functions_modified += 1
76+
77+
if file_modified:
78+
files_modified += 1
79+
80+
print("\nMigration complete:")
81+
print(f"Files modified: {files_modified}")
82+
print(f"Functions modified: {functions_modified}")
83+
84+
85+
if __name__ == "__main__":
86+
print("Initializing codebase...")
87+
codebase = Codebase("./input_repo")
88+
print("Running SQLAlchemy 1.6 to 2.0 codemod...")
89+
run(codebase)

0 commit comments

Comments
 (0)