Skip to content

Commit e5ee452

Browse files
Properly model nullable relationships (#370)
* Fixes [302](#302) * Disallow mapped_columns for SQLModels codegen * Disallow mapped_columns for SQLModels codegen * Ensure SQLModel is installed as part of the test-suite * PR Fixes * Update src/sqlacodegen/generators.py Co-authored-by: Alex Grönholm <[email protected]> * PR Fixes * PR Fixes * Further PR Fixes * Further PR Fixes * Further PR Fixes * Typo fix * PR FIx * PR FIx * Fix Enum rendering * Fix bad commit * Added new changes to CHANGES.rst * Support optional relationships * Support optional relationships * Fix all tests * PR Fixes * PR Fixes * Update CHANGES.rst Co-authored-by: Alex Grönholm <[email protected]> * Update src/sqlacodegen/generators.py Co-authored-by: Alex Grönholm <[email protected]> --------- Co-authored-by: Alex Grönholm <[email protected]>
1 parent 0b404d2 commit e5ee452

File tree

4 files changed

+27
-21
lines changed

4 files changed

+27
-21
lines changed

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Version history
33

44
**UNRELEASED**
55

6+
- Changed nullable relationships to include ``Optional`` in their type annotations
67
- Dropped support for Python 3.8
78
- Fixed SQLModel code generation
89
- Fixed two rendering issues in ``ENUM`` columns when a non-default schema is used: an

src/sqlacodegen/generators.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,11 @@ def render_join(terms: list[JoinType]) -> str:
13061306
RelationshipType.MANY_TO_ONE,
13071307
):
13081308
relationship_type = f"'{relationship.target.name}'"
1309+
if relationship.constraint and any(
1310+
col.nullable for col in relationship.constraint.columns
1311+
):
1312+
self.add_literal_import("typing", "Optional")
1313+
relationship_type = f"Optional[{relationship_type}]"
13091314
elif relationship.type == RelationshipType.MANY_TO_MANY:
13101315
self.add_literal_import("typing", "List")
13111316
relationship_type = f"List['{relationship.target.name}']"

tests/test_generator_dataclass.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class SimpleItems(Base):
127127
container_id: Mapped[Optional[int]] = \
128128
mapped_column(ForeignKey('simple_containers.id'))
129129
130-
container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \
130+
container: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \
131131
back_populates='simple_items')
132132
""",
133133
)
@@ -237,7 +237,7 @@ class SimpleItems(Base):
237237
id: Mapped[int] = mapped_column(Integer, primary_key=True)
238238
container_id: Mapped[Optional[int]] = mapped_column(Integer)
239239
240-
container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \
240+
container: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \
241241
back_populates='simple_items')
242242
""",
243243
)

tests/test_generator_declarative.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ class SimpleItems(Base):
148148
container_id: Mapped[Optional[int]] = \
149149
mapped_column(ForeignKey('simple_containers.id'))
150150
151-
container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \
151+
container: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \
152152
back_populates='simple_items')
153153
""",
154154
)
@@ -182,7 +182,7 @@ class SimpleItems(Base):
182182
parent_item_id: Mapped[Optional[int]] = \
183183
mapped_column(ForeignKey('simple_items.id'))
184184
185-
parent_item: Mapped['SimpleItems'] = relationship('SimpleItems', \
185+
parent_item: Mapped[Optional['SimpleItems']] = relationship('SimpleItems', \
186186
remote_side=[id], back_populates='parent_item_reverse')
187187
parent_item_reverse: Mapped[List['SimpleItems']] = relationship('SimpleItems', \
188188
remote_side=[parent_item_id], back_populates='parent_item')
@@ -221,12 +221,12 @@ class SimpleItems(Base):
221221
mapped_column(ForeignKey('simple_items.id'))
222222
top_item_id: Mapped[Optional[int]] = mapped_column(ForeignKey('simple_items.id'))
223223
224-
parent_item: Mapped['SimpleItems'] = relationship('SimpleItems', \
224+
parent_item: Mapped[Optional['SimpleItems']] = relationship('SimpleItems', \
225225
remote_side=[id], foreign_keys=[parent_item_id], back_populates='parent_item_reverse')
226226
parent_item_reverse: Mapped[List['SimpleItems']] = relationship('SimpleItems', \
227227
remote_side=[parent_item_id], foreign_keys=[parent_item_id], \
228228
back_populates='parent_item')
229-
top_item: Mapped['SimpleItems'] = relationship('SimpleItems', remote_side=[id], \
229+
top_item: Mapped[Optional['SimpleItems']] = relationship('SimpleItems', remote_side=[id], \
230230
foreign_keys=[top_item_id], back_populates='top_item_reverse')
231231
top_item_reverse: Mapped[List['SimpleItems']] = relationship('SimpleItems', \
232232
remote_side=[top_item_id], foreign_keys=[top_item_id], back_populates='top_item')
@@ -289,7 +289,7 @@ class SimpleItems(Base):
289289
container_id1: Mapped[Optional[int]] = mapped_column(Integer)
290290
container_id2: Mapped[Optional[int]] = mapped_column(Integer)
291291
292-
simple_containers: Mapped['SimpleContainers'] = relationship('SimpleContainers', \
292+
simple_containers: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \
293293
back_populates='simple_items')
294294
""",
295295
)
@@ -301,7 +301,7 @@ def test_onetomany_multiref(generator: CodeGenerator) -> None:
301301
generator.metadata,
302302
Column("id", INTEGER, primary_key=True),
303303
Column("parent_container_id", INTEGER),
304-
Column("top_container_id", INTEGER),
304+
Column("top_container_id", INTEGER, nullable=False),
305305
ForeignKeyConstraint(["parent_container_id"], ["simple_containers.id"]),
306306
ForeignKeyConstraint(["top_container_id"], ["simple_containers.id"]),
307307
)
@@ -338,12 +338,12 @@ class SimpleItems(Base):
338338
__tablename__ = 'simple_items'
339339
340340
id: Mapped[int] = mapped_column(Integer, primary_key=True)
341-
parent_container_id: Mapped[Optional[int]] = \
341+
top_container_id: Mapped[int] = \
342342
mapped_column(ForeignKey('simple_containers.id'))
343-
top_container_id: Mapped[Optional[int]] = \
343+
parent_container_id: Mapped[Optional[int]] = \
344344
mapped_column(ForeignKey('simple_containers.id'))
345345
346-
parent_container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \
346+
parent_container: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \
347347
foreign_keys=[parent_container_id], back_populates='simple_items')
348348
top_container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \
349349
foreign_keys=[top_container_id], back_populates='simple_items_')
@@ -383,7 +383,7 @@ class OtherItems(Base):
383383
384384
id: Mapped[int] = mapped_column(Integer, primary_key=True)
385385
386-
simple_items: Mapped['SimpleItems'] = relationship('SimpleItems', uselist=False, \
386+
simple_items: Mapped[Optional['SimpleItems']] = relationship('SimpleItems', uselist=False, \
387387
back_populates='other_item')
388388
389389
@@ -394,7 +394,7 @@ class SimpleItems(Base):
394394
other_item_id: Mapped[Optional[int]] = \
395395
mapped_column(ForeignKey('other_items.id'), unique=True)
396396
397-
other_item: Mapped['OtherItems'] = relationship('OtherItems', \
397+
other_item: Mapped[Optional['OtherItems']] = relationship('OtherItems', \
398398
back_populates='simple_items')
399399
""",
400400
)
@@ -437,7 +437,7 @@ class Oglkrogk(Base):
437437
id: Mapped[int] = mapped_column(Integer, primary_key=True)
438438
fehwiuhfiwID: Mapped[Optional[int]] = mapped_column(ForeignKey('fehwiuhfiw.id'))
439439
440-
fehwiuhfiw: Mapped['Fehwiuhfiw'] = \
440+
fehwiuhfiw: Mapped[Optional['Fehwiuhfiw']] = \
441441
relationship('Fehwiuhfiw', back_populates='oglkrogk')
442442
""",
443443
)
@@ -487,7 +487,7 @@ class SimpleItems(Base):
487487
container_id: Mapped[Optional[int]] = \
488488
mapped_column(ForeignKey('simple_containers.id'))
489489
490-
container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \
490+
container: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \
491491
back_populates='simple_items')
492492
""",
493493
)
@@ -531,7 +531,7 @@ class SimpleItems(Base):
531531
relationship_id: Mapped[Optional[int]] = \
532532
mapped_column(ForeignKey('relationship.id'))
533533
534-
relationship_: Mapped['Relationship'] = relationship('Relationship', \
534+
relationship_: Mapped[Optional['Relationship']] = relationship('Relationship', \
535535
back_populates='simple_items')
536536
""",
537537
)
@@ -577,7 +577,7 @@ class SimpleItems(Base):
577577
container_id: Mapped[Optional[int]] = \
578578
mapped_column(ForeignKey('simple_containers.id'))
579579
580-
container: Mapped['SimpleContainers'] = relationship('SimpleContainers')
580+
container: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers')
581581
""",
582582
)
583583

@@ -994,7 +994,7 @@ class {class_name.capitalize()}(Base):
994994
995995
id: Mapped[int] = mapped_column(Integer, primary_key=True)
996996
997-
simple_item: Mapped['SimpleItem'] = relationship('SimpleItem', uselist=False, \
997+
simple_item: Mapped[Optional['SimpleItem']] = relationship('SimpleItem', uselist=False, \
998998
back_populates='{relationship_name}')
999999
10001000
@@ -1005,7 +1005,7 @@ class SimpleItem(Base):
10051005
{relationship_name}_id: Mapped[Optional[int]] = \
10061006
mapped_column(ForeignKey('{table_name}.id'), unique=True)
10071007
1008-
{relationship_name}: Mapped['{class_name.capitalize()}'] = \
1008+
{relationship_name}: Mapped[Optional['{class_name.capitalize()}']] = \
10091009
relationship('{class_name.capitalize()}', back_populates='simple_item')
10101010
""",
10111011
)
@@ -1117,7 +1117,7 @@ class SimpleItems(Base):
11171117
other_item_id: Mapped[Optional[int]] = \
11181118
mapped_column(ForeignKey('otherschema.other_items.id'))
11191119
1120-
other_item: Mapped['OtherItems'] = relationship('OtherItems', \
1120+
other_item: Mapped[Optional['OtherItems']] = relationship('OtherItems', \
11211121
back_populates='simple_items')
11221122
""",
11231123
)
@@ -1472,7 +1472,7 @@ class SimpleItems(Base):
14721472
id: Mapped[int] = mapped_column(Integer, primary_key=True)
14731473
container_id: Mapped[Optional[int]] = mapped_column(Integer)
14741474
1475-
container: Mapped['SimpleContainers'] = relationship('SimpleContainers', \
1475+
container: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \
14761476
back_populates='simple_items')
14771477
""",
14781478
)

0 commit comments

Comments
 (0)