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:trueorfalse.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:
YMDDatetype is subclassingScalar` and implements ``parseandserializemethods.User.dateCreatedfield has typeYMDDatewhich is a custom scalar.dateCreatedfield returnsuser.dateCreatedwhich is adatetimeinstance.YMDDate.parsemethod will be called to parsedatetimeinstance into%Y-%m-%formatted string.userfield has input argumentolderThenwhich has scalar typeYMDDate.YMDDate.serializemethod will be called to serialize input argument string intodatetimeinstance.
If we run this query:
query {
user(olderThen: "2023-06-15") {
id
dateCreated
}
}
We will get this result:
{
"id": "1",
"dateCreated": "2023-06-15",
}