Skip to content

Commit 00f1574

Browse files
committed
fix: SQLAlchemy 2.0 compatibility for chapter_06_uow_exercise
- Replace deprecated mapper() with registry.map_imperatively() - Replace session.query() with session.scalars(select()) - Wrap raw SQL strings with text() - Replace clear_mappers() with mapper_registry.dispose() - Update requirements.txt to require sqlalchemy>=2.0
1 parent 6876e75 commit 00f1574

File tree

7 files changed

+72
-47
lines changed

7 files changed

+72
-47
lines changed

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# app
2-
sqlalchemy
2+
sqlalchemy>=2.0
33
flask
44
psycopg2-binary
55

src/allocation/adapters/orm.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from sqlalchemy import Table, MetaData, Column, Integer, String, Date, ForeignKey
2-
from sqlalchemy.orm import mapper, relationship
2+
from sqlalchemy.orm import registry, relationship
33

44
from allocation.domain import model
55

66

7-
metadata = MetaData()
7+
mapper_registry = registry()
8+
metadata = mapper_registry.metadata
89

910
order_lines = Table(
1011
"order_lines",
@@ -35,8 +36,8 @@
3536

3637

3738
def start_mappers():
38-
lines_mapper = mapper(model.OrderLine, order_lines)
39-
mapper(
39+
lines_mapper = mapper_registry.map_imperatively(model.OrderLine, order_lines)
40+
mapper_registry.map_imperatively(
4041
model.Batch,
4142
batches,
4243
properties={

src/allocation/adapters/repository.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import abc
2+
from sqlalchemy import select
23
from allocation.domain import model
34

45

@@ -20,7 +21,9 @@ def add(self, batch):
2021
self.session.add(batch)
2122

2223
def get(self, reference):
23-
return self.session.query(model.Batch).filter_by(reference=reference).one()
24+
return self.session.scalars(
25+
select(model.Batch).filter_by(reference=reference)
26+
).one()
2427

2528
def list(self):
26-
return self.session.query(model.Batch).all()
29+
return self.session.scalars(select(model.Batch)).all()

tests/conftest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
from requests.exceptions import ConnectionError
88
from sqlalchemy.exc import OperationalError
99
from sqlalchemy import create_engine
10-
from sqlalchemy.orm import sessionmaker, clear_mappers
10+
from sqlalchemy.orm import sessionmaker
1111

12-
from allocation.adapters.orm import metadata, start_mappers
12+
from allocation.adapters.orm import metadata, start_mappers, mapper_registry
1313
from allocation import config
1414

1515

@@ -24,7 +24,7 @@ def in_memory_db():
2424
def session_factory(in_memory_db):
2525
start_mappers()
2626
yield sessionmaker(bind=in_memory_db)
27-
clear_mappers()
27+
mapper_registry.dispose()
2828

2929

3030
@pytest.fixture
@@ -65,7 +65,7 @@ def postgres_db():
6565
def postgres_session(postgres_db):
6666
start_mappers()
6767
yield sessionmaker(bind=postgres_db)()
68-
clear_mappers()
68+
mapper_registry.dispose()
6969

7070

7171
@pytest.fixture

tests/integration/test_orm.py

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,61 @@
1+
from sqlalchemy import text, select
12
from allocation.domain import model
23
from datetime import date
34

45

56
def test_orderline_mapper_can_load_lines(session):
67
session.execute(
7-
"INSERT INTO order_lines (orderid, sku, qty) VALUES "
8-
'("order1", "RED-CHAIR", 12),'
9-
'("order1", "RED-TABLE", 13),'
10-
'("order2", "BLUE-LIPSTICK", 14)'
8+
text(
9+
"INSERT INTO order_lines (orderid, sku, qty) VALUES "
10+
'("order1", "RED-CHAIR", 12),'
11+
'("order1", "RED-TABLE", 13),'
12+
'("order2", "BLUE-LIPSTICK", 14)'
13+
)
1114
)
1215
expected = [
1316
model.OrderLine("order1", "RED-CHAIR", 12),
1417
model.OrderLine("order1", "RED-TABLE", 13),
1518
model.OrderLine("order2", "BLUE-LIPSTICK", 14),
1619
]
17-
assert session.query(model.OrderLine).all() == expected
20+
assert session.scalars(select(model.OrderLine)).all() == expected
1821

1922

2023
def test_orderline_mapper_can_save_lines(session):
2124
new_line = model.OrderLine("order1", "DECORATIVE-WIDGET", 12)
2225
session.add(new_line)
2326
session.commit()
2427

25-
rows = list(session.execute('SELECT orderid, sku, qty FROM "order_lines"'))
28+
rows = list(session.execute(text('SELECT orderid, sku, qty FROM "order_lines"')))
2629
assert rows == [("order1", "DECORATIVE-WIDGET", 12)]
2730

2831

2932
def test_retrieving_batches(session):
3033
session.execute(
31-
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
32-
' VALUES ("batch1", "sku1", 100, null)'
34+
text(
35+
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
36+
' VALUES ("batch1", "sku1", 100, null)'
37+
)
3338
)
3439
session.execute(
35-
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
36-
' VALUES ("batch2", "sku2", 200, "2011-04-11")'
40+
text(
41+
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
42+
' VALUES ("batch2", "sku2", 200, "2011-04-11")'
43+
)
3744
)
3845
expected = [
3946
model.Batch("batch1", "sku1", 100, eta=None),
4047
model.Batch("batch2", "sku2", 200, eta=date(2011, 4, 11)),
4148
]
4249

43-
assert session.query(model.Batch).all() == expected
50+
assert session.scalars(select(model.Batch)).all() == expected
4451

4552

4653
def test_saving_batches(session):
4754
batch = model.Batch("batch1", "sku1", 100, eta=None)
4855
session.add(batch)
4956
session.commit()
5057
rows = session.execute(
51-
'SELECT reference, sku, _purchased_quantity, eta FROM "batches"'
58+
text('SELECT reference, sku, _purchased_quantity, eta FROM "batches"')
5259
)
5360
assert list(rows) == [("batch1", "sku1", 100, None)]
5461

@@ -59,31 +66,33 @@ def test_saving_allocations(session):
5966
batch.allocate(line)
6067
session.add(batch)
6168
session.commit()
62-
rows = list(session.execute('SELECT orderline_id, batch_id FROM "allocations"'))
69+
rows = list(session.execute(text('SELECT orderline_id, batch_id FROM "allocations"')))
6370
assert rows == [(batch.id, line.id)]
6471

6572

6673
def test_retrieving_allocations(session):
6774
session.execute(
68-
'INSERT INTO order_lines (orderid, sku, qty) VALUES ("order1", "sku1", 12)'
75+
text('INSERT INTO order_lines (orderid, sku, qty) VALUES ("order1", "sku1", 12)')
6976
)
7077
[[olid]] = session.execute(
71-
"SELECT id FROM order_lines WHERE orderid=:orderid AND sku=:sku",
78+
text("SELECT id FROM order_lines WHERE orderid=:orderid AND sku=:sku"),
7279
dict(orderid="order1", sku="sku1"),
7380
)
7481
session.execute(
75-
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
76-
' VALUES ("batch1", "sku1", 100, null)'
82+
text(
83+
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
84+
' VALUES ("batch1", "sku1", 100, null)'
85+
)
7786
)
7887
[[bid]] = session.execute(
79-
"SELECT id FROM batches WHERE reference=:ref AND sku=:sku",
88+
text("SELECT id FROM batches WHERE reference=:ref AND sku=:sku"),
8089
dict(ref="batch1", sku="sku1"),
8190
)
8291
session.execute(
83-
"INSERT INTO allocations (orderline_id, batch_id) VALUES (:olid, :bid)",
92+
text("INSERT INTO allocations (orderline_id, batch_id) VALUES (:olid, :bid)"),
8493
dict(olid=olid, bid=bid),
8594
)
8695

87-
batch = session.query(model.Batch).one()
96+
batch = session.scalars(select(model.Batch)).one()
8897

8998
assert batch._allocations == {model.OrderLine("order1", "sku1", 12)}

tests/integration/test_repository.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# pylint: disable=protected-access
2+
from sqlalchemy import text
23
from allocation.domain import model
34
from allocation.adapters import repository
45

@@ -11,40 +12,46 @@ def test_repository_can_save_a_batch(session):
1112
session.commit()
1213

1314
rows = session.execute(
14-
'SELECT reference, sku, _purchased_quantity, eta FROM "batches"'
15+
text('SELECT reference, sku, _purchased_quantity, eta FROM "batches"')
1516
)
1617
assert list(rows) == [("batch1", "RUSTY-SOAPDISH", 100, None)]
1718

1819

1920
def insert_order_line(session):
2021
session.execute(
21-
"INSERT INTO order_lines (orderid, sku, qty)"
22-
' VALUES ("order1", "GENERIC-SOFA", 12)'
22+
text(
23+
"INSERT INTO order_lines (orderid, sku, qty)"
24+
' VALUES ("order1", "GENERIC-SOFA", 12)'
25+
)
2326
)
2427
[[orderline_id]] = session.execute(
25-
"SELECT id FROM order_lines WHERE orderid=:orderid AND sku=:sku",
28+
text("SELECT id FROM order_lines WHERE orderid=:orderid AND sku=:sku"),
2629
dict(orderid="order1", sku="GENERIC-SOFA"),
2730
)
2831
return orderline_id
2932

3033

3134
def insert_batch(session, batch_id):
3235
session.execute(
33-
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
34-
' VALUES (:batch_id, "GENERIC-SOFA", 100, null)',
36+
text(
37+
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
38+
' VALUES (:batch_id, "GENERIC-SOFA", 100, null)'
39+
),
3540
dict(batch_id=batch_id),
3641
)
3742
[[batch_id]] = session.execute(
38-
'SELECT id FROM batches WHERE reference=:batch_id AND sku="GENERIC-SOFA"',
43+
text('SELECT id FROM batches WHERE reference=:batch_id AND sku="GENERIC-SOFA"'),
3944
dict(batch_id=batch_id),
4045
)
4146
return batch_id
4247

4348

4449
def insert_allocation(session, orderline_id, batch_id):
4550
session.execute(
46-
"INSERT INTO allocations (orderline_id, batch_id)"
47-
" VALUES (:orderline_id, :batch_id)",
51+
text(
52+
"INSERT INTO allocations (orderline_id, batch_id)"
53+
" VALUES (:orderline_id, :batch_id)"
54+
),
4855
dict(orderline_id=orderline_id, batch_id=batch_id),
4956
)
5057

tests/integration/test_uow.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
import pytest
2+
from sqlalchemy import text
23
from allocation.domain import model
34
from allocation.service_layer import unit_of_work
45

56

67
def insert_batch(session, ref, sku, qty, eta):
78
session.execute(
8-
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
9-
" VALUES (:ref, :sku, :qty, :eta)",
9+
text(
10+
"INSERT INTO batches (reference, sku, _purchased_quantity, eta)"
11+
" VALUES (:ref, :sku, :qty, :eta)"
12+
),
1013
dict(ref=ref, sku=sku, qty=qty, eta=eta),
1114
)
1215

1316

1417
def get_allocated_batch_ref(session, orderid, sku):
1518
[[orderlineid]] = session.execute(
16-
"SELECT id FROM order_lines WHERE orderid=:orderid AND sku=:sku",
19+
text("SELECT id FROM order_lines WHERE orderid=:orderid AND sku=:sku"),
1720
dict(orderid=orderid, sku=sku),
1821
)
1922
[[batchref]] = session.execute(
20-
"SELECT b.reference FROM allocations JOIN batches AS b ON batch_id = b.id"
21-
" WHERE orderline_id=:orderlineid",
23+
text(
24+
"SELECT b.reference FROM allocations JOIN batches AS b ON batch_id = b.id"
25+
" WHERE orderline_id=:orderlineid"
26+
),
2227
dict(orderlineid=orderlineid),
2328
)
2429
return batchref
@@ -54,7 +59,7 @@ def test_rolls_back_uncommitted_work_by_default(session_factory):
5459
insert_batch(uow.session, "batch1", "MEDIUM-PLINTH", 100, None)
5560
5661
new_session = session_factory()
57-
rows = list(new_session.execute('SELECT * FROM "batches"'))
62+
rows = list(new_session.execute(text('SELECT * FROM "batches"')))
5863
assert rows == []
5964
6065
@@ -69,6 +74,6 @@ class MyException(Exception):
6974
raise MyException()
7075
7176
new_session = session_factory()
72-
rows = list(new_session.execute('SELECT * FROM "batches"'))
77+
rows = list(new_session.execute(text('SELECT * FROM "batches"')))
7378
assert rows == []
7479
"""

0 commit comments

Comments
 (0)