Memory

Views

Top-level view blocks that compose streams into a spreadsheet, with computed columns that run a graph for each row.

A view presents stream records as a typed table. It names its source streams, declares a row schema, and maps each source row with a columns block. Optional computed columns run a workflow once per row to enrich or look up data.

Views materialize on Swirls Cloud. Browse them in the dashboard or read them through the API. .swirls workflows cannot read directly from a view.

Top-level view block

FieldTypeRequiredDescription
labelstringNoDisplay name. Defaults to the view's name.
descriptionstringNoDescription.
streamslistYesStream block names this view composes. Their rows become the view's rows.
schema@json { } or named schemaYesJSON Schema for one mapped (non-computed) row.
columns@ts { }YesMaps one source stream row into the row shape (validated against schema).
computedblockNoNamed computed columns, each running a graph per row.
enabledbooleanNoWhen false, the view is not materialized.

Each computed column (inside computed { }):

FieldTypeRequiredDescription
graphidentifierYesWorkflow run once per row to compute this column.
input@ts { }YesMaps the row into the graph's trigger input (returns an object).
output@ts { }NoMaps the graph result into the cell value. Omit to store the graph output directly.

computed is a block, not a key: value field — write computed { ... } with no colon, the same way versions { } is written inside a stream block.

view topic_dashboard {
  label: "Topic dashboard"
  description: "One row per stored topic, enriched with sentiment"
  streams: [store_topic_tokens]

  schema: @json {
    {
      "type": "object",
      "required": ["topic", "tokens"],
      "properties": {
        "topic": { "type": "string" },
        "tokens": { "type": "number" }
      }
    }
  }

  columns: @ts {
    return {
      topic: context.streams.store_topic_tokens.output.topic,
      tokens: context.streams.store_topic_tokens.output.tokens
    }
  }

  computed {
    sentiment {
      graph: enrich_topic
      input: @ts {
        return { topic: context.row.topic }
      }
      output: @ts {
        return context.output.root.sentiment
      }
    }
  }
}

How rows are built

A view has one row per source stream row.

  • columns runs once per source row. The originating row is available as context.streams.<streamName>.output (and context.streams.<streamName>.<version>.output, e.g. .v1.output). Only the stream that produced the current row is present. Return the mapped row object — it is validated against the view schema, exactly like a stream's prepare is validated against its version schema.

  • Computed columns each run a workflow once per row:

    • input receives context.row (the mapped row from columns) plus the same context.streams.<name>. Return the object passed to the graph as its trigger input.
    • output receives context.output (the completed graph's leaf node outputs, keyed by leaf node name, the same shape a stream prepare sees) plus context.row. Return the cell value. Without output, the cell value is the graph's output directly.

Computed columns run real workflows

Every computed cell is a workflow execution. A view over a busy stream with computed columns can launch a large number of runs, so add computed columns deliberately.

  • Cells move through pending → running → completed → failed. The spreadsheet shows a loading state until each cell settles.
  • Computed-column runs are billed against execution_credits, the same as workflows started by a trigger. When the org is over quota, the cell settles as failed rather than running for free.
  • New rows materialize as the source workflow completes. Deploying a view backfills existing stream rows.
  • Recompute is available from the cloud UI. It fills gaps: it materializes stream rows the view missed and their cells. It does not re-run cells that already settled.

Avoid execution loops

A computed column must not run a graph that writes back into a stream the same view composes. That would make every materialized row enqueue another graph run, which writes another row, forever.

The validator rejects this at deploy time:

View "X" creates an infinite execution loop: a computed column runs a graph that writes a stream this view (or a view it feeds) composes.

It catches both the direct case and chains across multiple views. Point computed columns at graphs that enrich or look things up — not at graphs that append to the view's own source streams.

Validation rules

  • View names must match ^[a-zA-Z0-9_]+$; duplicate names error.
  • streams is required and non-empty; each entry must name a declared stream, and listing a stream twice errors.
  • schema and columns are required; columns must be a non-empty @ts block.
  • Each computed column needs a graph naming a declared workflow and a non-empty input; an empty output errors; duplicate computed column names error.
  • Execution-loop cycles are rejected (see above).

Further reading

  • Streams: the source rows a view composes
  • Workflows: the graph behind each computed column
  • Context: context.streams, context.row, context.output
  • Syntax: @ts / @json blocks

On this page