Enums#
Enums are a special types that can be used to define a set of possible values for a field.
In graphql you can use enum type like this:
enum Status {
ACTIVE
DELETED
}
type Usr {
id: ID!
status: Status!
}
type Query {
user: User!
}
Enum from string#
The simplest way to create enum in hiku from a list of strings:
from hiku.enum import Enum
Enum('Status', ['ACTIVE', 'DELETED'])
Enum from python Enum#
You can also create enum from builtin python Enum type:
from enum import Enum as PyEnum
from hiku.enum import Enum
class Status(PyEnum):
ACTIVE = 'active'
DELETED = 'deleted'
Enum.from_builtin(Status)
In this example:
EnumFromBuiltinwill useEnum.__name__as a enum name.EnumFromBuiltinwill useEnum.__members__to get a list of possible values.EnumFromBuiltinwill usemember.nameto get a value name:
So this python enum:
class Status(PyEnum):
ACTIVE = 1
DELETED = 2
is equivalent to this enum in graphql:
enum Status { ACTIVE, DELETED }
If you want to specify different name you can pass name argument to Enum.from_builtin method:
Enum.from_builtin(Status, name='User_Status')
Note
If you use builtin python Enum, then you MUST return enum value from the resolver function, otherwise hiku will raise an error.
def user_fields_resolver(fields, ids):
def get_field(field, user):
if field.name == 'id':
return user.id
elif field.name == 'status':
return Status(user.status)
return [[get_field(field, users[id]) for field in fields] for id in ids]
Lets look at the full example on how to use enum type in hiku:
from hiku.graph import Field, Graph, Link, Node, Root
from hiku.enum import Enum
from hiku.types import ID, TypeRef, Optional, EnumRef
users = {
1: {'id': "1", 'status': 'ACTIVE'},
}
def user_fields_resolver(fields, ids):
def get_field(field, user):
if field.name == 'id':
return user['id']
elif field.name == 'status':
return user['status']
return [[get_field(field, users[id]) for field in fields] for id in ids]
def get_user(opts):
return 1
enums = [
Enum('Status', ['ACTIVE', 'DELETED'])
]
GRAPH = Graph([
Node('User', [
Field('id', ID, user_fields_resolver),
Field('status', EnumRef['Status'], user_fields_resolver),
]),
Root([
Link('user', TypeRef['User'], get_user, requires=None),
]),
], enums=enums)
Lets decode the example above:
Enumtype is defined with a name and a list of possible values.User.statusfield has typeEnumRef['Status']which is a reference to theStatusenum type.statusfield returnsuser.statuswhich is plain string.
If we run this query:
query {
user {
id
status
}
}
We will get the following result:
{
'id': "1",
'status': 'ACTIVE',
}
Custom Enum type#
You can also create custom enum type by subclassing hiku.enum.BaseEnum class:
from hiku.enum import BaseEnum
class IntToStrEnum(BaseEnum):
_MAPPING = {1: 'one', 2: 'two', 3: 'three'}
_INVERTED_MAPPING = {v: k for k, v in _MAPPING.items()}
def __init__(self, name: str, values: list[int], description: str = None):
super().__init__(name, [_MAPPING[v] for v in values], description)
def parse(self, value: str) -> int:
return self._INVERTED_MAPPING[value]
def serialize(self, value: int) -> str:
return self._MAPPING[value]
Enum serialization#
Enumvalues are serialized into strings. If value is not in the list of possible values, thenhikuwill raise an error.EnumFromBuiltinvalues which are instances ofEnumclass are serialized into strings by calling .name on enum value. If value is not an instance ofEnumclass, thenhikuwill raise an error.
You can also define custom serialization for your enum type by subclassing hiku.enum.BaseEnum class.
Enum parsing#
Enumparses values into strings. If value is not in the list of possible values, thenhikuwill raise an error.EnumFromBuiltinparses values into enum values by calling Enum(value). If value is not in the list of possible values, thenhikuwill raise an error.
You can also define custom parsing for your enum type by subclassing hiku.enum.BaseEnum class.
Enum as an input argument#
You can use enum as an field input argument:
import enum
from hiku.enum import Enum
from hiku.graph import Node, Root, Field, Link, Graph, Option
from hiku.types import ID, TypeRef, Optional, EnumRef
users = [
{'id': "1", 'status': Status.ACTIVE},
{'id': "2", 'status': Status.DELETED},
]
def link_users(opts):
ids = []
for user in users:
# here opts['status'] will be an instance of Status enum
if user['status'] == opts['status']:
ids.append(user.id)
return ids
class Status(enum.Enum):
ACTIVE = 'active'
DELETED = 'deleted'
GRAPH = Graph([
Node('User', [
Field('id', ID, user_fields_resolver),
Field('status', EnumRef['Status'], user_fields_resolver),
]),
Root([
Link(
'users',
Sequence[TypeRef['User']],
link_users,
requires=None,
options=[
Option('status', EnumRef['Status'], default=Status.ACTIVE),
]
),
]),
], enums=[Enum.from_builtin(Status)])
Now you can use enum as a field argument:
query {
users(status: DELETED) {
id
status
}
}
The result will be:
[{
"id": "2",
"status": "DELETED",
}]