reym
Projections/Schema

Introduction

Documentation of the Projection service schema definition.

A projection can be defined by a GraphQL schema:

user.graphql
type User
    @upsertOn(
        on: { topic: "myApp", eventTypes: ["createUser", "updateUser"] }
        identifyBy: { payload: ["id"] }
    )
    @removeOn(
        on: { topic: "myApp", eventTypes: ["removeUser"] }
        identifyBy: { payload: ["id"] }
    ) {
    name: String!
}

The name of the projection equals the name of the type in the schema. The name will be part of the corresponding queries and subscriptions in the GraphQL API, too.

Views

A view is a projection that is based on one or more other projections. Views can be used for advanced reporting tasks that need to aggregate a lot of data.

A view can be defined by a GraphQL schema and a SQL file:

userStatistics.graphql
type UserStatistics @view(sqlFile: "./userStatistics.sql") {
    name: String! @index
    numberOfUsers: Int!
}

The name of the view equals the name of the type in the schema. The name will be part of the corresponding queries and subscriptions in the GraphQL API, too.

userStatistics.sql
SELECT name AS name, COUNT(1) AS numberOfUsers FROM user GROUP BY name

For more information about how to define a view please refer to the documentation of the @view directive.

Base Views

Base views can be used in views to reuse the same base view for multiple views. They work the same as views.

For more information about how to define a base view please refer to the documentation of the @baseView directive.

Object Directives

The following directives can be applied to the whole projection:

DirectiveDescription
@dangerouslyUpsertOnUpsert data from several topics into the same projection
@dangerouslyRemoveOnRemove data from several topics from the same projection
@expiresAutomatically remove data after expiration
@filterByJwtDataFilter data based on a field in the JWT
@globalProjections over all tenants
@permissionRestrict access permissions on the projection
@removeOnRemove projection data
@uniqueUnique constraints on multiple fields
@upsertOnCreate or update projection data
@viewA view can be used to calculate complex reports
@webhookUse webhooks if you need complex logic to generate projection data

Fields

Supported field types:

  • String
  • ID
  • Boolean
  • Int
  • Float
  • DateTime (unix timestamp, milliseconds)
  • Enums
  • Objects / references to other projections or CRUD types
  • Arrays of all types listed above
  • All types listed above in their required form
  • [EventEnvelope!]!

Event Envelope

The field type [EventEnvelope!]! is a special field type that can only be used in this form at the root level of a projection (not in a nested object). It will automatically aggregate all events that are applied on the projection entry into an array. Use the type in conjunction with the @aggregateEvents directive. This is very useful for debugging.

Every projection will automatically get three fields:

FieldTypeDescription
idID!The identifier of the projection
createdAtDateTime!The creation time of the entry
changedAtDateTime!The time of the last change of the entry

By default the value of a field equals the value of the event payload field that has the exact same name. Required fields are marked by an !, e.g. String!. Fields with the ! flag will default to their zero value ("" for strings, 0 for numbers, false for booleans, [] for arrays).

Field Directives

By default the value of a field equals the value of the event payload field that has the exact same name. This behavior can be changed by using directives on a field level:

DirectiveDescription
@aggregateEventsAggregate all events that changed the entry
@changedAtReflects the last change time of the entry
@createdAtReflects the creation time of the entry
@changedByReflects the user that has last changed the entry
@createdByReflects the user that has created the entry
@defaultSet a default value
@fromJwtDataFill a field with data from the JWT
@fromSet the value of a field by an expression
@gdprApply GDPR logic on a field
@identifierFill a field by the id of the projection entry
@immutableMark a field as immutable
@indexMake a field filterable ans sortable
@permissionRestrict access permissions on the field
@projectedAtReflects the projection time of the entry
@safeHtmlSanitize html strings
@sequenceAutomated sequence generator
@uniqueMake a field unique
@validateValidate field data
@webhookExecute complex calculations in a webhook

Debugging

Use the [EventEnvelope!]! field type at the root level of your projection to aggregate all events that are applied to a projection entry.

user.graphql
type User @upsertOn(...) {
    name: String!
    events: [EventEnvelope!]! @aggregateEvents
}