# Defining Queries

A query describes what someone wants to know. Define it as a struct, and answer it with a function that reads a view.

`all` hands out the items of a view as a stream, in which every element is an item or an error (see **[Defining Views](/docs/architecturekit/rust/defining-views)**). To filter and transform the items, and to stop after a number of them, use `TryStreamExt` and `StreamExt` of the **[futures](https://crates.io/crates/futures)** crate, and to order them, to pass over some of them for a page, and to get the first, the single one, or their number, use `QueryExt` of the kit's `query` module. Add the futures crate, and import the traits, together with `View` and `SingleError`, which the examples below use:

```shell
cargo add futures
```

```rust
use architecturekit::{
  View,
  query::{QueryExt, SingleError},
};
use futures::{StreamExt, TryStreamExt, future};
```

To turn the items into a vector, call the `try_collect` method. If the view fails while it is read, `try_collect` returns its error instead:

```rust
struct ListBooks {
  only_available: bool,
  limit: Option<usize>,
}

async fn list_books<V: View<BookItem>>(
  catalog: &V,
  query: ListBooks,
) -> Result<Vec<BookItem>, V::Error> {
  let items = catalog.all();

  // ...

  items.try_collect().await
}
```

The function takes any view that implements `View<BookItem>`, the view in memory as well as one in a database, and returns the error of that view. **Every step takes the stream and returns a stream again**, so the steps can be combined without collecting anything in between. An error of the view ends the stream. `try_filter` and `map_ok` hand it on unchanged, without calling the closure you hand over for it, and so do the steps of `QueryExt`, up to the method that returns the result, such as `try_collect`, which returns it.

*Note that `try_collect` returns no items along with an error, not even the ones it read before, so that a part of the result is never taken for all of it.*

*Note that the steps are for reading a view. Once the items are in a vector, for example because an answer groups the same snapshot of a view in several ways, work on the vector with its own methods and a loop, such as `sort_by_key`, which keeps the order of equal items. A vector can not fail, so handing it to the steps of a stream would only add errors that never occur.*

## Filtering and Transforming Items

To keep only some items, call the `try_filter` method with a closure that selects them, and returns its answer as a future, such as one made with `future::ready`:

```rust
let items = items.try_filter(|item| future::ready(!query.only_available || !item.is_borrowed));
```

To turn every item into something else, call the `map_ok` method:

```rust
let titles = items.map_ok(|item| item.title);
```

## Ordering Items

To order items by a key, call the `order_by` method, or the `order_by_descending` method for the reverse order:

```rust
let items = items.order_by(|item| item.title.clone());
```

To order items by a comparison, for example by several fields, call the `order_by_with` method. It expects a closure that returns an `Ordering`, so `cmp`, `then`, and `then_with` work with it:

```rust
let items = items.order_by_with(|left, right| {
  left.author.cmp(&right.author).then_with(|| left.title.cmp(&right.title))
});
```

*Note that ordering reads all items before it hands out the first one, so if the view fails, it hands out the error alone. Ordering is stable, so items that compare as equal keep their order.*

## Paging Items

To skip a number of items, call the `try_skip` method. To stop after a number of items, call the `take` method:

```rust
let items = items.take(query.limit.unwrap_or(usize::MAX));
```

Both can be combined, for example to get the third page of ten items:

```rust
let page = items.try_skip(20).take(10);
```

`take` reads no further than its items, so it never sees an error that comes later, as `first` does. `try_skip` hands on an error among the items it skips, since it is not an item, so that a view that fails is not taken for one with fewer items. **Page with `try_skip` rather than with `skip` of `StreamExt`, which counts an error like an item, and drops it along with the items it skips**, so that the page of a view that fails would come out empty rather than failed.

## Getting a Single Item

To get the first item, call the `first` method. It returns `None` if there is none:

```rust
let first = items.first().await?;
```

To get the only item, call the `single` method. It fails with `SingleError::NoItems` if there is none, and with `SingleError::TooManyItems` if there are several, and with `SingleError::View` if the view fails:

```rust
struct GetBook {
  book_id: String,
}

async fn get_book<V: View<BookItem>>(
  catalog: &V,
  query: GetBook,
) -> Result<BookItem, SingleError<V::Error>> {
  catalog.all().try_filter(|item| future::ready(item.id == query.book_id)).single().await
}
```

Both stop reading as soon as they know the answer, and return an error of the view only if it comes before that. `first` reads no further than the first item, so it never sees an error that comes later. `single` reads up to the second item, and only knows that an item is the only one once the view has ended, so it also returns an error that comes after the first item.

A missing item and several items belong to no category, since only the application knows what they mean: whether a missing item is expected, and whether several are a mistake in the data or a race. In a handler, `?` answers a missing item with `404 Not Found`, and several with `500 Internal Server Error` (see **[Mapping Errors to Status Codes](/docs/architecturekit/rust/mapping-errors-to-status-codes)**).

*Note that `try_filter` asks about every item it is handed. To get an item by its key, call the `get` method of a `KeyedView` instead, and to get items by the value of a secondary index, call the `lookup` method of the index (see **[Defining Views](/docs/architecturekit/rust/defining-views)**).*

## Counting Items

To count items, call the `try_count` method. To check whether at least one item matches, call the `try_any` method, which stops at the first match:

```rust
let count = catalog.all().try_count().await?;

let has_borrowed_books = catalog.all().try_any(|item| future::ready(item.is_borrowed)).await?;
```

`try_count` reads all items, and if the view fails, it returns the error and no count. It is called `try_count`, since `count` of `StreamExt` counts the errors as well. `try_any` returns an error only if the view fails before the first match. A stream is read once, so each of them reads the view anew.
