Collection type (LIST, SET, MAP) optimization for ScyllaDB.
Provides encoding/decoding, CQL generation, and query building for ScyllaDB collection types with support for:
- Frozen collections (immutable, stored as single values)
- Collection literals in CQL
- Collection operations (append, prepend, remove, index access)
- Secondary indexes on collections (for SET/LIST: full collection; for MAP: keys, values, or entries)
Usage
# Encode a list for Xandra
AshScylla.DataLayer.Collection.encode([1, 2, 3], :list, element_type: :int)
# Generate CQL for appending to a collection
AshScylla.DataLayer.Collection.append_cql(:users, :tags, ["new_tag"])
# Generate a CONTAINS filter
AshScylla.DataLayer.Collection.contains_cql(:users, :tags, "search_tag")
Summary
Functions
Generates CQL for appending to a collection.
Generates CQL for a secondary index on a collection column.
Returns the CQL type string for a collection type.
Generates CQL for a CONTAINS filter (for queries).
Generates CQL for a CONTAINS KEY filter (for map queries).
Decodes a collection from Xandra to Elixir format.
Encodes an Elixir collection to Xandra-compatible format.
Generates CQL for accessing a collection element by index/key.
Optimizes a collection value for storage.
Generates CQL for prepending to a list.
Generates CQL for removing from a collection.
Generates CQL for setting a collection element by index/key.
Generates CQL for getting collection size.
Validates a collection value against its declared type.
Functions
Generates CQL for appending to a collection.
Uses the + operator to append elements.
Examples
iex> AshScylla.DataLayer.Collection.append_cql(:users, :tags, ["new_tag"])
"UPDATE users SET tags = tags + ? WHERE ..."
iex> AshScylla.DataLayer.Collection.append_cql("users", :tags, ["new_tag"])
"UPDATE users SET tags = tags + ? WHERE ..."
@spec collection_index_cql( String.t() | atom(), atom(), :values | :keys | :entries | :full ) :: String.t()
Generates CQL for a secondary index on a collection column.
Index Types
:full— Index the entire frozen collection:values— Index individual values in a set or list:keys— Index map keys:entries— Index map entries as key-value pairs
Examples
iex> AshScylla.DataLayer.Collection.collection_index_cql(:users, :tags, :values)
"CREATE INDEX ON users (VALUES(tags))"
iex> AshScylla.DataLayer.Collection.collection_index_cql(:users, :metadata, :keys)
"CREATE INDEX ON users (KEYS(metadata))"
iex> AshScylla.DataLayer.Collection.collection_index_cql(:users, :frozen_data, :full)
"CREATE INDEX ON users (FULL(frozen_data))"
Returns the CQL type string for a collection type.
Options
:element_type— Element type for list/set (default::text):key_type— Key type for map (default::text):value_type— Value type for map (default::text):frozen— If true, wrap inFROZEN<...>
Examples
iex> AshScylla.DataLayer.Collection.collection_type_to_cql(:list, element_type: :text)
"LIST<TEXT>"
iex> AshScylla.DataLayer.Collection.collection_type_to_cql(:set, element_type: :int)
"SET<INT>"
iex> AshScylla.DataLayer.Collection.collection_type_to_cql(:map, key_type: :text, value_type: :int)
"MAP<TEXT, INT>"
iex> AshScylla.DataLayer.Collection.collection_type_to_cql(:list, element_type: :text, frozen: true)
"FROZEN<LIST<TEXT>>"
Generates CQL for a CONTAINS filter (for queries).
Returns a {cql_fragment, params} tuple.
Examples
iex> AshScylla.DataLayer.Collection.contains_cql(:users, :tags, "admin")
{"tags CONTAINS ?", ["admin"]}
Generates CQL for a CONTAINS KEY filter (for map queries).
Returns a {cql_fragment, params} tuple.
Examples
iex> AshScylla.DataLayer.Collection.contains_key_cql(:users, :metadata, "role")
{"metadata CONTAINS KEY ?", ["role"]}
Decodes a collection from Xandra to Elixir format.
Options
:frozen— If true, unwrap from tuple format
Examples
iex> AshScylla.DataLayer.Collection.decode(["a", "b"], :list, [])
["a", "b"]
iex> AshScylla.DataLayer.Collection.decode({1, 2, 3}, :set, frozen: true)
[1, 2, 3]
iex> AshScylla.DataLayer.Collection.decode({"k", "v"}, :map, frozen: true)
%{"k" => "v"}
Encodes an Elixir collection to Xandra-compatible format.
Options
:element_type— The type of elements (:text,:int,:uuid, etc.):key_type— For maps, the key type (default::text):value_type— For maps, the value type (default::text):frozen— If true, wrap in a tuple for frozen collections
Examples
iex> AshScylla.DataLayer.Collection.encode(["a", "b"], :list, element_type: :text)
["a", "b"]
iex> AshScylla.DataLayer.Collection.encode([1, 2, 3], :set, element_type: :int)
MapSet.new([1, 2, 3])
iex> AshScylla.DataLayer.Collection.encode(%{"k" => "v"}, :map, key_type: :text, value_type: :text)
%{"k" => "v"}
Generates CQL for accessing a collection element by index/key.
Examples
iex> AshScylla.DataLayer.Collection.get_at_cql(:users, :items, 0)
"SELECT items[?] FROM users WHERE ..."
iex> AshScylla.DataLayer.Collection.get_at_cql(:users, :metadata, "key")
"SELECT metadata[?] FROM users WHERE ..."
Optimizes a collection value for storage.
For lists: no change. For sets: sorts for consistent encoding. For maps: no change. For frozen: converts to tuple.
Examples
iex> AshScylla.DataLayer.Collection.optimize_for_storage([3, 1, 2], :set, element_type: :int)
[1, 2, 3]
iex> AshScylla.DataLayer.Collection.optimize_for_storage(["a", "b"], :list, element_type: :text)
["a", "b"]
Generates CQL for prepending to a list.
Uses the + operator with the value on the left side (list prepend).
Examples
iex> AshScylla.DataLayer.Collection.prepend_cql(:users, :items, ["first"])
"UPDATE users SET items = ? + items WHERE ..."
Generates CQL for removing from a collection.
Uses the - operator to remove elements.
Examples
iex> AshScylla.DataLayer.Collection.remove_cql(:users, :tags, ["old_tag"])
"UPDATE users SET tags = tags - ? WHERE ..."
Generates CQL for setting a collection element by index/key.
Examples
iex> AshScylla.DataLayer.Collection.set_at_cql(:users, :items, 0, "first")
"UPDATE users SET items[?] = ? WHERE ..."
iex> AshScylla.DataLayer.Collection.set_at_cql(:users, :metadata, "key", "val")
"UPDATE users SET metadata[?] = ? WHERE ..."
Generates CQL for getting collection size.
Examples
iex> AshScylla.DataLayer.Collection.size_cql(:users, :tags)
"SELECT SIZE(tags) FROM users WHERE ..."
Validates a collection value against its declared type.
Examples
iex> AshScylla.DataLayer.Collection.validate(["a", "b"], :list, element_type: :text)
:ok
iex> AshScylla.DataLayer.Collection.validate("not_a_list", :list, element_type: :text)
{:error, "Expected a list, got: "not_a_list""}