Current section
Files
Jump to
Current section
Files
lib/aerospike/op/list.ex
defmodule Aerospike.Op.List do
@moduledoc """
List CDT operations for `Aerospike.operate/4`.
These builders create server-side list operations. Pass `ctx:` for nested CDT
paths and `return_type:` for selector operations that can return indexes,
ranks, counts, values, or existence flags.
"""
alias Aerospike.PolicyInteger
alias Aerospike.Protocol.CDT
@typedoc """
Opaque list CDT operation for `Aerospike.operate/4`.
"""
@opaque t :: Aerospike.Op.t()
@typedoc """
Raw compatibility value for server integer policy constants.
"""
@type raw_integer :: non_neg_integer() | {:raw, non_neg_integer()}
@typedoc """
List order attribute.
"""
@type order :: :unordered | :ordered | raw_integer()
@typedoc """
List write policy flag or flags.
"""
@type write_flag :: :default | :add_unique | :insert_bounded | :no_fail | :partial
@type write_flags :: write_flag() | [write_flag()] | raw_integer()
@typedoc """
List selector return type.
"""
@type return_type ::
:none
| :index
| :reverse_index
| :rank
| :reverse_rank
| :count
| :value
| :exists
| :inverted
| [
:inverted
| :index
| :reverse_index
| :rank
| :reverse_rank
| :count
| :value
| :exists
]
| raw_integer()
@typedoc """
List sort flag or flags.
"""
@type sort_flags ::
:default
| :descending
| :drop_duplicates
| [:descending | :drop_duplicates]
| raw_integer()
@typedoc """
List write policy accepted in `opts[:policy]`.
Append, insert, and set operations expect both `:order` and `:flags`;
increment only reads `:flags`.
"""
@type policy ::
%{optional(:order) => order(), optional(:flags) => write_flags()}
| [{:order, order()} | {:flags, write_flags()}]
@typedoc """
Common list operation options.
Supported keys:
* `:ctx` - nested CDT context path from `Aerospike.Ctx`.
* `:return_type` - selector return type such as `:value`, `:count`, or
`[:value, :inverted]`.
* `:policy` - list write policy map for write operations that document it.
* `:persist_index` - persist the index for top-level ordered lists.
* `:pad` - allow nested list creation past the current boundary.
"""
@type opts :: [
ctx: Aerospike.Ctx.t(),
return_type: return_type(),
policy: policy(),
persist_index: boolean(),
pad: boolean()
]
@set_type 0
@append 1
@append_items 2
@insert 3
@insert_items 4
@pop 5
@pop_range 6
@remove 7
@remove_range 8
@set 9
@trim 10
@clear 11
@increment 12
@sort 13
@size 16
@get 17
@get_range 18
@get_by_index 19
@get_by_rank 21
@get_by_value 22
@get_by_value_list 23
@get_by_index_range 24
@get_by_value_interval 25
@get_by_rank_range 26
@get_by_value_rel_rank_range 27
@remove_by_index 32
@remove_by_rank 34
@remove_by_value 35
@remove_by_value_list 36
@remove_by_index_range 37
@remove_by_value_interval 38
@remove_by_rank_range 39
@remove_by_value_rel_rank_range 40
@inverted 0x10000
@doc "Create unordered lists by default."
@spec order_unordered() :: 0
def order_unordered, do: 0
@doc "Create ordered lists."
@spec order_ordered() :: 1
def order_ordered, do: 1
@doc "Use default list write behavior."
@spec write_default() :: 0
def write_default, do: 0
@doc "Only add unique list values."
@spec write_add_unique() :: 1
def write_add_unique, do: 1
@doc "Require list insert indexes to be inside list boundaries."
@spec write_insert_bounded() :: 2
def write_insert_bounded, do: 2
@doc "Do not fail the command when a list item is rejected by write flags."
@spec write_no_fail() :: 4
def write_no_fail, do: 4
@doc "Commit valid list items even when another item is rejected by write flags."
@spec write_partial() :: 8
def write_partial, do: 8
@doc "Return no result for a selector operation."
@spec return_none() :: 0
def return_none, do: 0
@doc "Return selected item indexes."
@spec return_index() :: 1
def return_index, do: 1
@doc "Return selected reverse indexes, counted from the list end."
@spec return_reverse_index() :: 2
def return_reverse_index, do: 2
@doc "Return selected value ranks."
@spec return_rank() :: 3
def return_rank, do: 3
@doc "Return selected reverse ranks, counted from the highest value."
@spec return_reverse_rank() :: 4
def return_reverse_rank, do: 4
@doc "Return the selected item count."
@spec return_count() :: 5
def return_count, do: 5
@doc "Return selected value or values."
@spec return_value() :: 7
def return_value, do: 7
@doc "Return whether matching items exist."
@spec return_exists() :: 13
def return_exists, do: 13
@doc "Invert the selector so it applies outside the matched range."
@spec return_inverted() :: 0x10000
def return_inverted, do: @inverted
@doc """
Sets the list order and write flags for a list bin.
"""
@spec set_type(String.t(), order(), write_flags(), opts()) :: t()
def set_type(bin_name, order, flags, opts \\ []) when is_binary(bin_name) do
CDT.list_modify_op(
bin_name,
@set_type,
[PolicyInteger.list_order(order), PolicyInteger.list_write_flags(flags)],
ctx(opts)
)
end
@doc """
Creates a list at the selected context level.
When `ctx:` is omitted, this sets the top-level bin list order. For nested
lists, pass `pad: true` to allow create indexes beyond the current boundary.
"""
@spec create(String.t(), order(), opts()) :: t()
def create(bin_name, order, opts \\ []) when is_binary(bin_name) do
normalized_order = PolicyInteger.list_order(order)
case ctx(opts) do
steps when is_list(steps) and steps != [] ->
CDT.list_create_op(
bin_name,
PolicyInteger.list_create_flag(order, Keyword.get(opts, :pad, false)),
[
@set_type,
normalized_order
],
steps
)
_ ->
set_order(bin_name, normalized_order, opts)
end
end
@doc """
Sets the list order.
Pass `persist_index: true` to persist an index for a top-level ordered list.
"""
@spec set_order(String.t(), order(), opts()) :: t()
def set_order(bin_name, order, opts \\ []) when is_binary(bin_name) do
CDT.list_modify_op(bin_name, @set_type, [order_attr(order, opts)], ctx(opts))
end
@doc """
Appends a value to a list bin.
Pass `policy: [order: order, flags: flags]` to include list order and write
flags in the operation payload.
"""
@spec append(String.t(), term(), opts()) :: t()
def append(bin_name, value, opts \\ []) when is_binary(bin_name) do
CDT.list_modify_op(bin_name, @append, [value | list_policy(opts)], ctx(opts))
end
@doc """
Appends multiple values to a list bin.
Pass `policy: [order: order, flags: flags]` to include list order and write
flags in the operation payload.
"""
@spec append_items(String.t(), list(), opts()) :: t()
def append_items(bin_name, values, opts \\ []) when is_binary(bin_name) and is_list(values) do
CDT.list_modify_op(bin_name, @append_items, [values | list_policy(opts)], ctx(opts))
end
@doc """
Inserts a value at `index`.
"""
@spec insert(String.t(), integer(), term(), opts()) :: t()
def insert(bin_name, index, value, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @insert, [index, value | list_policy(opts)], ctx(opts))
end
@doc """
Inserts multiple values at `index`.
"""
@spec insert_items(String.t(), integer(), list(), opts()) :: t()
def insert_items(bin_name, index, values, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_list(values) do
CDT.list_modify_op(bin_name, @insert_items, [index, values | list_policy(opts)], ctx(opts))
end
@doc """
Removes and returns the value at `index`.
"""
@spec pop(String.t(), integer(), opts()) :: t()
def pop(bin_name, index, opts \\ []) when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @pop, [index], ctx(opts))
end
@doc """
Removes and returns `count` values starting at `index`.
"""
@spec pop_range(String.t(), integer(), integer(), opts()) :: t()
def pop_range(bin_name, index, count, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_integer(count) do
CDT.list_modify_op(bin_name, @pop_range, [index, count], ctx(opts))
end
@doc """
Removes and returns values from `index` through the end of the list.
"""
@spec pop_range_from(String.t(), integer(), opts()) :: t()
def pop_range_from(bin_name, index, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @pop_range, [index], ctx(opts))
end
@doc """
Removes the value at `index` and returns the removed count.
"""
@spec remove(String.t(), integer(), opts()) :: t()
def remove(bin_name, index, opts \\ []) when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @remove, [index], ctx(opts))
end
@doc """
Removes `count` values starting at `index` and returns the removed count.
"""
@spec remove_range(String.t(), integer(), integer(), opts()) :: t()
def remove_range(bin_name, index, count, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_integer(count) do
CDT.list_modify_op(bin_name, @remove_range, [index, count], ctx(opts))
end
@doc """
Removes values from `index` through the end and returns the removed count.
"""
@spec remove_range_from(String.t(), integer(), opts()) :: t()
def remove_range_from(bin_name, index, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @remove_range, [index], ctx(opts))
end
@doc """
Sets the value at `index`.
Pass `policy: [order: order, flags: flags]` to include list order and write
flags in the operation payload.
"""
@spec set(String.t(), integer(), term(), opts()) :: t()
def set(bin_name, index, value, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @set, [index, value | list_policy(opts)], ctx(opts))
end
@doc """
Keeps `count` values starting at `index` and removes all others.
"""
@spec trim(String.t(), integer(), integer(), opts()) :: t()
def trim(bin_name, index, count, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_integer(count) do
CDT.list_modify_op(bin_name, @trim, [index, count], ctx(opts))
end
@doc """
Removes all values from the list.
"""
@spec clear(String.t(), opts()) :: t()
def clear(bin_name, opts \\ []) when is_binary(bin_name) do
CDT.list_modify_op(bin_name, @clear, [], ctx(opts))
end
@doc """
Increments the numeric value at `index`.
Pass `policy: %{flags: flags}` to include write flags in the operation
payload.
"""
@spec increment(String.t(), integer(), term(), opts()) :: t()
def increment(bin_name, index, value, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @increment, [index, value | increment_policy(opts)], ctx(opts))
end
@doc """
Sorts the list with `sort_flags`.
"""
@spec sort(String.t(), sort_flags() | opts(), opts()) :: t()
def sort(bin_name, sort_flags_or_opts \\ :default, opts \\ []) when is_binary(bin_name) do
{sort_flags, opts} = sort_args(sort_flags_or_opts, opts)
CDT.list_modify_op(bin_name, @sort, [PolicyInteger.list_sort_flags(sort_flags)], ctx(opts))
end
@doc """
Returns the number of values in the list.
"""
@spec size(String.t(), opts()) :: t()
def size(bin_name, opts \\ []) when is_binary(bin_name) do
CDT.list_read_op(bin_name, @size, [], ctx(opts))
end
@doc """
Returns the value at `index`.
"""
@spec get(String.t(), integer(), opts()) :: t()
def get(bin_name, index, opts \\ []) when is_binary(bin_name) and is_integer(index) do
CDT.list_read_op(bin_name, @get, [index], ctx(opts))
end
@doc """
Returns `count` values starting at `index`.
"""
@spec get_range(String.t(), integer(), integer(), opts()) :: t()
def get_range(bin_name, index, count, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_integer(count) do
CDT.list_read_op(bin_name, @get_range, [index, count], ctx(opts))
end
@doc """
Returns values from `index` through the end of the list.
"""
@spec get_range_from(String.t(), integer(), opts()) :: t()
def get_range_from(bin_name, index, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_read_op(bin_name, @get_range, [index], ctx(opts))
end
@doc """
Removes the value at `index`, returning data selected by `return_type:`.
"""
@spec remove_by_index(String.t(), integer(), opts()) :: t()
def remove_by_index(bin_name, index, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @remove_by_index, [rt(opts), index], ctx(opts))
end
@doc """
Removes values from `index` through the end, returning selected data.
"""
@spec remove_by_index_range_from(String.t(), integer(), opts()) :: t()
def remove_by_index_range_from(bin_name, index, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_modify_op(bin_name, @remove_by_index_range, [rt(opts), index], ctx(opts))
end
@doc """
Removes `count` values from `index`, returning selected data.
"""
@spec remove_by_index_range(String.t(), integer(), integer(), opts()) :: t()
def remove_by_index_range(bin_name, index, count, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_integer(count) do
CDT.list_modify_op(bin_name, @remove_by_index_range, [rt(opts), index, count], ctx(opts))
end
@doc """
Removes the value at `rank`, returning data selected by `return_type:`.
"""
@spec remove_by_rank(String.t(), integer(), opts()) :: t()
def remove_by_rank(bin_name, rank, opts \\ []) when is_binary(bin_name) and is_integer(rank) do
CDT.list_modify_op(bin_name, @remove_by_rank, [rt(opts), rank], ctx(opts))
end
@doc """
Removes values from `rank` through the highest rank, returning selected data.
"""
@spec remove_by_rank_range_from(String.t(), integer(), opts()) :: t()
def remove_by_rank_range_from(bin_name, rank, opts \\ [])
when is_binary(bin_name) and is_integer(rank) do
CDT.list_modify_op(bin_name, @remove_by_rank_range, [rt(opts), rank], ctx(opts))
end
@doc """
Removes `count` values from `rank`, returning selected data.
"""
@spec remove_by_rank_range(String.t(), integer(), integer(), opts()) :: t()
def remove_by_rank_range(bin_name, rank, count, opts \\ [])
when is_binary(bin_name) and is_integer(rank) and is_integer(count) do
CDT.list_modify_op(bin_name, @remove_by_rank_range, [rt(opts), rank, count], ctx(opts))
end
@doc """
Removes values equal to `value`, returning data selected by `return_type:`.
"""
@spec remove_by_value(String.t(), term(), opts()) :: t()
def remove_by_value(bin_name, value, opts \\ []) when is_binary(bin_name) do
CDT.list_modify_op(bin_name, @remove_by_value, [rt(opts), value], ctx(opts))
end
@doc """
Removes values matching any entry in `values`, returning selected data.
"""
@spec remove_by_value_list(String.t(), list(), opts()) :: t()
def remove_by_value_list(bin_name, values, opts \\ [])
when is_binary(bin_name) and is_list(values) do
CDT.list_modify_op(bin_name, @remove_by_value_list, [rt(opts), values], ctx(opts))
end
@doc """
Removes values in `[begin_value, end_value)`, returning selected data.
Pass `nil` for an open range boundary.
"""
@spec remove_by_value_range(String.t(), term(), term(), opts()) :: t()
def remove_by_value_range(bin_name, begin_value, end_value, opts \\ [])
when is_binary(bin_name) do
CDT.list_modify_op(
bin_name,
@remove_by_value_interval,
[rt(opts), begin_value, end_value],
ctx(opts)
)
end
@doc """
Removes values nearest to `value` and greater by relative `rank`.
"""
@spec remove_by_value_rel_rank_range(String.t(), term(), integer(), opts()) :: t()
def remove_by_value_rel_rank_range(bin_name, value, rank, opts \\ [])
when is_binary(bin_name) and is_integer(rank) do
CDT.list_modify_op(
bin_name,
@remove_by_value_rel_rank_range,
[rt(opts), value, rank],
ctx(opts)
)
end
@doc """
Removes `count` values nearest to `value` and greater by relative `rank`.
"""
@spec remove_by_value_rel_rank_range_count(String.t(), term(), integer(), integer(), opts()) ::
t()
def remove_by_value_rel_rank_range_count(bin_name, value, rank, count, opts \\ [])
when is_binary(bin_name) and is_integer(rank) and is_integer(count) do
CDT.list_modify_op(
bin_name,
@remove_by_value_rel_rank_range,
[rt(opts), value, rank, count],
ctx(opts)
)
end
@doc """
Returns the value at `index`, selected by `return_type:`.
"""
@spec get_by_index(String.t(), integer(), opts()) :: t()
def get_by_index(bin_name, index, opts \\ []) when is_binary(bin_name) and is_integer(index) do
CDT.list_read_op(bin_name, @get_by_index, [rt(opts), index], ctx(opts))
end
@doc """
Returns values from `index` through the end, selected by `return_type:`.
"""
@spec get_by_index_range_from(String.t(), integer(), opts()) :: t()
def get_by_index_range_from(bin_name, index, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.list_read_op(bin_name, @get_by_index_range, [rt(opts), index], ctx(opts))
end
@doc """
Returns `count` values from `index`, selected by `return_type:`.
"""
@spec get_by_index_range(String.t(), integer(), integer(), opts()) :: t()
def get_by_index_range(bin_name, index, count, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_integer(count) do
CDT.list_read_op(bin_name, @get_by_index_range, [rt(opts), index, count], ctx(opts))
end
@doc """
Returns the value at `rank`, selected by `return_type:`.
"""
@spec get_by_rank(String.t(), integer(), opts()) :: t()
def get_by_rank(bin_name, rank, opts \\ []) when is_binary(bin_name) and is_integer(rank) do
CDT.list_read_op(bin_name, @get_by_rank, [rt(opts), rank], ctx(opts))
end
@doc """
Returns values from `rank` through the highest rank, selected by `return_type:`.
"""
@spec get_by_rank_range_from(String.t(), integer(), opts()) :: t()
def get_by_rank_range_from(bin_name, rank, opts \\ [])
when is_binary(bin_name) and is_integer(rank) do
CDT.list_read_op(bin_name, @get_by_rank_range, [rt(opts), rank], ctx(opts))
end
@doc """
Returns `count` values from `rank`, selected by `return_type:`.
"""
@spec get_by_rank_range(String.t(), integer(), integer(), opts()) :: t()
def get_by_rank_range(bin_name, rank, count, opts \\ [])
when is_binary(bin_name) and is_integer(rank) and is_integer(count) do
CDT.list_read_op(bin_name, @get_by_rank_range, [rt(opts), rank, count], ctx(opts))
end
@doc """
Returns values equal to `value`, selected by `return_type:`.
"""
@spec get_by_value(String.t(), term(), opts()) :: t()
def get_by_value(bin_name, value, opts \\ []) when is_binary(bin_name) do
CDT.list_read_op(bin_name, @get_by_value, [rt(opts), value], ctx(opts))
end
@doc """
Returns values matching any entry in `values`, selected by `return_type:`.
"""
@spec get_by_value_list(String.t(), list(), opts()) :: t()
def get_by_value_list(bin_name, values, opts \\ [])
when is_binary(bin_name) and is_list(values) do
CDT.list_read_op(bin_name, @get_by_value_list, [rt(opts), values], ctx(opts))
end
@doc """
Returns values in `[begin_value, end_value)`, selected by `return_type:`.
Pass `nil` for an open range boundary.
"""
@spec get_by_value_range(String.t(), term(), term(), opts()) :: t()
def get_by_value_range(bin_name, begin_value, end_value, opts \\ [])
when is_binary(bin_name) do
CDT.list_read_op(
bin_name,
@get_by_value_interval,
[rt(opts), begin_value, end_value],
ctx(opts)
)
end
@doc """
Returns values nearest to `value` and greater by relative `rank`.
"""
@spec get_by_value_rel_rank_range(String.t(), term(), integer(), opts()) :: t()
def get_by_value_rel_rank_range(bin_name, value, rank, opts \\ [])
when is_binary(bin_name) and is_integer(rank) do
CDT.list_read_op(
bin_name,
@get_by_value_rel_rank_range,
[rt(opts), value, rank],
ctx(opts)
)
end
@doc """
Returns `count` values nearest to `value` and greater by relative `rank`.
"""
@spec get_by_value_rel_rank_range_count(String.t(), term(), integer(), integer(), opts()) ::
t()
def get_by_value_rel_rank_range_count(bin_name, value, rank, count, opts \\ [])
when is_binary(bin_name) and is_integer(rank) and is_integer(count) do
CDT.list_read_op(
bin_name,
@get_by_value_rel_rank_range,
[rt(opts), value, rank, count],
ctx(opts)
)
end
defp ctx(opts), do: Keyword.get(opts, :ctx)
defp rt(opts),
do: opts |> Keyword.get(:return_type, return_value()) |> PolicyInteger.list_return_type()
defp order_attr(order, opts) do
PolicyInteger.list_order_attr(order, Keyword.get(opts, :persist_index, false))
end
defp list_policy(opts) do
case Keyword.get(opts, :policy) do
nil ->
[]
policy ->
%{order: order, flags: flags} = PolicyInteger.list_policy(policy)
[order, flags]
end
end
defp increment_policy(opts) do
case Keyword.get(opts, :policy) do
nil -> []
policy -> [PolicyInteger.list_policy(policy).flags]
end
end
defp sort_args(opts, []) when is_list(opts) do
case Keyword.keyword?(opts) do
true -> {Keyword.get(opts, :sort_flags, :default), opts}
false -> {opts, []}
end
end
defp sort_args(sort_flags, opts), do: {sort_flags, opts}
end