you can create this using a custom callable for the actual composite type, where you would be bypassing the new-style annotations and dataclass detection part of things and relying on the older style of declaration. You'd add a composite_values to your dataclass as well and just use the old style
import dataclasses
from sqlalchemy import create_engine
from sqlalchemy import Integer
from sqlalchemy import select
from sqlalchemy.orm import composite
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import Session
@dataclasses.dataclass
class Point:
x: int | None
y: int | None
def __composite_values__(self):
return (self.x, self.y)
class Base(DeclarativeBase):
pass
def nullable_point(x, y):
if x is None and y is None:
return None
else:
return Point(x, y)
class Vertex(Base):
__tablename__ = "vertices"
id: Mapped[int] = mapped_column(primary_key=True)
nullable_point,
mapped_column("x1", Integer, nullable=True),
mapped_column("y1", Integer, nullable=True),
nullable_point,
mapped_column("x2", Integer, nullable=True),
mapped_column("y2", Integer, nullable=True),
)
def __repr__(self):
return f"Vertex(start={self.start}, end={self.end})"
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
s.add_all(
[
Vertex(start=Point(5, 10)),
Vertex(start=Point(10, None), end=Point(25, 17)),
]
)
s.commit()
for v in s.scalars(select(Vertex)):
print(f"{v.start} {v.end}")
Much thanks!
Jens
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
---
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.