# `Arangox.Query`
[🔗](https://github.com/ArangoDB-Community/arangox/blob/v0.8.0/lib/arangox/query.ex#L1)

An AQL query: the statement, and the options the server should run it under.

A query is what `Arangox.query/4` runs and what `Arangox.cursor/4` streams.

## There is no prepare step

_ArangoDB_ has no prepared statements, and `DBConnection.prepare/3` is refused
here rather than implemented. What the server offers instead is a **plan
cache**: a memoisation of parsing and planning, held server-side, keyed by
statement text, and shared by every caller in the database.

That shape matters, because it is not the one the word "prepare" implies. The
first execution populates an entry; the *second* reports the key of the entry
that served it; changing a bind **value** reuses the same entry, since the
plan is parameterised over values. The reuse therefore comes from running the
same text again, and nothing a client holds on to participates in it.

So the plan cache is asked for per query, and only when asked:

    Arangox.query(conn, "FOR d IN c FILTER d.x == @x RETURN d", %{x: 1},
      use_plan_cache: true)

It is opt-in rather than defaulted for two reasons. The server refuses to
cache some statements outright — an UPSERT is refused with `1584`,
`:query_not_eligible_for_plan_caching` — and the option has a server-version
floor of 3.12.4 that this driver gates on. Neither belongs to a caller who
never asked for the cache.

Deliberately holds no database. Plans are cached per database, so a query that
captured one could not be reused against another; the database is a property
of the request, not of the statement.

## Options

AQL options are given as snake_case atoms and mapped to the names the HTTP API
uses. The mapping is taken from the server's own published OpenAPI document,
which is also what decides whether an option belongs at the top level of the
request body or inside its `options` object — `:batch_size` is top-level,
`:full_count` is nested, and nothing about the name says which.

    Arangox.cursor(conn, "FOR i IN 1..100 RETURN i", %{}, batch_size: 10)

    %Arangox.Query{query: "FOR i IN 1..100 RETURN i", opts: [full_count: true]}

An option this module does not know is an error rather than a key invented on
the wire, because the server ignores unknown body attributes silently and a
typo would otherwise look like it worked.

`:properties` remains the escape hatch: a list or map of body attributes
passed through verbatim under the names the server uses. It is merged **last**,
so it wins over a mapped option. That ordering is what keeps code written
against the escape hatch working unchanged when a mapped name for the same
field arrives later.

# `t`

```elixir
@type t() :: %Arangox.Query{opts: keyword(), query: binary()}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
