A shape is a powerful syntactic construct that can be used to describe type variants in queries, data in INSERT and UPDATE statements, and to specify the format of statement output.

Shapes always follow an expression, and are a list of shape elements enclosed in curly braces:

expr "{"
    shape_element [, ...]

Shape element has the following syntax:

[ "[" IS object-type "]" ] pointer-spec

If an optional object-type filter is used, pointer-spec will only apply to those objects in the expr set that are instances of object-type.

pointer-spec is one of the following:

  • a name of an existing link or property of a type produced by expr;

  • a declaration of a computed link or property in the form

    [@]name := ptrexpr
  • a subshape in the form

    pointer-name: [ "[" IS target-type "]" ] "{" ... "}"`

    The pointer-name is the name of an existing link or property, and target-type is an optional object type that specifies the type of target objects selected or inserted, depending on the context.

A shape in an UPDATE statement is used to specify how links and properties of an object are updated.

FILTER .name = 'Issue #1'
# Update shape follows
    name := 'Issue #1 (important)',
    comments := Issue.comments UNION (INSERT Comment {
                    body := 'Issue #1 updated'

The above statement updates the name property and adds a comments link to a new comment for a given Issue object.

See UPDATE for more information on the use of shapes in UPDATE statements.

A shape in a SELECT clause (or the UNION clause of a FOR statement) determines the output format for the objects in a set computed by an expression annotated by the shape.

For example, the below query returns a set of Issue objects and includes a number and an associated owner User object, which in turn includes the name and the email for that user.

    Issue {
        owner: {  # sub-shape, selects Issue.owner objects

    'number': 1,
    'owner': {
        'name': 'Alice',
        'email': 'alice@example.com'

Typically the cardinality of an expression can be statically determined from the individual parts. Sometimes it is necessary to specify the cardinality explicitly. For example, when using computed expressions in shapes it may be desirable to specify the cardinality of the computed link or property they represent because it affects serialization.

    MODULE example
    multi nicknames := (SELECT 'Foo')

Cardinality is normally statically inferred from the query, so overruling this inference may only be done to relax the cardinality, so it is not valid to specify the single qualifier if the computed expression that may return multiple items.