# `Ash.Range`
[🔗](https://github.com/ash-project/ash/blob/v3.35.0/lib/ash/range.ex#L5)

A range of values: a lower bound, an upper bound, and whether each is inclusive.

`Ash.Type.Range` casts to and from it. In `bounds`, `[` or `]` is inclusive and `(` or
`)` exclusive. The default, `:"[)"`, is inclusive-exclusive. A `nil` bound is unbounded.

A range holding no values is empty: see `empty/0`.

### PostgreSQL

`Ash.Range` follows PostgreSQL's ranges: the same bounds, every empty range cast to
one, every range holding the empty range, and the same sort order (`compare/2`).

| the question | PostgreSQL | `Ash.Range` |
| --- | --- | --- |
| do they share a value? | `&&`, "overlaps" | `intersects?/2` |
| does one hold a value, or the other range? | `@>`, "contains" | `contains?/2` |
| does one meet the other, either way round? | `-|-` | `adjacent?/2` |
| which of Allen's relations holds? | — | `relation/2` |

PostgreSQL's overlaps and contains are wider than Allen's: `[1, 10)` intersects and
contains `[3, 5)`, and their relation is `:contains`.

# `allen`

```elixir
@type allen() ::
  :precedes
  | :meets
  | :overlaps
  | :finished_by
  | :contains
  | :starts
  | :equals
  | :started_by
  | :during
  | :finishes
  | :overlapped_by
  | :met_by
  | :preceded_by
```

One of Allen's thirteen interval relations.

# `bounds`

```elixir
@type bounds() :: :&quot;[)&quot; | :&quot;[]&quot; | :&quot;()&quot; | :&quot;(]&quot;
```

# `t`

```elixir
@type t() :: %Ash.Range{
  bounds: bounds(),
  empty?: boolean(),
  lower: term() | nil,
  upper: term() | nil
}
```

# `adjacent?`

```elixir
@spec adjacent?(t(), t()) :: boolean()
```

Whether one range meets the other, in either order: `[1, 5)` and `[5, 9)` are adjacent,
`[1, 5]` and `[5, 9)` share 5, and `[1, 5)` and `(5, 9)` leave it out. An empty range is
adjacent to nothing.

Consecutive ranges, each meeting the next, hold every value from the first lower bound
to the last upper bound once.

Compare ranges cast by `Ash.Type.Range`: as integers, `[1, 4]` and `[5, 9)` are adjacent,
since `[1, 4]` is cast to `[1, 5)`.

# `compare`

```elixir
@spec compare(t(), t()) :: :lt | :eq | :gt
```

Compares two ranges: empty first, then by lower bound, then by upper bound. Unbounded below sorts first, and unbounded above last. Of two bounds on the
same value, `[1` sorts before `(1`, and `5)` before `5]`.

A sort order: `[1, 10)` sorts before `[3, 5)` though it holds it.

# `contains?`

```elixir
@spec contains?(t(), term()) :: boolean()
```

Whether the range holds `value`, which may be a value or another range.

A range holds another range lying within it, and every range holds the empty range.

# `empty`

```elixir
@spec empty() :: t()
```

The empty range, holding no values. A range such as `[1, 1)` holds none, and
`Ash.Type.Range` casts it to this.

    iex> Ash.Range.empty()
    %Ash.Range{lower: nil, upper: nil, bounds: :"[)", empty?: true}

# `empty?`

```elixir
@spec empty?(t()) :: boolean()
```

Whether the range holds no values: `empty/0`, or bounds holding nothing, such as
`[3, 1)` or `[1, 1)`. A range unbounded at either end is never empty.

# `intersects?`

```elixir
@spec intersects?(t(), t()) :: boolean()
```

Whether two ranges share a value: `[1, 3)` and `[3, 5)` do not, `[1, 3]` and `[3, 5)` do.
An empty range intersects nothing.

Allen's `:overlaps` is narrower: `[1, 10)` intersects `[3, 5)`, and `relation/2` gives
`:contains`.

# `lower_inclusive?`

```elixir
@spec lower_inclusive?(bounds()) :: boolean()
```

Whether `bounds` makes the lower bound inclusive.

# `relation`

```elixir
@spec relation(t(), t()) :: allen() | nil
```

Which of Allen's thirteen relations `left` has to `right`, or `nil` if either is empty.
Exactly one holds for two non-empty ranges.

`[1, 5)` meets `[5, 9)`: one ends where the other begins, and exactly one includes that
value. `[1, 5]` overlaps `[5, 9)`, and `[1, 5)` precedes `(5, 9)`.

    iex> Ash.Range.relation(%Ash.Range{lower: 1, upper: 5}, %Ash.Range{lower: 5, upper: 9})
    :meets

# `relations`

```elixir
@spec relations() :: [allen()]
```

The thirteen relations `relation/2` returns, in Allen's order: from `left` furthest
before `right` to furthest after. Their positions can index a thirteen-bit mask.

    iex> Ash.Range.relations()
    [:precedes, :meets, :overlaps, :finished_by, :contains, :starts, :equals, :started_by,
     :during, :finishes, :overlapped_by, :met_by, :preceded_by]

# `upper_inclusive?`

```elixir
@spec upper_inclusive?(bounds()) :: boolean()
```

Whether `bounds` makes the upper bound inclusive.

# `valid_bounds?`

```elixir
@spec valid_bounds?(term()) :: boolean()
```

Whether `bounds` is one of `:"[)"`, `:"[]"`, `:"()"` or `:"(]"`.

---

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