Skip to content

Instantly share code, notes, and snippets.

@s3rgeym
Created June 14, 2019 00:43
Show Gist options
  • Save s3rgeym/e3f2ce6434fcf833134e0a00fd76160a to your computer and use it in GitHub Desktop.
Save s3rgeym/e3f2ce6434fcf833134e0a00fd76160a to your computer and use it in GitHub Desktop.
from collections import OrderedDict
import graphene
from graphene import relay
from graphene.types.utils import yank_fields_from_attrs
from graphene_sqlalchemy import SQLAlchemyConnectionField, SQLAlchemyObjectType
from graphene_sqlalchemy.converter import (convert_sqlalchemy_column,
convert_sqlalchemy_composite,
convert_sqlalchemy_hybrid_method)
from graphene_sqlalchemy.fields import default_connection_field_factory
from graphene_sqlalchemy.registry import get_global_registry
from sqlalchemy.ext.hybrid import hybrid_property
from . import models
class Connection(relay.Connection):
class Meta:
abstract = True
total_count = graphene.Int()
def resolve_total_count(self, info, **kw):
return self.length
# https://github.com/Rafik-Belkadi/graphene-sqlalchemy/blob/master/graphene_sqlalchemy/types.py#L214-L278
def construct_fields_for_input(obj_type, model, registry, connection_field_factory, only_fields, exclude_fields):
inspected_model = sqlalchemyinspect(model)
fields = OrderedDict()
for name, column in inspected_model.columns.items():
is_not_in_only = only_fields and name not in only_fields
# is_already_created = name in options.fields
is_excluded = name in exclude_fields # or is_already_created
if is_not_in_only or is_excluded:
# We skip this field if we specify only_fields and is not
# in there. Or when we exclude this field in exclude_fields
continue
converted_column = convert_sqlalchemy_column(column, registry)
fields[name] = converted_column
for name, composite in inspected_model.composites.items():
is_not_in_only = only_fields and name not in only_fields
# is_already_created = name in options.fields
is_excluded = name in exclude_fields # or is_already_created
if is_not_in_only or is_excluded:
# We skip this field if we specify only_fields and is not
# in there. Or when we exclude this field in exclude_fields
continue
converted_composite = convert_sqlalchemy_composite(composite, registry)
fields[name] = converted_composite
for hybrid_item in inspected_model.all_orm_descriptors:
if type(hybrid_item) == hybrid_property:
name = hybrid_item.__name__
is_not_in_only = only_fields and name not in only_fields
# is_already_created = name in options.fields
is_excluded = name in exclude_fields # or is_already_created
if is_not_in_only or is_excluded:
# We skip this field if we specify only_fields and is not
# in there. Or when we exclude this field in exclude_fields
continue
converted_hybrid_property = convert_sqlalchemy_hybrid_method(hybrid_item)
fields[name] = converted_hybrid_property
return fields
class SQLAlchemyInputObjectType(graphene.InputObjectType):
@classmethod
def __init_subclass_with_meta__(cls, model=None, registry=None, skip_registry=False,only_fields=(), exclude_fields=(), connection=None,_meta=None, connection_field_factory=default_connection_field_factory, use_connection=None, interfaces=(), id=None, **options):
if not registry:
registry = get_global_registry()
sqla_fields = yank_fields_from_attrs(
construct_fields_for_input(model=model, registry=registry,only_fields=only_fields, exclude_fields=exclude_fields,
connection_field_factory=connection_field_factory,obj_type=cls),
_as=graphene.Field,
)
class Todo(SQLAlchemyObjectType):
class Meta:
model = models.Todo
interfaces = (relay.Node, )
class TodoConnection(Connection):
class Meta:
node = Todo
class CreateTodoInput(SQLAlchemyInputObjectType):
class Model:
model = models.Todo
exclude_fields = ('id', )
class CreateTodo(graphene.Mutation):
class Arguments:
input = CreateTodoInput(required=True)
@classmethod
def mutate(cls, instance, info, **args):
class Query(graphene.ObjectType):
node = relay.Node.Field()
todos = SQLAlchemyConnectionField(TodoConnection)
schema = graphene.Schema(query=Query)
@s3rgeym
Copy link
Author

s3rgeym commented Jun 14, 2019

mutation {
  createContact(
    input: {
      firstName: "Ivan", 
      lastName: "Ivanov",
      email: "[email protected]",
      tel: "+79012345678"
    }
  ) {
    contact {
      id
    }
  }
}

query {
  allContacts(first: 10) {
    totalCount
    pageInfo {
      hasNextPage
      hasPreviousPage
      startCursor
      endCursor
    }
    edges {
      cursor
      node {
        id
        firstName
        lastName
      }
    }
  }
}

{
  "data": {
    "contacts": {
      "totalCount": 1,
      "pageInfo": {
        "hasNextPage": false,
        "hasPreviousPage": false,
        "startCursor": "YXJyYXljb25uZWN0aW9uOjA=",
        "endCursor": "YXJyYXljb25uZWN0aW9uOjA="
      },
      "edges": [
        {
          "cursor": "YXJyYXljb25uZWN0aW9uOjA=",
          "node": {
            "id": "Q29udGFjdE5vZGU6NA==",
            "firstName": "Ivan",
            "lastName": "Ivanov"
          }
        }
      ]
    }
  }
}

query {
  contact(id: "Q29udGFjdFR5cGU6NA==") {
    firstName
    lastName
  }
}

{
  "data": {
    "contact": {
      "firstName": "Ivan",
      "lastName": "Ivanov"
    }
  }
}

mutation {
  authenticate(username: "tz4678", password: "***") {
    tokenType
    token
  }
}

{
  "data": {
    "authenticate": {
      "tokenType": "bearer",
      "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjExMzY5OTMsImlhdCI6MTU2MDUzMjE5MywiaWRlbnRpdHkiOiJ0ejQ2NzgiLCJpcCI6IjEyNy4wLjAuMSJ9.TQzSk9cDk6BLnoaLf9rEMsmcaOuFmErJFFv5iU2mjxM"
    }
  }
}

mutation {
  createContact(
    token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjExMzg0MzksImlhdCI6MTU2MDUzMzYzOSwiaWRlbnRpdHkiOiJ0ejQ2NzgiLCJpcCI6IjEyNy4wLjAuMSJ9._ytB-Xyq_I1qQwhZXY4E0xZVlHS3Shw6ssT6LPa2sN4",
    input: {
      firstName: "Pavel", 
      lastName: "Durov",
      email: "[email protected]",
      tel: "+1234567890"
    }
  ) {
    contact {
      id
    }
  }
}

@s3rgeym
Copy link
Author

s3rgeym commented Jun 14, 2019

mutation {
  updateContact(
    id: "Q29udGFjdE5vZGU6Mw==",
    input: {
      firstName: "Sergey", 
    }
  ) {
    contact {
      id
      firstName
      lastName
      email
      tel
    }
  }
}

{
  "data": {
    "updateContact": {
      "contact": {
        "id": "Q29udGFjdE5vZGU6Mw==",
        "firstName": "Sergey",
        "lastName": "Ivanov",
        "email": "[email protected]",
        "tel": "+79012345678"
      }
    }
  }
}

@s3rgeym
Copy link
Author

s3rgeym commented Jun 14, 2019

mutation {
  deleteContact(
    id: "Q29udGFjdE5vZGU6Mw=="
  ) {
    ok
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment