Packages
electric_client
0.1.0-dev-2
0.10.3
0.10.2
0.10.1
0.10.1-beta-1
0.10.0
0.9.5-beta-1
0.9.4
0.9.4-beta-1
0.9.3
0.9.2
0.9.1
0.9.0
0.8.3
0.8.3-beta-1
0.8.2
0.8.1
0.8.0
0.8.0-beta-1
0.7.3
0.7.2
0.7.1
0.7.0
0.6.5
0.6.5-beta-5
0.6.5-beta-4
0.6.5-beta-3
0.6.5-beta-2
0.6.5-beta-1
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.5.0-beta-1
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.3.0-beta.4
0.3.0-beta.3
0.3.0-beta.2
0.2.6-pre-1
retired
0.2.6-beta.1
0.2.6-beta.0
0.2.5
0.2.4
0.2.4-pre-8
0.2.4-pre-7
0.2.4-pre-6
0.2.4-pre-5
0.2.4-pre-4
0.2.4-pre-3
0.2.4-pre-2
0.2.4-pre-1
0.2.3
0.2.3-rc-1
0.2.2
0.2.2-rc-1
0.2.1
0.2.1-rc-3
0.2.1-rc-2
0.2.1-rc-1
0.2.0
0.1.2
0.1.1
0.1.0
0.1.0-dev-9
0.1.0-dev-8
0.1.0-dev-7
0.1.0-dev-6
0.1.0-dev-5
0.1.0-dev-4
0.1.0-dev-3
0.1.0-dev-2
0.1.0-dev-17
0.1.0-dev-16
0.1.0-dev-15
0.1.0-dev-14
0.1.0-dev-13
0.1.0-dev-12
0.1.0-dev-11
0.1.0-dev-10
0.1.0-dev
Elixir client for ElectricSQL
Current section
Files
Jump to
Current section
Files
lib/electric/client/offset.ex
defmodule Electric.Client.Offset do
@moduledoc """
Represents an offset in the synchronisation stream from Electric.
"""
import Kernel, except: [to_string: 1]
defstruct tx: 0, op: 0
@type int64 :: 0..0xFFFFFFFFFFFFFFFF
@type tx_offset :: int64() | -1
@type op_offset :: int64() | :infinity
@type t :: %__MODULE__{
tx: tx_offset(),
op: op_offset()
}
@doc """
Return an offset that is guaranteed to be before any real database
operations.
"""
@spec before_all() :: t()
def before_all(), do: %__MODULE__{tx: -1, op: 0}
@doc """
The first possible offset in the log.
"""
@spec first() :: t()
def first, do: %__MODULE__{tx: 0, op: 0}
@doc """
A guard to test if the given offset is the first possible (as returned by `first/0`).
"""
defguard is_first(offset)
when is_struct(offset, __MODULE__) and offset.tx == 0 and offset.op == 0
@doc """
Parse an offset value from an HTTP header into a `%#{__MODULE__}{}` struct.
Raises if the offset header value is invalid.
iex> from_string!("-1")
%#{__MODULE__}{tx: -1, op: 0}
iex> from_string!("1378734_3")
%#{__MODULE__}{tx: 1378734, op: 3}
iex> from_string!("not a real offset")
** (ArgumentError) has invalid format
"""
@spec from_string!(String.t()) :: t() | no_return()
def from_string!(str) when is_binary(str) do
case from_string(str) do
{:ok, offset} -> offset
{:error, reason} -> raise ArgumentError, message: reason
end
end
@doc """
Parse an offset value from an HTTP header into a `%#{__MODULE__}{}` struct.
iex> from_string("-1")
{:ok, %#{__MODULE__}{tx: -1, op: 0}}
iex> from_string("1378734_3")
{:ok, %#{__MODULE__}{tx: 1378734, op: 3}}
iex> from_string("not a real offset")
{:error, "has invalid format"}
"""
@spec from_string(String.t()) :: {:ok, t()} | {:error, String.t()}
def from_string(str) when is_binary(str) do
if str == "-1" do
{:ok, before_all()}
else
with [tx_offset_str, op_offset_str] <- :binary.split(str, "_"),
{tx_offset, ""} <- Integer.parse(tx_offset_str),
{op_offset, ""} <- Integer.parse(op_offset_str) do
{:ok, %__MODULE__{tx: tx_offset, op: op_offset}}
else
_ -> {:error, "has invalid format"}
end
end
end
@doc """
Create a new #{__MODULE__} struct from the given LSN and operation
offsets.
iex> new(2349, 3)
%#{__MODULE__}{tx: 2349, op: 3}
"""
@spec new(non_neg_integer(), non_neg_integer()) :: t()
def new(tx_offset, op_offset)
when is_integer(tx_offset) and tx_offset >= 0 and is_integer(op_offset) and op_offset >= 0 do
%__MODULE__{tx: tx_offset, op: op_offset}
end
@doc """
Output the an Offset as a string for use in query parameters.
iex> new(2349, 3) |> #{__MODULE__}.to_string()
"2349_3"
iex> before_all() |> #{__MODULE__}.to_string()
"-1"
"""
@spec to_string(t()) :: String.t()
def to_string(%__MODULE__{tx: -1}) do
"-1"
end
def to_string(%__MODULE__{tx: tx, op: op}) do
"#{Integer.to_string(tx)}_#{Integer.to_string(op)}"
end
@spec to_tuple(t()) :: {tx_offset(), op_offset()}
def to_tuple(%__MODULE__{tx: tx, op: op}), do: {tx, op}
defimpl String.Chars do
def to_string(offset) do
Electric.Client.Offset.to_string(offset)
end
end
end