A :py~mercator.ProtoMapping
provides syntax sugar to define ways in which python dictionaries or objects can have its keys or properties serialized into predefined ProtoBuf messages.
Every :py~mercator.ProtoMapping
must declare a proto
attribute that points to a valid :py~google.protobuf.message.Message
subclass.
from google.protobuf.timestamp_pb2 import Timestamp
from mercator import ProtoMapping
from mercator import ProtoKey
class TimestampMapping(ProtoMapping):
__proto__ = Timestamp
seconds = ProtoKey('seconds', int)
Warning
Failing to declare a valid proto
attribute will cause mercator to raise a :pySyntaxError
If declared, this property will be considered as base-class of opaque objects that can have its properties mapped into protobuf.
This feature was primarily designed to support SQLAlchemy ORM models out of the box but supports any opaque python objects, as long as their base classes are defined by this attribute.
from sqlalchemy.ext.declarative import declarative_base
from mercator import ProtoMapping
from mercator import ProtoKey
MySimpleBaseModel = declarative_base()
class User(MySimpleBaseModel):
__tablename__ = 'user'
__table_args__ = {'useexisting': True}
login = sa.Column(sa.String(256))
email = sa.Column(sa.String(256))
password = sa.Column(sa.String(256))
class UserMapping(ProtoMapping):
__proto__ = domain_pb2.User
__source_input_type__ = User
Important
This attribute is optional when declaring proto mappings, but if defined it must be a :pytype
.
The section SQLAlchemy Support
for more information on how to use the __source_input_type__
attribute.
Field mappings are either :py~mercator.ProtoKey
or :py~mercator.ProtoList
class-attributes defined in the body of your :py~mercator.ProtoMapping
subclass.
This gives you the power to gather data from dictionaries with keys that are different than in the protobuf model.
Field mappings are subclasses of :pymercator.meta.FieldMapping
and share its __init__
signature:
FieldMapping(name_at_source: str, target_type: type)
ProtoKey(name_at_source: str, target_type: type)
ProtoList(name_at_source: str, target_type: type)
The target_type
argument is optional, but when given, supports different types.
Let's dive into the possibilities.
Ensures that the field value is cast into any python type, namely: :pystr
, :pyint
, :pyfloat
, :pylong
, :pydict
, :pylist
Allows recursively translating data into protobuf messages whose members contain sub-messages.
from mercator import (
ProtoMapping,
ProtoKey,
)
from . import domain_pb2
from . import sql
class UserMapping(ProtoMapping):
__proto__ = domain_pb2.User
uuid = ProtoKey('id', str)
email = ProtoKey('email', str)
username = ProtoKey('login', str)
class MediaMapping(ProtoMapping):
__proto__ = domain_pb2.UserMedia
author = ProtoKey('owner', UserMapping)
download_url = ProtoKey('link', str)