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!: configurable key to ID conversion #379

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions graphene_sqlalchemy/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@
use_non_null_many_relationships = non_null_flag


use_id_type_for_keys = True
erikwrede marked this conversation as resolved.
Show resolved Hide resolved


def set_id_for_keys(id_flag):
global use_id_type_for_keys
use_id_type_for_keys = id_flag

Check warning on line 101 in graphene_sqlalchemy/converter.py

View check run for this annotation

Codecov / codecov/patch

graphene_sqlalchemy/converter.py#L101

Added line #L101 was not covered by tests


def get_column_doc(column):
return getattr(column, "doc", None)

Expand Down Expand Up @@ -259,18 +267,34 @@
convert_sqlalchemy_composite.register = _register_composite_class


def _is_primary_or_foreign_key(column):
return getattr(column, "primary_key", False) or (
len(getattr(column, "foreign_keys", [])) > 0
)


def convert_sqlalchemy_column(column_prop, registry, resolver, **field_kwargs):
column = column_prop.columns[0]
# The converter expects a type to find the right conversion function.
# If we get an instance instead, we need to convert it to a type.
# The conversion function will still be able to access the instance via the column argument.
# We only use the converter if no type was specified using the ORMField
if "type_" not in field_kwargs:
column_type = getattr(column, "type", None)
if not isinstance(column_type, type):
column_type = type(column_type)
# If the column is a primary key, we use the ID typ
if use_id_type_for_keys and _is_primary_or_foreign_key(column):
field_type = graphene.ID
else:
# The converter expects a type to find the right conversion function.
# If we get an instance instead, we need to convert it to a type.
# The conversion function will still be able to access the instance via the column argument.
column_type = getattr(column, "type", None)
if not isinstance(column_type, type):
column_type = type(column_type)

field_type = convert_sqlalchemy_type(
column_type, column=column, registry=registry
)

field_kwargs.setdefault(
"type_",
convert_sqlalchemy_type(column_type, column=column, registry=registry),
field_type,
)
field_kwargs.setdefault("required", not is_column_nullable(column))
field_kwargs.setdefault("description", get_column_doc(column))
Expand Down Expand Up @@ -385,10 +409,6 @@
registry: Registry = None,
**kwargs,
):
# fixme drop the primary key processing from here in another pr
if column is not None:
if getattr(column, "primary_key", False) is True:
return graphene.ID
return graphene.Int


Expand Down
26 changes: 22 additions & 4 deletions graphene_sqlalchemy/tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pytest
import sqlalchemy
import sqlalchemy_utils as sqa_utils
from sqlalchemy import Column, func, select, types
from sqlalchemy import Column, ForeignKey, func, select, types
from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property
Expand Down Expand Up @@ -42,11 +42,13 @@ def mock_resolver():
pass


def get_field(sqlalchemy_type, **column_kwargs):
def get_field(sqlalchemy_type, *column_args, **column_kwargs):
class Model(declarative_base()):
__tablename__ = "model"
id_ = Column(types.Integer, primary_key=True)
column = Column(sqlalchemy_type, doc="Custom Help Text", **column_kwargs)
column = Column(
sqlalchemy_type, *column_args, doc="Custom Help Text", **column_kwargs
)

column_prop = inspect(Model).column_attrs["column"]
return convert_sqlalchemy_column(column_prop, get_global_registry(), mock_resolver)
Expand Down Expand Up @@ -381,12 +383,28 @@ def test_should_integer_convert_int():
assert get_field(types.Integer()).type == graphene.Int


def test_should_primary_integer_convert_id():
def test_should_key_integer_convert_id():
erikwrede marked this conversation as resolved.
Show resolved Hide resolved
assert get_field(types.Integer(), primary_key=True).type == graphene.NonNull(
graphene.ID
)


def test_should_primary_string_convert_id():
assert get_field(types.String(), primary_key=True).type == graphene.NonNull(
graphene.ID
)


def test_should_primary_uuid_convert_id():
assert get_field(sqa_utils.UUIDType, primary_key=True).type == graphene.NonNull(
graphene.ID
)


def test_should_foreign_key_convert_id():
assert get_field(types.Integer(), ForeignKey("model.id_")).type == graphene.ID


def test_should_boolean_convert_boolean():
assert get_field(types.Boolean()).type == graphene.Boolean

Expand Down