# `PropertyTable`
[🔗](https://github.com/nerves-project/property_table/blob/v0.3.2/lib/property_table.ex#L7)

In-memory key-value store with subscriptions

PropertyTable makes it easy to set up a key-value store where users can subscribe to changes based on patterns. PropertyTable refers to keys as
properties. Properties have values and are timestamped as to when they
received that value. Subscriptions make this library feel similar to Publish-Subscribe. Events, though, are only for changes to properties.

PropertyTable is useful when you want to expose a decent amount of state and
let consumers pick and choose what parts interest them.

PropertyTable consumers express their interest in properties using "patterns". A pattern could be as simple as the property of interest or it could contain
wildcards. This allows one to create hierarchical key-value stores, map-based
stores, or just simple key-value stores with notifications.

PropertyTable is optionally persistent to disk. Keys and values are backed by ETS.

# `options`

```elixir
@type options() :: [
  name: table_id(),
  properties: [property_value()],
  tuple_events: boolean(),
  matcher: module(),
  persist_data_path: String.t(),
  persist_interval: pos_integer(),
  persist_max_snapshots: pos_integer(),
  persist_compression: 0..9
]
```

PropertyTable configuration options

See `start_link/1` for usage.

# `pattern`

```elixir
@type pattern() :: any()
```

A match pattern

Just like properties, these can be anything but they have to be compatible
with the `PropertyTable.Matcher` implementation.

The default is that patterns are string lists with the addition of wildcards
like `:_`.

# `property`

```elixir
@type property() :: any()
```

A property

Properties can be anything, but in order to be useful, they need to be
compatible with the `PropertyTable.Matcher` implementation.

In is common for this to be a string list (`[String.t()]`) since the default
`PropertyTable.Matcher` works with those.

# `property_value`

```elixir
@type property_value() :: {property(), value()}
```

A property/value tuple

# `table_id`

```elixir
@type table_id() :: atom()
```

A table_id identifies a group of properties

# `value`

```elixir
@type value() :: any()
```

A properties value

These can be whatever makes sense to the PropertyTable user. The only
constraint is that if you're using PropertyTable's persistence feature, it
needs to be possible to save and restore them. This means that pids and
references, for example, can't be used.

# `child_spec`

```elixir
@spec child_spec(options()) :: Supervisor.child_spec()
```

Returns a specification to start a property_table under a supervisor.
See `Supervisor`.

# `delete`

```elixir
@spec delete(table_id(), property()) :: :ok
```

Delete the specified property

# `delete_matches`

```elixir
@spec delete_matches(table_id(), pattern()) :: :ok
```

Delete all properties that match a pattern

# `fetch_with_timestamp`

```elixir
@spec fetch_with_timestamp(table_id(), property()) ::
  {:ok, value(), integer()} | :error
```

Fetch a property with the time that it was set

Timestamps come from `System.monotonic_time()`. Use
`System.convert_time_unit/3` to convert from native time units.

# `flush_to_disk`

```elixir
@spec flush_to_disk(table_id()) :: :ok | {:error, Exception.t()}
```

Write any changes to disk

If persistence is enabled for this property table, save the current state to
disk immediately. The table is already written every `:persist_interval`, but
this is avoid waiting after important changes.

# `flush_to_disk!`

```elixir
@spec flush_to_disk!(table_id()) :: :ok
```

Same as `flush_to_disk/1` but raises an exception on error

# `get`

```elixir
@spec get(table_id(), property(), value()) :: value()
```

Get the current value of a property

# `get_all`

```elixir
@spec get_all(table_id()) :: [{property(), value()}]
```

Get all properties

This function might return a really long list so it's mainly intended for
debug or convenience when you know that the table only contains a few
properties.

# `get_all_with_timestamps`

```elixir
@spec get_all_with_timestamps(table_id()) :: [{property(), value(), integer()}]
```

Get all properties with timestamps

This function is similar to `get_all/1` but also returns the monotonic
time that the property was set. Use `System.convert_time_unit/3` to convert
from native time units.

# `get_snapshots`

```elixir
@spec get_snapshots(table_id()) :: [{String.t(), String.t()}]
```

Return available snapshot IDs

This scans the `snapshots` directory and returns a list of tuples containing
snapshot IDs and their full name.

# `match`

```elixir
@spec match(table_id(), pattern()) :: [{property(), value()}]
```

Get a list of all properties matching the specified property pattern

# `put`

```elixir
@spec put(table_id(), property(), value()) :: :ok
```

Update a property and notify listeners

# `put_many`

```elixir
@spec put_many(table_id(), [{property(), value()}]) :: :ok
```

Update many properties

This is similar to calling `put/3` several times in a row, but atomically. It is
also slightly more efficient when updating more than one property.

# `restore_snapshot`

```elixir
@spec restore_snapshot(table_id(), String.t()) :: :ok | {:error, Exception.t()}
```

Restart a previously saved snapshot

If persistence is enabled for this property table, restore the current state
of the PropertyTable to that of a past named snapshot

# `snapshot`

```elixir
@spec snapshot(table_id()) :: {:ok, String.t()} | {:error, Exception.t()}
```

Take a snapshot of the property table

If persistence is enabled for this property table, save the current state
and copy a snapshot of it into the `/snapshots` sub-directory of the set
data directory.

This returns an ID for the snapshot that can be passed `restore_snapshot/2`.

# `snapshot!`

```elixir
@spec snapshot!(table_id()) :: {:ok, String.t()}
```

Same as `snapshot/1` but raises an exception on error

# `start_link`

```elixir
@spec start_link(options()) :: Supervisor.on_start()
```

Start a PropertyTable's supervision tree

To create a PropertyTable for your application or library, add the following
`child_spec` to one of your supervision trees:

```elixir
{PropertyTable, name: MyTableName}
```

The `:name` option is required. All calls to `PropertyTable` will need to
know it and the process will be registered under than name so be sure it's
unique.

Options for properties and events:

* `:properties` - a list of `{property, value}` tuples to initially populate
  the `PropertyTable`
* `:matcher` - set the format for how properties and how they should be
  matched for triggering events. See `PropertyTable.Matcher`.
* `:tuple_events` - set to `true` for change events to be in the old tuple
  format. This is not recommended for new code and hopefully will be removed
  in the future. Prefer `:event_transformer`
* `:event_transformer` - set to a function that takes an `Event.t()` and returns
  the event that should be sent to subscribers.

Options for persisting properties:

* `:persist_data_path` - set to a directory where PropertyTable will
  persist the contents of the table to disk, snapshots will also be stored here.
* `:persist_interval` - if set PropertyTable will persist the contents of
  tables to disk in intervals of the provided value (in milliseconds) automatically.
* `:persist_max_snapshots` - Maximum number of manual snapshots to keep on disk before they
  are replaced - (oldest snapshots are replaced first.) Defaults to 25.
* `:persist_compression` - `0..9` range to compress the terms when written to disk, see `:erlang.term_to_binary/2`. Defaults to 6.

> #### Important {: .info}
>
> Setting `:persist_data_path` enables persistence. On initialization, if
> PropertyTable is able to load a snapshot, the data in the snapshot is used
> instead of the `:properties` option.

# `subscribe`

```elixir
@spec subscribe(table_id(), pattern()) :: :ok
```

Subscribe to receive property change events

Subscriptions may be for individual properties or contain wildcards as
allowed by the `PropertyTable.Matcher` that's in use. See
`PropertyTable.Matcher.StringPath` for the default.

> #### Important {: .warning}
>
> A common pattern is to subscribe to a property and then to get its initial
> value. The order matters. Subscription must be done first to prevent a race
> condition. For example, if you get a property's value and _then_ subscribe,
> it's possible for the value to change before the subscription takes effect.

# `unsubscribe`

```elixir
@spec unsubscribe(table_id(), pattern()) :: :ok
```

Stop subscribing to a property

---

*Consult [api-reference.md](api-reference.md) for complete listing*
