# `AshScylla.DataLayer.Batch`
[🔗](https://github.com/ohhi-vn/ash_scylla/blob/main/lib/ash_scylla/data_layer/batch.ex#L15)

Batch operations support for AshScylla using ScyllaDB's BATCH statements.

ScyllaDB/Cassandra supports batch operations for executing multiple
CQL statements in a single request.

## Synchronous Batches

For small batches or when ordering matters, use `batch_insert/3`,
`batch_update/3`, or `batch_delete/3`.

## Async Partition-Aware Batches

For large bulk operations, use `batch_insert_async/4`. This function:
- Groups records by partition key (safe for ScyllaDB)
- Executes sub-batches in parallel using `Task.async_stream`
- Respects ScyllaDB's recommendation to avoid cross-partition BATCH statements

## Examples

    # Synchronous batch
    statements = [
      {"INSERT INTO users (id, name) VALUES (?, ?)", [id1, "Alice"]},
      {"INSERT INTO users (id, name) VALUES (?, ?)", [id2, "Bob"]}
    ]
    AshScylla.DataLayer.Batch.batch_insert(repo, statements)

    # Async partition-aware batch
    AshScylla.DataLayer.Batch.batch_insert_async(repo, statements, max_concurrency: 8)

## Consistency

Batch operations use `:all` consistency by default. Override with
`consistency:` option.

# `batch_delete`

```elixir
@spec batch_delete(module(), [{String.t(), list()}], keyword()) ::
  {:ok, term()} | {:error, term()}
```

Executes a batch of DELETE statements.

# `batch_insert`

```elixir
@spec batch_insert(module(), [{String.t(), list()}], keyword()) ::
  {:ok, term()} | {:error, term()}
```

Executes a batch of INSERT statements.

# `batch_insert_async`

```elixir
@spec batch_insert_async(module(), [{String.t(), list()}], keyword()) ::
  {:ok, [term()]} | {:error, term()}
```

Executes batch inserts asynchronously, grouped by partition key.

This is the recommended approach for large bulk inserts in ScyllaDB.
Records are grouped by their partition key values, and each group
is executed as a separate batch in parallel. This avoids the
cross-partition BATCH anti-pattern.

## Options

- `:max_concurrency` - Maximum number of concurrent batch executions
  (defaults to `System.schedulers_online()`)

## Examples

    statements = [
      {"INSERT INTO users (id, name) VALUES (?, ?)", [id1, "Alice"]},
      {"INSERT INTO users (id, name) VALUES (?, ?)", [id2, "Bob"]},
      # ... hundreds more
    ]

    DataLayer.Batch.batch_insert_async(repo, statements, resource: MyApp.User)

# `batch_update`

```elixir
@spec batch_update(module(), [{String.t(), list()}], keyword()) ::
  {:ok, term()} | {:error, term()}
```

Executes a batch of UPDATE statements.

# `chunk_batch`

```elixir
@spec chunk_batch(
  [{String.t(), list()}],
  keyword()
) :: [[{String.t(), list()}]]
```

Splits a list of statements into chunks suitable for BATCH execution.

ScyllaDB has a configurable batch size threshold (default warn at 128KB,
fail at 256KB). Sending too many statements in a single BATCH will
cause performance degradation or outright failure. This function
chunks statements to stay within safe limits.

## Options

- `:max_statements_per_batch` — Maximum statements per chunk (default: 500)

## Examples

    statements = [{"INSERT INTO users (id) VALUES (?)", [i]} | 1..2000]
    chunks = AshScylla.DataLayer.Batch.chunk_batch(statements)
    # => 4 chunks of 500 statements each

# `default_max_statements_per_batch`

```elixir
@spec default_max_statements_per_batch() :: pos_integer()
```

Returns the default max statements per batch.

# `partition_key`

```elixir
@spec partition_key(map(), module()) :: map()
```

# `partition_key_hash`

```elixir
@spec partition_key_hash(list(), [atom()] | nil) :: non_neg_integer()
```

---

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