AshScylla.Identifier (AshScylla v1.2.0)

Copy Markdown View Source

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.

Summary

Functions

Quotes a CQL identifier for safe interpolation into CQL strings.

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

Returns the regex used to validate keyspace names.

Validates that the given string is a safe CQL identifier.

Validates a keyspace name, raising if invalid.

Functions

quote_name(name)

@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!(name)

@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()

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

Returns the regex used to validate keyspace names.

validate(name)

@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!(name)

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

Validates a keyspace name, raising if invalid.