Packages
FerricFlow durable workflows and queues with native-protocol storage, Raft durability, and Bitcask persistence.
Current section
Files
Jump to
Current section
Files
lib/ferricstore/commands/strings/range.ex
defmodule Ferricstore.Commands.Strings.Range do
@moduledoc false
alias Ferricstore.Commands.Strings.Compound
alias Ferricstore.Store.{Ops, ReadResult}
def getrange_parsed(key, start_idx, end_idx, store) do
with :ok <- Compound.ensure_string_key(key, store) do
do_getrange_parsed(key, start_idx, end_idx, store)
end
end
defp do_getrange_parsed(key, start_idx, end_idx, store) do
case metadata_value_size(store, key) do
{:error, {:storage_read_failed, _reason}} = failure ->
ReadResult.command_error(failure)
size when is_integer(size) ->
if getrange_empty_for_size?(size, start_idx, end_idx) do
empty_range_result(key, store)
else
read_getrange_value(key, start_idx, end_idx, store)
end
_unknown_or_missing ->
read_getrange_value(key, start_idx, end_idx, store)
end
end
defp metadata_value_size(%FerricStore.Instance{} = store, key), do: Ops.value_size(store, key)
defp metadata_value_size(%Ferricstore.Store.LocalTxStore{} = store, key),
do: Ops.value_size(store, key)
defp metadata_value_size(%{value_size: value_size}, key) when is_function(value_size, 1),
do: value_size.(key)
defp metadata_value_size(_store, _key), do: :unknown
defp read_getrange_value(key, start_idx, end_idx, store) do
case Ops.getrange(store, key, start_idx, end_idx) do
{:error, {:storage_read_failed, _reason}} = failure ->
ReadResult.command_error(failure)
nil ->
empty_range_result(key, store)
value ->
value
end
end
defp getrange_empty_for_size?(size, start_idx, end_idx) do
start_norm = if start_idx < 0, do: max(size + start_idx, 0), else: start_idx
end_norm = if end_idx < 0, do: size + end_idx, else: end_idx
start_clamped = min(start_norm, size)
end_clamped = min(end_norm, size - 1)
start_clamped > end_clamped
end
defp empty_range_result(key, store) do
case Compound.data_structure_status(key, store) do
:compound -> {:error, "WRONGTYPE Operation against a key holding the wrong kind of value"}
:plain -> ""
{:error, {:storage_read_failed, _reason}} = failure -> ReadResult.command_error(failure)
end
end
end