import re
import warnings
from sqlalchemy.exc import ArgumentError
from sqlalchemy.orm import class_mapper, object_mapper
from sqlalchemy.orm.exc import UnmappedClassError, UnmappedInstanceError
def get_session(context):
return context.get("session")
def get_query(model, context):
query = getattr(model, "query", None)
if not query:
session = get_session(context)
if not session:
raise Exception(
"A query in the model Base or a session in the schema is required for querying.\n"
"Read more http://docs.graphene-python.org/projects/sqlalchemy/en/latest/tips/#querying"
)
query = session.query(model)
return query
def is_mapped_class(cls):
try:
class_mapper(cls)
except (ArgumentError, UnmappedClassError):
return False
else:
return True
def is_mapped_instance(cls):
try:
object_mapper(cls)
except (ArgumentError, UnmappedInstanceError):
return False
else:
return True
def to_type_name(name):
"""Convert the given name to a GraphQL type name."""
return "".join(part[:1].upper() + part[1:] for part in name.split("_"))
_re_enum_value_name_1 = re.compile("(.)([A-Z][a-z]+)")
_re_enum_value_name_2 = re.compile("([a-z0-9])([A-Z])")
def to_enum_value_name(name):
"""Convert the given name to a GraphQL enum value name."""
return _re_enum_value_name_2.sub(
r"\1_\2", _re_enum_value_name_1.sub(r"\1_\2", name)
).upper()
class EnumValue(str):
"""String that has an additional value attached.
This is used to attach SQLAlchemy model columns to Enum symbols.
"""
def __new__(cls, s, value):
return super(EnumValue, cls).__new__(cls, s)
def __init__(self, _s, value):
super(EnumValue, self).__init__()
self.value = value
def _deprecated_default_symbol_name(column_name, sort_asc):
return column_name + ("_asc" if sort_asc else "_desc")
# unfortunately, we cannot use lru_cache because we still support Python 2
_deprecated_object_type_cache = {}
def _deprecated_object_type_for_model(cls, name):
try:
return _deprecated_object_type_cache[cls, name]
except KeyError:
from .types import SQLAlchemyObjectType
obj_type_name = name or cls.__name__
class ObjType(SQLAlchemyObjectType):
class Meta:
name = obj_type_name
model = cls
_deprecated_object_type_cache[cls, name] = ObjType
return ObjType
def sort_enum_for_model(cls, name=None, symbol_name=None):
"""Get a Graphene Enum for sorting the given model class.
This is deprecated, please use object_type.sort_enum() instead.
"""
warnings.warn(
"sort_enum_for_model() is deprecated; use object_type.sort_enum() instead.",
DeprecationWarning,
stacklevel=2,
)
from .enums import sort_enum_for_object_type
return sort_enum_for_object_type(
_deprecated_object_type_for_model(cls, name),
name,
get_symbol_name=symbol_name or _deprecated_default_symbol_name,
)
def sort_argument_for_model(cls, has_default=True):
"""Get a Graphene Argument for sorting the given model class.
This is deprecated, please use object_type.sort_argument() instead.
"""
warnings.warn(
"sort_argument_for_model() is deprecated;"
" use object_type.sort_argument() instead.",
DeprecationWarning,
stacklevel=2,
)
from graphene import Argument, List
from .enums import sort_enum_for_object_type
enum = sort_enum_for_object_type(
_deprecated_object_type_for_model(cls, None),
get_symbol_name=_deprecated_default_symbol_name,
)
if not has_default:
enum.default = None
return Argument(List(enum), default_value=enum.default)