-
Notifications
You must be signed in to change notification settings - Fork 4
data containers
Data containers are run-time incarnations of schema types. Their implementations should exist for every target programming language. These classes support marshalling into one of over-the-wire representations and unmarshalling back.
In many cases more than one implementation of data containers will be provided.
Raw containers are generic implementations that don't depend on particular schema. They provide minimal type safety but a lot of run-time checks, they're mostly suitable for general-purpose framework and library code. Examples:
trait RawRecordData(val schema: RecordSchema, val meta: Option[RawData]) {
def get(field: Field): RawData
def get(field: Field, schema: Schema): RawData
def set(field: Field, schema: Schema, value: RawData): Unit
}
trait RawMapData(val schema: MapSchema, val meta: Option[RawData]) {
def get(key: RawData): RawData
def get(key: RawData, schema: Schema): RawData
def set(key: RawData, schema: Schema, value: RawData): Unit
}
Notice how there are pairs of get
functions: one gives the default
representation, another one takes a specific model to return.
Type safe containers can come in different flavors with different degrees of type safety, depending on the implementation language. In many cases they are generated basing on the schema. For example they can look like this:
trait FileRecord {
def name: string
def name_=(name: string): Unit
def owner: UserId
def owner_=(owner: UserId):Unit
def getOwner(schema: Schema[User]): User
def setOwner(schema: Schema[User], owner: User): Unit
}
Typically that's what client code will be dealing with.
Value containers such as record fields, union tags, map values or list entries are all structured in the same way. There are several nested layers of information:
- At the innermost layer there is actual data container such as
RawRecordData
orStringPrimitive
- There is an
Either[Error,Data]
wrapper around it. We support fine-grained errors, and any part of the data tree can hold an error. - Then there is a
Future
around it, because federator can be asked to resolve any part of the tree asynchronously - Finally there is
MultiValue
which represents an instance ofMultiType
. This is a map from representation types to corresponding values. For non-pivotable fields it will contain only one entry
Graphically:
Plus any data instance can have meta-data attached to it, which happens at the innermost level.