jdkandersson / OpenAlchemy

Define SQLAlchemy models using the OpenAPI specification.
https://openapi-sqlalchemy.readthedocs.io/en/latest/
Apache License 2.0
47 stars 13 forks source link

Support enum #167

Open jdkandersson opened 4 years ago

jdkandersson commented 4 years ago

As a user I want to define a list of valid values for a variable so that only those values are accepted.

Reference to the OpenAPI documentation: https://swagger.io/docs/specification/data-models/enums/

Requested in #166

rgreinho commented 3 years ago

I am interested in working on this issue.

jdkandersson commented 3 years ago

What is supported

What is not supported

High Level Flow

OpenAlchemy follows the following high level steps to produce output:

  1. It validates the schema against any assumptions made (e.g. that a many-to-many relationship is well defined)
  2. It converts the schema to artefacts which are well defined classes in OpenAlchemy
  3. These artefacts are passed to SQLAlchemy in a facade to be converted to columns
  4. The artefacts are passed to a typing engine to generate the models_autogenerated.py files
  5. The models are constructed by inheriting from UtilityBase which adds some helper functions (such as from_dict)

For now, we will park step 4 and 5 for later

Validation

The functionality for validation is defined in the following folder:

open_alchemy/schemas/validation

The first step is break down the problem first to individual schemas and then to properties within those schemas. Then, there are a few different types of properties which is used to break down the problem a little further. The types are:

In this case we only need to worry about simple. For each property of this type the schema is passed to the check function in the following file:

openalchemy/schemas/validation/property/simple.py

This function needs to be modified to do the following checks if a property defines enum:

These checks should be performed after all other checks so that you can assume that the schema is otherwise valid.

I was looking for a function that could help with the item validation, the best I could find is that something similar is being done for the default function in open_alchemy/helpers/peek.py. I would recommend that a enum function be added to the same file that performs similar validation as default (it might be worth pulling that functionality out of the default function into a separate helper function) as well as the check for a list as above.

Other types

For relationship, a check should be implemented that enum is not defined. It should throw a FeatureNotImplementedError exception. The relevant file is: openalchemy/schemas/validation/property/relationship/property_.py

Artefacts

After validation passes, OpenAlchemy converts the schema into well-defined artefacts data classes. The relevant folder is: open_alchemy/schemas/artifacts

Again, the problem is broken down in a similar way as for validation. The relevant file to update is:

openalchemy/schemas/artifacts/property/simple.py

Additionally, the class that is returned has to be updated. The class is OpenApiSimplePropertyArtifacts which should have an enum property added (open to better ways of implementing this). This class is defined here:

open_alchemy/types.py

SQLAlchemy model construction

To construct the SQLAlchemy model, the artefacts class needs to be converted to a SQLAlchemy Column which is done in the following file:

open_alchemy/facades/sqlalchemy/simple.py

The mapping should be done to the following SQLAlchemy type:

https://docs.sqlalchemy.org/en/13/core/type_basics.html#sqlalchemy.types.Enum

Example

To verify that everything works up to this point, create an example in the following folder:

examples

And add a test to the following file:

tests/examples/test_example_specs.py

Next Steps

This is potentially enough to do an initial pull request. If you like, after completing each stage (e.g. validation), it would also be fine to do a pull request and have that stage merged into master, it won't break anything (assuming all tests pass) and it means you can more easily keep up with any changes on the master branch.

Let's reconnect after this, there are a few more things that we need to do:

  1. Update some integration tests
  2. Update the models file autogeneration
  3. Add a check for that UtilityBase correctly rejects invalid values due to enum
  4. Maybe some other things I can think of right now :wink:
iamthen0ise commented 7 months ago

Hi! Any news?