# Defining a View and a Query

In this step, you build the **reading side** of the library: a **view** that holds a catalog of all books, a **projection** that fills it from the events, and **queries** that read it.

## Separating Reading from Writing

The state of a book from **[Defining Events and State](/learn/tutorials/first-steps-with-architecturekit/rust/defining-events-and-state)** holds only what decisions need, and only for a single book. A list of all books with their titles needs a different shape, built from the same events. Keeping the two apart is the idea behind **[CQRS](/concepts/cqrs)**: the writing side decides on commands, and the reading side answers queries from **[read models](/concepts/read-models)**, which ArchitectureKit calls **views**.

## Defining the View

A view holds **items**, each under a **key** of its own. For the catalog, an item describes a book, and its key is the ID of the book. A **projection** turns events into items: it adds an item when a book is acquired, and changes it when the book is borrowed or returned.

Create a file `src/catalog.rs`:

```rust
use std::sync::Arc;

use architecturekit::{Envelope, InMemoryView, Projection, Revision, Subject, ViewError};

use crate::book::BookEvent;
use crate::commands::BOOK_SUBJECT;

#[derive(Clone, Debug)]
pub struct BookItem {
  pub id: String,
  pub title: String,
  pub author: String,
  pub is_borrowed: bool,
  pub borrowed_until: String,
}

pub fn new_catalog() -> Arc<InMemoryView<String, BookItem>> {
  Arc::new(InMemoryView::new(|item: &BookItem| item.id.clone()))
}

pub struct CatalogProjection {
  catalog: Arc<InMemoryView<String, BookItem>>,
}

impl CatalogProjection {
  pub fn new(catalog: Arc<InMemoryView<String, BookItem>>) -> Self {
    CatalogProjection { catalog }
  }
}

impl Projection for CatalogProjection {
  type Event = BookEvent;
  type Error = ViewError;

  async fn apply(&self, event: Envelope<BookEvent>) -> Result<(), ViewError> {
    let book_id = book_id_of(&event.subject);

    match &event.data {
      BookEvent::Acquired(acquired) => {
        self.catalog.insert(
          &event,
          BookItem {
            id: book_id,
            title: acquired.title.clone(),
            author: acquired.author.clone(),
            is_borrowed: false,
            borrowed_until: String::new(),
          },
        )?;
      }
      BookEvent::Borrowed(borrowed) => {
        self.catalog.update(&book_id, &event, |item| {
          item.is_borrowed = true;
          item.borrowed_until = borrowed.borrowed_until.clone();
        })?;
      }
      BookEvent::Returned(_) => {
        self.catalog.update(&book_id, &event, |item| {
          item.is_borrowed = false;
          item.borrowed_until = String::new();
        })?;
      }
    }

    Ok(())
  }

  fn seen(&self, event_id: Revision) {
    self.catalog.seen(event_id);
  }
}

fn book_id_of(subject: &Subject) -> String {
  BOOK_SUBJECT.value(subject, "book").unwrap_or_default().to_owned()
}
```

**`InMemoryView::new`** creates a view that holds its items in memory, and takes the key of an item from the given closure. `new_catalog` wraps it in an `Arc`, since the projection writes to the catalog while the queries read from it.

A projection implements **`Projection`**: `Event` names the enum of the events it applies, here the one of the state, and `Error` the error it fails with, here the **`ViewError`** of the view. **`apply`** receives every event in an **`Envelope`**, which holds the metadata of the event, such as its `id` and `subject`, and its data in `data`, already decoded into the enum, so that a `match` handles every event type.

`apply` calls **`insert`** to add an item, and **`update`** to change one. Both take the event they apply, so that the view can skip an event it has applied before. Both also return an **outcome**, which tells what they did, for example whether they skipped the event. The catalog does not need it, so `?` hands on only the error. Since the events do not contain the ID of the book, `book_id_of` takes it out of the subject with **`value`** of the subject scheme from **[Making Decisions](/learn/tutorials/first-steps-with-architecturekit/rust/making-decisions)**, which returns the value of the placeholder `book`.

**`seen`** tells the catalog about every event the projection has seen, including those it has nothing to do with. The last of them is the catalog's **revision**, which lets callers read their own writes in **[Serving Commands and Queries over HTTP](/learn/tutorials/first-steps-with-architecturekit/rust/serving-commands-and-queries-over-http)**.

For details, see **[Defining Views](/docs/architecturekit/rust/defining-views)** and **[Projections](/docs/architecturekit/rust/projections)**.

## Defining the Queries

A query describes what someone wants to know, and a function answers it by reading a view. A view hands out its items as a **stream**, and the steps that filter and collect a stream come from the `futures` crate. Add it:

```shell
cargo add futures
```

Then create a file `src/queries.rs` with a query that lists books, optionally only those that are available, and one that gets a single book by its ID:

```rust
use architecturekit::{KeyedView, View};
use futures::{TryStreamExt, future};
use serde::Serialize;

use crate::catalog::BookItem;

#[derive(Serialize)]
pub struct ListBooks {
  pub only_available: bool,
}

pub async fn list_books<V: View<BookItem>>(
  catalog: &V,
  query: &ListBooks,
) -> Result<Vec<BookItem>, V::Error> {
  catalog
    .all()
    .try_filter(|item| future::ready(!query.only_available || !item.is_borrowed))
    .try_collect()
    .await
}

#[derive(Serialize)]
pub struct GetBook {
  pub book_id: String,
}

pub async fn get_book<V: KeyedView<str, BookItem>>(
  catalog: &V,
  query: &GetBook,
) -> Result<Option<BookItem>, V::Error> {
  catalog.get(&query.book_id).await
}
```

**`all`** of the trait **`View`** returns a stream of the items of the view, which `InMemoryView` hands out in the order in which they were added, each as a `Result`, since a view that keeps its items in a database may fail while it reads them. **`try_filter`** of `TryStreamExt` keeps only the items that match, and **`try_collect`** collects them into a `Vec`, or returns the error if the view has failed. For everything else a query can do with the stream, such as ordering and paging, see **[Defining Queries](/docs/architecturekit/rust/defining-queries)**.

`get_book` does not run over all items, since the catalog can find a book by its key. So it takes a **`KeyedView`**, a view that offers **`get`**, which returns the item with the given key, or `None` if there is none. That way, a missing book can be told apart from a failure, which is the error. `InMemoryView` is a `KeyedView`, also for a key of type `str` when its keys are `String`s, so the catalog serves both queries (see **[Defining Views](/docs/architecturekit/rust/defining-views)**). You put `get_book` to use in **[Serving Commands and Queries over HTTP](/learn/tutorials/first-steps-with-architecturekit/rust/serving-commands-and-queries-over-http)**, which also needs the queries to derive `Serialize`.

## Running the Projection

Add the new modules to `src/lib.rs`, which now reads:

```rust
pub mod book;
pub mod catalog;
pub mod commands;
pub mod deciders;
pub mod events;
pub mod queries;
pub mod store;
```

Replace the content of `src/main.rs` with a program that builds the catalog from the stored events and lists all books:

```rust
use std::error::Error;
use std::sync::Arc;

use architecturekit::Subjects;
use library::catalog::{CatalogProjection, new_catalog};
use library::commands::BOOK_SUBJECT;
use library::queries::{ListBooks, list_books};
use library::store::new_store;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
  let store = new_store().await?;

  let catalog = new_catalog();
  let projection = CatalogProjection::new(Arc::clone(&catalog));

  store.catch_up_projection(&Subjects::tree(BOOK_SUBJECT.root()), &projection).await?;

  let query = ListBooks { only_available: false };
  let books = list_books(&catalog, &query).await?;

  for book in books {
    println!("{book:?}");
  }

  Ok(())
}
```

**`root`** of the subject scheme returns `/books`, the part of its pattern before the first placeholder, and **`Subjects::tree`** stands for that subject together with every subject below it. So **`catch_up_projection`** reads all events that are stored below `/books`, and applies them to the projection. It returns once all stored events have been applied.

Run the program:

```shell
cargo run
```

It prints the book from **[Making Decisions](/learn/tutorials/first-steps-with-architecturekit/rust/making-decisions)**, as `BookItem` derives `Debug` for it, now with its title and author from the `BookAcquired` event, and the return date from the `BookBorrowed` event:

```text
BookItem { id: "42", title: "2001 – A Space Odyssey", author: "Arthur C. Clarke", is_borrowed: true, borrowed_until: "2026-10-24" }
```

The view lives in memory, so it is gone once the program ends, and the projection builds it again from the events on the next start. That is fine, because the events are the **source of truth**, and a view can always be rebuilt from them. For views that keep their data and resume where they stopped, see **[Resuming Projections](/docs/architecturekit/rust/projections#resuming-projections)**.
