# `Aerospike.Key`
[🔗](https://github.com/luisgabrielroldan/aerospike_driver/blob/v0.3.1/lib/aerospike/key.ex#L1)

Record key: namespace, set, optional user key, and server digest.

The digest is **RIPEMD-160** over `set_name || particle_type_byte || encoded_user_key`.
The namespace is **not** part of the digest (standard Aerospike digest rules).

Supported user keys for `new/3`:

* `integer()` — encoded as particle type `INTEGER` (1) and 8-byte big-endian signed int64
* `String.t()` (binary) — encoded as particle type `STRING` (3) and UTF-8 bytes

Binaries are treated as **string** keys, not blob keys.

## Examples

    iex> k = Aerospike.Key.new("test", "users", "user:42")
    iex> byte_size(k.digest)
    20
    iex> is_binary(k.namespace)
    true

# `key_input`

```elixir
@type key_input() :: t() | key_tuple()
```

Accepted key input at public API boundaries.

Use `%Aerospike.Key{}` directly, or pass `{namespace, set, user_key}` for
convenience when you have user-key components.

# `key_tuple`

```elixir
@type key_tuple() :: {String.t(), String.t(), String.t() | integer()}
```

Tuple key form accepted by public command helpers.

The tuple is expanded with `new/3`, so it supports the same string and int64
user-key values and computes the digest locally.

# `t`

```elixir
@type t() :: %Aerospike.Key{
  digest: &lt;&lt;_::160&gt;&gt;,
  namespace: String.t(),
  set: String.t(),
  user_key: String.t() | integer() | nil
}
```

Record key with namespace, set, optional user key, and digest.

The digest is always a 20-byte Aerospike digest. `user_key` is `nil` for
digest-only keys created with `from_digest/3`.

# `coerce!`

```elixir
@spec coerce!(key_input()) :: t()
```

Coerces a public key input into `%Aerospike.Key{}`.

Passes `%Aerospike.Key{}` through unchanged. For tuple keys, delegates to
`new/3`, so tuple validation and int64 checks follow the same rules.

Raises `ArgumentError` for non-key inputs.

# `from_digest`

```elixir
@spec from_digest(String.t(), String.t(), &lt;&lt;_::160&gt;&gt;) :: t()
```

Builds a key from an existing 20-byte digest.

The returned key keeps `user_key` unset because only the server digest is
known at this boundary.

## Examples

    iex> digest = :crypto.hash(:ripemd160, "digest-only")
    iex> key = Aerospike.Key.from_digest("ns", "users", digest)
    iex> {key.user_key, key.digest == digest}
    {nil, true}

# `new`

```elixir
@spec new(String.t(), String.t(), String.t() | integer()) :: t()
```

Builds a key and computes the RIPEMD-160 digest.

`namespace` must be a non-empty string. `set` may be an empty string.
`user_key` must be an integer in the int64 range or a binary (string key).

Raises `ArgumentError` if the arguments are invalid.

## Examples

    iex> k = Aerospike.Key.new("ns", "s", 1)
    iex> byte_size(k.digest)
    20

# `partition_id`

```elixir
@spec partition_id(t()) :: 0..4095
```

Returns the partition id (0..4095) derived from the digest.

Uses the first four bytes of the digest as a little-endian unsigned 32-bit
integer, then masks to 12 bits (standard partition mapping).

## Examples

    iex> k = Aerospike.Key.new("namespace", "set", 0)
    iex> Aerospike.Key.partition_id(k)
    2451

# `validate_int64!`

```elixir
@spec validate_int64!(integer(), String.t()) :: integer()
```

Validates that `value` fits in Aerospike's signed 64-bit integer range.

This helper is used by key and secondary-index filter builders before values
are encoded for the server. It returns the integer unchanged or raises
`ArgumentError` with `label` in the message.

---

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