.. _object-schemas:
Object schemas
==============
Schemas define a structure of object fields and allowed values associated with a
specific object type. Schemas are specified as `JSON Schema
`_ data structures.
For instance, a very simple schema to store a *person* object could look
something like this (in YAML code):
.. code:: yaml
# Schema for an object of type 'person'
$schema: "http://json-schema.org/draft-06/schema"
type: object
additionalProperties: false
required: ['person_id', 'name', ]
_zoo_primarykey: 'person_id'
properties:
# every person entry must have a unique id which will never change.
person_id:
type: string
pattern: '^[a-z0-9_.-]+$'
name:
type: string
_flm: standalone
biography:
type: string
_flm: full
Data types and values validation
--------------------------------
The schema should conform to standard JSON schema. You can specify allowed
fields, allowed value types, allowed patterns for strings, etc.
Primary key field
-----------------
You can specify which field of the object should be used as the object's unique
identifier ("primary key"). Set the global schema field `_zoo_primarykey:` to
the name of the field you'd like to use as unique identifier.
Autopopulated fields
--------------------
Some fields are meant to be populated automatically by some database processor.
You can mark such fields with `_auto_populated: true`. In this case, no data is
expected to be provided when loading the object raw data.
.. note::
Auto-populated fields are not currently checked for absence during schema
validation. If data is accidentally provided for such a field, it will
be silently overwritten by the processor.
.. _zoodb-schemas-flmcontent:
FLM content strings
-------------------
String values can be marked to be parsed as Flexible Latex-like Markup (FLM)
content. Use the schema field `_flm:` to indicate that this is the case.
The database processor :js:class:`FLMSimpleContentCompiler` (which can be
installed via a :js:class:`ZooFLMProcessor` instance) will then detect which
fields are FLM markup and compile them accordingly into FLM fragment objects.
If the field `_flm:` is absent, if `_flm: false`, or if `_flm: null`, then FLM
is not enabled.
If you set `_flm: true` or `_flm: 'full'`, then full FLM parsing is available,
including code that might pin down labels and make use of cross-references.
If you set `_flm: 'standalone'`, then only standalone-mode FLM code is accepted.
See FLM's documentation for standalone mode.
If you set `_flm: 'block_level'`, then full FLM parsing is enabled in
block-level mode: the content can contain paragraphs, bullet lists, figures,
and other block-level constructs.
You can also specify whether or not to enable FLM parsing, standalone mode, and
block-level mode by specifying an object:
.. code:: yaml
_flm:
enabled: true|false
standalone: true|false
is_block_level: true|false|null
All three keys default to `false` when omitted, except `is_block_level` which
defaults to `null` (letting the FLM parser decide based on the content itself).
Relationships to other objects
------------------------------
An important feature of zoos is that they specify relationships between objects.
E.g., which error-correcting codes are special cases of which other
error-correcting codes is an important relationship feature in the `Error
Correction Zoo `_.
You can specify relationships between objects with a global `_zoo_relations:`
field. Relationship information specified here will be picked up by the
:js:class:`RelationsPopulator` database processor. The processor will then turn
field references by identifier into actual object references to the relevant
objects. The processor can also place backreferences where required, etc.
The global `_zoo_relations:` field should be a list of objects, each describing
a relationship. Each is referred to as a *relation specification object*. For
example:
.. code:: yaml
# schema
[...]
_zoo_relations:
- object_field: 'relations.parents'
to_object_type: 'person'
relation_primary_key_field: 'person_id'
relation_add_object_field: 'person'
backreference:
field: 'relations.children'
[ ... more relation specification objects can be added here ... ]
properties:
[...]
relations:
type: object
additionalProperties: false
properties:
parents:
type: array
items:
type: object
required: ['person_id']
additionalProperties: false
properties:
person_id:
_single_line_string: True
type: string
# automatically populated field, don't specify value manually:
children:
_auto_populated: true
type: array
items:
type: object
The code above specifies that the field `relations.parents` is a reference to
another `person` object specified in a field `relations.parents[].person_id`.
The `relations.parents` object will be extended to include a field `person` with
a reference to the corresponding person object. Furthermore, the field
`relations.children` on the target object will be a list of backreferences; each
will be a copy of the relationship object (`relations.parents[]`) but with the
`person_id` and `person` fields set to the referring object.
See the documentation for the :class:`RelationsPopulator` database processor
for how to specify relationships with *relation spec objects*.
Additional annotations intended for editors
-------------------------------------------
The field `_description: ` is intented to convey a meaningful
description of the contents that should be provided in this field.
For string values, the field `_single_line_string: ` should provide an
indication as to whether the value is expected to hold on a single line (e.g.,
an identifier, or a short description), or if it is a block of text that can
span multiple lines. This field does not contribute to validation of the field
value. A GUI editor should however inspect this field and provide a
correspondingly appropriate edit widget.