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

Alternate serialization plugin protocol that leverages DTOs #1501

Merged
merged 104 commits into from
Apr 21, 2023

Conversation

peterschutt
Copy link
Contributor

@peterschutt peterschutt commented Apr 16, 2023

This PR re-implements the SerializationPluginProtocol to leverage the DTOInterface protocol.

If a handler defines a plugin supported type as either the data kwarg type annotation, or as the return annotation for a handler function, and no DTO has otherwise been resolved to handle the type, the protocol creates a DTO implementation to represent that type which is then used to de-serialize into, and serialize from instances of that supported type.

Additionally this PR:

  • removes the starlite v1 SerializationPluginProtocol and associated handling.
  • removes the SQLAlchemy 1 contrib
  • temporarily removes the Piccolo and Tortoise ORM plugin implementations and docs, these are to be re-implemented in the new format (tracked in DTO Factory: piccolo implementation #1533 and DTO Factory: tortoise implementation #1555).
  • adds a new SQLAlchemy tutorial to demonstrate using the SQLAlchemy plugins (WIP).

Pull Request Checklist

  • New code has 100% test coverage
  • (If applicable) The prose documentation has been updated to reflect the changes introduced by this PR
  • (If applicable) The reference documentation has been updated to reflect the changes introduced by this PR

By submitting this issue, you agree to:

Description

Close Issue(s)

# Conflicts:
#	tests/conftest.py
This allows us to enforce how invariants are calculated and set on the type
from the annotation.
This allows the dto type to leverage the logic on the `ParsedType` object.
This means that related classes can remain inside `if TYPE_CHECKING` block in
a module where they are declared as a relationship to another orm class.
Pydantic timestamp parsed as date returns UTC date, while cattrs implementation was returning local date.

Correct issue in tests where UTC date were compared to local dates.

Closes #1491
This makes a single `AbstractDTOFactory` type much more versatile, making it
able to handle both scalar and collection annotations of the narrowed type.

Factory `on_registration()` callback receives the handler, and the annotation
it should represent and builds a dto backend for each annotation and config
that it encounters during route registration.

We also simplify the logic by being more restrictive, throwing errors for
handlers annotated with `AbstractDTOFactory` subtypes, non-homogeneous
collection type annotations, and being narrowed with union types. All things
that we may choose to support, but best to wait for someone to come knocking
with a concrete use-case.
This PR includes refactorings to better integrate DTO encoding with existing
serialization patterns, and modifications to the interface to better support
integration with websocket handlers.

# DTOInterface constructor methods

`from_connection()` reverted back to `from_bytes()`, and receives both the
already awaited raw data from the payload, and the connection instance.

Now that `from_bytes()` receives the raw payload data, already extracted from
the connection, it no longer needs to be an async method, improving symmetry
with the `from_data()` constructor method.

`from_data()` now also receives the connection instance, which further
improves symmetry between the two constructor methods.

# Data extraction methods

The `to_encodable_type()` method no longer receives the connection (this isn't
required any more as the constructor methods receive it, and so it can be
stored on the instance to be accessed in this method if it is required by an
implementation).

# serialization.py

An encoding hook has been added for serialization of DTO instances, so DTO
instances can be processed through the usual channel. This wraps any raw
bytes returned from the DTO in `msgspec.Raw`, which nicely resolves an earlier
issue encountered when trying to build this pattern.

These changes are based on discussion in discord development channel on April
14.
If annotated type is supported by the plugin, and no DTO is otherwise defined,
the plugin creates an `AbstractDTOFactory` type for the model type and
assigns it to the handler.

Only one DTO type is generated per model type, which is cached by the plugin
and used anytime that model is encountered by the plugin.

This is intended to replace `SerializationPluginProtocol`, however, I've
implemented it using the name `DTOSerializationPluginProtocol` and left all
the other plugin implementation handling in place in order to ease initial
reviews of the implementation.
@peterschutt peterschutt requested a review from a team as a code owner April 16, 2023 05:38
This is to make the interface more resilient to changes over time, as it is easier to
add attributes to the context object in a non-breaking fashion, compared to changing
function arguments.
This is no longer a feature supported by the framework.
Backend instances are instantiated directly with `BackendContext` object.
The `max_nested_depth` parameter will put a limit on self recursive models anyway,
and so I'd rather a use-case pop up for this before we bother with an implementation
for it.
This is received by the dto on instantiation and carries pertinent information about
the current connection.

Both `HandlerContext` and `ConnectionContext` receive `handler_id` instead of
`route_handler` and `connection` respectively.
Makes all attributes `Final`.
# Conflicts:
#	docs/reference/contrib/index.rst
#	docs/reference/contrib/sqlalchemy/index.rst
#	docs/usage/plugins/sqlalchemy.rst
#	litestar/handlers/http_handlers/_utils.py
Base automatically changed from dto-factory to main April 21, 2023 06:03
@sonarcloud
Copy link

sonarcloud bot commented Apr 21, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

100.0% 100.0% Coverage
0.0% 0.0% Duplication

@peterschutt peterschutt merged commit 899be0a into main Apr 21, 2023
@peterschutt peterschutt deleted the sqlalchemy-plugin branch April 21, 2023 06:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants