Packages

Aerospike driver for Elixir with an OTP-native cluster runtime

Current section

Files

Jump to
aerospike_driver lib aerospike query.ex
Raw

lib/aerospike/query.ex

defmodule Aerospike.Query do
@moduledoc """
Composable secondary-index query description (pure data, no I/O).
Queries require a namespace and set. Use `where/2` for the secondary-index predicate
and `filter/2` for additional expression filters (AND-ed at execution time).
Only one secondary-index filter is kept; `where/2` **replaces** any previous predicate.
"""
alias Aerospike.Exp
alias Aerospike.Filter
alias Aerospike.PartitionFilter
@enforce_keys [:namespace, :set]
defstruct [
:namespace,
:set,
:index_filter,
bin_names: [],
filters: [],
max_records: nil,
records_per_second: 0,
partition_filter: nil,
no_bins: false
]
@type t :: %__MODULE__{
namespace: String.t(),
set: String.t(),
index_filter: Filter.t() | nil,
bin_names: [String.t()],
filters: [Exp.t()],
max_records: pos_integer() | nil,
records_per_second: non_neg_integer(),
partition_filter: PartitionFilter.t() | nil,
no_bins: boolean()
}
@doc """
Starts a query for `namespace` and `set`. Both must be non-empty strings.
"""
@spec new(String.t(), String.t()) :: t()
def new(namespace, set) when is_binary(namespace) and is_binary(set) do
validate_namespace!(namespace)
if set == "" do
raise ArgumentError, "set must be a non-empty string for queries"
end
%__MODULE__{namespace: namespace, set: set}
end
@doc """
Sets the secondary-index predicate, replacing any previous `where/2` value.
"""
@spec where(t(), Filter.t()) :: t()
def where(%__MODULE__{} = query, %Filter{} = filter) do
%{query | index_filter: filter}
end
@doc """
Restricts returned bins to the given names (strings).
"""
@spec select(t(), [String.t()]) :: t()
def select(%__MODULE__{} = query, bin_names) when is_list(bin_names) do
validate_bin_names!(bin_names)
%{query | bin_names: bin_names}
end
@doc """
Appends a server-side expression filter (AND-ed with existing filters at execution).
"""
@spec filter(t(), Exp.t()) :: t()
def filter(%__MODULE__{} = query, %Exp{} = exp) do
%{query | filters: query.filters ++ [exp]}
end
@doc """
Sets the maximum number of records to return. Must be a positive integer.
"""
@spec max_records(t(), pos_integer()) :: t()
def max_records(%__MODULE__{} = query, n) when is_integer(n) and n > 0 do
%{query | max_records: n}
end
@doc """
Sets the server-side records-per-second throttle. Use `0` for no throttle.
"""
@spec records_per_second(t(), non_neg_integer()) :: t()
def records_per_second(%__MODULE__{} = query, n) when is_integer(n) and n >= 0 do
%{query | records_per_second: n}
end
@doc """
Attaches a partition filter for partial queries or resume.
"""
@spec partition_filter(t(), PartitionFilter.t()) :: t()
def partition_filter(%__MODULE__{} = query, %PartitionFilter{} = pf) do
%{query | partition_filter: pf}
end
@doc """
When `true`, the server omits bin payloads.
"""
@spec no_bins(t(), boolean()) :: t()
def no_bins(%__MODULE__{} = query, flag) when is_boolean(flag) do
%{query | no_bins: flag}
end
defp validate_namespace!(namespace) do
if namespace == "" do
raise ArgumentError, "namespace must be a non-empty string"
end
end
defp validate_bin_names!(bin_names) do
Enum.each(bin_names, fn name ->
unless is_binary(name) and name != "" do
raise ArgumentError, "bin names must be non-empty strings, got: #{inspect(name)}"
end
end)
end
end