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.