Current section
Files
Jump to
Current section
Files
lib/aerospike/op/map.ex
defmodule Aerospike.Op.Map do
@moduledoc """
Map CDT operations for `Aerospike.operate/4`.
These builders create server-side map operations. Pass `ctx:` for nested CDT
paths and `return_type:` for selector operations that can return keys,
values, key/value pairs, counts, ranks, indexes, or existence flags.
"""
alias Aerospike.PolicyInteger
alias Aerospike.Protocol.CDT
@typedoc """
Opaque map 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 """
Map order attribute.
"""
@type order ::
:unordered
| :key_ordered
| :key_value_ordered
| raw_integer()
@typedoc """
Map write policy flag or flags.
"""
@type write_flag :: :default | :create_only | :update_only | :no_fail | :partial
@type write_flags :: write_flag() | [write_flag()] | raw_integer()
@typedoc """
Map selector return type.
"""
@type return_type ::
:none
| :index
| :reverse_index
| :rank
| :reverse_rank
| :count
| :key
| :value
| :key_value
| :exists
| :unordered_map
| :ordered_map
| :inverted
| [
:inverted
| :index
| :reverse_index
| :rank
| :reverse_rank
| :count
| :key
| :value
| :key_value
| :exists
| :unordered_map
| :ordered_map
]
| raw_integer()
@typedoc """
Map write policy accepted in `opts[:policy]`.
Prefer `:order` for the map order. `:attr` remains accepted for
compatibility. Omitted keys default to `0`.
"""
@type policy ::
%{
optional(:order) => order(),
optional(:attr) => order(),
optional(:flags) => write_flags()
}
| [{:order, order()} | {:attr, order()} | {:flags, write_flags()}]
@typedoc """
Common map operation options.
Supported keys:
* `:ctx` - nested CDT context path from `Aerospike.Ctx`.
* `:return_type` - selector return type from the `return_*` helpers.
* `:policy` - map write policy for put/increment/decrement operations.
* `:persist_index` - persist the index for top-level ordered maps.
"""
@type opts :: [
ctx: Aerospike.Ctx.t(),
return_type: return_type(),
policy: policy(),
persist_index: boolean()
]
@set_policy 64
@put 67
@put_items 68
@increment 73
@decrement 74
@clear 75
@remove_by_key 76
@remove_by_index 77
@remove_by_rank 79
@remove_by_key_list 81
@remove_by_value 82
@remove_by_value_list 83
@remove_by_key_range 84
@remove_by_index_range 85
@remove_by_value_range 86
@remove_by_rank_range 87
@remove_by_key_rel_index_range 88
@remove_by_value_rel_rank_range 89
@size 96
@get_by_key 97
@get_by_index 98
@get_by_rank 100
@get_by_value 102
@get_by_key_range 103
@get_by_index_range 104
@get_by_value_range 105
@get_by_rank_range 106
@get_by_key_list 107
@get_by_value_list 108
@get_by_key_rel_index_range 109
@get_by_value_rel_rank_range 110
@inverted 0x10000
@doc "Create unordered maps by default."
@spec order_unordered() :: 0
def order_unordered, do: 0
@doc "Create maps ordered by key."
@spec order_key_ordered() :: 1
def order_key_ordered, do: 1
@doc "Create maps ordered by key and value."
@spec order_key_value_ordered() :: 3
def order_key_value_ordered, do: 3
@doc "Use default map write behavior."
@spec write_default() :: 0
def write_default, do: 0
@doc "Only create map items that do not already exist."
@spec write_create_only() :: 1
def write_create_only, do: 1
@doc "Only update map items that already exist."
@spec write_update_only() :: 2
def write_update_only, do: 2
@doc "Do not fail the command when a map item is rejected by write flags."
@spec write_no_fail() :: 4
def write_no_fail, do: 4
@doc "Commit valid map 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 map 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 keys."
@spec return_key() :: 6
def return_key, do: 6
@doc "Return selected values."
@spec return_value() :: 7
def return_value, do: 7
@doc "Return selected key/value pairs."
@spec return_key_value() :: 8
def return_key_value, do: 8
@doc "Return whether matching entries exist."
@spec return_exists() :: 13
def return_exists, do: 13
@doc "Return selected entries as an unordered map."
@spec return_unordered_map() :: 16
def return_unordered_map, do: 16
@doc "Return selected entries as an ordered map."
@spec return_ordered_map() :: 17
def return_ordered_map, do: 17
@doc "Invert the selector so it applies outside the matched range."
@spec return_inverted() :: 0x10000
def return_inverted, do: @inverted
@doc """
Creates a map at the selected context level.
When `ctx:` is omitted, this sets the top-level bin map order. Nested map
creation ignores `persist_index:` because server indexes are top-level only.
"""
@spec create(String.t(), order(), opts()) :: t()
def create(bin_name, order, opts \\ [])
when is_binary(bin_name) do
normalized_order = PolicyInteger.map_order(order)
case ctx(opts) do
steps when is_list(steps) and steps != [] ->
CDT.map_create_op(
bin_name,
PolicyInteger.map_create_flag(order),
[@set_policy, normalized_order],
steps
)
_ ->
set_policy(bin_name, normalized_order, opts)
end
end
@doc """
Sets the map order attributes.
"""
@spec set_policy(String.t(), order(), opts()) :: t()
def set_policy(bin_name, attributes, opts \\ [])
when is_binary(bin_name) do
steps = ctx(opts)
attributes = attributes |> order_attr(opts) |> policy_attr(steps)
CDT.map_modify_op(bin_name, @set_policy, [attributes], steps)
end
@doc """
Writes one key/value pair and returns the map size.
Pass `policy: [order: order, flags: flags]` to include map order attributes
and write flags in the operation payload.
"""
@spec put(String.t(), term(), term(), opts()) :: t()
def put(bin_name, map_key, value, opts \\ []) when is_binary(bin_name) do
%{attr: attr, flags: flags} = map_policy(opts)
CDT.map_modify_op(bin_name, @put, [map_key, value, attr | write_flags(flags)], ctx(opts))
end
@doc """
Writes multiple key/value pairs and returns the map size.
Pass `policy: [order: order, flags: flags]` to include map order attributes
and write flags in the operation payload.
"""
@spec put_items(String.t(), map(), opts()) :: t()
def put_items(bin_name, values, opts \\ []) when is_binary(bin_name) and is_map(values) do
%{attr: attr, flags: flags} = map_policy(opts)
CDT.map_modify_op(bin_name, @put_items, [values, attr | write_flags(flags)], ctx(opts))
end
@doc """
Increments the numeric value at `map_key` and returns the final value.
"""
@spec increment(String.t(), term(), term(), opts()) :: t()
def increment(bin_name, map_key, delta, opts \\ [])
when is_binary(bin_name) do
%{attr: attr} = map_policy(opts)
CDT.map_modify_op(bin_name, @increment, [map_key, delta, attr], ctx(opts))
end
@doc """
Decrements the numeric value at `map_key` and returns the final value.
"""
@spec decrement(String.t(), term(), term(), opts()) :: t()
def decrement(bin_name, map_key, delta, opts \\ [])
when is_binary(bin_name) do
%{attr: attr} = map_policy(opts)
CDT.map_modify_op(bin_name, @decrement, [map_key, delta, attr], ctx(opts))
end
@doc """
Removes all entries from the map.
"""
@spec clear(String.t(), opts()) :: t()
def clear(bin_name, opts \\ []) when is_binary(bin_name) do
CDT.map_modify_op(bin_name, @clear, [], ctx(opts))
end
@doc """
Removes the entry for `map_key`, returning data selected by `return_type:`.
"""
@spec remove_by_key(String.t(), term(), opts()) :: t()
def remove_by_key(bin_name, map_key, opts \\ []) when is_binary(bin_name) do
CDT.map_modify_op(bin_name, @remove_by_key, [key_rt(opts), map_key], ctx(opts))
end
@doc """
Removes entries matching any key in `keys`, returning selected data.
"""
@spec remove_by_key_list(String.t(), list(), opts()) :: t()
def remove_by_key_list(bin_name, keys, opts \\ []) when is_binary(bin_name) and is_list(keys) do
CDT.map_modify_op(bin_name, @remove_by_key_list, [key_rt(opts), keys], ctx(opts))
end
@doc """
Removes entries with keys in `[begin_key, end_key)`, returning selected data.
Pass `nil` for an open range boundary.
"""
@spec remove_by_key_range(String.t(), term(), term(), opts()) :: t()
def remove_by_key_range(bin_name, begin_key, end_key, opts \\ []) when is_binary(bin_name) do
CDT.map_modify_op(
bin_name,
@remove_by_key_range,
[key_rt(opts), begin_key, end_key],
ctx(opts)
)
end
@doc """
Removes entries nearest to `map_key` and greater by relative `index`.
"""
@spec remove_by_key_rel_index_range(String.t(), term(), integer(), opts()) :: t()
def remove_by_key_rel_index_range(bin_name, map_key, index, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.map_modify_op(
bin_name,
@remove_by_key_rel_index_range,
[key_rt(opts), map_key, index],
ctx(opts)
)
end
@doc """
Removes `count` entries nearest to `map_key` and greater by relative `index`.
"""
@spec remove_by_key_rel_index_range_count(String.t(), term(), integer(), integer(), opts()) ::
t()
def remove_by_key_rel_index_range_count(bin_name, map_key, index, count, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_integer(count) do
CDT.map_modify_op(
bin_name,
@remove_by_key_rel_index_range,
[key_rt(opts), map_key, index, count],
ctx(opts)
)
end
@doc """
Removes entries 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.map_modify_op(bin_name, @remove_by_value, [value_rt(opts), value], ctx(opts))
end
@doc """
Removes entries matching any value 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.map_modify_op(bin_name, @remove_by_value_list, [value_rt(opts), values], ctx(opts))
end
@doc """
Removes entries with 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.map_modify_op(
bin_name,
@remove_by_value_range,
[value_rt(opts), begin_value, end_value],
ctx(opts)
)
end
@doc """
Removes entries 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.map_modify_op(
bin_name,
@remove_by_value_rel_rank_range,
[value_rt(opts), value, rank],
ctx(opts)
)
end
@doc """
Removes `count` entries 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.map_modify_op(
bin_name,
@remove_by_value_rel_rank_range,
[value_rt(opts), value, rank, count],
ctx(opts)
)
end
@doc """
Removes the entry 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.map_modify_op(bin_name, @remove_by_index, [key_rt(opts), index], ctx(opts))
end
@doc """
Removes entries 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.map_modify_op(bin_name, @remove_by_index_range, [key_rt(opts), index], ctx(opts))
end
@doc """
Removes `count` entries 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.map_modify_op(bin_name, @remove_by_index_range, [key_rt(opts), index, count], ctx(opts))
end
@doc """
Removes the entry 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.map_modify_op(bin_name, @remove_by_rank, [value_rt(opts), rank], ctx(opts))
end
@doc """
Removes entries 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.map_modify_op(bin_name, @remove_by_rank_range, [value_rt(opts), rank], ctx(opts))
end
@doc """
Removes `count` entries 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.map_modify_op(bin_name, @remove_by_rank_range, [value_rt(opts), rank, count], ctx(opts))
end
@doc """
Returns the number of entries in the map.
"""
@spec size(String.t(), opts()) :: t()
def size(bin_name, opts \\ []) when is_binary(bin_name) do
CDT.map_read_op(bin_name, @size, [], ctx(opts))
end
@doc """
Returns the entry for `map_key`, selected by `return_type:`.
"""
@spec get_by_key(String.t(), term(), opts()) :: t()
def get_by_key(bin_name, map_key, opts \\ []) when is_binary(bin_name) do
CDT.map_read_op(bin_name, @get_by_key, [value_rt(opts), map_key], ctx(opts))
end
@doc """
Returns entries matching any key in `keys`, selected by `return_type:`.
"""
@spec get_by_key_list(String.t(), list(), opts()) :: t()
def get_by_key_list(bin_name, keys, opts \\ []) when is_binary(bin_name) and is_list(keys) do
CDT.map_read_op(bin_name, @get_by_key_list, [key_value_rt(opts), keys], ctx(opts))
end
@doc """
Returns entries with keys in `[begin_key, end_key)`, selected by `return_type:`.
Pass `nil` for an open range boundary.
"""
@spec get_by_key_range(String.t(), term(), term(), opts()) :: t()
def get_by_key_range(bin_name, begin_key, end_key, opts \\ []) when is_binary(bin_name) do
CDT.map_read_op(
bin_name,
@get_by_key_range,
[key_value_rt(opts), begin_key, end_key],
ctx(opts)
)
end
@doc """
Returns entries nearest to `map_key` and greater by relative `index`.
"""
@spec get_by_key_rel_index_range(String.t(), term(), integer(), opts()) :: t()
def get_by_key_rel_index_range(bin_name, map_key, index, opts \\ [])
when is_binary(bin_name) and is_integer(index) do
CDT.map_read_op(
bin_name,
@get_by_key_rel_index_range,
[key_value_rt(opts), map_key, index],
ctx(opts)
)
end
@doc """
Returns `count` entries nearest to `map_key` and greater by relative `index`.
"""
@spec get_by_key_rel_index_range_count(String.t(), term(), integer(), integer(), opts()) ::
t()
def get_by_key_rel_index_range_count(bin_name, map_key, index, count, opts \\ [])
when is_binary(bin_name) and is_integer(index) and is_integer(count) do
CDT.map_read_op(
bin_name,
@get_by_key_rel_index_range,
[key_value_rt(opts), map_key, index, count],
ctx(opts)
)
end
@doc """
Returns entries 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.map_read_op(bin_name, @get_by_value, [key_value_rt(opts), value], ctx(opts))
end
@doc """
Returns entries matching any value 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.map_read_op(bin_name, @get_by_value_list, [key_value_rt(opts), values], ctx(opts))
end
@doc """
Returns entries with 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.map_read_op(
bin_name,
@get_by_value_range,
[key_value_rt(opts), begin_value, end_value],
ctx(opts)
)
end
@doc """
Returns entries 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.map_read_op(
bin_name,
@get_by_value_rel_rank_range,
[key_value_rt(opts), value, rank],
ctx(opts)
)
end
@doc """
Returns `count` entries 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.map_read_op(
bin_name,
@get_by_value_rel_rank_range,
[key_value_rt(opts), value, rank, count],
ctx(opts)
)
end
@doc """
Returns the entry 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.map_read_op(bin_name, @get_by_index, [key_value_rt(opts), index], ctx(opts))
end
@doc """
Returns entries 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.map_read_op(bin_name, @get_by_index_range, [key_value_rt(opts), index], ctx(opts))
end
@doc """
Returns `count` entries 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.map_read_op(bin_name, @get_by_index_range, [key_value_rt(opts), index, count], ctx(opts))
end
@doc """
Returns the entry 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.map_read_op(bin_name, @get_by_rank, [key_value_rt(opts), rank], ctx(opts))
end
@doc """
Returns entries 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.map_read_op(bin_name, @get_by_rank_range, [key_value_rt(opts), rank], ctx(opts))
end
@doc """
Returns `count` entries 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.map_read_op(bin_name, @get_by_rank_range, [key_value_rt(opts), rank, count], ctx(opts))
end
defp ctx(opts), do: Keyword.get(opts, :ctx)
defp key_rt(opts),
do: opts |> Keyword.get(:return_type, :key) |> PolicyInteger.map_return_type()
defp key_value_rt(opts),
do: opts |> Keyword.get(:return_type, :key_value) |> PolicyInteger.map_return_type()
defp value_rt(opts),
do: opts |> Keyword.get(:return_type, :value) |> PolicyInteger.map_return_type()
defp order_attr(order, opts) do
PolicyInteger.map_order_attr(order, Keyword.get(opts, :persist_index, false))
end
defp policy_attr(attributes, steps) when is_list(steps) and steps != [] do
PolicyInteger.strip_persist_index(attributes)
end
defp policy_attr(attributes, _steps), do: attributes
defp map_policy(opts), do: opts |> Keyword.get(:policy) |> PolicyInteger.map_policy()
defp write_flags(0), do: []
defp write_flags(flags), do: [flags]
end