# 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.

To filter, order, page, and transform the items, use the `query` package:

*(Changed in 2.0)*

```go
import "github.com/thenativeweb/architecturekit-golang/v2/architecturekit/query"
```

To turn the items into a slice, call the `Collect` function. If the view fails while it is read, `Collect` returns its error instead:

```go
type ListBooks struct {
  OnlyAvailable bool
  Limit         int
}

func listBooks(catalog architecturekit.View[BookItem]) func(context.Context, ListBooks) ([]BookItem, error) {
  return func(ctx context.Context, q ListBooks) ([]BookItem, error) {
    items := catalog.All(ctx)

    // ...

    return query.Collect(items)
  }
}
```

All functions of the `query` package take an iterator over items and errors, as `All` returns it, and those that return items return such an iterator again, so they can be combined without collecting anything in between. An error of the view ends the iterator. Every function hands it on unchanged, without calling the function you hand over for it, up to the function that returns the result, such as `Collect`, which returns it.

*Note that `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 `query` package is for reading a view. Once the items are in a slice, for example because an answer groups the same snapshot of a view in several ways, work on the slice with the `slices` package and a loop, such as `slices.SortStableFunc` to order it. A slice can not fail, so handing it to the `query` package would only add errors that never occur.*

## Filtering and Transforming Items

To keep only some items, call the `Where` function with a function that selects them:

```go
if q.OnlyAvailable {
  items = query.Where(items, func(item BookItem) bool {
    return !item.IsBorrowed
  })
}
```

To turn every item into something else, call the `Select` function:

```go
titles := query.Select(items, func(item BookItem) string {
  return item.Title
})
```

## Ordering Items

To order items by a key, call the `OrderBy` function, or the `OrderByDescending` function for the reverse order:

```go
items = query.OrderBy(items, func(item BookItem) string {
  return item.Title
})
```

To order items by a comparison function, for example by several fields, call the `OrderByFunc` function. It expects the same kind of function as `slices.SortFunc`, so `cmp.Or` and `strings.Compare` work with it:

```go
items = query.OrderByFunc(items, func(left, right BookItem) int {
  return cmp.Or(
    strings.Compare(left.Author, right.Author),
    strings.Compare(left.Title, 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 `Skip` function. To stop after a number of items, call the `Take` function:

```go
if q.Limit > 0 {
  items = query.Take(items, q.Limit)
}
```

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

```go
items = query.Take(query.Skip(items, 20), 10)
```

## Getting a Single Item

To get the first item, call the `First` function. It returns `false` if there is none:

```go
first, ok, err := query.First(items)
```

To get the only item, call the `Single` function. It returns `query.ErrNoItems` if there is none, and `query.ErrTooManyItems` if there are several:

```go
type GetBook struct {
  BookID string
}

func getBook(catalog architecturekit.View[BookItem]) func(context.Context, GetBook) (BookItem, error) {
  return func(ctx context.Context, q GetBook) (BookItem, error) {
    return query.Single(query.Where(catalog.All(ctx), func(item BookItem) bool {
      return item.ID == q.BookID
    }))
  }
}
```

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. With an error, the item is empty.

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

## Counting Items

To count items, call the `Count` function. To check whether at least one item matches, call the `Any` function, which stops at the first match:

```go
count, err := query.Count(items)

hasBorrowedBooks, err := query.Any(items, func(item BookItem) bool {
  return item.IsBorrowed
})
```

`Count` reads all items, and if the view fails, it returns the error with `0`. `Any` returns an error only if the view fails before the first match.
