Packages
ferricstore
0.10.3
0.11.14
0.11.12
0.11.11
0.11.10
0.11.9
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.0
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.2.0
0.1.0
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