# A page query with no bound

> osy lint's ui-page-query-without-a-take (CONSIDER) is the catch-all: a page query reads every row of an entity with no Take, and the page uses it some other way than a list, a dropdown or a chart. A page query is sent about 2 MB of rows an answer, so whatever the page computes from it is computed over the first answer once the table is larger. Bound it, narrow it, or ask for the number itself.

<!-- id: ui-unbounded-page-queries · area: ui · stability: stable · html: https://osysharp.com/reference/ui/unbounded-page-queries/ -->

## Summary        {#summary}

`ui-page-query-without-a-take` is a **CONSIDER** finding: a page holds a read of every row of an entity and uses it for
something other than drawing a list, a choice or a chart — a count, a total, a row handed to another component. A page
query is sent about 2 MB of rows an answer ([How many rows a page is sent](https://osysharp.com/reference/ui/read-limits/)), so a count taken from the list stops where the
answer does.

When the page needs a number, ask for the number; it is answered over every row:

```osy title="a count asked of the database, not of a list" test app=ui-unbounded-page-queries
entity Visit {
  DateTime At;
  security { allow read, create when IsAnonymous || IsAuthenticated; }
}

[Route("/visits")] [Render(CSR)] [AllowAnonymous]
component VisitsPage() {
  live var visits = Visit.Count();

  render { Text($"{visits} visits"); }
}
```

## Signature      {#signature}

```osy syntax
live var n = Entity.Count(x => …);              // a number over every row
live var rows = Entity.….Take(n).ToList();      // or a bound the author chose
```

## Description    {#description}

### When does it fire?   {#fires}

On a component field read from an entity with no `Take` that the render reads, when none of the three specific rules
applies — it is not a list's rows ([A list or table with no bound](https://osysharp.com/reference/ui/unbounded-lists/)), not a choice's options
([A picker over every row — the SearchPicker](https://osysharp.com/reference/ui/search-pickers/)) and not a chart's data ([A chart over every row](https://osysharp.com/reference/ui/chart-aggregates/)).

### When is it silent?   {#silent}

When the read is bounded (a `Take`, a one-row read, an aggregate, a child collection pinned to one parent), and when
the page never draws it at all — a read only an action uses, such as an export. An export of every row belongs in a
server function, which is never capped.

### An editor's list   {#editors}

A page that adds rows of the entity it lists before a Save is told here rather than by the list rule, because the list
rule's remedy — a `Take` — would hide the row just added: an unsaved row joins a list only while the list is every row
of its type. When the set is a handful by construction, say so on the member, with the reason:

```osy title="an editor of a handful, and why it reads every row" test app=ui-unbounded-page-queries-editor
entity Shelf {
  [Required, MaxLength(40)] string Name;
  int Rank;
  security { allow read, create, update when IsAnonymous || IsAuthenticated; }
}

[Route("/shelves")] [Render(CSR)] [AllowAnonymous]
component ShelvesEditor() {
  // Every shelf: one added here is on the list before Save only while the list is every row. A shop has a handful.
  [SuppressWarning("ui-page-query-without-a-take")]
  live var shelves = Shelf.OrderBy(s => s.Rank).ToList();

  action Add() { UnitOfWork.Mark("Add a shelf"); new Shelf { Name = "New shelf", Rank = shelves.Count + 1 }; }
  action Save() { UnitOfWork.Commit(); }

  render {
    Stack(gap: 2) {
      foreach (var s in shelves) { Text(s.Name); }
      Button("Add a shelf", onPress: Add);
      Button("Save", onPress: Save);
    }
  }
}
```

When it can grow, edit it a parent at a time — a parent's collection takes a new child too — or commit each row as it
is made and bound the list with `.OrderBy(…).Take(n)`.

### Why CONSIDER?   {#tier}

Because it is the widest net: the linter sees that the page holds a read with no bound, not what the page does with it.
A component that pages its own rows still holds an unbounded read, and the remedy — a `Take`, a `Where` — is cheap.

## See also        {#see-also}

- [How many rows a page is sent](https://osysharp.com/reference/ui/read-limits/) — what a page is sent
- [A list or table with no bound](https://osysharp.com/reference/ui/unbounded-lists/) — a list's rows with no bound
