View Source Electric.Client (Electric Client v0.1.0-dev-9)
An Elixir client for the ElectricSQL synchronisation server.
Subscribing to a particular Shape produce a stream of update messages that will allow you to synchronise your local system to the state the Postgres database.
Quickstart
Start and connect the Electric Sync Service
Follow the quickstart guide to get Electric running and connected to a Postgres database.
Install the Electric Client and Receive sync events
Create a simple script that will subscribe to events from the foo table you created as part of the Quickstart.
# electric.ex
Mix.install([
:electric_client
])
{:ok, client} = Electric.Client.new(base_url: "http://localhost:3000")
# You can create a stream from a table name or a Shape defined using
# `ShapeDefinition.new/2`
stream = Electric.Client.stream(client, "foo")
for msg <- stream do
IO.inspect(msg, pretty: true, syntax_colors: IO.ANSI.syntax_colors())
endThen run it:
elixir electric.exIn a separate terminal window, connect to the Postgres database:
psql "postgresql://postgres:password@localhost:54321/electric"Now any modifications you make to the data in the foo table will appear
as messages in the elixir process.
INSERT INTO foo (name, value) VALUES
('josevalim', 4545),
('eksperimental', 966),
('lexmag', 677),
('whatyouhide', 598),
('ericmj', 583),
('alco', 377);
UPDATE foo SET value = value + 1;Filtering Using WHERE clauses
You can subscribe to subsets of the data in your table using where clauses.
{:ok, client} = Electric.Client.new(base_url: "http://localhost:3000")
{:ok, shape} = Electric.Client.ShapeDefinition.new("foo", where: "name ILIKE 'a%'")
stream = Electric.Client.stream(client, shape)
for msg <- stream do
# you will now only receive events for database rows matching the `where` clause
endConfiguration
See new/1 for configuration options of the client itself,
and stream/3 for details on configuring the stream itself.
Ecto Integration
If you have Ecto installed then you can define you Shapes using Ecto queries:
# ecto.ex
Mix.install([
:ecto_sql,
:electric_client
])
import Ecto.Query, only: [from: 2]
import Ecto.Query.API, only: [ilike: 2]
defmodule Foo do
use Ecto.Schema
schema "foo" do
field :name, :string
field :value, :float
end
end
{:ok, client} = Electric.Client.new(base_url: "http://localhost:3000")
# Replace the table or `ShapeDefinition` with an `Ecto` query and set
# `update_mode` to `:full` to receive full rows for update messages.
#
# The normal `update_mode: :modified` setting will only send the changed
# columns, so we'd end up with partial `%Foo{}` instances.
stream =
Electric.Client.stream(
client,
from(f in Foo, where: ilike(f.name, "a%")),
update_mode: :full
)
for %{headers: %{operation: operation}, value: value} <- stream do
# The message `value` will now be a `%Foo{}` struct
IO.inspect([{operation, value}], pretty: true, syntax_colors: IO.ANSI.syntax_colors())
endCustom Values
Electric sends all column values as binaries. The Ecto integration uses
Ecto's schema information to turn those into the relevant Elixir terms but
we can provide our own binary() => term() mapping by implementing the
Electric.Client.ValueMapper behaviour.
Summary
Functions
Authenticate the given request using the authenticator configured in the Client.
Get authentication query parameters for the given Elixir.Electric.Client.ShapeDefinition.
Use the given client to delete the shape instance from the server.
Create a new client.
Create a new client with the given options or raise if the configuration is invalid.
A shortcut to ShapeDefinition.new/2.
A shortcut to ShapeDefinition.new!/2.
Use the client to return a stream of update messages for the given shape.
Return an authenticated URL for the given request attributes.
Types
@type client_options() :: [client_option()]
@type column() :: %{ :type => String.t(), optional(:pk_index) => non_neg_integer(), optional(:not_null) => boolean(), optional(:max_length) => non_neg_integer(), optional(:length) => non_neg_integer() }
@type cursor() :: integer()
@type message() :: Electric.Client.Message.ControlMessage.t() | Electric.Client.Message.ChangeMessage.t() | Electric.Client.Message.ResumeMessage.t()
@type shape() :: table_name() | Electric.Client.ShapeDefinition.t() | Ecto.Queryable.t()
@type shape_id() :: String.t()
@type shape_option() :: {:parser, {module(), [term()]}} | {:live, boolean()} | {:update_mode, :modified | :full} | {:oneshot, boolean()} | {:resume, Electric.Client.Message.ResumeMessage.t() | nil}
@type shape_options() :: [shape_option()]
@type table_name() :: String.t()
@type update_mode() :: :modified | :full
Functions
@spec authenticate_request(t(), Electric.Client.Fetch.Request.t()) :: Electric.Client.Fetch.Request.authenticated()
Authenticate the given request using the authenticator configured in the Client.
@spec authenticate_shape(t(), Electric.Client.ShapeDefinition.t()) :: Electric.Client.Authenticator.params()
Get authentication query parameters for the given Elixir.Electric.Client.ShapeDefinition.
Use the given client to delete the shape instance from the server.
Delete shape only works if Electric is configured to allow_shape_deletion.
@spec new(client_options()) :: {:ok, t()} | {:error, term()}
Create a new client.
Options
:base_url(String.t/0) - Required. The URL of the electric server, e.g. for local development this would behttp://localhost:3000.
@spec new!(client_options()) :: t() | no_return()
Create a new client with the given options or raise if the configuration is invalid.
@spec shape(String.t(), Electric.Client.ShapeDefinition.options()) :: {:ok, Electric.Client.ShapeDefinition.t()} | {:error, term()}
A shortcut to ShapeDefinition.new/2.
@spec shape!(String.t(), Electric.Client.ShapeDefinition.options()) :: Electric.Client.ShapeDefinition.t() | no_return()
A shortcut to ShapeDefinition.new!/2.
@spec stream(t(), shape(), shape_options()) :: Enumerable.t(message())
Use the client to return a stream of update messages for the given shape.
shape can be a table name, e.g. "my_table", a full ShapeDefinition
including a table name and where clause, or (if Ecto is installed) an
Ecto.Queryable instance, such as an Ecto.Query or a Ecto.Schema struct.
Options
:parser- A{module, args}tuple specifying theElectric.Client.ValueMapperimplementation to use for mapping values from the sync stream into Elixir terms. The default value is{Electric.Client.ValueMapper, []}.:live(boolean/0) - Iftrue(the default) reads an infinite stream of update messages from the server. The default value istrue.:update_mode- Instructs the server to send just the changed columns for an update (:modified) or the full row (:full). The default value is:modified.:oneshot(boolean/0) - Only make a single request and then terminate the stream. The default value isfalse.:resume- Resume the stream from the given point.Message.ResumeMessagemessages are appended to the change stream if you terminate it early usinglive: falseoroneshot: true
@spec url(t(), Electric.Client.Fetch.Request.attrs()) :: binary()
Return an authenticated URL for the given request attributes.