Bandera.Store.Persistent.Ecto.Serializer (bandera v0.1.0)

Copy Markdown

Pure mapping between Bandera.Gates and SQL table rows.

A row is a plain map %{flag_name, gate_type, target, enabled}. Both percentage gate types collapse to gate_type: "percentage" (one percentage gate per flag), with the ratio and kind encoded in target ("time/<r>" / "actors/<r>"). The boolean gate's nil target is stored as the "_bandera_none" sentinel because SQL unique indexes treat NULL values as distinct.

Flag names read back from storage are converted to atoms with String.to_atom/1 (so that listing flags created in a previous VM session works). Feature-flag names must therefore be a bounded, developer-defined set — never untrusted user input.

Summary

Functions

Rebuilds a Bandera.Flag from the rows stored for it.

Encodes a gate target for the target column.

Maps a flag name and gate to the row map persisted by the Ecto adapter.

Types

row()

@type row() :: %{
  flag_name: String.t(),
  gate_type: String.t(),
  target: String.t(),
  enabled: boolean()
}

Functions

deserialize_flag(flag_name, rows)

@spec deserialize_flag(atom() | String.t(), [map()]) :: Bandera.Flag.t()

Rebuilds a Bandera.Flag from the rows stored for it.

Rows are sorted for a stable gate order; the flag name is converted to an atom, so it must be a bounded, developer-defined value — never untrusted input.

Examples

iex> rows = [%{gate_type: "boolean", target: "_bandera_none", enabled: true}]
iex> flag = Bandera.Store.Persistent.Ecto.Serializer.deserialize_flag(:my_flag, rows)
iex> flag.name
:my_flag
iex> flag.gates
[%Bandera.Gate{type: :boolean, for: nil, enabled: true}]

serialize_target(value)

@spec serialize_target(term()) :: String.t()

Encodes a gate target for the target column.

nil becomes the "_bandera_none" sentinel; binaries pass through; everything else is stringified.

Examples

iex> Bandera.Store.Persistent.Ecto.Serializer.serialize_target(nil)
"_bandera_none"

iex> Bandera.Store.Persistent.Ecto.Serializer.serialize_target("user-1")
"user-1"

iex> Bandera.Store.Persistent.Ecto.Serializer.serialize_target(0.5)
"0.5"

to_row(flag_name, gate)

@spec to_row(atom(), Bandera.Gate.t()) :: row()

Maps a flag name and gate to the row map persisted by the Ecto adapter.

Percentage gates collapse to gate_type: "percentage" with the kind and ratio encoded in target; a boolean gate's nil target becomes the "_bandera_none" sentinel (SQL unique indexes treat NULLs as distinct).

Examples

iex> row = Bandera.Store.Persistent.Ecto.Serializer.to_row(:my_flag, Bandera.Gate.new(:boolean, true))
iex> {row.flag_name, row.gate_type, row.target, row.enabled}
{"my_flag", "boolean", "_bandera_none", true}

iex> row = Bandera.Store.Persistent.Ecto.Serializer.to_row(:my_flag, Bandera.Gate.new(:actor, "u1", true))
iex> {row.gate_type, row.target}
{"actor", "u1"}