Scalars#
Scalar are a types that used to represent leaves of a graph.
Hiku has a few built-in scalars according to the GraphQL specification:
ID
- a string that represents unique identifier.Int
- a signed 32‐bit integer.Float
- a signed double-precision floating-point value.String
- a UTF‐8 character sequence.Boolean
- a boolean value:true
orfalse
.Any
- any value.
Although these scalar types are sufficient to represent the majority of data types returned from graph, it is sometimes necessary to define custom scalar types.
Hiku
has a few additional custom scalars:
Date
- a date value in ISO 8601 format.DateTime
- a date and time value in ISO 8601 format.UUID
- a UUID value.
Note
Hiku built-in custom scalars are not enabled by default.
You need to enable them explicitly, by adding each scalar that you need
to the scalars
argument of the Graph
constructor.
Custom scalars#
If builtin scalars do not cover your specific needs, you can define custom scalar type like this:
from hiku.scalar import Scalar
class YMDDate(Scalar):
"""Format datetime info %Y-%m-%d"""
@classmethod
def parse(cls, value: str) -> datetime:
return datetime.strptime(value, '%Y-%m-%d')
@classmethod
def serialize(cls, value: datetime) -> str:
return value.strftime('%Y-%m-%d')
Note
By default scalar name will be the name of a class.
If you want to specify a custom name for scalar or add description,
you can use @scalar()
decorator:
from hiku.scalar import Scalar, scalar
@scalar('YearMonthDayDate', 'Format datetime info %Y-%m-%d')
class YMDDate(Scalar):
...
Now, lets look at the full example:
from datetime import datetime
from hiku.graph import Field, Graph, Link, Node, Root
from hiku.scalar import Scalar
from hiku.types import ID, TypeRef, Optional
users = {
1: {'id': "1", 'dateCreated': datetime(2023, 6, 15, 12, 30, 59, 0)},
}
class YMDDate(Scalar):
"""Format datetime info %Y-%m-%d"""
@classmethod
def parse(cls, value: str) -> datetime:
return datetime.strptime(value, '%Y-%m-%d')
@classmethod
def serialize(cls, value: datetime) -> str:
return value.strftime('%Y-%m-%d')
def user_fields_resolver(fields, ids):
def get_field(field, user):
if field.name == 'id':
return user['id']
elif field.name == 'dateCreated':
return user['dateCreated']
return [[get_field(field, users[id]) for field in fields] for id in ids]
def get_user(opts):
if opts['olderThen'] <= datetime(2023, 6, 15):
return 1
return Nothing
scalars = [YMDDate]
GRAPH = Graph([
Node('User', [
Field('id', ID, user_fields_resolver),
Field('dateCreated', YMDDate, user_fields_resolver),
]),
Root([
Link(
'user',
TypeRef['User'],
get_user,
requires=None,
options=[
Option('olderThen', Optional[YMDDate]),
]
),
]),
], scalars=scalars)
Lets decode the example above:
YMDDate
type is subclassingScalar` and implements ``parse
andserialize
methods.User.dateCreated
field has typeYMDDate
which is a custom scalar.dateCreated
field returnsuser.dateCreated
which is adatetime
instance.YMDDate.parse
method will be called to parsedatetime
instance into%Y-%m-%
formatted string.user
field has input argumentolderThen
which has scalar typeYMDDate
.YMDDate.serialize
method will be called to serialize input argument string intodatetime
instance.
If we run this query:
query {
user(olderThen: "2023-06-15") {
id
dateCreated
}
}
We will get this result:
{
'id': "1",
'dateCreated': '2023-06-15',
}