# `AshScylla.Identifier`
[🔗](https://github.com/ohhi-vn/ash_scylla/blob/main/lib/ash_scylla/identifier.ex#L15)

Centralized CQL identifier sanitization.

All CQL identifiers (table names, column names, keyspace names, index names,
etc.) MUST be validated through this module before being interpolated into
CQL strings. This prevents CQL injection attacks.

## Valid identifiers

CQL identifiers must start with a letter or underscore, followed by
alphanumeric characters or underscores. This matches the regex
`~r/^[a-zA-Z_][a-zA-Z0-9_]*$/`.

## Usage

    iex> AshScylla.Identifier.sanitize!("users")
    "users"

    iex> AshScylla.Identifier.sanitize!("my_table")
    "my_table"

    iex> AshScylla.Identifier.sanitize!("users; DROP TABLE users")
    ** (ArgumentError) Invalid CQL identifier: "users; DROP TABLE users"

## Design

This module is compile-time optimized: `sanitize_identifier/1` is inlined
and the regex match is compiled once. All public CQL-generating functions
in AshScylla call this before interpolating identifiers.

# `quote_name`

```elixir
@spec quote_name(atom() | String.t()) :: String.t() | no_return()
```

Quotes a CQL identifier for safe interpolation into CQL strings.

Validates the identifier first, then wraps in double quotes.
Escapes embedded double quotes by doubling them per CQL spec.

Returns the quoted string, or raises `ArgumentError` if invalid.

## Examples

    iex> AshScylla.Identifier.quote_name("users")
    ""users""

    iex> AshScylla.Identifier.quote_name("my table")
    ** (ArgumentError) Invalid CQL identifier: ...

# `sanitize!`

```elixir
@spec sanitize!(atom() | String.t()) :: String.t() | no_return()
```

Validates that the given value is a safe CQL identifier, raising on failure.

Accepts both atoms (common in Ash resource definitions) and strings.
Atoms are converted to strings before validation.

Returns the sanitized string if valid, raises `ArgumentError` if not.

# `valid_keyspace_regex`

```elixir
@spec valid_keyspace_regex() :: Regex.t()
```

Returns the regex used to validate keyspace names.

# `validate`

```elixir
@spec validate(String.t()) :: {:ok, String.t()} | {:error, String.t()}
```

Validates that the given string is a safe CQL identifier.

Returns `{:ok, name}` if valid, or `{:error, reason}` if not.

# `validate_keyspace!`

```elixir
@spec validate_keyspace!(String.t() | atom()) :: String.t() | no_return()
```

Validates a keyspace name, raising if invalid.

---

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