strawberry-sqlalchemy-mapper


Namestrawberry-sqlalchemy-mapper JSON
Version 0.4.2 PyPI version JSON
download
home_pagehttps://strawberry.rocks/
SummaryA library for autogenerating Strawberry GraphQL types from SQLAlchemy models.
upload_time2023-12-29 21:02:19
maintainer
docs_urlNone
authorTim Dumol
requires_python>=3.8,<4.0
licenseMIT
keywords graphql sqlalchemy strawberry
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            # strawberry-sqlalchemy-mapper


Strawberry-sqlalchemy-mapper is the simplest way to implement autogenerated strawberry types for columns and relationships in SQLAlchemy models.


- Instead of manually listing every column and relationship in a SQLAlchemy model, strawberry-sqlalchemy-mapper
lets you decorate a class declaration and it will automatically generate the necessary strawberry fields
for all columns and relationships (subject to the limitations below) in the given model.

- Native support for most of SQLAlchemy's most common types.
- Extensible to arbitrary custom SQLAlchemy types.
- Automatic batching of queries, avoiding N+1 queries when getting relationships
- Support for SQLAlchemy >=1.4.x
- Lightweight and fast.

## Getting Started

strawberry-sqlalchemy-mapper is available on [PyPi](https://pypi.org/project/strawberry-sqlalchemy-mapper/)

```
pip install strawberry-sqlalchemy-mapper
```


First, define your sqlalchemy model:

```python
# models.py
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Employee(Base):
    __tablename__ = "employee"
    id = Column(UUID, primary_key=True)
    name = Column(String, nullable=False)
    password_hash = Column(String, nullable=False)
    department_id = Column(UUID, ForeignKey("department.id"))
    department = relationship("Department", back_populates="employees")


class Department(Base):
    __tablename__ = "department"
    id = Column(UUID, primary_key=True)
    name = Column(String, nullable=False)
    employees = relationship("Employee", back_populates="department")
```

Next, decorate a type with `strawberry_sqlalchemy_mapper.type()`
to register it as a strawberry type for the given SQLAlchemy model.
This will automatically add fields for the model's columns, relationships, association proxies,
and hybrid properties. For example:

```python
# elsewhere
# ...
from strawberry_sqlalchemy_mapper import StrawberrySQLAlchemyMapper

strawberry_sqlalchemy_mapper = StrawberrySQLAlchemyMapper()


@strawberry_sqlalchemy_mapper.type(models.Employee)
class Employee:
    __exclude__ = ["password_hash"]


@strawberry_sqlalchemy_mapper.type(models.Department)
class Department:
    pass


@strawberry.type
class Query:
    @strawberry.field
    def departments(self):
        return db.session.scalars(select(models.Department)).all()


# context is expected to have an instance of StrawberrySQLAlchemyLoader
class CustomGraphQLView(GraphQLView):
    def get_context(self):
        return {
            "sqlalchemy_loader": StrawberrySQLAlchemyLoader(bind=YOUR_SESSION),
        }


# call finalize() before using the schema:
# (note that models that are related to models that are in the schema
# are automatically mapped at this stage -- e.g., Department is mapped
# because employee.department is a relationshp to Department)
strawberry_sqlalchemy_mapper.finalize()
# only needed if you have polymorphic types
additional_types = list(strawberry_sqlalchemy_mapper.mapped_types.values())
schema = strawberry.Schema(
    query=Query,
    mutation=Mutation,
    extensions=extensions,
    types=additional_types,
)

# You can now query, e.g.:
"""
query {
    departments {
        id
        name
        employees {
            edge {
                node {
                    id
                    name
                    department {
                        # Just an example of nested relationships
                        id
                        name
                    }
                }
            }
        }
    }
}
"""
```

## Limitations

SQLAlchemy Models -> Strawberry Types and Interfaces are expected to have a consistent
(customizable) naming convention. These can be configured by passing `model_to_type_name`
and `model_to_interface_name` when constructing the mapper.

Natively supports the following SQLAlchemy types:

```python
Integer: int,
Float: float,
BigInteger: BigInt,
Numeric: Decimal,
DateTime: datetime,
Date: date,
Time: time,
String: str,
Text: str,
Boolean: bool,
Unicode: str,
UnicodeText: str,
SmallInteger: int,
SQLAlchemyUUID: uuid.UUID,
VARCHAR: str,
ARRAY[T]: List[T] # PostgreSQL array
JSON: JSON # SQLAlchemy JSON
Enum: (the Python enum it is mapped to, which should be @strawberry.enum-decorated)
```

Additional types can be supported by passing `extra_sqlalchemy_type_to_strawberry_type_map`,
although support for `TypeDecorator` types is untested.

Association proxies are expected to be of the form `association_proxy('relationship1', 'relationship2')`,
i.e., both properties are expected to be relationships.

Roots of polymorphic hierarchies **are supported**, but are also expected to be registered via
`strawberry_sqlalchemy_mapper.interface()`, and its concrete type and
its descendants are expected to inherit from the interface:

```python
class Book(Model):
    id = Column(UUID, primary_key=True)


class Novel(Book):
    pass


class ShortStory(Book):
    pass


# in another file
strawberry_sqlalchemy_mapper = StrawberrySQLAlchemyMapper()


@strawberry_sqlalchemy_mapper.interface(models.Book)
class BookInterface:
    pass


@strawberry_sqlalchemy_mapper.type(models.Book)
class Book:
    pass


@strawberry_sqlalchemy_mapper.type(models.Novel)
class Novel:
    pass


@strawberry_sqlalchemy_mapper.type(models.ShortStory)
class ShortStory:
    pass
```

## Contributing

We encourage you to contribute to strawberry-sqlalchemy-mapper! Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. Don't forget to give the project a star! Thanks again!

1. Fork the Project
2. Create your Feature Branch (git checkout -b feature)
3. Commit your Changes (git commit -m 'Add some feature')
4. Push to the Branch (git push origin feature)
5. Open a Pull Request


### Prerequisites

This project uses `pre-commit`_, please make sure to install it before making any
changes::

    pip install pre-commit
    cd strawberry-sqlalchemy-mapper
    pre-commit install

It is a good idea to update the hooks to the latest version::

    pre-commit autoupdate

Don't forget to tell your contributors to also install and use pre-commit.

### Installation

```bash
pip install -r requirements.txt
```

Install [PostgreSQL 14+](https://www.postgresql.org/download/)

### Test

```bash
pytest
```

## ⚖️ LICENSE

MIT © [strawberry-sqlalchemy-mapper](LICENSE.txt)

            

Raw data

            {
    "_id": null,
    "home_page": "https://strawberry.rocks/",
    "name": "strawberry-sqlalchemy-mapper",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "graphql,sqlalchemy,strawberry",
    "author": "Tim Dumol",
    "author_email": "tim@timdumol.com",
    "download_url": "https://files.pythonhosted.org/packages/c1/39/199e8040938425f28596eebee8f8e6100d2316c2ea2d065b346a0d9db96a/strawberry_sqlalchemy_mapper-0.4.2.tar.gz",
    "platform": null,
    "description": "# strawberry-sqlalchemy-mapper\n\n\nStrawberry-sqlalchemy-mapper is the simplest way to implement autogenerated strawberry types for columns and relationships in SQLAlchemy models.\n\n\n- Instead of manually listing every column and relationship in a SQLAlchemy model, strawberry-sqlalchemy-mapper\nlets you decorate a class declaration and it will automatically generate the necessary strawberry fields\nfor all columns and relationships (subject to the limitations below) in the given model.\n\n- Native support for most of SQLAlchemy's most common types.\n- Extensible to arbitrary custom SQLAlchemy types.\n- Automatic batching of queries, avoiding N+1 queries when getting relationships\n- Support for SQLAlchemy >=1.4.x\n- Lightweight and fast.\n\n## Getting Started\n\nstrawberry-sqlalchemy-mapper is available on [PyPi](https://pypi.org/project/strawberry-sqlalchemy-mapper/)\n\n```\npip install strawberry-sqlalchemy-mapper\n```\n\n\nFirst, define your sqlalchemy model:\n\n```python\n# models.py\nfrom sqlalchemy import Column, Integer, String\nfrom sqlalchemy.ext.declarative import declarative_base\n\nBase = declarative_base()\n\n\nclass Employee(Base):\n    __tablename__ = \"employee\"\n    id = Column(UUID, primary_key=True)\n    name = Column(String, nullable=False)\n    password_hash = Column(String, nullable=False)\n    department_id = Column(UUID, ForeignKey(\"department.id\"))\n    department = relationship(\"Department\", back_populates=\"employees\")\n\n\nclass Department(Base):\n    __tablename__ = \"department\"\n    id = Column(UUID, primary_key=True)\n    name = Column(String, nullable=False)\n    employees = relationship(\"Employee\", back_populates=\"department\")\n```\n\nNext, decorate a type with `strawberry_sqlalchemy_mapper.type()`\nto register it as a strawberry type for the given SQLAlchemy model.\nThis will automatically add fields for the model's columns, relationships, association proxies,\nand hybrid properties. For example:\n\n```python\n# elsewhere\n# ...\nfrom strawberry_sqlalchemy_mapper import StrawberrySQLAlchemyMapper\n\nstrawberry_sqlalchemy_mapper = StrawberrySQLAlchemyMapper()\n\n\n@strawberry_sqlalchemy_mapper.type(models.Employee)\nclass Employee:\n    __exclude__ = [\"password_hash\"]\n\n\n@strawberry_sqlalchemy_mapper.type(models.Department)\nclass Department:\n    pass\n\n\n@strawberry.type\nclass Query:\n    @strawberry.field\n    def departments(self):\n        return db.session.scalars(select(models.Department)).all()\n\n\n# context is expected to have an instance of StrawberrySQLAlchemyLoader\nclass CustomGraphQLView(GraphQLView):\n    def get_context(self):\n        return {\n            \"sqlalchemy_loader\": StrawberrySQLAlchemyLoader(bind=YOUR_SESSION),\n        }\n\n\n# call finalize() before using the schema:\n# (note that models that are related to models that are in the schema\n# are automatically mapped at this stage -- e.g., Department is mapped\n# because employee.department is a relationshp to Department)\nstrawberry_sqlalchemy_mapper.finalize()\n# only needed if you have polymorphic types\nadditional_types = list(strawberry_sqlalchemy_mapper.mapped_types.values())\nschema = strawberry.Schema(\n    query=Query,\n    mutation=Mutation,\n    extensions=extensions,\n    types=additional_types,\n)\n\n# You can now query, e.g.:\n\"\"\"\nquery {\n    departments {\n        id\n        name\n        employees {\n            edge {\n                node {\n                    id\n                    name\n                    department {\n                        # Just an example of nested relationships\n                        id\n                        name\n                    }\n                }\n            }\n        }\n    }\n}\n\"\"\"\n```\n\n## Limitations\n\nSQLAlchemy Models -> Strawberry Types and Interfaces are expected to have a consistent\n(customizable) naming convention. These can be configured by passing `model_to_type_name`\nand `model_to_interface_name` when constructing the mapper.\n\nNatively supports the following SQLAlchemy types:\n\n```python\nInteger: int,\nFloat: float,\nBigInteger: BigInt,\nNumeric: Decimal,\nDateTime: datetime,\nDate: date,\nTime: time,\nString: str,\nText: str,\nBoolean: bool,\nUnicode: str,\nUnicodeText: str,\nSmallInteger: int,\nSQLAlchemyUUID: uuid.UUID,\nVARCHAR: str,\nARRAY[T]: List[T] # PostgreSQL array\nJSON: JSON # SQLAlchemy JSON\nEnum: (the Python enum it is mapped to, which should be @strawberry.enum-decorated)\n```\n\nAdditional types can be supported by passing `extra_sqlalchemy_type_to_strawberry_type_map`,\nalthough support for `TypeDecorator` types is untested.\n\nAssociation proxies are expected to be of the form `association_proxy('relationship1', 'relationship2')`,\ni.e., both properties are expected to be relationships.\n\nRoots of polymorphic hierarchies **are supported**, but are also expected to be registered via\n`strawberry_sqlalchemy_mapper.interface()`, and its concrete type and\nits descendants are expected to inherit from the interface:\n\n```python\nclass Book(Model):\n    id = Column(UUID, primary_key=True)\n\n\nclass Novel(Book):\n    pass\n\n\nclass ShortStory(Book):\n    pass\n\n\n# in another file\nstrawberry_sqlalchemy_mapper = StrawberrySQLAlchemyMapper()\n\n\n@strawberry_sqlalchemy_mapper.interface(models.Book)\nclass BookInterface:\n    pass\n\n\n@strawberry_sqlalchemy_mapper.type(models.Book)\nclass Book:\n    pass\n\n\n@strawberry_sqlalchemy_mapper.type(models.Novel)\nclass Novel:\n    pass\n\n\n@strawberry_sqlalchemy_mapper.type(models.ShortStory)\nclass ShortStory:\n    pass\n```\n\n## Contributing\n\nWe encourage you to contribute to strawberry-sqlalchemy-mapper! Any contributions you make are greatly appreciated.\n\nIf you have a suggestion that would make this better, please fork the repo and create a pull request. Don't forget to give the project a star! Thanks again!\n\n1. Fork the Project\n2. Create your Feature Branch (git checkout -b feature)\n3. Commit your Changes (git commit -m 'Add some feature')\n4. Push to the Branch (git push origin feature)\n5. Open a Pull Request\n\n\n### Prerequisites\n\nThis project uses `pre-commit`_, please make sure to install it before making any\nchanges::\n\n    pip install pre-commit\n    cd strawberry-sqlalchemy-mapper\n    pre-commit install\n\nIt is a good idea to update the hooks to the latest version::\n\n    pre-commit autoupdate\n\nDon't forget to tell your contributors to also install and use pre-commit.\n\n### Installation\n\n```bash\npip install -r requirements.txt\n```\n\nInstall [PostgreSQL 14+](https://www.postgresql.org/download/)\n\n### Test\n\n```bash\npytest\n```\n\n## \u2696\ufe0f LICENSE\n\nMIT \u00a9 [strawberry-sqlalchemy-mapper](LICENSE.txt)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A library for autogenerating Strawberry GraphQL types from SQLAlchemy models.",
    "version": "0.4.2",
    "project_urls": {
        "Changelog": "https://strawberry.rocks/changelog",
        "Discord": "https://discord.com/invite/3uQ2PaY",
        "Documentation": "https://strawberry.rocks/",
        "Homepage": "https://strawberry.rocks/",
        "Mastodon": "https://farbun.social/@strawberry",
        "Repository": "https://github.com/strawberry-graphql/strawberry-sqlalchemy",
        "Sponsor on GitHub": "https://github.com/sponsors/strawberry-graphql",
        "Sponsor on Open Collective": "https://opencollective.com/strawberry-graphql",
        "Twitter": "https://twitter.com/strawberry_gql"
    },
    "split_keywords": [
        "graphql",
        "sqlalchemy",
        "strawberry"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2f3d35bfeb944adae8d5b0d2bc33ba74acaea5051675f0dd0f9ad5f8a95cca3e",
                "md5": "3d220815de9e6e9641b7c5e2da16c5bf",
                "sha256": "e8375d1173d8604117ea6e8f0212201000815d9150cf475e05f6bc658e7ecc10"
            },
            "downloads": -1,
            "filename": "strawberry_sqlalchemy_mapper-0.4.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3d220815de9e6e9641b7c5e2da16c5bf",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 23813,
            "upload_time": "2023-12-29T21:02:18",
            "upload_time_iso_8601": "2023-12-29T21:02:18.093703Z",
            "url": "https://files.pythonhosted.org/packages/2f/3d/35bfeb944adae8d5b0d2bc33ba74acaea5051675f0dd0f9ad5f8a95cca3e/strawberry_sqlalchemy_mapper-0.4.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c139199e8040938425f28596eebee8f8e6100d2316c2ea2d065b346a0d9db96a",
                "md5": "8f22c6c63865a644431c5d9243f288f8",
                "sha256": "7cc7a676b363eafdd14c5aaf4d9b17af440d386919bad7caa996971543d0f029"
            },
            "downloads": -1,
            "filename": "strawberry_sqlalchemy_mapper-0.4.2.tar.gz",
            "has_sig": false,
            "md5_digest": "8f22c6c63865a644431c5d9243f288f8",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 24388,
            "upload_time": "2023-12-29T21:02:19",
            "upload_time_iso_8601": "2023-12-29T21:02:19.238568Z",
            "url": "https://files.pythonhosted.org/packages/c1/39/199e8040938425f28596eebee8f8e6100d2316c2ea2d065b346a0d9db96a/strawberry_sqlalchemy_mapper-0.4.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-12-29 21:02:19",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "strawberry-graphql",
    "github_project": "strawberry-sqlalchemy",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "tox": true,
    "lcname": "strawberry-sqlalchemy-mapper"
}
        
Elapsed time: 0.17466s