# `Selecto.Query`

Core query building operations for Selecto.

This module contains the basic query building functions like select, filter,
order_by, group_by, limit, and offset.

# `filter`

```elixir
@spec filter(Selecto.Types.t(), [Selecto.Types.filter()]) :: Selecto.Types.t()
@spec filter(Selecto.Types.t(), Selecto.Types.filter()) :: Selecto.Types.t()
```

Add filters to the query.

For macro-free query composition, prefer importing `Selecto.Expr` and using
runtime filter constructors like `eq/2`, `gte/2`, and `compact_and/1`.

## Examples

    import Selecto.Expr

    selecto
    |> Selecto.Query.filter(eq("active", true))
    |> Selecto.Query.filter(compact_and([gte("age", 18), not_null("email")]))

# `group_by`

```elixir
@spec group_by(Selecto.Types.t(), [Selecto.Types.field_name()]) :: Selecto.Types.t()
@spec group_by(Selecto.Types.t(), Selecto.Types.field_name()) :: Selecto.Types.t()
```

Add to the Group By clause.

## Examples

    import Selecto.Expr

    selecto
    |> Selecto.Query.group_by(["category", "region"])
    |> Selecto.Query.group_by(rollup(["status"]))

# `limit`

```elixir
@spec limit(Selecto.Types.t(), non_neg_integer()) :: Selecto.Types.t()
```

Limit the number of rows returned by the query.

## Examples

    # Limit to 10 rows
    selecto |> Selecto.Query.limit(10)

    # Limit with offset for pagination
    selecto |> Selecto.Query.limit(10) |> Selecto.Query.offset(20)

# `offset`

```elixir
@spec offset(Selecto.Types.t(), non_neg_integer()) :: Selecto.Types.t()
```

Set the offset for the query results.

## Examples

    # Skip first 20 rows
    selecto |> Selecto.Query.offset(20)

    # Pagination: page 3 with 10 items per page
    selecto |> Selecto.Query.limit(10) |> Selecto.Query.offset(20)

# `order_by`

```elixir
@spec order_by(Selecto.Types.t(), [Selecto.Types.order_spec()]) :: Selecto.Types.t()
@spec order_by(Selecto.Types.t(), Selecto.Types.order_spec()) :: Selecto.Types.t()
```

Add to the Order By clause.

## Examples

    import Selecto.Expr

    selecto
    |> Selecto.Query.order_by([asc("created_at"), desc("name")])

# `post_retarget_filter`

```elixir
@spec post_retarget_filter(Selecto.Types.t(), [Selecto.Types.filter()]) ::
  Selecto.Types.t()
@spec post_retarget_filter(Selecto.Types.t(), Selecto.Types.filter()) ::
  Selecto.Types.t()
```

Explicitly append filters to the post-retarget filter list (`set.post_retarget_filters`).

Use this when constraints should apply to the retargeted target root.

# `post_retarget_filters`

```elixir
@spec post_retarget_filters(Selecto.Types.t()) :: [Selecto.Types.filter()]
```

Return only post-retarget filters currently attached to the query.

# `pre_retarget_filter`

```elixir
@spec pre_retarget_filter(Selecto.Types.t(), [Selecto.Types.filter()]) ::
  Selecto.Types.t()
@spec pre_retarget_filter(Selecto.Types.t(), Selecto.Types.filter()) ::
  Selecto.Types.t()
```

Explicitly append filters to the pre-retarget filter list (`set.filtered`).

Use this when you want filters to be preserved as source-root constraints even
when composing a retargeted query.

# `pre_retarget_filters`

```elixir
@spec pre_retarget_filters(Selecto.Types.t()) :: [Selecto.Types.filter()]
```

Return only pre-retarget filters currently attached to the query.

This reads `set.filtered` and does not include post-retarget buckets.

# `query_filters`

```elixir
@spec query_filters(
  Selecto.Types.t(),
  keyword()
) :: [Selecto.Types.filter()]
```

Return query filters across current buckets as a flat list.

This is useful for integrations that need to copy filters between Selecto and
other query/update builders.

## Options

- `:include_post_retarget` - include `set.post_retarget_filters` (default: `true`)

# `required_filters`

```elixir
@spec required_filters(Selecto.Types.t()) :: [Selecto.Types.filter()]
```

Return required filters currently attached to the query.

This includes domain-level required filters and query-level required filters
added at runtime.

# `select`

```elixir
@spec select(Selecto.Types.t(), [Selecto.Types.selector()]) :: Selecto.Types.t()
@spec select(Selecto.Types.t(), Selecto.Types.selector()) :: Selecto.Types.t()
```

Add fields to the select list.

For macro-free query composition, prefer importing `Selecto.Expr` and passing
string field paths plus runtime helper constructors.

## Examples

    import Selecto.Expr

    selecto
    |> Selecto.Query.select(["name", "email", as(count(), "total")])
    |> Selecto.Query.select(avg("price"))

# `to_sql`

```elixir
@spec to_sql(
  Selecto.Types.t(),
  keyword()
) :: {String.t(), list()}
```

Generate SQL without executing - useful for debugging and caching.

## Examples

    {sql, params} = Selecto.Query.to_sql(selecto)
    IO.puts(sql)

## Options

- `:pretty` - format SQL for readability
- `:highlight` - apply highlighting (`:ansi` or `:markdown`)
- `:indent` - indentation string used by pretty formatter

---

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