guides/wide_column_entities.md

# Wide-Column Entities

Starting with RocksDB 8.8 and Erlang RocksDB 2.0.0, you can store structured data using the Wide-Column Entity API. This allows storing multiple named columns per key, providing a more flexible schema than simple key-value pairs.

## Basic Usage

### Storing an Entity

Use `put_entity/4` to store an entity with multiple columns:

```erlang
{ok, Db} = rocksdb:open("/tmp/mydb", [{create_if_missing, true}]),

%% Store a user entity with multiple attributes
Key = <<"user:123">>,
Columns = [
    {<<"name">>, <<"Alice">>},
    {<<"email">>, <<"alice@example.com">>},
    {<<"role">>, <<"admin">>}
],
ok = rocksdb:put_entity(Db, Key, Columns, []).
```

### Retrieving an Entity

Use `get_entity/3` to retrieve all columns as a proplist:

```erlang
{ok, Result} = rocksdb:get_entity(Db, <<"user:123">>, []),
Name = proplists:get_value(<<"name">>, Result),    %% <<"Alice">>
Email = proplists:get_value(<<"email">>, Result),  %% <<"alice@example.com">>
```

### Deleting an Entity

Entities are deleted using the normal delete operation. All columns are removed when the key is deleted:

```erlang
ok = rocksdb:delete_entity(Db, <<"user:123">>, []),
%% or equivalently:
ok = rocksdb:delete(Db, <<"user:123">>, []).
```

## Column Families

Entities work with column families just like regular key-values:

```erlang
{ok, Db, [DefaultCf, UsersCf]} = rocksdb:open("/tmp/mydb",
    [{create_if_missing, true}, {create_missing_column_families, true}],
    [{"default", []}, {"users", []}]),

%% Store entity in users column family
ok = rocksdb:put_entity(Db, UsersCf, <<"user:456">>,
    [{<<"name">>, <<"Bob">>}], []),

%% Retrieve from column family
{ok, Result} = rocksdb:get_entity(Db, UsersCf, <<"user:456">>, []).
```

## Iterating Over Entities

When iterating, use `iterator_columns/1` to access the columns of the current entry:

```erlang
{ok, Itr} = rocksdb:iterator(Db, []),
{ok, Key, _Value} = rocksdb:iterator_move(Itr, first),

%% Get all columns for the current entry
{ok, Columns} = rocksdb:iterator_columns(Itr),
lists:foreach(fun({Name, Value}) ->
    io:format("~s: ~s~n", [Name, Value])
end, Columns),

rocksdb:iterator_close(Itr).
```

### Mixed Data

`iterator_columns/1` works for both entities and regular key-values:

- **Entities**: Returns all stored columns
- **Regular key-values**: Returns `[{<<>>, Value}]` - a single column with the default (empty) name

```erlang
%% Store mixed data
ok = rocksdb:put(Db, <<"plain_key">>, <<"plain_value">>, []),
ok = rocksdb:put_entity(Db, <<"entity_key">>,
    [{<<"attr">>, <<"value">>}], []),

{ok, Itr} = rocksdb:iterator(Db, []),

%% First entry: entity
{ok, <<"entity_key">>, _} = rocksdb:iterator_move(Itr, first),
{ok, [{<<"attr">>, <<"value">>}]} = rocksdb:iterator_columns(Itr),

%% Second entry: plain key-value
{ok, <<"plain_key">>, <<"plain_value">>} = rocksdb:iterator_move(Itr, next),
{ok, [{<<>>, <<"plain_value">>}]} = rocksdb:iterator_columns(Itr),

rocksdb:iterator_close(Itr).
```

## The Default Column

In RocksDB's wide-column model, the default column has an empty name (`<<>>`). When you use `put/4` to store a regular key-value, it's internally treated as an entity with a single default column:

```erlang
%% These are equivalent from RocksDB's perspective:
rocksdb:put(Db, <<"key">>, <<"value">>, []),
rocksdb:put_entity(Db, <<"key">>, [{<<>>, <<"value">>}], []).
```

When using `get/3` on an entity, RocksDB returns the value of the default column (or empty if none exists).

## Multi-Column Family Iteration

Use `coalescing_iterator/3` to iterate across multiple column families efficiently:

```erlang
{ok, Db, [Cf1, Cf2, Cf3]} = rocksdb:open("/tmp/mydb",
    [{create_if_missing, true}, {create_missing_column_families, true}],
    [{"default", []}, {"cf1", []}, {"cf2", []}]),

%% Store data in different column families
ok = rocksdb:put_entity(Db, Cf1, <<"a">>, [{<<"src">>, <<"cf1">>}], []),
ok = rocksdb:put_entity(Db, Cf2, <<"b">>, [{<<"src">>, <<"cf2">>}], []),

%% Iterate across all column families in sorted key order
{ok, Itr} = rocksdb:coalescing_iterator(Db, [Cf1, Cf2], []),
{ok, <<"a">>, _} = rocksdb:iterator_move(Itr, first),
{ok, <<"b">>, _} = rocksdb:iterator_move(Itr, next),
rocksdb:iterator_close(Itr).
```

## Use Cases

Wide-column entities are useful when:

- You have structured data with multiple attributes per key
- You want to avoid serialization/deserialization overhead
- Different keys may have different sets of columns
- You need to update individual columns without rewriting the entire value

## API Reference

| Function | Description |
|----------|-------------|
| `put_entity/4` | Store entity in default column family |
| `put_entity/5` | Store entity in specified column family |
| `get_entity/3` | Get entity from default column family |
| `get_entity/4` | Get entity from specified column family |
| `delete_entity/3` | Delete entity from default column family |
| `delete_entity/4` | Delete entity from specified column family |
| `iterator_columns/1` | Get columns from current iterator position |
| `coalescing_iterator/3` | Create iterator across multiple column families |