Skip to content

Commit

Permalink
Merge c69ba5b into 64a5740
Browse files Browse the repository at this point in the history
  • Loading branch information
karol-gruszczyk committed May 30, 2018
2 parents 64a5740 + c69ba5b commit 00ce316
Show file tree
Hide file tree
Showing 32 changed files with 579 additions and 387 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
Expand Up @@ -2,7 +2,7 @@ graphql-core>=2<3
cached-property==1.4

# optional
django>=2.0<3
django==2.0
psycopg2-binary>=2.7<3

# development
Expand Down
Empty file removed slothql/arguments/__init__.py
Empty file.
62 changes: 0 additions & 62 deletions slothql/arguments/filters.py

This file was deleted.

Empty file.
30 changes: 0 additions & 30 deletions slothql/arguments/tests/integration.py

This file was deleted.

15 changes: 0 additions & 15 deletions slothql/arguments/utils.py

This file was deleted.

9 changes: 4 additions & 5 deletions slothql/conftest.py
Expand Up @@ -6,7 +6,6 @@
from django.db import models

import graphql
from graphql.type.definition import GraphQLType

import slothql
from slothql.types.base import BaseType
Expand Down Expand Up @@ -35,7 +34,7 @@ def pytest_runtest_setup(item):

@pytest.fixture()
def type_mock():
return lambda: BaseType(mock.Mock(spec=GraphQLType))
return lambda: BaseType


@pytest.fixture()
Expand All @@ -45,12 +44,12 @@ def info_mock():

@pytest.fixture()
def resolver_mock():
return mock.Mock(side_effect=lambda o, *_: o)
return mock.Mock(spec=staticmethod, side_effect=lambda o, *_: o)


@pytest.fixture()
def field_mock():
return mock.Mock(spec=slothql.Field)
def field_mock(resolver_mock):
return mock.Mock(spec=slothql.Field, _resolver=resolver_mock, description=None, source=None, many=False)


@pytest.fixture()
Expand Down
36 changes: 18 additions & 18 deletions slothql/django/types/__init__.py
Expand Up @@ -10,32 +10,32 @@

from .registry import TypeRegistry

TypeRegistry().register(models.AutoField, slothql.Integer())
TypeRegistry().register(models.BigAutoField, slothql.Integer())
TypeRegistry().register(models.AutoField, slothql.Integer)
TypeRegistry().register(models.BigAutoField, slothql.Integer)

TypeRegistry().register(models.CharField, slothql.String())
TypeRegistry().register(models.TextField, slothql.String())
TypeRegistry().register(models.EmailField, slothql.String())
TypeRegistry().register(models.CharField, slothql.String)
TypeRegistry().register(models.TextField, slothql.String)
TypeRegistry().register(models.EmailField, slothql.String)

TypeRegistry().register(models.IntegerField, slothql.Integer())
TypeRegistry().register(models.BigIntegerField, slothql.Integer())
TypeRegistry().register(models.PositiveIntegerField, slothql.Integer())
TypeRegistry().register(models.SmallIntegerField, slothql.Integer())
TypeRegistry().register(models.PositiveSmallIntegerField, slothql.Integer())
TypeRegistry().register(models.IntegerField, slothql.Integer)
TypeRegistry().register(models.BigIntegerField, slothql.Integer)
TypeRegistry().register(models.PositiveIntegerField, slothql.Integer)
TypeRegistry().register(models.SmallIntegerField, slothql.Integer)
TypeRegistry().register(models.PositiveSmallIntegerField, slothql.Integer)

TypeRegistry().register(models.BooleanField, slothql.Boolean())
TypeRegistry().register(models.NullBooleanField, slothql.Boolean())
TypeRegistry().register(models.BooleanField, slothql.Boolean)
TypeRegistry().register(models.NullBooleanField, slothql.Boolean)

TypeRegistry().register(models.FloatField, slothql.Float())
TypeRegistry().register(models.DecimalField, slothql.Float())
TypeRegistry().register(models.FloatField, slothql.Float)
TypeRegistry().register(models.DecimalField, slothql.Float)

TypeRegistry().register(models.DateTimeField, slothql.DateTime())
TypeRegistry().register(models.DateField, slothql.Date())
TypeRegistry().register(models.TimeField, slothql.Time())
TypeRegistry().register(models.DateTimeField, slothql.DateTime)
TypeRegistry().register(models.DateField, slothql.Date)
TypeRegistry().register(models.TimeField, slothql.Time)

try:
from django.contrib.postgres import fields

TypeRegistry().register(fields.JSONField, slothql.JsonString())
TypeRegistry().register(fields.JSONField, slothql.JsonString)
except ImportError:
pass
32 changes: 18 additions & 14 deletions slothql/django/types/model.py
@@ -1,10 +1,11 @@
import inspect
from typing import Type, Iterable, Dict, Union
import typing as t

import graphql
from django.db import models

from slothql import Field
from slothql.types.fields.resolver import ResolveArgs
from slothql.types.object import Object, ObjectMeta, ObjectOptions
from slothql.django.utils.model import get_model_attrs

Expand All @@ -13,29 +14,29 @@

class ModelOptions(ObjectOptions):
__slots__ = ('model',)
model: t.Type[models.Model]

def __init__(self, **kwargs):
super().__init__(**kwargs)
assert self.abstract or self.model, f'"model" is required for object ModelOptions'


class ModelMeta(ObjectMeta):
def __new__(mcs, name, bases, attrs: dict, options_class: Type[ModelOptions] = ModelOptions, **kwargs):
def __new__(mcs, name, bases, attrs: dict, options_class: t.Type[ModelOptions] = ModelOptions, **kwargs):
assert 'Meta' in attrs, f'class {name} is missing "Meta" class'
return super().__new__(mcs, name, bases, attrs, options_class, **kwargs)

@classmethod
def get_option_attrs(mcs, name: str, base_attrs: dict, attrs: dict, meta_attrs: dict):
def get_option_attrs(cls, class_name: str, base_attrs: dict, attrs: dict, meta_attrs: dict):
fields = meta_attrs.pop('fields', None)
if fields:
model = base_attrs.get('model') or meta_attrs.get('model')
resolved_fields = mcs.get_meta_fields(model, fields)
resolved_fields = cls.get_meta_fields(model, fields)
attrs.update({name: resolved_fields[name] for name in set(resolved_fields) - set(attrs)})
return super().get_option_attrs(name, base_attrs, attrs, meta_attrs)
return super().get_option_attrs(class_name, base_attrs, attrs, meta_attrs)

@classmethod
def get_meta_fields(mcs, model: Type[models.Model], fields: Union[str, Iterable[str]]) -> Dict[str, Field]:
assert fields == '__all__' or isinstance(fields, Iterable) and all(isinstance(f, str) for f in fields), \
def get_meta_fields(mcs, model: t.Type[models.Model], fields: t.Union[str, t.Iterable[str]]) -> t.Dict[str, Field]:
assert fields == '__all__' or isinstance(fields, t.Iterable) and all(isinstance(f, str) for f in fields), \
f'Meta.fields needs to be an iterable of field names or "__all__", but received {fields}'
assert model, f'Meta.model is required when using Meta.fields'
assert inspect.isclass(model) and issubclass(model, models.Model), \
Expand All @@ -46,7 +47,7 @@ def get_meta_fields(mcs, model: Type[models.Model], fields: Union[str, Iterable[
return {name: TypeRegistry().get(field) for name, field in model_attrs.items()}

@classmethod
def resolve_attr_list(mcs, model: Type[models.Model], fields: Iterable[str]) -> dict:
def resolve_attr_list(mcs, model: t.Type[models.Model], fields: t.Iterable[str]) -> dict:
attrs = {}
model_attrs = get_model_attrs(model)
for name in fields:
Expand All @@ -60,20 +61,22 @@ def resolve_attr_list(mcs, model: Type[models.Model], fields: Iterable[str]) ->
return attrs

@classmethod
def resolve_all_fields(mcs, model: Type[models.Model]) -> dict:
def resolve_all_fields(mcs, model: t.Type[models.Model]) -> dict:
return {
name: attr for name, attr in get_model_attrs(model).items()
if not isinstance(attr, TypeRegistry.RELATION_TYPES)
}

@classmethod
def get_attrs(mcs, model: Type[models.Model], fields: Union[str, Iterable[str]]) -> dict:
def get_attrs(mcs, model: t.Type[models.Model], fields: t.Union[str, t.Iterable[str]]) -> dict:
if fields == '__all__':
return mcs.resolve_all_fields(model)
return mcs.resolve_attr_list(model, fields)


class Model(Object, metaclass=ModelMeta):
_meta: ModelOptions

class Meta:
abstract = True

Expand All @@ -83,9 +86,10 @@ def filter_queryset(cls, queryset: models.QuerySet, args: dict):
return queryset.filter()

@classmethod
def resolve(cls, parent, info: graphql.ResolveInfo, args: dict):
if parent is None:
def resolve(cls, resolved: t.Iterable, info: graphql.ResolveInfo, args: ResolveArgs) -> t.Iterable:
if resolved is None:
queryset = cls._meta.model._default_manager.get_queryset()
else:
queryset = parent.get_queryset() if isinstance(parent, models.Manager) else parent
queryset = resolved.get_queryset() if isinstance(resolved, models.Manager) else resolved
return cls.filter_queryset(queryset, args)
return super().resolve(queryset, info, args)
26 changes: 15 additions & 11 deletions slothql/django/types/registry.py
@@ -1,5 +1,5 @@
import inspect
from typing import Type
import typing as t

from django.db import models

Expand All @@ -15,20 +15,24 @@ class TypeRegistry(metaclass=Singleton):
models.OneToOneField,
models.OneToOneRel,
)
_type_mapping = {}

def register(self, django_field: Type[models.Field], field: slothql.Field):
assert inspect.isclass(django_field) and issubclass(django_field, models.Field)
assert isinstance(field, slothql.Field)
self._type_mapping[django_field] = field

def unregister(self, django_field: Type[models.Field]):
_type_mapping: t.Dict[t.Type[models.Field], t.Type[slothql.Field]] = {}

def register(self, django_field: t.Type[models.Field], field_resolver: t.Type[slothql.Field]):
assert inspect.isclass(django_field) and issubclass(django_field, models.Field), (
f'Expected django_field to be a subclass of django.db.models.Field, but got: {repr(django_field)}'
)
assert inspect.isclass(field_resolver) and issubclass(field_resolver, slothql.Field), (
f'Expected field_resolver to be a subclass of slothql.Field, but got {repr(field_resolver)}'
)
self._type_mapping[django_field] = field_resolver

def unregister(self, django_field: t.Type[models.Field]):
del self._type_mapping[django_field]

def clear(self):
self._type_mapping.clear()

def get(self, django_field: models.Field):
def get(self, django_field: models.Field) -> slothql.Field:
if type(django_field) not in self._type_mapping:
raise NotImplementedError(f'{repr(django_field)} field conversion is not implemented')
return self._type_mapping[type(django_field)]
return self._type_mapping[type(django_field)]()
5 changes: 1 addition & 4 deletions slothql/django/types/tests/meta_fields.py
Expand Up @@ -3,8 +3,6 @@

from django.db import models

import slothql

from ..model import Model
from ..registry import TypeRegistry

Expand All @@ -17,8 +15,7 @@ class Meta:
app_label = 'slothql'


def test_fields__regular():
field_mock = mock.Mock(spec=slothql.Field)
def test_fields__regular(field_mock):
with mock.patch.object(TypeRegistry, 'get', return_value=field_mock) as get:
class Test(Model):
class Meta:
Expand Down

0 comments on commit 00ce316

Please sign in to comment.