Skip to content

Commit

Permalink
docs: Add SQLAFactory docs
Browse files Browse the repository at this point in the history
  • Loading branch information
adhtruong committed Sep 17, 2023
1 parent 02babdd commit ad5a267
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 1 deletion.
23 changes: 23 additions & 0 deletions docs/examples/library_factories/sqlalchemy/test_example_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

from polyfactory.factories.sqlalchemy_factory import SQLAlchemyFactory


class Base(DeclarativeBase):
...


class Author(Base):
__tablename__ = "authors"

id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]


class AuthorFactory(SQLAlchemyFactory[Author]):
__model__ = Author


def test_sqla_factory() -> None:
author = AuthorFactory.build()
assert isinstance(author, Author)
46 changes: 46 additions & 0 deletions docs/examples/library_factories/sqlalchemy/test_example_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from typing import List

from sqlalchemy import ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship

from polyfactory.factories.sqlalchemy_factory import SQLAlchemyFactory


class Base(DeclarativeBase):
...


class Author(Base):
__tablename__ = "authors"

id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]

books: Mapped[List["Book"]] = relationship("Book", uselist=True)


class Book(Base):
__tablename__ = "books"

id: Mapped[int] = mapped_column(primary_key=True)
author_id: Mapped[int] = mapped_column(ForeignKey(Author.id))


class AuthorFactory(SQLAlchemyFactory[Author]):
__model__ = Author


class AuthorFactoryWithRelationship(SQLAlchemyFactory[Author]):
__model__ = Author
__set_relationships__ = True


def test_sqla_factory_without_relationship() -> None:
author = AuthorFactory.build()
assert author.books == []


def test_sqla_factory() -> None:
author = AuthorFactoryWithRelationship.build()
assert isinstance(author, Author)
assert isinstance(author.books[0], Book)
43 changes: 43 additions & 0 deletions docs/examples/library_factories/sqlalchemy/test_example_3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from typing import List

from sqlalchemy import ForeignKey, create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column, relationship

from polyfactory.factories.sqlalchemy_factory import SQLAlchemyFactory


class Base(DeclarativeBase):
...


class Author(Base):
__tablename__ = "authors"

id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]

books: Mapped[List["Book"]] = relationship("Book", uselist=True)


class Book(Base):
__tablename__ = "books"

id: Mapped[int] = mapped_column(primary_key=True)
author_id: Mapped[int] = mapped_column(ForeignKey(Author.id))


class AuthorFactory(SQLAlchemyFactory[Author]):
__model__ = Author
__set_relationships__ = True


def test_sqla_factory_persistence() -> None:
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
session = Session(engine)

AuthorFactory.__session__ = session # Or using a callable that returns a session

author = AuthorFactory.create_sync()
assert author.id is not None
assert author.id == author.books[0].author_id
2 changes: 1 addition & 1 deletion docs/usage/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Usage Guide
:titlesonly:
:maxdepth: 1

library_factories
library_factories/index
declaring_factories
configuration
fields
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,9 @@ These include:

.. note::
We will be adding additional factories to this package, so make sure to checkout the above list from time to time.


.. toctree::
:maxdepth: 1

sqlalchemy_factory
39 changes: 39 additions & 0 deletions docs/usage/library_factories/sqlalchemy_factory.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
SQLAlchemyFactory
===================

Basic usage is like other factories

.. literalinclude:: /examples/library_factories/sqlalchemy/test_example_1.py
:caption: Declaring a factory for a SQLAlchemy model
:language: python

Configurations
------------------------------

By default, relationships will not be set. This can be overridden via ``__set_relationships__``.

.. literalinclude:: /examples/library_factories/sqlalchemy/test_example_2.py
:caption: Setting relationships
:language: python

.. note::
In general, foreign keys are not automatically generated by ``.build``. This can be resolved by setting the fields yourself and/or using ``create_sync``/ ``create_async`` so models can be added to a SQLA session so these are set.


Persistence
------------------------------

A handler is provided to allow persistence. This can be used by setting ``__session__`` attribute on a factory.

.. literalinclude:: /examples/library_factories/sqlalchemy/test_example_3.py
:caption: Using persistence
:language: python

By default, this will add generated models to the session and then commit. This can be customised further by setting ``__sync_persistence__``.

Similarly for ``__async_session__`` and ``create_async``.


API reference
------------------------------
Full API docs are available :class:`here <polyfactory.factories.sqlalchemy_factory.SQLAlchemyFactory>`.

0 comments on commit ad5a267

Please sign in to comment.