# Reading Your Own Writes

A view lags behind the events that have been written, by however long its projection takes. To read your own writes, wait until the view has seen the events you have written.

The ID of the last event a view has seen is its revision. Since the database assigns event IDs in ascending order across all subjects, revisions can be compared.

A view sees only the events of the subjects its projection reads. So wait only for a write to one of those subjects: if the write went to another subject, the view does not reach its revision until a later event lands in one of its own subjects, and waiting for it lasts the full time, with `WaitFor`, with `Await`, and with the `Wait-For-Revision` header alike. `WaitForWritten` even fails then, with an error that wraps `ErrNotCaughtUp`, so hand it only the events written to the subjects the view reads.

## Tracking Revisions

To track the revision of a view, wrap the projection with the `Tracking` function and hand over the view. It records every event that reaches the projection, including the ones the projection ignores:

```go
trackedProjection := architecturekit.Tracking(catalogProjection, catalog)
```

If the projection writes to several views, such as a `libraryProjection` that keeps both the `catalog` and the `readers` up to date (see **[Sharing Items with Readers](/docs/architecturekit/v2.0/defining-views#sharing-items-with-readers)**), hand over all of them, so that each one knows how far it has come:

```go
trackedProjection := architecturekit.Tracking(libraryProjection, catalog, readers)
```

Then run `trackedProjection` instead of `catalogProjection` (see **[Running Projections](/docs/architecturekit/v2.0/projections#running-projections)**).

`Tracking` accepts every view that implements the `RevisionSink` interface, which consists of the `Seen` function. `InMemoryView` implements it. The interface is meant for a view that keeps no transaction, since `Tracking` records the revision once the projection has applied the event, apart from its data. Where data and revision have to become durable together, as in a view in a database, the revision belongs inside the transaction, so the projection has to write it itself.

*Note that calling `Tracking` with `nil` as the projection, without any view, or with `nil` as one of the views panics. A `nil` pointer or a `nil` `ProjectionFunc` counts as `nil`, too, such as a view that was declared but never created with `NewInMemoryView`.*

The tracked projection keeps the mode and the batch size of the projection it wraps. A transactional projection can not be tracked, since it has no `Apply` function. Record its revision within the transaction instead.

To get the revision your own write has produced, call the `RevisionOf` function with the written events. It returns the highest event ID, or an empty string if no events were written:

```go
revision := architecturekit.RevisionOf(writtenEvents)
```

## Waiting for Revisions

To wait until a view has reached a revision, call the `WaitFor` function with a context and the revision. It returns `nil` once the view has reached the revision, at once if it has already. If the context ends first, it returns the error of the context, such as `context.DeadlineExceeded`, and for a value that is not a revision, it returns an error that wraps `ErrNotARevision` (see **[Comparing Revisions](/docs/architecturekit/v2.0/reading-your-own-writes#comparing-revisions)**):

```go
ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
defer cancel()

err := catalog.WaitFor(ctx, revision)
if err != nil {
  // ...
}
```

*Note that running out of time is an error here. The `Await` function of the `httpapi` package, which waits for the revision an HTTP request asks for, takes it for none instead, and returns `nil`, so that the handler answers with what the view holds (see **[Waiting for a Revision in a Handler of Your Own](/docs/architecturekit/v2.0/reading-your-own-writes-over-http#waiting-for-a-revision-in-a-handler-of-your-own)**).*

To get the current revision of a view, call the `Revision` function with a context. It returns an empty string as long as the view has not seen any event, and an error if it can not read the revision, which may happen to a view of your own that keeps its revision in a database. `InMemoryView` keeps its revision in memory, so it never fails:

```go
current, err := catalog.Revision(ctx)
if err != nil {
  // ...
}
```

Both functions form the `Revisioned` interface, which `InMemoryView` implements. To wait for revisions of a view of your own, implement it as well.

## Comparing Revisions

To compare two revisions, call the `CompareRevisions` function. Like `cmp.Compare`, it returns `-1`, `0`, or `1`. An empty revision comes before every other one. If a value is not a revision, it returns an error that wraps `ErrNotARevision` and names the value:

```go
result, err := architecturekit.CompareRevisions("9", "10")
// result == -1
```

A revision is a decimal number from `0` to `2^63-1`, the range of the event IDs of the database. To check a revision that comes from outside, such as the one a caller hands over, call the `ParseRevision` function. It reads the revision by the same rules, and returns the number it stands for. Unlike `CompareRevisions`, it refuses an empty revision as well, since that is the ID of no event, and so it is the function to check a revision with before it becomes part of a command (see **[Handling Commands over HTTP](/docs/architecturekit/v2.0/handling-commands-over-http)**):

```go
number, err := architecturekit.ParseRevision("42")
// number == 42

_, err = architecturekit.ParseRevision("")
// errors.Is(err, architecturekit.ErrNotARevision) == true
```

For a value that is not a revision, it returns an error that wraps `ErrNotARevision` and names the value, as `CompareRevisions` does.

## Waiting for Written Events

Sometimes a step on the server builds on what was just written, for example a handler that executes a command and then answers with what a view holds after it. To wait until a view has seen the events that `Execute` or `Write` returned, call the `WaitForWritten` function with a context, the view, the written events, and how long to wait at most:

```go
writtenEvents, err := architecturekit.Execute(ctx, store, borrowBook, cmd)
if err != nil {
  // ...
}

err = architecturekit.WaitForWritten(ctx, catalog, writtenEvents, 5*time.Second)
if errors.Is(err, architecturekit.ErrNotCaughtUp) {
  // The command has succeeded, so answer with success all the same, and with
  // the revision, for which the caller can wait with Wait-For-Revision.
}
```

It waits with `WaitFor` for the revision that `RevisionOf` returns for the events, and returns `nil` once the view has reached it. If no events were written, it returns `nil` at once, since there is nothing to wait for. Every error it returns wraps `ErrNotCaughtUp`, since the events were written in any case, and says why the view has not caught up, keeping the cause, so that `errors.Is` and `errors.As` still find it:

- If the time runs out first, the error says so, as in `not caught up: the events were written, but the view did not catch up within 5s`.
- If the context ends first, it wraps the error of the context, as in `not caught up: the events were written, but waiting for the view ended: context canceled`, so `errors.Is` finds `context.Canceled` or `context.DeadlineExceeded`.
- If the view fails otherwise, for example because a view in a database can not read its revision, it wraps the error of the view, as in `not caught up: the events were written, but the view could not be asked: …`, together with the category of that error, if it has one.

`ErrNotCaughtUp` belongs to no category, since the write has succeeded, and only the view lags behind: trying the write again would store its events twice, and the view may still catch up (see **[Handling Errors](/docs/architecturekit/v2.0/handling-errors)**). So a handler that waits after a command usually answers with success when it gets `ErrNotCaughtUp`, as in the example above, and with the revision of the written events. If the caller needs to see what was written, it can wait for the revision with the `Wait-For-Revision` header of a query (see **[Reading Your Own Writes over HTTP](/docs/architecturekit/v2.0/reading-your-own-writes-over-http)**). Answered as an error, `StatusFor` maps it to `500 Internal Server Error`, rather than to a status that invites trying again, also if its cause is `ErrTransient` or the end of the context, and the message says that the request has succeeded (see **[Mapping Errors to Status Codes](/docs/architecturekit/v2.0/mapping-errors-to-status-codes)**).

*Note that the view sees only the events of the subjects its projection reads, so hand over only the events written to those subjects. For a write to several subjects, such as one with `Write`, the highest ID of all events may lie in a subject the view does not read, and then the view does not reach it until a later event lands in one of its own subjects (see **[Waiting for Revisions](/docs/architecturekit/v2.0/reading-your-own-writes#waiting-for-revisions)**).*

*Note that running out of time is an error here, since the step needs what was written. The `Await` function of the `httpapi` package, on the other hand, waits for the revision a caller asks for, and takes running out of time for none, so that the handler answers with what the view holds (see **[Waiting for a Revision in a Handler of Your Own](/docs/architecturekit/v2.0/reading-your-own-writes-over-http#waiting-for-a-revision-in-a-handler-of-your-own)**).*

*Note that `WaitForWritten` panics for a `nil` view, a `nil` pointer included, and for a timeout that is not positive, since a view that catches up with a write that has just happened needs some time, and waiting no time at all would fail almost always.*
