# `AshWeight`
[🔗](https://github.com/sephianl/ash_weight/blob/v0.1.0/lib/ash_weight.ex#L1)

A metric weight type for [Ash](https://hexdocs.pm/ash).

Stored canonically as integer milligrams (`BIGINT` in Postgres), with
ergonomic conversions to grams and kilograms via `Decimal` to avoid float
drift.

## Usage

    attribute :weight, AshWeight, constraints: [min: 0]

    AshWeight.new(1.5, :g)        # => %AshWeight{mg: 1500}
    AshWeight.from_kg("2.25")     # => %AshWeight{mg: 2_250_000}
    AshWeight.to_kg(weight)       # => #Decimal<0.0015>
    to_string(AshWeight.from_kg(1.5))  # => "1.5 kg"

Accepted input shapes for `Ash.Type.cast_input/3`:

  * `%AshWeight{}`
  * integer — treated as milligrams
  * `{value, :mg | :g | :kg}` — explicit unit
  * `%{value: _, unit: _}` / `%{"value" => _, "unit" => _}` — form data
  * `nil`

# `t`

```elixir
@type t() :: %AshWeight{mg: integer()}
```

# `unit`

```elixir
@type unit() :: :mg | :g | :kg
```

# `add`

```elixir
@spec add(t(), t()) :: t()
```

Adds two weights.

# `compare`

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

Compares two weights. Returns `:lt`, `:eq`, or `:gt`.

# `from_g`

```elixir
@spec from_g(integer() | float() | Decimal.t() | String.t()) :: t()
```

Builds a weight from a gram value (mass × 1_000 mg).

# `from_kg`

```elixir
@spec from_kg(integer() | float() | Decimal.t() | String.t()) :: t()
```

Builds a weight from a kilogram value (mass × 1_000_000 mg).

# `from_mg`

```elixir
@spec from_mg(integer() | float() | Decimal.t() | String.t()) :: t()
```

Builds a weight from a milligram value.

# `handle_change?`

# `multiply`

```elixir
@spec multiply(t(), integer() | float() | Decimal.t() | String.t()) :: t()
```

Multiplies a weight by a scalar.

# `new`

```elixir
@spec new(value :: integer() | float() | Decimal.t() | String.t(), unit()) :: t()
```

Builds a weight from `value` in the given metric `unit` (default `:mg`).

`value` may be an integer, float, `Decimal`, or numeric string. Internally
normalized through `Decimal` arithmetic and rounded to integer milligrams,
so `new(0.1, :g)` is exactly `100` mg with no float drift.

# `prepare_change?`

# `subtract`

```elixir
@spec subtract(t(), t()) :: t()
```

Subtracts `b` from `a`.

# `to_g`

```elixir
@spec to_g(t()) :: Decimal.t()
```

Returns the weight in grams as a `Decimal`.

# `to_kg`

```elixir
@spec to_kg(t()) :: Decimal.t()
```

Returns the weight in kilograms as a `Decimal`.

# `to_mg`

```elixir
@spec to_mg(t()) :: integer()
```

Returns the weight in integer milligrams.

---

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