Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for SQLAlchemy dataclass-mapped tables #518

Merged
merged 10 commits into from
May 25, 2024

Conversation

barsa-net
Copy link
Contributor

Resolves #517

This hopefully add support for SQLAlchemy dataclass-mapped tables without breaking anything else

The following code should run without errors:

from typing import Optional

import sqlalchemy as sa
from sqlalchemy import String, create_engine, JSON
from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Session
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column

from serde import serde, from_dict
from serde.json import to_json


class Base(MappedAsDataclass, DeclarativeBase):
    pass


@serde
class User(Base):
    __tablename__ = "user"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    fullname: Mapped[str] = mapped_column(String(30))
    nickname: Mapped[Optional[str]]
    meta: Mapped[Optional[JSON]] = mapped_column(type_=JSON)


engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)

user = from_dict(User, {"id": 1, "name": "john", "fullname": "John Doe"})
with Session(engine) as session:
    session.add(user)
    session.commit()

    user = session.scalar(sa.select(User))

to_json(user)

Copy link

codecov bot commented Apr 25, 2024

Codecov Report

Attention: Patch coverage is 85.00000% with 3 lines in your changes are missing coverage. Please review.

Project coverage is 91.34%. Comparing base (fb93ed7) to head (1a9f937).
Report is 13 commits behind head on main.

Files Patch % Lines
serde/sqlalchemy.py 76.92% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #518      +/-   ##
==========================================
- Coverage   91.42%   91.34%   -0.08%     
==========================================
  Files          12       13       +1     
  Lines        1901     1919      +18     
  Branches      401      402       +1     
==========================================
+ Hits         1738     1753      +15     
- Misses        107      110       +3     
  Partials       56       56              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@barsa-net
Copy link
Contributor Author

I added only some simple tests at the moment, but reaching codecov target is unfeasible without bloat testing everything after except ImportError:
@yukinarit may I ask for some advices on what other cases than simples one should be covered by tests?

@barsa-net barsa-net force-pushed the sqlalchemy branch 2 times, most recently from 124ec10 to 31d457f Compare April 26, 2024 13:38
@yukinarit yukinarit self-requested a review April 29, 2024 01:32
Copy link
Owner

@yukinarit yukinarit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @barsa-net

Thank you for contributing to pyserde! 🙏

Please do the followings and the PR can be merged.

fullname: Mapped[str] = mapped_column(String(30))

user = User(1, "john", "John Doe")
assert user == de(User, se(user))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you run tests without sqlalchemy?

You can manually uninstall sqlalchemy and run tests here IMO
https://github.com/yukinarit/pyserde/blob/main/.github/workflows/test.yml#L32-L38

Copy link
Contributor Author

@barsa-net barsa-net Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure can do, but I have a unrelated doubt regarding https://github.com/yukinarit/pyserde/blob/main/.github/workflows/test.yml#L34
All tests are being run through poetry run ... while orjson is being installed (seemingly) outside the virtual enviroment with pip install orjson, it should be poetry install --extras orjson or do I miss something?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. This line had been added two years ago by this commit but apparently pyserde was never tested with orjson 🤣

@barsa-net barsa-net force-pushed the sqlalchemy branch 2 times, most recently from 217ce89 to 99ad356 Compare April 30, 2024 15:41
@barsa-net
Copy link
Contributor Author

barsa-net commented Apr 30, 2024

Just to make it clear and avoiding misunderstanding about the scope of this PR, SQLAlchemy is a HUGE project with countless ways to declare tables, at the moment I plan to add only "basic" support to declarative dataclass mapping.

As such, I suggest it should be annotated as an "experimental" feature, as some features at the moment don't work, e.g.:

  • @serde(type_check=strict) does nothing, no errors on wrong types, so I guess no type checking is being performed at Beartype level.
  • As SQLAlchemy want fields "annotated" with its mapped_column() function I'm unsure if it's even possible to make serde.core.field() and sqlalchemy.orm.mapped_column() working along each other, that means no field attributes.

Copy link
Owner

@yukinarit yukinarit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@yukinarit yukinarit added the enhancement New feature or request label May 4, 2024
@yukinarit yukinarit marked this pull request as ready for review May 7, 2024 05:57
@yukinarit
Copy link
Owner

@barsa-net is it ready for merge, or you would be adding some more changes?

@barsa-net
Copy link
Contributor Author

barsa-net commented May 7, 2024

Sorry, I have been busy those days.
I want to add a notice in Types docs about that is not feature complete (refer to my previous comment)
Also I'm trying something else but I don't know if it works at this time, I'll get in touch by the end of the week.

@barsa-net
Copy link
Contributor Author

Sorry for the delay, I added an additional test for nested SQLAlchemy models and I made clear in the documentation that the feature has to be considered experimental and as such some features could not work.

I consider the PR "complete", if I manage to get some other feature working together with SQLAlchemy I'll eventually open another PR.

@yukinarit yukinarit merged commit 1df7499 into yukinarit:main May 25, 2024
6 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for SQLAlchemy dataclass
2 participants